@codebakers/mcp 5.4.3 → 5.4.4
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/INSTALL.md +221 -221
- package/LICENSE +21 -21
- package/README.md +412 -412
- package/dist/cli.js +29 -29
- package/dist/cli.js.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/analyze-mockups.js +37 -37
- package/dist/tools/autonomous-build.d.ts +18 -18
- package/dist/tools/autonomous-build.js +286 -286
- package/dist/tools/check-gate.js +6 -6
- package/dist/tools/check-scope.js +10 -10
- package/dist/tools/enforce-feature.js +15 -15
- package/dist/tools/fix-commit.js +18 -18
- package/dist/tools/fix-mockups.js +191 -191
- package/dist/tools/generate-api-route.js +155 -155
- package/dist/tools/generate-chatbot.js +306 -306
- package/dist/tools/generate-component.js +117 -117
- package/dist/tools/generate-docs.js +525 -525
- package/dist/tools/generate-e2e-tests.js +19 -19
- package/dist/tools/generate-migration.js +22 -22
- package/dist/tools/generate-schema.js +37 -37
- package/dist/tools/generate-spec.js +38 -38
- package/dist/tools/generate-store-contracts.js +42 -42
- package/dist/tools/generate-store.js +109 -109
- package/dist/tools/generate-unit-tests.js +57 -57
- package/dist/tools/map-dependencies.js +45 -45
- package/dist/tools/run-interview.js +142 -142
- package/dist/tools/setup-github.js +8 -8
- package/dist/tools/setup-supabase.js +8 -8
- package/dist/tools/setup-vercel.js +8 -8
- package/dist/tools/start.d.ts +12 -0
- package/dist/tools/start.d.ts.map +1 -0
- package/dist/tools/start.js +252 -0
- package/dist/tools/start.js.map +1 -0
- package/dist/tools/validate-mockups.js +19 -19
- package/package.json +50 -50
|
@@ -9,29 +9,29 @@ export async function generateE2ETests(args) {
|
|
|
9
9
|
const cwd = process.cwd();
|
|
10
10
|
const { flow_name, steps } = args;
|
|
11
11
|
const fileName = flow_name.toLowerCase().replace(/\s+/g, '-');
|
|
12
|
-
const code = `import { test, expect } from '@playwright/test';
|
|
13
|
-
|
|
14
|
-
test.describe('${flow_name}', () => {
|
|
15
|
-
test.beforeEach(async ({ page }) => {
|
|
16
|
-
await page.goto('/');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('${flow_name} flow', async ({ page }) => {
|
|
20
|
-
${steps.map((step, i) => `// Step ${i + 1}: ${step}`).join('\n ')}
|
|
21
|
-
|
|
22
|
-
await expect(page).toHaveURL('/');
|
|
23
|
-
});
|
|
24
|
-
});
|
|
12
|
+
const code = `import { test, expect } from '@playwright/test';
|
|
13
|
+
|
|
14
|
+
test.describe('${flow_name}', () => {
|
|
15
|
+
test.beforeEach(async ({ page }) => {
|
|
16
|
+
await page.goto('/');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('${flow_name} flow', async ({ page }) => {
|
|
20
|
+
${steps.map((step, i) => `// Step ${i + 1}: ${step}`).join('\n ')}
|
|
21
|
+
|
|
22
|
+
await expect(page).toHaveURL('/');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
25
|
`;
|
|
26
26
|
const filePath = path.join(cwd, `e2e/${fileName}.spec.ts`);
|
|
27
27
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
28
28
|
await fs.writeFile(filePath, code, 'utf-8');
|
|
29
|
-
return `🍞 CodeBakers: E2E Tests Generated
|
|
30
|
-
|
|
31
|
-
**File:** e2e/${fileName}.spec.ts
|
|
32
|
-
**Flow:** ${flow_name}
|
|
33
|
-
**Steps:** ${steps.length}
|
|
34
|
-
|
|
29
|
+
return `🍞 CodeBakers: E2E Tests Generated
|
|
30
|
+
|
|
31
|
+
**File:** e2e/${fileName}.spec.ts
|
|
32
|
+
**Flow:** ${flow_name}
|
|
33
|
+
**Steps:** ${steps.length}
|
|
34
|
+
|
|
35
35
|
✅ Playwright test created`;
|
|
36
36
|
}
|
|
37
37
|
//# sourceMappingURL=generate-e2e-tests.js.map
|
|
@@ -47,28 +47,28 @@ export async function generateMigration(args) {
|
|
|
47
47
|
await fs.mkdir(migrationDir, { recursive: true });
|
|
48
48
|
const migrationPath = path.join(migrationDir, filename);
|
|
49
49
|
await fs.writeFile(migrationPath, sql, 'utf-8');
|
|
50
|
-
return `🍞 CodeBakers: Migration Generated
|
|
51
|
-
|
|
52
|
-
**File:** supabase/migrations/${filename}
|
|
53
|
-
**Table:** ${tableName}
|
|
54
|
-
**Fields:** ${fields.length}
|
|
55
|
-
**RLS:** ${add_rls ? 'Enabled' : 'Disabled'}
|
|
56
|
-
|
|
57
|
-
Migration includes:
|
|
58
|
-
✅ Table creation with UUID primary key
|
|
59
|
-
✅ user_id foreign key (security)
|
|
60
|
-
✅ Timestamps (created_at, updated_at)
|
|
61
|
-
✅ Indexes (user_id, created_at)
|
|
62
|
-
${add_rls ? '✅ RLS policies (user isolation)' : ''}
|
|
63
|
-
|
|
64
|
-
**Apply migration:**
|
|
65
|
-
\`\`\`bash
|
|
66
|
-
supabase db push
|
|
67
|
-
\`\`\`
|
|
68
|
-
|
|
69
|
-
Or manually:
|
|
70
|
-
\`\`\`bash
|
|
71
|
-
psql -f supabase/migrations/${filename}
|
|
50
|
+
return `🍞 CodeBakers: Migration Generated
|
|
51
|
+
|
|
52
|
+
**File:** supabase/migrations/${filename}
|
|
53
|
+
**Table:** ${tableName}
|
|
54
|
+
**Fields:** ${fields.length}
|
|
55
|
+
**RLS:** ${add_rls ? 'Enabled' : 'Disabled'}
|
|
56
|
+
|
|
57
|
+
Migration includes:
|
|
58
|
+
✅ Table creation with UUID primary key
|
|
59
|
+
✅ user_id foreign key (security)
|
|
60
|
+
✅ Timestamps (created_at, updated_at)
|
|
61
|
+
✅ Indexes (user_id, created_at)
|
|
62
|
+
${add_rls ? '✅ RLS policies (user isolation)' : ''}
|
|
63
|
+
|
|
64
|
+
**Apply migration:**
|
|
65
|
+
\`\`\`bash
|
|
66
|
+
supabase db push
|
|
67
|
+
\`\`\`
|
|
68
|
+
|
|
69
|
+
Or manually:
|
|
70
|
+
\`\`\`bash
|
|
71
|
+
psql -f supabase/migrations/${filename}
|
|
72
72
|
\`\`\``;
|
|
73
73
|
}
|
|
74
74
|
catch (error) {
|
|
@@ -24,14 +24,14 @@ export async function generateSchema(args) {
|
|
|
24
24
|
// 1. CHECK IF ANALYSIS FILE EXISTS
|
|
25
25
|
const exists = await fs.access(analysisPath).then(() => true).catch(() => false);
|
|
26
26
|
if (!exists) {
|
|
27
|
-
return `🍞 CodeBakers: Phase 2B - Schema Generation
|
|
28
|
-
|
|
29
|
-
❌ BLOCKER: Mock analysis file not found
|
|
30
|
-
|
|
31
|
-
Expected location: ${analysisPath}
|
|
32
|
-
|
|
33
|
-
Phase 2B cannot proceed without Phase 2A analysis.
|
|
34
|
-
|
|
27
|
+
return `🍞 CodeBakers: Phase 2B - Schema Generation
|
|
28
|
+
|
|
29
|
+
❌ BLOCKER: Mock analysis file not found
|
|
30
|
+
|
|
31
|
+
Expected location: ${analysisPath}
|
|
32
|
+
|
|
33
|
+
Phase 2B cannot proceed without Phase 2A analysis.
|
|
34
|
+
|
|
35
35
|
Next step: Run Phase 2A first (use tool: codebakers_analyze_mockups_deep)`;
|
|
36
36
|
}
|
|
37
37
|
// 2. READ MOCK-ANALYSIS.md
|
|
@@ -39,12 +39,12 @@ Next step: Run Phase 2A first (use tool: codebakers_analyze_mockups_deep)`;
|
|
|
39
39
|
// 3. PARSE ANALYSIS FILE TO EXTRACT SCHEMA REQUIREMENTS
|
|
40
40
|
const { tables, enums } = parseAnalysisForSchema(analysisContent);
|
|
41
41
|
if (tables.length === 0) {
|
|
42
|
-
return `🍞 CodeBakers: Phase 2B - Schema Generation
|
|
43
|
-
|
|
44
|
-
⚠️ WARNING: No entities found in analysis file
|
|
45
|
-
|
|
46
|
-
The mock analysis appears incomplete or empty.
|
|
47
|
-
|
|
42
|
+
return `🍞 CodeBakers: Phase 2B - Schema Generation
|
|
43
|
+
|
|
44
|
+
⚠️ WARNING: No entities found in analysis file
|
|
45
|
+
|
|
46
|
+
The mock analysis appears incomplete or empty.
|
|
47
|
+
|
|
48
48
|
Please verify Phase 2A analysis contains data fields and entities.`;
|
|
49
49
|
}
|
|
50
50
|
console.error(`Extracted ${tables.length} tables and ${enums.length} enum types`);
|
|
@@ -56,33 +56,33 @@ Please verify Phase 2A analysis contains data fields and entities.`;
|
|
|
56
56
|
console.error(`✓ Schema generated: ${schemaPath}`);
|
|
57
57
|
// 6. GENERATE SUMMARY
|
|
58
58
|
const summary = generateSchemaSummary(tables, enums);
|
|
59
|
-
return `🍞 CodeBakers: Phase 2B - Schema Generation Complete
|
|
60
|
-
|
|
61
|
-
${summary}
|
|
62
|
-
|
|
63
|
-
📄 Schema written to: .codebakers/SCHEMA.sql
|
|
64
|
-
|
|
65
|
-
Next steps:
|
|
66
|
-
1. Review SCHEMA.sql to verify all tables and relationships
|
|
67
|
-
2. Proceed to Phase 2C: Dependency Mapping (use tool: codebakers_map_dependencies)
|
|
68
|
-
3. Run verification gate before Phase 3
|
|
69
|
-
|
|
70
|
-
Verification gate requirement:
|
|
71
|
-
→ Every data field in mockups has corresponding database column
|
|
72
|
-
→ All entity relationships captured in foreign keys
|
|
59
|
+
return `🍞 CodeBakers: Phase 2B - Schema Generation Complete
|
|
60
|
+
|
|
61
|
+
${summary}
|
|
62
|
+
|
|
63
|
+
📄 Schema written to: .codebakers/SCHEMA.sql
|
|
64
|
+
|
|
65
|
+
Next steps:
|
|
66
|
+
1. Review SCHEMA.sql to verify all tables and relationships
|
|
67
|
+
2. Proceed to Phase 2C: Dependency Mapping (use tool: codebakers_map_dependencies)
|
|
68
|
+
3. Run verification gate before Phase 3
|
|
69
|
+
|
|
70
|
+
Verification gate requirement:
|
|
71
|
+
→ Every data field in mockups has corresponding database column
|
|
72
|
+
→ All entity relationships captured in foreign keys
|
|
73
73
|
→ No unresolved dependencies`;
|
|
74
74
|
}
|
|
75
75
|
catch (error) {
|
|
76
76
|
console.error('Error during schema generation:', error);
|
|
77
|
-
return `🍞 CodeBakers: Phase 2B - Schema Generation Failed
|
|
78
|
-
|
|
79
|
-
Error: ${error instanceof Error ? error.message : String(error)}
|
|
80
|
-
|
|
81
|
-
Please check:
|
|
82
|
-
- Mock analysis file exists and is readable
|
|
83
|
-
- Analysis file contains entity and field data
|
|
84
|
-
- File permissions allow writing
|
|
85
|
-
|
|
77
|
+
return `🍞 CodeBakers: Phase 2B - Schema Generation Failed
|
|
78
|
+
|
|
79
|
+
Error: ${error instanceof Error ? error.message : String(error)}
|
|
80
|
+
|
|
81
|
+
Please check:
|
|
82
|
+
- Mock analysis file exists and is readable
|
|
83
|
+
- Analysis file contains entity and field data
|
|
84
|
+
- File permissions allow writing
|
|
85
|
+
|
|
86
86
|
If issue persists, log to ERROR-LOG.md and request human assistance.`;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -16,16 +16,16 @@ import * as path from 'path';
|
|
|
16
16
|
export async function generateSpec(args) {
|
|
17
17
|
const { description, project_name } = args;
|
|
18
18
|
if (!description) {
|
|
19
|
-
return `🍞 CodeBakers: Phase 0 - Spec Generation
|
|
20
|
-
|
|
21
|
-
Please provide a description of what you want to build.
|
|
22
|
-
|
|
23
|
-
Example:
|
|
24
|
-
{
|
|
25
|
-
"description": "Email client for Microsoft 365 with inbox, compose, and search",
|
|
26
|
-
"project_name": "EmailFlow"
|
|
27
|
-
}
|
|
28
|
-
|
|
19
|
+
return `🍞 CodeBakers: Phase 0 - Spec Generation
|
|
20
|
+
|
|
21
|
+
Please provide a description of what you want to build.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
{
|
|
25
|
+
"description": "Email client for Microsoft 365 with inbox, compose, and search",
|
|
26
|
+
"project_name": "EmailFlow"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
29
|
Then I'll generate a complete PROJECT-SPEC.md with Gates 0-5.`;
|
|
30
30
|
}
|
|
31
31
|
const cwd = process.cwd();
|
|
@@ -58,38 +58,38 @@ Then I'll generate a complete PROJECT-SPEC.md with Gates 0-5.`;
|
|
|
58
58
|
await fs.writeFile(buildStatePath, buildStateContent, 'utf-8');
|
|
59
59
|
console.error(`✓ Build state initialized: ${buildStatePath}`);
|
|
60
60
|
const summary = generateSpecSummary(gate0, gate1, gate2, gate3, gate4, gate5);
|
|
61
|
-
return `🍞 CodeBakers: Phase 0 - Spec Generation Complete
|
|
62
|
-
|
|
63
|
-
${summary}
|
|
64
|
-
|
|
65
|
-
📄 Spec written to: .codebakers/PROJECT-SPEC.md
|
|
66
|
-
📄 Build state initialized: .codebakers/BUILD-STATE.md
|
|
67
|
-
|
|
68
|
-
Specification includes:
|
|
69
|
-
✓ Gate 0: Identity (product name, mission, target user, value prop)
|
|
70
|
-
✓ Gate 1: ${gate1.length} entities identified
|
|
71
|
-
✓ Gate 2: ${gate2.length} state changes mapped
|
|
72
|
-
✓ Gate 3: ${gate3.length} roles with permissions
|
|
73
|
-
✓ Gate 4: ${gate4.length} external dependencies
|
|
74
|
-
✓ Gate 5: ${gate5.length} integrations
|
|
75
|
-
|
|
76
|
-
Next steps:
|
|
77
|
-
1. Review PROJECT-SPEC.md to verify all requirements
|
|
78
|
-
2. Add/modify entities, permissions, or integrations as needed
|
|
79
|
-
3. When ready, proceed to Phase 1: UI Mockup & Design
|
|
61
|
+
return `🍞 CodeBakers: Phase 0 - Spec Generation Complete
|
|
62
|
+
|
|
63
|
+
${summary}
|
|
64
|
+
|
|
65
|
+
📄 Spec written to: .codebakers/PROJECT-SPEC.md
|
|
66
|
+
📄 Build state initialized: .codebakers/BUILD-STATE.md
|
|
67
|
+
|
|
68
|
+
Specification includes:
|
|
69
|
+
✓ Gate 0: Identity (product name, mission, target user, value prop)
|
|
70
|
+
✓ Gate 1: ${gate1.length} entities identified
|
|
71
|
+
✓ Gate 2: ${gate2.length} state changes mapped
|
|
72
|
+
✓ Gate 3: ${gate3.length} roles with permissions
|
|
73
|
+
✓ Gate 4: ${gate4.length} external dependencies
|
|
74
|
+
✓ Gate 5: ${gate5.length} integrations
|
|
75
|
+
|
|
76
|
+
Next steps:
|
|
77
|
+
1. Review PROJECT-SPEC.md to verify all requirements
|
|
78
|
+
2. Add/modify entities, permissions, or integrations as needed
|
|
79
|
+
3. When ready, proceed to Phase 1: UI Mockup & Design
|
|
80
80
|
4. Use: codebakers_init_session to resume project`;
|
|
81
81
|
}
|
|
82
82
|
catch (error) {
|
|
83
83
|
console.error('Error during spec generation:', error);
|
|
84
|
-
return `🍞 CodeBakers: Phase 0 - Spec Generation Failed
|
|
85
|
-
|
|
86
|
-
Error: ${error instanceof Error ? error.message : String(error)}
|
|
87
|
-
|
|
88
|
-
Please check:
|
|
89
|
-
- Description is clear and specific
|
|
90
|
-
- Project directory exists and is writable
|
|
91
|
-
- File permissions allow writing
|
|
92
|
-
|
|
84
|
+
return `🍞 CodeBakers: Phase 0 - Spec Generation Failed
|
|
85
|
+
|
|
86
|
+
Error: ${error instanceof Error ? error.message : String(error)}
|
|
87
|
+
|
|
88
|
+
Please check:
|
|
89
|
+
- Description is clear and specific
|
|
90
|
+
- Project directory exists and is writable
|
|
91
|
+
- File permissions allow writing
|
|
92
|
+
|
|
93
93
|
If issue persists, log to ERROR-LOG.md and request human assistance.`;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -24,25 +24,25 @@ export async function generateStoreContracts(args) {
|
|
|
24
24
|
const schemaExists = await fs.access(schemaPath).then(() => true).catch(() => false);
|
|
25
25
|
const depMapExists = await fs.access(depMapPath).then(() => true).catch(() => false);
|
|
26
26
|
if (!schemaExists) {
|
|
27
|
-
return `🍞 CodeBakers: Phase 2D - Store Contract Generation
|
|
28
|
-
|
|
29
|
-
❌ BLOCKER: Schema file not found
|
|
30
|
-
|
|
31
|
-
Expected location: ${schemaPath}
|
|
32
|
-
|
|
33
|
-
Phase 2D requires Phase 2B schema to generate store contracts.
|
|
34
|
-
|
|
27
|
+
return `🍞 CodeBakers: Phase 2D - Store Contract Generation
|
|
28
|
+
|
|
29
|
+
❌ BLOCKER: Schema file not found
|
|
30
|
+
|
|
31
|
+
Expected location: ${schemaPath}
|
|
32
|
+
|
|
33
|
+
Phase 2D requires Phase 2B schema to generate store contracts.
|
|
34
|
+
|
|
35
35
|
Next step: Run Phase 2B first (use tool: codebakers_generate_schema)`;
|
|
36
36
|
}
|
|
37
37
|
if (!depMapExists) {
|
|
38
|
-
return `🍞 CodeBakers: Phase 2D - Store Contract Generation
|
|
39
|
-
|
|
40
|
-
❌ BLOCKER: Dependency map not found
|
|
41
|
-
|
|
42
|
-
Expected location: ${depMapPath}
|
|
43
|
-
|
|
44
|
-
Phase 2D requires Phase 2C dependency map to generate store contracts.
|
|
45
|
-
|
|
38
|
+
return `🍞 CodeBakers: Phase 2D - Store Contract Generation
|
|
39
|
+
|
|
40
|
+
❌ BLOCKER: Dependency map not found
|
|
41
|
+
|
|
42
|
+
Expected location: ${depMapPath}
|
|
43
|
+
|
|
44
|
+
Phase 2D requires Phase 2C dependency map to generate store contracts.
|
|
45
|
+
|
|
46
46
|
Next step: Run Phase 2C first (use tool: codebakers_map_dependencies)`;
|
|
47
47
|
}
|
|
48
48
|
// 2. READ SCHEMA AND DEPENDENCY MAP
|
|
@@ -64,36 +64,36 @@ Next step: Run Phase 2C first (use tool: codebakers_map_dependencies)`;
|
|
|
64
64
|
console.error(`✓ TypeScript interfaces written: ${interfacesPath}`);
|
|
65
65
|
// 6. GENERATE SUMMARY
|
|
66
66
|
const summary = generateContractsSummary(contracts);
|
|
67
|
-
return `🍞 CodeBakers: Phase 2D - Store Contract Generation Complete
|
|
68
|
-
|
|
69
|
-
${summary}
|
|
70
|
-
|
|
71
|
-
📄 Documentation: .codebakers/STORE-CONTRACTS.md
|
|
72
|
-
📄 TypeScript interfaces: .codebakers/store-contracts.ts
|
|
73
|
-
|
|
74
|
-
These contracts define:
|
|
75
|
-
✓ State shape for each store
|
|
76
|
-
✓ Required methods (create, update, delete, query)
|
|
77
|
-
✓ Method signatures with types
|
|
78
|
-
✓ Dependencies (which stores this store depends on)
|
|
79
|
-
|
|
80
|
-
Next steps:
|
|
81
|
-
1. Review store contracts to verify completeness
|
|
82
|
-
2. Phase 2 is now COMPLETE
|
|
83
|
-
3. Ready for Phase 3: Foundation Build
|
|
67
|
+
return `🍞 CodeBakers: Phase 2D - Store Contract Generation Complete
|
|
68
|
+
|
|
69
|
+
${summary}
|
|
70
|
+
|
|
71
|
+
📄 Documentation: .codebakers/STORE-CONTRACTS.md
|
|
72
|
+
📄 TypeScript interfaces: .codebakers/store-contracts.ts
|
|
73
|
+
|
|
74
|
+
These contracts define:
|
|
75
|
+
✓ State shape for each store
|
|
76
|
+
✓ Required methods (create, update, delete, query)
|
|
77
|
+
✓ Method signatures with types
|
|
78
|
+
✓ Dependencies (which stores this store depends on)
|
|
79
|
+
|
|
80
|
+
Next steps:
|
|
81
|
+
1. Review store contracts to verify completeness
|
|
82
|
+
2. Phase 2 is now COMPLETE
|
|
83
|
+
3. Ready for Phase 3: Foundation Build
|
|
84
84
|
4. When implementing stores, use store-contracts.ts as the interface`;
|
|
85
85
|
}
|
|
86
86
|
catch (error) {
|
|
87
87
|
console.error('Error during store contract generation:', error);
|
|
88
|
-
return `🍞 CodeBakers: Phase 2D - Store Contract Generation Failed
|
|
89
|
-
|
|
90
|
-
Error: ${error instanceof Error ? error.message : String(error)}
|
|
91
|
-
|
|
92
|
-
Please check:
|
|
93
|
-
- Schema file and dependency map exist and are readable
|
|
94
|
-
- Files contain valid content
|
|
95
|
-
- File permissions allow writing
|
|
96
|
-
|
|
88
|
+
return `🍞 CodeBakers: Phase 2D - Store Contract Generation Failed
|
|
89
|
+
|
|
90
|
+
Error: ${error instanceof Error ? error.message : String(error)}
|
|
91
|
+
|
|
92
|
+
Please check:
|
|
93
|
+
- Schema file and dependency map exist and are readable
|
|
94
|
+
- Files contain valid content
|
|
95
|
+
- File permissions allow writing
|
|
96
|
+
|
|
97
97
|
If issue persists, log to ERROR-LOG.md and request human assistance.`;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
@@ -12,84 +12,84 @@ export async function generateStore(args) {
|
|
|
12
12
|
const cwd = process.cwd();
|
|
13
13
|
const { entity, operations, dependencies = [] } = args;
|
|
14
14
|
const storeName = `${entity.toLowerCase()}-store`;
|
|
15
|
-
const code = `import { create } from 'zustand';
|
|
16
|
-
|
|
17
|
-
export interface ${entity} {
|
|
18
|
-
id: string;
|
|
19
|
-
user_id: string;
|
|
20
|
-
created_at: string;
|
|
21
|
-
updated_at: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface ${entity}Store {
|
|
25
|
-
${entity.toLowerCase()}s: ${entity}[];
|
|
26
|
-
loading: boolean;
|
|
27
|
-
error: string | null;
|
|
28
|
-
|
|
29
|
-
${operations.includes('list') ? `fetch${entity}s: () => Promise<void>;` : ''}
|
|
30
|
-
${operations.includes('create') ? `create${entity}: (data: Partial<${entity}>) => Promise<void>;` : ''}
|
|
31
|
-
${operations.includes('update') ? `update${entity}: (id: string, data: Partial<${entity}>) => Promise<void>;` : ''}
|
|
32
|
-
${operations.includes('delete') ? `delete${entity}: (id: string) => Promise<void>;` : ''}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const use${entity}Store = create<${entity}Store>((set, get) => ({
|
|
36
|
-
${entity.toLowerCase()}s: [],
|
|
37
|
-
loading: false,
|
|
38
|
-
error: null,
|
|
39
|
-
|
|
40
|
-
${operations.includes('list') ? generateFetchMethod(entity) : ''}
|
|
41
|
-
${operations.includes('create') ? generateCreateMethod(entity, dependencies) : ''}
|
|
42
|
-
${operations.includes('update') ? generateUpdateMethod(entity, dependencies) : ''}
|
|
43
|
-
${operations.includes('delete') ? generateDeleteMethod(entity, dependencies) : ''}
|
|
44
|
-
}));
|
|
15
|
+
const code = `import { create } from 'zustand';
|
|
16
|
+
|
|
17
|
+
export interface ${entity} {
|
|
18
|
+
id: string;
|
|
19
|
+
user_id: string;
|
|
20
|
+
created_at: string;
|
|
21
|
+
updated_at: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ${entity}Store {
|
|
25
|
+
${entity.toLowerCase()}s: ${entity}[];
|
|
26
|
+
loading: boolean;
|
|
27
|
+
error: string | null;
|
|
28
|
+
|
|
29
|
+
${operations.includes('list') ? `fetch${entity}s: () => Promise<void>;` : ''}
|
|
30
|
+
${operations.includes('create') ? `create${entity}: (data: Partial<${entity}>) => Promise<void>;` : ''}
|
|
31
|
+
${operations.includes('update') ? `update${entity}: (id: string, data: Partial<${entity}>) => Promise<void>;` : ''}
|
|
32
|
+
${operations.includes('delete') ? `delete${entity}: (id: string) => Promise<void>;` : ''}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const use${entity}Store = create<${entity}Store>((set, get) => ({
|
|
36
|
+
${entity.toLowerCase()}s: [],
|
|
37
|
+
loading: false,
|
|
38
|
+
error: null,
|
|
39
|
+
|
|
40
|
+
${operations.includes('list') ? generateFetchMethod(entity) : ''}
|
|
41
|
+
${operations.includes('create') ? generateCreateMethod(entity, dependencies) : ''}
|
|
42
|
+
${operations.includes('update') ? generateUpdateMethod(entity, dependencies) : ''}
|
|
43
|
+
${operations.includes('delete') ? generateDeleteMethod(entity, dependencies) : ''}
|
|
44
|
+
}));
|
|
45
45
|
`;
|
|
46
46
|
const filePath = path.join(cwd, `src/stores/${storeName}.ts`);
|
|
47
47
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
48
48
|
await fs.writeFile(filePath, code, 'utf-8');
|
|
49
|
-
return `🍞 CodeBakers: Store Generated
|
|
50
|
-
|
|
51
|
-
**File:** src/stores/${storeName}.ts
|
|
52
|
-
**Entity:** ${entity}
|
|
53
|
-
**Operations:** ${operations.join(', ')}
|
|
54
|
-
${dependencies.length > 0 ? `**Dependencies:** ${dependencies.join(', ')}` : ''}
|
|
55
|
-
|
|
56
|
-
Includes:
|
|
57
|
-
✅ TypeScript interfaces
|
|
58
|
-
✅ Zustand store
|
|
59
|
-
✅ Loading/error states
|
|
60
|
-
✅ CRUD operations
|
|
49
|
+
return `🍞 CodeBakers: Store Generated
|
|
50
|
+
|
|
51
|
+
**File:** src/stores/${storeName}.ts
|
|
52
|
+
**Entity:** ${entity}
|
|
53
|
+
**Operations:** ${operations.join(', ')}
|
|
54
|
+
${dependencies.length > 0 ? `**Dependencies:** ${dependencies.join(', ')}` : ''}
|
|
55
|
+
|
|
56
|
+
Includes:
|
|
57
|
+
✅ TypeScript interfaces
|
|
58
|
+
✅ Zustand store
|
|
59
|
+
✅ Loading/error states
|
|
60
|
+
✅ CRUD operations
|
|
61
61
|
${dependencies.length > 0 ? '✅ Dependency updates (from DEPENDENCY-MAP.md)' : ''}`;
|
|
62
62
|
}
|
|
63
63
|
function generateFetchMethod(entity) {
|
|
64
|
-
return `fetch${entity}s: async () => {
|
|
65
|
-
set({ loading: true, error: null });
|
|
66
|
-
try {
|
|
67
|
-
const res = await fetch('/api/${entity.toLowerCase()}s');
|
|
68
|
-
if (!res.ok) throw new Error('Fetch failed');
|
|
69
|
-
const { data } = await res.json();
|
|
70
|
-
set({ ${entity.toLowerCase()}s: data, loading: false });
|
|
71
|
-
} catch (error) {
|
|
72
|
-
set({ error: (error as Error).message, loading: false });
|
|
73
|
-
}
|
|
74
|
-
},
|
|
64
|
+
return `fetch${entity}s: async () => {
|
|
65
|
+
set({ loading: true, error: null });
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetch('/api/${entity.toLowerCase()}s');
|
|
68
|
+
if (!res.ok) throw new Error('Fetch failed');
|
|
69
|
+
const { data } = await res.json();
|
|
70
|
+
set({ ${entity.toLowerCase()}s: data, loading: false });
|
|
71
|
+
} catch (error) {
|
|
72
|
+
set({ error: (error as Error).message, loading: false });
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
75
|
`;
|
|
76
76
|
}
|
|
77
77
|
function generateCreateMethod(entity, deps) {
|
|
78
|
-
let code = `create${entity}: async (data) => {
|
|
79
|
-
set({ loading: true, error: null });
|
|
80
|
-
try {
|
|
81
|
-
const res = await fetch('/api/${entity.toLowerCase()}s', {
|
|
82
|
-
method: 'POST',
|
|
83
|
-
headers: { 'Content-Type': 'application/json' },
|
|
84
|
-
body: JSON.stringify(data),
|
|
85
|
-
});
|
|
86
|
-
if (!res.ok) throw new Error('Create failed');
|
|
87
|
-
const { data: new${entity} } = await res.json();
|
|
88
|
-
|
|
89
|
-
set(state => ({
|
|
90
|
-
${entity.toLowerCase()}s: [new${entity}, ...state.${entity.toLowerCase()}s],
|
|
91
|
-
loading: false,
|
|
92
|
-
}));
|
|
78
|
+
let code = `create${entity}: async (data) => {
|
|
79
|
+
set({ loading: true, error: null });
|
|
80
|
+
try {
|
|
81
|
+
const res = await fetch('/api/${entity.toLowerCase()}s', {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: { 'Content-Type': 'application/json' },
|
|
84
|
+
body: JSON.stringify(data),
|
|
85
|
+
});
|
|
86
|
+
if (!res.ok) throw new Error('Create failed');
|
|
87
|
+
const { data: new${entity} } = await res.json();
|
|
88
|
+
|
|
89
|
+
set(state => ({
|
|
90
|
+
${entity.toLowerCase()}s: [new${entity}, ...state.${entity.toLowerCase()}s],
|
|
91
|
+
loading: false,
|
|
92
|
+
}));
|
|
93
93
|
`;
|
|
94
94
|
if (deps.length > 0) {
|
|
95
95
|
code += `\n // Update dependent stores (from DEPENDENCY-MAP.md)\n`;
|
|
@@ -97,31 +97,31 @@ function generateCreateMethod(entity, deps) {
|
|
|
97
97
|
code += ` ${dep}.getState().refresh();\n`;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
code += ` } catch (error) {
|
|
101
|
-
set({ error: (error as Error).message, loading: false });
|
|
102
|
-
}
|
|
103
|
-
},
|
|
100
|
+
code += ` } catch (error) {
|
|
101
|
+
set({ error: (error as Error).message, loading: false });
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
104
|
`;
|
|
105
105
|
return code;
|
|
106
106
|
}
|
|
107
107
|
function generateUpdateMethod(entity, deps) {
|
|
108
|
-
let code = `update${entity}: async (id, data) => {
|
|
109
|
-
set({ loading: true, error: null });
|
|
110
|
-
try {
|
|
111
|
-
const res = await fetch(\`/api/${entity.toLowerCase()}s/\${id}\`, {
|
|
112
|
-
method: 'PATCH',
|
|
113
|
-
headers: { 'Content-Type': 'application/json' },
|
|
114
|
-
body: JSON.stringify(data),
|
|
115
|
-
});
|
|
116
|
-
if (!res.ok) throw new Error('Update failed');
|
|
117
|
-
const { data: updated } = await res.json();
|
|
118
|
-
|
|
119
|
-
set(state => ({
|
|
120
|
-
${entity.toLowerCase()}s: state.${entity.toLowerCase()}s.map(item =>
|
|
121
|
-
item.id === id ? updated : item
|
|
122
|
-
),
|
|
123
|
-
loading: false,
|
|
124
|
-
}));
|
|
108
|
+
let code = `update${entity}: async (id, data) => {
|
|
109
|
+
set({ loading: true, error: null });
|
|
110
|
+
try {
|
|
111
|
+
const res = await fetch(\`/api/${entity.toLowerCase()}s/\${id}\`, {
|
|
112
|
+
method: 'PATCH',
|
|
113
|
+
headers: { 'Content-Type': 'application/json' },
|
|
114
|
+
body: JSON.stringify(data),
|
|
115
|
+
});
|
|
116
|
+
if (!res.ok) throw new Error('Update failed');
|
|
117
|
+
const { data: updated } = await res.json();
|
|
118
|
+
|
|
119
|
+
set(state => ({
|
|
120
|
+
${entity.toLowerCase()}s: state.${entity.toLowerCase()}s.map(item =>
|
|
121
|
+
item.id === id ? updated : item
|
|
122
|
+
),
|
|
123
|
+
loading: false,
|
|
124
|
+
}));
|
|
125
125
|
`;
|
|
126
126
|
if (deps.length > 0) {
|
|
127
127
|
code += `\n // Update dependent stores\n`;
|
|
@@ -129,26 +129,26 @@ function generateUpdateMethod(entity, deps) {
|
|
|
129
129
|
code += ` ${dep}.getState().refresh();\n`;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
code += ` } catch (error) {
|
|
133
|
-
set({ error: (error as Error).message, loading: false });
|
|
134
|
-
}
|
|
135
|
-
},
|
|
132
|
+
code += ` } catch (error) {
|
|
133
|
+
set({ error: (error as Error).message, loading: false });
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
136
|
`;
|
|
137
137
|
return code;
|
|
138
138
|
}
|
|
139
139
|
function generateDeleteMethod(entity, deps) {
|
|
140
|
-
let code = `delete${entity}: async (id) => {
|
|
141
|
-
set({ loading: true, error: null });
|
|
142
|
-
try {
|
|
143
|
-
const res = await fetch(\`/api/${entity.toLowerCase()}s/\${id}\`, {
|
|
144
|
-
method: 'DELETE',
|
|
145
|
-
});
|
|
146
|
-
if (!res.ok) throw new Error('Delete failed');
|
|
147
|
-
|
|
148
|
-
set(state => ({
|
|
149
|
-
${entity.toLowerCase()}s: state.${entity.toLowerCase()}s.filter(item => item.id !== id),
|
|
150
|
-
loading: false,
|
|
151
|
-
}));
|
|
140
|
+
let code = `delete${entity}: async (id) => {
|
|
141
|
+
set({ loading: true, error: null });
|
|
142
|
+
try {
|
|
143
|
+
const res = await fetch(\`/api/${entity.toLowerCase()}s/\${id}\`, {
|
|
144
|
+
method: 'DELETE',
|
|
145
|
+
});
|
|
146
|
+
if (!res.ok) throw new Error('Delete failed');
|
|
147
|
+
|
|
148
|
+
set(state => ({
|
|
149
|
+
${entity.toLowerCase()}s: state.${entity.toLowerCase()}s.filter(item => item.id !== id),
|
|
150
|
+
loading: false,
|
|
151
|
+
}));
|
|
152
152
|
`;
|
|
153
153
|
if (deps.length > 0) {
|
|
154
154
|
code += `\n // Update ALL dependent stores (CRITICAL - prevents stale UI)\n`;
|
|
@@ -156,10 +156,10 @@ function generateDeleteMethod(entity, deps) {
|
|
|
156
156
|
code += ` ${dep}.getState().refresh();\n`;
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
-
code += ` } catch (error) {
|
|
160
|
-
set({ error: (error as Error).message, loading: false });
|
|
161
|
-
}
|
|
162
|
-
},
|
|
159
|
+
code += ` } catch (error) {
|
|
160
|
+
set({ error: (error as Error).message, loading: false });
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
163
|
`;
|
|
164
164
|
return code;
|
|
165
165
|
}
|