@auto-engineer/component-implementor-react 1.108.0 → 1.110.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 +67 -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
@@ -1,116 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest';
2
- vi.mock('ai', () => ({
3
- generateText: vi.fn(),
4
- }));
5
- vi.mock('node:fs/promises', () => ({
6
- readFile: vi.fn(),
7
- writeFile: vi.fn(),
8
- }));
9
- vi.mock('../../tools/type-checker', () => ({
10
- runTypeCheck: vi.fn(),
11
- }));
12
- import { readFile, writeFile } from 'node:fs/promises';
13
- import { generateText } from 'ai';
14
- import { runTypeCheck } from '../../tools/type-checker.js';
15
- import { typeFixLoop } from './type-fix-loop.js';
16
- afterEach(() => {
17
- vi.clearAllMocks();
18
- });
19
- function makeCtx(overrides = {}) {
20
- return {
21
- componentName: 'MyButton',
22
- componentPath: '/project/src/MyButton.tsx',
23
- testPath: '/project/src/MyButton.test.tsx',
24
- storyPath: '/project/src/MyButton.stories.tsx',
25
- componentImportPath: '@/components/ui/MyButton',
26
- targetDir: '/project',
27
- specDeltas: { structure: [], rendering: [], interaction: [], styling: [] },
28
- projectSection: '',
29
- composes: [],
30
- isModify: false,
31
- llmCalls: 0,
32
- fixIterations: 0,
33
- typeFixIterations: 0,
34
- testFixIterations: 0,
35
- lintFixIterations: 0,
36
- storyFixIterations: 0,
37
- componentCode: 'original component',
38
- testCode: 'original test',
39
- ...overrides,
40
- };
41
- }
42
- describe('typeFixLoop', () => {
43
- it('returns success immediately when type check passes', async () => {
44
- vi.mocked(runTypeCheck).mockReturnValue({ passed: true, errors: [] });
45
- const result = await typeFixLoop('mock-model', makeCtx(), 3);
46
- expect(result).toEqual({ success: true });
47
- expect(generateText).not.toHaveBeenCalled();
48
- });
49
- it('calls LLM to fix type errors and writes fixed files', async () => {
50
- vi.mocked(runTypeCheck)
51
- .mockReturnValueOnce({ passed: false, errors: ['error TS2307: Module not found'] })
52
- .mockReturnValueOnce({ passed: true, errors: [] });
53
- vi.mocked(generateText).mockResolvedValue({
54
- text: '```tsx\nfixed component\n```\n```tsx\nfixed test\n```',
55
- });
56
- vi.mocked(writeFile).mockResolvedValue(undefined);
57
- const result = await typeFixLoop('mock-model', makeCtx(), 3);
58
- expect(result).toEqual({ success: true });
59
- expect(generateText).toHaveBeenCalledTimes(1);
60
- expect(writeFile).toHaveBeenCalledWith('/project/src/MyButton.tsx', 'fixed component', 'utf-8');
61
- expect(writeFile).toHaveBeenCalledWith('/project/src/MyButton.test.tsx', 'fixed test', 'utf-8');
62
- });
63
- it('returns failure after exhausting max iterations', async () => {
64
- vi.mocked(runTypeCheck).mockReturnValue({
65
- passed: false,
66
- errors: ['persistent error'],
67
- });
68
- vi.mocked(generateText).mockResolvedValue({
69
- text: '```tsx\nstill broken\n```\n```tsx\nstill broken test\n```',
70
- });
71
- vi.mocked(writeFile).mockResolvedValue(undefined);
72
- vi.mocked(readFile).mockResolvedValue('still broken');
73
- const result = await typeFixLoop('mock-model', makeCtx(), 2);
74
- expect(result).toEqual({
75
- success: false,
76
- error: expect.stringContaining('Type errors remain after 2 iterations'),
77
- });
78
- expect(generateText).toHaveBeenCalledTimes(2);
79
- });
80
- it('handles single code block response by updating only component', async () => {
81
- vi.mocked(runTypeCheck)
82
- .mockReturnValueOnce({ passed: false, errors: ['error in component'] })
83
- .mockReturnValueOnce({ passed: true, errors: [] });
84
- vi.mocked(generateText).mockResolvedValue({
85
- text: '```tsx\nfixed component only\n```',
86
- });
87
- vi.mocked(writeFile).mockResolvedValue(undefined);
88
- const result = await typeFixLoop('mock-model', makeCtx(), 3);
89
- expect(result).toEqual({ success: true });
90
- expect(writeFile).toHaveBeenCalledWith('/project/src/MyButton.tsx', 'fixed component only', 'utf-8');
91
- expect(writeFile).toHaveBeenCalledTimes(1);
92
- });
93
- it('returns success when final check passes after last iteration fix', async () => {
94
- vi.mocked(runTypeCheck)
95
- .mockReturnValueOnce({ passed: false, errors: ['error'] })
96
- .mockReturnValueOnce({ passed: true, errors: [] });
97
- vi.mocked(generateText).mockResolvedValue({
98
- text: '```tsx\nfixed\n```\n```tsx\nfixed test\n```',
99
- });
100
- vi.mocked(writeFile).mockResolvedValue(undefined);
101
- const result = await typeFixLoop('mock-model', makeCtx(), 1);
102
- expect(result).toEqual({ success: true });
103
- });
104
- it('uses empty string fallback when componentCode and testCode are undefined', async () => {
105
- vi.mocked(runTypeCheck)
106
- .mockReturnValueOnce({ passed: false, errors: ['error'] })
107
- .mockReturnValueOnce({ passed: true, errors: [] });
108
- vi.mocked(generateText).mockResolvedValue({
109
- text: '```tsx\nfixed\n```\n```tsx\nfixed test\n```',
110
- });
111
- vi.mocked(writeFile).mockResolvedValue(undefined);
112
- const result = await typeFixLoop('mock-model', makeCtx({ componentCode: undefined, testCode: undefined }), 1);
113
- expect(result).toEqual({ success: true });
114
- });
115
- });
116
- //# sourceMappingURL=type-fix-loop.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"type-fix-loop.test.js","sourceRoot":"","sources":["../../../../src/pipeline/steps/type-fix-loop.test.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import type { StepResult } from '../run-pipeline';
2
- export declare function visualTestStep(): Promise<StepResult>;
3
- //# sourceMappingURL=visual-test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visual-test.d.ts","sourceRoot":"","sources":["../../../../src/pipeline/steps/visual-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC,CAE1D"}
@@ -1,4 +0,0 @@
1
- export async function visualTestStep() {
2
- return { success: true };
3
- }
4
- //# sourceMappingURL=visual-test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visual-test.js","sourceRoot":"","sources":["../../../../src/pipeline/steps/visual-test.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=visual-test.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visual-test.test.d.ts","sourceRoot":"","sources":["../../../../src/pipeline/steps/visual-test.test.ts"],"names":[],"mappings":""}
@@ -1,9 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { visualTestStep } from './visual-test.js';
3
- describe('visualTestStep', () => {
4
- it('returns success (placeholder)', async () => {
5
- const result = await visualTestStep();
6
- expect(result).toEqual({ success: true });
7
- });
8
- });
9
- //# sourceMappingURL=visual-test.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visual-test.test.js","sourceRoot":"","sources":["../../../../src/pipeline/steps/visual-test.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;QAEtC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,176 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest';
2
-
3
- vi.mock('ai', () => ({
4
- generateText: vi.fn(),
5
- }));
6
-
7
- vi.mock('node:fs/promises', () => ({
8
- readFile: vi.fn(),
9
- writeFile: vi.fn(),
10
- }));
11
-
12
- vi.mock('../../tools/lint-runner', () => ({
13
- runLint: vi.fn(),
14
- runLintFix: vi.fn(),
15
- }));
16
-
17
- import { readFile, writeFile } from 'node:fs/promises';
18
- import { generateText } from 'ai';
19
- import { runLint, runLintFix } from '../../tools/lint-runner';
20
- import type { PipelineContext } from '../run-pipeline';
21
- import { lintFixLoop } from './lint-fix-loop';
22
-
23
- afterEach(() => {
24
- vi.clearAllMocks();
25
- });
26
-
27
- function makeCtx(overrides: Partial<PipelineContext> = {}): PipelineContext {
28
- return {
29
- componentName: 'MyButton',
30
- componentPath: '/project/src/MyButton.tsx',
31
- testPath: '/project/src/MyButton.test.tsx',
32
- storyPath: '/project/src/MyButton.stories.tsx',
33
- componentImportPath: '@/components/ui/MyButton',
34
- targetDir: '/project',
35
- specDeltas: { structure: [], rendering: [], interaction: [], styling: [] },
36
- projectSection: '',
37
- composes: [],
38
- isModify: false,
39
- llmCalls: 0,
40
- fixIterations: 0,
41
- typeFixIterations: 0,
42
- testFixIterations: 0,
43
- lintFixIterations: 0,
44
- storyFixIterations: 0,
45
- componentCode: 'original component',
46
- testCode: 'original test',
47
- ...overrides,
48
- };
49
- }
50
-
51
- describe('lintFixLoop', () => {
52
- it('runs auto-fix first, then returns success if lint passes', async () => {
53
- vi.mocked(runLintFix).mockReturnValue({ passed: true, errors: [] });
54
- vi.mocked(readFile).mockResolvedValue('auto-fixed code' as never);
55
- vi.mocked(runLint).mockReturnValue({ passed: true, errors: [] });
56
-
57
- const result = await lintFixLoop('mock-model' as never, makeCtx(), 2);
58
-
59
- expect(result).toEqual({ success: true });
60
- expect(runLintFix).toHaveBeenCalledWith(
61
- ['/project/src/MyButton.tsx', '/project/src/MyButton.test.tsx'],
62
- '/project',
63
- );
64
- expect(generateText).not.toHaveBeenCalled();
65
- });
66
-
67
- it('calls LLM for remaining lint errors after auto-fix', async () => {
68
- vi.mocked(runLintFix).mockReturnValue({ passed: false, errors: ['unfixable'] });
69
- vi.mocked(readFile).mockResolvedValue('auto-fixed partial' as never);
70
- vi.mocked(runLint)
71
- .mockReturnValueOnce({ passed: false, errors: ['remaining error'] })
72
- .mockReturnValueOnce({ passed: true, errors: [] });
73
-
74
- vi.mocked(generateText).mockResolvedValue({
75
- text: '```tsx\nlint-fixed component\n```\n```tsx\nlint-fixed test\n```',
76
- } as Awaited<ReturnType<typeof generateText>>);
77
- vi.mocked(writeFile).mockResolvedValue(undefined);
78
-
79
- const result = await lintFixLoop('mock-model' as never, makeCtx(), 2);
80
-
81
- expect(result).toEqual({ success: true });
82
- expect(generateText).toHaveBeenCalledTimes(1);
83
- });
84
-
85
- it('returns failure after exhausting max iterations', async () => {
86
- vi.mocked(runLintFix).mockReturnValue({ passed: true, errors: [] });
87
- vi.mocked(readFile).mockResolvedValue('code' as never);
88
- vi.mocked(runLint).mockReturnValue({ passed: false, errors: ['persistent lint error'] });
89
-
90
- vi.mocked(generateText).mockResolvedValue({
91
- text: '```tsx\nstill bad\n```\n```tsx\nstill bad test\n```',
92
- } as Awaited<ReturnType<typeof generateText>>);
93
- vi.mocked(writeFile).mockResolvedValue(undefined);
94
-
95
- const result = await lintFixLoop('mock-model' as never, makeCtx(), 1);
96
-
97
- expect(result).toEqual({
98
- success: false,
99
- error: expect.stringContaining('Lint errors remain after 1 iterations'),
100
- });
101
- });
102
-
103
- it('handles single code block response by updating only component', async () => {
104
- vi.mocked(runLintFix).mockReturnValue({ passed: true, errors: [] });
105
- vi.mocked(readFile).mockResolvedValue('auto-fixed' as never);
106
- vi.mocked(runLint)
107
- .mockReturnValueOnce({ passed: false, errors: ['lint error'] })
108
- .mockReturnValueOnce({ passed: true, errors: [] });
109
-
110
- vi.mocked(generateText).mockResolvedValue({
111
- text: '```tsx\nfixed component only\n```',
112
- } as Awaited<ReturnType<typeof generateText>>);
113
- vi.mocked(writeFile).mockResolvedValue(undefined);
114
-
115
- const result = await lintFixLoop('mock-model' as never, makeCtx(), 2);
116
-
117
- expect(result).toEqual({ success: true });
118
- expect(writeFile).toHaveBeenCalledWith('/project/src/MyButton.tsx', 'fixed component only', 'utf-8');
119
- expect(writeFile).toHaveBeenCalledTimes(1);
120
- });
121
-
122
- it('returns success when final check passes after last iteration', async () => {
123
- vi.mocked(runLintFix).mockReturnValue({ passed: true, errors: [] });
124
- vi.mocked(readFile).mockResolvedValue('auto-fixed' as never);
125
- vi.mocked(runLint)
126
- .mockReturnValueOnce({ passed: false, errors: ['error'] })
127
- .mockReturnValueOnce({ passed: true, errors: [] });
128
-
129
- vi.mocked(generateText).mockResolvedValue({
130
- text: '```tsx\nfixed\n```\n```tsx\nfixed test\n```',
131
- } as Awaited<ReturnType<typeof generateText>>);
132
- vi.mocked(writeFile).mockResolvedValue(undefined);
133
-
134
- const result = await lintFixLoop('mock-model' as never, makeCtx(), 1);
135
-
136
- expect(result).toEqual({ success: true });
137
- });
138
-
139
- it('re-runs auto-fix after each LLM write to handle formatting issues', async () => {
140
- vi.mocked(runLintFix).mockReturnValue({ passed: true, errors: [] });
141
- vi.mocked(readFile).mockResolvedValue('auto-fixed' as never);
142
- vi.mocked(runLint)
143
- .mockReturnValueOnce({ passed: false, errors: ['format error'] })
144
- .mockReturnValueOnce({ passed: true, errors: [] });
145
-
146
- vi.mocked(generateText).mockResolvedValue({
147
- text: '```tsx\nfixed component\n```\n```tsx\nfixed test\n```',
148
- } as Awaited<ReturnType<typeof generateText>>);
149
- vi.mocked(writeFile).mockResolvedValue(undefined);
150
-
151
- await lintFixLoop('mock-model' as never, makeCtx(), 2);
152
-
153
- expect(runLintFix).toHaveBeenCalledTimes(2);
154
- });
155
-
156
- it('uses empty string fallback when componentCode and testCode are undefined after readFile', async () => {
157
- vi.mocked(runLintFix).mockReturnValue({ passed: true, errors: [] });
158
- vi.mocked(readFile).mockResolvedValue(undefined as never);
159
- vi.mocked(runLint)
160
- .mockReturnValueOnce({ passed: false, errors: ['error'] })
161
- .mockReturnValueOnce({ passed: true, errors: [] });
162
-
163
- vi.mocked(generateText).mockResolvedValue({
164
- text: '```tsx\nfixed\n```\n```tsx\nfixed test\n```',
165
- } as Awaited<ReturnType<typeof generateText>>);
166
- vi.mocked(writeFile).mockResolvedValue(undefined);
167
-
168
- const result = await lintFixLoop(
169
- 'mock-model' as never,
170
- makeCtx({ componentCode: undefined, testCode: undefined }),
171
- 1,
172
- );
173
-
174
- expect(result).toEqual({ success: true });
175
- });
176
- });
@@ -1,61 +0,0 @@
1
- import { readFile, writeFile } from 'node:fs/promises';
2
- import type { LanguageModel } from 'ai';
3
- import { generateText } from 'ai';
4
- import { extractCodeBlocks } from '../../extract-code-block';
5
- import { buildLintFixPrompt } from '../../prompt';
6
- import { runLint, runLintFix } from '../../tools/lint-runner';
7
- import type { PipelineContext, StepResult } from '../run-pipeline';
8
-
9
- export async function lintFixLoop(
10
- model: LanguageModel,
11
- ctx: PipelineContext,
12
- maxIterations: number,
13
- ): Promise<StepResult> {
14
- const filePaths = [ctx.componentPath, ctx.testPath];
15
-
16
- runLintFix(filePaths, ctx.targetDir);
17
-
18
- ctx.componentCode = await readFile(ctx.componentPath, 'utf-8');
19
- ctx.testCode = await readFile(ctx.testPath, 'utf-8');
20
-
21
- for (let i = 0; i < maxIterations; i++) {
22
- const result = runLint(filePaths, ctx.targetDir);
23
-
24
- if (result.passed) {
25
- return { success: true };
26
- }
27
-
28
- const { system, prompt } = buildLintFixPrompt({
29
- componentCode: ctx.componentCode ?? '',
30
- testCode: ctx.testCode ?? '',
31
- errors: result.errors,
32
- });
33
-
34
- const { text } = await generateText({ model, system, prompt });
35
- ctx.llmCalls++;
36
- ctx.fixIterations++;
37
- ctx.lintFixIterations++;
38
-
39
- const blocks = extractCodeBlocks(text);
40
- if (blocks.length >= 2) {
41
- await writeFile(ctx.componentPath, blocks[0], 'utf-8');
42
- await writeFile(ctx.testPath, blocks[1], 'utf-8');
43
- } else if (blocks.length === 1) {
44
- await writeFile(ctx.componentPath, blocks[0], 'utf-8');
45
- }
46
-
47
- runLintFix(filePaths, ctx.targetDir);
48
- ctx.componentCode = await readFile(ctx.componentPath, 'utf-8');
49
- ctx.testCode = await readFile(ctx.testPath, 'utf-8');
50
- }
51
-
52
- const finalResult = runLint(filePaths, ctx.targetDir);
53
- if (finalResult.passed) {
54
- return { success: true };
55
- }
56
-
57
- return {
58
- success: false,
59
- error: `Lint errors remain after ${maxIterations} iterations: ${finalResult.errors.slice(0, 3).join('; ')}`,
60
- };
61
- }
@@ -1,127 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest';
2
-
3
- vi.mock('ai', () => ({
4
- generateText: vi.fn(),
5
- }));
6
-
7
- vi.mock('node:fs/promises', () => ({
8
- readFile: vi.fn(),
9
- writeFile: vi.fn(),
10
- }));
11
-
12
- vi.mock('../../tools/type-checker', () => ({
13
- runTypeCheck: vi.fn(),
14
- }));
15
-
16
- import { readFile, writeFile } from 'node:fs/promises';
17
- import { generateText } from 'ai';
18
- import { runTypeCheck } from '../../tools/type-checker';
19
- import type { PipelineContext } from '../run-pipeline';
20
- import { storyFixLoop } from './story-fix-loop';
21
-
22
- afterEach(() => {
23
- vi.clearAllMocks();
24
- });
25
-
26
- function makeCtx(overrides: Partial<PipelineContext> = {}): PipelineContext {
27
- return {
28
- componentName: 'MyButton',
29
- componentPath: '/project/src/MyButton.tsx',
30
- testPath: '/project/src/MyButton.test.tsx',
31
- storyPath: '/project/src/MyButton.stories.tsx',
32
- componentImportPath: '@/components/ui/MyButton',
33
- targetDir: '/project',
34
- specDeltas: { structure: [], rendering: [], interaction: [], styling: [] },
35
- projectSection: '',
36
- composes: [],
37
- isModify: false,
38
- llmCalls: 0,
39
- fixIterations: 0,
40
- typeFixIterations: 0,
41
- testFixIterations: 0,
42
- lintFixIterations: 0,
43
- storyFixIterations: 0,
44
- storyCode: 'original story',
45
- componentCode: 'original component',
46
- ...overrides,
47
- };
48
- }
49
-
50
- describe('storyFixLoop', () => {
51
- it('returns success immediately when story type-checks', async () => {
52
- vi.mocked(runTypeCheck).mockReturnValue({ passed: true, errors: [] });
53
-
54
- const result = await storyFixLoop('mock-model' as never, makeCtx(), 2);
55
-
56
- expect(result).toEqual({ success: true });
57
- expect(generateText).not.toHaveBeenCalled();
58
- });
59
-
60
- it('calls LLM to fix story type errors and writes fixed story', async () => {
61
- vi.mocked(runTypeCheck)
62
- .mockReturnValueOnce({ passed: false, errors: ['error in story'] })
63
- .mockReturnValueOnce({ passed: true, errors: [] });
64
-
65
- vi.mocked(generateText).mockResolvedValue({
66
- text: '```tsx\nfixed story code\n```',
67
- } as Awaited<ReturnType<typeof generateText>>);
68
- vi.mocked(writeFile).mockResolvedValue(undefined);
69
-
70
- const result = await storyFixLoop('mock-model' as never, makeCtx(), 2);
71
-
72
- expect(result).toEqual({ success: true });
73
- expect(generateText).toHaveBeenCalledTimes(1);
74
- expect(writeFile).toHaveBeenCalledWith('/project/src/MyButton.stories.tsx', 'fixed story code', 'utf-8');
75
- });
76
-
77
- it('returns failure after exhausting max iterations', async () => {
78
- vi.mocked(runTypeCheck).mockReturnValue({ passed: false, errors: ['persistent story error'] });
79
-
80
- vi.mocked(generateText).mockResolvedValue({
81
- text: '```tsx\nstill broken story\n```',
82
- } as Awaited<ReturnType<typeof generateText>>);
83
- vi.mocked(writeFile).mockResolvedValue(undefined);
84
- vi.mocked(readFile).mockResolvedValue('still broken story' as never);
85
-
86
- const result = await storyFixLoop('mock-model' as never, makeCtx(), 1);
87
-
88
- expect(result).toEqual({
89
- success: false,
90
- error: expect.stringContaining('Story type errors remain after 1 iterations'),
91
- });
92
- });
93
-
94
- it('returns success when final check passes after last iteration fix', async () => {
95
- vi.mocked(runTypeCheck)
96
- .mockReturnValueOnce({ passed: false, errors: ['error'] })
97
- .mockReturnValueOnce({ passed: true, errors: [] });
98
-
99
- vi.mocked(generateText).mockResolvedValue({
100
- text: '```tsx\nfixed story\n```',
101
- } as Awaited<ReturnType<typeof generateText>>);
102
- vi.mocked(writeFile).mockResolvedValue(undefined);
103
-
104
- const result = await storyFixLoop('mock-model' as never, makeCtx(), 1);
105
-
106
- expect(result).toEqual({ success: true });
107
- });
108
-
109
- it('uses empty string fallback when storyCode and componentCode are undefined', async () => {
110
- vi.mocked(runTypeCheck)
111
- .mockReturnValueOnce({ passed: false, errors: ['error'] })
112
- .mockReturnValueOnce({ passed: true, errors: [] });
113
-
114
- vi.mocked(generateText).mockResolvedValue({
115
- text: '```tsx\nfixed story\n```',
116
- } as Awaited<ReturnType<typeof generateText>>);
117
- vi.mocked(writeFile).mockResolvedValue(undefined);
118
-
119
- const result = await storyFixLoop(
120
- 'mock-model' as never,
121
- makeCtx({ storyCode: undefined, componentCode: undefined }),
122
- 1,
123
- );
124
-
125
- expect(result).toEqual({ success: true });
126
- });
127
- });
@@ -1,48 +0,0 @@
1
- import { readFile, writeFile } from 'node:fs/promises';
2
- import type { LanguageModel } from 'ai';
3
- import { generateText } from 'ai';
4
- import { extractCodeBlock } from '../../extract-code-block';
5
- import { buildStoryFixPrompt } from '../../prompt';
6
- import { runTypeCheck } from '../../tools/type-checker';
7
- import type { PipelineContext, StepResult } from '../run-pipeline';
8
-
9
- export async function storyFixLoop(
10
- model: LanguageModel,
11
- ctx: PipelineContext,
12
- maxIterations: number,
13
- ): Promise<StepResult> {
14
- for (let i = 0; i < maxIterations; i++) {
15
- const result = runTypeCheck(ctx.targetDir, [ctx.storyPath]);
16
-
17
- if (result.passed) {
18
- return { success: true };
19
- }
20
-
21
- const { system, prompt } = buildStoryFixPrompt({
22
- storyCode: ctx.storyCode ?? '',
23
- componentCode: ctx.componentCode ?? '',
24
- errors: result.errors,
25
- });
26
-
27
- const { text } = await generateText({ model, system, prompt });
28
- ctx.llmCalls++;
29
- ctx.fixIterations++;
30
- ctx.storyFixIterations++;
31
-
32
- const fixedStory = extractCodeBlock(text);
33
- ctx.storyCode = fixedStory;
34
- await writeFile(ctx.storyPath, fixedStory, 'utf-8');
35
- }
36
-
37
- const finalResult = runTypeCheck(ctx.targetDir, [ctx.storyPath]);
38
- if (finalResult.passed) {
39
- return { success: true };
40
- }
41
-
42
- ctx.storyCode = await readFile(ctx.storyPath, 'utf-8');
43
-
44
- return {
45
- success: false,
46
- error: `Story type errors remain after ${maxIterations} iterations: ${finalResult.errors.join('; ')}`,
47
- };
48
- }
@@ -1,86 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
-
3
- vi.mock('../../tools/type-checker', () => ({
4
- runTypeCheck: vi.fn(),
5
- }));
6
-
7
- vi.mock('../../tools/storybook-runner', () => ({
8
- runStorybookTest: vi.fn(),
9
- }));
10
-
11
- import { runStorybookTest } from '../../tools/storybook-runner';
12
- import { runTypeCheck } from '../../tools/type-checker';
13
- import type { PipelineContext } from '../run-pipeline';
14
- import { storybookTestStep } from './storybook-test';
15
-
16
- function makeCtx(overrides: Partial<PipelineContext> = {}): PipelineContext {
17
- return {
18
- componentName: 'MyButton',
19
- componentPath: '/project/src/MyButton.tsx',
20
- testPath: '/project/src/MyButton.test.tsx',
21
- storyPath: '/project/src/MyButton.stories.tsx',
22
- componentImportPath: '@/components/ui/MyButton',
23
- targetDir: '/project',
24
- specDeltas: { structure: [], rendering: [], interaction: [], styling: [] },
25
- projectSection: '',
26
- composes: [],
27
- isModify: false,
28
- llmCalls: 0,
29
- fixIterations: 0,
30
- typeFixIterations: 0,
31
- testFixIterations: 0,
32
- lintFixIterations: 0,
33
- storyFixIterations: 0,
34
- ...overrides,
35
- };
36
- }
37
-
38
- describe('storybookTestStep', () => {
39
- it('returns success when type check passes and storybook cli disabled', async () => {
40
- vi.mocked(runTypeCheck).mockReturnValue({ passed: true, errors: [] });
41
-
42
- const result = await storybookTestStep(makeCtx(), false);
43
-
44
- expect(result).toEqual({ success: true });
45
- expect(runStorybookTest).not.toHaveBeenCalled();
46
- });
47
-
48
- it('returns failure when story type check fails', async () => {
49
- vi.mocked(runTypeCheck).mockReturnValue({
50
- passed: false,
51
- errors: ['error in story'],
52
- });
53
-
54
- const result = await storybookTestStep(makeCtx(), false);
55
-
56
- expect(result).toEqual({
57
- success: false,
58
- error: expect.stringContaining('Story type errors'),
59
- });
60
- });
61
-
62
- it('runs storybook CLI test when enabled and type check passes', async () => {
63
- vi.mocked(runTypeCheck).mockReturnValue({ passed: true, errors: [] });
64
- vi.mocked(runStorybookTest).mockReturnValue({ passed: true, errors: [] });
65
-
66
- const result = await storybookTestStep(makeCtx(), true);
67
-
68
- expect(result).toEqual({ success: true });
69
- expect(runStorybookTest).toHaveBeenCalledWith('/project/src/MyButton.stories.tsx', '/project');
70
- });
71
-
72
- it('returns failure when storybook CLI test fails', async () => {
73
- vi.mocked(runTypeCheck).mockReturnValue({ passed: true, errors: [] });
74
- vi.mocked(runStorybookTest).mockReturnValue({
75
- passed: false,
76
- errors: ['Story failed'],
77
- });
78
-
79
- const result = await storybookTestStep(makeCtx(), true);
80
-
81
- expect(result).toEqual({
82
- success: false,
83
- error: expect.stringContaining('Storybook test failures'),
84
- });
85
- });
86
- });