codereview-aia 0.1.2 → 0.1.4

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 (200) hide show
  1. package/dist/analysis/static/wpPhpcsRunner.d.ts +11 -0
  2. package/dist/analysis/static/wpPhpcsRunner.js +219 -0
  3. package/dist/analysis/static/wpPhpcsRunner.js.map +1 -0
  4. package/dist/clients/implementations/openRouterClient.js +2 -2
  5. package/dist/clients/implementations/openRouterClient.js.map +1 -1
  6. package/dist/clients/openRouterClient.js +2 -2
  7. package/dist/clients/openRouterClient.js.map +1 -1
  8. package/dist/clients/utils/promptFormatter.d.ts +3 -2
  9. package/dist/clients/utils/promptFormatter.js +82 -24
  10. package/dist/clients/utils/promptFormatter.js.map +1 -1
  11. package/dist/core/ConfigurationService.d.ts +21 -0
  12. package/dist/core/ConfigurationService.js +39 -0
  13. package/dist/core/ConfigurationService.js.map +1 -1
  14. package/dist/core/handlers/FileProcessingHandler.js +5 -0
  15. package/dist/core/handlers/FileProcessingHandler.js.map +1 -1
  16. package/dist/core/reviewOrchestrator.js +61 -1
  17. package/dist/core/reviewOrchestrator.js.map +1 -1
  18. package/dist/index.d.ts +0 -1
  19. package/dist/index.js +0 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/runtime/cliEntry.js +57 -4
  22. package/dist/runtime/cliEntry.js.map +1 -1
  23. package/dist/runtime/fileCollector.d.ts +10 -1
  24. package/dist/runtime/fileCollector.js +217 -2
  25. package/dist/runtime/fileCollector.js.map +1 -1
  26. package/dist/runtime/reporting/markdownReportBuilder.d.ts +2 -0
  27. package/dist/runtime/reporting/markdownReportBuilder.js +57 -0
  28. package/dist/runtime/reporting/markdownReportBuilder.js.map +1 -1
  29. package/dist/runtime/reviewPipeline.d.ts +22 -3
  30. package/dist/runtime/reviewPipeline.js +46 -7
  31. package/dist/runtime/reviewPipeline.js.map +1 -1
  32. package/dist/runtime/runAiCodeReview.d.ts +19 -1
  33. package/dist/runtime/runAiCodeReview.js +243 -8
  34. package/dist/runtime/runAiCodeReview.js.map +1 -1
  35. package/dist/runtime/ui/RuntimeApp.js +15 -4
  36. package/dist/runtime/ui/RuntimeApp.js.map +1 -1
  37. package/dist/runtime/ui/screens/ProgressScreen.d.ts +6 -1
  38. package/dist/runtime/ui/screens/ProgressScreen.js +28 -2
  39. package/dist/runtime/ui/screens/ProgressScreen.js.map +1 -1
  40. package/dist/runtime/ui/screens/ResultsScreen.js +8 -1
  41. package/dist/runtime/ui/screens/ResultsScreen.js.map +1 -1
  42. package/dist/types/review.d.ts +60 -0
  43. package/dist/utils/detection/frameworkDetector.js +55 -0
  44. package/dist/utils/detection/frameworkDetector.js.map +1 -1
  45. package/dist/utils/promptTemplateManager.js +1 -0
  46. package/dist/utils/promptTemplateManager.js.map +1 -1
  47. package/package.json +13 -10
  48. package/.cr-aia.yml +0 -23
  49. package/.crignore +0 -0
  50. package/src/analysis/FindingsExtractor.ts +0 -431
  51. package/src/analysis/ai-detection/analyzers/BaseAnalyzer.ts +0 -267
  52. package/src/analysis/ai-detection/analyzers/DocumentationAnalyzer.ts +0 -622
  53. package/src/analysis/ai-detection/analyzers/GitHistoryAnalyzer.ts +0 -430
  54. package/src/analysis/ai-detection/core/AIDetectionEngine.ts +0 -467
  55. package/src/analysis/ai-detection/types/DetectionTypes.ts +0 -406
  56. package/src/analysis/ai-detection/utils/SubmissionConverter.ts +0 -390
  57. package/src/analysis/context/ReviewContext.ts +0 -378
  58. package/src/analysis/context/index.ts +0 -7
  59. package/src/analysis/index.ts +0 -8
  60. package/src/analysis/tokens/TokenAnalysisFormatter.ts +0 -154
  61. package/src/analysis/tokens/TokenAnalyzer.ts +0 -747
  62. package/src/analysis/tokens/index.ts +0 -8
  63. package/src/clients/base/abstractClient.ts +0 -190
  64. package/src/clients/base/httpClient.ts +0 -160
  65. package/src/clients/base/index.ts +0 -12
  66. package/src/clients/base/modelDetection.ts +0 -107
  67. package/src/clients/base/responseProcessor.ts +0 -586
  68. package/src/clients/factory/clientFactory.ts +0 -55
  69. package/src/clients/factory/index.ts +0 -8
  70. package/src/clients/implementations/index.ts +0 -8
  71. package/src/clients/implementations/openRouterClient.ts +0 -411
  72. package/src/clients/openRouterClient.ts +0 -863
  73. package/src/clients/openRouterClientWrapper.ts +0 -44
  74. package/src/clients/utils/directoryStructure.ts +0 -52
  75. package/src/clients/utils/index.ts +0 -11
  76. package/src/clients/utils/languageDetection.ts +0 -44
  77. package/src/clients/utils/promptFormatter.ts +0 -105
  78. package/src/clients/utils/promptLoader.ts +0 -53
  79. package/src/clients/utils/tokenCounter.ts +0 -297
  80. package/src/core/ApiClientSelector.ts +0 -37
  81. package/src/core/ConfigurationService.ts +0 -591
  82. package/src/core/ConsolidationService.ts +0 -423
  83. package/src/core/InteractiveDisplayManager.ts +0 -81
  84. package/src/core/OutputManager.ts +0 -275
  85. package/src/core/ReviewGenerator.ts +0 -140
  86. package/src/core/fileDiscovery.ts +0 -237
  87. package/src/core/handlers/EstimationHandler.ts +0 -104
  88. package/src/core/handlers/FileProcessingHandler.ts +0 -204
  89. package/src/core/handlers/OutputHandler.ts +0 -125
  90. package/src/core/handlers/ReviewExecutor.ts +0 -104
  91. package/src/core/reviewOrchestrator.ts +0 -333
  92. package/src/core/utils/ModelInfoUtils.ts +0 -56
  93. package/src/formatters/outputFormatter.ts +0 -62
  94. package/src/formatters/utils/IssueFormatters.ts +0 -83
  95. package/src/formatters/utils/JsonFormatter.ts +0 -77
  96. package/src/formatters/utils/MarkdownFormatters.ts +0 -609
  97. package/src/formatters/utils/MetadataFormatter.ts +0 -269
  98. package/src/formatters/utils/ModelInfoExtractor.ts +0 -115
  99. package/src/index.ts +0 -28
  100. package/src/plugins/PluginInterface.ts +0 -50
  101. package/src/plugins/PluginManager.ts +0 -126
  102. package/src/prompts/PromptManager.ts +0 -69
  103. package/src/prompts/cache/PromptCache.ts +0 -50
  104. package/src/prompts/promptText/common/variables/css-frameworks.json +0 -33
  105. package/src/prompts/promptText/common/variables/framework-versions.json +0 -45
  106. package/src/prompts/promptText/frameworks/react/comprehensive.hbs +0 -19
  107. package/src/prompts/promptText/languages/css/comprehensive.hbs +0 -18
  108. package/src/prompts/promptText/languages/generic/comprehensive.hbs +0 -20
  109. package/src/prompts/promptText/languages/html/comprehensive.hbs +0 -18
  110. package/src/prompts/promptText/languages/javascript/comprehensive.hbs +0 -18
  111. package/src/prompts/promptText/languages/python/comprehensive.hbs +0 -18
  112. package/src/prompts/promptText/languages/typescript/comprehensive.hbs +0 -18
  113. package/src/runtime/auth/service.ts +0 -58
  114. package/src/runtime/auth/session.ts +0 -103
  115. package/src/runtime/auth/types.ts +0 -11
  116. package/src/runtime/cliEntry.ts +0 -196
  117. package/src/runtime/debug/logManager.ts +0 -37
  118. package/src/runtime/errors.ts +0 -13
  119. package/src/runtime/fileCollector.ts +0 -222
  120. package/src/runtime/manifest.ts +0 -64
  121. package/src/runtime/openrouterProxy.ts +0 -45
  122. package/src/runtime/preprod/webCheck.ts +0 -104
  123. package/src/runtime/proxyConfig.ts +0 -94
  124. package/src/runtime/proxyEnvironment.ts +0 -71
  125. package/src/runtime/reportMerge.ts +0 -102
  126. package/src/runtime/reporting/markdownReportBuilder.ts +0 -138
  127. package/src/runtime/reporting/reportDataCollector.ts +0 -234
  128. package/src/runtime/reporting/summaryGenerator.ts +0 -86
  129. package/src/runtime/reviewPipeline.ts +0 -161
  130. package/src/runtime/runAiCodeReview.ts +0 -153
  131. package/src/runtime/runtimeConfig.ts +0 -5
  132. package/src/runtime/ui/Layout.tsx +0 -57
  133. package/src/runtime/ui/RuntimeApp.tsx +0 -233
  134. package/src/runtime/ui/inkModules.ts +0 -73
  135. package/src/runtime/ui/screens/AuthScreen.tsx +0 -128
  136. package/src/runtime/ui/screens/ModeSelection.tsx +0 -185
  137. package/src/runtime/ui/screens/ProgressScreen.tsx +0 -62
  138. package/src/runtime/ui/screens/ResultsScreen.tsx +0 -83
  139. package/src/strategies/ArchitecturalReviewStrategy.ts +0 -54
  140. package/src/strategies/CodingTestReviewStrategy.ts +0 -920
  141. package/src/strategies/ConsolidatedReviewStrategy.ts +0 -59
  142. package/src/strategies/ExtractPatternsReviewStrategy.ts +0 -64
  143. package/src/strategies/MultiPassReviewStrategy.ts +0 -785
  144. package/src/strategies/ReviewStrategy.ts +0 -64
  145. package/src/strategies/StrategyFactory.ts +0 -79
  146. package/src/strategies/index.ts +0 -14
  147. package/src/tokenizers/baseTokenizer.ts +0 -61
  148. package/src/tokenizers/gptTokenizer.ts +0 -27
  149. package/src/tokenizers/index.ts +0 -8
  150. package/src/types/apiResponses.ts +0 -40
  151. package/src/types/cli.ts +0 -24
  152. package/src/types/common.ts +0 -39
  153. package/src/types/configuration.ts +0 -201
  154. package/src/types/handlebars.d.ts +0 -5
  155. package/src/types/patch.d.ts +0 -25
  156. package/src/types/review.ts +0 -294
  157. package/src/types/reviewContext.d.ts +0 -65
  158. package/src/types/reviewSchema.ts +0 -181
  159. package/src/types/structuredReview.ts +0 -167
  160. package/src/types/tokenAnalysis.ts +0 -56
  161. package/src/utils/FileReader.ts +0 -93
  162. package/src/utils/FileWriter.ts +0 -76
  163. package/src/utils/PathGenerator.ts +0 -97
  164. package/src/utils/api/apiUtils.ts +0 -14
  165. package/src/utils/api/index.ts +0 -1
  166. package/src/utils/apiErrorHandler.ts +0 -287
  167. package/src/utils/ciDataCollector.ts +0 -252
  168. package/src/utils/codingTestConfigLoader.ts +0 -466
  169. package/src/utils/dependencies/aiDependencyAnalyzer.ts +0 -454
  170. package/src/utils/detection/frameworkDetector.ts +0 -879
  171. package/src/utils/detection/index.ts +0 -10
  172. package/src/utils/detection/projectTypeDetector.ts +0 -518
  173. package/src/utils/diagramGenerator.ts +0 -206
  174. package/src/utils/errorLogger.ts +0 -60
  175. package/src/utils/estimationUtils.ts +0 -407
  176. package/src/utils/fileFilters.ts +0 -373
  177. package/src/utils/fileSystem.ts +0 -57
  178. package/src/utils/index.ts +0 -36
  179. package/src/utils/logger.ts +0 -290
  180. package/src/utils/pathValidator.ts +0 -98
  181. package/src/utils/priorityFilter.ts +0 -59
  182. package/src/utils/projectDocs.ts +0 -189
  183. package/src/utils/promptPaths.ts +0 -29
  184. package/src/utils/promptTemplateManager.ts +0 -157
  185. package/src/utils/review/consolidateReview.ts +0 -553
  186. package/src/utils/review/fixDisplay.ts +0 -100
  187. package/src/utils/review/fixImplementation.ts +0 -61
  188. package/src/utils/review/index.ts +0 -36
  189. package/src/utils/review/interactiveProcessing.ts +0 -294
  190. package/src/utils/review/progressTracker.ts +0 -296
  191. package/src/utils/review/reviewExtraction.ts +0 -382
  192. package/src/utils/review/types.ts +0 -46
  193. package/src/utils/reviewActionHandler.ts +0 -18
  194. package/src/utils/reviewParser.ts +0 -253
  195. package/src/utils/sanitizer.ts +0 -238
  196. package/src/utils/smartFileSelector.ts +0 -255
  197. package/src/utils/templateLoader.ts +0 -514
  198. package/src/utils/treeGenerator.ts +0 -153
  199. package/tsconfig.build.json +0 -14
  200. package/tsconfig.json +0 -59
