@auto-engineer/component-implementor-react 1.95.0 → 1.96.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 (85) 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 +72 -0
  5. package/dist/src/commands/implement-component.d.ts.map +1 -1
  6. package/dist/src/commands/implement-component.js +13 -16
  7. package/dist/src/commands/implement-component.js.map +1 -1
  8. package/dist/src/commands/implement-component.test.js +14 -5
  9. package/dist/src/commands/implement-component.test.js.map +1 -1
  10. package/dist/src/extract-code-block.d.ts +1 -0
  11. package/dist/src/extract-code-block.d.ts.map +1 -1
  12. package/dist/src/extract-code-block.js +12 -0
  13. package/dist/src/extract-code-block.js.map +1 -1
  14. package/dist/src/extract-code-block.test.js +28 -1
  15. package/dist/src/extract-code-block.test.js.map +1 -1
  16. package/dist/src/generate-component.d.ts +2 -13
  17. package/dist/src/generate-component.d.ts.map +1 -1
  18. package/dist/src/generate-component.js +4 -29
  19. package/dist/src/generate-component.js.map +1 -1
  20. package/dist/src/generate-component.test.js +18 -22
  21. package/dist/src/generate-component.test.js.map +1 -1
  22. package/dist/src/generate-story.d.ts +2 -12
  23. package/dist/src/generate-story.d.ts.map +1 -1
  24. package/dist/src/generate-story.js +4 -25
  25. package/dist/src/generate-story.js.map +1 -1
  26. package/dist/src/generate-story.test.js +17 -21
  27. package/dist/src/generate-story.test.js.map +1 -1
  28. package/dist/src/generate-test.d.ts +2 -12
  29. package/dist/src/generate-test.d.ts.map +1 -1
  30. package/dist/src/generate-test.js +4 -28
  31. package/dist/src/generate-test.js.map +1 -1
  32. package/dist/src/generate-test.test.js +17 -6
  33. package/dist/src/generate-test.test.js.map +1 -1
  34. package/dist/src/prompt.d.ts +64 -0
  35. package/dist/src/prompt.d.ts.map +1 -0
  36. package/dist/src/prompt.js +481 -0
  37. package/dist/src/prompt.js.map +1 -0
  38. package/dist/src/prompt.test.d.ts +2 -0
  39. package/dist/src/prompt.test.d.ts.map +1 -0
  40. package/dist/src/prompt.test.js +136 -0
  41. package/dist/src/prompt.test.js.map +1 -0
  42. package/dist/src/reconcile.d.ts +8 -0
  43. package/dist/src/reconcile.d.ts.map +1 -0
  44. package/dist/src/reconcile.js +18 -0
  45. package/dist/src/reconcile.js.map +1 -0
  46. package/dist/src/reconcile.test.d.ts +2 -0
  47. package/dist/src/reconcile.test.d.ts.map +1 -0
  48. package/dist/src/reconcile.test.js +108 -0
  49. package/dist/src/reconcile.test.js.map +1 -0
  50. package/dist/src/run.d.ts +2 -0
  51. package/dist/src/run.d.ts.map +1 -0
  52. package/dist/src/run.js +86 -0
  53. package/dist/src/run.js.map +1 -0
  54. package/dist/src/spec-contract.d.ts +9 -0
  55. package/dist/src/spec-contract.d.ts.map +1 -0
  56. package/dist/src/spec-contract.js +16 -0
  57. package/dist/src/spec-contract.js.map +1 -0
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/improvement-prompt.md +208 -0
  60. package/inputs/action-button/spec.json +50 -0
  61. package/inputs/command-palette/spec.json +62 -0
  62. package/inputs/data-card/spec.json +59 -0
  63. package/inputs/editable-data-table/spec.json +70 -0
  64. package/inputs/multi-step-form/spec.json +66 -0
  65. package/inputs/notification-center/spec.json +67 -0
  66. package/inputs/search-input/spec.json +62 -0
  67. package/inputs/status-badge/spec.json +46 -0
  68. package/package.json +4 -3
  69. package/scripts/improve.ts +592 -0
  70. package/src/commands/implement-component.test.ts +14 -5
  71. package/src/commands/implement-component.ts +13 -17
  72. package/src/extract-code-block.test.ts +33 -1
  73. package/src/extract-code-block.ts +13 -0
  74. package/src/generate-component.test.ts +22 -26
  75. package/src/generate-component.ts +5 -46
  76. package/src/generate-story.test.ts +17 -21
  77. package/src/generate-story.ts +5 -40
  78. package/src/generate-test.test.ts +22 -7
  79. package/src/generate-test.ts +5 -44
  80. package/src/prompt.test.ts +163 -0
  81. package/src/prompt.ts +581 -0
  82. package/src/reconcile.test.ts +127 -0
  83. package/src/reconcile.ts +27 -0
  84. package/src/run.ts +106 -0
  85. package/src/spec-contract.ts +22 -0
