@auto-engineer/component-implementor-react 1.107.0 → 1.109.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 (96) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +6 -6
  3. package/.turbo/turbo-type-check.log +1 -1
  4. package/CHANGELOG.md +69 -0
  5. package/dist/src/commands/implement-component.d.ts +3 -0
  6. package/dist/src/commands/implement-component.d.ts.map +1 -1
  7. package/dist/src/commands/implement-component.js +11 -33
  8. package/dist/src/commands/implement-component.js.map +1 -1
  9. package/dist/src/commands/implement-component.test.js +6 -66
  10. package/dist/src/commands/implement-component.test.js.map +1 -1
  11. package/dist/src/pipeline/run-pipeline.d.ts +5 -25
  12. package/dist/src/pipeline/run-pipeline.d.ts.map +1 -1
  13. package/dist/src/pipeline/run-pipeline.js +17 -47
  14. package/dist/src/pipeline/run-pipeline.js.map +1 -1
  15. package/dist/src/pipeline/run-pipeline.test.js +29 -132
  16. package/dist/src/pipeline/run-pipeline.test.js.map +1 -1
  17. package/dist/src/pipeline/steps/fix-from-feedback.d.ts +4 -0
  18. package/dist/src/pipeline/steps/fix-from-feedback.d.ts.map +1 -0
  19. package/dist/src/pipeline/steps/fix-from-feedback.js +94 -0
  20. package/dist/src/pipeline/steps/fix-from-feedback.js.map +1 -0
  21. package/dist/src/pipeline/steps/generate-component.test.js +1 -5
  22. package/dist/src/pipeline/steps/generate-component.test.js.map +1 -1
  23. package/dist/src/pipeline/steps/generate-story.test.js +1 -5
  24. package/dist/src/pipeline/steps/generate-story.test.js.map +1 -1
  25. package/dist/src/pipeline/steps/generate-test.test.js +1 -5
  26. package/dist/src/pipeline/steps/generate-test.test.js.map +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +3 -3
  29. package/src/commands/implement-component.test.ts +6 -66
  30. package/src/commands/implement-component.ts +16 -47
  31. package/src/pipeline/run-pipeline.test.ts +32 -141
  32. package/src/pipeline/run-pipeline.ts +22 -74
  33. package/src/pipeline/steps/fix-from-feedback.ts +105 -0
  34. package/src/pipeline/steps/generate-component.test.ts +1 -5
  35. package/src/pipeline/steps/generate-story.test.ts +1 -5
  36. package/src/pipeline/steps/generate-test.test.ts +1 -5
  37. package/dist/src/pipeline/steps/lint-fix-loop.d.ts +0 -4
  38. package/dist/src/pipeline/steps/lint-fix-loop.d.ts.map +0 -1
  39. package/dist/src/pipeline/steps/lint-fix-loop.js +0 -46
  40. package/dist/src/pipeline/steps/lint-fix-loop.js.map +0 -1
  41. package/dist/src/pipeline/steps/lint-fix-loop.test.d.ts +0 -2
  42. package/dist/src/pipeline/steps/lint-fix-loop.test.d.ts.map +0 -1
  43. package/dist/src/pipeline/steps/lint-fix-loop.test.js +0 -136
  44. package/dist/src/pipeline/steps/lint-fix-loop.test.js.map +0 -1
  45. package/dist/src/pipeline/steps/story-fix-loop.d.ts +0 -4
  46. package/dist/src/pipeline/steps/story-fix-loop.d.ts.map +0 -1
  47. package/dist/src/pipeline/steps/story-fix-loop.js +0 -35
  48. package/dist/src/pipeline/steps/story-fix-loop.js.map +0 -1
  49. package/dist/src/pipeline/steps/story-fix-loop.test.d.ts +0 -2
  50. package/dist/src/pipeline/steps/story-fix-loop.test.d.ts.map +0 -1
  51. package/dist/src/pipeline/steps/story-fix-loop.test.js +0 -98
  52. package/dist/src/pipeline/steps/story-fix-loop.test.js.map +0 -1
  53. package/dist/src/pipeline/steps/storybook-test.d.ts +0 -3
  54. package/dist/src/pipeline/steps/storybook-test.d.ts.map +0 -1
  55. package/dist/src/pipeline/steps/storybook-test.js +0 -22
  56. package/dist/src/pipeline/steps/storybook-test.js.map +0 -1
  57. package/dist/src/pipeline/steps/storybook-test.test.d.ts +0 -2
  58. package/dist/src/pipeline/steps/storybook-test.test.d.ts.map +0 -1
  59. package/dist/src/pipeline/steps/storybook-test.test.js +0 -70
  60. package/dist/src/pipeline/steps/storybook-test.test.js.map +0 -1
  61. package/dist/src/pipeline/steps/test-fix-loop.d.ts +0 -4
  62. package/dist/src/pipeline/steps/test-fix-loop.d.ts.map +0 -1
  63. package/dist/src/pipeline/steps/test-fix-loop.js +0 -45
  64. package/dist/src/pipeline/steps/test-fix-loop.js.map +0 -1
  65. package/dist/src/pipeline/steps/test-fix-loop.test.d.ts +0 -2
  66. package/dist/src/pipeline/steps/test-fix-loop.test.d.ts.map +0 -1
  67. package/dist/src/pipeline/steps/test-fix-loop.test.js +0 -172
  68. package/dist/src/pipeline/steps/test-fix-loop.test.js.map +0 -1
  69. package/dist/src/pipeline/steps/type-fix-loop.d.ts +0 -4
  70. package/dist/src/pipeline/steps/type-fix-loop.d.ts.map +0 -1
  71. package/dist/src/pipeline/steps/type-fix-loop.js +0 -44
  72. package/dist/src/pipeline/steps/type-fix-loop.js.map +0 -1
  73. package/dist/src/pipeline/steps/type-fix-loop.test.d.ts +0 -2
  74. package/dist/src/pipeline/steps/type-fix-loop.test.d.ts.map +0 -1
  75. package/dist/src/pipeline/steps/type-fix-loop.test.js +0 -116
  76. package/dist/src/pipeline/steps/type-fix-loop.test.js.map +0 -1
  77. package/dist/src/pipeline/steps/visual-test.d.ts +0 -3
  78. package/dist/src/pipeline/steps/visual-test.d.ts.map +0 -1
  79. package/dist/src/pipeline/steps/visual-test.js +0 -4
  80. package/dist/src/pipeline/steps/visual-test.js.map +0 -1
  81. package/dist/src/pipeline/steps/visual-test.test.d.ts +0 -2
  82. package/dist/src/pipeline/steps/visual-test.test.d.ts.map +0 -1
  83. package/dist/src/pipeline/steps/visual-test.test.js +0 -9
  84. package/dist/src/pipeline/steps/visual-test.test.js.map +0 -1
  85. package/src/pipeline/steps/lint-fix-loop.test.ts +0 -176
  86. package/src/pipeline/steps/lint-fix-loop.ts +0 -61
  87. package/src/pipeline/steps/story-fix-loop.test.ts +0 -127
  88. package/src/pipeline/steps/story-fix-loop.ts +0 -48
  89. package/src/pipeline/steps/storybook-test.test.ts +0 -86
  90. package/src/pipeline/steps/storybook-test.ts +0 -27
  91. package/src/pipeline/steps/test-fix-loop.test.ts +0 -205
  92. package/src/pipeline/steps/test-fix-loop.ts +0 -57
  93. package/src/pipeline/steps/type-fix-loop.test.ts +0 -149
  94. package/src/pipeline/steps/type-fix-loop.ts +0 -56
  95. package/src/pipeline/steps/visual-test.test.ts +0 -10
  96. package/src/pipeline/steps/visual-test.ts +0 -5
