popeye-cli 1.0.1 → 1.1.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.
Files changed (166) hide show
  1. package/README.md +521 -125
  2. package/dist/adapters/claude.d.ts +16 -4
  3. package/dist/adapters/claude.d.ts.map +1 -1
  4. package/dist/adapters/claude.js +679 -33
  5. package/dist/adapters/claude.js.map +1 -1
  6. package/dist/adapters/gemini.d.ts +55 -0
  7. package/dist/adapters/gemini.d.ts.map +1 -0
  8. package/dist/adapters/gemini.js +318 -0
  9. package/dist/adapters/gemini.js.map +1 -0
  10. package/dist/adapters/openai.d.ts.map +1 -1
  11. package/dist/adapters/openai.js +41 -7
  12. package/dist/adapters/openai.js.map +1 -1
  13. package/dist/auth/claude.d.ts +11 -9
  14. package/dist/auth/claude.d.ts.map +1 -1
  15. package/dist/auth/claude.js +107 -71
  16. package/dist/auth/claude.js.map +1 -1
  17. package/dist/auth/gemini.d.ts +58 -0
  18. package/dist/auth/gemini.d.ts.map +1 -0
  19. package/dist/auth/gemini.js +172 -0
  20. package/dist/auth/gemini.js.map +1 -0
  21. package/dist/auth/index.d.ts +11 -7
  22. package/dist/auth/index.d.ts.map +1 -1
  23. package/dist/auth/index.js +23 -5
  24. package/dist/auth/index.js.map +1 -1
  25. package/dist/auth/keychain.d.ts +20 -7
  26. package/dist/auth/keychain.d.ts.map +1 -1
  27. package/dist/auth/keychain.js +85 -29
  28. package/dist/auth/keychain.js.map +1 -1
  29. package/dist/auth/openai.d.ts +2 -2
  30. package/dist/auth/openai.d.ts.map +1 -1
  31. package/dist/auth/openai.js +30 -32
  32. package/dist/auth/openai.js.map +1 -1
  33. package/dist/cli/interactive.d.ts.map +1 -1
  34. package/dist/cli/interactive.js +1151 -110
  35. package/dist/cli/interactive.js.map +1 -1
  36. package/dist/config/defaults.d.ts +6 -1
  37. package/dist/config/defaults.d.ts.map +1 -1
  38. package/dist/config/defaults.js +10 -2
  39. package/dist/config/defaults.js.map +1 -1
  40. package/dist/config/index.d.ts +10 -0
  41. package/dist/config/index.d.ts.map +1 -1
  42. package/dist/config/index.js +19 -0
  43. package/dist/config/index.js.map +1 -1
  44. package/dist/config/schema.d.ts +20 -0
  45. package/dist/config/schema.d.ts.map +1 -1
  46. package/dist/config/schema.js +7 -0
  47. package/dist/config/schema.js.map +1 -1
  48. package/dist/generators/python.d.ts.map +1 -1
  49. package/dist/generators/python.js +1 -0
  50. package/dist/generators/python.js.map +1 -1
  51. package/dist/generators/typescript.d.ts.map +1 -1
  52. package/dist/generators/typescript.js +1 -0
  53. package/dist/generators/typescript.js.map +1 -1
  54. package/dist/state/index.d.ts +108 -0
  55. package/dist/state/index.d.ts.map +1 -1
  56. package/dist/state/index.js +551 -4
  57. package/dist/state/index.js.map +1 -1
  58. package/dist/state/registry.d.ts +52 -0
  59. package/dist/state/registry.d.ts.map +1 -0
  60. package/dist/state/registry.js +215 -0
  61. package/dist/state/registry.js.map +1 -0
  62. package/dist/types/cli.d.ts +4 -0
  63. package/dist/types/cli.d.ts.map +1 -1
  64. package/dist/types/cli.js.map +1 -1
  65. package/dist/types/consensus.d.ts +69 -4
  66. package/dist/types/consensus.d.ts.map +1 -1
  67. package/dist/types/consensus.js +24 -3
  68. package/dist/types/consensus.js.map +1 -1
  69. package/dist/types/workflow.d.ts +55 -0
  70. package/dist/types/workflow.d.ts.map +1 -1
  71. package/dist/types/workflow.js +16 -0
  72. package/dist/types/workflow.js.map +1 -1
  73. package/dist/workflow/auto-fix.d.ts +45 -0
  74. package/dist/workflow/auto-fix.d.ts.map +1 -0
  75. package/dist/workflow/auto-fix.js +274 -0
  76. package/dist/workflow/auto-fix.js.map +1 -0
  77. package/dist/workflow/consensus.d.ts +44 -2
  78. package/dist/workflow/consensus.d.ts.map +1 -1
  79. package/dist/workflow/consensus.js +565 -17
  80. package/dist/workflow/consensus.js.map +1 -1
  81. package/dist/workflow/execution-mode.d.ts +10 -4
  82. package/dist/workflow/execution-mode.d.ts.map +1 -1
  83. package/dist/workflow/execution-mode.js +547 -58
  84. package/dist/workflow/execution-mode.js.map +1 -1
  85. package/dist/workflow/index.d.ts +14 -2
  86. package/dist/workflow/index.d.ts.map +1 -1
  87. package/dist/workflow/index.js +69 -6
  88. package/dist/workflow/index.js.map +1 -1
  89. package/dist/workflow/milestone-workflow.d.ts +34 -0
  90. package/dist/workflow/milestone-workflow.d.ts.map +1 -0
  91. package/dist/workflow/milestone-workflow.js +414 -0
  92. package/dist/workflow/milestone-workflow.js.map +1 -0
  93. package/dist/workflow/plan-mode.d.ts +14 -1
  94. package/dist/workflow/plan-mode.d.ts.map +1 -1
  95. package/dist/workflow/plan-mode.js +589 -47
  96. package/dist/workflow/plan-mode.js.map +1 -1
  97. package/dist/workflow/plan-storage.d.ts +142 -0
  98. package/dist/workflow/plan-storage.d.ts.map +1 -0
  99. package/dist/workflow/plan-storage.js +331 -0
  100. package/dist/workflow/plan-storage.js.map +1 -0
  101. package/dist/workflow/project-verification.d.ts +37 -0
  102. package/dist/workflow/project-verification.d.ts.map +1 -0
  103. package/dist/workflow/project-verification.js +381 -0
  104. package/dist/workflow/project-verification.js.map +1 -0
  105. package/dist/workflow/task-workflow.d.ts +37 -0
  106. package/dist/workflow/task-workflow.d.ts.map +1 -0
  107. package/dist/workflow/task-workflow.js +383 -0
  108. package/dist/workflow/task-workflow.js.map +1 -0
  109. package/dist/workflow/test-runner.d.ts +1 -0
  110. package/dist/workflow/test-runner.d.ts.map +1 -1
  111. package/dist/workflow/test-runner.js +9 -5
  112. package/dist/workflow/test-runner.js.map +1 -1
  113. package/dist/workflow/ui-designer.d.ts +82 -0
  114. package/dist/workflow/ui-designer.d.ts.map +1 -0
  115. package/dist/workflow/ui-designer.js +234 -0
  116. package/dist/workflow/ui-designer.js.map +1 -0
  117. package/dist/workflow/ui-setup.d.ts +58 -0
  118. package/dist/workflow/ui-setup.d.ts.map +1 -0
  119. package/dist/workflow/ui-setup.js +685 -0
  120. package/dist/workflow/ui-setup.js.map +1 -0
  121. package/dist/workflow/ui-verification.d.ts +114 -0
  122. package/dist/workflow/ui-verification.d.ts.map +1 -0
  123. package/dist/workflow/ui-verification.js +258 -0
  124. package/dist/workflow/ui-verification.js.map +1 -0
  125. package/dist/workflow/workflow-logger.d.ts +110 -0
  126. package/dist/workflow/workflow-logger.d.ts.map +1 -0
  127. package/dist/workflow/workflow-logger.js +267 -0
  128. package/dist/workflow/workflow-logger.js.map +1 -0
  129. package/package.json +2 -2
  130. package/src/adapters/claude.ts +815 -34
  131. package/src/adapters/gemini.ts +373 -0
  132. package/src/adapters/openai.ts +40 -7
  133. package/src/auth/claude.ts +120 -78
  134. package/src/auth/gemini.ts +207 -0
  135. package/src/auth/index.ts +28 -8
  136. package/src/auth/keychain.ts +95 -28
  137. package/src/auth/openai.ts +29 -36
  138. package/src/cli/interactive.ts +1357 -115
  139. package/src/config/defaults.ts +10 -2
  140. package/src/config/index.ts +21 -0
  141. package/src/config/schema.ts +7 -0
  142. package/src/generators/python.ts +1 -0
  143. package/src/generators/typescript.ts +1 -0
  144. package/src/state/index.ts +713 -4
  145. package/src/state/registry.ts +278 -0
  146. package/src/types/cli.ts +4 -0
  147. package/src/types/consensus.ts +65 -6
  148. package/src/types/workflow.ts +35 -0
  149. package/src/workflow/auto-fix.ts +340 -0
  150. package/src/workflow/consensus.ts +750 -16
  151. package/src/workflow/execution-mode.ts +673 -74
  152. package/src/workflow/index.ts +95 -6
  153. package/src/workflow/milestone-workflow.ts +576 -0
  154. package/src/workflow/plan-mode.ts +696 -50
  155. package/src/workflow/plan-storage.ts +482 -0
  156. package/src/workflow/project-verification.ts +471 -0
  157. package/src/workflow/task-workflow.ts +525 -0
  158. package/src/workflow/test-runner.ts +10 -5
  159. package/src/workflow/ui-designer.ts +337 -0
  160. package/src/workflow/ui-setup.ts +797 -0
  161. package/src/workflow/ui-verification.ts +357 -0
  162. package/src/workflow/workflow-logger.ts +353 -0
  163. package/tests/config/config.test.ts +1 -1
  164. package/tests/types/consensus.test.ts +3 -3
  165. package/tests/workflow/plan-mode.test.ts +213 -0
  166. package/tests/workflow/test-runner.test.ts +5 -3
