popeye-cli 1.4.3 → 1.4.5
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-mode.d.ts","sourceRoot":"","sources":["../../src/workflow/execution-mode.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAgD,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAS/G,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAC;AAU1B;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BjE;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAuBrE;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACzD,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9E,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gCAAgC;IAChC,WAAW,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9C,+BAA+B;IAC/B,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;CAC3D;
|
|
1
|
+
{"version":3,"file":"execution-mode.d.ts","sourceRoot":"","sources":["../../src/workflow/execution-mode.ts"],"names":[],"mappings":"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"}
|
|
@@ -94,6 +94,7 @@ const DEFAULT_MAX_RETRIES = 3;
|
|
|
94
94
|
async function generateProjectReadme(projectDir, state) {
|
|
95
95
|
try {
|
|
96
96
|
const readmePath = path.join(projectDir, 'README.md');
|
|
97
|
+
const workspace = isWorkspace(state.language);
|
|
97
98
|
// Extract features from completed milestones
|
|
98
99
|
const features = state.milestones
|
|
99
100
|
.filter(m => m.status === 'complete')
|
|
@@ -102,119 +103,495 @@ async function generateProjectReadme(projectDir, state) {
|
|
|
102
103
|
description: m.description,
|
|
103
104
|
tasks: m.tasks.filter(t => t.status === 'complete').map(t => t.name),
|
|
104
105
|
}));
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
// Load workspace.json for workspace projects
|
|
107
|
+
let wsConfig = null;
|
|
108
|
+
if (workspace) {
|
|
109
|
+
try {
|
|
110
|
+
const wsContent = await fs.readFile(path.join(projectDir, '.popeye', 'workspace.json'), 'utf-8');
|
|
111
|
+
wsConfig = JSON.parse(wsContent);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// workspace.json not available, use defaults
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const description = state.specification
|
|
118
|
+
? extractDescriptionFromSpec(state.specification)
|
|
119
|
+
: 'A project generated by Popeye CLI.';
|
|
120
|
+
const sections = [];
|
|
121
|
+
// Title and description
|
|
122
|
+
sections.push(`# ${state.name}\n\n${description}`);
|
|
123
|
+
// Features
|
|
124
|
+
const featuresContent = features.map(f => `### ${f.name}
|
|
125
|
+
${f.description || ''}
|
|
126
|
+
${f.tasks.length > 0 ? f.tasks.map(t => `- ${t}`).join('\n') : ''}`).join('\n\n');
|
|
127
|
+
sections.push(`## Features\n\n${featuresContent}`);
|
|
128
|
+
// Prerequisites
|
|
129
|
+
sections.push(`## Prerequisites\n\n${generatePrerequisites(state.language)}`);
|
|
130
|
+
// Installation
|
|
131
|
+
sections.push(`## Installation\n\n${generateInstallation(state.name, state.language)}`);
|
|
132
|
+
// Environment Setup
|
|
133
|
+
sections.push(`## Environment Setup
|
|
113
134
|
|
|
114
|
-
|
|
135
|
+
1. Copy the example environment file:
|
|
136
|
+
\`\`\`bash
|
|
137
|
+
cp .env.example .env
|
|
138
|
+
\`\`\`
|
|
115
139
|
|
|
116
|
-
|
|
140
|
+
2. Edit \`.env\` and fill in the required values.`);
|
|
141
|
+
// Running the Application
|
|
142
|
+
sections.push(`## Running the Application\n\n${generateRunSection(state.language, wsConfig)}`);
|
|
143
|
+
// Project Structure
|
|
144
|
+
sections.push(`## Project Structure\n\n${generateStructureSection(state.name, state.language)}`);
|
|
145
|
+
// Deployment - per-app for workspace projects
|
|
146
|
+
if (workspace) {
|
|
147
|
+
sections.push(`## Deployment\n\n${generateDeploymentSection(state.name, state.language, wsConfig)}`);
|
|
148
|
+
}
|
|
149
|
+
// Development footer
|
|
150
|
+
sections.push(`## Development
|
|
117
151
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
152
|
+
This project was generated using [Popeye CLI](https://github.com/your-org/popeye-cli), an autonomous code generation tool.
|
|
153
|
+
|
|
154
|
+
### Development Plan
|
|
155
|
+
|
|
156
|
+
See [docs/PLAN.md](docs/PLAN.md) for the complete development plan used to build this project.
|
|
157
|
+
|
|
158
|
+
### Workflow Log
|
|
159
|
+
|
|
160
|
+
See [docs/WORKFLOW_LOG.md](docs/WORKFLOW_LOG.md) for detailed execution logs.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT`);
|
|
165
|
+
const readmeContent = sections.join('\n\n') + '\n';
|
|
166
|
+
await fs.writeFile(readmePath, readmeContent, 'utf-8');
|
|
167
|
+
return { success: true, path: readmePath };
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
error: error instanceof Error ? error.message : 'Failed to generate README',
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Generate prerequisites section based on language
|
|
178
|
+
*/
|
|
179
|
+
function generatePrerequisites(language) {
|
|
180
|
+
if (language === 'python') {
|
|
181
|
+
return `- Python 3.9 or higher
|
|
182
|
+
- pip (Python package manager)`;
|
|
183
|
+
}
|
|
184
|
+
if (language === 'typescript' || language === 'website') {
|
|
185
|
+
return `- Node.js 18.0 or higher
|
|
186
|
+
- npm 8.0 or higher`;
|
|
187
|
+
}
|
|
188
|
+
// Workspace projects (fullstack, all) need both
|
|
189
|
+
return `- Node.js 18.0 or higher
|
|
190
|
+
- npm 8.0 or higher
|
|
191
|
+
- Python 3.9 or higher
|
|
192
|
+
- pip (Python package manager)
|
|
193
|
+
- Docker and Docker Compose (recommended for local development)`;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Generate installation section based on language
|
|
197
|
+
*/
|
|
198
|
+
function generateInstallation(name, language) {
|
|
199
|
+
const lines = [`\`\`\`bash`, `cd ${name}`, ''];
|
|
200
|
+
if (isWorkspace(language)) {
|
|
201
|
+
lines.push('# Install all workspace dependencies');
|
|
202
|
+
lines.push('npm install');
|
|
203
|
+
lines.push('');
|
|
204
|
+
lines.push('# Install backend Python dependencies');
|
|
205
|
+
lines.push('cd apps/backend && pip install -r requirements.txt && cd ../..');
|
|
206
|
+
if (language === 'all') {
|
|
207
|
+
lines.push('');
|
|
208
|
+
lines.push('# Install website dependencies (if not covered by workspace)');
|
|
209
|
+
lines.push('cd apps/website && npm install && cd ../..');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (language === 'python') {
|
|
213
|
+
lines.push('pip install -r requirements.txt');
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
lines.push('npm install');
|
|
217
|
+
}
|
|
218
|
+
lines.push('```');
|
|
219
|
+
return lines.join('\n');
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Generate run commands section based on language
|
|
223
|
+
*/
|
|
224
|
+
function generateRunSection(language, wsConfig) {
|
|
225
|
+
if (language === 'python') {
|
|
226
|
+
return `### Development Mode
|
|
121
227
|
|
|
122
|
-
|
|
228
|
+
\`\`\`bash
|
|
229
|
+
python src/main.py
|
|
230
|
+
\`\`\`
|
|
231
|
+
|
|
232
|
+
### Running Tests
|
|
123
233
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
234
|
+
\`\`\`bash
|
|
235
|
+
pytest tests/ -v
|
|
236
|
+
\`\`\`
|
|
127
237
|
|
|
128
|
-
|
|
238
|
+
### Build for Production
|
|
129
239
|
|
|
130
240
|
\`\`\`bash
|
|
131
|
-
|
|
132
|
-
|
|
241
|
+
python -m py_compile src/**/*.py
|
|
242
|
+
\`\`\``;
|
|
243
|
+
}
|
|
244
|
+
if (language === 'typescript') {
|
|
245
|
+
return `### Development Mode
|
|
133
246
|
|
|
134
|
-
|
|
135
|
-
|
|
247
|
+
\`\`\`bash
|
|
248
|
+
npm run dev
|
|
136
249
|
\`\`\`
|
|
137
250
|
|
|
138
|
-
|
|
251
|
+
### Running Tests
|
|
139
252
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
253
|
+
\`\`\`bash
|
|
254
|
+
npm test
|
|
255
|
+
\`\`\`
|
|
256
|
+
|
|
257
|
+
### Build for Production
|
|
144
258
|
|
|
145
|
-
|
|
259
|
+
\`\`\`bash
|
|
260
|
+
npm run build
|
|
261
|
+
\`\`\`
|
|
146
262
|
|
|
147
|
-
|
|
263
|
+
### Start Production Server
|
|
148
264
|
|
|
149
|
-
|
|
265
|
+
\`\`\`bash
|
|
266
|
+
npm start
|
|
267
|
+
\`\`\``;
|
|
268
|
+
}
|
|
269
|
+
if (language === 'website') {
|
|
270
|
+
return `### Development Mode
|
|
150
271
|
|
|
151
272
|
\`\`\`bash
|
|
152
|
-
|
|
273
|
+
npm run dev
|
|
153
274
|
\`\`\`
|
|
154
275
|
|
|
155
276
|
### Running Tests
|
|
156
277
|
|
|
157
278
|
\`\`\`bash
|
|
158
|
-
|
|
279
|
+
npm test
|
|
159
280
|
\`\`\`
|
|
160
281
|
|
|
161
282
|
### Build for Production
|
|
162
283
|
|
|
163
284
|
\`\`\`bash
|
|
164
|
-
|
|
285
|
+
npm run build
|
|
165
286
|
\`\`\`
|
|
166
287
|
|
|
167
|
-
|
|
288
|
+
### Preview Production Build
|
|
168
289
|
|
|
169
290
|
\`\`\`bash
|
|
170
|
-
npm start
|
|
291
|
+
npm run start
|
|
292
|
+
\`\`\``;
|
|
293
|
+
}
|
|
294
|
+
// Workspace projects (fullstack, all)
|
|
295
|
+
const apps = wsConfig?.apps;
|
|
296
|
+
const lines = [];
|
|
297
|
+
lines.push(`### Run Everything (Docker Compose)
|
|
298
|
+
|
|
299
|
+
\`\`\`bash
|
|
300
|
+
docker-compose up
|
|
171
301
|
\`\`\`
|
|
172
|
-
` : ''}
|
|
173
|
-
## Project Structure
|
|
174
302
|
|
|
303
|
+
### Run Individual Apps`);
|
|
304
|
+
// Frontend
|
|
305
|
+
const fePath = apps?.frontend?.path || 'apps/frontend';
|
|
306
|
+
lines.push(`
|
|
307
|
+
#### Frontend (React/Vite)
|
|
308
|
+
|
|
309
|
+
\`\`\`bash
|
|
310
|
+
cd ${fePath}
|
|
311
|
+
npm run dev # Development server
|
|
312
|
+
npm run build # Production build
|
|
313
|
+
npm test # Run tests
|
|
314
|
+
\`\`\``);
|
|
315
|
+
// Backend
|
|
316
|
+
const bePath = apps?.backend?.path || 'apps/backend';
|
|
317
|
+
lines.push(`
|
|
318
|
+
#### Backend (Python/FastAPI)
|
|
319
|
+
|
|
320
|
+
\`\`\`bash
|
|
321
|
+
cd ${bePath}
|
|
322
|
+
uvicorn src.backend.main:app --reload --port 8000 # Development server
|
|
323
|
+
pip install -e . # Build/install
|
|
324
|
+
pytest tests/ -v # Run tests
|
|
325
|
+
\`\`\``);
|
|
326
|
+
// Website (for 'all' projects)
|
|
327
|
+
if (language === 'all') {
|
|
328
|
+
const webPath = apps?.website?.path || 'apps/website';
|
|
329
|
+
lines.push(`
|
|
330
|
+
#### Website (Next.js)
|
|
331
|
+
|
|
332
|
+
\`\`\`bash
|
|
333
|
+
cd ${webPath}
|
|
334
|
+
npm run dev # Development server (port 3001)
|
|
335
|
+
npm run build # Production build
|
|
336
|
+
npm test # Run tests
|
|
337
|
+
\`\`\``);
|
|
338
|
+
}
|
|
339
|
+
// All-at-once commands
|
|
340
|
+
lines.push(`
|
|
341
|
+
### Run All Tests
|
|
342
|
+
|
|
343
|
+
\`\`\`bash
|
|
344
|
+
npm run test:all
|
|
175
345
|
\`\`\`
|
|
176
|
-
|
|
346
|
+
|
|
347
|
+
### Build All
|
|
348
|
+
|
|
349
|
+
\`\`\`bash
|
|
350
|
+
npm run build:all
|
|
351
|
+
\`\`\``);
|
|
352
|
+
return lines.join('\n');
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Generate project structure section based on language
|
|
356
|
+
*/
|
|
357
|
+
function generateStructureSection(name, language) {
|
|
358
|
+
if (language === 'python') {
|
|
359
|
+
return `\`\`\`
|
|
360
|
+
${name}/
|
|
177
361
|
├── src/ # Source code
|
|
178
|
-
|
|
179
|
-
│ └── main.py # Main entry point
|
|
362
|
+
│ ├── __init__.py
|
|
363
|
+
│ └── main.py # Main entry point
|
|
180
364
|
├── tests/ # Test files
|
|
181
365
|
├── docs/ # Documentation
|
|
182
366
|
│ ├── PLAN.md # Development plan
|
|
183
367
|
│ └── WORKFLOW_LOG.md # Execution log
|
|
184
|
-
|
|
185
|
-
├──
|
|
186
|
-
├── pyproject.toml # Project configuration`}
|
|
368
|
+
├── requirements.txt # Python dependencies
|
|
369
|
+
├── pyproject.toml # Project configuration
|
|
187
370
|
├── .env.example # Environment template
|
|
188
371
|
├── .gitignore
|
|
189
372
|
├── Dockerfile
|
|
190
373
|
└── README.md
|
|
191
|
-
|
|
374
|
+
\`\`\``;
|
|
375
|
+
}
|
|
376
|
+
if (language === 'typescript') {
|
|
377
|
+
return `\`\`\`
|
|
378
|
+
${name}/
|
|
379
|
+
├── src/ # Source code
|
|
380
|
+
│ └── index.ts # Main entry point
|
|
381
|
+
├── tests/ # Test files
|
|
382
|
+
├── docs/ # Documentation
|
|
383
|
+
│ ├── PLAN.md # Development plan
|
|
384
|
+
│ └── WORKFLOW_LOG.md # Execution log
|
|
385
|
+
├── package.json # Dependencies and scripts
|
|
386
|
+
├── tsconfig.json # TypeScript configuration
|
|
387
|
+
├── .env.example # Environment template
|
|
388
|
+
├── .gitignore
|
|
389
|
+
├── Dockerfile
|
|
390
|
+
└── README.md
|
|
391
|
+
\`\`\``;
|
|
392
|
+
}
|
|
393
|
+
if (language === 'website') {
|
|
394
|
+
return `\`\`\`
|
|
395
|
+
${name}/
|
|
396
|
+
├── app/ # Next.js app directory
|
|
397
|
+
│ ├── layout.tsx # Root layout
|
|
398
|
+
│ └── page.tsx # Home page
|
|
399
|
+
├── components/ # React components
|
|
400
|
+
├── public/ # Static assets
|
|
401
|
+
├── docs/ # Documentation
|
|
402
|
+
│ ├── PLAN.md # Development plan
|
|
403
|
+
│ └── WORKFLOW_LOG.md # Execution log
|
|
404
|
+
├── package.json # Dependencies and scripts
|
|
405
|
+
├── next.config.js # Next.js configuration
|
|
406
|
+
├── tsconfig.json # TypeScript configuration
|
|
407
|
+
├── .env.example # Environment template
|
|
408
|
+
├── .gitignore
|
|
409
|
+
├── Dockerfile
|
|
410
|
+
└── README.md
|
|
411
|
+
\`\`\``;
|
|
412
|
+
}
|
|
413
|
+
// Workspace (fullstack / all)
|
|
414
|
+
const websiteTree = language === 'all' ? `│ ├── website/ # Next.js marketing/landing site
|
|
415
|
+
│ │ ├── app/
|
|
416
|
+
│ │ ├── components/
|
|
417
|
+
│ │ ├── package.json
|
|
418
|
+
│ │ └── Dockerfile
|
|
419
|
+
` : '';
|
|
420
|
+
const packagesTree = language === 'all' ? `├── packages/ # Shared packages
|
|
421
|
+
│ ├── design-tokens/ # Shared design tokens
|
|
422
|
+
│ ├── ui/ # Shared UI components
|
|
423
|
+
│ └── contracts/ # API contracts (OpenAPI)
|
|
424
|
+
` : '';
|
|
425
|
+
return `\`\`\`
|
|
426
|
+
${name}/
|
|
427
|
+
├── apps/
|
|
428
|
+
│ ├── frontend/ # React/Vite frontend
|
|
429
|
+
│ │ ├── src/
|
|
430
|
+
│ │ ├── package.json
|
|
431
|
+
│ │ └── Dockerfile
|
|
432
|
+
│ ├── backend/ # Python/FastAPI backend
|
|
433
|
+
│ │ ├── src/
|
|
434
|
+
│ │ ├── tests/
|
|
435
|
+
│ │ ├── requirements.txt
|
|
436
|
+
│ │ └── Dockerfile
|
|
437
|
+
${websiteTree}${packagesTree}├── docs/ # Documentation
|
|
438
|
+
│ ├── PLAN.md # Development plan
|
|
439
|
+
│ └── WORKFLOW_LOG.md # Execution log
|
|
440
|
+
├── .popeye/ # Popeye configuration
|
|
441
|
+
│ └── workspace.json # Workspace configuration
|
|
442
|
+
├── docker-compose.yml # Local development stack
|
|
443
|
+
├── package.json # Root workspace config
|
|
444
|
+
├── .env.example # Environment template
|
|
445
|
+
├── .gitignore
|
|
446
|
+
└── README.md
|
|
447
|
+
\`\`\``;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Generate deployment section for workspace projects
|
|
451
|
+
*/
|
|
452
|
+
function generateDeploymentSection(name, language, wsConfig) {
|
|
453
|
+
const apps = wsConfig?.apps;
|
|
454
|
+
const feImage = apps?.frontend?.docker?.imageName || `${name}-frontend`;
|
|
455
|
+
const beImage = apps?.backend?.docker?.imageName || `${name}-backend`;
|
|
456
|
+
const lines = [];
|
|
457
|
+
lines.push(`Each app can be built and deployed independently as a Docker container.
|
|
192
458
|
|
|
193
|
-
|
|
459
|
+
### Build Docker Images
|
|
194
460
|
|
|
195
|
-
|
|
461
|
+
\`\`\`bash
|
|
462
|
+
# Frontend
|
|
463
|
+
docker build -t ${feImage} -f apps/frontend/Dockerfile apps/frontend
|
|
196
464
|
|
|
197
|
-
|
|
465
|
+
# Backend
|
|
466
|
+
docker build -t ${beImage} -f apps/backend/Dockerfile apps/backend`);
|
|
467
|
+
if (language === 'all') {
|
|
468
|
+
const webImage = apps?.website?.docker?.imageName || `${name}-website`;
|
|
469
|
+
lines.push(`
|
|
470
|
+
# Website
|
|
471
|
+
docker build -t ${webImage} -f apps/website/Dockerfile apps/website`);
|
|
472
|
+
}
|
|
473
|
+
lines.push('```');
|
|
474
|
+
lines.push(`
|
|
475
|
+
### Deploy with Docker Compose
|
|
198
476
|
|
|
199
|
-
|
|
477
|
+
\`\`\`bash
|
|
478
|
+
# Start all services
|
|
479
|
+
docker-compose up -d
|
|
200
480
|
|
|
201
|
-
|
|
481
|
+
# View logs
|
|
482
|
+
docker-compose logs -f
|
|
202
483
|
|
|
203
|
-
|
|
484
|
+
# Stop all services
|
|
485
|
+
docker-compose down
|
|
486
|
+
\`\`\``);
|
|
487
|
+
lines.push(`
|
|
488
|
+
### Individual App Deployment
|
|
204
489
|
|
|
205
|
-
|
|
490
|
+
#### Frontend (Static Site)
|
|
491
|
+
The frontend builds to static files that can be served by any CDN or static hosting:
|
|
492
|
+
\`\`\`bash
|
|
493
|
+
cd apps/frontend
|
|
494
|
+
npm run build
|
|
495
|
+
# Deploy the dist/ folder to your hosting provider (Vercel, Netlify, S3, etc.)
|
|
496
|
+
\`\`\`
|
|
206
497
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
498
|
+
#### Backend (API Server)
|
|
499
|
+
The backend runs as a Python ASGI server:
|
|
500
|
+
\`\`\`bash
|
|
501
|
+
cd apps/backend
|
|
502
|
+
pip install -r requirements.txt
|
|
503
|
+
uvicorn src.backend.main:app --host 0.0.0.0 --port 8000
|
|
504
|
+
\`\`\``);
|
|
505
|
+
if (language === 'all') {
|
|
506
|
+
lines.push(`
|
|
507
|
+
#### Website (Next.js SSR/SSG)
|
|
508
|
+
The website can be deployed as a Node.js server or exported as static files:
|
|
509
|
+
\`\`\`bash
|
|
510
|
+
cd apps/website
|
|
511
|
+
npm run build
|
|
512
|
+
npm start # Run as Node.js server
|
|
513
|
+
# Or deploy to Vercel/Netlify for automatic SSR support
|
|
514
|
+
\`\`\``);
|
|
211
515
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
516
|
+
return lines.join('\n');
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Validate that the generated README contains required sections for the project type.
|
|
520
|
+
*
|
|
521
|
+
* Critical sections block completion; recommended sections produce warnings.
|
|
522
|
+
*
|
|
523
|
+
* @param projectDir - Project root directory
|
|
524
|
+
* @param language - Project language type
|
|
525
|
+
* @returns Validation result with lists of missing sections
|
|
526
|
+
*/
|
|
527
|
+
async function validateReadme(projectDir, language) {
|
|
528
|
+
const missingCritical = [];
|
|
529
|
+
const missingRecommended = [];
|
|
530
|
+
let content;
|
|
531
|
+
try {
|
|
532
|
+
content = await fs.readFile(path.join(projectDir, 'README.md'), 'utf-8');
|
|
217
533
|
}
|
|
534
|
+
catch {
|
|
535
|
+
return { valid: false, missingCritical: ['README.md file not found'], missingRecommended: [] };
|
|
536
|
+
}
|
|
537
|
+
const contentLower = content.toLowerCase();
|
|
538
|
+
// Sections required for ALL project types
|
|
539
|
+
const universalRequired = [
|
|
540
|
+
{ label: 'Installation', patterns: ['## installation'] },
|
|
541
|
+
{ label: 'Running the Application', patterns: ['## running', 'development mode'] },
|
|
542
|
+
{ label: 'Project Structure', patterns: ['## project structure'] },
|
|
543
|
+
{ label: 'Environment Setup', patterns: ['## environment', '.env'] },
|
|
544
|
+
];
|
|
545
|
+
for (const section of universalRequired) {
|
|
546
|
+
if (!section.patterns.some(p => contentLower.includes(p))) {
|
|
547
|
+
missingCritical.push(section.label);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// Check for build/test commands
|
|
551
|
+
if (!contentLower.includes('npm run build') && !contentLower.includes('pip install') && !contentLower.includes('py_compile')) {
|
|
552
|
+
missingCritical.push('Build command');
|
|
553
|
+
}
|
|
554
|
+
if (!contentLower.includes('npm test') && !contentLower.includes('pytest')) {
|
|
555
|
+
missingRecommended.push('Test command');
|
|
556
|
+
}
|
|
557
|
+
// Workspace-specific checks (fullstack, all)
|
|
558
|
+
if (isWorkspace(language)) {
|
|
559
|
+
// Must have per-app sections
|
|
560
|
+
if (!contentLower.includes('frontend') || !contentLower.includes('backend')) {
|
|
561
|
+
missingCritical.push('Per-app instructions (frontend/backend)');
|
|
562
|
+
}
|
|
563
|
+
// Must have deployment section
|
|
564
|
+
if (!contentLower.includes('## deployment') && !contentLower.includes('### deploy')) {
|
|
565
|
+
missingCritical.push('Deployment section');
|
|
566
|
+
}
|
|
567
|
+
// Must mention docker
|
|
568
|
+
if (!contentLower.includes('docker')) {
|
|
569
|
+
missingCritical.push('Docker instructions');
|
|
570
|
+
}
|
|
571
|
+
// 'all' projects must mention website
|
|
572
|
+
if (language === 'all') {
|
|
573
|
+
if (!contentLower.includes('website') && !contentLower.includes('next.js')) {
|
|
574
|
+
missingCritical.push('Website app instructions');
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
// Website-specific
|
|
579
|
+
if (language === 'website') {
|
|
580
|
+
if (!contentLower.includes('next.js') && !contentLower.includes('next')) {
|
|
581
|
+
missingRecommended.push('Next.js reference');
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
// Python-specific
|
|
585
|
+
if (language === 'python') {
|
|
586
|
+
if (!contentLower.includes('pip install') && !contentLower.includes('requirements.txt')) {
|
|
587
|
+
missingCritical.push('Python dependency installation');
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
valid: missingCritical.length === 0,
|
|
592
|
+
missingCritical,
|
|
593
|
+
missingRecommended,
|
|
594
|
+
};
|
|
218
595
|
}
|
|
219
596
|
/**
|
|
220
597
|
* Extract a brief description from the specification
|
|
@@ -979,6 +1356,36 @@ ${buildResult.structuralIssue ? buildErrors.slice(0, 1500) : buildErrors.slice(0
|
|
|
979
1356
|
error: readmeResult.error,
|
|
980
1357
|
});
|
|
981
1358
|
}
|
|
1359
|
+
// ============================================
|
|
1360
|
+
// VALIDATE README COMPLETENESS
|
|
1361
|
+
// ============================================
|
|
1362
|
+
onProgress?.('readme', 'Validating README completeness...');
|
|
1363
|
+
let readmeValidation = await validateReadme(projectDir, state.language);
|
|
1364
|
+
if (!readmeValidation.valid) {
|
|
1365
|
+
onProgress?.('readme-warning', `README missing critical sections: ${readmeValidation.missingCritical.join(', ')}`);
|
|
1366
|
+
// Re-generate and retry once
|
|
1367
|
+
onProgress?.('readme', 'Re-generating README to include missing sections...');
|
|
1368
|
+
await generateProjectReadme(projectDir, state);
|
|
1369
|
+
readmeValidation = await validateReadme(projectDir, state.language);
|
|
1370
|
+
if (!readmeValidation.valid) {
|
|
1371
|
+
onProgress?.('readme-warning', `README still missing after re-generation: ${readmeValidation.missingCritical.join(', ')}`);
|
|
1372
|
+
await logger.warn('completion', 'readme_incomplete', 'README is missing critical sections', {
|
|
1373
|
+
missing: readmeValidation.missingCritical,
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
else {
|
|
1377
|
+
onProgress?.('readme', 'README validated successfully after re-generation');
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
else {
|
|
1381
|
+
onProgress?.('readme', 'README validated successfully');
|
|
1382
|
+
}
|
|
1383
|
+
// Log recommended (non-blocking) warnings
|
|
1384
|
+
if (readmeValidation.missingRecommended.length > 0) {
|
|
1385
|
+
for (const rec of readmeValidation.missingRecommended) {
|
|
1386
|
+
onProgress?.('readme-info', `README recommendation: add ${rec}`);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
982
1389
|
// All milestones complete
|
|
983
1390
|
state = await completeProject(projectDir);
|
|
984
1391
|
onProgress?.('execution-complete', `Project complete! ${completedMilestones} milestones, ${completedTasks} tasks executed successfully.`);
|