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":"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"}
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
- // Determine run commands based on language
106
- const isTypeScript = state.language === 'typescript';
107
- const installCmd = isTypeScript ? 'npm install' : 'pip install -r requirements.txt';
108
- const devCmd = isTypeScript ? 'npm run dev' : 'python src/main.py';
109
- const testCmd = isTypeScript ? 'npm test' : 'pytest tests/ -v';
110
- const buildCmd = isTypeScript ? 'npm run build' : 'python -m py_compile src/**/*.py';
111
- // Build README content
112
- const readmeContent = `# ${state.name}
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
- ${state.specification ? extractDescriptionFromSpec(state.specification) : 'A project generated by Popeye CLI.'}
135
+ 1. Copy the example environment file:
136
+ \`\`\`bash
137
+ cp .env.example .env
138
+ \`\`\`
115
139
 
116
- ## Features
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
- ${features.map(f => `### ${f.name}
119
- ${f.description || ''}
120
- ${f.tasks.length > 0 ? f.tasks.map(t => `- ${t}`).join('\n') : ''}`).join('\n\n')}
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
- ## Prerequisites
228
+ \`\`\`bash
229
+ python src/main.py
230
+ \`\`\`
231
+
232
+ ### Running Tests
123
233
 
124
- ${isTypeScript ? `- Node.js 18.0 or higher
125
- - npm 8.0 or higher` : `- Python 3.9 or higher
126
- - pip (Python package manager)`}
234
+ \`\`\`bash
235
+ pytest tests/ -v
236
+ \`\`\`
127
237
 
128
- ## Installation
238
+ ### Build for Production
129
239
 
130
240
  \`\`\`bash
131
- # Clone the repository (if applicable)
132
- cd ${state.name}
241
+ python -m py_compile src/**/*.py
242
+ \`\`\``;
243
+ }
244
+ if (language === 'typescript') {
245
+ return `### Development Mode
133
246
 
134
- # Install dependencies
135
- ${installCmd}
247
+ \`\`\`bash
248
+ npm run dev
136
249
  \`\`\`
137
250
 
138
- ## Environment Setup
251
+ ### Running Tests
139
252
 
140
- 1. Copy the example environment file:
141
- \`\`\`bash
142
- cp .env.example .env
143
- \`\`\`
253
+ \`\`\`bash
254
+ npm test
255
+ \`\`\`
256
+
257
+ ### Build for Production
144
258
 
145
- 2. Edit \`.env\` and fill in the required values.
259
+ \`\`\`bash
260
+ npm run build
261
+ \`\`\`
146
262
 
147
- ## Running the Application
263
+ ### Start Production Server
148
264
 
149
- ### Development Mode
265
+ \`\`\`bash
266
+ npm start
267
+ \`\`\``;
268
+ }
269
+ if (language === 'website') {
270
+ return `### Development Mode
150
271
 
151
272
  \`\`\`bash
152
- ${devCmd}
273
+ npm run dev
153
274
  \`\`\`
154
275
 
155
276
  ### Running Tests
156
277
 
157
278
  \`\`\`bash
158
- ${testCmd}
279
+ npm test
159
280
  \`\`\`
160
281
 
161
282
  ### Build for Production
162
283
 
163
284
  \`\`\`bash
164
- ${buildCmd}
285
+ npm run build
165
286
  \`\`\`
166
287
 
167
- ${isTypeScript ? `### Start Production Server
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
- ${state.name}/
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
- ${isTypeScript ? `│ └── index.ts # Main entry point` : `│ ├── __init__.py
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
- ${isTypeScript ? `├── package.json # Dependencies and scripts
185
- ├── tsconfig.json # TypeScript configuration` : `├── requirements.txt # Python dependencies
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
- ## Development
459
+ ### Build Docker Images
194
460
 
195
- This project was generated using [Popeye CLI](https://github.com/your-org/popeye-cli), an autonomous code generation tool.
461
+ \`\`\`bash
462
+ # Frontend
463
+ docker build -t ${feImage} -f apps/frontend/Dockerfile apps/frontend
196
464
 
197
- ### Development Plan
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
- See [docs/PLAN.md](docs/PLAN.md) for the complete development plan used to build this project.
477
+ \`\`\`bash
478
+ # Start all services
479
+ docker-compose up -d
200
480
 
201
- ### Workflow Log
481
+ # View logs
482
+ docker-compose logs -f
202
483
 
203
- See [docs/WORKFLOW_LOG.md](docs/WORKFLOW_LOG.md) for detailed execution logs.
484
+ # Stop all services
485
+ docker-compose down
486
+ \`\`\``);
487
+ lines.push(`
488
+ ### Individual App Deployment
204
489
 
205
- ## License
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
- MIT
208
- `;
209
- await fs.writeFile(readmePath, readmeContent, 'utf-8');
210
- return { success: true, path: readmePath };
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
- catch (error) {
213
- return {
214
- success: false,
215
- error: error instanceof Error ? error.message : 'Failed to generate README',
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.`);