@auto-engineer/component-implementor-react 1.95.0 → 1.97.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 +90 -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
@@ -1 +1 @@
1
- {"version":3,"file":"generate-story.js","sourceRoot":"","sources":["../../src/generate-story.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAexD,SAAS,gBAAgB,CAAC,OAAe,EAAE,KAAe;IACxD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO,MAAM,OAAO,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,SAAS,WAAW,CAAC,KAAyB;IAC5C,MAAM,QAAQ,GAAG;QACf,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;QACzD,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;QACzD,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC;QAC7D,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;KACtD;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO,cAAc,KAAK,CAAC,aAAa,OAAO,QAAQ,qCAAqC,KAAK,CAAC,aAAa,UAAU,CAAC;AAC5H,CAAC;AAED,MAAM,aAAa,GAAG;;;;;;iDAM2B,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAyB;IAC/D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,YAAY,CAAC;QAClC,KAAK,EAAE,kBAAkB,EAAE;QAC3B,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC;KAC3B,CAAC,CAAC;IACH,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"generate-story.js","sourceRoot":"","sources":["../../src/generate-story.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAyB,MAAM,UAAU,CAAC;AAInE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAyB;IAC/D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACnD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,YAAY,CAAC;QAClC,KAAK,EAAE,kBAAkB,EAAE;QAC3B,MAAM;QACN,MAAM;KACP,CAAC,CAAC;IACH,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
@@ -25,38 +25,34 @@ describe('generateStoryFile', () => {
25
25
  const result = await generateStoryFile({
26
26
  componentName: 'Button',
27
27
  specDeltas,
28
- componentCode: 'export function Button() { return <button />; }',
29
28
  });
30
29
  expect(result).toBe('import type { Meta } from "@storybook/react";');
31
30
  });
32
- it('includes spec deltas and component code in the prompt', async () => {
31
+ it('passes system prompt with methodology, rules, and checklist', async () => {
33
32
  const mockGenerateText = vi.mocked(generateText);
34
33
  mockGenerateText.mockResolvedValue({
35
34
  text: 'story code',
36
35
  });
37
- await generateStoryFile({
38
- componentName: 'Button',
39
- specDeltas,
40
- componentCode: 'export function Button() {}',
41
- });
42
- const prompt = mockGenerateText.mock.calls[0][0].prompt;
43
- expect(prompt).toContain('## Structure');
44
- expect(prompt).toContain('renders a Button element');
45
- expect(prompt).toContain('## Component Code');
46
- expect(prompt).toContain('export function Button() {}');
36
+ await generateStoryFile({ componentName: 'Button', specDeltas });
37
+ const system = mockGenerateText.mock.calls[0][0].system;
38
+ expect(system).toContain('design systems engineer');
39
+ expect(system).toContain('METHODOLOGY');
40
+ expect(system).toContain('RULES');
41
+ expect(system).toContain('QUALITY CHECKLIST');
42
+ expect(system).toContain('CSF3 format');
43
+ expect(system).toContain('Named import');
47
44
  });
48
- it('uses system prompt referencing Storybook', async () => {
45
+ it('includes spec deltas in the user prompt but not component code', async () => {
49
46
  const mockGenerateText = vi.mocked(generateText);
50
47
  mockGenerateText.mockResolvedValue({
51
- text: 'code',
52
- });
53
- await generateStoryFile({
54
- componentName: 'Button',
55
- specDeltas,
56
- componentCode: 'code',
48
+ text: 'story code',
57
49
  });
58
- const system = mockGenerateText.mock.calls[0][0].system;
59
- expect(system).toContain('Storybook');
50
+ await generateStoryFile({ componentName: 'Button', specDeltas });
51
+ const prompt = mockGenerateText.mock.calls[0][0].prompt;
52
+ expect(prompt).toContain('## Spec Deltas');
53
+ expect(prompt).toContain('## Structure');
54
+ expect(prompt).toContain('renders a Button element');
55
+ expect(prompt).not.toContain('## Component Code');
60
56
  });
61
57
  });
62
58
  //# sourceMappingURL=generate-story.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-story.test.js","sourceRoot":"","sources":["../../src/generate-story.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generate-story.test.js","sourceRoot":"","sources":["../../src/generate-story.test.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,4 @@
1
- type SpecDeltas = {
2
- structure: string[];
3
- rendering: string[];
4
- interaction: string[];
5
- styling: string[];
6
- };
7
- type GenerateTestInput = {
8
- componentName: string;
9
- specDeltas: SpecDeltas;
10
- existingComponent?: string;
11
- };
1
+ import { type TestPromptInput } from './prompt';
2
+ export type GenerateTestInput = TestPromptInput;
12
3
  export declare function generateTestFile(input: GenerateTestInput): Promise<string>;
13
- export {};
14
4
  //# sourceMappingURL=generate-test.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-test.d.ts","sourceRoot":"","sources":["../../src/generate-test.ts"],"names":[],"mappings":"AAIA,KAAK,UAAU,GAAG;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAgCF,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAOhF"}
1
+ {"version":3,"file":"generate-test.d.ts","sourceRoot":"","sources":["../../src/generate-test.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAEjE,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAQhF"}
@@ -1,37 +1,13 @@
1
1
  import { createModelFromEnv } from '@auto-engineer/model-factory';
2
2
  import { generateText } from 'ai';
3
3
  import { extractCodeBlock } from './extract-code-block.js';
4
- function buildSpecSection(heading, items) {
5
- if (items.length === 0)
6
- return '';
7
- return `## ${heading}\n${items.map((i) => `- ${i}`).join('\n')}`;
8
- }
9
- function buildPrompt(input) {
10
- const sections = [
11
- buildSpecSection('Structure', input.specDeltas.structure),
12
- buildSpecSection('Rendering', input.specDeltas.rendering),
13
- buildSpecSection('Interaction', input.specDeltas.interaction),
14
- buildSpecSection('Styling', input.specDeltas.styling),
15
- ]
16
- .filter(Boolean)
17
- .join('\n\n');
18
- const existingContext = input.existingComponent
19
- ? `\n\n## Existing Component\n\`\`\`tsx\n${input.existingComponent}\n\`\`\``
20
- : '';
21
- return `Component: ${input.componentName}\n\n${sections}${existingContext}`;
22
- }
23
- const SYSTEM_PROMPT = `You are a React testing expert. Write a vitest test file for the described component using @testing-library/react.
24
-
25
- Rules:
26
- - Import from vitest (describe, it, expect) and @testing-library/react (render, screen, fireEvent)
27
- - Use describe/it blocks
28
- - Test each specified behavior
29
- - Return ONLY the test file code, no commentary`;
4
+ import { buildTestPrompt } from './prompt.js';
30
5
  export async function generateTestFile(input) {
6
+ const { system, prompt } = buildTestPrompt(input);
31
7
  const { text } = await generateText({
32
8
  model: createModelFromEnv(),
33
- system: SYSTEM_PROMPT,
34
- prompt: buildPrompt(input),
9
+ system,
10
+ prompt,
35
11
  });
36
12
  return extractCodeBlock(text);
37
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generate-test.js","sourceRoot":"","sources":["../../src/generate-test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAexD,SAAS,gBAAgB,CAAC,OAAe,EAAE,KAAe;IACxD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO,MAAM,OAAO,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,SAAS,WAAW,CAAC,KAAwB;IAC3C,MAAM,QAAQ,GAAG;QACf,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;QACzD,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC;QACzD,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC;QAC7D,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;KACtD;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,eAAe,GAAG,KAAK,CAAC,iBAAiB;QAC7C,CAAC,CAAC,yCAAyC,KAAK,CAAC,iBAAiB,UAAU;QAC5E,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,cAAc,KAAK,CAAC,aAAa,OAAO,QAAQ,GAAG,eAAe,EAAE,CAAC;AAC9E,CAAC;AAED,MAAM,aAAa,GAAG;;;;;;gDAM0B,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAwB;IAC7D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,YAAY,CAAC;QAClC,KAAK,EAAE,kBAAkB,EAAE;QAC3B,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC;KAC3B,CAAC,CAAC;IACH,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"generate-test.js","sourceRoot":"","sources":["../../src/generate-test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAwB,MAAM,UAAU,CAAC;AAIjE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAwB;IAC7D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,YAAY,CAAC;QAClC,KAAK,EAAE,kBAAkB,EAAE;QAC3B,MAAM;QACN,MAAM;KACP,CAAC,CAAC;IACH,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
@@ -17,7 +17,7 @@ describe('generateTestFile', () => {
17
17
  afterEach(() => {
18
18
  vi.clearAllMocks();
19
19
  });
20
- it('returns generated test code from AI with spec deltas in prompt', async () => {
20
+ it('returns generated test code from AI', async () => {
21
21
  const mockGenerateText = vi.mocked(generateText);
22
22
  mockGenerateText.mockResolvedValue({
23
23
  text: '```tsx\nimport { render } from "@testing-library/react";\n```',
@@ -27,19 +27,29 @@ describe('generateTestFile', () => {
27
27
  specDeltas,
28
28
  });
29
29
  expect(result).toBe('import { render } from "@testing-library/react";');
30
- expect(mockGenerateText).toHaveBeenCalledWith({
31
- model: 'mock-model',
32
- system: expect.stringContaining('vitest'),
33
- prompt: expect.stringContaining('renders a Button element'),
30
+ });
31
+ it('passes system prompt with methodology, rules, and checklist', async () => {
32
+ const mockGenerateText = vi.mocked(generateText);
33
+ mockGenerateText.mockResolvedValue({
34
+ text: 'test code',
34
35
  });
36
+ await generateTestFile({ componentName: 'Button', specDeltas });
37
+ const system = mockGenerateText.mock.calls[0][0].system;
38
+ expect(system).toContain('senior frontend engineer who specializes in testing');
39
+ expect(system).toContain('METHODOLOGY');
40
+ expect(system).toContain('RULES');
41
+ expect(system).toContain('QUALITY CHECKLIST');
42
+ expect(system).toContain('Semantic queries first');
43
+ expect(system).toContain('source of truth');
35
44
  });
36
- it('includes all spec delta sections in the prompt', async () => {
45
+ it('includes all spec delta sections in the user prompt', async () => {
37
46
  const mockGenerateText = vi.mocked(generateText);
38
47
  mockGenerateText.mockResolvedValue({
39
48
  text: 'test code',
40
49
  });
41
50
  await generateTestFile({ componentName: 'Button', specDeltas });
42
51
  const prompt = mockGenerateText.mock.calls[0][0].prompt;
52
+ expect(prompt).toContain('## Spec Deltas');
43
53
  expect(prompt).toContain('## Structure');
44
54
  expect(prompt).toContain('renders a Button element');
45
55
  expect(prompt).toContain('## Rendering');
@@ -60,6 +70,7 @@ describe('generateTestFile', () => {
60
70
  existingComponent: 'export function Button() { return <button />; }',
61
71
  });
62
72
  const prompt = mockGenerateText.mock.calls[0][0].prompt;
73
+ expect(prompt).toContain('## Existing Component');
63
74
  expect(prompt).toContain('export function Button() { return <button />; }');
64
75
  });
65
76
  });
@@ -1 +1 @@
1
- {"version":3,"file":"generate-test.test.js","sourceRoot":"","sources":["../../src/generate-test.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generate-test.test.js","sourceRoot":"","sources":["../../src/generate-test.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnB,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;CACtB,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,8BAA8B,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7C,kBAAkB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;CAC9C,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAElC,MAAM,UAAU,GAAG;IACjB,SAAS,EAAE,CAAC,0BAA0B,EAAE,uBAAuB,CAAC;IAChE,SAAS,EAAE,CAAC,yCAAyC,CAAC;IACtD,WAAW,EAAE,CAAC,4BAA4B,CAAC;IAC3C,OAAO,EAAE,CAAC,oCAAoC,CAAC;CAChD,CAAC;AAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,gBAAgB,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACjD,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,IAAI,EAAE,+DAA+D;SAC1B,CAAC,CAAC;QAE/C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC;YACpC,aAAa,EAAE,QAAQ;YACvB,UAAU;SACX,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,gBAAgB,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACjD,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,IAAI,EAAE,WAAW;SAC0B,CAAC,CAAC;QAE/C,MAAM,gBAAgB,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAgB,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,qDAAqD,CAAC,CAAC;QAChF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,gBAAgB,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACjD,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,IAAI,EAAE,WAAW;SAC0B,CAAC,CAAC;QAE/C,MAAM,gBAAgB,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAgB,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,yCAAyC,CAAC,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oCAAoC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,gBAAgB,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACjD,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,IAAI,EAAE,WAAW;SAC0B,CAAC,CAAC;QAE/C,MAAM,gBAAgB,CAAC;YACrB,aAAa,EAAE,QAAQ;YACvB,UAAU;YACV,iBAAiB,EAAE,iDAAiD;SACrE,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAgB,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iDAAiD,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { type SpecDeltas } from './spec-contract';
2
+ export interface PromptResult {
3
+ system: string;
4
+ prompt: string;
5
+ }
6
+ export declare const componentPromptSections: {
7
+ readonly 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.\n\nWhen you read a spec, you instinctively think about:\n- 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.\n- 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.\n- 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.\n- What breaks at the edges. Empty strings, missing callbacks, rapid re-renders. You handle them gracefully because you've been burned before.\n\nYou 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.";
8
+ readonly INPUT_FORMAT: "─────────────────────────────────────────────\nYOUR INPUT — SPEC DELTAS\n─────────────────────────────────────────────\n\nYou receive four arrays of declarative spec strings:\n\n- **Structure**: DOM hierarchy, slots, layout, composition (e.g. \"Contains a header region and a content region\")\n- **Rendering**: Data display, conditional content, loading/empty/error states (e.g. \"Shows loading spinner while data fetches\")\n- **Interaction**: User actions, event handlers, state transitions (e.g. \"Calls onSubmit when form is submitted\")\n- **Styling**: Visual feedback, animations, conditional styles (e.g. \"Applies destructive style when variant is danger\")\n\nEach spec string describes exactly one behavior or constraint. Your component must satisfy every one.\n\nWhen an existing component is provided, you are modifying it — preserve all existing behavior and add the new specs on top.";
9
+ readonly OUTPUT_FORMAT: "─────────────────────────────────────────────\nYOUR OUTPUT — A SINGLE .tsx FILE\n─────────────────────────────────────────────\n\nReturn a single TypeScript React component file. The file must contain:\n\n1. All necessary imports at the top\n2. An exported Props type (e.g. `export type ButtonProps = { ... }`)\n3. A named export of the component function (e.g. `export function Button({ ... }: ButtonProps) { ... }`)\n4. No default exports";
10
+ readonly METHODOLOGY: "─────────────────────────────────────────────\nMETHODOLOGY\n─────────────────────────────────────────────\n\n### Phase 1 — Read and internalize the spec\nRead every spec delta. Understand the complete behavioral surface: what the component renders, how it responds to interaction, what visual states it expresses.\n\n### Phase 2 — Derive the props interface\nEach 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.\n\nName props to match the spec language directly. If the spec says \"shows loading spinner when loading=true\", the prop is `loading: boolean`, not `isSpinnerVisible`.\n\n### Phase 3 — Implement the component body\nBuild 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.\n\n### Phase 4 — Verify completeness\nWalk through each spec delta and confirm the implementation covers it. Every spec string must trace to a specific line of code.";
11
+ readonly RULES: "─────────────────────────────────────────────\nRULES\n─────────────────────────────────────────────\n\n1. **Functional components only.** Use `function ComponentName` with TypeScript. No class components.\n2. **Named exports.** Export the component as a named export. Export the Props type. No default exports.\n3. **Tailwind CSS.** Use Tailwind utility classes for all styling. No inline styles, no CSS modules, no styled-components.\n4. **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.\n5. **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`.\n6. **One file.** Everything goes in one file — imports, types, component. No splitting into sub-files.\n7. **No side effects.** No fetch calls, no localStorage, no timers unless a spec explicitly requires them.\n8. **No unnecessary state.** Derive from props where possible. Only use `useState` when the component genuinely manages internal state per spec.\n9. **Composition-ready.** If structure specs mention slots or regions, accept them as children or named props (e.g. `header`, `footer`).\n10. **Code only.** Return ONLY the component file code. No markdown fences, no commentary, no file names.";
12
+ readonly CHECKLIST: "─────────────────────────────────────────────\nQUALITY CHECKLIST\n─────────────────────────────────────────────\n\nBefore returning, verify:\n- [ ] Every structure spec is reflected in the JSX tree\n- [ ] Every rendering spec has a corresponding conditional render\n- [ ] Every interaction spec has a corresponding event handler wired to a prop\n- [ ] Every styling spec has corresponding Tailwind classes (conditionally applied where needed)\n- [ ] Props type is exported and names match spec language\n- [ ] Component is exported as a named export\n- [ ] ARIA roles and semantic elements are used where specs imply them\n- [ ] No dead code or unused imports\n- [ ] Existing component behavior is preserved when modifying";
13
+ };
14
+ export declare const testPromptSections: {
15
+ readonly 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.\n\nWhen you read a spec, you instinctively think about:\n- 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.\n- 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.\n- 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.\n- 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`.\n\nYou 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.";
16
+ readonly INPUT_FORMAT: "─────────────────────────────────────────────\nYOUR INPUT — SPEC DELTAS\n─────────────────────────────────────────────\n\nYou receive four arrays of declarative spec strings:\n\n- **Structure**: DOM hierarchy, slots, layout, composition — test that elements exist and are correctly nested\n- **Rendering**: Data display, conditional content, loading/empty/error states — test what renders under different prop combinations\n- **Interaction**: User actions, event handlers, state transitions — test that events fire and state changes occur\n- **Styling**: Visual feedback, conditional styles — test that CSS classes or attributes change based on props/state\n\nEach spec string describes exactly one behavior. Write at least one test for each spec.\n\nWhen an existing component is provided, you are testing a modification — ensure tests cover both new and preserved behavior.";
17
+ readonly OUTPUT_FORMAT: "─────────────────────────────────────────────\nYOUR OUTPUT — A SINGLE .test.tsx FILE\n─────────────────────────────────────────────\n\nReturn a single vitest test file. The file must:\n\n1. Import `describe`, `it`, `expect` from `vitest` and `vi` if mocking is needed\n2. Import `render`, `screen`, `fireEvent` (and `waitFor` if async) from `@testing-library/react`\n3. Import the component as a **named import** from `./ComponentName`\n4. Use a top-level `describe('ComponentName', () => { ... })` block\n5. Group related tests in nested `describe` blocks by spec category when the component has many specs";
18
+ readonly METHODOLOGY: "─────────────────────────────────────────────\nMETHODOLOGY\n─────────────────────────────────────────────\n\n### Phase 1 — Read the spec and plan test cases\nRead every spec delta. For each spec string, determine:\n- What to render (which props to pass)\n- What to assert (what element, text, attribute, or callback to verify)\n- What user action to simulate (if any)\n\n### Phase 2 — Derive prop names from spec language\nThe 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.\n\n### Phase 3 — Write precise, isolated tests\nEach `it()` block tests one spec. The test description should read as the spec behavior (e.g. `it('shows loading spinner when loading is true')`).\n\n### Phase 4 — Verify coverage\nWalk through each spec delta and confirm at least one test covers it. No spec should be untested.";
19
+ readonly RULES: "─────────────────────────────────────────────\nRULES\n─────────────────────────────────────────────\n\n1. **Semantic queries first.** Prefer `getByRole`, `getByLabelText`, `getByText` over `getByTestId`. Use `getByTestId` only as a last resort.\n2. **Named imports.** Import the component as `import { ComponentName } from './ComponentName'`. Never use default imports.\n3. **Prop names from spec language.** Use the exact prop names implied by the spec (e.g. spec says \"loading\" → prop is `loading`).\n4. **One behavior per test.** Each `it()` block tests exactly one spec string's behavior. Do not combine multiple specs into one test.\n5. **Minimal props.** Pass only the props needed for each test. Use required props with sensible defaults.\n6. **Mock callbacks.** Use `vi.fn()` for callback props (onClick, onSubmit, onChange). Assert they are called with correct arguments.\n7. **No implementation testing.** Test behavior, not implementation details. Do not assert on internal state, hook calls, or component instance methods.\n8. **Async awareness.** Use `waitFor` or `findBy*` queries when specs involve async behavior (loading states, delayed rendering).\n9. **Test descriptions mirror specs.** Use spec language directly in test descriptions so traceability is obvious.\n10. **Code only.** Return ONLY the test file code. No markdown fences, no commentary, no file names.";
20
+ readonly CHECKLIST: "─────────────────────────────────────────────\nQUALITY CHECKLIST\n─────────────────────────────────────────────\n\nBefore returning, verify:\n- [ ] Every structure spec has a test asserting the element exists with correct role/tag\n- [ ] Every rendering spec has a test for the conditional render path\n- [ ] Every interaction spec has a test simulating the user action and asserting the outcome\n- [ ] Every styling spec has a test asserting the class or attribute changes\n- [ ] All imports are correct (vitest, testing-library, component as named import)\n- [ ] Test descriptions map 1:1 to spec strings\n- [ ] Semantic queries are used everywhere possible\n- [ ] Mock functions use `vi.fn()` and are asserted correctly\n- [ ] No tests depend on other tests (each is isolated)";
21
+ };
22
+ export declare const storyPromptSections: {
23
+ readonly 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.\n\nWhen you read a spec, you instinctively think about:\n- 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.\n- 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.\n- 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.\n- 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.\n\nYou 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.";
24
+ readonly INPUT_FORMAT: "─────────────────────────────────────────────\nYOUR INPUT — SPEC DELTAS\n─────────────────────────────────────────────\n\nYou receive four arrays of declarative spec strings:\n\n- **Structure**: DOM hierarchy, slots, layout — derive stories that exercise different slot/composition combinations\n- **Rendering**: Data display, conditional content, loading/empty/error states — derive stories for each render state\n- **Interaction**: User actions, event handlers — derive stories with args that trigger interactions\n- **Styling**: Visual feedback, variants, conditional styles — derive stories for each visual variant\n\nEach spec string describes a behavior. Your stories must collectively cover the full visual surface.";
25
+ readonly OUTPUT_FORMAT: "─────────────────────────────────────────────\nYOUR OUTPUT — A SINGLE .stories.tsx FILE\n─────────────────────────────────────────────\n\nReturn a single Storybook story file using CSF3 format. The file must contain:\n\n1. Import `Meta` and `StoryObj` types from `@storybook/react`\n2. Import the component as a named import from `./ComponentName`\n3. A `meta` object (typed as `Meta<typeof ComponentName>`) as the default export\n4. Named story exports typed as `StoryObj<typeof ComponentName>`\n5. At minimum: a `Default` story plus one story per distinct visual/behavioral state";
26
+ readonly METHODOLOGY: "─────────────────────────────────────────────\nMETHODOLOGY\n─────────────────────────────────────────────\n\n### Phase 1 — Inventory visual states from the spec\nRead every spec delta. Identify distinct visual states:\n- Rendering specs → loading, empty, error, populated states\n- Styling specs → variants (primary, secondary, destructive), sizes, disabled states\n- Structure specs → different composition configurations (with/without optional slots)\n\n### Phase 2 — Plan stories\nOne story per distinct state. Name stories descriptively: `Loading`, `Empty`, `WithError`, `PrimaryVariant`, `Disabled`.\n\n### Phase 3 — Write stories with correct args\nDerive prop names from the spec language. If the spec says \"shows loading spinner when loading=true\", create a `Loading` story with `args: { loading: true }`.\n\n### Phase 4 — Verify visual coverage\nEvery rendering and styling spec should be visually demonstrable via at least one story.";
27
+ readonly RULES: "─────────────────────────────────────────────\nRULES\n─────────────────────────────────────────────\n\n1. **CSF3 format.** Use `export default meta` and named story exports. No CSF2 `Template.bind({})` pattern.\n2. **Named import.** Import the component as `import { ComponentName } from './ComponentName'`.\n3. **Type annotations.** Type meta as `Meta<typeof ComponentName>` and stories as `StoryObj<typeof ComponentName>`.\n4. **Prop names from spec language.** Use the exact prop names implied by the spec, matching the component and test agents.\n5. **Args over render.** Prefer `args: { ... }` over custom `render` functions. Use `render` only when you need to wrap the component or demonstrate interaction.\n6. **Action callbacks.** Use `action('onEventName')` from `@storybook/addon-actions` for callback props, or simply omit them if not critical to the story.\n7. **Descriptive story names.** PascalCase names that describe the state: `Loading`, `Empty`, `WithLongContent`, `Disabled`, `ErrorState`.\n8. **Default story first.** Always include a `Default` story that shows the component in its most common/ready state.\n9. **No mock data in meta.** Put shared default args in `meta.args` only if they apply to all stories.\n10. **Code only.** Return ONLY the story file code. No markdown fences, no commentary, no file names.";
28
+ readonly CHECKLIST: "─────────────────────────────────────────────\nQUALITY CHECKLIST\n─────────────────────────────────────────────\n\nBefore returning, verify:\n- [ ] A Default story exists showing the ready/populated state\n- [ ] Every rendering spec state (loading, empty, error) has a dedicated story\n- [ ] Every styling variant (size, color, emphasis) has a dedicated story\n- [ ] Story names are descriptive PascalCase\n- [ ] Args use prop names that match spec language\n- [ ] Meta has correct component reference and title\n- [ ] CSF3 format is used throughout\n- [ ] No unnecessary render functions — args suffice where possible";
29
+ };
30
+ export declare const reconcilerPromptSections: {
31
+ readonly 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>`.\n\nWhen you look at three files that should agree but don't, you instinctively:\n- 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.\n- 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.\n- 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.\n- 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.\n\nYou 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.";
32
+ readonly INPUT_FORMAT: "─────────────────────────────────────────────\nYOUR INPUT\n─────────────────────────────────────────────\n\nYou receive:\n\n1. **Spec deltas** — the original behavioral contract (structure, rendering, interaction, styling arrays)\n2. **Component code** — a React component (.tsx) generated from the spec\n3. **Test file** (source of truth) — a vitest test file generated from the same spec\n4. **Story file** — a Storybook story file generated from the same spec\n5. **Existing component** (optional) — the previous version when modifying\n\nThe three files were generated independently and in parallel, so they may disagree on:\n- Import paths or named exports\n- Prop names or prop types\n- Component behavior or JSX structure\n- ARIA roles or semantic elements";
33
+ readonly OUTPUT_FORMAT: "─────────────────────────────────────────────\nYOUR OUTPUT — EXACTLY TWO CODE BLOCKS\n─────────────────────────────────────────────\n\nReturn exactly two code blocks:\n\n1. **First code block**: The fixed component code\n2. **Second code block**: The fixed story code\n\nDo NOT return the test file. It is immutable.\n\nEach code block must be wrapped in triple-backtick fences with `tsx` language tag.";
34
+ readonly METHODOLOGY: "─────────────────────────────────────────────\nMETHODOLOGY\n─────────────────────────────────────────────\n\n### Phase 1 — Analyze the test file\nRead every test case. Extract:\n- How the component is imported (named import, import path)\n- What props are passed in each render call (names, types, values)\n- What queries are used (getByRole, getByText, getByLabelText — these imply ARIA roles and text content)\n- What events are fired (fireEvent.click, fireEvent.change — these imply event handler props)\n- What assertions are made (expect(...).toBeInTheDocument(), toHaveClass(), toHaveBeenCalledWith())\n\n### Phase 2 — Align the component to the tests\nFix the component so every test passes:\n- **Export name** must match the import in the test file\n- **Props type** must accept every prop the tests pass\n- **Prop names** must match exactly (if tests use `loading`, the prop is `loading`, not `isLoading`)\n- **ARIA roles** must match what the tests query (if tests use `getByRole('button')`, there must be a `<button>` or `role=\"button\"`)\n- **Text content** must match what the tests assert (if tests use `getByText('Submit')`, that text must render)\n- **Event handlers** must be called when the tests fire events\n- **Conditional rendering** must produce the elements the tests expect under given prop combinations\n\n### Phase 3 — Align the story to the fixed component\nFix the story so it:\n- Imports the component using the same export name as the test and component\n- Uses the same prop names as the fixed component\n- Has correct Meta type and component reference\n- Stories still demonstrate the visual states from the spec\n\n### Phase 4 — Verify end-to-end\nMentally run each test against the fixed component. Confirm every assertion would pass.";
35
+ readonly RULES: "─────────────────────────────────────────────\nRULES\n─────────────────────────────────────────────\n\n1. **Tests are immutable.** Never suggest changes to the test file. Adjust component and story to match.\n2. **Exact prop names.** If tests pass `loading={true}`, the component must accept a prop named `loading`, not `isLoading` or `showLoader`.\n3. **Exact export names.** If tests import `{ Button }`, the component must export `function Button` or `const Button`.\n4. **Exact query matches.** If tests use `getByRole('alert')`, the component must render an element with `role=\"alert\"` or a `<div role=\"alert\">`.\n5. **Exact text matches.** If tests use `getByText('Save')`, that exact string must render in the component.\n6. **Callback wiring.** If tests assert `onClick` was called, the component must call the `onClick` prop in the appropriate handler.\n7. **Preserve spec intent.** While fixing alignment, preserve the component's functional intent from the spec deltas. Do not gut the component — fix it.\n8. **Minimal changes.** Change only what's necessary to pass the tests. Do not refactor for style or add features.\n9. **Both outputs required.** Always return both code blocks, even if one needed no changes.\n10. **Code only.** Return ONLY the two code blocks. No commentary, no explanations between them.";
36
+ readonly CHECKLIST: "─────────────────────────────────────────────\nQUALITY CHECKLIST\n─────────────────────────────────────────────\n\nBefore returning, verify:\n- [ ] Every test's component import matches the component's export\n- [ ] Every prop passed in tests is accepted by the component's Props type\n- [ ] Every getByRole query has a matching ARIA role or semantic element in the component\n- [ ] Every getByText query has matching text content rendered by the component\n- [ ] Every fireEvent call triggers a handler that calls the expected callback prop\n- [ ] Every assertion (toBeInTheDocument, toHaveClass, toHaveBeenCalledWith) would pass\n- [ ] The story imports match the component's export name\n- [ ] The story's args use prop names that match the fixed component\n- [ ] Existing component behavior is preserved where tests don't contradict it";
37
+ };
38
+ export interface ComponentPromptInput {
39
+ componentName: string;
40
+ specDeltas: SpecDeltas;
41
+ existingComponent?: string;
42
+ }
43
+ export interface TestPromptInput {
44
+ componentName: string;
45
+ specDeltas: SpecDeltas;
46
+ existingComponent?: string;
47
+ }
48
+ export interface StoryPromptInput {
49
+ componentName: string;
50
+ specDeltas: SpecDeltas;
51
+ }
52
+ export interface ReconcilerPromptInput {
53
+ componentName: string;
54
+ specDeltas: SpecDeltas;
55
+ componentCode: string;
56
+ testCode: string;
57
+ storyCode: string;
58
+ existingComponent?: string;
59
+ }
60
+ export declare function buildComponentPrompt(input: ComponentPromptInput): PromptResult;
61
+ export declare function buildTestPrompt(input: TestPromptInput): PromptResult;
62
+ export declare function buildStoryPrompt(input: StoryPromptInput): PromptResult;
63
+ export declare function buildReconcilerPrompt(input: ReconcilerPromptInput): PromptResult;
64
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMjE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AA0FD,eAAO,MAAM,uBAAuB;;;;;;;CAO1B,CAAC;AAuGX,eAAO,MAAM,kBAAkB;;;;;;;CAOrB,CAAC;AA+FX,eAAO,MAAM,mBAAmB;;;;;;;CAOtB,CAAC;AAwHX,eAAO,MAAM,wBAAwB;;;;;;;CAO3B,CAAC;AAiBX,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,CAmB9E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAmBpE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CActE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CAkChF"}