create-auto-app 1.12.0 → 1.12.1
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 +22 -77
- 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.12.
|
|
3
|
+
"version": "1.12.1",
|
|
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.12.
|
|
36
|
+
"@auto-engineer/id": "1.12.1"
|
|
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
|
+
});
|
|
@@ -2,11 +2,6 @@ import * as path from 'node:path';
|
|
|
2
2
|
import type { Event } from '@auto-engineer/message-bus';
|
|
3
3
|
import { define } from '@auto-engineer/pipeline';
|
|
4
4
|
|
|
5
|
-
interface Component {
|
|
6
|
-
type: 'molecule' | 'organism' | 'page';
|
|
7
|
-
filePath: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
5
|
interface SchemaExportedData {
|
|
11
6
|
directory: string;
|
|
12
7
|
outputPath: string;
|
|
@@ -28,11 +23,6 @@ interface SliceImplementedData {
|
|
|
28
23
|
slicePath: string;
|
|
29
24
|
}
|
|
30
25
|
|
|
31
|
-
interface ClientGeneratedData {
|
|
32
|
-
components: Component[];
|
|
33
|
-
targetDir: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
26
|
interface CheckEventData {
|
|
37
27
|
targetDirectory?: string;
|
|
38
28
|
errors?: string;
|
|
@@ -91,14 +81,6 @@ function incrementRetryCount(slicePath: string): number {
|
|
|
91
81
|
return attempts + 1;
|
|
92
82
|
}
|
|
93
83
|
|
|
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
84
|
function resolvePath(relativePath: string): string {
|
|
103
85
|
if (projectRoot === '') {
|
|
104
86
|
return relativePath;
|
|
@@ -117,16 +99,15 @@ export const fileId = 'kanbanNew1';
|
|
|
117
99
|
export const plugins = [
|
|
118
100
|
'@auto-engineer/model-diff',
|
|
119
101
|
'@auto-engineer/server-checks',
|
|
120
|
-
'@auto-engineer/design-system-importer',
|
|
121
102
|
'@auto-engineer/server-generator-apollo-emmett',
|
|
122
103
|
'@auto-engineer/narrative',
|
|
123
|
-
'@auto-engineer/frontend-checks',
|
|
124
|
-
'@auto-engineer/frontend-implementer',
|
|
125
|
-
'@auto-engineer/component-implementer',
|
|
126
104
|
'@auto-engineer/information-architect',
|
|
127
|
-
'@auto-engineer/
|
|
105
|
+
'@auto-engineer/generate-react-client',
|
|
106
|
+
'@auto-engineer/react-component-implementer',
|
|
128
107
|
'@auto-engineer/server-implementer',
|
|
108
|
+
'@auto-engineer/app-implementer',
|
|
129
109
|
'@auto-engineer/dev-server',
|
|
110
|
+
'@auto-engineer/job-graph-processor',
|
|
130
111
|
];
|
|
131
112
|
|
|
132
113
|
export const pipeline = define('kanban-todo')
|
|
@@ -151,7 +132,7 @@ export const pipeline = define('kanban-todo')
|
|
|
151
132
|
.on('SliceGenerated')
|
|
152
133
|
.emit('ImplementSlice', (e: { data: SliceGeneratedData }) => ({
|
|
153
134
|
slicePath: resolvePath(e.data.slicePath),
|
|
154
|
-
context: { previousOutputs: '
|
|
135
|
+
context: { previousOutputs: '', attemptNumber: 0 },
|
|
155
136
|
aiOptions: { maxTokens: 2000 },
|
|
156
137
|
}))
|
|
157
138
|
|
|
@@ -183,7 +164,11 @@ export const pipeline = define('kanban-todo')
|
|
|
183
164
|
const slicePath = extractSlicePath(events);
|
|
184
165
|
|
|
185
166
|
if (!shouldRetry(slicePath)) {
|
|
186
|
-
|
|
167
|
+
const errors = collectErrors(allEvents);
|
|
168
|
+
console.error(`Slice implementation failed after ${MAX_RETRIES} retries: ${slicePath}`);
|
|
169
|
+
if (errors) {
|
|
170
|
+
console.error(` Last errors:\n${errors}`);
|
|
171
|
+
}
|
|
187
172
|
return;
|
|
188
173
|
}
|
|
189
174
|
|
|
@@ -197,6 +182,9 @@ export const pipeline = define('kanban-todo')
|
|
|
197
182
|
})
|
|
198
183
|
|
|
199
184
|
.on('ServerGenerated')
|
|
185
|
+
.emit('GenerateReactClient', () => ({
|
|
186
|
+
targetDir: resolvePath('./client'),
|
|
187
|
+
}))
|
|
200
188
|
.emit('GenerateIA', () => {
|
|
201
189
|
iaRetryCount = 0;
|
|
202
190
|
return {
|
|
@@ -208,6 +196,15 @@ export const pipeline = define('kanban-todo')
|
|
|
208
196
|
serverDirectory: resolvePath('./server'),
|
|
209
197
|
}))
|
|
210
198
|
|
|
199
|
+
.on('ReactClientGenerated')
|
|
200
|
+
.emit('StartClient', (e: { data: { targetDir: string } }) => ({
|
|
201
|
+
clientDirectory: e.data.targetDir,
|
|
202
|
+
command: 'pnpm dev',
|
|
203
|
+
}))
|
|
204
|
+
.emit('StartStorybook', (e: { data: { targetDir: string } }) => ({
|
|
205
|
+
storybookDirectory: e.data.targetDir,
|
|
206
|
+
}))
|
|
207
|
+
|
|
211
208
|
.on('IAValidationFailed')
|
|
212
209
|
.emit('GenerateIA', (e: { data: IAValidationFailedData }) => {
|
|
213
210
|
iaRetryCount += 1;
|
|
@@ -225,58 +222,6 @@ export const pipeline = define('kanban-todo')
|
|
|
225
222
|
};
|
|
226
223
|
})
|
|
227
224
|
|
|
228
|
-
.on('IAGenerated')
|
|
229
|
-
.emit('GenerateClient', () => ({
|
|
230
|
-
targetDir: resolvePath('./client'),
|
|
231
|
-
iaSchemaPath: resolvePath('./.context/auto-ia-scheme.json'),
|
|
232
|
-
gqlSchemaPath: resolvePath('./.context/schema.graphql'),
|
|
233
|
-
figmaVariablesPath: resolvePath('./.context/figma-file.json'),
|
|
234
|
-
}))
|
|
235
|
-
|
|
236
|
-
.on('ClientGenerated')
|
|
237
|
-
.when(hasValidComponents)
|
|
238
|
-
.emit('StartClient', () => ({
|
|
239
|
-
clientDirectory: resolvePath('./client'),
|
|
240
|
-
}))
|
|
241
|
-
|
|
242
|
-
.on('ClientGenerated')
|
|
243
|
-
.when(hasInvalidComponents)
|
|
244
|
-
.emit('ImplementComponent', () => ({
|
|
245
|
-
projectDir: resolvePath('./client'),
|
|
246
|
-
iaSchemeDir: resolvePath('./.context'),
|
|
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 },
|
|
252
|
-
}))
|
|
253
|
-
|
|
254
|
-
.on('ClientGenerated')
|
|
255
|
-
.when(hasValidComponents)
|
|
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 },
|
|
273
|
-
}))
|
|
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
|
-
|
|
280
225
|
.build();
|
|
281
226
|
|
|
282
227
|
export function resetState(): void {
|
|
@@ -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
|
}
|