phantom-pr 0.4.19 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +216 -80
  2. package/dist/core/analysis/astExtractor.d.ts +15 -0
  3. package/dist/core/analysis/astExtractor.js +354 -0
  4. package/dist/core/analysis/astExtractor.js.map +1 -0
  5. package/dist/core/analysis/index.d.ts +3 -0
  6. package/dist/core/analysis/index.js +3 -0
  7. package/dist/core/analysis/index.js.map +1 -0
  8. package/dist/core/analysis/types.d.ts +50 -0
  9. package/dist/core/analysis/types.js +16 -0
  10. package/dist/core/analysis/types.js.map +1 -0
  11. package/dist/core/context/contextSelector.d.ts +29 -0
  12. package/dist/core/context/contextSelector.js +293 -0
  13. package/dist/core/context/contextSelector.js.map +1 -0
  14. package/dist/core/context/index.d.ts +4 -0
  15. package/dist/core/context/index.js +3 -0
  16. package/dist/core/context/index.js.map +1 -0
  17. package/dist/core/generator/enhancedContext.d.ts +34 -0
  18. package/dist/core/generator/enhancedContext.js +144 -0
  19. package/dist/core/generator/enhancedContext.js.map +1 -0
  20. package/dist/core/generator/postValidation.d.ts +24 -0
  21. package/dist/core/generator/postValidation.js +57 -0
  22. package/dist/core/generator/postValidation.js.map +1 -0
  23. package/dist/core/retry/errorParser.d.ts +12 -0
  24. package/dist/core/retry/errorParser.js +264 -0
  25. package/dist/core/retry/errorParser.js.map +1 -0
  26. package/dist/core/retry/feedbackGenerator.d.ts +12 -0
  27. package/dist/core/retry/feedbackGenerator.js +164 -0
  28. package/dist/core/retry/feedbackGenerator.js.map +1 -0
  29. package/dist/core/retry/index.d.ts +3 -0
  30. package/dist/core/retry/index.js +3 -0
  31. package/dist/core/retry/index.js.map +1 -0
  32. package/dist/core/retry/types.d.ts +40 -0
  33. package/dist/core/retry/types.js +5 -0
  34. package/dist/core/retry/types.js.map +1 -0
  35. package/dist/core/testRunner/retryEnhancer.d.ts +32 -0
  36. package/dist/core/testRunner/retryEnhancer.js +58 -0
  37. package/dist/core/testRunner/retryEnhancer.js.map +1 -0
  38. package/dist/core/validation/coverageVerifier.d.ts +16 -0
  39. package/dist/core/validation/coverageVerifier.js +226 -0
  40. package/dist/core/validation/coverageVerifier.js.map +1 -0
  41. package/dist/core/validation/index.d.ts +2 -0
  42. package/dist/core/validation/index.js +2 -0
  43. package/dist/core/validation/index.js.map +1 -0
  44. package/dist/core/validation/types.d.ts +24 -0
  45. package/dist/core/validation/types.js +6 -0
  46. package/dist/core/validation/types.js.map +1 -0
  47. package/package.json +1 -1
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Parser that extracts actionable information from Jest/Vitest test failures.
3
+ * Returns structured feedback for retry generation.
4
+ */
5
+ /**
6
+ * Extract the test name from a FAIL line or surrounding context.
7
+ */
8
+ function extractTestName(lines, index) {
9
+ // Look backwards for test name
10
+ for (let i = index; i >= Math.max(0, index - 10); i--) {
11
+ const line = lines[i] ?? '';
12
+ // Match patterns like: ✕ test name (123 ms)
13
+ const failMatch = line.match(/[✕×✗]\s+(.+?)(?:\s+\(\d+\s*m?s\))?$/);
14
+ if (failMatch)
15
+ return failMatch[1]?.trim() ?? 'unknown';
16
+ // Match patterns like: FAIL src/file.test.ts › test name
17
+ const failPathMatch = line.match(/FAIL\s+.+?›\s+(.+)$/);
18
+ if (failPathMatch)
19
+ return failPathMatch[1]?.trim() ?? 'unknown';
20
+ // Match patterns like: ● test name
21
+ const bulletMatch = line.match(/[●•]\s+(.+)$/);
22
+ if (bulletMatch)
23
+ return bulletMatch[1]?.trim() ?? 'unknown';
24
+ }
25
+ return 'unknown';
26
+ }
27
+ /**
28
+ * Parse assertion mismatch errors.
29
+ * Example:
30
+ * expect(received).toEqual(expected)
31
+ * Expected: "foo"
32
+ * Received: "bar"
33
+ */
34
+ function parseAssertionMismatch(lines, startIndex) {
35
+ let expected;
36
+ let received;
37
+ for (let i = startIndex; i < Math.min(lines.length, startIndex + 10); i++) {
38
+ const line = lines[i] ?? '';
39
+ const expectedMatch = line.match(/Expected:\s*(.+)/);
40
+ if (expectedMatch)
41
+ expected = expectedMatch[1]?.trim();
42
+ const receivedMatch = line.match(/Received:\s*(.+)/);
43
+ if (receivedMatch)
44
+ received = receivedMatch[1]?.trim();
45
+ if (expected !== undefined && received !== undefined)
46
+ break;
47
+ }
48
+ if (expected === undefined && received === undefined)
49
+ return null;
50
+ const details = {};
51
+ if (expected !== undefined)
52
+ details.expected = expected;
53
+ if (received !== undefined)
54
+ details.received = received;
55
+ return {
56
+ kind: 'assertion_mismatch',
57
+ testName: extractTestName(lines, startIndex),
58
+ details,
59
+ suggestedFix: `Change expected value from ${expected ?? 'unknown'} to ${received ?? 'unknown'}, or fix the test setup/mock to return the expected value`,
60
+ };
61
+ }
62
+ /**
63
+ * Parse mock not called errors.
64
+ * Example:
65
+ * expect(jest.fn()).toHaveBeenCalled()
66
+ * Expected number of calls: >= 1
67
+ * Received number of calls: 0
68
+ */
69
+ function parseMockNotCalled(lines, startIndex) {
70
+ let expectedCalls = 1;
71
+ let receivedCalls = 0;
72
+ for (let i = startIndex; i < Math.min(lines.length, startIndex + 10); i++) {
73
+ const line = lines[i] ?? '';
74
+ const expectedMatch = line.match(/Expected number of calls:\s*(?:>=\s*)?(\d+)/);
75
+ if (expectedMatch)
76
+ expectedCalls = parseInt(expectedMatch[1] ?? '1', 10);
77
+ const receivedMatch = line.match(/Received number of calls:\s*(\d+)/);
78
+ if (receivedMatch)
79
+ receivedCalls = parseInt(receivedMatch[1] ?? '0', 10);
80
+ }
81
+ return {
82
+ kind: 'mock_not_called',
83
+ testName: extractTestName(lines, startIndex),
84
+ details: {
85
+ callCount: { expected: expectedCalls, received: receivedCalls },
86
+ },
87
+ suggestedFix: 'Mock was never called - check if the code path that should call it is actually executed. Verify conditions/props trigger the expected behavior.',
88
+ };
89
+ }
90
+ /**
91
+ * Parse mock wrong arguments errors.
92
+ * Example:
93
+ * expect(jest.fn()).toHaveBeenCalledWith(...expected)
94
+ * Expected: "arg1", "arg2"
95
+ * Received: "arg1", "arg3"
96
+ */
97
+ function parseMockWrongArgs(lines, startIndex) {
98
+ let expected;
99
+ let received;
100
+ for (let i = startIndex; i < Math.min(lines.length, startIndex + 10); i++) {
101
+ const line = lines[i] ?? '';
102
+ const expectedMatch = line.match(/Expected:\s*(.+)/);
103
+ if (expectedMatch && !expected)
104
+ expected = expectedMatch[1]?.trim();
105
+ const receivedMatch = line.match(/Received:\s*(.+)/);
106
+ if (receivedMatch && !received)
107
+ received = receivedMatch[1]?.trim();
108
+ }
109
+ const details = {};
110
+ if (expected !== undefined)
111
+ details.expected = expected;
112
+ if (received !== undefined)
113
+ details.received = received;
114
+ return {
115
+ kind: 'mock_wrong_args',
116
+ testName: extractTestName(lines, startIndex),
117
+ details,
118
+ suggestedFix: `Mock was called with different arguments than expected. Update expected args to match actual: got ${received ?? 'unknown'}, expected ${expected ?? 'unknown'}`,
119
+ };
120
+ }
121
+ /**
122
+ * Parse import/module errors.
123
+ * Example:
124
+ * Cannot find module './SomeComponent'
125
+ */
126
+ function parseImportError(line, lines, index) {
127
+ const match = line.match(/Cannot find module ['"]([^'"]+)['"]/);
128
+ if (!match)
129
+ return null;
130
+ const modulePath = match[1] ?? 'unknown';
131
+ return {
132
+ kind: 'import_error',
133
+ testName: extractTestName(lines, index),
134
+ details: { missingImport: modulePath },
135
+ suggestedFix: `Add jest.mock('${modulePath}') or vi.mock('${modulePath}') at the top of the test file to mock this missing module`,
136
+ };
137
+ }
138
+ /**
139
+ * Parse undefined variable errors.
140
+ * Example:
141
+ * ReferenceError: someVar is not defined
142
+ */
143
+ function parseUndefinedVariable(line, lines, index) {
144
+ const match = line.match(/ReferenceError:\s*(\w+)\s+is not defined/);
145
+ if (!match)
146
+ return null;
147
+ const variableName = match[1] ?? 'unknown';
148
+ return {
149
+ kind: 'undefined_variable',
150
+ testName: extractTestName(lines, index),
151
+ details: { variableName },
152
+ suggestedFix: `Variable '${variableName}' is not defined. Import it from the appropriate module, or check for typos in the variable name.`,
153
+ };
154
+ }
155
+ /**
156
+ * Parse timeout errors.
157
+ * Example:
158
+ * Timeout - Async callback was not invoked within the 5000 ms timeout
159
+ */
160
+ function parseTimeout(line, lines, index) {
161
+ if (!/timeout/i.test(line))
162
+ return null;
163
+ return {
164
+ kind: 'timeout',
165
+ testName: extractTestName(lines, index),
166
+ details: {},
167
+ suggestedFix: 'Test timed out. Check if async operations complete properly, or if act() is needed around state updates. Consider increasing timeout or using waitFor() correctly.',
168
+ };
169
+ }
170
+ /**
171
+ * Parse type errors.
172
+ * Example:
173
+ * TypeError: Cannot read properties of undefined (reading 'map')
174
+ */
175
+ function parseTypeError(line, lines, index) {
176
+ const match = line.match(/TypeError:\s*(.+)/);
177
+ if (!match)
178
+ return null;
179
+ const stackTrace = match[1];
180
+ const details = {};
181
+ if (stackTrace !== undefined)
182
+ details.stackTrace = stackTrace;
183
+ return {
184
+ kind: 'type_error',
185
+ testName: extractTestName(lines, index),
186
+ details,
187
+ suggestedFix: 'Type error occurred. Check if props/data are correctly mocked and not undefined. Ensure mock return values have the expected shape.',
188
+ };
189
+ }
190
+ /**
191
+ * Parse test errors from Jest/Vitest output.
192
+ *
193
+ * @param jestOutput - Raw test runner output
194
+ * @returns Array of parsed errors with actionable information
195
+ */
196
+ export function parseTestErrors(jestOutput) {
197
+ const errors = [];
198
+ const lines = jestOutput.split('\n');
199
+ const seen = new Set();
200
+ for (let i = 0; i < lines.length; i++) {
201
+ const line = lines[i] ?? '';
202
+ const lineLower = line.toLowerCase();
203
+ // Skip empty lines
204
+ if (!line.trim())
205
+ continue;
206
+ let error = null;
207
+ // Check for import errors first (highest priority)
208
+ if (line.includes('Cannot find module')) {
209
+ error = parseImportError(line, lines, i);
210
+ }
211
+ // Check for undefined variable
212
+ else if (line.includes('ReferenceError') && line.includes('is not defined')) {
213
+ error = parseUndefinedVariable(line, lines, i);
214
+ }
215
+ // Check for type errors
216
+ else if (line.includes('TypeError:')) {
217
+ error = parseTypeError(line, lines, i);
218
+ }
219
+ // Check for timeout
220
+ else if (lineLower.includes('timeout') && (lineLower.includes('async') || lineLower.includes('callback'))) {
221
+ error = parseTimeout(line, lines, i);
222
+ }
223
+ // Check for mock wrong args (must come before mock not called since it contains 'toHaveBeenCalled')
224
+ else if (line.includes('toHaveBeenCalledWith')) {
225
+ error = parseMockWrongArgs(lines, i);
226
+ }
227
+ // Check for mock not called
228
+ else if (line.includes('toHaveBeenCalled') ||
229
+ (line.includes('Expected number of calls') && line.includes('>= 1'))) {
230
+ error = parseMockNotCalled(lines, i);
231
+ }
232
+ // Check for assertion mismatch (general case)
233
+ else if ((line.includes('expect(') && (line.includes(').toBe') || line.includes(').toEqual'))) ||
234
+ line.match(/^\s*Expected:/)) {
235
+ error = parseAssertionMismatch(lines, i);
236
+ }
237
+ if (error) {
238
+ // Deduplicate by test name and kind
239
+ const key = `${error.kind}:${error.testName}`;
240
+ if (!seen.has(key)) {
241
+ seen.add(key);
242
+ errors.push(error);
243
+ }
244
+ }
245
+ }
246
+ // If no specific errors found but output suggests failure, add unknown
247
+ if (errors.length === 0 && /FAIL|failed|Error:/i.test(jestOutput)) {
248
+ // Look for any error-like content
249
+ for (let i = 0; i < lines.length; i++) {
250
+ const line = lines[i] ?? '';
251
+ if (/Error:|FAIL|failed|✕|×/i.test(line) && line.trim().length > 10) {
252
+ errors.push({
253
+ kind: 'unknown',
254
+ testName: extractTestName(lines, i),
255
+ details: { stackTrace: line.trim() },
256
+ suggestedFix: 'Unknown error occurred. Review the test output and fix the issue based on the error message.',
257
+ });
258
+ break; // Only add one unknown error
259
+ }
260
+ }
261
+ }
262
+ return errors;
263
+ }
264
+ //# sourceMappingURL=errorParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorParser.js","sourceRoot":"","sources":["../../../src/core/retry/errorParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,SAAS,eAAe,CAAC,KAAe,EAAE,KAAa;IACrD,+BAA+B;IAC/B,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,4CAA4C;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACpE,IAAI,SAAS;YAAE,OAAO,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QAExD,yDAAyD;QACzD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACxD,IAAI,aAAa;YAAE,OAAO,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QAEhE,mCAAmC;QACnC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/C,IAAI,WAAW;YAAE,OAAO,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAC9D,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,sBAAsB,CAAC,KAAe,EAAE,UAAkB;IACjE,IAAI,QAA4B,CAAC;IACjC,IAAI,QAA4B,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE5B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACrD,IAAI,aAAa;YAAE,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAEvD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACrD,IAAI,aAAa;YAAE,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAEvD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM;IAC9D,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAElE,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACxD,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAExD,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC;QAC5C,OAAO;QACP,YAAY,EAAE,8BAA8B,QAAQ,IAAI,SAAS,OAAO,QAAQ,IAAI,SAAS,2DAA2D;KACzJ,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,KAAe,EAAE,UAAkB;IAC7D,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE5B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAChF,IAAI,aAAa;YAAE,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;QAEzE,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACtE,IAAI,aAAa;YAAE,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC;QAC5C,OAAO,EAAE;YACP,SAAS,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE;SAChE;QACD,YAAY,EAAE,iJAAiJ;KAChK,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,KAAe,EAAE,UAAkB;IAC7D,IAAI,QAA4B,CAAC;IACjC,IAAI,QAA4B,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE5B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACrD,IAAI,aAAa,IAAI,CAAC,QAAQ;YAAE,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAEpE,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACrD,IAAI,aAAa,IAAI,CAAC,QAAQ;YAAE,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACtE,CAAC;IAED,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACxD,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAExD,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC;QAC5C,OAAO;QACP,YAAY,EAAE,qGAAqG,QAAQ,IAAI,SAAS,cAAc,QAAQ,IAAI,SAAS,EAAE;KAC9K,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,IAAY,EAAE,KAAe,EAAE,KAAa;IACpE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAChE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAEzC,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;QACvC,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE;QACtC,YAAY,EAAE,kBAAkB,UAAU,kBAAkB,UAAU,4DAA4D;KACnI,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,sBAAsB,CAAC,IAAY,EAAE,KAAe,EAAE,KAAa;IAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACrE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAE3C,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;QACvC,OAAO,EAAE,EAAE,YAAY,EAAE;QACzB,YAAY,EAAE,aAAa,YAAY,mGAAmG;KAC3I,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,KAAe,EAAE,KAAa;IAChE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,OAAO;QACL,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;QACvC,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,oKAAoK;KACnL,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,KAAe,EAAE,KAAa;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC;IAE9D,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC;QACvC,OAAO;QACP,YAAY,EAAE,qIAAqI;KACpJ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAErC,mBAAmB;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAE3B,IAAI,KAAK,GAA2B,IAAI,CAAC;QAEzC,mDAAmD;QACnD,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;YACxC,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC3C,CAAC;QACD,+BAA+B;aAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC5E,KAAK,GAAG,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACjD,CAAC;QACD,wBAAwB;aACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACrC,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,oBAAoB;aACf,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YAC1G,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,oGAAoG;aAC/F,IAAI,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;YAC/C,KAAK,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,4BAA4B;aACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YACjC,CAAC,IAAI,CAAC,QAAQ,CAAC,0BAA0B,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAC9E,KAAK,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,8CAA8C;aACzC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;YACrF,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC;YACrC,KAAK,GAAG,sBAAsB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACV,oCAAoC;YACpC,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC9C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAClE,kCAAkC;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;gBACpE,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,SAAS;oBACf,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC;oBACnC,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE;oBACpC,YAAY,EAAE,8FAA8F;iBAC7G,CAAC,CAAC;gBACH,MAAM,CAAC,6BAA6B;YACtC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Feedback generator that creates LLM-friendly retry prompts from parsed errors.
3
+ * Outputs valid prompt text with prioritized, actionable fixes.
4
+ */
5
+ import type { RetryContext, RetryPrompt } from './types.js';
6
+ /**
7
+ * Generate a retry prompt from the context.
8
+ *
9
+ * @param context - The retry context with errors and previous test
10
+ * @returns A structured retry prompt, or null if no actionable retry possible
11
+ */
12
+ export declare function generateRetryPrompt(context: RetryContext): RetryPrompt | null;
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Feedback generator that creates LLM-friendly retry prompts from parsed errors.
3
+ * Outputs valid prompt text with prioritized, actionable fixes.
4
+ */
5
+ /** Maximum characters for generated prompt (roughly 500 tokens). */
6
+ const MAX_PROMPT_CHARS = 2000;
7
+ /**
8
+ * Get priority for an error kind.
9
+ */
10
+ function getErrorPriority(kind) {
11
+ switch (kind) {
12
+ case 'import_error':
13
+ case 'undefined_variable':
14
+ return 'critical';
15
+ case 'mock_not_called':
16
+ case 'mock_wrong_args':
17
+ case 'type_error':
18
+ return 'high';
19
+ case 'assertion_mismatch':
20
+ case 'timeout':
21
+ return 'medium';
22
+ default:
23
+ return 'medium';
24
+ }
25
+ }
26
+ /**
27
+ * Get focus area description for an error kind.
28
+ */
29
+ function getFocusArea(kind) {
30
+ switch (kind) {
31
+ case 'import_error':
32
+ return 'Add missing mock at the top of the file';
33
+ case 'undefined_variable':
34
+ return 'Fix missing import or variable declaration';
35
+ case 'mock_not_called':
36
+ return 'Ensure the code path triggers the expected function call';
37
+ case 'mock_wrong_args':
38
+ return 'Update mock expectations to match actual arguments';
39
+ case 'type_error':
40
+ return 'Fix undefined/null access by properly mocking data';
41
+ case 'assertion_mismatch':
42
+ return 'Update expected value or fix test setup';
43
+ case 'timeout':
44
+ return 'Fix async handling with proper await/act patterns';
45
+ default:
46
+ return 'Review and fix the error based on the message';
47
+ }
48
+ }
49
+ /**
50
+ * Format error details for the prompt.
51
+ */
52
+ function formatErrorDetails(error) {
53
+ const parts = [];
54
+ parts.push(`**Error Type:** ${error.kind.replace(/_/g, ' ')}`);
55
+ parts.push(`**Test:** ${error.testName}`);
56
+ if (error.details.expected !== undefined) {
57
+ parts.push(`**Expected:** ${error.details.expected}`);
58
+ }
59
+ if (error.details.received !== undefined) {
60
+ parts.push(`**Received:** ${error.details.received}`);
61
+ }
62
+ if (error.details.callCount !== undefined) {
63
+ parts.push(`**Expected calls:** ${error.details.callCount.expected}`);
64
+ parts.push(`**Received calls:** ${error.details.callCount.received}`);
65
+ }
66
+ if (error.details.missingImport !== undefined) {
67
+ parts.push(`**Missing module:** ${error.details.missingImport}`);
68
+ }
69
+ if (error.details.variableName !== undefined) {
70
+ parts.push(`**Undefined variable:** ${error.details.variableName}`);
71
+ }
72
+ return parts.join('\n');
73
+ }
74
+ /**
75
+ * Sort errors by priority (most actionable first).
76
+ */
77
+ function sortByPriority(errors) {
78
+ const priorityOrder = { critical: 0, high: 1, medium: 2 };
79
+ return [...errors].sort((a, b) => {
80
+ const pa = priorityOrder[getErrorPriority(a.kind)];
81
+ const pb = priorityOrder[getErrorPriority(b.kind)];
82
+ return pa - pb;
83
+ });
84
+ }
85
+ /**
86
+ * Generate a retry prompt from the context.
87
+ *
88
+ * @param context - The retry context with errors and previous test
89
+ * @returns A structured retry prompt, or null if no actionable retry possible
90
+ */
91
+ export function generateRetryPrompt(context) {
92
+ // Return null if we've exceeded max attempts
93
+ if (context.attempt >= context.maxAttempts) {
94
+ return null;
95
+ }
96
+ // Return null if no errors provided
97
+ if (context.errors.length === 0) {
98
+ return null;
99
+ }
100
+ // Sort errors by priority and get the most actionable one
101
+ const sortedErrors = sortByPriority(context.errors);
102
+ const primaryError = sortedErrors[0];
103
+ // Return null if all errors are unknown (can't provide actionable feedback)
104
+ if (primaryError === undefined) {
105
+ return null;
106
+ }
107
+ if (primaryError.kind === 'unknown' && sortedErrors.every(e => e.kind === 'unknown')) {
108
+ return null;
109
+ }
110
+ // If primary is unknown but there are other errors, use the first non-unknown
111
+ const actionableError = primaryError.kind === 'unknown'
112
+ ? sortedErrors.find(e => e.kind !== 'unknown') ?? primaryError
113
+ : primaryError;
114
+ const priority = getErrorPriority(actionableError.kind);
115
+ const focusArea = getFocusArea(actionableError.kind);
116
+ // Build the prompt
117
+ const promptParts = [];
118
+ promptParts.push(`## RETRY ATTEMPT ${context.attempt + 1}/${context.maxAttempts}`);
119
+ promptParts.push('');
120
+ promptParts.push('Your previous test failed with the following error:');
121
+ promptParts.push('');
122
+ promptParts.push(formatErrorDetails(actionableError));
123
+ promptParts.push('');
124
+ promptParts.push('## REQUIRED FIX');
125
+ promptParts.push(actionableError.suggestedFix);
126
+ promptParts.push('');
127
+ promptParts.push('## FOCUS AREA');
128
+ promptParts.push(focusArea);
129
+ promptParts.push('');
130
+ // Include other errors as context if there are more
131
+ if (sortedErrors.length > 1) {
132
+ const otherErrors = sortedErrors.slice(1, 4); // Max 3 additional errors
133
+ if (otherErrors.length > 0) {
134
+ promptParts.push('## ADDITIONAL ERRORS (fix after primary)');
135
+ for (const err of otherErrors) {
136
+ promptParts.push(`- ${err.kind.replace(/_/g, ' ')}: ${err.suggestedFix.slice(0, 100)}`);
137
+ }
138
+ promptParts.push('');
139
+ }
140
+ }
141
+ promptParts.push('## ORIGINAL TEST (with error)');
142
+ promptParts.push('```');
143
+ // Truncate test if needed to stay under limit
144
+ let testContent = context.generatedTest;
145
+ const headerLength = promptParts.join('\n').length + 100; // Buffer for closing
146
+ const maxTestChars = MAX_PROMPT_CHARS - headerLength;
147
+ if (testContent.length > maxTestChars) {
148
+ testContent = testContent.slice(0, maxTestChars - 50) + '\n// ... (truncated)';
149
+ }
150
+ promptParts.push(testContent);
151
+ promptParts.push('```');
152
+ promptParts.push('');
153
+ promptParts.push('## INSTRUCTIONS');
154
+ promptParts.push('1. Fix ONLY the identified error');
155
+ promptParts.push('2. Do NOT change unrelated parts of the test');
156
+ promptParts.push('3. Output the complete corrected test file');
157
+ const prompt = promptParts.join('\n');
158
+ return {
159
+ prompt,
160
+ priority,
161
+ focusArea,
162
+ };
163
+ }
164
+ //# sourceMappingURL=feedbackGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedbackGenerator.js","sourceRoot":"","sources":["../../../src/core/retry/feedbackGenerator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export type { ErrorKind, ErrorDetails, ParsedTestError, RetryPriority, RetryContext, RetryPrompt, } from './types.js';
2
+ export { parseTestErrors } from './errorParser.js';
3
+ export { generateRetryPrompt } from './feedbackGenerator.js';
@@ -0,0 +1,3 @@
1
+ export { parseTestErrors } from './errorParser.js';
2
+ export { generateRetryPrompt } from './feedbackGenerator.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/retry/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Types for error parsing and retry feedback generation.
3
+ */
4
+ /** Kind of test error detected. */
5
+ export type ErrorKind = 'assertion_mismatch' | 'mock_not_called' | 'mock_wrong_args' | 'undefined_variable' | 'import_error' | 'timeout' | 'type_error' | 'unknown';
6
+ /** Details extracted from the error. */
7
+ export type ErrorDetails = {
8
+ expected?: string;
9
+ received?: string;
10
+ callCount?: {
11
+ expected: number;
12
+ received: number;
13
+ };
14
+ missingImport?: string;
15
+ variableName?: string;
16
+ stackTrace?: string;
17
+ };
18
+ /** A parsed test error with actionable information. */
19
+ export type ParsedTestError = {
20
+ kind: ErrorKind;
21
+ testName: string;
22
+ details: ErrorDetails;
23
+ suggestedFix: string;
24
+ };
25
+ /** Priority of a retry prompt. */
26
+ export type RetryPriority = 'critical' | 'high' | 'medium';
27
+ /** Context for generating a retry prompt. */
28
+ export type RetryContext = {
29
+ originalPrompt: string;
30
+ generatedTest: string;
31
+ errors: ParsedTestError[];
32
+ attempt: number;
33
+ maxAttempts: number;
34
+ };
35
+ /** A generated retry prompt. */
36
+ export type RetryPrompt = {
37
+ prompt: string;
38
+ priority: RetryPriority;
39
+ focusArea: string;
40
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types for error parsing and retry feedback generation.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/retry/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Retry enhancement utilities.
3
+ * Provides smarter retry prompts based on parsed test errors.
4
+ */
5
+ import { type ParsedTestError, type RetryPrompt } from '../retry/index.js';
6
+ export type RetryEnhanceOptions = {
7
+ originalPrompt: string;
8
+ generatedTest: string;
9
+ testOutput: string;
10
+ attempt: number;
11
+ maxAttempts: number;
12
+ enabled?: boolean;
13
+ };
14
+ export type RetryEnhanceResult = {
15
+ hasActionableErrors: boolean;
16
+ retryPrompt: RetryPrompt | null;
17
+ parsedErrors: ParsedTestError[];
18
+ enabled: boolean;
19
+ };
20
+ /**
21
+ * Enhance retry feedback using parsed test errors.
22
+ * Generates a smarter retry prompt with specific fixes.
23
+ *
24
+ * @param opts - Retry options
25
+ * @returns Enhanced retry result with prompt and parsed errors
26
+ */
27
+ export declare function enhanceRetryFeedback(opts: RetryEnhanceOptions): RetryEnhanceResult;
28
+ /**
29
+ * Format parsed errors for feedback section in existing prompt format.
30
+ * This provides backward-compatible integration with existing feedback mechanism.
31
+ */
32
+ export declare function formatErrorsForFeedback(errors: ParsedTestError[]): string;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Retry enhancement utilities.
3
+ * Provides smarter retry prompts based on parsed test errors.
4
+ */
5
+ import { parseTestErrors, generateRetryPrompt } from '../retry/index.js';
6
+ /**
7
+ * Enhance retry feedback using parsed test errors.
8
+ * Generates a smarter retry prompt with specific fixes.
9
+ *
10
+ * @param opts - Retry options
11
+ * @returns Enhanced retry result with prompt and parsed errors
12
+ */
13
+ export function enhanceRetryFeedback(opts) {
14
+ const enabled = opts.enabled ?? true;
15
+ if (!enabled) {
16
+ return {
17
+ hasActionableErrors: false,
18
+ retryPrompt: null,
19
+ parsedErrors: [],
20
+ enabled: false,
21
+ };
22
+ }
23
+ // Parse errors from test output
24
+ const parsedErrors = parseTestErrors(opts.testOutput);
25
+ // Generate retry prompt if we have actionable errors
26
+ const retryPrompt = generateRetryPrompt({
27
+ originalPrompt: opts.originalPrompt,
28
+ generatedTest: opts.generatedTest,
29
+ errors: parsedErrors,
30
+ attempt: opts.attempt,
31
+ maxAttempts: opts.maxAttempts,
32
+ });
33
+ // Check if we have actionable errors (not all unknown)
34
+ const hasActionableErrors = parsedErrors.some(e => e.kind !== 'unknown');
35
+ return {
36
+ hasActionableErrors,
37
+ retryPrompt,
38
+ parsedErrors,
39
+ enabled: true,
40
+ };
41
+ }
42
+ /**
43
+ * Format parsed errors for feedback section in existing prompt format.
44
+ * This provides backward-compatible integration with existing feedback mechanism.
45
+ */
46
+ export function formatErrorsForFeedback(errors) {
47
+ if (errors.length === 0) {
48
+ return '';
49
+ }
50
+ const lines = [];
51
+ lines.push('## PARSED ERRORS (prioritized fixes)');
52
+ for (const error of errors.slice(0, 5)) {
53
+ lines.push(`- ${error.kind}: ${error.suggestedFix.slice(0, 100)}`);
54
+ }
55
+ lines.push('');
56
+ return lines.join('\n');
57
+ }
58
+ //# sourceMappingURL=retryEnhancer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retryEnhancer.js","sourceRoot":"","sources":["../../../src/core/testRunner/retryEnhancer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAA0C,MAAM,mBAAmB,CAAC;AAkBjH;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAyB;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;IAErC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,mBAAmB,EAAE,KAAK;YAC1B,WAAW,EAAE,IAAI;YACjB,YAAY,EAAE,EAAE;YAChB,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;IAED,gCAAgC;IAChC,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEtD,qDAAqD;IACrD,MAAM,WAAW,GAAG,mBAAmB,CAAC;QACtC,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC;IAEH,uDAAuD;IACvD,MAAM,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAEzE,OAAO;QACL,mBAAmB;QACnB,WAAW;QACX,YAAY;QACZ,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAyB;IAC/D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IAEnD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Post-generation validator that verifies generated tests cover all identified behaviors.
3
+ * Returns structured validation result with specific rejection codes.
4
+ *
5
+ * Static analysis only - does NOT execute the test.
6
+ */
7
+ import type { ComponentAnalysis } from '../analysis/types.js';
8
+ import type { ValidationResult } from './types.js';
9
+ /**
10
+ * Verify that generated test adequately covers the analyzed component.
11
+ *
12
+ * @param analysis - Component analysis from AST extraction
13
+ * @param generatedTestContent - The generated test file content
14
+ * @returns ValidationResult with coverage details and any rejections
15
+ */
16
+ export declare function verifyCoverage(analysis: ComponentAnalysis, generatedTestContent: string): ValidationResult;