@@ -1,20 +1,21 @@
1
1
  /**
2
2
  * Execution Mode workflow
3
- * Handles task execution, testing, and error recovery
3
+ * Handles task execution with hierarchical consensus:
4
+ * Milestone Plan → Consensus → (Task Plan → Consensus → Implement → Test) → Milestone Review
4
5
  */
5
6
 
7
+ import { promises as fs } from 'node:fs';
8
+ import path from 'node:path';
6
9
  import type { ProjectState, Task, Milestone } from '../types/workflow.js';
10
+ import type { ConsensusConfig } from '../types/consensus.js';
7
11
  import { generateCode, type ClaudeExecuteResult } from '../adapters/claude.js';
8
12
  import {
9
13
  loadProject,
10
14
  updateState,
11
- updateTaskStatus,
12
15
  setCurrentMilestone,
13
- setCurrentTask,
14
- getNextTask,
15
- getProgress,
16
16
  completeProject,
17
- failProject,
17
+ verifyProjectCompletion,
18
+ comprehensiveProjectVerification,
18
19
  } from '../state/index.js';
19
20
  import {
20
21
  runTests,
@@ -22,6 +23,11 @@ import {
22
23
  getTestSummary,
23
24
  type TestResult,
24
25
  } from './test-runner.js';
26
+ import { getWorkflowLogger } from './workflow-logger.js';
27
+ import { buildWithAutoFix } from './auto-fix.js';
28
+ import { runComprehensiveVerification, autoFixIssues } from './project-verification.js';
29
+ import { setupUI } from './ui-setup.js';
30
+ import { designUI, saveUISpecification, loadUISpecification } from './ui-designer.js';
25
31
 
26
32
  /**
27
33
  * Options for execution mode
@@ -29,6 +35,7 @@ import {
29
35
  export interface ExecutionModeOptions {
30
36
  projectDir: string;
31
37
  maxRetries?: number;
38
+ consensusConfig?: Partial<ConsensusConfig>; // For per-task and per-milestone consensus
32
39
  onProgress?: (phase: string, message: string) => void;
33
40
  onTaskStart?: (milestone: Milestone, task: Task) => void;
34
41
  onTaskComplete?: (milestone: Milestone, task: Task, success: boolean) => void;
@@ -63,6 +70,177 @@ export interface ExecutionModeResult {
63
70
  */
64
71
  const DEFAULT_MAX_RETRIES = 3;
65
72
 
73
+ /**
74
+ * Generate a comprehensive README.md for the completed project
75
+ * This provides users with setup and run instructions
76
+ *
77
+ * @param projectDir - Project directory
78
+ * @param state - Project state
79
+ * @returns Path to generated README or error
80
+ */
81
+ async function generateProjectReadme(
82
+ projectDir: string,
83
+ state: ProjectState
84
+ ): Promise<{ success: boolean; path?: string; error?: string }> {
85
+ try {
86
+ const readmePath = path.join(projectDir, 'README.md');
87
+
88
+ // Extract features from completed milestones
89
+ const features = state.milestones
90
+ .filter(m => m.status === 'complete')
91
+ .map(m => ({
92
+ name: m.name,
93
+ description: m.description,
94
+ tasks: m.tasks.filter(t => t.status === 'complete').map(t => t.name),
95
+ }));
96
+
97
+ // Determine run commands based on language
98
+ const isTypeScript = state.language === 'typescript';
99
+ const installCmd = isTypeScript ? 'npm install' : 'pip install -r requirements.txt';
100
+ const devCmd = isTypeScript ? 'npm run dev' : 'python src/main.py';
101
+ const testCmd = isTypeScript ? 'npm test' : 'pytest tests/ -v';
102
+ const buildCmd = isTypeScript ? 'npm run build' : 'python -m py_compile src/**/*.py';
103
+
104
+ // Build README content
105
+ const readmeContent = `# ${state.name}
106
+
107
+ ${state.specification ? extractDescriptionFromSpec(state.specification) : 'A project generated by Popeye CLI.'}
108
+
109
+ ## Features
110
+
111
+ ${features.map(f => `### ${f.name}
112
+ ${f.description || ''}
113
+ ${f.tasks.length > 0 ? f.tasks.map(t => `- ${t}`).join('\n') : ''}`).join('\n\n')}
114
+
115
+ ## Prerequisites
116
+
117
+ ${isTypeScript ? `- Node.js 18.0 or higher
118
+ - npm 8.0 or higher` : `- Python 3.9 or higher
119
+ - pip (Python package manager)`}
120
+
121
+ ## Installation
122
+
123
+ \`\`\`bash
124
+ # Clone the repository (if applicable)
125
+ cd ${state.name}
126
+
127
+ # Install dependencies
128
+ ${installCmd}
129
+ \`\`\`
130
+
131
+ ## Environment Setup
132
+
133
+ 1. Copy the example environment file:
134
+ \`\`\`bash
135
+ cp .env.example .env
136
+ \`\`\`
137
+
138
+ 2. Edit \`.env\` and fill in the required values.
139
+
140
+ ## Running the Application
141
+
142
+ ### Development Mode
143
+
144
+ \`\`\`bash
145
+ ${devCmd}
146
+ \`\`\`
147
+
148
+ ### Running Tests
149
+
150
+ \`\`\`bash
151
+ ${testCmd}
152
+ \`\`\`
153
+
154
+ ### Build for Production
155
+
156
+ \`\`\`bash
157
+ ${buildCmd}
158
+ \`\`\`
159
+
160
+ ${isTypeScript ? `### Start Production Server
161
+
162
+ \`\`\`bash
163
+ npm start
164
+ \`\`\`
165
+ ` : ''}
166
+ ## Project Structure
167
+
168
+ \`\`\`
169
+ ${state.name}/
170
+ ├── src/ # Source code
171
+ ${isTypeScript ? `│ └── index.ts # Main entry point` : `│ ├── __init__.py
172
+ │ └── main.py # Main entry point`}
173
+ ├── tests/ # Test files
174
+ ├── docs/ # Documentation
175
+ │ ├── PLAN.md # Development plan
176
+ │ └── WORKFLOW_LOG.md # Execution log
177
+ ${isTypeScript ? `├── package.json # Dependencies and scripts
178
+ ├── tsconfig.json # TypeScript configuration` : `├── requirements.txt # Python dependencies
179
+ ├── pyproject.toml # Project configuration`}
180
+ ├── .env.example # Environment template
181
+ ├── .gitignore
182
+ ├── Dockerfile
183
+ └── README.md
184
+ \`\`\`
185
+
186
+ ## Development
187
+
188
+ This project was generated using [Popeye CLI](https://github.com/your-org/popeye-cli), an autonomous code generation tool.
189
+
190
+ ### Development Plan
191
+
192
+ See [docs/PLAN.md](docs/PLAN.md) for the complete development plan used to build this project.
193
+
194
+ ### Workflow Log
195
+
196
+ See [docs/WORKFLOW_LOG.md](docs/WORKFLOW_LOG.md) for detailed execution logs.
197
+
198
+ ## License
199
+
200
+ MIT
201
+ `;
202
+
203
+ await fs.writeFile(readmePath, readmeContent, 'utf-8');
204
+
205
+ return { success: true, path: readmePath };
206
+ } catch (error) {
207
+ return {
208
+ success: false,
209
+ error: error instanceof Error ? error.message : 'Failed to generate README',
210
+ };
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Extract a brief description from the specification
216
+ *
217
+ * @param spec - Full specification text
218
+ * @returns Brief description (first paragraph or summary)
219
+ */
220
+ function extractDescriptionFromSpec(spec: string): string {
221
+ // Try to find a summary section
222
+ const summaryMatch = spec.match(/(?:##?\s*(?:Summary|Overview|Description)[\s\S]*?\n)([\s\S]*?)(?:\n##|\n\n##|$)/i);
223
+ if (summaryMatch) {
224
+ const summary = summaryMatch[1].trim();
225
+ if (summary.length > 0 && summary.length < 500) {
226
+ return summary;
227
+ }
228
+ }
229
+
230
+ // Fall back to first paragraph
231
+ const lines = spec.split('\n').filter(line => line.trim() && !line.startsWith('#'));
232
+ const firstParagraph = lines.slice(0, 3).join(' ').trim();
233
+
234
+ if (firstParagraph.length > 500) {
235
+ return firstParagraph.slice(0, 497) + '...';
236
+ }
237
+
238
+ return firstParagraph || 'A project generated by Popeye CLI.';
239
+ }
240
+
241
+ // Note: runCommand and runFinalBuildVerification replaced by buildWithAutoFix from auto-fix.ts
242
+ // which provides automatic error fixing capabilities
243
+
66
244
  /**
67
245
  * Build the execution context for a task
68
246
  *
@@ -74,7 +252,8 @@ const DEFAULT_MAX_RETRIES = 3;
74
252
  function buildTaskContext(
75
253
  state: ProjectState,
76
254
  milestone: Milestone,
77
- _task: Task
255
+ _task: Task,
256
+ uiDesignContext?: string
78
257
  ): string {
79
258
  const lines: string[] = [];
80
259
 
@@ -94,6 +273,12 @@ function buildTaskContext(
94
273
  lines.push('');
95
274
  }
96
275
 
276
+ // Include UI design context if available
277
+ if (uiDesignContext) {
278
+ lines.push(uiDesignContext);
279
+ lines.push('');
280
+ }
281
+
97
282
  lines.push('## Current Milestone');
98
283
  lines.push(`Name: ${milestone.name}`);
99
284
  lines.push(`Description: ${milestone.description}`);
@@ -118,12 +303,14 @@ function buildTaskContext(
118
303
  * @param task - The task to execute
119
304
  * @param context - Execution context
120
305
  * @param projectDir - Project directory
306
+ * @param onProgress - Progress callback for Claude activity
121
307
  * @returns Execution result
122
308
  */
123
309
  export async function executeTask(
124
310
  task: Task,
125
311
  context: string,
126
- projectDir: string
312
+ projectDir: string,
313
+ onProgress?: (message: string) => void
127
314
  ): Promise<ClaudeExecuteResult> {
128
315
  const prompt = `
129
316
  ## Task
@@ -140,7 +327,7 @@ Please implement this task completely. After implementing:
140
327
  3. Document any complex logic
141
328
  `.trim();
142
329
 
143
- return generateCode(prompt, context, { cwd: projectDir });
330
+ return generateCode(prompt, context, { cwd: projectDir, onProgress });
144
331
  }
145
332
 
146
333
  /**
@@ -150,13 +337,15 @@ Please implement this task completely. After implementing:
150
337
  * @param testResult - The test result
151
338
  * @param context - Execution context
152
339
  * @param projectDir - Project directory
340
+ * @param onProgress - Progress callback for Claude activity
153
341
  * @returns Fix attempt result
154
342
  */
155
343
  export async function handleTestFailure(
156
344
  task: Task,
157
345
  testResult: TestResult,
158
346
  context: string,
159
- projectDir: string
347
+ projectDir: string,
348
+ onProgress?: (message: string) => void
160
349
  ): Promise<ClaudeExecuteResult> {
161
350
  const prompt = `
162
351
  ## Test Failure Fix Required
@@ -180,7 +369,7 @@ Please:
180
369
  3. Do NOT modify the tests unless they are incorrect
181
370
  `.trim();
182
371
 
183
- return generateCode(prompt, context, { cwd: projectDir });
372
+ return generateCode(prompt, context, { cwd: projectDir, onProgress });
184
373
  }
185
374
 
186
375
  /**
@@ -202,13 +391,31 @@ async function executeTaskWithRetry(
202
391
  projectDir,
203
392
  maxRetries = DEFAULT_MAX_RETRIES,
204
393
  onTestResult,
394
+ onProgress,
205
395
  } = options;
206
396
 
207
- const context = buildTaskContext(state, milestone, task);
397
+ // Load UI design context if available
398
+ let uiDesignContext: string | undefined;
399
+ try {
400
+ const uiSpec = await loadUISpecification(projectDir);
401
+ if (uiSpec) {
402
+ const { generateDesignSystemPrompt } = await import('./ui-designer.js');
403
+ uiDesignContext = generateDesignSystemPrompt(uiSpec);
404
+ }
405
+ } catch {
406
+ // UI spec not available, continue without it
407
+ }
408
+
409
+ const context = buildTaskContext(state, milestone, task, uiDesignContext);
208
410
  let retries = 0;
209
411
 
412
+ // Create a progress handler that prefixes messages with [claude]
413
+ const claudeProgress = onProgress
414
+ ? (msg: string) => onProgress('claude', msg)
415
+ : undefined;
416
+
210
417
  // Execute the task
211
- const execResult = await executeTask(task, context, projectDir);
418
+ const execResult = await executeTask(task, context, projectDir, claudeProgress);
212
419
 
213
420
  if (!execResult.success) {
214
421
  return {
@@ -287,7 +494,8 @@ async function executeTaskWithRetry(
287
494
  }
288
495
 
289
496
  /**
290
- * Run execution mode for a project
497
+ * Run execution mode for a project using hierarchical consensus workflow
498
+ * Each milestone and task goes through: Plan → Consensus → Implement → Test → Review
291
499
  *
292
500
  * @param options - Execution options
293
501
  * @returns Execution mode result
@@ -302,12 +510,23 @@ export async function runExecutionMode(
302
510
  onTaskComplete,
303
511
  } = options;
304
512
 
513
+ // Initialize workflow logger
514
+ const logger = getWorkflowLogger(projectDir);
515
+
305
516
  let completedTasks = 0;
306
517
  let failedTasks = 0;
518
+ let completedMilestones = 0;
307
519
 
308
520
  try {
309
521
  let state = await loadProject(projectDir);
310
522
 
523
+ await logger.stageStart('execution', 'Execution Mode started', {
524
+ projectName: state.name,
525
+ phase: state.phase,
526
+ totalMilestones: state.milestones.length,
527
+ totalTasks: state.milestones.reduce((sum, m) => sum + m.tasks.length, 0),
528
+ });
529
+
311
530
  // Ensure we're in execution phase
312
531
  if (state.phase !== 'execution') {
313
532
  return {
@@ -322,95 +541,409 @@ export async function runExecutionMode(
322
541
  // Update status
323
542
  state = await updateState(projectDir, { status: 'in-progress' });
324
543
 
325
- onProgress?.('execution-start', 'Starting execution mode...');
544
+ onProgress?.('execution-start', 'Starting hierarchical execution mode...');
545
+ onProgress?.('execution-start', `Processing ${state.milestones.length} milestones with per-task consensus`);
326
546
 
327
- // Process tasks
328
- let nextTask = await getNextTask(projectDir);
547
+ // Import milestone workflow dynamically to avoid circular dependencies
548
+ const { runMilestoneWorkflow } = await import('./milestone-workflow.js');
329
549
 
330
- while (nextTask) {
331
- const { milestone, task } = nextTask;
550
+ // Process each milestone
551
+ for (const milestone of state.milestones) {
552
+ // Skip completed milestones
553
+ if (milestone.status === 'complete' && milestone.completionApproved) {
554
+ onProgress?.('milestone-skip', `Skipping completed milestone: ${milestone.name}`);
555
+ completedMilestones++;
556
+ completedTasks += milestone.tasks.filter(t => t.status === 'complete').length;
557
+ continue;
558
+ }
332
559
 
333
- // Set current milestone and task
560
+ // Set current milestone
334
561
  state = await setCurrentMilestone(projectDir, milestone.id);
335
- state = await setCurrentTask(projectDir, task.id);
336
-
337
- // Update task to in-progress
338
- state = await updateTaskStatus(projectDir, task.id, 'in-progress');
339
562
 
340
563
  onProgress?.(
341
- 'task-start',
342
- `Executing: ${task.name} (Milestone: ${milestone.name})`
564
+ 'milestone-start',
565
+ `Starting milestone: ${milestone.name} (${milestone.tasks.length} tasks)`
343
566
  );
344
567
 
345
- if (onTaskStart) {
346
- onTaskStart(milestone, task);
568
+ await logger.stageStart('milestone', `Starting milestone: ${milestone.name}`, {
569
+ milestoneId: milestone.id,
570
+ milestoneName: milestone.name,
571
+ taskCount: milestone.tasks.length,
572
+ taskNames: milestone.tasks.map(t => t.name),
573
+ });
574
+
575
+ // Run the complete milestone workflow
576
+ const milestoneResult = await runMilestoneWorkflow(milestone, {
577
+ projectDir,
578
+ consensusConfig: options.consensusConfig,
579
+ onProgress,
580
+ onTaskStart: (task) => {
581
+ if (onTaskStart) {
582
+ onTaskStart(milestone, task);
583
+ }
584
+ },
585
+ onTaskComplete: (task, success) => {
586
+ if (success) {
587
+ completedTasks++;
588
+ } else {
589
+ failedTasks++;
590
+ }
591
+ if (onTaskComplete) {
592
+ onTaskComplete(milestone, task, success);
593
+ }
594
+ },
595
+ });
596
+
597
+ if (milestoneResult.success) {
598
+ completedMilestones++;
599
+ onProgress?.(
600
+ 'milestone-complete',
601
+ `Milestone complete: ${milestone.name} (Score: ${milestoneResult.completionConsensus?.finalScore}%)`
602
+ );
603
+
604
+ await logger.stageComplete('milestone', `Milestone completed: ${milestone.name}`, {
605
+ milestoneId: milestone.id,
606
+ milestoneName: milestone.name,
607
+ consensusScore: milestoneResult.completionConsensus?.finalScore,
608
+ tasksCompleted: milestone.tasks.filter(t => t.status === 'complete').length,
609
+ });
610
+ } else {
611
+ onProgress?.(
612
+ 'milestone-failed',
613
+ `Milestone failed: ${milestone.name} - ${milestoneResult.error}`
614
+ );
615
+
616
+ await logger.stageFailed('milestone', `Milestone failed: ${milestone.name}`, milestoneResult.error || 'Unknown error', {
617
+ milestoneId: milestone.id,
618
+ milestoneName: milestone.name,
619
+ });
620
+
621
+ // Reload state to get latest
622
+ state = await loadProject(projectDir);
623
+
624
+ return {
625
+ success: false,
626
+ state,
627
+ completedTasks,
628
+ failedTasks,
629
+ error: `Milestone "${milestone.name}" failed: ${milestoneResult.error}`,
630
+ };
347
631
  }
632
+ }
348
633
 
349
- // Execute the task
350
- const result = await executeTaskWithRetry(
351
- milestone,
352
- task,
353
- state,
354
- options
355
- );
634
+ // ============================================
635
+ // UI SETUP PHASE
636
+ // ============================================
637
+ onProgress?.('ui-setup', 'Running UI setup and design system configuration...');
638
+ await logger.stageStart('ui-setup', 'Starting UI setup');
639
+
640
+ // Check if this is a frontend project
641
+ const frontendDir = path.join(projectDir, 'packages', 'frontend');
642
+ const hasFrontend = await fs.access(frontendDir).then(() => true).catch(() => false);
643
+
644
+ if (hasFrontend) {
645
+ try {
646
+ // Load or generate UI specification
647
+ let uiSpec = await loadUISpecification(projectDir);
648
+
649
+ if (!uiSpec && state.idea) {
650
+ onProgress?.('ui-setup', 'Designing UI from project idea...');
651
+ uiSpec = await designUI(state.idea, (msg) => onProgress?.('ui-setup', msg));
652
+ await saveUISpecification(projectDir, uiSpec);
653
+ onProgress?.('ui-setup', `UI design complete: ${uiSpec.themeName} theme selected`);
654
+ }
655
+
656
+ // Run UI setup to install components and configure styling
657
+ onProgress?.('ui-setup', 'Setting up component library and styling...');
658
+ const uiResult = await setupUI(
659
+ projectDir,
660
+ {
661
+ theme: uiSpec?.themeName || 'modern',
662
+ idea: state.idea,
663
+ },
664
+ (msg) => onProgress?.('ui-setup', msg)
665
+ );
356
666
 
357
- if (result.success) {
358
- state = await updateTaskStatus(projectDir, task.id, 'complete', {
359
- testsPassed: result.testResult?.success,
667
+ if (uiResult.success) {
668
+ onProgress?.('ui-setup', `UI setup complete: ${uiResult.componentsInstalled.length} components installed`);
669
+ await logger.success('ui-setup', 'ui_setup_complete', 'UI setup completed successfully', {
670
+ theme: uiResult.theme,
671
+ components: uiResult.componentsInstalled,
672
+ });
673
+ } else {
674
+ onProgress?.('ui-setup', `UI setup warning: ${uiResult.error}`);
675
+ await logger.warn('ui-setup', 'ui_setup_warning', 'UI setup had issues', {
676
+ error: uiResult.error,
677
+ });
678
+ }
679
+ } catch (uiError) {
680
+ // Non-blocking - UI setup failures shouldn't stop the project
681
+ onProgress?.('ui-setup', `UI setup skipped: ${uiError instanceof Error ? uiError.message : 'Unknown error'}`);
682
+ await logger.warn('ui-setup', 'ui_setup_skipped', 'UI setup was skipped', {
683
+ error: uiError instanceof Error ? uiError.message : 'Unknown error',
360
684
  });
361
- completedTasks++;
685
+ }
686
+ } else {
687
+ onProgress?.('ui-setup', 'No frontend detected, skipping UI setup');
688
+ }
362
689
 
690
+ // ============================================
691
+ // FINAL VERIFICATION PHASE
692
+ // ============================================
693
+ onProgress?.('verification', 'Running final verification...');
694
+ await logger.stageStart('verification', 'Starting final verification');
695
+
696
+ // Reload state to get latest
697
+ state = await loadProject(projectDir);
698
+
699
+ // Verify all milestones are complete
700
+ const incompleteMilestones = state.milestones.filter(m => m.status !== 'complete');
701
+ if (incompleteMilestones.length > 0) {
702
+ const incompleteNames = incompleteMilestones.map(m => m.name).join(', ');
703
+ onProgress?.(
704
+ 'verification-warning',
705
+ `Warning: ${incompleteMilestones.length} milestone(s) not marked complete: ${incompleteNames}`
706
+ );
707
+ }
708
+
709
+ // Verify all tasks are complete
710
+ const allTasks = state.milestones.flatMap(m => m.tasks);
711
+ const incompleteTasks = allTasks.filter(t => t.status !== 'complete');
712
+ if (incompleteTasks.length > 0) {
713
+ const incompleteTaskNames = incompleteTasks.slice(0, 5).map(t => t.name).join(', ');
714
+ onProgress?.(
715
+ 'verification-warning',
716
+ `Warning: ${incompleteTasks.length} task(s) not complete: ${incompleteTaskNames}${incompleteTasks.length > 5 ? '...' : ''}`
717
+ );
718
+ }
719
+
720
+ // Run final build verification with auto-fix
721
+ onProgress?.('verification', 'Running final build verification...');
722
+ const buildResult = await buildWithAutoFix(
723
+ projectDir,
724
+ state.language,
725
+ 3, // max fix attempts
726
+ (msg) => onProgress?.('verification', `[auto-fix] ${msg}`)
727
+ );
728
+
729
+ if (!buildResult.success) {
730
+ onProgress?.(
731
+ 'verification-error',
732
+ `Build verification failed${buildResult.autoFixed ? ' (after auto-fix attempts)' : ''}: Build errors remain`
733
+ );
734
+ await logger.error('verification', 'build_failed', 'Build verification failed', {
735
+ output: buildResult.output.slice(0, 2000),
736
+ autoFixed: buildResult.autoFixed,
737
+ });
738
+
739
+ // Block completion if build fails
740
+ onProgress?.(
741
+ 'verification-error',
742
+ 'BLOCKING: Cannot complete project with build errors. Please fix manually and resume.'
743
+ );
744
+
745
+ return {
746
+ success: false,
747
+ state,
748
+ completedTasks,
749
+ failedTasks,
750
+ error: 'Build verification failed - project not complete',
751
+ };
752
+ } else {
753
+ onProgress?.('verification', `Build verification passed${buildResult.autoFixed ? ' (after auto-fix)' : ''}`);
754
+ await logger.success('verification', 'build_passed', 'Build verification passed', {
755
+ autoFixed: buildResult.autoFixed,
756
+ });
757
+ }
758
+
759
+ // Run final test verification
760
+ const hasTests = await testsExist(projectDir, state.language);
761
+ if (hasTests) {
762
+ onProgress?.('verification', 'Running final test verification...');
763
+ const testResult = await runTests(projectDir, state.language);
764
+ if (!testResult.success) {
363
765
  onProgress?.(
364
- 'task-complete',
365
- `Completed: ${task.name}${result.testResult ? ` (${getTestSummary(result.testResult)})` : ''}`
766
+ 'verification-warning',
767
+ `Final test verification failed: ${testResult.failed} test(s) failed`
366
768
  );
367
- } else {
368
- state = await updateTaskStatus(projectDir, task.id, 'failed', {
369
- testsPassed: false,
370
- error: result.error,
769
+ await logger.warn('verification', 'tests_failed', 'Final test verification failed', {
770
+ passed: testResult.passed,
771
+ failed: testResult.failed,
772
+ total: testResult.total,
773
+ failedTests: testResult.failedTests,
371
774
  });
372
- failedTasks++;
373
-
775
+ } else {
374
776
  onProgress?.(
375
- 'task-failed',
376
- `Failed: ${task.name} - ${result.error}`
777
+ 'verification',
778
+ `All tests passed: ${testResult.passed}/${testResult.total}`
377
779
  );
780
+ await logger.success('verification', 'tests_passed', 'All tests passed', {
781
+ passed: testResult.passed,
782
+ total: testResult.total,
783
+ });
378
784
  }
785
+ }
786
+
787
+ // Run comprehensive code quality verification
788
+ onProgress?.('verification', 'Running code quality verification...');
789
+ const codeVerification = await comprehensiveProjectVerification(projectDir);
790
+
791
+ // Log comprehensive verification results
792
+ await logger.info('verification', 'code_quality_check', 'Code quality verification results', {
793
+ totalSourceFiles: codeVerification.codeVerification.totalSourceFiles,
794
+ totalLinesOfCode: codeVerification.codeVerification.totalLinesOfCode,
795
+ hasMainEntryPoint: codeVerification.codeVerification.hasMainEntryPoint,
796
+ hasTests: codeVerification.codeVerification.hasTests,
797
+ hasSubstantiveCode: codeVerification.codeVerification.hasSubstantiveCode,
798
+ issues: codeVerification.codeVerification.issues,
799
+ warnings: codeVerification.codeVerification.warnings,
800
+ });
379
801
 
380
- if (onTaskComplete) {
381
- onTaskComplete(milestone, task, result.success);
802
+ // Display code quality results
803
+ onProgress?.(
804
+ 'verification',
805
+ `Code: ${codeVerification.codeVerification.totalSourceFiles} files, ` +
806
+ `${codeVerification.codeVerification.totalLinesOfCode} lines of code`
807
+ );
808
+
809
+ if (codeVerification.codeVerification.issues.length > 0) {
810
+ for (const issue of codeVerification.codeVerification.issues) {
811
+ onProgress?.('verification-warning', `Code Issue: ${issue}`);
382
812
  }
813
+ }
383
814
 
384
- // Get next task
385
- nextTask = await getNextTask(projectDir);
815
+ if (codeVerification.codeVerification.warnings.length > 0) {
816
+ for (const warning of codeVerification.codeVerification.warnings.slice(0, 3)) {
817
+ onProgress?.('verification-info', `Code Warning: ${warning}`);
818
+ }
386
819
  }
387
820
 
388
- // Check final status
389
- const progress = await getProgress(projectDir);
821
+ // Summary
822
+ onProgress?.(
823
+ 'verification-summary',
824
+ `Verification complete: ${completedMilestones}/${state.milestones.length} milestones, ` +
825
+ `${completedTasks}/${allTasks.length} tasks, ` +
826
+ `${codeVerification.codeVerification.totalLinesOfCode} lines of code`
827
+ );
390
828
 
391
- if (failedTasks > 0) {
392
- state = await failProject(
393
- projectDir,
394
- `${failedTasks} tasks failed out of ${progress.totalTasks}`
829
+ // Check if genuinely complete
830
+ if (!codeVerification.isGenuinelyComplete) {
831
+ onProgress?.(
832
+ 'verification-warning',
833
+ 'WARNING: Project may not be genuinely complete. Code verification found issues.'
395
834
  );
835
+ await logger.warn('verification', 'incomplete_code', 'Project may not be genuinely complete', {
836
+ taskComplete: codeVerification.taskVerification.isComplete,
837
+ codeQualityPassed: codeVerification.codeVerification.passed,
838
+ summary: codeVerification.summary,
839
+ });
840
+ }
841
+
842
+ // ============================================
843
+ // COMPREHENSIVE PROJECT VERIFICATION
844
+ // ============================================
845
+ onProgress?.('verification', 'Running comprehensive project verification...');
846
+
847
+ const comprehensiveReport = await runComprehensiveVerification(
848
+ projectDir,
849
+ (msg) => onProgress?.('verification', msg)
850
+ );
851
+
852
+ // Log verification results
853
+ for (const result of comprehensiveReport.results) {
854
+ if (!result.passed) {
855
+ const level = result.severity === 'error' ? 'verification-error' : 'verification-warning';
856
+ onProgress?.(level, `[${result.category}] ${result.message}`);
857
+ }
858
+ }
859
+
860
+ // Auto-fix fixable issues
861
+ if (comprehensiveReport.failedChecks > 0) {
862
+ const fixableCount = comprehensiveReport.results.filter(r => !r.passed && r.autoFixable).length;
863
+ if (fixableCount > 0) {
864
+ onProgress?.('verification', `Attempting to auto-fix ${fixableCount} issue(s)...`);
865
+ const fixed = await autoFixIssues(comprehensiveReport, (msg) => onProgress?.('verification', msg));
866
+ onProgress?.('verification', `Auto-fixed ${fixed} issue(s)`);
867
+
868
+ // Re-run verification after fixes
869
+ if (fixed > 0) {
870
+ onProgress?.('verification', 'Re-running verification after fixes...');
871
+ const reVerifyReport = await runComprehensiveVerification(projectDir);
872
+
873
+ if (reVerifyReport.failedChecks > 0) {
874
+ onProgress?.(
875
+ 'verification-error',
876
+ `${reVerifyReport.failedChecks} critical issue(s) remain after auto-fix`
877
+ );
878
+ }
879
+ }
880
+ }
881
+ }
882
+
883
+ // Block completion if critical issues remain
884
+ if (comprehensiveReport.criticalIssues.length > 0) {
885
+ onProgress?.(
886
+ 'verification-error',
887
+ `BLOCKING: ${comprehensiveReport.criticalIssues.length} critical issue(s) found`
888
+ );
889
+
890
+ for (const issue of comprehensiveReport.criticalIssues) {
891
+ onProgress?.('verification-error', ` - ${issue}`);
892
+ }
893
+
894
+ await logger.error('verification', 'critical_issues', 'Critical verification issues found', {
895
+ issues: comprehensiveReport.criticalIssues,
896
+ });
396
897
 
397
898
  return {
398
899
  success: false,
399
900
  state,
400
901
  completedTasks,
401
902
  failedTasks,
402
- error: `Execution completed with ${failedTasks} failed tasks`,
903
+ error: `Project verification failed: ${comprehensiveReport.criticalIssues.length} critical issues`,
403
904
  };
404
905
  }
405
906
 
406
- // All tasks complete
907
+ onProgress?.(
908
+ 'verification',
909
+ `Verification complete: ${comprehensiveReport.passedChecks}/${comprehensiveReport.totalChecks} checks passed`
910
+ );
911
+
912
+ // ============================================
913
+ // GENERATE PROJECT README
914
+ // ============================================
915
+ onProgress?.('readme', 'Generating project README with setup and run instructions...');
916
+ const readmeResult = await generateProjectReadme(projectDir, state);
917
+
918
+ if (readmeResult.success) {
919
+ onProgress?.('readme', `README.md generated successfully`);
920
+ await logger.success('completion', 'readme_generated', 'Project README generated', {
921
+ path: readmeResult.path,
922
+ });
923
+ } else {
924
+ onProgress?.('readme-warning', `Failed to generate README: ${readmeResult.error}`);
925
+ await logger.warn('completion', 'readme_failed', 'Failed to generate README', {
926
+ error: readmeResult.error,
927
+ });
928
+ }
929
+
930
+ // All milestones complete
407
931
  state = await completeProject(projectDir);
408
932
 
409
933
  onProgress?.(
410
934
  'execution-complete',
411
- `Project complete! ${completedTasks} tasks executed successfully.`
935
+ `Project complete! ${completedMilestones} milestones, ${completedTasks} tasks executed successfully.`
412
936
  );
413
937
 
938
+ await logger.stageComplete('completion', 'Project execution completed successfully', {
939
+ completedMilestones: completedMilestones,
940
+ totalMilestones: state.milestones.length,
941
+ completedTasks: completedTasks,
942
+ totalTasks: state.milestones.reduce((sum, m) => sum + m.tasks.length, 0),
943
+ buildPassed: buildResult.success,
944
+ testsPassed: hasTests ? (await runTests(projectDir, state.language)).success : true,
945
+ });
946
+
414
947
  return {
415
948
  success: true,
416
949
  state,
@@ -421,6 +954,13 @@ export async function runExecutionMode(
421
954
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
422
955
  onProgress?.('error', errorMessage);
423
956
 
957
+ await logger.stageFailed('execution', 'Execution Mode failed', errorMessage, {
958
+ errorType: error instanceof Error ? error.constructor.name : typeof error,
959
+ completedTasks: completedTasks,
960
+ failedTasks: failedTasks,
961
+ completedMilestones: completedMilestones,
962
+ });
963
+
424
964
  return {
425
965
  success: false,
426
966
  state: await loadProject(projectDir).catch(() => ({} as ProjectState)),
@@ -440,32 +980,91 @@ export async function runExecutionMode(
440
980
  export async function resumeExecutionMode(
441
981
  options: ExecutionModeOptions
442
982
  ): Promise<ExecutionModeResult> {
443
- const state = await loadProject(options.projectDir);
983
+ const { projectDir, onProgress } = options;
984
+ let state = await loadProject(projectDir);
444
985
 
445
- // Check current status
446
- if (state.status === 'complete') {
447
- return {
448
- success: true,
449
- state,
450
- completedTasks: state.milestones.flatMap((m) => m.tasks).filter((t) => t.status === 'complete').length,
451
- failedTasks: 0,
452
- };
986
+ // Verify actual completion - don't trust status alone
987
+ const verification = await verifyProjectCompletion(projectDir);
988
+ const progress = verification.progress;
989
+
990
+ // Log current progress
991
+ onProgress?.(
992
+ 'resume-analysis',
993
+ `Current progress: ${progress.progressSummary}`
994
+ );
995
+
996
+ // Check if actually complete
997
+ if (state.status === 'complete' || state.phase === 'complete') {
998
+ if (verification.isComplete) {
999
+ onProgress?.('resume-complete', 'Project is genuinely complete');
1000
+ return {
1001
+ success: true,
1002
+ state,
1003
+ completedTasks: progress.completedTasks,
1004
+ failedTasks: 0,
1005
+ };
1006
+ }
1007
+
1008
+ // Status says complete but work is incomplete
1009
+ onProgress?.(
1010
+ 'resume-mismatch',
1011
+ `Status mismatch detected: status='complete' but ${progress.completedTasks}/${progress.totalTasks} tasks done`
1012
+ );
1013
+
1014
+ // Reset incorrect status
1015
+ state = await updateState(projectDir, {
1016
+ status: 'in-progress',
1017
+ phase: 'execution',
1018
+ error: undefined,
1019
+ });
1020
+
1021
+ onProgress?.(
1022
+ 'resume-reset',
1023
+ `Reset project status. Will continue with ${progress.pendingTasks + progress.failedTasks} remaining tasks`
1024
+ );
453
1025
  }
454
1026
 
455
1027
  // Reset failed tasks to pending so they can be retried
456
- if (state.status === 'failed') {
1028
+ if (state.status === 'failed' || progress.failedTasks > 0) {
457
1029
  const updatedMilestones = state.milestones.map((m) => ({
458
1030
  ...m,
1031
+ // Also reset milestone status if needed
1032
+ status: m.tasks.every(t => t.status === 'complete')
1033
+ ? 'complete' as const
1034
+ : m.tasks.some(t => t.status === 'complete' || t.status === 'in-progress')
1035
+ ? 'in-progress' as const
1036
+ : 'pending' as const,
459
1037
  tasks: m.tasks.map((t) =>
460
1038
  t.status === 'failed' ? { ...t, status: 'pending' as const, error: undefined } : t
461
1039
  ),
462
1040
  }));
463
1041
 
464
- await updateState(options.projectDir, {
1042
+ await updateState(projectDir, {
465
1043
  milestones: updatedMilestones,
466
- status: 'pending',
1044
+ status: 'in-progress',
467
1045
  error: undefined,
468
1046
  });
1047
+
1048
+ if (progress.failedTasks > 0) {
1049
+ onProgress?.(
1050
+ 'resume-retry',
1051
+ `Reset ${progress.failedTasks} failed task(s) to pending for retry`
1052
+ );
1053
+ }
1054
+ }
1055
+
1056
+ // Show what will be worked on
1057
+ if (progress.nextMilestone) {
1058
+ onProgress?.(
1059
+ 'resume-next',
1060
+ `Next milestone: ${progress.nextMilestone.name}`
1061
+ );
1062
+ }
1063
+ if (progress.nextTask) {
1064
+ onProgress?.(
1065
+ 'resume-next',
1066
+ `Next task: ${progress.nextTask.name} (in ${progress.nextTask.milestone})`
1067
+ );
469
1068
  }
470
1069
 
471
1070
  return runExecutionMode(options);