@@ -1,252 +0,0 @@
1
- /**
2
- * @fileoverview CI/CD data collector utility.
3
- *
4
- * This module collects CI/CD data (type check errors, lint errors) to include
5
- * in code reviews. It supports both project-wide and per-file analysis.
6
- */
7
-
8
- import { exec } from 'node:child_process';
9
- import path from 'node:path';
10
- import { promisify } from 'node:util';
11
- import logger from './logger';
12
-
13
- const execAsync = promisify(exec);
14
-
15
- /**
16
- * CI data structure
17
- */
18
- export interface CIData {
19
- /**
20
- * Number of type check errors
21
- */
22
- typeCheckErrors?: number;
23
-
24
- /**
25
- * Number of lint errors
26
- */
27
- lintErrors?: number;
28
-
29
- /**
30
- * Raw type check output
31
- */
32
- typeCheckOutput?: string;
33
-
34
- /**
35
- * Raw lint output
36
- */
37
- lintOutput?: string;
38
-
39
- /**
40
- * Per-file error counts
41
- */
42
- fileErrors?: {
43
- [filePath: string]: {
44
- typeCheckErrors: number;
45
- lintErrors: number;
46
- typeCheckMessages?: string[];
47
- lintMessages?: string[];
48
- };
49
- };
50
- }
51
-
52
- /**
53
- * Collect CI/CD data for the current project
54
- * @param projectPath Path to the project root
55
- * @returns Promise resolving to CI data
56
- */
57
- export async function collectCIData(projectPath: string): Promise<CIData> {
58
- const ciData: CIData = {
59
- fileErrors: {},
60
- };
61
-
62
- // Collect type check errors
63
- try {
64
- logger.info('Running type check to collect error count...');
65
- const { stdout, stderr } = await execAsync('npm run build:types', {
66
- cwd: projectPath,
67
- env: { ...process.env, CI: 'true' },
68
- });
69
-
70
- ciData.typeCheckOutput = stdout + stderr;
71
- parseTypeCheckErrors(ciData.typeCheckOutput, ciData, projectPath);
72
- } catch (error: any) {
73
- // Type check failed - extract error count from output
74
- const output = error.stdout + error.stderr;
75
- ciData.typeCheckOutput = output;
76
- parseTypeCheckErrors(output, ciData, projectPath);
77
- }
78
-
79
- // Collect lint errors
80
- try {
81
- logger.info('Running lint to collect error count...');
82
- const { stdout, stderr } = await execAsync('npm run lint', {
83
- cwd: projectPath,
84
- env: { ...process.env, CI: 'true' },
85
- });
86
-
87
- ciData.lintOutput = stdout + stderr;
88
- parseLintErrors(ciData.lintOutput, ciData, projectPath);
89
- } catch (error: any) {
90
- // Lint failed - extract error count from output
91
- const output = error.stdout + error.stderr;
92
- ciData.lintOutput = output;
93
- parseLintErrors(output, ciData, projectPath);
94
- }
95
-
96
- // Calculate totals
97
- calculateTotals(ciData);
98
-
99
- return ciData;
100
- }
101
-
102
- /**
103
- * Parse TypeScript errors from output
104
- */
105
- function parseTypeCheckErrors(output: string, ciData: CIData, projectPath: string): void {
106
- const lines = output.split('\n');
107
-
108
- for (const line of lines) {
109
- // TypeScript error format: src/file.ts(line,col): error TS2322: ...
110
- const match = line.match(/^(.+?)\((\d+),(\d+)\): error (TS\d+): (.+)$/);
111
- if (match) {
112
- const [, file, lineNum, colNum, errorCode, message] = match;
113
- const relativeFile = path.relative(projectPath, file);
114
-
115
- if (!ciData.fileErrors?.[relativeFile]) {
116
- ciData.fileErrors![relativeFile] = {
117
- typeCheckErrors: 0,
118
- lintErrors: 0,
119
- typeCheckMessages: [],
120
- lintMessages: [],
121
- };
122
- }
123
-
124
- const fileError = ciData.fileErrors?.[relativeFile];
125
- if (fileError) {
126
- fileError.typeCheckErrors++;
127
- fileError.typeCheckMessages?.push(`Line ${lineNum}:${colNum} - ${errorCode}: ${message}`);
128
- }
129
- }
130
- }
131
- }
132
-
133
- /**
134
- * Parse ESLint errors from output
135
- */
136
- function parseLintErrors(output: string, ciData: CIData, projectPath: string): void {
137
- const lines = output.split('\n');
138
- let currentFile: string | null = null;
139
-
140
- for (const line of lines) {
141
- // ESLint file header format: /path/to/file.ts
142
- if (line.match(/^[/\\]/)) {
143
- currentFile = path.relative(projectPath, line.trim());
144
- if (!ciData.fileErrors?.[currentFile]) {
145
- ciData.fileErrors![currentFile] = {
146
- typeCheckErrors: 0,
147
- lintErrors: 0,
148
- typeCheckMessages: [],
149
- lintMessages: [],
150
- };
151
- }
152
- }
153
- // ESLint error format: line:col error message rule-name
154
- else if (currentFile && line.match(/^\s*\d+:\d+\s+error\s+/)) {
155
- const match = line.match(/^\s*(\d+):(\d+)\s+error\s+(.+?)\s+(.+)$/);
156
- if (match) {
157
- const [, lineNum, colNum, message, rule] = match;
158
- const fileError = ciData.fileErrors?.[currentFile];
159
- if (fileError) {
160
- fileError.lintErrors++;
161
- fileError.lintMessages?.push(`Line ${lineNum}:${colNum} - ${message} (${rule})`);
162
- }
163
- }
164
- }
165
- }
166
- }
167
-
168
- /**
169
- * Calculate total error counts from per-file data
170
- */
171
- function calculateTotals(ciData: CIData): void {
172
- let totalTypeCheckErrors = 0;
173
- let totalLintErrors = 0;
174
-
175
- for (const fileData of Object.values(ciData.fileErrors || {})) {
176
- totalTypeCheckErrors += fileData.typeCheckErrors;
177
- totalLintErrors += fileData.lintErrors;
178
- }
179
-
180
- ciData.typeCheckErrors = totalTypeCheckErrors;
181
- ciData.lintErrors = totalLintErrors;
182
-
183
- logger.info(
184
- `Found ${totalTypeCheckErrors} type check errors and ${totalLintErrors} lint errors across all files`,
185
- );
186
- }
187
-
188
- /**
189
- * Format CI data for inclusion in prompts
190
- * @param ciData CI data to format
191
- * @param specificFile Optional specific file to focus on
192
- * @returns Formatted string for prompt inclusion
193
- */
194
- export function formatCIDataForPrompt(ciData: CIData, specificFile?: string): string {
195
- const lines: string[] = [];
196
-
197
- lines.push('## CI/CD Status');
198
- lines.push('');
199
-
200
- // Overall summary
201
- lines.push(`- Total TypeScript errors: ${ciData.typeCheckErrors || 0}`);
202
- lines.push(`- Total ESLint errors: ${ciData.lintErrors || 0}`);
203
-
204
- // Per-file data
205
- if (ciData.fileErrors && Object.keys(ciData.fileErrors).length > 0) {
206
- lines.push('');
207
- lines.push('### Errors by file:');
208
-
209
- // If reviewing a specific file, show only that file's errors
210
- if (specificFile && ciData.fileErrors[specificFile]) {
211
- const fileData = ciData.fileErrors[specificFile];
212
- lines.push('');
213
- lines.push(`**${specificFile}**:`);
214
- lines.push(`- TypeScript errors: ${fileData.typeCheckErrors}`);
215
- if (fileData.typeCheckMessages && fileData.typeCheckMessages.length > 0) {
216
- lines.push(' TypeScript issues:');
217
- fileData.typeCheckMessages.slice(0, 5).forEach((msg) => {
218
- lines.push(` - ${msg}`);
219
- });
220
- }
221
- lines.push(`- ESLint errors: ${fileData.lintErrors}`);
222
- if (fileData.lintMessages && fileData.lintMessages.length > 0) {
223
- lines.push(' ESLint issues:');
224
- fileData.lintMessages.slice(0, 5).forEach((msg) => {
225
- lines.push(` - ${msg}`);
226
- });
227
- }
228
- } else {
229
- // Show top 5 files with most errors
230
- const fileList = Object.entries(ciData.fileErrors)
231
- .map(([file, data]) => ({
232
- file,
233
- totalErrors: data.typeCheckErrors + data.lintErrors,
234
- ...data,
235
- }))
236
- .sort((a, b) => b.totalErrors - a.totalErrors)
237
- .slice(0, 5);
238
-
239
- for (const fileInfo of fileList) {
240
- lines.push('');
241
- lines.push(`**${fileInfo.file}**: ${fileInfo.totalErrors} total errors`);
242
- lines.push(` - TypeScript: ${fileInfo.typeCheckErrors} errors`);
243
- lines.push(` - ESLint: ${fileInfo.lintErrors} errors`);
244
- }
245
- }
246
- }
247
-
248
- lines.push('');
249
- lines.push('Please include fixes for these CI/CD issues in your code review.');
250
-
251
- return lines.join('\n');
252
- }
@@ -1,466 +0,0 @@
1
- /**
2
- * @fileoverview Coding test configuration loader utility.
3
- *
4
- * This module provides utilities for loading and parsing coding test configuration
5
- * files in various formats (JSON, YAML) and converting them to the internal
6
- * configuration format used by the CodingTestReviewStrategy.
7
- */
8
-
9
- import * as fs from 'node:fs';
10
- import * as path from 'node:path';
11
- import type { CodingTestConfig } from '../strategies/CodingTestReviewStrategy';
12
- import logger from './logger';
13
-
14
- /**
15
- * Extended configuration interface that includes additional metadata
16
- */
17
- export interface ExtendedCodingTestConfig extends CodingTestConfig {
18
- /** Evaluation section with criteria and descriptions */
19
- evaluation?: {
20
- criteria?: Record<string, number | { weight: number; description?: string }>;
21
- };
22
-
23
- /** Additional evaluation criteria beyond the standard ones */
24
- additionalCriteria?: Record<
25
- string,
26
- {
27
- weight: number;
28
- description: string;
29
- }
30
- >;
31
-
32
- /** Expected deliverables checklist */
33
- deliverables?: string[];
34
-
35
- /** Technical requirements */
36
- technicalRequirements?: Record<string, string>;
37
-
38
- /** Bonus points for optional features */
39
- bonusPoints?: string[];
40
-
41
- /** Common pitfalls to avoid */
42
- commonPitfalls?: string[];
43
- }
44
-
45
- /**
46
- * Load coding test configuration from a file
47
- * @param configPath Path to the configuration file
48
- * @returns Parsed configuration object
49
- */
50
- export function loadCodingTestConfig(configPath: string): ExtendedCodingTestConfig {
51
- try {
52
- if (!fs.existsSync(configPath)) {
53
- throw new Error(`Configuration file not found: ${configPath}`);
54
- }
55
-
56
- const configContent = fs.readFileSync(configPath, 'utf8');
57
- const extension = path.extname(configPath).toLowerCase();
58
-
59
- let config: ExtendedCodingTestConfig;
60
-
61
- switch (extension) {
62
- case '.json':
63
- config = JSON.parse(configContent);
64
- break;
65
- case '.yaml':
66
- case '.yml':
67
- // Simple YAML parser for basic structures - in production, use js-yaml
68
- config = parseBasicYaml(configContent);
69
- break;
70
- default:
71
- throw new Error(`Unsupported configuration file format: ${extension}`);
72
- }
73
-
74
- // Validate and normalize the configuration
75
- return validateAndNormalizeConfig(config, configPath);
76
- } catch (error) {
77
- logger.error(`Failed to load coding test configuration from ${configPath}:`, error);
78
- throw error;
79
- }
80
- }
81
-
82
- /**
83
- * Load configuration from URL
84
- * @param configUrl URL to the configuration file
85
- * @returns Parsed configuration object
86
- */
87
- export async function loadCodingTestConfigFromUrl(
88
- configUrl: string,
89
- ): Promise<ExtendedCodingTestConfig> {
90
- try {
91
- const response = await fetch(configUrl);
92
- if (!response.ok) {
93
- throw new Error(`Failed to fetch configuration from ${configUrl}: ${response.statusText}`);
94
- }
95
-
96
- const configContent = await response.text();
97
- const urlParts = new URL(configUrl);
98
- const extension = path.extname(urlParts.pathname).toLowerCase();
99
-
100
- let config: ExtendedCodingTestConfig;
101
-
102
- switch (extension) {
103
- case '.json':
104
- config = JSON.parse(configContent);
105
- break;
106
- case '.yaml':
107
- case '.yml':
108
- // Simple YAML parser for basic structures - in production, use js-yaml
109
- config = parseBasicYaml(configContent);
110
- break;
111
- default: {
112
- // Try to detect format from content-type header
113
- const contentType = response.headers.get('content-type') || '';
114
- if (contentType.includes('application/json')) {
115
- config = JSON.parse(configContent);
116
- } else if (contentType.includes('text/yaml') || contentType.includes('application/yaml')) {
117
- // Simple YAML parser for basic structures - in production, use js-yaml
118
- config = parseBasicYaml(configContent);
119
- } else {
120
- throw new Error(`Unable to determine configuration format from URL: ${configUrl}`);
121
- }
122
- }
123
- }
124
-
125
- // Validate and normalize the configuration
126
- return validateAndNormalizeConfig(config, configUrl);
127
- } catch (error) {
128
- logger.error(`Failed to load coding test configuration from URL ${configUrl}:`, error);
129
- throw error;
130
- }
131
- }
132
-
133
- /**
134
- * Validate and normalize configuration
135
- * @param config Raw configuration object
136
- * @param source Source path or URL for error messages
137
- * @returns Validated and normalized configuration
138
- */
139
- function validateAndNormalizeConfig(
140
- config: ExtendedCodingTestConfig,
141
- source: string,
142
- ): ExtendedCodingTestConfig {
143
- const normalized: ExtendedCodingTestConfig = {
144
- ...config,
145
- };
146
-
147
- // Validate required sections
148
- if (!normalized.assignment) {
149
- throw new Error(`Missing 'assignment' section in configuration: ${source}`);
150
- }
151
-
152
- if (!normalized.evaluation) {
153
- throw new Error(`Missing 'evaluation' section in configuration: ${source}`);
154
- }
155
-
156
- // Normalize assignment defaults
157
- if (normalized.assignment) {
158
- normalized.assignment = {
159
- type: 'coding-challenge',
160
- difficulty: 'mid',
161
- timeLimit: 120,
162
- ...normalized.assignment,
163
- };
164
- }
165
-
166
- // Normalize evaluation criteria
167
- if (normalized.evaluation?.criteria) {
168
- const weights: number[] = [];
169
- Object.values(normalized.evaluation.criteria).forEach((criterion) => {
170
- if (typeof criterion === 'number') {
171
- weights.push(criterion);
172
- } else if (criterion && typeof criterion === 'object' && 'weight' in criterion) {
173
- weights.push(criterion.weight);
174
- }
175
- });
176
-
177
- const criteriaTotal = weights.reduce((sum, weight) => sum + weight, 0);
178
-
179
- if (Math.abs(criteriaTotal - 100) > 0.1) {
180
- logger.warn(
181
- `Criteria weights sum to ${criteriaTotal}, expected 100 (source: ${source}). Normalizing...`,
182
- );
183
-
184
- // Normalize weights to sum to 100
185
- const normalizationFactor = 100 / criteriaTotal;
186
- Object.keys(normalized.evaluation.criteria).forEach((key) => {
187
- const criterion = normalized.evaluation?.criteria?.[key];
188
- if (typeof criterion === 'number' && normalized.evaluation?.criteria) {
189
- normalized.evaluation.criteria[key] = Math.round(criterion * normalizationFactor);
190
- } else if (criterion && typeof criterion === 'object' && 'weight' in criterion) {
191
- criterion.weight = Math.round(criterion.weight * normalizationFactor);
192
- }
193
- });
194
- }
195
- }
196
-
197
- // Normalize scoring defaults
198
- if (normalized.scoring) {
199
- normalized.scoring = {
200
- system: 'numeric',
201
- maxScore: 100,
202
- passingThreshold: 70,
203
- breakdown: true,
204
- ...normalized.scoring,
205
- };
206
- }
207
-
208
- // Normalize feedback defaults
209
- if (normalized.feedback) {
210
- normalized.feedback = {
211
- level: 'detailed',
212
- includeExamples: true,
213
- includeSuggestions: true,
214
- includeResources: false,
215
- ...normalized.feedback,
216
- };
217
- }
218
-
219
- // Validate constraints
220
- if (normalized.constraints) {
221
- if (
222
- normalized.constraints.allowedLibraries &&
223
- !Array.isArray(normalized.constraints.allowedLibraries)
224
- ) {
225
- throw new Error(`'allowedLibraries' must be an array in configuration: ${source}`);
226
- }
227
-
228
- if (
229
- normalized.constraints.forbiddenPatterns &&
230
- !Array.isArray(normalized.constraints.forbiddenPatterns)
231
- ) {
232
- throw new Error(`'forbiddenPatterns' must be an array in configuration: ${source}`);
233
- }
234
- }
235
-
236
- // Validate additional criteria if present
237
- if (normalized.additionalCriteria) {
238
- Object.entries(normalized.additionalCriteria).forEach(([key, criterion]) => {
239
- if (typeof criterion !== 'object' || typeof criterion.weight !== 'number') {
240
- throw new Error(`Invalid additional criterion '${key}' in configuration: ${source}`);
241
- }
242
-
243
- if (criterion.weight < 0 || criterion.weight > 100) {
244
- throw new Error(
245
- `Invalid weight for additional criterion '${key}' in configuration: ${source}`,
246
- );
247
- }
248
- });
249
- }
250
-
251
- return normalized;
252
- }
253
-
254
- /**
255
- * Convert extended configuration to basic CodingTestConfig
256
- * @param extendedConfig Extended configuration object
257
- * @returns Basic configuration object
258
- */
259
- export function convertToCodingTestConfig(
260
- extendedConfig: ExtendedCodingTestConfig,
261
- ): CodingTestConfig {
262
- const basicConfig: CodingTestConfig = {
263
- assignment: extendedConfig.assignment,
264
- criteria: {},
265
- scoring: extendedConfig.scoring,
266
- feedback: extendedConfig.feedback,
267
- constraints: extendedConfig.constraints,
268
- };
269
-
270
- // Convert evaluation criteria
271
- if (extendedConfig.evaluation?.criteria) {
272
- Object.entries(extendedConfig.evaluation.criteria).forEach(([key, criterion]) => {
273
- if (typeof criterion === 'number') {
274
- (basicConfig.criteria as Record<string, number>)[key] = criterion;
275
- } else if (criterion && typeof criterion === 'object' && 'weight' in criterion) {
276
- (basicConfig.criteria as Record<string, number>)[key] = criterion.weight;
277
- }
278
- });
279
- }
280
-
281
- // Merge additional criteria
282
- if (extendedConfig.additionalCriteria) {
283
- Object.entries(extendedConfig.additionalCriteria).forEach(([key, criterion]) => {
284
- (basicConfig.criteria as Record<string, number>)[key] = criterion.weight;
285
- });
286
- }
287
-
288
- return basicConfig;
289
- }
290
-
291
- /**
292
- * Create a default configuration for testing
293
- * @returns Default coding test configuration
294
- */
295
- export function createDefaultCodingTestConfig(): CodingTestConfig {
296
- return {
297
- assignment: {
298
- type: 'coding-challenge',
299
- difficulty: 'mid',
300
- timeLimit: 120,
301
- title: 'Coding Challenge',
302
- description: 'Complete the coding challenge according to the provided requirements.',
303
- requirements: [
304
- 'Implement the core functionality',
305
- 'Include proper error handling',
306
- 'Write comprehensive tests',
307
- 'Provide clear documentation',
308
- ],
309
- },
310
- criteria: {
311
- correctness: 30,
312
- codeQuality: 25,
313
- architecture: 20,
314
- performance: 15,
315
- testing: 10,
316
- },
317
- scoring: {
318
- system: 'numeric',
319
- maxScore: 100,
320
- passingThreshold: 70,
321
- breakdown: true,
322
- },
323
- feedback: {
324
- level: 'detailed',
325
- includeExamples: true,
326
- includeSuggestions: true,
327
- includeResources: false,
328
- },
329
- constraints: {
330
- targetLanguage: 'typescript',
331
- forbiddenPatterns: ['eval', 'Function'],
332
- },
333
- };
334
- }
335
-
336
- /**
337
- * Validate assignment text and extract basic requirements
338
- * @param assignmentText Raw assignment text
339
- * @returns Parsed assignment information
340
- */
341
- export function parseAssignmentText(assignmentText: string): {
342
- title?: string;
343
- description?: string;
344
- requirements?: string[];
345
- } {
346
- const lines = assignmentText
347
- .split('\n')
348
- .map((line) => line.trim())
349
- .filter((line) => line);
350
-
351
- let title: string | undefined;
352
- let description: string | undefined;
353
- const requirements: string[] = [];
354
-
355
- let currentSection = 'description';
356
- const descriptionLines: string[] = [];
357
-
358
- for (const line of lines) {
359
- // Check for title (first line or line starting with #)
360
- if (!title && (line.startsWith('#') || lines.indexOf(line) === 0)) {
361
- title = line.replace(/^#+\s*/, '').trim();
362
- continue;
363
- }
364
-
365
- // Check for requirements section
366
- if (line.toLowerCase().includes('requirement') || line.toLowerCase().includes('task')) {
367
- currentSection = 'requirements';
368
- continue;
369
- }
370
-
371
- // Parse requirements (lines starting with - or numbers)
372
- if (
373
- currentSection === 'requirements' &&
374
- (line.startsWith('-') || line.startsWith('*') || /^\d+\./.test(line))
375
- ) {
376
- const requirement = line.replace(/^[-*\d.)\s]+/, '').trim();
377
- if (requirement) {
378
- requirements.push(requirement);
379
- }
380
- continue;
381
- }
382
-
383
- // Add to description
384
- if (currentSection === 'description') {
385
- descriptionLines.push(line);
386
- }
387
- }
388
-
389
- if (descriptionLines.length > 0) {
390
- description = descriptionLines.join('\n');
391
- }
392
-
393
- return {
394
- title,
395
- description,
396
- requirements: requirements.length > 0 ? requirements : undefined,
397
- };
398
- }
399
-
400
- /**
401
- * Simple YAML parser for basic configuration structures
402
- * Note: This is a minimal implementation. For production use, consider js-yaml
403
- * @param yamlContent YAML content string
404
- * @returns Parsed object
405
- */
406
- function parseBasicYaml(yamlContent: string): ExtendedCodingTestConfig {
407
- try {
408
- // This is a very basic YAML parser - in production, use js-yaml
409
- // For now, we'll try to parse as JSON if possible, or create a basic structure
410
-
411
- // Remove comments and clean up
412
- const _lines = yamlContent
413
- .split('\n')
414
- .map((line) => line.replace(/#.*$/, '').trim())
415
- .filter((line) => line.length > 0);
416
-
417
- // For this POC, we'll return a default structure if YAML parsing fails
418
- // In production, implement proper YAML parsing or use js-yaml
419
- return {
420
- assignment: {
421
- type: 'take-home',
422
- difficulty: 'mid',
423
- timeLimit: 240,
424
- title: 'Events Platform API Development',
425
- description: 'Build a RESTful API for an events platform',
426
- requirements: [
427
- 'Implement user authentication',
428
- 'Create event management endpoints',
429
- 'Add event attendance functionality',
430
- ],
431
- },
432
- evaluation: {
433
- criteria: {
434
- correctness: 35,
435
- codeQuality: 25,
436
- architecture: 20,
437
- performance: 10,
438
- testing: 10,
439
- },
440
- },
441
- scoring: {
442
- system: 'numeric',
443
- maxScore: 100,
444
- passingThreshold: 75,
445
- breakdown: true,
446
- },
447
- feedback: {
448
- level: 'comprehensive',
449
- includeExamples: true,
450
- includeSuggestions: true,
451
- includeResources: true,
452
- },
453
- constraints: {
454
- targetLanguage: 'typescript',
455
- framework: 'express',
456
- allowedLibraries: ['express', 'joi', 'jsonwebtoken'],
457
- forbiddenPatterns: ['eval', 'Function'],
458
- },
459
- };
460
- } catch (_error) {
461
- logger.warn('Failed to parse YAML content, using default configuration');
462
- throw new Error(
463
- 'YAML parsing failed. Please use JSON format or install js-yaml for YAML support.',
464
- );
465
- }
466
- }