create-auto-app 1.12.0 → 1.13.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.
- package/package.json +2 -2
- package/templates/kanban-todo/README.md +2 -4
- package/templates/kanban-todo/auto.config.ts +9 -6
- package/templates/kanban-todo/package.json +4 -5
- package/templates/minimal/README.md +2 -4
- package/templates/questionnaires/README.md +2 -4
- package/templates/typical/README.md +2 -4
- package/templates/typical/auto.config.specs.ts +47 -0
- package/templates/typical/auto.config.ts +804 -75
- package/templates/typical/package.json +8 -7
- package/templates/typical/vitest.config.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-auto-app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Create Auto Engineer apps with no configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"fs-extra": "^11.2.0",
|
|
34
34
|
"inquirer": "^9.2.15",
|
|
35
35
|
"ora": "^8.0.1",
|
|
36
|
-
"@auto-engineer/id": "1.
|
|
36
|
+
"@auto-engineer/id": "1.13.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/fs-extra": "^11.0.4",
|
|
@@ -6,7 +6,7 @@ Shared design system assets for Auto Engineer examples.
|
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/
|
|
9
|
+
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/generate-react-client` package and frontend generation plugins.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -155,7 +155,5 @@ auto import:design-system \
|
|
|
155
155
|
|
|
156
156
|
| Package | Relationship |
|
|
157
157
|
|---------|--------------|
|
|
158
|
-
| `@auto-engineer/
|
|
159
|
-
| `@auto-engineer/frontend-generator-react-graphql` | Uses figma-file.json for tokens |
|
|
160
|
-
| `@auto-engineer/component-implementer` | Uses design-system.md for constraints |
|
|
158
|
+
| `@auto-engineer/generate-react-client` | Uses design system files for client generation |
|
|
161
159
|
| `@auto-engineer/information-architect` | References component list for IA |
|
|
@@ -117,15 +117,13 @@ export const fileId = 'kanbanNew1';
|
|
|
117
117
|
export const plugins = [
|
|
118
118
|
'@auto-engineer/model-diff',
|
|
119
119
|
'@auto-engineer/server-checks',
|
|
120
|
-
'@auto-engineer/design-system-importer',
|
|
121
120
|
'@auto-engineer/server-generator-apollo-emmett',
|
|
122
121
|
'@auto-engineer/narrative',
|
|
123
|
-
'@auto-engineer/frontend-checks',
|
|
124
|
-
'@auto-engineer/frontend-implementer',
|
|
125
|
-
'@auto-engineer/component-implementer',
|
|
126
122
|
'@auto-engineer/information-architect',
|
|
127
|
-
'@auto-engineer/
|
|
123
|
+
'@auto-engineer/generate-react-client',
|
|
124
|
+
'@auto-engineer/react-component-implementer',
|
|
128
125
|
'@auto-engineer/server-implementer',
|
|
126
|
+
'@auto-engineer/app-implementer',
|
|
129
127
|
'@auto-engineer/dev-server',
|
|
130
128
|
];
|
|
131
129
|
|
|
@@ -151,7 +149,7 @@ export const pipeline = define('kanban-todo')
|
|
|
151
149
|
.on('SliceGenerated')
|
|
152
150
|
.emit('ImplementSlice', (e: { data: SliceGeneratedData }) => ({
|
|
153
151
|
slicePath: resolvePath(e.data.slicePath),
|
|
154
|
-
context: { previousOutputs: '
|
|
152
|
+
context: { previousOutputs: '', attemptNumber: 0 },
|
|
155
153
|
aiOptions: { maxTokens: 2000 },
|
|
156
154
|
}))
|
|
157
155
|
|
|
@@ -183,6 +181,11 @@ export const pipeline = define('kanban-todo')
|
|
|
183
181
|
const slicePath = extractSlicePath(events);
|
|
184
182
|
|
|
185
183
|
if (!shouldRetry(slicePath)) {
|
|
184
|
+
const errors = collectErrors(allEvents);
|
|
185
|
+
console.error(`❌ Slice implementation failed after ${MAX_RETRIES} retries: ${slicePath}`);
|
|
186
|
+
if (errors) {
|
|
187
|
+
console.error(` Last errors:\n${errors}`);
|
|
188
|
+
}
|
|
186
189
|
sliceRetryState.delete(slicePath);
|
|
187
190
|
return;
|
|
188
191
|
}
|
|
@@ -9,15 +9,14 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@auto-engineer/cli": "workspace:*",
|
|
12
|
-
"@auto-engineer/component-implementer": "workspace:*",
|
|
13
|
-
"@auto-engineer/design-system-importer": "workspace:*",
|
|
14
12
|
"@auto-engineer/dev-server": "workspace:*",
|
|
15
13
|
"@auto-engineer/narrative": "workspace:*",
|
|
16
|
-
"@auto-engineer/
|
|
17
|
-
"@auto-engineer/frontend-generator-react-graphql": "workspace:*",
|
|
18
|
-
"@auto-engineer/frontend-implementer": "workspace:*",
|
|
14
|
+
"@auto-engineer/generate-react-client": "workspace:*",
|
|
19
15
|
"@auto-engineer/information-architect": "workspace:*",
|
|
16
|
+
"@auto-engineer/react-component-implementer": "workspace:*",
|
|
17
|
+
"@auto-engineer/app-implementer": "workspace:*",
|
|
20
18
|
"@auto-engineer/message-bus": "workspace:*",
|
|
19
|
+
"@auto-engineer/model-diff": "workspace:*",
|
|
21
20
|
"@auto-engineer/pipeline": "workspace:*",
|
|
22
21
|
"@auto-engineer/server-checks": "workspace:*",
|
|
23
22
|
"@auto-engineer/server-generator-apollo-emmett": "workspace:*",
|
|
@@ -6,7 +6,7 @@ Shared design system assets for Auto Engineer examples.
|
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/
|
|
9
|
+
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/generate-react-client` package and frontend generation plugins.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -155,7 +155,5 @@ auto import:design-system \
|
|
|
155
155
|
|
|
156
156
|
| Package | Relationship |
|
|
157
157
|
|---------|--------------|
|
|
158
|
-
| `@auto-engineer/
|
|
159
|
-
| `@auto-engineer/frontend-generator-react-graphql` | Uses figma-file.json for tokens |
|
|
160
|
-
| `@auto-engineer/component-implementer` | Uses design-system.md for constraints |
|
|
158
|
+
| `@auto-engineer/generate-react-client` | Uses design system files for client generation |
|
|
161
159
|
| `@auto-engineer/information-architect` | References component list for IA |
|
|
@@ -6,7 +6,7 @@ Shared design system assets for Auto Engineer examples.
|
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/
|
|
9
|
+
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/generate-react-client` package and frontend generation plugins.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -155,7 +155,5 @@ auto import:design-system \
|
|
|
155
155
|
|
|
156
156
|
| Package | Relationship |
|
|
157
157
|
|---------|--------------|
|
|
158
|
-
| `@auto-engineer/
|
|
159
|
-
| `@auto-engineer/frontend-generator-react-graphql` | Uses figma-file.json for tokens |
|
|
160
|
-
| `@auto-engineer/component-implementer` | Uses design-system.md for constraints |
|
|
158
|
+
| `@auto-engineer/generate-react-client` | Uses design system files for client generation |
|
|
161
159
|
| `@auto-engineer/information-architect` | References component list for IA |
|
|
@@ -6,7 +6,7 @@ Shared design system assets for Auto Engineer examples.
|
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/
|
|
9
|
+
This directory provides pre-configured design system files that other examples copy into their `.context/` directories. These files are consumed by the `@auto-engineer/generate-react-client` package and frontend generation plugins.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -155,7 +155,5 @@ auto import:design-system \
|
|
|
155
155
|
|
|
156
156
|
| Package | Relationship |
|
|
157
157
|
|---------|--------------|
|
|
158
|
-
| `@auto-engineer/
|
|
159
|
-
| `@auto-engineer/frontend-generator-react-graphql` | Uses figma-file.json for tokens |
|
|
160
|
-
| `@auto-engineer/component-implementer` | Uses design-system.md for constraints |
|
|
158
|
+
| `@auto-engineer/generate-react-client` | Uses design system files for client generation |
|
|
161
159
|
| `@auto-engineer/information-architect` | References component list for IA |
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Event } from '@auto-engineer/message-bus';
|
|
2
|
+
import type { SettledHandlerDescriptor } from '@auto-engineer/pipeline/src/core/descriptors';
|
|
3
|
+
import { describe, expect, it, beforeEach } from 'vitest';
|
|
4
|
+
import { pipeline, resetState } from './auto.config';
|
|
5
|
+
|
|
6
|
+
function getSettledHandler(): SettledHandlerDescriptor {
|
|
7
|
+
const handler = pipeline.descriptor.handlers.find((h) => h.type === 'settled');
|
|
8
|
+
return handler as SettledHandlerDescriptor;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function makeFailingCheckEvents(slicePath: string): Record<string, Event[]> {
|
|
12
|
+
return {
|
|
13
|
+
CheckTests: [{ type: 'TestsCheckFailed', data: { targetDirectory: slicePath, errors: 'test failed' } }],
|
|
14
|
+
CheckTypes: [{ type: 'TypeCheckFailed', data: { targetDirectory: slicePath, errors: 'type error' } }],
|
|
15
|
+
CheckLint: [{ type: 'LintCheckPassed', data: { targetDirectory: slicePath } }],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('settled handler retry logic', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
resetState();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should not retry after max retries even when handler is called again for same slice', () => {
|
|
25
|
+
const settled = getSettledHandler();
|
|
26
|
+
const slicePath = '/some/slice/path';
|
|
27
|
+
const events = makeFailingCheckEvents(slicePath);
|
|
28
|
+
const dispatched: Array<{ type: string; data: unknown }> = [];
|
|
29
|
+
const send = (type: string, data: unknown) => dispatched.push({ type, data });
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < 4; i++) {
|
|
32
|
+
settled.handler(events, send);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
expect(dispatched).toHaveLength(4);
|
|
36
|
+
|
|
37
|
+
dispatched.length = 0;
|
|
38
|
+
settled.handler(events, send);
|
|
39
|
+
|
|
40
|
+
expect(dispatched).toHaveLength(0);
|
|
41
|
+
|
|
42
|
+
dispatched.length = 0;
|
|
43
|
+
settled.handler(events, send);
|
|
44
|
+
|
|
45
|
+
expect(dispatched).toHaveLength(0);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { Event } from '@auto-engineer/message-bus';
|
|
1
|
+
import type { Event, Command } from '@auto-engineer/message-bus';
|
|
3
2
|
import { define } from '@auto-engineer/pipeline';
|
|
4
3
|
|
|
5
|
-
interface Component {
|
|
6
|
-
type: 'molecule' | 'organism' | 'page';
|
|
7
|
-
filePath: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
4
|
interface SchemaExportedData {
|
|
11
5
|
directory: string;
|
|
12
6
|
outputPath: string;
|
|
@@ -28,11 +22,6 @@ interface SliceImplementedData {
|
|
|
28
22
|
slicePath: string;
|
|
29
23
|
}
|
|
30
24
|
|
|
31
|
-
interface ClientGeneratedData {
|
|
32
|
-
components: Component[];
|
|
33
|
-
targetDir: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
25
|
interface CheckEventData {
|
|
37
26
|
targetDirectory?: string;
|
|
38
27
|
errors?: string;
|
|
@@ -52,6 +41,38 @@ interface IAValidationFailedData {
|
|
|
52
41
|
modelPath: string;
|
|
53
42
|
}
|
|
54
43
|
|
|
44
|
+
// --- Job Graph Types ---
|
|
45
|
+
|
|
46
|
+
interface JobFiles {
|
|
47
|
+
create: string[];
|
|
48
|
+
modify?: string[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface JobPayload {
|
|
52
|
+
title: string;
|
|
53
|
+
description: string;
|
|
54
|
+
type: 'component';
|
|
55
|
+
componentId: string;
|
|
56
|
+
implementation: string;
|
|
57
|
+
acceptanceCriteria: string[];
|
|
58
|
+
prompt: string;
|
|
59
|
+
storybookPath: string;
|
|
60
|
+
files: JobFiles;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface Job {
|
|
64
|
+
id: string;
|
|
65
|
+
dependsOn: string[];
|
|
66
|
+
target: string;
|
|
67
|
+
payload: JobPayload;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface JobGraphReadyData {
|
|
71
|
+
jobs: Job[];
|
|
72
|
+
projectDir?: string;
|
|
73
|
+
failurePolicy?: 'halt' | 'skip-dependents' | 'continue';
|
|
74
|
+
}
|
|
75
|
+
|
|
55
76
|
const MAX_RETRIES = 4;
|
|
56
77
|
const MAX_IA_RETRIES = 3;
|
|
57
78
|
const sliceRetryState = new Map<string, number>();
|
|
@@ -91,14 +112,6 @@ function incrementRetryCount(slicePath: string): number {
|
|
|
91
112
|
return attempts + 1;
|
|
92
113
|
}
|
|
93
114
|
|
|
94
|
-
function hasValidComponents(e: { data: ClientGeneratedData | null }): boolean {
|
|
95
|
-
return e.data !== null && Array.isArray(e.data.components) && e.data.components.length > 0;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function hasInvalidComponents(e: { data: ClientGeneratedData | null }): boolean {
|
|
99
|
-
return !hasValidComponents(e);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
115
|
function resolvePath(relativePath: string): string {
|
|
103
116
|
if (projectRoot === '') {
|
|
104
117
|
return relativePath;
|
|
@@ -112,21 +125,700 @@ function resolvePath(relativePath: string): string {
|
|
|
112
125
|
return `${projectRoot}/${relativePath}`;
|
|
113
126
|
}
|
|
114
127
|
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Hardcoded Book Store jobs for testing the job-graph pipeline end-to-end.
|
|
130
|
+
// Trigger with: auto dispatch TriggerJobGraph
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
const BOOK_STORE_JOBS: Job[] = [
|
|
134
|
+
{
|
|
135
|
+
id: 'job_nav_link',
|
|
136
|
+
dependsOn: [],
|
|
137
|
+
target: 'ImplementComponent',
|
|
138
|
+
payload: {
|
|
139
|
+
title: 'Implement NavLink',
|
|
140
|
+
description: 'A navigation link component with active state styling for the main site navigation',
|
|
141
|
+
type: 'component',
|
|
142
|
+
componentId: 'nav_link',
|
|
143
|
+
implementation: 'Create a link component that supports active state styling. Should accept href, children, and active props. Apply distinct styling when the link is active to indicate current page/section.',
|
|
144
|
+
acceptanceCriteria: [
|
|
145
|
+
'Renders as a clickable link with provided href',
|
|
146
|
+
'Displays children content within the link',
|
|
147
|
+
'Applies active styling when active prop is true',
|
|
148
|
+
'Supports keyboard navigation and screen readers',
|
|
149
|
+
],
|
|
150
|
+
prompt: 'Implement a navigation link component with active state support',
|
|
151
|
+
storybookPath: 'components/NavLink',
|
|
152
|
+
files: { create: ['src/components/ui/NavLink/NavLink.tsx', 'src/components/ui/NavLink/index.ts'] },
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 'job_cart_icon',
|
|
157
|
+
dependsOn: [],
|
|
158
|
+
target: 'ImplementComponent',
|
|
159
|
+
payload: {
|
|
160
|
+
title: 'Implement CartIcon',
|
|
161
|
+
description: 'A shopping cart icon component for the header navigation',
|
|
162
|
+
type: 'component',
|
|
163
|
+
componentId: 'cart_icon',
|
|
164
|
+
implementation: 'Create a shopping cart SVG icon component. Should be scalable and support custom size and color props. Use standard shopping cart iconography.',
|
|
165
|
+
acceptanceCriteria: [
|
|
166
|
+
'Renders a shopping cart SVG icon',
|
|
167
|
+
'Accepts size prop to control icon dimensions',
|
|
168
|
+
'Accepts color prop to customize icon color',
|
|
169
|
+
'Maintains aspect ratio when scaled',
|
|
170
|
+
],
|
|
171
|
+
prompt: 'Implement a scalable shopping cart icon component',
|
|
172
|
+
storybookPath: 'components/CartIcon',
|
|
173
|
+
files: { create: ['src/components/ui/CartIcon/CartIcon.tsx', 'src/components/ui/CartIcon/index.ts'] },
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: 'job_book_card',
|
|
178
|
+
dependsOn: [],
|
|
179
|
+
target: 'ImplementComponent',
|
|
180
|
+
payload: {
|
|
181
|
+
title: 'Implement BookCard',
|
|
182
|
+
description: 'A card component for displaying book information with add to cart functionality',
|
|
183
|
+
type: 'component',
|
|
184
|
+
componentId: 'book_card',
|
|
185
|
+
implementation: 'Extend the existing Card component to create a book-specific card layout. Include book title, author, price, and add to cart button. Handle cart state to disable button when book is already added.',
|
|
186
|
+
acceptanceCriteria: [
|
|
187
|
+
'Displays book title, author, and price clearly',
|
|
188
|
+
'Shows add to cart button when book is not in cart',
|
|
189
|
+
'Disables add to cart button when book is already in cart',
|
|
190
|
+
'Calls onAddToCart function when button is clicked',
|
|
191
|
+
'Supports featured variant for highlighted books',
|
|
192
|
+
],
|
|
193
|
+
prompt: 'Create a book card component using the existing Card as a base',
|
|
194
|
+
storybookPath: 'components/BookCard',
|
|
195
|
+
files: { create: ['src/components/ui/BookCard/BookCard.tsx', 'src/components/ui/BookCard/index.ts'] },
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: 'job_search_icon',
|
|
200
|
+
dependsOn: [],
|
|
201
|
+
target: 'ImplementComponent',
|
|
202
|
+
payload: {
|
|
203
|
+
title: 'Implement SearchIcon',
|
|
204
|
+
description: 'A magnifying glass search icon for the search input field',
|
|
205
|
+
type: 'component',
|
|
206
|
+
componentId: 'search_icon',
|
|
207
|
+
implementation: 'Create a search/magnifying glass SVG icon component. Should be scalable and support custom size and color props.',
|
|
208
|
+
acceptanceCriteria: [
|
|
209
|
+
'Renders a magnifying glass SVG icon',
|
|
210
|
+
'Accepts size prop to control icon dimensions',
|
|
211
|
+
'Accepts color prop to customize icon color',
|
|
212
|
+
'Uses standard search icon design',
|
|
213
|
+
],
|
|
214
|
+
prompt: 'Implement a scalable search magnifying glass icon component',
|
|
215
|
+
storybookPath: 'components/SearchIcon',
|
|
216
|
+
files: { create: ['src/components/ui/SearchIcon/SearchIcon.tsx', 'src/components/ui/SearchIcon/index.ts'] },
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
id: 'job_result_item',
|
|
221
|
+
dependsOn: [],
|
|
222
|
+
target: 'ImplementComponent',
|
|
223
|
+
payload: {
|
|
224
|
+
title: 'Implement ResultItem',
|
|
225
|
+
description: 'An individual search result item component showing book information',
|
|
226
|
+
type: 'component',
|
|
227
|
+
componentId: 'result_item',
|
|
228
|
+
implementation: 'Create a clickable search result item that displays book title, author, and price. Support highlighted state for keyboard navigation or hover effects.',
|
|
229
|
+
acceptanceCriteria: [
|
|
230
|
+
'Displays book title, author, and price in a compact layout',
|
|
231
|
+
'Responds to click events by calling onClick function',
|
|
232
|
+
'Supports highlighted variant for better UX',
|
|
233
|
+
'Is keyboard accessible for navigation',
|
|
234
|
+
],
|
|
235
|
+
prompt: 'Create a search result item component for book search results',
|
|
236
|
+
storybookPath: 'components/ResultItem',
|
|
237
|
+
files: { create: ['src/components/ui/ResultItem/ResultItem.tsx', 'src/components/ui/ResultItem/index.ts'] },
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: 'job_cart_item',
|
|
242
|
+
dependsOn: [],
|
|
243
|
+
target: 'ImplementComponent',
|
|
244
|
+
payload: {
|
|
245
|
+
title: 'Implement CartItem',
|
|
246
|
+
description: 'A cart item component displaying book details with optional remove functionality',
|
|
247
|
+
type: 'component',
|
|
248
|
+
componentId: 'cart_item',
|
|
249
|
+
implementation: 'Create a cart item component that shows book title, quantity, price, and optionally a remove button. Support readonly variant when removal is not allowed.',
|
|
250
|
+
acceptanceCriteria: [
|
|
251
|
+
'Displays book title, quantity, and price clearly',
|
|
252
|
+
'Shows remove button when allowRemoval is true',
|
|
253
|
+
'Hides remove button when allowRemoval is false (readonly variant)',
|
|
254
|
+
'Calls onRemove function when remove button is clicked',
|
|
255
|
+
],
|
|
256
|
+
prompt: 'Create a cart item component with conditional remove functionality',
|
|
257
|
+
storybookPath: 'components/CartItem',
|
|
258
|
+
files: { create: ['src/components/ui/CartItem/CartItem.tsx', 'src/components/ui/CartItem/index.ts'] },
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: 'job_price_display',
|
|
263
|
+
dependsOn: [],
|
|
264
|
+
target: 'ImplementComponent',
|
|
265
|
+
payload: {
|
|
266
|
+
title: 'Implement PriceDisplay',
|
|
267
|
+
description: 'A formatted price display component with currency support',
|
|
268
|
+
type: 'component',
|
|
269
|
+
componentId: 'price_display',
|
|
270
|
+
implementation: 'Create a price formatting component that displays monetary amounts with proper currency formatting. Support different sizes for various contexts.',
|
|
271
|
+
acceptanceCriteria: [
|
|
272
|
+
'Formats price with currency symbol correctly',
|
|
273
|
+
'Supports different size variants (small, default, large)',
|
|
274
|
+
'Handles decimal places appropriately',
|
|
275
|
+
'Uses proper currency formatting for different locales',
|
|
276
|
+
],
|
|
277
|
+
prompt: 'Create a price display component with currency formatting',
|
|
278
|
+
storybookPath: 'components/PriceDisplay',
|
|
279
|
+
files: { create: ['src/components/ui/PriceDisplay/PriceDisplay.tsx', 'src/components/ui/PriceDisplay/index.ts'] },
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: 'job_item_count',
|
|
284
|
+
dependsOn: [],
|
|
285
|
+
target: 'ImplementComponent',
|
|
286
|
+
payload: {
|
|
287
|
+
title: 'Implement ItemCount',
|
|
288
|
+
description: 'A component for displaying the number of items with descriptive label',
|
|
289
|
+
type: 'component',
|
|
290
|
+
componentId: 'item_count',
|
|
291
|
+
implementation: "Create a simple component that displays a count number with an associated label (e.g., '3 items').",
|
|
292
|
+
acceptanceCriteria: [
|
|
293
|
+
'Displays count number prominently',
|
|
294
|
+
'Shows descriptive label alongside count',
|
|
295
|
+
'Handles singular/plural forms appropriately',
|
|
296
|
+
'Uses appropriate typography for readability',
|
|
297
|
+
],
|
|
298
|
+
prompt: 'Create an item count display component with label support',
|
|
299
|
+
storybookPath: 'components/ItemCount',
|
|
300
|
+
files: { create: ['src/components/ui/ItemCount/ItemCount.tsx', 'src/components/ui/ItemCount/index.ts'] },
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: 'job_status_text',
|
|
305
|
+
dependsOn: [],
|
|
306
|
+
target: 'ImplementComponent',
|
|
307
|
+
payload: {
|
|
308
|
+
title: 'Implement StatusText',
|
|
309
|
+
description: 'A text component for displaying order status information with timestamps',
|
|
310
|
+
type: 'component',
|
|
311
|
+
componentId: 'status_text',
|
|
312
|
+
implementation: 'Create a status text component that displays order status with optional timestamp information. Format timestamps in a user-friendly way.',
|
|
313
|
+
acceptanceCriteria: [
|
|
314
|
+
'Displays status text clearly',
|
|
315
|
+
'Shows formatted timestamp when provided',
|
|
316
|
+
'Uses appropriate typography hierarchy',
|
|
317
|
+
'Handles different status types with consistent formatting',
|
|
318
|
+
],
|
|
319
|
+
prompt: 'Create a status text component for order status display',
|
|
320
|
+
storybookPath: 'components/StatusText',
|
|
321
|
+
files: { create: ['src/components/ui/StatusText/StatusText.tsx', 'src/components/ui/StatusText/index.ts'] },
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
id: 'job_history_item',
|
|
326
|
+
dependsOn: [],
|
|
327
|
+
target: 'ImplementComponent',
|
|
328
|
+
payload: {
|
|
329
|
+
title: 'Implement HistoryItem',
|
|
330
|
+
description: 'A timeline item component for displaying order history events',
|
|
331
|
+
type: 'component',
|
|
332
|
+
componentId: 'history_item',
|
|
333
|
+
implementation: 'Create a history item component for order timeline display. Show status, timestamp, and description with visual indicators for current vs past events.',
|
|
334
|
+
acceptanceCriteria: [
|
|
335
|
+
'Displays status, timestamp, and description clearly',
|
|
336
|
+
'Supports current variant to highlight active status',
|
|
337
|
+
'Uses timeline-appropriate visual design',
|
|
338
|
+
'Formats timestamps in user-friendly format',
|
|
339
|
+
],
|
|
340
|
+
prompt: 'Create a history item component for order timeline display',
|
|
341
|
+
storybookPath: 'components/HistoryItem',
|
|
342
|
+
files: { create: ['src/components/ui/HistoryItem/HistoryItem.tsx', 'src/components/ui/HistoryItem/index.ts'] },
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
id: 'job_timeline_connector',
|
|
347
|
+
dependsOn: [],
|
|
348
|
+
target: 'ImplementComponent',
|
|
349
|
+
payload: {
|
|
350
|
+
title: 'Implement TimelineConnector',
|
|
351
|
+
description: 'A visual connector component for linking timeline items',
|
|
352
|
+
type: 'component',
|
|
353
|
+
componentId: 'timeline_connector',
|
|
354
|
+
implementation: 'Create a visual connector line that links timeline items together. Support active and inactive states with different visual styles.',
|
|
355
|
+
acceptanceCriteria: [
|
|
356
|
+
'Renders as a connecting line between timeline items',
|
|
357
|
+
'Shows active state with emphasized styling',
|
|
358
|
+
'Shows inactive state with subtle styling',
|
|
359
|
+
'Integrates well with timeline layout',
|
|
360
|
+
],
|
|
361
|
+
prompt: 'Create a timeline connector for linking history items',
|
|
362
|
+
storybookPath: 'components/TimelineConnector',
|
|
363
|
+
files: { create: ['src/components/ui/TimelineConnector/TimelineConnector.tsx', 'src/components/ui/TimelineConnector/index.ts'] },
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
id: 'job_cart_indicator',
|
|
368
|
+
dependsOn: ['job_cart_icon'],
|
|
369
|
+
target: 'ImplementComponent',
|
|
370
|
+
payload: {
|
|
371
|
+
title: 'Implement CartIndicator',
|
|
372
|
+
description: 'A cart icon with item count badge for the header navigation',
|
|
373
|
+
type: 'component',
|
|
374
|
+
componentId: 'cart_indicator',
|
|
375
|
+
implementation: 'Combine the CartIcon with a Badge component to show cart item count. Position the badge as an overlay on the cart icon.',
|
|
376
|
+
acceptanceCriteria: [
|
|
377
|
+
'Displays cart icon with count badge overlay',
|
|
378
|
+
'Badge shows current item count',
|
|
379
|
+
'Handles zero count appropriately (hide or show 0)',
|
|
380
|
+
'Responds to click events',
|
|
381
|
+
'Badge positioning works across different screen sizes',
|
|
382
|
+
],
|
|
383
|
+
prompt: 'Create a cart indicator combining cart icon with count badge',
|
|
384
|
+
storybookPath: 'components/CartIndicator',
|
|
385
|
+
files: { create: ['src/components/ui/CartIndicator/CartIndicator.tsx', 'src/components/ui/CartIndicator/index.ts'] },
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
id: 'job_book_grid',
|
|
390
|
+
dependsOn: ['job_book_card'],
|
|
391
|
+
target: 'ImplementComponent',
|
|
392
|
+
payload: {
|
|
393
|
+
title: 'Implement BookGrid',
|
|
394
|
+
description: 'A responsive grid layout for displaying multiple book cards',
|
|
395
|
+
type: 'component',
|
|
396
|
+
componentId: 'book_grid',
|
|
397
|
+
implementation: 'Create a responsive grid container that displays BookCard components. Support configurable column count and handle responsive breakpoints.',
|
|
398
|
+
acceptanceCriteria: [
|
|
399
|
+
'Displays books in responsive grid layout',
|
|
400
|
+
'Supports configurable column count',
|
|
401
|
+
'Handles empty state gracefully',
|
|
402
|
+
'Passes click events to individual book cards',
|
|
403
|
+
'Maintains grid spacing consistently',
|
|
404
|
+
],
|
|
405
|
+
prompt: 'Create a responsive grid layout for book cards',
|
|
406
|
+
storybookPath: 'components/BookGrid',
|
|
407
|
+
files: { create: ['src/components/ui/BookGrid/BookGrid.tsx', 'src/components/ui/BookGrid/index.ts'] },
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
id: 'job_search_bar',
|
|
412
|
+
dependsOn: ['job_search_icon'],
|
|
413
|
+
target: 'ImplementComponent',
|
|
414
|
+
payload: {
|
|
415
|
+
title: 'Implement SearchBar',
|
|
416
|
+
description: 'A search input field with icon and real-time search capabilities',
|
|
417
|
+
type: 'component',
|
|
418
|
+
componentId: 'search_bar',
|
|
419
|
+
implementation: 'Configure InputGroup with SearchIcon and add debounced search functionality for real-time search as user types.',
|
|
420
|
+
acceptanceCriteria: [
|
|
421
|
+
'Displays search icon at the start of input field',
|
|
422
|
+
'Supports placeholder text',
|
|
423
|
+
'Debounces search input to avoid excessive API calls',
|
|
424
|
+
'Calls onSearch function with debounced value',
|
|
425
|
+
'Maintains focus and cursor position during typing',
|
|
426
|
+
],
|
|
427
|
+
prompt: 'Create a search bar with icon and debounced search functionality',
|
|
428
|
+
storybookPath: 'components/SearchBar',
|
|
429
|
+
files: { create: ['src/components/ui/SearchBar/SearchBar.tsx', 'src/components/ui/SearchBar/index.ts'] },
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
id: 'job_search_results',
|
|
434
|
+
dependsOn: ['job_result_item'],
|
|
435
|
+
target: 'ImplementComponent',
|
|
436
|
+
payload: {
|
|
437
|
+
title: 'Implement SearchResults',
|
|
438
|
+
description: 'A list container for search results with empty state handling',
|
|
439
|
+
type: 'component',
|
|
440
|
+
componentId: 'search_results',
|
|
441
|
+
implementation: 'Create a container that displays a list of ResultItem components. Handle loading state and empty results with appropriate messaging using the Empty component.',
|
|
442
|
+
acceptanceCriteria: [
|
|
443
|
+
'Displays search results as a vertical list',
|
|
444
|
+
'Shows loading state while searching',
|
|
445
|
+
'Displays empty state message when no results found',
|
|
446
|
+
'Passes result click events to parent component',
|
|
447
|
+
'Handles keyboard navigation between results',
|
|
448
|
+
],
|
|
449
|
+
prompt: 'Create a search results container with loading and empty states',
|
|
450
|
+
storybookPath: 'components/SearchResults',
|
|
451
|
+
files: { create: ['src/components/ui/SearchResults/SearchResults.tsx', 'src/components/ui/SearchResults/index.ts'] },
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
id: 'job_cart_item_list',
|
|
456
|
+
dependsOn: ['job_cart_item'],
|
|
457
|
+
target: 'ImplementComponent',
|
|
458
|
+
payload: {
|
|
459
|
+
title: 'Implement CartItemList',
|
|
460
|
+
description: 'A list container for shopping cart items with removal functionality',
|
|
461
|
+
type: 'component',
|
|
462
|
+
componentId: 'cart_item_list',
|
|
463
|
+
implementation: 'Create a container that displays a list of CartItem components. Handle item removal and empty cart state.',
|
|
464
|
+
acceptanceCriteria: [
|
|
465
|
+
'Displays cart items in vertical list layout',
|
|
466
|
+
'Passes removal function to individual cart items',
|
|
467
|
+
'Respects allowRemoval prop to enable/disable removal',
|
|
468
|
+
'Handles empty cart state appropriately',
|
|
469
|
+
'Maintains consistent spacing between items',
|
|
470
|
+
],
|
|
471
|
+
prompt: 'Create a cart item list container with removal functionality',
|
|
472
|
+
storybookPath: 'components/CartItemList',
|
|
473
|
+
files: { create: ['src/components/ui/CartItemList/CartItemList.tsx', 'src/components/ui/CartItemList/index.ts'] },
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
id: 'job_cart_summary',
|
|
478
|
+
dependsOn: ['job_price_display', 'job_item_count'],
|
|
479
|
+
target: 'ImplementComponent',
|
|
480
|
+
payload: {
|
|
481
|
+
title: 'Implement CartSummary',
|
|
482
|
+
description: 'A summary component showing cart total and item count',
|
|
483
|
+
type: 'component',
|
|
484
|
+
componentId: 'cart_summary',
|
|
485
|
+
implementation: 'Combine PriceDisplay and ItemCount components to show cart totals. Display prominently for easy scanning.',
|
|
486
|
+
acceptanceCriteria: [
|
|
487
|
+
'Displays total price using PriceDisplay component',
|
|
488
|
+
'Shows item count using ItemCount component',
|
|
489
|
+
'Updates automatically when cart changes',
|
|
490
|
+
'Uses appropriate typography hierarchy',
|
|
491
|
+
'Handles zero items and empty cart states',
|
|
492
|
+
],
|
|
493
|
+
prompt: 'Create a cart summary showing totals and item count',
|
|
494
|
+
storybookPath: 'components/CartSummary',
|
|
495
|
+
files: { create: ['src/components/ui/CartSummary/CartSummary.tsx', 'src/components/ui/CartSummary/index.ts'] },
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
id: 'job_order_status',
|
|
500
|
+
dependsOn: ['job_status_text'],
|
|
501
|
+
target: 'ImplementComponent',
|
|
502
|
+
payload: {
|
|
503
|
+
title: 'Implement OrderStatus',
|
|
504
|
+
description: 'A component displaying current order status with visual indicators',
|
|
505
|
+
type: 'component',
|
|
506
|
+
componentId: 'order_status',
|
|
507
|
+
implementation: 'Extend Badge component with order-specific status styling and combine with StatusText for comprehensive status display.',
|
|
508
|
+
acceptanceCriteria: [
|
|
509
|
+
'Displays status badge with appropriate color coding',
|
|
510
|
+
'Shows status text with timestamp information',
|
|
511
|
+
'Uses distinct styling for different order statuses',
|
|
512
|
+
'Supports status change animations',
|
|
513
|
+
'Maintains accessibility with proper labels',
|
|
514
|
+
],
|
|
515
|
+
prompt: 'Create an order status component with badge and text display',
|
|
516
|
+
storybookPath: 'components/OrderStatus',
|
|
517
|
+
files: { create: ['src/components/ui/OrderStatus/OrderStatus.tsx', 'src/components/ui/OrderStatus/index.ts'] },
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
id: 'job_order_history',
|
|
522
|
+
dependsOn: ['job_history_item', 'job_timeline_connector'],
|
|
523
|
+
target: 'ImplementComponent',
|
|
524
|
+
payload: {
|
|
525
|
+
title: 'Implement OrderHistory',
|
|
526
|
+
description: 'A timeline component showing order status change history',
|
|
527
|
+
type: 'component',
|
|
528
|
+
componentId: 'order_history',
|
|
529
|
+
implementation: 'Create a vertical timeline using HistoryItem and TimelineConnector components to show the progression of order status changes.',
|
|
530
|
+
acceptanceCriteria: [
|
|
531
|
+
'Displays history items in chronological order',
|
|
532
|
+
'Connects items with timeline connectors',
|
|
533
|
+
'Highlights current status appropriately',
|
|
534
|
+
'Shows timestamps when enabled',
|
|
535
|
+
'Handles varying numbers of history items',
|
|
536
|
+
],
|
|
537
|
+
prompt: 'Create an order history timeline with connected status items',
|
|
538
|
+
storybookPath: 'components/OrderHistory',
|
|
539
|
+
files: { create: ['src/components/ui/OrderHistory/OrderHistory.tsx', 'src/components/ui/OrderHistory/index.ts'] },
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
id: 'job_nav_menu',
|
|
544
|
+
dependsOn: ['job_nav_link'],
|
|
545
|
+
target: 'ImplementComponent',
|
|
546
|
+
payload: {
|
|
547
|
+
title: 'Implement NavMenu',
|
|
548
|
+
description: 'A navigation menu component with book store specific navigation items',
|
|
549
|
+
type: 'component',
|
|
550
|
+
componentId: 'nav_menu',
|
|
551
|
+
implementation: 'Extend NavigationMenu component with book store specific navigation items and active link styling using NavLink components.',
|
|
552
|
+
acceptanceCriteria: [
|
|
553
|
+
'Displays navigation items horizontally',
|
|
554
|
+
'Uses NavLink components for navigation items',
|
|
555
|
+
'Highlights active navigation item',
|
|
556
|
+
'Supports keyboard navigation',
|
|
557
|
+
'Includes book store specific menu items (Browse, Search, Cart)',
|
|
558
|
+
],
|
|
559
|
+
prompt: 'Create a navigation menu for book store using existing NavigationMenu',
|
|
560
|
+
storybookPath: 'components/NavMenu',
|
|
561
|
+
files: { create: ['src/components/ui/NavMenu/NavMenu.tsx', 'src/components/ui/NavMenu/index.ts'] },
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
id: 'job_sort_controls',
|
|
566
|
+
dependsOn: [],
|
|
567
|
+
target: 'ImplementComponent',
|
|
568
|
+
payload: {
|
|
569
|
+
title: 'Implement SortControls',
|
|
570
|
+
description: 'Dropdown and buttons for sorting the book catalog by various criteria',
|
|
571
|
+
type: 'component',
|
|
572
|
+
componentId: 'sort_controls',
|
|
573
|
+
implementation: 'Wrap Select component with book-specific sort options (title, price, author) and add sort direction toggle functionality.',
|
|
574
|
+
acceptanceCriteria: [
|
|
575
|
+
'Provides sort options specific to books (title, author, price)',
|
|
576
|
+
'Includes sort direction toggle (ascending/descending)',
|
|
577
|
+
'Calls onSortChange when sort criteria changes',
|
|
578
|
+
'Shows current sort selection clearly',
|
|
579
|
+
'Groups sort dropdown and direction button logically',
|
|
580
|
+
],
|
|
581
|
+
prompt: 'Create sort controls for book catalog with dropdown and direction toggle',
|
|
582
|
+
storybookPath: 'components/SortControls',
|
|
583
|
+
files: { create: ['src/components/ui/SortControls/SortControls.tsx', 'src/components/ui/SortControls/index.ts'] },
|
|
584
|
+
},
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
id: 'job_shipping_form',
|
|
588
|
+
dependsOn: [],
|
|
589
|
+
target: 'ImplementComponent',
|
|
590
|
+
payload: {
|
|
591
|
+
title: 'Implement ShippingForm',
|
|
592
|
+
description: 'Form component for collecting shipping address information during checkout',
|
|
593
|
+
type: 'component',
|
|
594
|
+
componentId: 'shipping_form',
|
|
595
|
+
implementation: 'Configure Form component with shipping address specific fields and validation. Include proper labels and error handling.',
|
|
596
|
+
acceptanceCriteria: [
|
|
597
|
+
'Displays shipping address input fields',
|
|
598
|
+
'Validates address completeness',
|
|
599
|
+
'Shows validation errors clearly',
|
|
600
|
+
'Calls onChange when address changes',
|
|
601
|
+
'Supports address autocomplete if possible',
|
|
602
|
+
],
|
|
603
|
+
prompt: 'Create a shipping form with address validation using existing Form component',
|
|
604
|
+
storybookPath: 'components/ShippingForm',
|
|
605
|
+
files: { create: ['src/components/ui/ShippingForm/ShippingForm.tsx', 'src/components/ui/ShippingForm/index.ts'] },
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
id: 'job_book_form_fields',
|
|
610
|
+
dependsOn: [],
|
|
611
|
+
target: 'ImplementComponent',
|
|
612
|
+
payload: {
|
|
613
|
+
title: 'Implement BookFormFields',
|
|
614
|
+
description: 'Form field group for adding new books with title, author, and price inputs',
|
|
615
|
+
type: 'component',
|
|
616
|
+
componentId: 'book_form_fields',
|
|
617
|
+
implementation: 'Group multiple Field components for book-specific form layout with proper validation for title, author, and price fields.',
|
|
618
|
+
acceptanceCriteria: [
|
|
619
|
+
'Displays title, author, and price input fields',
|
|
620
|
+
'Validates required fields appropriately',
|
|
621
|
+
'Formats price input with proper decimal handling',
|
|
622
|
+
'Shows validation errors per field',
|
|
623
|
+
'Calls onChange when any field value changes',
|
|
624
|
+
],
|
|
625
|
+
prompt: 'Create book form fields group with validation using existing Field components',
|
|
626
|
+
storybookPath: 'components/BookFormFields',
|
|
627
|
+
files: { create: ['src/components/ui/BookFormFields/BookFormFields.tsx', 'src/components/ui/BookFormFields/index.ts'] },
|
|
628
|
+
},
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
id: 'job_header',
|
|
632
|
+
dependsOn: ['job_nav_menu', 'job_cart_indicator'],
|
|
633
|
+
target: 'ImplementComponent',
|
|
634
|
+
payload: {
|
|
635
|
+
title: 'Implement Header',
|
|
636
|
+
description: 'Main site header with navigation menu and cart access',
|
|
637
|
+
type: 'component',
|
|
638
|
+
componentId: 'header',
|
|
639
|
+
implementation: 'Create a header component that combines NavMenu and CartIndicator. Support different header variants for different pages (with/without cart, with/without back button).',
|
|
640
|
+
acceptanceCriteria: [
|
|
641
|
+
'Displays site title prominently',
|
|
642
|
+
'Includes navigation menu for site sections',
|
|
643
|
+
'Shows cart indicator with item count',
|
|
644
|
+
'Supports optional back button for sub-pages',
|
|
645
|
+
'Maintains responsive layout across screen sizes',
|
|
646
|
+
],
|
|
647
|
+
prompt: 'Create a site header combining navigation and cart functionality',
|
|
648
|
+
storybookPath: 'components/Header',
|
|
649
|
+
files: { create: ['src/components/ui/Header/Header.tsx', 'src/components/ui/Header/index.ts'] },
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
id: 'job_book_catalog',
|
|
654
|
+
dependsOn: ['job_book_grid', 'job_sort_controls'],
|
|
655
|
+
target: 'ImplementComponent',
|
|
656
|
+
payload: {
|
|
657
|
+
title: 'Implement BookCatalog',
|
|
658
|
+
description: 'Complete book catalog with grid display and sorting capabilities',
|
|
659
|
+
type: 'component',
|
|
660
|
+
componentId: 'book_catalog',
|
|
661
|
+
implementation: 'Combine BookGrid and SortControls to create a complete catalog interface. Handle sorting state and book interactions.',
|
|
662
|
+
acceptanceCriteria: [
|
|
663
|
+
'Displays books in responsive grid layout',
|
|
664
|
+
'Provides sorting controls for different criteria',
|
|
665
|
+
'Updates display when sort options change',
|
|
666
|
+
'Handles add to cart functionality for books',
|
|
667
|
+
'Shows loading and empty states appropriately',
|
|
668
|
+
],
|
|
669
|
+
prompt: 'Create a complete book catalog with grid and sorting',
|
|
670
|
+
storybookPath: 'components/BookCatalog',
|
|
671
|
+
files: { create: ['src/components/ui/BookCatalog/BookCatalog.tsx', 'src/components/ui/BookCatalog/index.ts'] },
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
id: 'job_search_interface',
|
|
676
|
+
dependsOn: ['job_search_bar', 'job_search_results'],
|
|
677
|
+
target: 'ImplementComponent',
|
|
678
|
+
payload: {
|
|
679
|
+
title: 'Implement SearchInterface',
|
|
680
|
+
description: 'Complete search interface with input and live results display',
|
|
681
|
+
type: 'component',
|
|
682
|
+
componentId: 'search_interface',
|
|
683
|
+
implementation: 'Combine SearchBar and SearchResults to create a complete search experience. Handle search state, API calls, and result display.',
|
|
684
|
+
acceptanceCriteria: [
|
|
685
|
+
'Provides search input with real-time results',
|
|
686
|
+
'Shows search results as user types (debounced)',
|
|
687
|
+
'Displays loading state during search',
|
|
688
|
+
'Shows appropriate message when no results found',
|
|
689
|
+
'Handles search result selection',
|
|
690
|
+
],
|
|
691
|
+
prompt: 'Create a complete search interface with live results',
|
|
692
|
+
storybookPath: 'components/SearchInterface',
|
|
693
|
+
files: { create: ['src/components/ui/SearchInterface/SearchInterface.tsx', 'src/components/ui/SearchInterface/index.ts'] },
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
id: 'job_cart_display',
|
|
698
|
+
dependsOn: ['job_cart_item_list', 'job_cart_summary'],
|
|
699
|
+
target: 'ImplementComponent',
|
|
700
|
+
payload: {
|
|
701
|
+
title: 'Implement CartDisplay',
|
|
702
|
+
description: 'Complete shopping cart display with items list and summary',
|
|
703
|
+
type: 'component',
|
|
704
|
+
componentId: 'cart_display',
|
|
705
|
+
implementation: 'Combine CartItemList and CartSummary to create a complete cart viewing experience. Handle cart state management and item operations.',
|
|
706
|
+
acceptanceCriteria: [
|
|
707
|
+
'Displays all cart items with removal functionality',
|
|
708
|
+
'Shows cart summary with total and item count',
|
|
709
|
+
'Updates automatically when cart changes',
|
|
710
|
+
'Handles empty cart state appropriately',
|
|
711
|
+
'Supports both editable and readonly modes',
|
|
712
|
+
],
|
|
713
|
+
prompt: 'Create a complete cart display with items and summary',
|
|
714
|
+
storybookPath: 'components/CartDisplay',
|
|
715
|
+
files: { create: ['src/components/ui/CartDisplay/CartDisplay.tsx', 'src/components/ui/CartDisplay/index.ts'] },
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
id: 'job_checkout_form',
|
|
720
|
+
dependsOn: ['job_shipping_form'],
|
|
721
|
+
target: 'ImplementComponent',
|
|
722
|
+
payload: {
|
|
723
|
+
title: 'Implement CheckoutForm',
|
|
724
|
+
description: 'Checkout form with shipping details and payment processing',
|
|
725
|
+
type: 'component',
|
|
726
|
+
componentId: 'checkout_form',
|
|
727
|
+
implementation: 'Create a checkout form that includes ShippingForm and checkout button. Handle form validation and submission.',
|
|
728
|
+
acceptanceCriteria: [
|
|
729
|
+
'Includes shipping address form section',
|
|
730
|
+
'Provides checkout button that enables when form is valid',
|
|
731
|
+
'Validates all required information before enabling checkout',
|
|
732
|
+
'Shows loading state during checkout processing',
|
|
733
|
+
'Handles checkout errors and success states',
|
|
734
|
+
],
|
|
735
|
+
prompt: 'Create a checkout form with shipping and payment processing',
|
|
736
|
+
storybookPath: 'components/CheckoutForm',
|
|
737
|
+
files: { create: ['src/components/ui/CheckoutForm/CheckoutForm.tsx', 'src/components/ui/CheckoutForm/index.ts'] },
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
id: 'job_order_tracking',
|
|
742
|
+
dependsOn: ['job_order_status', 'job_order_history'],
|
|
743
|
+
target: 'ImplementComponent',
|
|
744
|
+
payload: {
|
|
745
|
+
title: 'Implement OrderTracking',
|
|
746
|
+
description: 'Order status display with current status and history timeline',
|
|
747
|
+
type: 'component',
|
|
748
|
+
componentId: 'order_tracking',
|
|
749
|
+
implementation: 'Combine OrderStatus and OrderHistory to create a complete order tracking interface. Show current status and historical progression.',
|
|
750
|
+
acceptanceCriteria: [
|
|
751
|
+
'Displays current order status prominently',
|
|
752
|
+
'Shows order history timeline when enabled',
|
|
753
|
+
'Includes delivery estimate for shipped orders',
|
|
754
|
+
'Handles different order statuses appropriately',
|
|
755
|
+
'Updates in real-time when order status changes',
|
|
756
|
+
],
|
|
757
|
+
prompt: 'Create an order tracking interface with status and history',
|
|
758
|
+
storybookPath: 'components/OrderTracking',
|
|
759
|
+
files: { create: ['src/components/ui/OrderTracking/OrderTracking.tsx', 'src/components/ui/OrderTracking/index.ts'] },
|
|
760
|
+
},
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
id: 'job_order_status_update',
|
|
764
|
+
dependsOn: [],
|
|
765
|
+
target: 'ImplementComponent',
|
|
766
|
+
payload: {
|
|
767
|
+
title: 'Implement OrderStatusUpdate',
|
|
768
|
+
description: 'Administrative form for updating order status with validation',
|
|
769
|
+
type: 'component',
|
|
770
|
+
componentId: 'order_status_update',
|
|
771
|
+
implementation: 'Create an administrative form using existing Select and Button components for order status updates. Include proper validation for status transitions.',
|
|
772
|
+
acceptanceCriteria: [
|
|
773
|
+
'Displays dropdown with available order statuses',
|
|
774
|
+
'Enables update button only when status is changed',
|
|
775
|
+
'Validates status transition rules',
|
|
776
|
+
'Shows confirmation after successful update',
|
|
777
|
+
'Handles update errors appropriately',
|
|
778
|
+
],
|
|
779
|
+
prompt: 'Create an order status update form for administrators',
|
|
780
|
+
storybookPath: 'components/OrderStatusUpdate',
|
|
781
|
+
files: { create: ['src/components/ui/OrderStatusUpdate/OrderStatusUpdate.tsx', 'src/components/ui/OrderStatusUpdate/index.ts'] },
|
|
782
|
+
},
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
id: 'job_book_addition_form',
|
|
786
|
+
dependsOn: ['job_book_form_fields'],
|
|
787
|
+
target: 'ImplementComponent',
|
|
788
|
+
payload: {
|
|
789
|
+
title: 'Implement BookAdditionForm',
|
|
790
|
+
description: 'Form for adding new books to the catalog with comprehensive validation',
|
|
791
|
+
type: 'component',
|
|
792
|
+
componentId: 'book_addition_form',
|
|
793
|
+
implementation: 'Create a form component using BookFormFields with submission handling. Include validation for all fields and proper error handling.',
|
|
794
|
+
acceptanceCriteria: [
|
|
795
|
+
'Displays form fields for title, author, and price',
|
|
796
|
+
'Enables submit button only when all fields are valid',
|
|
797
|
+
'Validates price as positive number',
|
|
798
|
+
'Shows field-specific validation errors',
|
|
799
|
+
'Handles form submission and loading states',
|
|
800
|
+
],
|
|
801
|
+
prompt: 'Create a book addition form with validation and submission handling',
|
|
802
|
+
storybookPath: 'components/BookAdditionForm',
|
|
803
|
+
files: { create: ['src/components/ui/BookAdditionForm/BookAdditionForm.tsx', 'src/components/ui/BookAdditionForm/index.ts'] },
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
];
|
|
807
|
+
|
|
115
808
|
export const fileId = 'kanbanNew1';
|
|
116
809
|
|
|
117
810
|
export const plugins = [
|
|
118
811
|
'@auto-engineer/model-diff',
|
|
119
812
|
'@auto-engineer/server-checks',
|
|
120
|
-
'@auto-engineer/design-system-importer',
|
|
121
813
|
'@auto-engineer/server-generator-apollo-emmett',
|
|
122
814
|
'@auto-engineer/narrative',
|
|
123
|
-
'@auto-engineer/frontend-checks',
|
|
124
|
-
'@auto-engineer/frontend-implementer',
|
|
125
|
-
'@auto-engineer/component-implementer',
|
|
126
815
|
'@auto-engineer/information-architect',
|
|
127
|
-
'@auto-engineer/
|
|
816
|
+
'@auto-engineer/generate-react-client',
|
|
817
|
+
'@auto-engineer/react-component-implementer',
|
|
128
818
|
'@auto-engineer/server-implementer',
|
|
819
|
+
'@auto-engineer/app-implementer',
|
|
129
820
|
'@auto-engineer/dev-server',
|
|
821
|
+
'@auto-engineer/job-graph-processor',
|
|
130
822
|
];
|
|
131
823
|
|
|
132
824
|
export const pipeline = define('kanban-todo')
|
|
@@ -151,7 +843,7 @@ export const pipeline = define('kanban-todo')
|
|
|
151
843
|
.on('SliceGenerated')
|
|
152
844
|
.emit('ImplementSlice', (e: { data: SliceGeneratedData }) => ({
|
|
153
845
|
slicePath: resolvePath(e.data.slicePath),
|
|
154
|
-
context: { previousOutputs: '
|
|
846
|
+
context: { previousOutputs: '', attemptNumber: 0 },
|
|
155
847
|
aiOptions: { maxTokens: 2000 },
|
|
156
848
|
}))
|
|
157
849
|
|
|
@@ -183,7 +875,11 @@ export const pipeline = define('kanban-todo')
|
|
|
183
875
|
const slicePath = extractSlicePath(events);
|
|
184
876
|
|
|
185
877
|
if (!shouldRetry(slicePath)) {
|
|
186
|
-
|
|
878
|
+
const errors = collectErrors(allEvents);
|
|
879
|
+
console.error(`Slice implementation failed after ${MAX_RETRIES} retries: ${slicePath}`);
|
|
880
|
+
if (errors) {
|
|
881
|
+
console.error(` Last errors:\n${errors}`);
|
|
882
|
+
}
|
|
187
883
|
return;
|
|
188
884
|
}
|
|
189
885
|
|
|
@@ -197,6 +893,9 @@ export const pipeline = define('kanban-todo')
|
|
|
197
893
|
})
|
|
198
894
|
|
|
199
895
|
.on('ServerGenerated')
|
|
896
|
+
.emit('GenerateReactClient', () => ({
|
|
897
|
+
targetDir: resolvePath('./client'),
|
|
898
|
+
}))
|
|
200
899
|
.emit('GenerateIA', () => {
|
|
201
900
|
iaRetryCount = 0;
|
|
202
901
|
return {
|
|
@@ -208,6 +907,18 @@ export const pipeline = define('kanban-todo')
|
|
|
208
907
|
serverDirectory: resolvePath('./server'),
|
|
209
908
|
}))
|
|
210
909
|
|
|
910
|
+
.on('ReactClientGenerated')
|
|
911
|
+
.emit('StartClient', (e: { data: { targetDir: string } }) => ({
|
|
912
|
+
clientDirectory: e.data.targetDir,
|
|
913
|
+
command: 'pnpm dev',
|
|
914
|
+
}))
|
|
915
|
+
.emit('StartStorybook', (e: { data: { targetDir: string } }) => ({
|
|
916
|
+
storybookDirectory: e.data.targetDir,
|
|
917
|
+
}))
|
|
918
|
+
|
|
919
|
+
.on('StorybookStarted')
|
|
920
|
+
.emit('TriggerJobGraph', () => ({}))
|
|
921
|
+
|
|
211
922
|
.on('IAValidationFailed')
|
|
212
923
|
.emit('GenerateIA', (e: { data: IAValidationFailedData }) => {
|
|
213
924
|
iaRetryCount += 1;
|
|
@@ -225,57 +936,46 @@ export const pipeline = define('kanban-todo')
|
|
|
225
936
|
};
|
|
226
937
|
})
|
|
227
938
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
.
|
|
237
|
-
.
|
|
238
|
-
.emit('
|
|
239
|
-
|
|
240
|
-
|
|
939
|
+
// --- Job Graph-Based Component Implementation ---
|
|
940
|
+
// Receives a DAG of component jobs with dependsOn edges.
|
|
941
|
+
// The job-graph-processor validates the DAG, performs topological scheduling,
|
|
942
|
+
// and dispatches each job's target command (ImplementReactComponent) as its
|
|
943
|
+
// dependencies are satisfied. Jobs at the same depth run in parallel.
|
|
944
|
+
//
|
|
945
|
+
// Each job is reshaped before dispatch: the graph processor sends job.payload
|
|
946
|
+
// as command data, so we wrap the original job inside the payload to match
|
|
947
|
+
// the { targetDir, job } shape that ImplementReactComponent expects.
|
|
948
|
+
.on('JobGraphReady')
|
|
949
|
+
.emit('ProcessJobGraph', (e: { data: JobGraphReadyData }) => {
|
|
950
|
+
const clientDir = resolvePath(e.data.projectDir ?? './client');
|
|
951
|
+
return {
|
|
952
|
+
graphId: `components-${Date.now()}`,
|
|
953
|
+
jobs: e.data.jobs.map((job) => ({
|
|
954
|
+
...job,
|
|
955
|
+
target: 'ImplementReactComponent',
|
|
956
|
+
payload: {
|
|
957
|
+
targetDir: clientDir,
|
|
958
|
+
job: {
|
|
959
|
+
...job,
|
|
960
|
+
target: 'ImplementReactComponent',
|
|
961
|
+
},
|
|
962
|
+
},
|
|
963
|
+
})),
|
|
964
|
+
failurePolicy: e.data.failurePolicy ?? 'skip-dependents',
|
|
965
|
+
};
|
|
966
|
+
})
|
|
241
967
|
|
|
242
|
-
|
|
243
|
-
.
|
|
244
|
-
.emit('
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
designSystemPath: resolvePath('./.context/design-system.md'),
|
|
248
|
-
componentType: 'molecule',
|
|
249
|
-
filePath: resolvePath('client/src/components/molecules/Example.tsx'),
|
|
250
|
-
componentName: 'Example.tsx',
|
|
251
|
-
aiOptions: { maxTokens: 3000 },
|
|
968
|
+
// After all component jobs complete, run project-wide checks
|
|
969
|
+
.on('graph.completed')
|
|
970
|
+
.emit('CheckTypes', () => ({
|
|
971
|
+
targetDirectory: resolvePath('./client'),
|
|
972
|
+
scope: 'project',
|
|
252
973
|
}))
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
// build dependency chain
|
|
259
|
-
// page >> org1 && org 2
|
|
260
|
-
// org2 >> mol1 && mol2
|
|
261
|
-
// process dependency tree
|
|
262
|
-
|
|
263
|
-
.forEach((e: { data: ClientGeneratedData }) => e.data.components)
|
|
264
|
-
.groupInto(['molecule', 'organism', 'page'], (c) => c.type) // group into phased chain
|
|
265
|
-
.process('ImplementComponent', (c: Component) => ({ // processPhase
|
|
266
|
-
projectDir: resolvePath('./client'),
|
|
267
|
-
iaSchemeDir: resolvePath('./.context'),
|
|
268
|
-
designSystemPath: resolvePath('./.context/design-system.md'),
|
|
269
|
-
componentType: c.type ?? 'molecule',
|
|
270
|
-
filePath: resolvePath(c.filePath ?? ''),
|
|
271
|
-
componentName: (c.filePath ?? '').split('/').pop()?.replace('.tsx', '') ?? '',
|
|
272
|
-
aiOptions: { maxTokens: 3000 },
|
|
974
|
+
.emit('CheckLint', () => ({
|
|
975
|
+
targetDirectory: resolvePath('./client'),
|
|
976
|
+
scope: 'project',
|
|
977
|
+
fix: true,
|
|
273
978
|
}))
|
|
274
|
-
.onComplete({
|
|
275
|
-
success: { name: 'AllComponentsImplemented', displayName: 'All Components Implemented' },
|
|
276
|
-
failure: { name: 'ComponentsFailed', displayName: 'Components Failed' },
|
|
277
|
-
itemKey: (e) => (e.data as { filePath?: string }).filePath ?? '',
|
|
278
|
-
})
|
|
279
979
|
|
|
280
980
|
.build();
|
|
281
981
|
|
|
@@ -288,3 +988,32 @@ export function resetState(): void {
|
|
|
288
988
|
export function setProjectRoot(root: string): void {
|
|
289
989
|
projectRoot = root;
|
|
290
990
|
}
|
|
991
|
+
|
|
992
|
+
// ---------------------------------------------------------------------------
|
|
993
|
+
// Command handler: dispatch "TriggerJobGraph" to kick off the hardcoded jobs.
|
|
994
|
+
// auto dispatch TriggerJobGraph
|
|
995
|
+
// ---------------------------------------------------------------------------
|
|
996
|
+
|
|
997
|
+
export const COMMANDS = [
|
|
998
|
+
{
|
|
999
|
+
name: 'TriggerJobGraph',
|
|
1000
|
+
alias: 'trigger:job-graph',
|
|
1001
|
+
description: 'Emit JobGraphReady with the hardcoded Book Store component jobs',
|
|
1002
|
+
events: [{ name: 'JobGraphReady' }],
|
|
1003
|
+
handle: async (_command: Command) => ({
|
|
1004
|
+
type: 'JobGraphReady' as const,
|
|
1005
|
+
data: {
|
|
1006
|
+
jobs: BOOK_STORE_JOBS,
|
|
1007
|
+
projectDir: './client',
|
|
1008
|
+
failurePolicy: 'skip-dependents' as const,
|
|
1009
|
+
},
|
|
1010
|
+
}),
|
|
1011
|
+
},
|
|
1012
|
+
];
|
|
1013
|
+
|
|
1014
|
+
export default {
|
|
1015
|
+
fileId,
|
|
1016
|
+
plugins,
|
|
1017
|
+
pipeline,
|
|
1018
|
+
COMMANDS,
|
|
1019
|
+
};
|
|
@@ -9,18 +9,18 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@auto-engineer/cli": "workspace:*",
|
|
12
|
-
"@auto-engineer/component-implementer": "workspace:*",
|
|
13
|
-
"@auto-engineer/design-system-importer": "workspace:*",
|
|
14
12
|
"@auto-engineer/dev-server": "workspace:*",
|
|
15
|
-
"@auto-engineer/
|
|
16
|
-
"@auto-engineer/frontend-checks": "workspace:*",
|
|
17
|
-
"@auto-engineer/frontend-generator-react-graphql": "workspace:*",
|
|
18
|
-
"@auto-engineer/frontend-implementer": "workspace:*",
|
|
13
|
+
"@auto-engineer/generate-react-client": "workspace:*",
|
|
19
14
|
"@auto-engineer/information-architect": "workspace:*",
|
|
15
|
+
"@auto-engineer/job-graph-processor": "workspace:*",
|
|
20
16
|
"@auto-engineer/message-bus": "workspace:*",
|
|
17
|
+
"@auto-engineer/model-diff": "workspace:*",
|
|
18
|
+
"@auto-engineer/narrative": "workspace:*",
|
|
21
19
|
"@auto-engineer/pipeline": "workspace:*",
|
|
22
20
|
"@auto-engineer/server-checks": "workspace:*",
|
|
23
21
|
"@auto-engineer/server-generator-apollo-emmett": "workspace:*",
|
|
22
|
+
"@auto-engineer/react-component-implementer": "workspace:*",
|
|
23
|
+
"@auto-engineer/app-implementer": "workspace:*",
|
|
24
24
|
"@auto-engineer/server-implementer": "workspace:*"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"chokidar": "^3.6.0",
|
|
29
29
|
"dotenv": "^16.4.5",
|
|
30
30
|
"dotenv-cli": "^9.0.0",
|
|
31
|
-
"tsx": "^3.12.7"
|
|
31
|
+
"tsx": "^3.12.7",
|
|
32
|
+
"vitest": "^3.2.4"
|
|
32
33
|
}
|
|
33
34
|
}
|