package/package.json CHANGED
@@ -6,13 +6,13 @@
6
6
  "dependencies": {
7
7
  "ai": "^6.0.0",
8
8
  "debug": "^4.4.1",
9
- "@auto-engineer/message-bus": "1.107.0",
10
- "@auto-engineer/model-factory": "1.107.0"
9
+ "@auto-engineer/message-bus": "1.109.0",
10
+ "@auto-engineer/model-factory": "1.109.0"
11
11
  },
12
12
  "devDependencies": {
13
13
  "vitest": "^3.2.1"
14
14
  },
15
- "version": "1.107.0",
15
+ "version": "1.109.0",
16
16
  "publishConfig": {
17
17
  "access": "public"
18
18
  },
@@ -69,11 +69,6 @@ describe('implement-component', () => {
69
69
  vi.mocked(runPipeline).mockResolvedValue({
70
70
  success: true,
71
71
  llmCalls: 4,
72
- fixIterations: 1,
73
- typeFixIterations: 0,
74
- testFixIterations: 0,
75
- lintFixIterations: 0,
76
- storyFixIterations: 0,
77
72
  });
78
73
 
79
74
  const result = await handleImplementComponent(makeCommand());
@@ -92,6 +87,9 @@ describe('implement-component', () => {
92
87
  ],
93
88
  targetDir: '/project/client',
94
89
  job: makeCommand().data.job,
90
+ llmCalls: expect.any(Number),
91
+ attemptNumber: 0,
92
+ intermediate: true,
95
93
  },
96
94
  timestamp: expect.any(Date),
97
95
  requestId: 'req-1',
@@ -107,11 +105,6 @@ describe('implement-component', () => {
107
105
  success: false,
108
106
  error: 'Step "Type Fix Loop" failed: errors remain',
109
107
  llmCalls: 5,
110
- fixIterations: 3,
111
- typeFixIterations: 0,
112
- testFixIterations: 0,
113
- lintFixIterations: 0,
114
- storyFixIterations: 0,
115
108
  });
116
109
 
117
110
  const result = await handleImplementComponent(makeCommand());
@@ -134,11 +127,6 @@ describe('implement-component', () => {
134
127
  vi.mocked(runPipeline).mockResolvedValue({
135
128
  success: true,
136
129
  llmCalls: 3,
137
- fixIterations: 0,
138
- typeFixIterations: 0,
139
- testFixIterations: 0,
140
- lintFixIterations: 0,
141
- storyFixIterations: 0,
142
130
  });
143
131
 
144
132
  const command = makeCommand({
@@ -195,11 +183,6 @@ describe('implement-component', () => {
195
183
  vi.mocked(runPipeline).mockResolvedValue({
196
184
  success: true,
197
185
  llmCalls: 4,
198
- fixIterations: 1,
199
- typeFixIterations: 0,
200
- testFixIterations: 0,
201
- lintFixIterations: 0,
202
- storyFixIterations: 0,
203
186
  });
204
187
 
205
188
  const command = {
@@ -237,11 +220,6 @@ describe('implement-component', () => {
237
220
  vi.mocked(runPipeline).mockResolvedValue({
238
221
  success: true,
239
222
  llmCalls: 2,
240
- fixIterations: 0,
241
- typeFixIterations: 0,
242
- testFixIterations: 0,
243
- lintFixIterations: 0,
244
- storyFixIterations: 0,
245
223
  });
246
224
 
247
225
  const command = {
@@ -283,11 +261,6 @@ describe('implement-component', () => {
283
261
  vi.mocked(runPipeline).mockResolvedValue({
284
262
  success: true,
285
263
  llmCalls: 4,
286
- fixIterations: 0,
287
- typeFixIterations: 0,
288
- testFixIterations: 0,
289
- lintFixIterations: 0,
290
- storyFixIterations: 0,
291
264
  });
292
265
 
293
266
  const command = makeCommand({
@@ -323,6 +296,9 @@ describe('implement-component', () => {
323
296
  ]),
324
297
  targetDir: '/project/client',
325
298
  job: command.data.job,
299
+ llmCalls: expect.any(Number),
300
+ attemptNumber: 0,
301
+ intermediate: true,
326
302
  },
327
303
  timestamp: expect.any(Date),
328
304
  requestId: 'req-1',
@@ -335,11 +311,6 @@ describe('implement-component', () => {
335
311
  vi.mocked(runPipeline).mockResolvedValue({
336
312
  success: true,
337
313
  llmCalls: 2,
338
- fixIterations: 0,
339
- typeFixIterations: 0,
340
- testFixIterations: 0,
341
- lintFixIterations: 0,
342
- storyFixIterations: 0,
343
314
  });
344
315
 
345
316
  await handleImplementComponent(makeCommand());
@@ -360,7 +331,6 @@ describe('implement-component', () => {
360
331
  },
361
332
  isModify: false,
362
333
  llmCalls: 0,
363
- fixIterations: 0,
364
334
  }),
365
335
  );
366
336
  });
@@ -377,11 +347,6 @@ describe('implement-component', () => {
377
347
  vi.mocked(runPipeline).mockResolvedValue({
378
348
  success: true,
379
349
  llmCalls: 0,
380
- fixIterations: 0,
381
- typeFixIterations: 0,
382
- testFixIterations: 0,
383
- lintFixIterations: 0,
384
- storyFixIterations: 0,
385
350
  });
386
351
 
387
352
  const result = await commandHandler.handle(makeCommand());
@@ -396,11 +361,6 @@ describe('implement-component', () => {
396
361
  vi.mocked(runPipeline).mockResolvedValue({
397
362
  success: true,
398
363
  llmCalls: 0,
399
- fixIterations: 0,
400
- typeFixIterations: 0,
401
- testFixIterations: 0,
402
- lintFixIterations: 0,
403
- storyFixIterations: 0,
404
364
  });
405
365
 
406
366
  const command = makeCommand({
@@ -439,11 +399,6 @@ describe('implement-component', () => {
439
399
  vi.mocked(runPipeline).mockResolvedValue({
440
400
  success: true,
441
401
  llmCalls: 1,
442
- fixIterations: 0,
443
- typeFixIterations: 0,
444
- testFixIterations: 0,
445
- lintFixIterations: 0,
446
- storyFixIterations: 0,
447
402
  });
448
403
 
449
404
  const command = makeCommand({
@@ -481,11 +436,6 @@ describe('implement-component', () => {
481
436
  vi.mocked(runPipeline).mockResolvedValue({
482
437
  success: true,
483
438
  llmCalls: 1,
484
- fixIterations: 0,
485
- typeFixIterations: 0,
486
- testFixIterations: 0,
487
- lintFixIterations: 0,
488
- storyFixIterations: 0,
489
439
  });
490
440
 
491
441
  const command = makeCommand({
@@ -522,11 +472,6 @@ describe('implement-component', () => {
522
472
  vi.mocked(runPipeline).mockResolvedValue({
523
473
  success: false,
524
474
  llmCalls: 0,
525
- fixIterations: 0,
526
- typeFixIterations: 0,
527
- testFixIterations: 0,
528
- lintFixIterations: 0,
529
- storyFixIterations: 0,
530
475
  });
531
476
 
532
477
  const result = await handleImplementComponent(makeCommand());
@@ -566,11 +511,6 @@ describe('implement-component', () => {
566
511
  vi.mocked(runPipeline).mockResolvedValue({
567
512
  success: true,
568
513
  llmCalls: 0,
569
- fixIterations: 0,
570
- typeFixIterations: 0,
571
- testFixIterations: 0,
572
- lintFixIterations: 0,
573
- storyFixIterations: 0,
574
514
  });
575
515
 
576
516
  const command = makeCommand({
@@ -67,6 +67,9 @@ export type ComponentImplementedEvent = Event<
67
67
  filesCreated: string[];
68
68
  targetDir: string;
69
69
  job: ComponentJob;
70
+ llmCalls: number;
71
+ attemptNumber: number;
72
+ intermediate?: boolean;
70
73
  }
71
74
  >;
72
75
 
@@ -130,37 +133,13 @@ function buildPipelineConfig(): PipelineConfig {
130
133
  process.env.IMPL_MODEL ??
131
134
  process.env.CUSTOM_PROVIDER_DEFAULT_MODEL ??
132
135
  '',
133
- typeFixer:
134
- process.env.STEP_TYPE_FIXER_MODEL ??
135
- process.env.IMPL_FIXER_MODEL ??
136
- process.env.IMPL_MODEL ??
137
- process.env.CUSTOM_PROVIDER_DEFAULT_MODEL ??
138
- '',
139
- testFixer:
140
- process.env.STEP_TEST_FIXER_MODEL ??
141
- process.env.IMPL_FIXER_MODEL ??
142
- process.env.IMPL_MODEL ??
143
- process.env.CUSTOM_PROVIDER_DEFAULT_MODEL ??
144
- '',
145
- lintFixer:
146
- process.env.STEP_LINT_FIXER_MODEL ??
147
- process.env.IMPL_FIXER_MODEL ??
148
- process.env.IMPL_MODEL ??
149
- process.env.CUSTOM_PROVIDER_DEFAULT_MODEL ??
150
- '',
151
- storyFixer:
152
- process.env.STEP_STORY_FIXER_MODEL ??
136
+ fixer:
137
+ process.env.STEP_FIXER_MODEL ??
153
138
  process.env.IMPL_FIXER_MODEL ??
154
139
  process.env.IMPL_MODEL ??
155
140
  process.env.CUSTOM_PROVIDER_DEFAULT_MODEL ??
156
141
  '',
157
142
  },
158
- maxTypeFixIterations: 3,
159
- maxTestFixIterations: 3,
160
- maxLintFixIterations: 2,
161
- maxStoryFixIterations: 2,
162
- enableStorybookTest: process.env.ENABLE_STORYBOOK_TEST === 'true',
163
- enableVisualTest: process.env.ENABLE_VISUAL_TEST === 'true',
164
143
  };
165
144
  }
166
145
 
@@ -169,10 +148,7 @@ function createPipelineModels(): PipelineModels {
169
148
  return {
170
149
  generateTest: model,
171
150
  generateComponent: model,
172
- typeFixer: model,
173
- testFixer: model,
174
- lintFixer: model,
175
- storyFixer: model,
151
+ fixer: model,
176
152
  };
177
153
  }
178
154
 
@@ -209,6 +185,9 @@ export async function handleImplementComponent(
209
185
 
210
186
  await mkdir(path.dirname(testPath), { recursive: true });
211
187
 
188
+ const attemptNumber = command.data.context?.attemptNumber ?? 0;
189
+ const errorFeedback = command.data.context?.previousOutputs;
190
+
212
191
  const ctx: PipelineContext = {
213
192
  componentName,
214
193
  componentPath,
@@ -225,11 +204,8 @@ export async function handleImplementComponent(
225
204
  isModify,
226
205
  storyVariants: payload.storyVariants,
227
206
  llmCalls: 0,
228
- fixIterations: 0,
229
- typeFixIterations: 0,
230
- testFixIterations: 0,
231
- lintFixIterations: 0,
232
- storyFixIterations: 0,
207
+ errorFeedback,
208
+ attemptNumber,
233
209
  };
234
210
 
235
211
  const config = buildPipelineConfig();
@@ -240,12 +216,7 @@ export async function handleImplementComponent(
240
216
  const result = await runPipeline(steps, ctx);
241
217
 
242
218
  if (!result.success) {
243
- debug(
244
- 'Pipeline failed: %s (LLM calls: %d, fix iterations: %d)',
245
- result.error,
246
- result.llmCalls,
247
- result.fixIterations,
248
- );
219
+ debug('Pipeline failed: %s (LLM calls: %d)', result.error, result.llmCalls);
249
220
  return {
250
221
  type: 'ComponentImplementationFailed',
251
222
  data: { error: result.error ?? 'Pipeline failed', name: componentName },
@@ -255,12 +226,7 @@ export async function handleImplementComponent(
255
226
  };
256
227
  }
257
228
 
258
- debug(
259
- 'Pipeline succeeded for %s (LLM calls: %d, fix iterations: %d)',
260
- componentName,
261
- result.llmCalls,
262
- result.fixIterations,
263
- );
229
+ debug('Pipeline succeeded for %s (LLM calls: %d)', componentName, result.llmCalls);
264
230
 
265
231
  return {
266
232
  type: 'ComponentImplemented',
@@ -272,6 +238,9 @@ export async function handleImplementComponent(
272
238
  filesCreated: [testPath, componentPath, storyPath],
273
239
  targetDir,
274
240
  job,
241
+ llmCalls: result.llmCalls,
242
+ attemptNumber,
243
+ intermediate: true,
275
244
  },
276
245
  timestamp: new Date(),
277
246
  requestId: command.requestId,
@@ -7,26 +7,11 @@ vi.mock('./steps/generate-test', () => ({
7
7
  vi.mock('./steps/generate-component', () => ({
8
8
  generateComponentStep: vi.fn(async () => ({ success: true })),
9
9
  }));
10
- vi.mock('./steps/type-fix-loop', () => ({
11
- typeFixLoop: vi.fn(async () => ({ success: true })),
12
- }));
13
- vi.mock('./steps/test-fix-loop', () => ({
14
- testFixLoop: vi.fn(async () => ({ success: true })),
15
- }));
16
- vi.mock('./steps/lint-fix-loop', () => ({
17
- lintFixLoop: vi.fn(async () => ({ success: true })),
18
- }));
19
10
  vi.mock('./steps/generate-story', () => ({
20
11
  generateStoryStep: vi.fn(async () => ({ success: true })),
21
12
  }));
22
- vi.mock('./steps/story-fix-loop', () => ({
23
- storyFixLoop: vi.fn(async () => ({ success: true })),
24
- }));
25
- vi.mock('./steps/storybook-test', () => ({
26
- storybookTestStep: vi.fn(async () => ({ success: true })),
27
- }));
28
- vi.mock('./steps/visual-test', () => ({
29
- visualTestStep: vi.fn(async () => ({ success: true })),
13
+ vi.mock('./steps/fix-from-feedback', () => ({
14
+ fixFromFeedbackStep: vi.fn(async () => ({ success: true })),
30
15
  }));
31
16
 
32
17
  import {
@@ -37,15 +22,10 @@ import {
37
22
  type PipelineStep,
38
23
  runPipeline,
39
24
  } from './run-pipeline';
25
+ import { fixFromFeedbackStep } from './steps/fix-from-feedback';
40
26
  import { generateComponentStep } from './steps/generate-component';
41
27
  import { generateStoryStep } from './steps/generate-story';
42
28
  import { generateTestStep } from './steps/generate-test';
43
- import { lintFixLoop } from './steps/lint-fix-loop';
44
- import { storyFixLoop } from './steps/story-fix-loop';
45
- import { storybookTestStep } from './steps/storybook-test';
46
- import { testFixLoop } from './steps/test-fix-loop';
47
- import { typeFixLoop } from './steps/type-fix-loop';
48
- import { visualTestStep } from './steps/visual-test';
49
29
 
50
30
  afterEach(() => {
51
31
  vi.clearAllMocks();
@@ -64,19 +44,11 @@ function makeCtx(overrides: Partial<PipelineContext> = {}): PipelineContext {
64
44
  composes: [],
65
45
  isModify: false,
66
46
  llmCalls: 0,
67
- fixIterations: 0,
68
- typeFixIterations: 0,
69
- testFixIterations: 0,
70
- lintFixIterations: 0,
71
- storyFixIterations: 0,
47
+ attemptNumber: 0,
72
48
  ...overrides,
73
49
  };
74
50
  }
75
51
 
76
- function successStep(name: string): PipelineStep {
77
- return { name, run: async () => ({ success: true }) };
78
- }
79
-
80
52
  function failStep(name: string, error: string): PipelineStep {
81
53
  return { name, run: async () => ({ success: false, error }) };
82
54
  }
@@ -113,11 +85,6 @@ describe('runPipeline', () => {
113
85
  expect(result).toEqual({
114
86
  success: true,
115
87
  llmCalls: 0,
116
- fixIterations: 0,
117
- typeFixIterations: 0,
118
- testFixIterations: 0,
119
- lintFixIterations: 0,
120
- storyFixIterations: 0,
121
88
  });
122
89
  expect(executionOrder).toEqual(['A', 'B', 'C']);
123
90
  });
@@ -148,11 +115,6 @@ describe('runPipeline', () => {
148
115
  success: false,
149
116
  error: 'Step "Step B" failed: something broke',
150
117
  llmCalls: 0,
151
- fixIterations: 0,
152
- typeFixIterations: 0,
153
- testFixIterations: 0,
154
- lintFixIterations: 0,
155
- storyFixIterations: 0,
156
118
  });
157
119
  expect(executionOrder).toEqual(['A']);
158
120
  });
@@ -163,34 +125,24 @@ describe('runPipeline', () => {
163
125
  expect(result).toEqual({
164
126
  success: true,
165
127
  llmCalls: 0,
166
- fixIterations: 0,
167
- typeFixIterations: 0,
168
- testFixIterations: 0,
169
- lintFixIterations: 0,
170
- storyFixIterations: 0,
171
128
  });
172
129
  });
173
130
 
174
- it('reports accumulated llmCalls and fixIterations from context', async () => {
131
+ it('reports accumulated llmCalls from context', async () => {
175
132
  const steps: PipelineStep[] = [{ name: 'Step A', run: async () => ({ success: true }) }];
176
- const ctx = makeCtx({ llmCalls: 5, fixIterations: 3 });
133
+ const ctx = makeCtx({ llmCalls: 5 });
177
134
 
178
135
  const result = await runPipeline(steps, ctx);
179
136
 
180
137
  expect(result).toEqual({
181
138
  success: true,
182
139
  llmCalls: 5,
183
- fixIterations: 3,
184
- typeFixIterations: 0,
185
- testFixIterations: 0,
186
- lintFixIterations: 0,
187
- storyFixIterations: 0,
188
140
  });
189
141
  });
190
142
 
191
143
  it('reports context metrics on failure', async () => {
192
144
  const steps: PipelineStep[] = [failStep('Broken', 'oops')];
193
- const ctx = makeCtx({ llmCalls: 2, fixIterations: 1 });
145
+ const ctx = makeCtx({ llmCalls: 2 });
194
146
 
195
147
  const result = await runPipeline(steps, ctx);
196
148
 
@@ -198,11 +150,6 @@ describe('runPipeline', () => {
198
150
  success: false,
199
151
  error: 'Step "Broken" failed: oops',
200
152
  llmCalls: 2,
201
- fixIterations: 1,
202
- typeFixIterations: 0,
203
- testFixIterations: 0,
204
- lintFixIterations: 0,
205
- storyFixIterations: 0,
206
153
  });
207
154
  });
208
155
  });
@@ -213,101 +160,37 @@ function makeModels(): PipelineModels {
213
160
  return {
214
161
  generateTest: fakeModel,
215
162
  generateComponent: fakeModel,
216
- typeFixer: fakeModel,
217
- testFixer: fakeModel,
218
- lintFixer: fakeModel,
219
- storyFixer: fakeModel,
163
+ fixer: fakeModel,
220
164
  };
221
165
  }
222
166
 
223
- function makeConfig(overrides: Partial<PipelineConfig> = {}): PipelineConfig {
167
+ function makeConfig(): PipelineConfig {
224
168
  return {
225
169
  models: {
226
170
  generateTest: '',
227
171
  generateComponent: '',
228
- typeFixer: '',
229
- testFixer: '',
230
- lintFixer: '',
231
- storyFixer: '',
172
+ fixer: '',
232
173
  },
233
- maxTypeFixIterations: 3,
234
- maxTestFixIterations: 3,
235
- maxLintFixIterations: 2,
236
- maxStoryFixIterations: 2,
237
- enableStorybookTest: false,
238
- enableVisualTest: false,
239
- ...overrides,
240
174
  };
241
175
  }
242
176
 
243
177
  describe('buildPipelineSteps', () => {
244
- it('returns 7 core steps by default', () => {
178
+ it('returns 3 core steps for first attempt', () => {
245
179
  const steps = buildPipelineSteps(makeModels(), makeConfig(), makeCtx());
246
180
 
247
- expect(steps.map((s) => s.name)).toEqual([
248
- 'Generate Test',
249
- 'Generate Component',
250
- 'Type Fix Loop',
251
- 'Test Fix Loop',
252
- 'Lint Fix Loop',
253
- 'Generate Story',
254
- 'Story Fix Loop',
255
- ]);
181
+ expect(steps.map((s) => s.name)).toEqual(['Generate Test', 'Generate Component', 'Generate Story']);
256
182
  });
257
183
 
258
- it('adds Storybook Test step when enabled', () => {
259
- const steps = buildPipelineSteps(makeModels(), makeConfig({ enableStorybookTest: true }), makeCtx());
260
-
261
- expect(steps.map((s) => s.name)).toEqual([
262
- 'Generate Test',
263
- 'Generate Component',
264
- 'Type Fix Loop',
265
- 'Test Fix Loop',
266
- 'Lint Fix Loop',
267
- 'Generate Story',
268
- 'Story Fix Loop',
269
- 'Storybook Test',
270
- ]);
271
- });
272
-
273
- it('adds Visual Test step when enabled', () => {
274
- const steps = buildPipelineSteps(makeModels(), makeConfig({ enableVisualTest: true }), makeCtx());
275
-
276
- expect(steps.map((s) => s.name)).toEqual([
277
- 'Generate Test',
278
- 'Generate Component',
279
- 'Type Fix Loop',
280
- 'Test Fix Loop',
281
- 'Lint Fix Loop',
282
- 'Generate Story',
283
- 'Story Fix Loop',
284
- 'Visual Test',
285
- ]);
286
- });
184
+ it('returns fix + story steps for retry attempt', () => {
185
+ const ctx = makeCtx({ attemptNumber: 1, errorFeedback: 'Test failed: expected X to equal Y' });
186
+ const steps = buildPipelineSteps(makeModels(), makeConfig(), ctx);
287
187
 
288
- it('adds both optional steps when both enabled', () => {
289
- const steps = buildPipelineSteps(
290
- makeModels(),
291
- makeConfig({ enableStorybookTest: true, enableVisualTest: true }),
292
- makeCtx(),
293
- );
294
-
295
- expect(steps.map((s) => s.name)).toEqual([
296
- 'Generate Test',
297
- 'Generate Component',
298
- 'Type Fix Loop',
299
- 'Test Fix Loop',
300
- 'Lint Fix Loop',
301
- 'Generate Story',
302
- 'Story Fix Loop',
303
- 'Storybook Test',
304
- 'Visual Test',
305
- ]);
188
+ expect(steps.map((s) => s.name)).toEqual(['Fix From Feedback', 'Generate Story']);
306
189
  });
307
190
 
308
- it('wires each step to its corresponding function', async () => {
191
+ it('wires each step to its corresponding function on first attempt', async () => {
309
192
  const models = makeModels();
310
- const config = makeConfig({ enableStorybookTest: true, enableVisualTest: true });
193
+ const config = makeConfig();
311
194
  const ctx = makeCtx();
312
195
  const steps = buildPipelineSteps(models, config, ctx);
313
196
 
@@ -317,12 +200,20 @@ describe('buildPipelineSteps', () => {
317
200
 
318
201
  expect(generateTestStep).toHaveBeenCalledWith(models.generateTest, ctx);
319
202
  expect(generateComponentStep).toHaveBeenCalledWith(models.generateComponent, ctx);
320
- expect(typeFixLoop).toHaveBeenCalledWith(models.typeFixer, ctx, 3);
321
- expect(testFixLoop).toHaveBeenCalledWith(models.testFixer, ctx, 3);
322
- expect(lintFixLoop).toHaveBeenCalledWith(models.lintFixer, ctx, 2);
323
203
  expect(generateStoryStep).toHaveBeenCalledWith(ctx);
324
- expect(storyFixLoop).toHaveBeenCalledWith(models.storyFixer, ctx, 2);
325
- expect(storybookTestStep).toHaveBeenCalledWith(ctx, true);
326
- expect(visualTestStep).toHaveBeenCalled();
204
+ });
205
+
206
+ it('wires fix step on retry attempt', async () => {
207
+ const models = makeModels();
208
+ const config = makeConfig();
209
+ const ctx = makeCtx({ attemptNumber: 1, errorFeedback: 'Some error' });
210
+ const steps = buildPipelineSteps(models, config, ctx);
211
+
212
+ for (const step of steps) {
213
+ await step.run();
214
+ }
215
+
216
+ expect(fixFromFeedbackStep).toHaveBeenCalledWith(models.fixer, ctx);
217
+ expect(generateStoryStep).toHaveBeenCalledWith(ctx);
327
218
  });
328
219
  });