popeye-cli 1.2.0 → 1.3.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/.env.example +4 -1
- package/CONTRIBUTING.md +10 -0
- package/README.md +111 -2
- package/dist/adapters/claude.d.ts +26 -2
- package/dist/adapters/claude.d.ts.map +1 -1
- package/dist/adapters/claude.js +257 -10
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/grok.d.ts +2 -1
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js.map +1 -1
- package/dist/adapters/index.d.ts +8 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +12 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/openai.d.ts +2 -2
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js.map +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +25 -5
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +79 -6
- package/dist/cli/interactive.js.map +1 -1
- package/dist/generators/all.d.ts +40 -0
- package/dist/generators/all.d.ts.map +1 -0
- package/dist/generators/all.js +826 -0
- package/dist/generators/all.js.map +1 -0
- package/dist/generators/fullstack.d.ts +9 -0
- package/dist/generators/fullstack.d.ts.map +1 -1
- package/dist/generators/fullstack.js.map +1 -1
- package/dist/generators/index.d.ts +3 -1
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +33 -0
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/templates/index.d.ts +2 -0
- package/dist/generators/templates/index.d.ts.map +1 -1
- package/dist/generators/templates/index.js +2 -0
- package/dist/generators/templates/index.js.map +1 -1
- package/dist/generators/templates/website.d.ts +85 -0
- package/dist/generators/templates/website.d.ts.map +1 -0
- package/dist/generators/templates/website.js +877 -0
- package/dist/generators/templates/website.js.map +1 -0
- package/dist/generators/website.d.ts +56 -0
- package/dist/generators/website.d.ts.map +1 -0
- package/dist/generators/website.js +269 -0
- package/dist/generators/website.js.map +1 -0
- package/dist/types/consensus.d.ts +8 -3
- package/dist/types/consensus.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/project.d.ts +115 -1
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js +41 -1
- package/dist/types/project.js.map +1 -1
- package/dist/types/workflow.d.ts +8 -0
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +2 -2
- package/dist/types/workflow.js.map +1 -1
- package/dist/workflow/consensus.d.ts +2 -1
- package/dist/workflow/consensus.d.ts.map +1 -1
- package/dist/workflow/consensus.js.map +1 -1
- package/dist/workflow/execution-mode.d.ts +2 -0
- package/dist/workflow/execution-mode.d.ts.map +1 -1
- package/dist/workflow/execution-mode.js +20 -0
- package/dist/workflow/execution-mode.js.map +1 -1
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +19 -0
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/milestone-workflow.d.ts +2 -0
- package/dist/workflow/milestone-workflow.d.ts.map +1 -1
- package/dist/workflow/milestone-workflow.js +17 -0
- package/dist/workflow/milestone-workflow.js.map +1 -1
- package/dist/workflow/plan-mode.d.ts +3 -3
- package/dist/workflow/plan-mode.d.ts.map +1 -1
- package/dist/workflow/plan-mode.js.map +1 -1
- package/dist/workflow/plan-parser.d.ts +97 -0
- package/dist/workflow/plan-parser.d.ts.map +1 -0
- package/dist/workflow/plan-parser.js +235 -0
- package/dist/workflow/plan-parser.js.map +1 -0
- package/dist/workflow/plan-storage.d.ts +40 -12
- package/dist/workflow/plan-storage.d.ts.map +1 -1
- package/dist/workflow/plan-storage.js +47 -20
- package/dist/workflow/plan-storage.js.map +1 -1
- package/dist/workflow/seo-tests.d.ts +43 -0
- package/dist/workflow/seo-tests.d.ts.map +1 -0
- package/dist/workflow/seo-tests.js +192 -0
- package/dist/workflow/seo-tests.js.map +1 -0
- package/dist/workflow/separation-guard.d.ts +35 -0
- package/dist/workflow/separation-guard.d.ts.map +1 -0
- package/dist/workflow/separation-guard.js +154 -0
- package/dist/workflow/separation-guard.js.map +1 -0
- package/dist/workflow/task-workflow.d.ts +2 -0
- package/dist/workflow/task-workflow.d.ts.map +1 -1
- package/dist/workflow/task-workflow.js +19 -0
- package/dist/workflow/task-workflow.js.map +1 -1
- package/dist/workflow/test-runner.d.ts.map +1 -1
- package/dist/workflow/test-runner.js +128 -0
- package/dist/workflow/test-runner.js.map +1 -1
- package/dist/workflow/workspace-manager.d.ts +31 -20
- package/dist/workflow/workspace-manager.d.ts.map +1 -1
- package/dist/workflow/workspace-manager.js +38 -9
- package/dist/workflow/workspace-manager.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/claude.ts +289 -14
- package/src/adapters/grok.ts +2 -1
- package/src/adapters/index.ts +15 -0
- package/src/adapters/openai.ts +2 -2
- package/src/cli/commands/create.ts +25 -5
- package/src/cli/interactive.ts +76 -6
- package/src/generators/all.ts +897 -0
- package/src/generators/fullstack.ts +10 -0
- package/src/generators/index.ts +54 -0
- package/src/generators/templates/index.ts +2 -0
- package/src/generators/templates/website.ts +906 -0
- package/src/generators/website.ts +350 -0
- package/src/types/consensus.ts +9 -3
- package/src/types/index.ts +33 -0
- package/src/types/project.ts +139 -2
- package/src/types/workflow.ts +2 -2
- package/src/workflow/consensus.ts +3 -2
- package/src/workflow/execution-mode.ts +32 -0
- package/src/workflow/index.ts +20 -0
- package/src/workflow/milestone-workflow.ts +22 -0
- package/src/workflow/plan-mode.ts +3 -3
- package/src/workflow/plan-parser.ts +317 -0
- package/src/workflow/plan-storage.ts +69 -30
- package/src/workflow/seo-tests.ts +246 -0
- package/src/workflow/separation-guard.ts +200 -0
- package/src/workflow/task-workflow.ts +25 -0
- package/src/workflow/test-runner.ts +149 -0
- package/src/workflow/workspace-manager.ts +68 -31
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Website project generator
|
|
3
|
+
* Creates SEO-ready Next.js marketing website
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { promises as fs } from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import type { ProjectSpec } from '../types/project.js';
|
|
9
|
+
import {
|
|
10
|
+
generateWebsitePackageJson,
|
|
11
|
+
generateNextConfig,
|
|
12
|
+
generateWebsiteTsconfig,
|
|
13
|
+
generateWebsiteTailwindConfig,
|
|
14
|
+
generateWebsitePostcssConfig,
|
|
15
|
+
generateWebsiteLayout,
|
|
16
|
+
generateWebsiteGlobalsCss,
|
|
17
|
+
generateWebsiteLandingPage,
|
|
18
|
+
generateWebsitePricingPage,
|
|
19
|
+
generateWebsiteSitemap,
|
|
20
|
+
generateWebsiteRobots,
|
|
21
|
+
generateWebsiteDockerfile,
|
|
22
|
+
generateWebsiteReadme,
|
|
23
|
+
generateWebsiteSpec,
|
|
24
|
+
generateWebsiteVitestConfig,
|
|
25
|
+
generateWebsiteVitestSetup,
|
|
26
|
+
generateWebsiteTest,
|
|
27
|
+
generateWebsiteDocsPage,
|
|
28
|
+
generateWebsiteBlogPage,
|
|
29
|
+
generateWebsiteNextEnv,
|
|
30
|
+
} from './templates/website.js';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Project generation result
|
|
34
|
+
*/
|
|
35
|
+
export interface GenerationResult {
|
|
36
|
+
success: boolean;
|
|
37
|
+
projectDir: string;
|
|
38
|
+
filesCreated: string[];
|
|
39
|
+
error?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Website generator options for workspace/monorepo support
|
|
44
|
+
*/
|
|
45
|
+
export interface WebsiteGeneratorOptions {
|
|
46
|
+
/** Base directory for project (defaults to outputDir/projectName) */
|
|
47
|
+
baseDir?: string;
|
|
48
|
+
/** Override auto-derived package name */
|
|
49
|
+
packageName?: string;
|
|
50
|
+
/** Adjust paths for monorepo structure */
|
|
51
|
+
workspaceMode?: boolean;
|
|
52
|
+
/** Skip Docker files (fullstack uses root docker-compose) */
|
|
53
|
+
skipDocker?: boolean;
|
|
54
|
+
/** Skip README (fullstack has root README) */
|
|
55
|
+
skipReadme?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create a directory if it doesn't exist
|
|
60
|
+
*/
|
|
61
|
+
async function ensureDir(dirPath: string): Promise<void> {
|
|
62
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Write a file with content
|
|
67
|
+
*/
|
|
68
|
+
async function writeFile(filePath: string, content: string): Promise<void> {
|
|
69
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Generate a complete Next.js website project
|
|
74
|
+
*
|
|
75
|
+
* @param spec - Project specification
|
|
76
|
+
* @param outputDir - Output directory
|
|
77
|
+
* @param options - Generator options for workspace/monorepo support
|
|
78
|
+
* @returns Generation result
|
|
79
|
+
*/
|
|
80
|
+
export async function generateWebsiteProject(
|
|
81
|
+
spec: ProjectSpec,
|
|
82
|
+
outputDir: string,
|
|
83
|
+
options: WebsiteGeneratorOptions = {}
|
|
84
|
+
): Promise<GenerationResult> {
|
|
85
|
+
const {
|
|
86
|
+
baseDir,
|
|
87
|
+
// packageName reserved for future use
|
|
88
|
+
workspaceMode = false,
|
|
89
|
+
skipDocker = false,
|
|
90
|
+
skipReadme = false,
|
|
91
|
+
} = options;
|
|
92
|
+
|
|
93
|
+
const projectName = spec.name || 'my-project';
|
|
94
|
+
|
|
95
|
+
// In workspace mode with baseDir, use it directly; otherwise create subdirectory
|
|
96
|
+
const projectDir = baseDir || path.join(outputDir, projectName);
|
|
97
|
+
const filesCreated: string[] = [];
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
// Create project directory structure
|
|
101
|
+
await ensureDir(projectDir);
|
|
102
|
+
await ensureDir(path.join(projectDir, 'src', 'app'));
|
|
103
|
+
await ensureDir(path.join(projectDir, 'src', 'app', 'pricing'));
|
|
104
|
+
await ensureDir(path.join(projectDir, 'src', 'app', 'docs'));
|
|
105
|
+
await ensureDir(path.join(projectDir, 'src', 'app', 'blog'));
|
|
106
|
+
await ensureDir(path.join(projectDir, 'src', 'components'));
|
|
107
|
+
await ensureDir(path.join(projectDir, 'src', 'lib'));
|
|
108
|
+
await ensureDir(path.join(projectDir, 'content', 'blog'));
|
|
109
|
+
await ensureDir(path.join(projectDir, 'content', 'docs'));
|
|
110
|
+
await ensureDir(path.join(projectDir, 'public'));
|
|
111
|
+
await ensureDir(path.join(projectDir, 'tests'));
|
|
112
|
+
|
|
113
|
+
// Only create .popeye dir in standalone mode
|
|
114
|
+
if (!workspaceMode) {
|
|
115
|
+
await ensureDir(path.join(projectDir, '.popeye'));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Generate and write files
|
|
119
|
+
const files: Array<{ path: string; content: string }> = [
|
|
120
|
+
// Config files
|
|
121
|
+
{
|
|
122
|
+
path: path.join(projectDir, 'package.json'),
|
|
123
|
+
content: generateWebsitePackageJson(projectName),
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
path: path.join(projectDir, 'next.config.mjs'),
|
|
127
|
+
content: generateNextConfig(),
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
path: path.join(projectDir, 'tsconfig.json'),
|
|
131
|
+
content: generateWebsiteTsconfig(),
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
path: path.join(projectDir, 'tailwind.config.ts'),
|
|
135
|
+
content: generateWebsiteTailwindConfig(),
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
path: path.join(projectDir, 'postcss.config.js'),
|
|
139
|
+
content: generateWebsitePostcssConfig(),
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
path: path.join(projectDir, 'vitest.config.ts'),
|
|
143
|
+
content: generateWebsiteVitestConfig(),
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
path: path.join(projectDir, 'next-env.d.ts'),
|
|
147
|
+
content: generateWebsiteNextEnv(),
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// App Router files
|
|
151
|
+
{
|
|
152
|
+
path: path.join(projectDir, 'src', 'app', 'layout.tsx'),
|
|
153
|
+
content: generateWebsiteLayout(projectName),
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
path: path.join(projectDir, 'src', 'app', 'globals.css'),
|
|
157
|
+
content: generateWebsiteGlobalsCss(),
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
path: path.join(projectDir, 'src', 'app', 'page.tsx'),
|
|
161
|
+
content: generateWebsiteLandingPage(projectName),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
path: path.join(projectDir, 'src', 'app', 'pricing', 'page.tsx'),
|
|
165
|
+
content: generateWebsitePricingPage(projectName),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
path: path.join(projectDir, 'src', 'app', 'docs', 'page.tsx'),
|
|
169
|
+
content: generateWebsiteDocsPage(),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
path: path.join(projectDir, 'src', 'app', 'blog', 'page.tsx'),
|
|
173
|
+
content: generateWebsiteBlogPage(),
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// SEO files
|
|
177
|
+
{
|
|
178
|
+
path: path.join(projectDir, 'src', 'app', 'sitemap.ts'),
|
|
179
|
+
content: generateWebsiteSitemap(projectName),
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
path: path.join(projectDir, 'src', 'app', 'robots.ts'),
|
|
183
|
+
content: generateWebsiteRobots(projectName),
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
// Test files
|
|
187
|
+
{
|
|
188
|
+
path: path.join(projectDir, 'tests', 'setup.ts'),
|
|
189
|
+
content: generateWebsiteVitestSetup(),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
path: path.join(projectDir, 'tests', 'page.test.tsx'),
|
|
193
|
+
content: generateWebsiteTest(projectName),
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
// Placeholder files
|
|
197
|
+
{
|
|
198
|
+
path: path.join(projectDir, 'public', '.gitkeep'),
|
|
199
|
+
content: '',
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
path: path.join(projectDir, 'content', 'blog', '.gitkeep'),
|
|
203
|
+
content: '',
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
path: path.join(projectDir, 'content', 'docs', '.gitkeep'),
|
|
207
|
+
content: '',
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
path: path.join(projectDir, 'src', 'components', '.gitkeep'),
|
|
211
|
+
content: '',
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
path: path.join(projectDir, 'src', 'lib', '.gitkeep'),
|
|
215
|
+
content: '',
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// Environment
|
|
219
|
+
{
|
|
220
|
+
path: path.join(projectDir, '.env.example'),
|
|
221
|
+
content: 'NEXT_PUBLIC_SITE_URL=http://localhost:3001\nNEXT_PUBLIC_APP_URL=http://localhost:3000\n',
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
path: path.join(projectDir, '.gitignore'),
|
|
225
|
+
content:
|
|
226
|
+
'node_modules/\n.next/\nout/\n.env\n.env.local\n.env.*.local\ncoverage/\n*.log\n.DS_Store\n',
|
|
227
|
+
},
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
// Add website spec in standalone mode
|
|
231
|
+
if (!workspaceMode) {
|
|
232
|
+
files.push({
|
|
233
|
+
path: path.join(projectDir, '.popeye', 'website-spec.json'),
|
|
234
|
+
content: generateWebsiteSpec(projectName),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Add README if not skipped
|
|
239
|
+
if (!skipReadme) {
|
|
240
|
+
files.push({
|
|
241
|
+
path: path.join(projectDir, 'README.md'),
|
|
242
|
+
content: generateWebsiteReadme(projectName),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Add Docker files if not skipped
|
|
247
|
+
if (!skipDocker) {
|
|
248
|
+
files.push({
|
|
249
|
+
path: path.join(projectDir, 'Dockerfile'),
|
|
250
|
+
content: generateWebsiteDockerfile(),
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Write all files
|
|
255
|
+
for (const file of files) {
|
|
256
|
+
await writeFile(file.path, file.content);
|
|
257
|
+
filesCreated.push(file.path);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
success: true,
|
|
262
|
+
projectDir,
|
|
263
|
+
filesCreated,
|
|
264
|
+
};
|
|
265
|
+
} catch (error) {
|
|
266
|
+
return {
|
|
267
|
+
success: false,
|
|
268
|
+
projectDir,
|
|
269
|
+
filesCreated,
|
|
270
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get the list of files that would be generated for a website project
|
|
277
|
+
*
|
|
278
|
+
* @param _projectName - Project name
|
|
279
|
+
* @returns List of relative file paths
|
|
280
|
+
*/
|
|
281
|
+
export function getWebsiteProjectFiles(_projectName: string): string[] {
|
|
282
|
+
return [
|
|
283
|
+
// Config
|
|
284
|
+
'package.json',
|
|
285
|
+
'next.config.mjs',
|
|
286
|
+
'tsconfig.json',
|
|
287
|
+
'tailwind.config.ts',
|
|
288
|
+
'postcss.config.js',
|
|
289
|
+
'vitest.config.ts',
|
|
290
|
+
'next-env.d.ts',
|
|
291
|
+
'.gitignore',
|
|
292
|
+
'.env.example',
|
|
293
|
+
'README.md',
|
|
294
|
+
'Dockerfile',
|
|
295
|
+
// App Router
|
|
296
|
+
'src/app/layout.tsx',
|
|
297
|
+
'src/app/globals.css',
|
|
298
|
+
'src/app/page.tsx',
|
|
299
|
+
'src/app/pricing/page.tsx',
|
|
300
|
+
'src/app/docs/page.tsx',
|
|
301
|
+
'src/app/blog/page.tsx',
|
|
302
|
+
'src/app/sitemap.ts',
|
|
303
|
+
'src/app/robots.ts',
|
|
304
|
+
// Tests
|
|
305
|
+
'tests/setup.ts',
|
|
306
|
+
'tests/page.test.tsx',
|
|
307
|
+
// Content
|
|
308
|
+
'content/blog/.gitkeep',
|
|
309
|
+
'content/docs/.gitkeep',
|
|
310
|
+
// Spec
|
|
311
|
+
'.popeye/website-spec.json',
|
|
312
|
+
];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Validate a website project structure
|
|
317
|
+
*
|
|
318
|
+
* @param projectDir - Project directory
|
|
319
|
+
* @returns Validation result
|
|
320
|
+
*/
|
|
321
|
+
export async function validateWebsiteProject(projectDir: string): Promise<{
|
|
322
|
+
valid: boolean;
|
|
323
|
+
missingFiles: string[];
|
|
324
|
+
}> {
|
|
325
|
+
const missingFiles: string[] = [];
|
|
326
|
+
|
|
327
|
+
const requiredFiles = [
|
|
328
|
+
'package.json',
|
|
329
|
+
'next.config.mjs',
|
|
330
|
+
'tsconfig.json',
|
|
331
|
+
'src/app/layout.tsx',
|
|
332
|
+
'src/app/page.tsx',
|
|
333
|
+
'src/app/sitemap.ts',
|
|
334
|
+
'src/app/robots.ts',
|
|
335
|
+
];
|
|
336
|
+
|
|
337
|
+
for (const file of requiredFiles) {
|
|
338
|
+
const filePath = path.join(projectDir, file);
|
|
339
|
+
try {
|
|
340
|
+
await fs.access(filePath);
|
|
341
|
+
} catch {
|
|
342
|
+
missingFiles.push(file);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
valid: missingFiles.length === 0,
|
|
348
|
+
missingFiles,
|
|
349
|
+
};
|
|
350
|
+
}
|
package/src/types/consensus.ts
CHANGED
|
@@ -195,9 +195,9 @@ export interface EscalationDetails {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
/**
|
|
198
|
-
* App target for fullstack reviews
|
|
198
|
+
* App target for fullstack/all reviews
|
|
199
199
|
*/
|
|
200
|
-
export type ReviewAppTarget = 'frontend' | 'backend' | 'unified';
|
|
200
|
+
export type ReviewAppTarget = 'frontend' | 'backend' | 'website' | 'unified';
|
|
201
201
|
|
|
202
202
|
/**
|
|
203
203
|
* Tagged concern/recommendation with app context
|
|
@@ -208,11 +208,12 @@ export interface TaggedItem {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
/**
|
|
211
|
-
* Per-app consensus scores for fullstack projects
|
|
211
|
+
* Per-app consensus scores for fullstack/all projects
|
|
212
212
|
*/
|
|
213
213
|
export interface AppConsensusScores {
|
|
214
214
|
frontend?: number;
|
|
215
215
|
backend?: number;
|
|
216
|
+
website?: number;
|
|
216
217
|
unified: number; // Combined/overall score
|
|
217
218
|
}
|
|
218
219
|
|
|
@@ -253,6 +254,7 @@ export interface FullstackConsensusIteration extends ConsensusIteration {
|
|
|
253
254
|
appApproved?: {
|
|
254
255
|
frontend?: boolean;
|
|
255
256
|
backend?: boolean;
|
|
257
|
+
website?: boolean;
|
|
256
258
|
unified: boolean;
|
|
257
259
|
};
|
|
258
260
|
}
|
|
@@ -295,6 +297,10 @@ export interface ConsensusTrackingRecord {
|
|
|
295
297
|
backendApproved?: boolean;
|
|
296
298
|
backendIterations?: number;
|
|
297
299
|
|
|
300
|
+
websiteScore?: number;
|
|
301
|
+
websiteApproved?: boolean;
|
|
302
|
+
websiteIterations?: number;
|
|
303
|
+
|
|
298
304
|
/** All corrections/revisions made */
|
|
299
305
|
corrections: CorrectionRecord[];
|
|
300
306
|
|
package/src/types/index.ts
CHANGED
|
@@ -9,11 +9,28 @@ export {
|
|
|
9
9
|
OpenAIModelSchema,
|
|
10
10
|
ProjectSpecSchema,
|
|
11
11
|
OPENAI_MODELS,
|
|
12
|
+
languageToApps,
|
|
13
|
+
hasApp,
|
|
12
14
|
type OutputLanguage,
|
|
13
15
|
type OpenAIModel,
|
|
14
16
|
type ProjectSpec,
|
|
15
17
|
type GeneratedProject,
|
|
16
18
|
type GenerationOptions,
|
|
19
|
+
type AppType,
|
|
20
|
+
type WorkspaceApp,
|
|
21
|
+
type WorkspaceAppCommands,
|
|
22
|
+
type WorkspaceAppDocker,
|
|
23
|
+
type WorkspaceShared,
|
|
24
|
+
type WorkspaceCommands,
|
|
25
|
+
type WorkspaceDocker,
|
|
26
|
+
type WorkspaceConfig,
|
|
27
|
+
type WebsiteSpec,
|
|
28
|
+
type WebsiteBrandColors,
|
|
29
|
+
type WebsiteTypography,
|
|
30
|
+
type WebsiteSeo,
|
|
31
|
+
type WebsitePage,
|
|
32
|
+
type WebsiteCta,
|
|
33
|
+
type WebsiteFeatures,
|
|
17
34
|
} from './project.js';
|
|
18
35
|
|
|
19
36
|
// Workflow types
|
|
@@ -37,12 +54,28 @@ export {
|
|
|
37
54
|
export {
|
|
38
55
|
ConsensusConfigSchema,
|
|
39
56
|
DEFAULT_CONSENSUS_CONFIG,
|
|
57
|
+
DEFAULT_GROK_MODEL,
|
|
58
|
+
AIProviderSchema,
|
|
59
|
+
GeminiModelSchema,
|
|
60
|
+
GrokModelSchema,
|
|
61
|
+
type AIProvider,
|
|
62
|
+
type GeminiModel,
|
|
63
|
+
type GrokModel,
|
|
40
64
|
type ConsensusResult,
|
|
41
65
|
type ConsensusIteration,
|
|
42
66
|
type ConsensusConfig,
|
|
43
67
|
type PlanDocument,
|
|
44
68
|
type ConsensusRequest,
|
|
45
69
|
type EscalationDetails,
|
|
70
|
+
type ArbitrationResult,
|
|
71
|
+
type ReviewAppTarget,
|
|
72
|
+
type TaggedItem,
|
|
73
|
+
type AppConsensusScores,
|
|
74
|
+
type AppFeedback,
|
|
75
|
+
type FullstackConsensusResult,
|
|
76
|
+
type FullstackConsensusIteration,
|
|
77
|
+
type CorrectionRecord,
|
|
78
|
+
type ConsensusTrackingRecord,
|
|
46
79
|
} from './consensus.js';
|
|
47
80
|
|
|
48
81
|
// CLI types
|
package/src/types/project.ts
CHANGED
|
@@ -8,9 +8,56 @@ import { z } from 'zod';
|
|
|
8
8
|
/**
|
|
9
9
|
* Supported output languages for generated projects
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Supported output languages for generated projects
|
|
13
|
+
* - python: Backend only (FastAPI)
|
|
14
|
+
* - typescript: Frontend only (React/Vite)
|
|
15
|
+
* - fullstack: FE + BE
|
|
16
|
+
* - website: Website only (Next.js SSG/SSR)
|
|
17
|
+
* - all: FE + BE + Website (everything)
|
|
18
|
+
*/
|
|
19
|
+
export const OutputLanguageSchema = z.enum([
|
|
20
|
+
'python',
|
|
21
|
+
'typescript',
|
|
22
|
+
'fullstack',
|
|
23
|
+
'website',
|
|
24
|
+
'all',
|
|
25
|
+
]);
|
|
12
26
|
export type OutputLanguage = z.infer<typeof OutputLanguageSchema>;
|
|
13
27
|
|
|
28
|
+
/**
|
|
29
|
+
* App types that can be generated
|
|
30
|
+
*/
|
|
31
|
+
export type AppType = 'frontend' | 'backend' | 'website';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Maps a language to the apps it will generate
|
|
35
|
+
*
|
|
36
|
+
* @param language - The output language
|
|
37
|
+
* @returns Array of app types to generate
|
|
38
|
+
*/
|
|
39
|
+
export function languageToApps(language: OutputLanguage): AppType[] {
|
|
40
|
+
const mapping: Record<OutputLanguage, AppType[]> = {
|
|
41
|
+
python: ['backend'],
|
|
42
|
+
typescript: ['frontend'],
|
|
43
|
+
fullstack: ['frontend', 'backend'],
|
|
44
|
+
website: ['website'],
|
|
45
|
+
all: ['frontend', 'backend', 'website'],
|
|
46
|
+
};
|
|
47
|
+
return mapping[language];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Checks if a language generates a specific app type
|
|
52
|
+
*
|
|
53
|
+
* @param language - The output language
|
|
54
|
+
* @param app - The app type to check
|
|
55
|
+
* @returns True if the language generates the app
|
|
56
|
+
*/
|
|
57
|
+
export function hasApp(language: OutputLanguage, app: AppType): boolean {
|
|
58
|
+
return languageToApps(language).includes(app);
|
|
59
|
+
}
|
|
60
|
+
|
|
14
61
|
/**
|
|
15
62
|
* Commands configuration for a workspace app
|
|
16
63
|
*/
|
|
@@ -56,6 +103,10 @@ export interface WorkspaceShared {
|
|
|
56
103
|
contracts?: string;
|
|
57
104
|
/** Generator command for FE client from OpenAPI */
|
|
58
105
|
contractsGenerator?: string;
|
|
106
|
+
/** Shared UI components package path */
|
|
107
|
+
ui?: string;
|
|
108
|
+
/** Design tokens package path */
|
|
109
|
+
designTokens?: string;
|
|
59
110
|
}
|
|
60
111
|
|
|
61
112
|
/**
|
|
@@ -78,13 +129,14 @@ export interface WorkspaceDocker {
|
|
|
78
129
|
}
|
|
79
130
|
|
|
80
131
|
/**
|
|
81
|
-
* Workspace configuration for fullstack projects
|
|
132
|
+
* Workspace configuration for fullstack/website/all projects
|
|
82
133
|
*/
|
|
83
134
|
export interface WorkspaceConfig {
|
|
84
135
|
version: '1.0';
|
|
85
136
|
apps: {
|
|
86
137
|
frontend?: WorkspaceApp;
|
|
87
138
|
backend?: WorkspaceApp;
|
|
139
|
+
website?: WorkspaceApp;
|
|
88
140
|
};
|
|
89
141
|
shared?: WorkspaceShared;
|
|
90
142
|
/** Repo-level commands that orchestrate across apps */
|
|
@@ -92,6 +144,91 @@ export interface WorkspaceConfig {
|
|
|
92
144
|
docker: WorkspaceDocker;
|
|
93
145
|
}
|
|
94
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Brand colors for website design
|
|
149
|
+
*/
|
|
150
|
+
export interface WebsiteBrandColors {
|
|
151
|
+
primary: string;
|
|
152
|
+
secondary: string;
|
|
153
|
+
accent: string;
|
|
154
|
+
background: string;
|
|
155
|
+
foreground: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Typography configuration for website
|
|
160
|
+
*/
|
|
161
|
+
export interface WebsiteTypography {
|
|
162
|
+
headingFont: string;
|
|
163
|
+
bodyFont: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* SEO configuration for website
|
|
168
|
+
*/
|
|
169
|
+
export interface WebsiteSeo {
|
|
170
|
+
title: string;
|
|
171
|
+
description: string;
|
|
172
|
+
keywords: string[];
|
|
173
|
+
ogImage?: string;
|
|
174
|
+
twitterHandle?: string;
|
|
175
|
+
locale: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Page configuration for website
|
|
180
|
+
*/
|
|
181
|
+
export interface WebsitePage {
|
|
182
|
+
name: string;
|
|
183
|
+
path: string;
|
|
184
|
+
type: 'landing' | 'pricing' | 'docs' | 'blog' | 'changelog' | 'legal';
|
|
185
|
+
seo?: {
|
|
186
|
+
title?: string;
|
|
187
|
+
description?: string;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Call-to-action configuration
|
|
193
|
+
*/
|
|
194
|
+
export interface WebsiteCta {
|
|
195
|
+
primary: {
|
|
196
|
+
text: string;
|
|
197
|
+
href: string;
|
|
198
|
+
};
|
|
199
|
+
secondary?: {
|
|
200
|
+
text: string;
|
|
201
|
+
href: string;
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Feature flags for website
|
|
207
|
+
*/
|
|
208
|
+
export interface WebsiteFeatures {
|
|
209
|
+
analytics?: boolean;
|
|
210
|
+
newsletter?: boolean;
|
|
211
|
+
mdxBlog?: boolean;
|
|
212
|
+
docsSearch?: boolean;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Website specification for Next.js marketing sites
|
|
217
|
+
*/
|
|
218
|
+
export interface WebsiteSpec {
|
|
219
|
+
version: '1.0';
|
|
220
|
+
brand: {
|
|
221
|
+
name: string;
|
|
222
|
+
tagline?: string;
|
|
223
|
+
colors: WebsiteBrandColors;
|
|
224
|
+
typography: WebsiteTypography;
|
|
225
|
+
};
|
|
226
|
+
seo: WebsiteSeo;
|
|
227
|
+
pages: WebsitePage[];
|
|
228
|
+
cta: WebsiteCta;
|
|
229
|
+
features?: WebsiteFeatures;
|
|
230
|
+
}
|
|
231
|
+
|
|
95
232
|
/**
|
|
96
233
|
* Supported OpenAI models for consensus reviews
|
|
97
234
|
*/
|
package/src/types/workflow.ts
CHANGED
|
@@ -16,13 +16,13 @@ export type WorkflowPhase = z.infer<typeof WorkflowPhaseSchema>;
|
|
|
16
16
|
/**
|
|
17
17
|
* Project status
|
|
18
18
|
*/
|
|
19
|
-
export const ProjectStatusSchema = z.enum(['pending', 'in-progress', 'complete', 'failed']);
|
|
19
|
+
export const ProjectStatusSchema = z.enum(['pending', 'in-progress', 'complete', 'failed', 'paused']);
|
|
20
20
|
export type ProjectStatus = z.infer<typeof ProjectStatusSchema>;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Status of a task or milestone
|
|
24
24
|
*/
|
|
25
|
-
export const TaskStatusSchema = z.enum(['pending', 'in-progress', 'complete', 'failed']);
|
|
25
|
+
export const TaskStatusSchema = z.enum(['pending', 'in-progress', 'complete', 'failed', 'paused']);
|
|
26
26
|
export type TaskStatus = z.infer<typeof TaskStatusSchema>;
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
AppConsensusScores,
|
|
15
15
|
CorrectionRecord,
|
|
16
16
|
} from '../types/consensus.js';
|
|
17
|
+
import type { OutputLanguage } from '../types/project.js';
|
|
17
18
|
import { DEFAULT_CONSENSUS_CONFIG } from '../types/consensus.js';
|
|
18
19
|
import { requestConsensus as requestOpenAIConsensus } from '../adapters/openai.js';
|
|
19
20
|
import { requestConsensus as requestGeminiConsensus, requestArbitration as requestGeminiArbitration } from '../adapters/gemini.js';
|
|
@@ -36,7 +37,7 @@ export interface ConsensusOptions {
|
|
|
36
37
|
/** Whether this is a fullstack project (enables per-app tracking) */
|
|
37
38
|
isFullstack?: boolean;
|
|
38
39
|
/** Project language for revision prompts */
|
|
39
|
-
language?:
|
|
40
|
+
language?: OutputLanguage;
|
|
40
41
|
onIteration?: (iteration: number, result: ConsensusResult) => void;
|
|
41
42
|
onRevision?: (iteration: number, revisedPlan: string) => void;
|
|
42
43
|
onConcerns?: (concerns: string[], recommendations: string[]) => void;
|
|
@@ -947,7 +948,7 @@ export async function runOptimizedConsensusProcess(
|
|
|
947
948
|
} = options;
|
|
948
949
|
|
|
949
950
|
// Derive language from isFullstack for revision prompts
|
|
950
|
-
const language:
|
|
951
|
+
const language: OutputLanguage = isFullstack ? 'fullstack' : 'python';
|
|
951
952
|
|
|
952
953
|
const {
|
|
953
954
|
threshold = DEFAULT_CONSENSUS_CONFIG.threshold,
|