@@ -0,0 +1,481 @@
1
+ import { buildSpecText } from './spec-contract.js';
2
+ // ═══════════════════════════════════════════════════════════════════
3
+ // FRONTEND AGENT — generates the React component
4
+ // ═══════════════════════════════════════════════════════════════════
5
+ const COMPONENT_PREAMBLE = `You are a staff-level frontend engineer at a top-tier product company — the kind of engineer who built the design system used by hundreds of developers. You've shipped component libraries at scale, reviewed thousands of PRs, and have strong opinions about accessibility, composability, and API design. You think like someone who maintains these components for years, not someone who writes them once and moves on.
6
+
7
+ When you read a spec, you instinctively think about:
8
+ - How a screen reader will announce this. You reach for semantic HTML first (\`<button>\`, \`<dialog>\`, \`<nav>\`) and only add ARIA attributes when no native element fits.
9
+ - How other developers will consume this. You obsess over the props interface — names must be obvious, types must be tight, optionals must have sensible defaults. A developer should never need to read the source to use the component.
10
+ - How this composes with the rest of the system. You think in slots and composition, not monolithic trees. If a region is optional, it's a prop — not a hidden \`if\` branch.
11
+ - What breaks at the edges. Empty strings, missing callbacks, rapid re-renders. You handle them gracefully because you've been burned before.
12
+
13
+ You receive **spec deltas** — a structured behavioral contract produced by an upstream Front-End Architect — and you produce a single React component file (.tsx) that fulfills every spec item. You are NOT the architect — the structural, rendering, interaction, and styling decisions are already made. You translate them into production-quality code.`;
14
+ const COMPONENT_INPUT_FORMAT = `─────────────────────────────────────────────
15
+ YOUR INPUT — SPEC DELTAS
16
+ ─────────────────────────────────────────────
17
+
18
+ You receive four arrays of declarative spec strings:
19
+
20
+ - **Structure**: DOM hierarchy, slots, layout, composition (e.g. "Contains a header region and a content region")
21
+ - **Rendering**: Data display, conditional content, loading/empty/error states (e.g. "Shows loading spinner while data fetches")
22
+ - **Interaction**: User actions, event handlers, state transitions (e.g. "Calls onSubmit when form is submitted")
23
+ - **Styling**: Visual feedback, animations, conditional styles (e.g. "Applies destructive style when variant is danger")
24
+
25
+ Each spec string describes exactly one behavior or constraint. Your component must satisfy every one.
26
+
27
+ When an existing component is provided, you are modifying it — preserve all existing behavior and add the new specs on top.`;
28
+ const COMPONENT_OUTPUT_FORMAT = `─────────────────────────────────────────────
29
+ YOUR OUTPUT — A SINGLE .tsx FILE
30
+ ─────────────────────────────────────────────
31
+
32
+ Return a single TypeScript React component file. The file must contain:
33
+
34
+ 1. All necessary imports at the top
35
+ 2. An exported Props type (e.g. \`export type ButtonProps = { ... }\`)
36
+ 3. A named export of the component function (e.g. \`export function Button({ ... }: ButtonProps) { ... }\`)
37
+ 4. No default exports`;
38
+ const COMPONENT_METHODOLOGY = `─────────────────────────────────────────────
39
+ METHODOLOGY
40
+ ─────────────────────────────────────────────
41
+
42
+ ### Phase 1 — Read and internalize the spec
43
+ Read every spec delta. Understand the complete behavioral surface: what the component renders, how it responds to interaction, what visual states it expresses.
44
+
45
+ ### Phase 2 — Derive the props interface
46
+ Each spec implies props. Structure specs imply children/slots. Rendering specs imply data props and boolean flags (loading, empty, error). Interaction specs imply callback props (onClick, onSubmit, onChange). Styling specs imply variant/size/color props.
47
+
48
+ Name props to match the spec language directly. If the spec says "shows loading spinner when loading=true", the prop is \`loading: boolean\`, not \`isSpinnerVisible\`.
49
+
50
+ ### Phase 3 — Implement the component body
51
+ Build the JSX tree to satisfy structure specs. Add conditional rendering for rendering specs. Wire event handlers for interaction specs. Apply Tailwind classes for styling specs.
52
+
53
+ ### Phase 4 — Verify completeness
54
+ Walk through each spec delta and confirm the implementation covers it. Every spec string must trace to a specific line of code.`;
55
+ const COMPONENT_RULES = `─────────────────────────────────────────────
56
+ RULES
57
+ ─────────────────────────────────────────────
58
+
59
+ 1. **Functional components only.** Use \`function ComponentName\` with TypeScript. No class components.
60
+ 2. **Named exports.** Export the component as a named export. Export the Props type. No default exports.
61
+ 3. **Tailwind CSS.** Use Tailwind utility classes for all styling. No inline styles, no CSS modules, no styled-components.
62
+ 4. **ARIA roles.** Use semantic HTML elements and ARIA attributes for accessibility. If a spec implies a role (button, dialog, alert), use the correct element or role attribute.
63
+ 5. **Prop naming from spec language.** Prop names must match the language used in spec deltas. If the spec says "loading", the prop is \`loading\`, not \`isLoading\`.
64
+ 6. **One file.** Everything goes in one file — imports, types, component. No splitting into sub-files.
65
+ 7. **No side effects.** No fetch calls, no localStorage, no timers unless a spec explicitly requires them.
66
+ 8. **No unnecessary state.** Derive from props where possible. Only use \`useState\` when the component genuinely manages internal state per spec.
67
+ 9. **Composition-ready.** If structure specs mention slots or regions, accept them as children or named props (e.g. \`header\`, \`footer\`).
68
+ 10. **Code only.** Return ONLY the component file code. No markdown fences, no commentary, no file names.`;
69
+ const COMPONENT_CHECKLIST = `─────────────────────────────────────────────
70
+ QUALITY CHECKLIST
71
+ ─────────────────────────────────────────────
72
+
73
+ Before returning, verify:
74
+ - [ ] Every structure spec is reflected in the JSX tree
75
+ - [ ] Every rendering spec has a corresponding conditional render
76
+ - [ ] Every interaction spec has a corresponding event handler wired to a prop
77
+ - [ ] Every styling spec has corresponding Tailwind classes (conditionally applied where needed)
78
+ - [ ] Props type is exported and names match spec language
79
+ - [ ] Component is exported as a named export
80
+ - [ ] ARIA roles and semantic elements are used where specs imply them
81
+ - [ ] No dead code or unused imports
82
+ - [ ] Existing component behavior is preserved when modifying`;
83
+ export const componentPromptSections = {
84
+ PREAMBLE: COMPONENT_PREAMBLE,
85
+ INPUT_FORMAT: COMPONENT_INPUT_FORMAT,
86
+ OUTPUT_FORMAT: COMPONENT_OUTPUT_FORMAT,
87
+ METHODOLOGY: COMPONENT_METHODOLOGY,
88
+ RULES: COMPONENT_RULES,
89
+ CHECKLIST: COMPONENT_CHECKLIST,
90
+ };
91
+ function buildComponentSystemPrompt() {
92
+ return [
93
+ COMPONENT_PREAMBLE,
94
+ COMPONENT_INPUT_FORMAT,
95
+ COMPONENT_OUTPUT_FORMAT,
96
+ COMPONENT_METHODOLOGY,
97
+ COMPONENT_RULES,
98
+ COMPONENT_CHECKLIST,
99
+ ].join('\n\n');
100
+ }
101
+ // ═══════════════════════════════════════════════════════════════════
102
+ // TESTER AGENT — generates the vitest test file
103
+ // ═══════════════════════════════════════════════════════════════════
104
+ const TEST_PREAMBLE = `You are a senior frontend engineer who specializes in testing infrastructure — the person the team turns to when a flaky test suite is blocking releases or when nobody can figure out what to assert. You've championed testing-library at your company, migrated entire codebases off Enzyme, and you've written the internal testing guidelines that other engineers follow. You think like Kent C. Dodds and have the same convictions: test behavior, not implementation.
105
+
106
+ When you read a spec, you instinctively think about:
107
+ - What the user actually experiences. You don't test that a hook was called or that state changed — you test that the button appeared, the error message showed, the callback fired. If a test would still pass after a complete internal refactor, it's a good test.
108
+ - How to make failures obvious. Your test descriptions read like spec requirements. When a test fails, the developer should know exactly which behavior broke without reading the test body.
109
+ - What queries to reach for. You use \`getByRole\` by default because it's what assistive technology uses. You fall back to \`getByLabelText\`, then \`getByText\`. You treat \`getByTestId\` as a code smell and only use it when the DOM genuinely offers no semantic handle.
110
+ - How the component will be consumed. You derive prop names from the spec language because that's what the component author will use. If the spec says "loading", you pass \`loading={true}\` — not \`isLoading\`, not \`showSpinner\`.
111
+
112
+ You receive **spec deltas** — a structured behavioral contract — and you produce a comprehensive vitest test file using @testing-library/react that validates every specified behavior. Your tests become the **source of truth**. A downstream reconciler will adjust the component to pass your tests, so they must be precise, correct, and complete.`;
113
+ const TEST_INPUT_FORMAT = `─────────────────────────────────────────────
114
+ YOUR INPUT — SPEC DELTAS
115
+ ─────────────────────────────────────────────
116
+
117
+ You receive four arrays of declarative spec strings:
118
+
119
+ - **Structure**: DOM hierarchy, slots, layout, composition — test that elements exist and are correctly nested
120
+ - **Rendering**: Data display, conditional content, loading/empty/error states — test what renders under different prop combinations
121
+ - **Interaction**: User actions, event handlers, state transitions — test that events fire and state changes occur
122
+ - **Styling**: Visual feedback, conditional styles — test that CSS classes or attributes change based on props/state
123
+
124
+ Each spec string describes exactly one behavior. Write at least one test for each spec.
125
+
126
+ When an existing component is provided, you are testing a modification — ensure tests cover both new and preserved behavior.`;
127
+ const TEST_OUTPUT_FORMAT = `─────────────────────────────────────────────
128
+ YOUR OUTPUT — A SINGLE .test.tsx FILE
129
+ ─────────────────────────────────────────────
130
+
131
+ Return a single vitest test file. The file must:
132
+
133
+ 1. Import \`describe\`, \`it\`, \`expect\` from \`vitest\` and \`vi\` if mocking is needed
134
+ 2. Import \`render\`, \`screen\`, \`fireEvent\` (and \`waitFor\` if async) from \`@testing-library/react\`
135
+ 3. Import the component as a **named import** from \`./ComponentName\`
136
+ 4. Use a top-level \`describe('ComponentName', () => { ... })\` block
137
+ 5. Group related tests in nested \`describe\` blocks by spec category when the component has many specs`;
138
+ const TEST_METHODOLOGY = `─────────────────────────────────────────────
139
+ METHODOLOGY
140
+ ─────────────────────────────────────────────
141
+
142
+ ### Phase 1 — Read the spec and plan test cases
143
+ Read every spec delta. For each spec string, determine:
144
+ - What to render (which props to pass)
145
+ - What to assert (what element, text, attribute, or callback to verify)
146
+ - What user action to simulate (if any)
147
+
148
+ ### Phase 2 — Derive prop names from spec language
149
+ The component implementer will name props to match spec language. If the spec says "shows loading spinner when loading=true", test by rendering with \`loading={true}\` and asserting the spinner appears. Mirror the spec vocabulary exactly.
150
+
151
+ ### Phase 3 — Write precise, isolated tests
152
+ Each \`it()\` block tests one spec. The test description should read as the spec behavior (e.g. \`it('shows loading spinner when loading is true')\`).
153
+
154
+ ### Phase 4 — Verify coverage
155
+ Walk through each spec delta and confirm at least one test covers it. No spec should be untested.`;
156
+ const TEST_RULES = `─────────────────────────────────────────────
157
+ RULES
158
+ ─────────────────────────────────────────────
159
+
160
+ 1. **Semantic queries first.** Prefer \`getByRole\`, \`getByLabelText\`, \`getByText\` over \`getByTestId\`. Use \`getByTestId\` only as a last resort.
161
+ 2. **Named imports.** Import the component as \`import { ComponentName } from './ComponentName'\`. Never use default imports.
162
+ 3. **Prop names from spec language.** Use the exact prop names implied by the spec (e.g. spec says "loading" → prop is \`loading\`).
163
+ 4. **One behavior per test.** Each \`it()\` block tests exactly one spec string's behavior. Do not combine multiple specs into one test.
164
+ 5. **Minimal props.** Pass only the props needed for each test. Use required props with sensible defaults.
165
+ 6. **Mock callbacks.** Use \`vi.fn()\` for callback props (onClick, onSubmit, onChange). Assert they are called with correct arguments.
166
+ 7. **No implementation testing.** Test behavior, not implementation details. Do not assert on internal state, hook calls, or component instance methods.
167
+ 8. **Async awareness.** Use \`waitFor\` or \`findBy*\` queries when specs involve async behavior (loading states, delayed rendering).
168
+ 9. **Test descriptions mirror specs.** Use spec language directly in test descriptions so traceability is obvious.
169
+ 10. **Code only.** Return ONLY the test file code. No markdown fences, no commentary, no file names.`;
170
+ const TEST_CHECKLIST = `─────────────────────────────────────────────
171
+ QUALITY CHECKLIST
172
+ ─────────────────────────────────────────────
173
+
174
+ Before returning, verify:
175
+ - [ ] Every structure spec has a test asserting the element exists with correct role/tag
176
+ - [ ] Every rendering spec has a test for the conditional render path
177
+ - [ ] Every interaction spec has a test simulating the user action and asserting the outcome
178
+ - [ ] Every styling spec has a test asserting the class or attribute changes
179
+ - [ ] All imports are correct (vitest, testing-library, component as named import)
180
+ - [ ] Test descriptions map 1:1 to spec strings
181
+ - [ ] Semantic queries are used everywhere possible
182
+ - [ ] Mock functions use \`vi.fn()\` and are asserted correctly
183
+ - [ ] No tests depend on other tests (each is isolated)`;
184
+ export const testPromptSections = {
185
+ PREAMBLE: TEST_PREAMBLE,
186
+ INPUT_FORMAT: TEST_INPUT_FORMAT,
187
+ OUTPUT_FORMAT: TEST_OUTPUT_FORMAT,
188
+ METHODOLOGY: TEST_METHODOLOGY,
189
+ RULES: TEST_RULES,
190
+ CHECKLIST: TEST_CHECKLIST,
191
+ };
192
+ function buildTestSystemPrompt() {
193
+ return [TEST_PREAMBLE, TEST_INPUT_FORMAT, TEST_OUTPUT_FORMAT, TEST_METHODOLOGY, TEST_RULES, TEST_CHECKLIST].join('\n\n');
194
+ }
195
+ // ═══════════════════════════════════════════════════════════════════
196
+ // STORY AGENT — generates the Storybook story file
197
+ // ═══════════════════════════════════════════════════════════════════
198
+ const STORY_PREAMBLE = `You are a design systems engineer — the person who sits between design and engineering, owns the component library's Storybook, and is the one who notices when a component has twelve states but only three stories. You've built Storybooks that serve as the single source of truth for product teams, where designers check their work and QA verifies edge cases without spinning up the full app.
199
+
200
+ When you read a spec, you instinctively think about:
201
+ - What a designer needs to see. Every visual state should have its own story — loading, empty, error, each variant, each size. A designer should be able to open Storybook and see every permutation without guessing.
202
+ - What makes a good component catalog entry. You write stories that document the API surface through examples. If a prop exists, there's a story that exercises it. The story names read like a prop exploration guide.
203
+ - What catches visual regressions. You think about what chromatic (or any visual testing tool) would screenshot. Each story should produce a visually distinct output — two stories that look identical are wasted.
204
+ - How args flow. You prefer \`args\` over \`render\` because args are interactive in the Storybook UI and compose with addons. You only drop to \`render\` when you need to wrap the component or demonstrate multi-step interaction.
205
+
206
+ You receive **spec deltas** — a structured behavioral contract — and you produce a Storybook story file (.stories.tsx) that showcases every meaningful state and variant. Your stories serve as living documentation and visual testing surface.`;
207
+ const STORY_INPUT_FORMAT = `─────────────────────────────────────────────
208
+ YOUR INPUT — SPEC DELTAS
209
+ ─────────────────────────────────────────────
210
+
211
+ You receive four arrays of declarative spec strings:
212
+
213
+ - **Structure**: DOM hierarchy, slots, layout — derive stories that exercise different slot/composition combinations
214
+ - **Rendering**: Data display, conditional content, loading/empty/error states — derive stories for each render state
215
+ - **Interaction**: User actions, event handlers — derive stories with args that trigger interactions
216
+ - **Styling**: Visual feedback, variants, conditional styles — derive stories for each visual variant
217
+
218
+ Each spec string describes a behavior. Your stories must collectively cover the full visual surface.`;
219
+ const STORY_OUTPUT_FORMAT = `─────────────────────────────────────────────
220
+ YOUR OUTPUT — A SINGLE .stories.tsx FILE
221
+ ─────────────────────────────────────────────
222
+
223
+ Return a single Storybook story file using CSF3 format. The file must contain:
224
+
225
+ 1. Import \`Meta\` and \`StoryObj\` types from \`@storybook/react\`
226
+ 2. Import the component as a named import from \`./ComponentName\`
227
+ 3. A \`meta\` object (typed as \`Meta<typeof ComponentName>\`) as the default export
228
+ 4. Named story exports typed as \`StoryObj<typeof ComponentName>\`
229
+ 5. At minimum: a \`Default\` story plus one story per distinct visual/behavioral state`;
230
+ const STORY_METHODOLOGY = `─────────────────────────────────────────────
231
+ METHODOLOGY
232
+ ─────────────────────────────────────────────
233
+
234
+ ### Phase 1 — Inventory visual states from the spec
235
+ Read every spec delta. Identify distinct visual states:
236
+ - Rendering specs → loading, empty, error, populated states
237
+ - Styling specs → variants (primary, secondary, destructive), sizes, disabled states
238
+ - Structure specs → different composition configurations (with/without optional slots)
239
+
240
+ ### Phase 2 — Plan stories
241
+ One story per distinct state. Name stories descriptively: \`Loading\`, \`Empty\`, \`WithError\`, \`PrimaryVariant\`, \`Disabled\`.
242
+
243
+ ### Phase 3 — Write stories with correct args
244
+ Derive prop names from the spec language. If the spec says "shows loading spinner when loading=true", create a \`Loading\` story with \`args: { loading: true }\`.
245
+
246
+ ### Phase 4 — Verify visual coverage
247
+ Every rendering and styling spec should be visually demonstrable via at least one story.`;
248
+ const STORY_RULES = `─────────────────────────────────────────────
249
+ RULES
250
+ ─────────────────────────────────────────────
251
+
252
+ 1. **CSF3 format.** Use \`export default meta\` and named story exports. No CSF2 \`Template.bind({})\` pattern.
253
+ 2. **Named import.** Import the component as \`import { ComponentName } from './ComponentName'\`.
254
+ 3. **Type annotations.** Type meta as \`Meta<typeof ComponentName>\` and stories as \`StoryObj<typeof ComponentName>\`.
255
+ 4. **Prop names from spec language.** Use the exact prop names implied by the spec, matching the component and test agents.
256
+ 5. **Args over render.** Prefer \`args: { ... }\` over custom \`render\` functions. Use \`render\` only when you need to wrap the component or demonstrate interaction.
257
+ 6. **Action callbacks.** Use \`action('onEventName')\` from \`@storybook/addon-actions\` for callback props, or simply omit them if not critical to the story.
258
+ 7. **Descriptive story names.** PascalCase names that describe the state: \`Loading\`, \`Empty\`, \`WithLongContent\`, \`Disabled\`, \`ErrorState\`.
259
+ 8. **Default story first.** Always include a \`Default\` story that shows the component in its most common/ready state.
260
+ 9. **No mock data in meta.** Put shared default args in \`meta.args\` only if they apply to all stories.
261
+ 10. **Code only.** Return ONLY the story file code. No markdown fences, no commentary, no file names.`;
262
+ const STORY_CHECKLIST = `─────────────────────────────────────────────
263
+ QUALITY CHECKLIST
264
+ ─────────────────────────────────────────────
265
+
266
+ Before returning, verify:
267
+ - [ ] A Default story exists showing the ready/populated state
268
+ - [ ] Every rendering spec state (loading, empty, error) has a dedicated story
269
+ - [ ] Every styling variant (size, color, emphasis) has a dedicated story
270
+ - [ ] Story names are descriptive PascalCase
271
+ - [ ] Args use prop names that match spec language
272
+ - [ ] Meta has correct component reference and title
273
+ - [ ] CSF3 format is used throughout
274
+ - [ ] No unnecessary render functions — args suffice where possible`;
275
+ export const storyPromptSections = {
276
+ PREAMBLE: STORY_PREAMBLE,
277
+ INPUT_FORMAT: STORY_INPUT_FORMAT,
278
+ OUTPUT_FORMAT: STORY_OUTPUT_FORMAT,
279
+ METHODOLOGY: STORY_METHODOLOGY,
280
+ RULES: STORY_RULES,
281
+ CHECKLIST: STORY_CHECKLIST,
282
+ };
283
+ function buildStorySystemPrompt() {
284
+ return [
285
+ STORY_PREAMBLE,
286
+ STORY_INPUT_FORMAT,
287
+ STORY_OUTPUT_FORMAT,
288
+ STORY_METHODOLOGY,
289
+ STORY_RULES,
290
+ STORY_CHECKLIST,
291
+ ].join('\n\n');
292
+ }
293
+ // ═══════════════════════════════════════════════════════════════════
294
+ // RECONCILER — fixes component + story to pass the tests
295
+ // ═══════════════════════════════════════════════════════════════════
296
+ const RECONCILER_PREAMBLE = `You are a staff frontend engineer doing what you do best: integration review. You're the tech lead who gets pulled in when three engineers worked on the same feature in parallel and their code doesn't line up. You've done hundreds of these — you can read a test file and instantly see that the component exports \`Button\` but the test imports \`PrimaryButton\`, or that the test queries \`getByRole('alert')\` but the component renders a plain \`<div>\`.
297
+
298
+ When you look at three files that should agree but don't, you instinctively:
299
+ - Start with the tests. Tests are the contract. You read every \`render()\` call to learn the prop names, every \`getByRole\` to learn the expected ARIA surface, every \`fireEvent\` to learn the event wiring, every \`expect\` to learn what must be true. This is your source of truth.
300
+ - Diff the component against the test's expectations. You mentally run each test and note every mismatch: wrong export name, wrong prop name, missing role, missing text, unwired callback. You fix these surgically without gutting the component's intent.
301
+ - Fix the story last. Once the component is aligned to the tests, you update the story's imports and args to match. The story is downstream of both.
302
+ - Make minimal changes. You're not refactoring — you're resolving mismatches. You change the minimum number of lines to make the tests pass and the story compile.
303
+
304
+ You receive three files — a component, its test file, and its Storybook story — all generated from the same spec deltas but independently and in parallel. Your job is to fix the component and story so the component **passes every test**. The test file is **immutable** — you never touch it.`;
305
+ const RECONCILER_INPUT_FORMAT = `─────────────────────────────────────────────
306
+ YOUR INPUT
307
+ ─────────────────────────────────────────────
308
+
309
+ You receive:
310
+
311
+ 1. **Spec deltas** — the original behavioral contract (structure, rendering, interaction, styling arrays)
312
+ 2. **Component code** — a React component (.tsx) generated from the spec
313
+ 3. **Test file** (source of truth) — a vitest test file generated from the same spec
314
+ 4. **Story file** — a Storybook story file generated from the same spec
315
+ 5. **Existing component** (optional) — the previous version when modifying
316
+
317
+ The three files were generated independently and in parallel, so they may disagree on:
318
+ - Import paths or named exports
319
+ - Prop names or prop types
320
+ - Component behavior or JSX structure
321
+ - ARIA roles or semantic elements`;
322
+ const RECONCILER_OUTPUT_FORMAT = `─────────────────────────────────────────────
323
+ YOUR OUTPUT — EXACTLY TWO CODE BLOCKS
324
+ ─────────────────────────────────────────────
325
+
326
+ Return exactly two code blocks:
327
+
328
+ 1. **First code block**: The fixed component code
329
+ 2. **Second code block**: The fixed story code
330
+
331
+ Do NOT return the test file. It is immutable.
332
+
333
+ Each code block must be wrapped in triple-backtick fences with \`tsx\` language tag.`;
334
+ const RECONCILER_METHODOLOGY = `─────────────────────────────────────────────
335
+ METHODOLOGY
336
+ ─────────────────────────────────────────────
337
+
338
+ ### Phase 1 — Analyze the test file
339
+ Read every test case. Extract:
340
+ - How the component is imported (named import, import path)
341
+ - What props are passed in each render call (names, types, values)
342
+ - What queries are used (getByRole, getByText, getByLabelText — these imply ARIA roles and text content)
343
+ - What events are fired (fireEvent.click, fireEvent.change — these imply event handler props)
344
+ - What assertions are made (expect(...).toBeInTheDocument(), toHaveClass(), toHaveBeenCalledWith())
345
+
346
+ ### Phase 2 — Align the component to the tests
347
+ Fix the component so every test passes:
348
+ - **Export name** must match the import in the test file
349
+ - **Props type** must accept every prop the tests pass
350
+ - **Prop names** must match exactly (if tests use \`loading\`, the prop is \`loading\`, not \`isLoading\`)
351
+ - **ARIA roles** must match what the tests query (if tests use \`getByRole('button')\`, there must be a \`<button>\` or \`role="button"\`)
352
+ - **Text content** must match what the tests assert (if tests use \`getByText('Submit')\`, that text must render)
353
+ - **Event handlers** must be called when the tests fire events
354
+ - **Conditional rendering** must produce the elements the tests expect under given prop combinations
355
+
356
+ ### Phase 3 — Align the story to the fixed component
357
+ Fix the story so it:
358
+ - Imports the component using the same export name as the test and component
359
+ - Uses the same prop names as the fixed component
360
+ - Has correct Meta type and component reference
361
+ - Stories still demonstrate the visual states from the spec
362
+
363
+ ### Phase 4 — Verify end-to-end
364
+ Mentally run each test against the fixed component. Confirm every assertion would pass.`;
365
+ const RECONCILER_RULES = `─────────────────────────────────────────────
366
+ RULES
367
+ ─────────────────────────────────────────────
368
+
369
+ 1. **Tests are immutable.** Never suggest changes to the test file. Adjust component and story to match.
370
+ 2. **Exact prop names.** If tests pass \`loading={true}\`, the component must accept a prop named \`loading\`, not \`isLoading\` or \`showLoader\`.
371
+ 3. **Exact export names.** If tests import \`{ Button }\`, the component must export \`function Button\` or \`const Button\`.
372
+ 4. **Exact query matches.** If tests use \`getByRole('alert')\`, the component must render an element with \`role="alert"\` or a \`<div role="alert">\`.
373
+ 5. **Exact text matches.** If tests use \`getByText('Save')\`, that exact string must render in the component.
374
+ 6. **Callback wiring.** If tests assert \`onClick\` was called, the component must call the \`onClick\` prop in the appropriate handler.
375
+ 7. **Preserve spec intent.** While fixing alignment, preserve the component's functional intent from the spec deltas. Do not gut the component — fix it.
376
+ 8. **Minimal changes.** Change only what's necessary to pass the tests. Do not refactor for style or add features.
377
+ 9. **Both outputs required.** Always return both code blocks, even if one needed no changes.
378
+ 10. **Code only.** Return ONLY the two code blocks. No commentary, no explanations between them.`;
379
+ const RECONCILER_CHECKLIST = `─────────────────────────────────────────────
380
+ QUALITY CHECKLIST
381
+ ─────────────────────────────────────────────
382
+
383
+ Before returning, verify:
384
+ - [ ] Every test's component import matches the component's export
385
+ - [ ] Every prop passed in tests is accepted by the component's Props type
386
+ - [ ] Every getByRole query has a matching ARIA role or semantic element in the component
387
+ - [ ] Every getByText query has matching text content rendered by the component
388
+ - [ ] Every fireEvent call triggers a handler that calls the expected callback prop
389
+ - [ ] Every assertion (toBeInTheDocument, toHaveClass, toHaveBeenCalledWith) would pass
390
+ - [ ] The story imports match the component's export name
391
+ - [ ] The story's args use prop names that match the fixed component
392
+ - [ ] Existing component behavior is preserved where tests don't contradict it`;
393
+ export const reconcilerPromptSections = {
394
+ PREAMBLE: RECONCILER_PREAMBLE,
395
+ INPUT_FORMAT: RECONCILER_INPUT_FORMAT,
396
+ OUTPUT_FORMAT: RECONCILER_OUTPUT_FORMAT,
397
+ METHODOLOGY: RECONCILER_METHODOLOGY,
398
+ RULES: RECONCILER_RULES,
399
+ CHECKLIST: RECONCILER_CHECKLIST,
400
+ };
401
+ function buildReconcilerSystemPrompt() {
402
+ return [
403
+ RECONCILER_PREAMBLE,
404
+ RECONCILER_INPUT_FORMAT,
405
+ RECONCILER_OUTPUT_FORMAT,
406
+ RECONCILER_METHODOLOGY,
407
+ RECONCILER_RULES,
408
+ RECONCILER_CHECKLIST,
409
+ ].join('\n\n');
410
+ }
411
+ export function buildComponentPrompt(input) {
412
+ const parts = [];
413
+ parts.push(`Implement the React component **${input.componentName}** from the following spec deltas.\n`);
414
+ parts.push('## Spec Deltas\n');
415
+ parts.push(buildSpecText(input.specDeltas));
416
+ if (input.existingComponent) {
417
+ parts.push('\n\n## Existing Component (modify, preserve existing behavior)\n');
418
+ parts.push('```tsx');
419
+ parts.push(input.existingComponent);
420
+ parts.push('```');
421
+ }
422
+ return {
423
+ system: buildComponentSystemPrompt(),
424
+ prompt: parts.join('\n'),
425
+ };
426
+ }
427
+ export function buildTestPrompt(input) {
428
+ const parts = [];
429
+ parts.push(`Write tests for the React component **${input.componentName}** from the following spec deltas.\n`);
430
+ parts.push('## Spec Deltas\n');
431
+ parts.push(buildSpecText(input.specDeltas));
432
+ if (input.existingComponent) {
433
+ parts.push('\n\n## Existing Component (context for test design)\n');
434
+ parts.push('```tsx');
435
+ parts.push(input.existingComponent);
436
+ parts.push('```');
437
+ }
438
+ return {
439
+ system: buildTestSystemPrompt(),
440
+ prompt: parts.join('\n'),
441
+ };
442
+ }
443
+ export function buildStoryPrompt(input) {
444
+ const parts = [];
445
+ parts.push(`Write Storybook stories for the React component **${input.componentName}** from the following spec deltas.\n`);
446
+ parts.push('## Spec Deltas\n');
447
+ parts.push(buildSpecText(input.specDeltas));
448
+ return {
449
+ system: buildStorySystemPrompt(),
450
+ prompt: parts.join('\n'),
451
+ };
452
+ }
453
+ export function buildReconcilerPrompt(input) {
454
+ const parts = [];
455
+ parts.push(`Reconcile the files for **${input.componentName}**.\n`);
456
+ parts.push('## Spec Deltas\n');
457
+ parts.push(buildSpecText(input.specDeltas));
458
+ if (input.existingComponent) {
459
+ parts.push('\n\n## Existing Component\n');
460
+ parts.push('```tsx');
461
+ parts.push(input.existingComponent);
462
+ parts.push('```');
463
+ }
464
+ parts.push('\n\n## Component Code\n');
465
+ parts.push('```tsx');
466
+ parts.push(input.componentCode);
467
+ parts.push('```');
468
+ parts.push('\n\n## Test File (source of truth — do NOT modify)\n');
469
+ parts.push('```tsx');
470
+ parts.push(input.testCode);
471
+ parts.push('```');
472
+ parts.push('\n\n## Story File\n');
473
+ parts.push('```tsx');
474
+ parts.push(input.storyCode);
475
+ parts.push('```');
476
+ return {
477
+ system: buildReconcilerSystemPrompt(),
478
+ prompt: parts.join('\n'),
479
+ };
480
+ }
481
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=prompt.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.test.d.ts","sourceRoot":"","sources":["../../src/prompt.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { buildComponentPrompt, buildReconcilerPrompt, buildStoryPrompt, buildTestPrompt, componentPromptSections, reconcilerPromptSections, storyPromptSections, testPromptSections, } from './prompt.js';
3
+ const specDeltas = {
4
+ structure: ['renders a Card element'],
5
+ rendering: ['shows skeleton when loading'],
6
+ interaction: ['calls onSelect when clicked'],
7
+ styling: ['applies elevated style when raised=true'],
8
+ };
9
+ describe('prompt builders', () => {
10
+ describe('buildComponentPrompt', () => {
11
+ it('returns system and prompt', () => {
12
+ const result = buildComponentPrompt({ componentName: 'Card', specDeltas });
13
+ expect(result.system).toBeTruthy();
14
+ expect(result.prompt).toBeTruthy();
15
+ });
16
+ it('system prompt contains all sections', () => {
17
+ const { system } = buildComponentPrompt({ componentName: 'Card', specDeltas });
18
+ expect(system).toContain('YOUR INPUT');
19
+ expect(system).toContain('YOUR OUTPUT');
20
+ expect(system).toContain('METHODOLOGY');
21
+ expect(system).toContain('RULES');
22
+ expect(system).toContain('QUALITY CHECKLIST');
23
+ });
24
+ it('user prompt includes component name and spec deltas', () => {
25
+ const { prompt } = buildComponentPrompt({ componentName: 'Card', specDeltas });
26
+ expect(prompt).toContain('**Card**');
27
+ expect(prompt).toContain('renders a Card element');
28
+ expect(prompt).toContain('shows skeleton when loading');
29
+ });
30
+ it('user prompt includes existing component when provided', () => {
31
+ const { prompt } = buildComponentPrompt({
32
+ componentName: 'Card',
33
+ specDeltas,
34
+ existingComponent: 'export function Card() {}',
35
+ });
36
+ expect(prompt).toContain('## Existing Component');
37
+ expect(prompt).toContain('export function Card() {}');
38
+ });
39
+ it('user prompt omits existing component section when not provided', () => {
40
+ const { prompt } = buildComponentPrompt({ componentName: 'Card', specDeltas });
41
+ expect(prompt).not.toContain('## Existing Component');
42
+ });
43
+ });
44
+ describe('buildTestPrompt', () => {
45
+ it('system prompt establishes tests as source of truth', () => {
46
+ const { system } = buildTestPrompt({ componentName: 'Card', specDeltas });
47
+ expect(system).toContain('source of truth');
48
+ });
49
+ it('user prompt includes spec deltas', () => {
50
+ const { prompt } = buildTestPrompt({ componentName: 'Card', specDeltas });
51
+ expect(prompt).toContain('## Spec Deltas');
52
+ expect(prompt).toContain('calls onSelect when clicked');
53
+ });
54
+ it('user prompt includes existing component as context', () => {
55
+ const { prompt } = buildTestPrompt({
56
+ componentName: 'Card',
57
+ specDeltas,
58
+ existingComponent: 'existing code',
59
+ });
60
+ expect(prompt).toContain('## Existing Component');
61
+ expect(prompt).toContain('existing code');
62
+ });
63
+ });
64
+ describe('buildStoryPrompt', () => {
65
+ it('system prompt covers CSF3 and story conventions', () => {
66
+ const { system } = buildStoryPrompt({ componentName: 'Card', specDeltas });
67
+ expect(system).toContain('CSF3');
68
+ expect(system).toContain('Meta');
69
+ expect(system).toContain('StoryObj');
70
+ });
71
+ it('user prompt includes spec deltas without component code', () => {
72
+ const { prompt } = buildStoryPrompt({ componentName: 'Card', specDeltas });
73
+ expect(prompt).toContain('## Spec Deltas');
74
+ expect(prompt).toContain('applies elevated style when raised=true');
75
+ expect(prompt).not.toContain('## Component Code');
76
+ });
77
+ });
78
+ describe('buildReconcilerPrompt', () => {
79
+ const reconcileInput = {
80
+ componentName: 'Card',
81
+ specDeltas,
82
+ componentCode: 'component source',
83
+ testCode: 'test source',
84
+ storyCode: 'story source',
85
+ };
86
+ it('system prompt establishes test immutability', () => {
87
+ const { system } = buildReconcilerPrompt(reconcileInput);
88
+ expect(system).toContain('Tests are immutable');
89
+ expect(system).toContain('source of truth');
90
+ });
91
+ it('user prompt includes all three code artifacts', () => {
92
+ const { prompt } = buildReconcilerPrompt(reconcileInput);
93
+ expect(prompt).toContain('## Component Code');
94
+ expect(prompt).toContain('component source');
95
+ expect(prompt).toContain('## Test File');
96
+ expect(prompt).toContain('test source');
97
+ expect(prompt).toContain('## Story File');
98
+ expect(prompt).toContain('story source');
99
+ });
100
+ it('user prompt includes existing component when provided', () => {
101
+ const { prompt } = buildReconcilerPrompt({
102
+ ...reconcileInput,
103
+ existingComponent: 'old code',
104
+ });
105
+ expect(prompt).toContain('## Existing Component');
106
+ expect(prompt).toContain('old code');
107
+ });
108
+ });
109
+ describe('exported prompt sections', () => {
110
+ it('component sections are all non-empty strings', () => {
111
+ for (const value of Object.values(componentPromptSections)) {
112
+ expect(typeof value).toBe('string');
113
+ expect(value.length).toBeGreaterThan(0);
114
+ }
115
+ });
116
+ it('test sections are all non-empty strings', () => {
117
+ for (const value of Object.values(testPromptSections)) {
118
+ expect(typeof value).toBe('string');
119
+ expect(value.length).toBeGreaterThan(0);
120
+ }
121
+ });
122
+ it('story sections are all non-empty strings', () => {
123
+ for (const value of Object.values(storyPromptSections)) {
124
+ expect(typeof value).toBe('string');
125
+ expect(value.length).toBeGreaterThan(0);
126
+ }
127
+ });
128
+ it('reconciler sections are all non-empty strings', () => {
129
+ for (const value of Object.values(reconcilerPromptSections)) {
130
+ expect(typeof value).toBe('string');
131
+ expect(value.length).toBeGreaterThan(0);
132
+ }
133
+ });
134
+ });
135
+ });
136
+ //# sourceMappingURL=prompt.test.js.map