popeye-cli 1.0.1 → 1.2.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 (216) hide show
  1. package/.env.example +24 -1
  2. package/CONTRIBUTING.md +275 -0
  3. package/OPEN_SOURCE_MANIFESTO.md +172 -0
  4. package/README.md +832 -123
  5. package/dist/adapters/claude.d.ts +19 -4
  6. package/dist/adapters/claude.d.ts.map +1 -1
  7. package/dist/adapters/claude.js +908 -42
  8. package/dist/adapters/claude.js.map +1 -1
  9. package/dist/adapters/gemini.d.ts +55 -0
  10. package/dist/adapters/gemini.d.ts.map +1 -0
  11. package/dist/adapters/gemini.js +318 -0
  12. package/dist/adapters/gemini.js.map +1 -0
  13. package/dist/adapters/grok.d.ts +73 -0
  14. package/dist/adapters/grok.d.ts.map +1 -0
  15. package/dist/adapters/grok.js +430 -0
  16. package/dist/adapters/grok.js.map +1 -0
  17. package/dist/adapters/openai.d.ts +1 -1
  18. package/dist/adapters/openai.d.ts.map +1 -1
  19. package/dist/adapters/openai.js +47 -8
  20. package/dist/adapters/openai.js.map +1 -1
  21. package/dist/auth/claude.d.ts +11 -9
  22. package/dist/auth/claude.d.ts.map +1 -1
  23. package/dist/auth/claude.js +107 -71
  24. package/dist/auth/claude.js.map +1 -1
  25. package/dist/auth/gemini.d.ts +58 -0
  26. package/dist/auth/gemini.d.ts.map +1 -0
  27. package/dist/auth/gemini.js +172 -0
  28. package/dist/auth/gemini.js.map +1 -0
  29. package/dist/auth/grok.d.ts +73 -0
  30. package/dist/auth/grok.d.ts.map +1 -0
  31. package/dist/auth/grok.js +211 -0
  32. package/dist/auth/grok.js.map +1 -0
  33. package/dist/auth/index.d.ts +14 -7
  34. package/dist/auth/index.d.ts.map +1 -1
  35. package/dist/auth/index.js +41 -6
  36. package/dist/auth/index.js.map +1 -1
  37. package/dist/auth/keychain.d.ts +20 -7
  38. package/dist/auth/keychain.d.ts.map +1 -1
  39. package/dist/auth/keychain.js +85 -29
  40. package/dist/auth/keychain.js.map +1 -1
  41. package/dist/auth/openai.d.ts +2 -2
  42. package/dist/auth/openai.d.ts.map +1 -1
  43. package/dist/auth/openai.js +30 -32
  44. package/dist/auth/openai.js.map +1 -1
  45. package/dist/cli/commands/auth.d.ts +1 -1
  46. package/dist/cli/commands/auth.d.ts.map +1 -1
  47. package/dist/cli/commands/auth.js +79 -8
  48. package/dist/cli/commands/auth.js.map +1 -1
  49. package/dist/cli/commands/create.d.ts.map +1 -1
  50. package/dist/cli/commands/create.js +15 -4
  51. package/dist/cli/commands/create.js.map +1 -1
  52. package/dist/cli/interactive.d.ts.map +1 -1
  53. package/dist/cli/interactive.js +1494 -114
  54. package/dist/cli/interactive.js.map +1 -1
  55. package/dist/config/defaults.d.ts +9 -1
  56. package/dist/config/defaults.d.ts.map +1 -1
  57. package/dist/config/defaults.js +19 -2
  58. package/dist/config/defaults.js.map +1 -1
  59. package/dist/config/index.d.ts +19 -0
  60. package/dist/config/index.d.ts.map +1 -1
  61. package/dist/config/index.js +33 -1
  62. package/dist/config/index.js.map +1 -1
  63. package/dist/config/schema.d.ts +47 -0
  64. package/dist/config/schema.d.ts.map +1 -1
  65. package/dist/config/schema.js +29 -1
  66. package/dist/config/schema.js.map +1 -1
  67. package/dist/generators/fullstack.d.ts +32 -0
  68. package/dist/generators/fullstack.d.ts.map +1 -0
  69. package/dist/generators/fullstack.js +497 -0
  70. package/dist/generators/fullstack.js.map +1 -0
  71. package/dist/generators/index.d.ts +4 -3
  72. package/dist/generators/index.d.ts.map +1 -1
  73. package/dist/generators/index.js +15 -1
  74. package/dist/generators/index.js.map +1 -1
  75. package/dist/generators/python.d.ts +17 -1
  76. package/dist/generators/python.d.ts.map +1 -1
  77. package/dist/generators/python.js +34 -20
  78. package/dist/generators/python.js.map +1 -1
  79. package/dist/generators/templates/fullstack.d.ts +113 -0
  80. package/dist/generators/templates/fullstack.d.ts.map +1 -0
  81. package/dist/generators/templates/fullstack.js +1004 -0
  82. package/dist/generators/templates/fullstack.js.map +1 -0
  83. package/dist/generators/typescript.d.ts +19 -1
  84. package/dist/generators/typescript.d.ts.map +1 -1
  85. package/dist/generators/typescript.js +37 -20
  86. package/dist/generators/typescript.js.map +1 -1
  87. package/dist/state/index.d.ts +108 -0
  88. package/dist/state/index.d.ts.map +1 -1
  89. package/dist/state/index.js +551 -4
  90. package/dist/state/index.js.map +1 -1
  91. package/dist/state/registry.d.ts +52 -0
  92. package/dist/state/registry.d.ts.map +1 -0
  93. package/dist/state/registry.js +215 -0
  94. package/dist/state/registry.js.map +1 -0
  95. package/dist/types/cli.d.ts +8 -0
  96. package/dist/types/cli.d.ts.map +1 -1
  97. package/dist/types/cli.js.map +1 -1
  98. package/dist/types/consensus.d.ts +186 -4
  99. package/dist/types/consensus.d.ts.map +1 -1
  100. package/dist/types/consensus.js +35 -3
  101. package/dist/types/consensus.js.map +1 -1
  102. package/dist/types/project.d.ts +76 -0
  103. package/dist/types/project.d.ts.map +1 -1
  104. package/dist/types/project.js +1 -1
  105. package/dist/types/project.js.map +1 -1
  106. package/dist/types/workflow.d.ts +217 -16
  107. package/dist/types/workflow.d.ts.map +1 -1
  108. package/dist/types/workflow.js +40 -1
  109. package/dist/types/workflow.js.map +1 -1
  110. package/dist/workflow/auto-fix.d.ts +45 -0
  111. package/dist/workflow/auto-fix.d.ts.map +1 -0
  112. package/dist/workflow/auto-fix.js +274 -0
  113. package/dist/workflow/auto-fix.js.map +1 -0
  114. package/dist/workflow/consensus.d.ts +70 -2
  115. package/dist/workflow/consensus.d.ts.map +1 -1
  116. package/dist/workflow/consensus.js +872 -17
  117. package/dist/workflow/consensus.js.map +1 -1
  118. package/dist/workflow/execution-mode.d.ts +10 -4
  119. package/dist/workflow/execution-mode.d.ts.map +1 -1
  120. package/dist/workflow/execution-mode.js +547 -58
  121. package/dist/workflow/execution-mode.js.map +1 -1
  122. package/dist/workflow/index.d.ts +14 -2
  123. package/dist/workflow/index.d.ts.map +1 -1
  124. package/dist/workflow/index.js +69 -6
  125. package/dist/workflow/index.js.map +1 -1
  126. package/dist/workflow/milestone-workflow.d.ts +34 -0
  127. package/dist/workflow/milestone-workflow.d.ts.map +1 -0
  128. package/dist/workflow/milestone-workflow.js +414 -0
  129. package/dist/workflow/milestone-workflow.js.map +1 -0
  130. package/dist/workflow/plan-mode.d.ts +80 -3
  131. package/dist/workflow/plan-mode.d.ts.map +1 -1
  132. package/dist/workflow/plan-mode.js +767 -49
  133. package/dist/workflow/plan-mode.js.map +1 -1
  134. package/dist/workflow/plan-storage.d.ts +386 -0
  135. package/dist/workflow/plan-storage.d.ts.map +1 -0
  136. package/dist/workflow/plan-storage.js +878 -0
  137. package/dist/workflow/plan-storage.js.map +1 -0
  138. package/dist/workflow/project-verification.d.ts +37 -0
  139. package/dist/workflow/project-verification.d.ts.map +1 -0
  140. package/dist/workflow/project-verification.js +381 -0
  141. package/dist/workflow/project-verification.js.map +1 -0
  142. package/dist/workflow/task-workflow.d.ts +37 -0
  143. package/dist/workflow/task-workflow.d.ts.map +1 -0
  144. package/dist/workflow/task-workflow.js +386 -0
  145. package/dist/workflow/task-workflow.js.map +1 -0
  146. package/dist/workflow/test-runner.d.ts +9 -0
  147. package/dist/workflow/test-runner.d.ts.map +1 -1
  148. package/dist/workflow/test-runner.js +101 -5
  149. package/dist/workflow/test-runner.js.map +1 -1
  150. package/dist/workflow/ui-designer.d.ts +82 -0
  151. package/dist/workflow/ui-designer.d.ts.map +1 -0
  152. package/dist/workflow/ui-designer.js +234 -0
  153. package/dist/workflow/ui-designer.js.map +1 -0
  154. package/dist/workflow/ui-setup.d.ts +58 -0
  155. package/dist/workflow/ui-setup.d.ts.map +1 -0
  156. package/dist/workflow/ui-setup.js +685 -0
  157. package/dist/workflow/ui-setup.js.map +1 -0
  158. package/dist/workflow/ui-verification.d.ts +114 -0
  159. package/dist/workflow/ui-verification.d.ts.map +1 -0
  160. package/dist/workflow/ui-verification.js +258 -0
  161. package/dist/workflow/ui-verification.js.map +1 -0
  162. package/dist/workflow/workflow-logger.d.ts +110 -0
  163. package/dist/workflow/workflow-logger.d.ts.map +1 -0
  164. package/dist/workflow/workflow-logger.js +267 -0
  165. package/dist/workflow/workflow-logger.js.map +1 -0
  166. package/dist/workflow/workspace-manager.d.ts +342 -0
  167. package/dist/workflow/workspace-manager.d.ts.map +1 -0
  168. package/dist/workflow/workspace-manager.js +733 -0
  169. package/dist/workflow/workspace-manager.js.map +1 -0
  170. package/package.json +2 -2
  171. package/src/adapters/claude.ts +1067 -47
  172. package/src/adapters/gemini.ts +373 -0
  173. package/src/adapters/grok.ts +492 -0
  174. package/src/adapters/openai.ts +48 -9
  175. package/src/auth/claude.ts +120 -78
  176. package/src/auth/gemini.ts +207 -0
  177. package/src/auth/grok.ts +255 -0
  178. package/src/auth/index.ts +47 -9
  179. package/src/auth/keychain.ts +95 -28
  180. package/src/auth/openai.ts +29 -36
  181. package/src/cli/commands/auth.ts +89 -10
  182. package/src/cli/commands/create.ts +13 -4
  183. package/src/cli/interactive.ts +1774 -142
  184. package/src/config/defaults.ts +19 -2
  185. package/src/config/index.ts +36 -1
  186. package/src/config/schema.ts +30 -1
  187. package/src/generators/fullstack.ts +551 -0
  188. package/src/generators/index.ts +25 -1
  189. package/src/generators/python.ts +65 -20
  190. package/src/generators/templates/fullstack.ts +1047 -0
  191. package/src/generators/typescript.ts +69 -20
  192. package/src/state/index.ts +713 -4
  193. package/src/state/registry.ts +278 -0
  194. package/src/types/cli.ts +8 -0
  195. package/src/types/consensus.ts +197 -6
  196. package/src/types/project.ts +82 -1
  197. package/src/types/workflow.ts +90 -1
  198. package/src/workflow/auto-fix.ts +340 -0
  199. package/src/workflow/consensus.ts +1180 -16
  200. package/src/workflow/execution-mode.ts +673 -74
  201. package/src/workflow/index.ts +95 -6
  202. package/src/workflow/milestone-workflow.ts +576 -0
  203. package/src/workflow/plan-mode.ts +924 -50
  204. package/src/workflow/plan-storage.ts +1282 -0
  205. package/src/workflow/project-verification.ts +471 -0
  206. package/src/workflow/task-workflow.ts +528 -0
  207. package/src/workflow/test-runner.ts +120 -5
  208. package/src/workflow/ui-designer.ts +337 -0
  209. package/src/workflow/ui-setup.ts +797 -0
  210. package/src/workflow/ui-verification.ts +357 -0
  211. package/src/workflow/workflow-logger.ts +353 -0
  212. package/src/workflow/workspace-manager.ts +912 -0
  213. package/tests/config/config.test.ts +1 -1
  214. package/tests/types/consensus.test.ts +3 -3
  215. package/tests/workflow/plan-mode.test.ts +213 -0
  216. package/tests/workflow/test-runner.test.ts +5 -3
@@ -1,14 +1,180 @@
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
  */
6
+ import { promises as fs } from 'node:fs';
7
+ import path from 'node:path';
5
8
  import { generateCode } from '../adapters/claude.js';
6
- import { loadProject, updateState, updateTaskStatus, setCurrentMilestone, setCurrentTask, getNextTask, getProgress, completeProject, failProject, } from '../state/index.js';
9
+ import { loadProject, updateState, setCurrentMilestone, completeProject, verifyProjectCompletion, comprehensiveProjectVerification, } from '../state/index.js';
7
10
  import { runTests, testsExist, getTestSummary, } from './test-runner.js';
11
+ import { getWorkflowLogger } from './workflow-logger.js';
12
+ import { buildWithAutoFix } from './auto-fix.js';
13
+ import { runComprehensiveVerification, autoFixIssues } from './project-verification.js';
14
+ import { setupUI } from './ui-setup.js';
15
+ import { designUI, saveUISpecification, loadUISpecification } from './ui-designer.js';
8
16
  /**
9
17
  * Maximum number of retries for failed tests
10
18
  */
11
19
  const DEFAULT_MAX_RETRIES = 3;
20
+ /**
21
+ * Generate a comprehensive README.md for the completed project
22
+ * This provides users with setup and run instructions
23
+ *
24
+ * @param projectDir - Project directory
25
+ * @param state - Project state
26
+ * @returns Path to generated README or error
27
+ */
28
+ async function generateProjectReadme(projectDir, state) {
29
+ try {
30
+ const readmePath = path.join(projectDir, 'README.md');
31
+ // Extract features from completed milestones
32
+ const features = state.milestones
33
+ .filter(m => m.status === 'complete')
34
+ .map(m => ({
35
+ name: m.name,
36
+ description: m.description,
37
+ tasks: m.tasks.filter(t => t.status === 'complete').map(t => t.name),
38
+ }));
39
+ // Determine run commands based on language
40
+ const isTypeScript = state.language === 'typescript';
41
+ const installCmd = isTypeScript ? 'npm install' : 'pip install -r requirements.txt';
42
+ const devCmd = isTypeScript ? 'npm run dev' : 'python src/main.py';
43
+ const testCmd = isTypeScript ? 'npm test' : 'pytest tests/ -v';
44
+ const buildCmd = isTypeScript ? 'npm run build' : 'python -m py_compile src/**/*.py';
45
+ // Build README content
46
+ const readmeContent = `# ${state.name}
47
+
48
+ ${state.specification ? extractDescriptionFromSpec(state.specification) : 'A project generated by Popeye CLI.'}
49
+
50
+ ## Features
51
+
52
+ ${features.map(f => `### ${f.name}
53
+ ${f.description || ''}
54
+ ${f.tasks.length > 0 ? f.tasks.map(t => `- ${t}`).join('\n') : ''}`).join('\n\n')}
55
+
56
+ ## Prerequisites
57
+
58
+ ${isTypeScript ? `- Node.js 18.0 or higher
59
+ - npm 8.0 or higher` : `- Python 3.9 or higher
60
+ - pip (Python package manager)`}
61
+
62
+ ## Installation
63
+
64
+ \`\`\`bash
65
+ # Clone the repository (if applicable)
66
+ cd ${state.name}
67
+
68
+ # Install dependencies
69
+ ${installCmd}
70
+ \`\`\`
71
+
72
+ ## Environment Setup
73
+
74
+ 1. Copy the example environment file:
75
+ \`\`\`bash
76
+ cp .env.example .env
77
+ \`\`\`
78
+
79
+ 2. Edit \`.env\` and fill in the required values.
80
+
81
+ ## Running the Application
82
+
83
+ ### Development Mode
84
+
85
+ \`\`\`bash
86
+ ${devCmd}
87
+ \`\`\`
88
+
89
+ ### Running Tests
90
+
91
+ \`\`\`bash
92
+ ${testCmd}
93
+ \`\`\`
94
+
95
+ ### Build for Production
96
+
97
+ \`\`\`bash
98
+ ${buildCmd}
99
+ \`\`\`
100
+
101
+ ${isTypeScript ? `### Start Production Server
102
+
103
+ \`\`\`bash
104
+ npm start
105
+ \`\`\`
106
+ ` : ''}
107
+ ## Project Structure
108
+
109
+ \`\`\`
110
+ ${state.name}/
111
+ ├── src/ # Source code
112
+ ${isTypeScript ? `│ └── index.ts # Main entry point` : `│ ├── __init__.py
113
+ │ └── main.py # Main entry point`}
114
+ ├── tests/ # Test files
115
+ ├── docs/ # Documentation
116
+ │ ├── PLAN.md # Development plan
117
+ │ └── WORKFLOW_LOG.md # Execution log
118
+ ${isTypeScript ? `├── package.json # Dependencies and scripts
119
+ ├── tsconfig.json # TypeScript configuration` : `├── requirements.txt # Python dependencies
120
+ ├── pyproject.toml # Project configuration`}
121
+ ├── .env.example # Environment template
122
+ ├── .gitignore
123
+ ├── Dockerfile
124
+ └── README.md
125
+ \`\`\`
126
+
127
+ ## Development
128
+
129
+ This project was generated using [Popeye CLI](https://github.com/your-org/popeye-cli), an autonomous code generation tool.
130
+
131
+ ### Development Plan
132
+
133
+ See [docs/PLAN.md](docs/PLAN.md) for the complete development plan used to build this project.
134
+
135
+ ### Workflow Log
136
+
137
+ See [docs/WORKFLOW_LOG.md](docs/WORKFLOW_LOG.md) for detailed execution logs.
138
+
139
+ ## License
140
+
141
+ MIT
142
+ `;
143
+ await fs.writeFile(readmePath, readmeContent, 'utf-8');
144
+ return { success: true, path: readmePath };
145
+ }
146
+ catch (error) {
147
+ return {
148
+ success: false,
149
+ error: error instanceof Error ? error.message : 'Failed to generate README',
150
+ };
151
+ }
152
+ }
153
+ /**
154
+ * Extract a brief description from the specification
155
+ *
156
+ * @param spec - Full specification text
157
+ * @returns Brief description (first paragraph or summary)
158
+ */
159
+ function extractDescriptionFromSpec(spec) {
160
+ // Try to find a summary section
161
+ const summaryMatch = spec.match(/(?:##?\s*(?:Summary|Overview|Description)[\s\S]*?\n)([\s\S]*?)(?:\n##|\n\n##|$)/i);
162
+ if (summaryMatch) {
163
+ const summary = summaryMatch[1].trim();
164
+ if (summary.length > 0 && summary.length < 500) {
165
+ return summary;
166
+ }
167
+ }
168
+ // Fall back to first paragraph
169
+ const lines = spec.split('\n').filter(line => line.trim() && !line.startsWith('#'));
170
+ const firstParagraph = lines.slice(0, 3).join(' ').trim();
171
+ if (firstParagraph.length > 500) {
172
+ return firstParagraph.slice(0, 497) + '...';
173
+ }
174
+ return firstParagraph || 'A project generated by Popeye CLI.';
175
+ }
176
+ // Note: runCommand and runFinalBuildVerification replaced by buildWithAutoFix from auto-fix.ts
177
+ // which provides automatic error fixing capabilities
12
178
  /**
13
179
  * Build the execution context for a task
14
180
  *
@@ -17,7 +183,7 @@ const DEFAULT_MAX_RETRIES = 3;
17
183
  * @param task - Current task
18
184
  * @returns Context string for code generation
19
185
  */
20
- function buildTaskContext(state, milestone, _task) {
186
+ function buildTaskContext(state, milestone, _task, uiDesignContext) {
21
187
  const lines = [];
22
188
  lines.push(`## Project: ${state.name}`);
23
189
  lines.push(`Language: ${state.language}`);
@@ -32,6 +198,11 @@ function buildTaskContext(state, milestone, _task) {
32
198
  lines.push(state.plan.slice(0, 2000));
33
199
  lines.push('');
34
200
  }
201
+ // Include UI design context if available
202
+ if (uiDesignContext) {
203
+ lines.push(uiDesignContext);
204
+ lines.push('');
205
+ }
35
206
  lines.push('## Current Milestone');
36
207
  lines.push(`Name: ${milestone.name}`);
37
208
  lines.push(`Description: ${milestone.description}`);
@@ -53,9 +224,10 @@ function buildTaskContext(state, milestone, _task) {
53
224
  * @param task - The task to execute
54
225
  * @param context - Execution context
55
226
  * @param projectDir - Project directory
227
+ * @param onProgress - Progress callback for Claude activity
56
228
  * @returns Execution result
57
229
  */
58
- export async function executeTask(task, context, projectDir) {
230
+ export async function executeTask(task, context, projectDir, onProgress) {
59
231
  const prompt = `
60
232
  ## Task
61
233
  ${task.name}
@@ -70,7 +242,7 @@ Please implement this task completely. After implementing:
70
242
  2. Ensure code follows best practices
71
243
  3. Document any complex logic
72
244
  `.trim();
73
- return generateCode(prompt, context, { cwd: projectDir });
245
+ return generateCode(prompt, context, { cwd: projectDir, onProgress });
74
246
  }
75
247
  /**
76
248
  * Handle a test failure by attempting to fix the code
@@ -79,9 +251,10 @@ Please implement this task completely. After implementing:
79
251
  * @param testResult - The test result
80
252
  * @param context - Execution context
81
253
  * @param projectDir - Project directory
254
+ * @param onProgress - Progress callback for Claude activity
82
255
  * @returns Fix attempt result
83
256
  */
84
- export async function handleTestFailure(task, testResult, context, projectDir) {
257
+ export async function handleTestFailure(task, testResult, context, projectDir, onProgress) {
85
258
  const prompt = `
86
259
  ## Test Failure Fix Required
87
260
 
@@ -103,7 +276,7 @@ Please:
103
276
  2. Fix the code to make all tests pass
104
277
  3. Do NOT modify the tests unless they are incorrect
105
278
  `.trim();
106
- return generateCode(prompt, context, { cwd: projectDir });
279
+ return generateCode(prompt, context, { cwd: projectDir, onProgress });
107
280
  }
108
281
  /**
109
282
  * Execute a task with retry logic for test failures
@@ -115,11 +288,27 @@ Please:
115
288
  * @returns Task execution result
116
289
  */
117
290
  async function executeTaskWithRetry(milestone, task, state, options) {
118
- const { projectDir, maxRetries = DEFAULT_MAX_RETRIES, onTestResult, } = options;
119
- const context = buildTaskContext(state, milestone, task);
291
+ const { projectDir, maxRetries = DEFAULT_MAX_RETRIES, onTestResult, onProgress, } = options;
292
+ // Load UI design context if available
293
+ let uiDesignContext;
294
+ try {
295
+ const uiSpec = await loadUISpecification(projectDir);
296
+ if (uiSpec) {
297
+ const { generateDesignSystemPrompt } = await import('./ui-designer.js');
298
+ uiDesignContext = generateDesignSystemPrompt(uiSpec);
299
+ }
300
+ }
301
+ catch {
302
+ // UI spec not available, continue without it
303
+ }
304
+ const context = buildTaskContext(state, milestone, task, uiDesignContext);
120
305
  let retries = 0;
306
+ // Create a progress handler that prefixes messages with [claude]
307
+ const claudeProgress = onProgress
308
+ ? (msg) => onProgress('claude', msg)
309
+ : undefined;
121
310
  // Execute the task
122
- const execResult = await executeTask(task, context, projectDir);
311
+ const execResult = await executeTask(task, context, projectDir, claudeProgress);
123
312
  if (!execResult.success) {
124
313
  return {
125
314
  success: false,
@@ -187,17 +376,27 @@ async function executeTaskWithRetry(milestone, task, state, options) {
187
376
  };
188
377
  }
189
378
  /**
190
- * Run execution mode for a project
379
+ * Run execution mode for a project using hierarchical consensus workflow
380
+ * Each milestone and task goes through: Plan → Consensus → Implement → Test → Review
191
381
  *
192
382
  * @param options - Execution options
193
383
  * @returns Execution mode result
194
384
  */
195
385
  export async function runExecutionMode(options) {
196
386
  const { projectDir, onProgress, onTaskStart, onTaskComplete, } = options;
387
+ // Initialize workflow logger
388
+ const logger = getWorkflowLogger(projectDir);
197
389
  let completedTasks = 0;
198
390
  let failedTasks = 0;
391
+ let completedMilestones = 0;
199
392
  try {
200
393
  let state = await loadProject(projectDir);
394
+ await logger.stageStart('execution', 'Execution Mode started', {
395
+ projectName: state.name,
396
+ phase: state.phase,
397
+ totalMilestones: state.milestones.length,
398
+ totalTasks: state.milestones.reduce((sum, m) => sum + m.tasks.length, 0),
399
+ });
201
400
  // Ensure we're in execution phase
202
401
  if (state.phase !== 'execution') {
203
402
  return {
@@ -210,58 +409,308 @@ export async function runExecutionMode(options) {
210
409
  }
211
410
  // Update status
212
411
  state = await updateState(projectDir, { status: 'in-progress' });
213
- onProgress?.('execution-start', 'Starting execution mode...');
214
- // Process tasks
215
- let nextTask = await getNextTask(projectDir);
216
- while (nextTask) {
217
- const { milestone, task } = nextTask;
218
- // Set current milestone and task
412
+ onProgress?.('execution-start', 'Starting hierarchical execution mode...');
413
+ onProgress?.('execution-start', `Processing ${state.milestones.length} milestones with per-task consensus`);
414
+ // Import milestone workflow dynamically to avoid circular dependencies
415
+ const { runMilestoneWorkflow } = await import('./milestone-workflow.js');
416
+ // Process each milestone
417
+ for (const milestone of state.milestones) {
418
+ // Skip completed milestones
419
+ if (milestone.status === 'complete' && milestone.completionApproved) {
420
+ onProgress?.('milestone-skip', `Skipping completed milestone: ${milestone.name}`);
421
+ completedMilestones++;
422
+ completedTasks += milestone.tasks.filter(t => t.status === 'complete').length;
423
+ continue;
424
+ }
425
+ // Set current milestone
219
426
  state = await setCurrentMilestone(projectDir, milestone.id);
220
- state = await setCurrentTask(projectDir, task.id);
221
- // Update task to in-progress
222
- state = await updateTaskStatus(projectDir, task.id, 'in-progress');
223
- onProgress?.('task-start', `Executing: ${task.name} (Milestone: ${milestone.name})`);
224
- if (onTaskStart) {
225
- onTaskStart(milestone, task);
427
+ onProgress?.('milestone-start', `Starting milestone: ${milestone.name} (${milestone.tasks.length} tasks)`);
428
+ await logger.stageStart('milestone', `Starting milestone: ${milestone.name}`, {
429
+ milestoneId: milestone.id,
430
+ milestoneName: milestone.name,
431
+ taskCount: milestone.tasks.length,
432
+ taskNames: milestone.tasks.map(t => t.name),
433
+ });
434
+ // Run the complete milestone workflow
435
+ const milestoneResult = await runMilestoneWorkflow(milestone, {
436
+ projectDir,
437
+ consensusConfig: options.consensusConfig,
438
+ onProgress,
439
+ onTaskStart: (task) => {
440
+ if (onTaskStart) {
441
+ onTaskStart(milestone, task);
442
+ }
443
+ },
444
+ onTaskComplete: (task, success) => {
445
+ if (success) {
446
+ completedTasks++;
447
+ }
448
+ else {
449
+ failedTasks++;
450
+ }
451
+ if (onTaskComplete) {
452
+ onTaskComplete(milestone, task, success);
453
+ }
454
+ },
455
+ });
456
+ if (milestoneResult.success) {
457
+ completedMilestones++;
458
+ onProgress?.('milestone-complete', `Milestone complete: ${milestone.name} (Score: ${milestoneResult.completionConsensus?.finalScore}%)`);
459
+ await logger.stageComplete('milestone', `Milestone completed: ${milestone.name}`, {
460
+ milestoneId: milestone.id,
461
+ milestoneName: milestone.name,
462
+ consensusScore: milestoneResult.completionConsensus?.finalScore,
463
+ tasksCompleted: milestone.tasks.filter(t => t.status === 'complete').length,
464
+ });
226
465
  }
227
- // Execute the task
228
- const result = await executeTaskWithRetry(milestone, task, state, options);
229
- if (result.success) {
230
- state = await updateTaskStatus(projectDir, task.id, 'complete', {
231
- testsPassed: result.testResult?.success,
466
+ else {
467
+ onProgress?.('milestone-failed', `Milestone failed: ${milestone.name} - ${milestoneResult.error}`);
468
+ await logger.stageFailed('milestone', `Milestone failed: ${milestone.name}`, milestoneResult.error || 'Unknown error', {
469
+ milestoneId: milestone.id,
470
+ milestoneName: milestone.name,
471
+ });
472
+ // Reload state to get latest
473
+ state = await loadProject(projectDir);
474
+ return {
475
+ success: false,
476
+ state,
477
+ completedTasks,
478
+ failedTasks,
479
+ error: `Milestone "${milestone.name}" failed: ${milestoneResult.error}`,
480
+ };
481
+ }
482
+ }
483
+ // ============================================
484
+ // UI SETUP PHASE
485
+ // ============================================
486
+ onProgress?.('ui-setup', 'Running UI setup and design system configuration...');
487
+ await logger.stageStart('ui-setup', 'Starting UI setup');
488
+ // Check if this is a frontend project
489
+ const frontendDir = path.join(projectDir, 'packages', 'frontend');
490
+ const hasFrontend = await fs.access(frontendDir).then(() => true).catch(() => false);
491
+ if (hasFrontend) {
492
+ try {
493
+ // Load or generate UI specification
494
+ let uiSpec = await loadUISpecification(projectDir);
495
+ if (!uiSpec && state.idea) {
496
+ onProgress?.('ui-setup', 'Designing UI from project idea...');
497
+ uiSpec = await designUI(state.idea, (msg) => onProgress?.('ui-setup', msg));
498
+ await saveUISpecification(projectDir, uiSpec);
499
+ onProgress?.('ui-setup', `UI design complete: ${uiSpec.themeName} theme selected`);
500
+ }
501
+ // Run UI setup to install components and configure styling
502
+ onProgress?.('ui-setup', 'Setting up component library and styling...');
503
+ const uiResult = await setupUI(projectDir, {
504
+ theme: uiSpec?.themeName || 'modern',
505
+ idea: state.idea,
506
+ }, (msg) => onProgress?.('ui-setup', msg));
507
+ if (uiResult.success) {
508
+ onProgress?.('ui-setup', `UI setup complete: ${uiResult.componentsInstalled.length} components installed`);
509
+ await logger.success('ui-setup', 'ui_setup_complete', 'UI setup completed successfully', {
510
+ theme: uiResult.theme,
511
+ components: uiResult.componentsInstalled,
512
+ });
513
+ }
514
+ else {
515
+ onProgress?.('ui-setup', `UI setup warning: ${uiResult.error}`);
516
+ await logger.warn('ui-setup', 'ui_setup_warning', 'UI setup had issues', {
517
+ error: uiResult.error,
518
+ });
519
+ }
520
+ }
521
+ catch (uiError) {
522
+ // Non-blocking - UI setup failures shouldn't stop the project
523
+ onProgress?.('ui-setup', `UI setup skipped: ${uiError instanceof Error ? uiError.message : 'Unknown error'}`);
524
+ await logger.warn('ui-setup', 'ui_setup_skipped', 'UI setup was skipped', {
525
+ error: uiError instanceof Error ? uiError.message : 'Unknown error',
526
+ });
527
+ }
528
+ }
529
+ else {
530
+ onProgress?.('ui-setup', 'No frontend detected, skipping UI setup');
531
+ }
532
+ // ============================================
533
+ // FINAL VERIFICATION PHASE
534
+ // ============================================
535
+ onProgress?.('verification', 'Running final verification...');
536
+ await logger.stageStart('verification', 'Starting final verification');
537
+ // Reload state to get latest
538
+ state = await loadProject(projectDir);
539
+ // Verify all milestones are complete
540
+ const incompleteMilestones = state.milestones.filter(m => m.status !== 'complete');
541
+ if (incompleteMilestones.length > 0) {
542
+ const incompleteNames = incompleteMilestones.map(m => m.name).join(', ');
543
+ onProgress?.('verification-warning', `Warning: ${incompleteMilestones.length} milestone(s) not marked complete: ${incompleteNames}`);
544
+ }
545
+ // Verify all tasks are complete
546
+ const allTasks = state.milestones.flatMap(m => m.tasks);
547
+ const incompleteTasks = allTasks.filter(t => t.status !== 'complete');
548
+ if (incompleteTasks.length > 0) {
549
+ const incompleteTaskNames = incompleteTasks.slice(0, 5).map(t => t.name).join(', ');
550
+ onProgress?.('verification-warning', `Warning: ${incompleteTasks.length} task(s) not complete: ${incompleteTaskNames}${incompleteTasks.length > 5 ? '...' : ''}`);
551
+ }
552
+ // Run final build verification with auto-fix
553
+ onProgress?.('verification', 'Running final build verification...');
554
+ const buildResult = await buildWithAutoFix(projectDir, state.language, 3, // max fix attempts
555
+ (msg) => onProgress?.('verification', `[auto-fix] ${msg}`));
556
+ if (!buildResult.success) {
557
+ onProgress?.('verification-error', `Build verification failed${buildResult.autoFixed ? ' (after auto-fix attempts)' : ''}: Build errors remain`);
558
+ await logger.error('verification', 'build_failed', 'Build verification failed', {
559
+ output: buildResult.output.slice(0, 2000),
560
+ autoFixed: buildResult.autoFixed,
561
+ });
562
+ // Block completion if build fails
563
+ onProgress?.('verification-error', 'BLOCKING: Cannot complete project with build errors. Please fix manually and resume.');
564
+ return {
565
+ success: false,
566
+ state,
567
+ completedTasks,
568
+ failedTasks,
569
+ error: 'Build verification failed - project not complete',
570
+ };
571
+ }
572
+ else {
573
+ onProgress?.('verification', `Build verification passed${buildResult.autoFixed ? ' (after auto-fix)' : ''}`);
574
+ await logger.success('verification', 'build_passed', 'Build verification passed', {
575
+ autoFixed: buildResult.autoFixed,
576
+ });
577
+ }
578
+ // Run final test verification
579
+ const hasTests = await testsExist(projectDir, state.language);
580
+ if (hasTests) {
581
+ onProgress?.('verification', 'Running final test verification...');
582
+ const testResult = await runTests(projectDir, state.language);
583
+ if (!testResult.success) {
584
+ onProgress?.('verification-warning', `Final test verification failed: ${testResult.failed} test(s) failed`);
585
+ await logger.warn('verification', 'tests_failed', 'Final test verification failed', {
586
+ passed: testResult.passed,
587
+ failed: testResult.failed,
588
+ total: testResult.total,
589
+ failedTests: testResult.failedTests,
232
590
  });
233
- completedTasks++;
234
- onProgress?.('task-complete', `Completed: ${task.name}${result.testResult ? ` (${getTestSummary(result.testResult)})` : ''}`);
235
591
  }
236
592
  else {
237
- state = await updateTaskStatus(projectDir, task.id, 'failed', {
238
- testsPassed: false,
239
- error: result.error,
593
+ onProgress?.('verification', `All tests passed: ${testResult.passed}/${testResult.total}`);
594
+ await logger.success('verification', 'tests_passed', 'All tests passed', {
595
+ passed: testResult.passed,
596
+ total: testResult.total,
240
597
  });
241
- failedTasks++;
242
- onProgress?.('task-failed', `Failed: ${task.name} - ${result.error}`);
243
598
  }
244
- if (onTaskComplete) {
245
- onTaskComplete(milestone, task, result.success);
599
+ }
600
+ // Run comprehensive code quality verification
601
+ onProgress?.('verification', 'Running code quality verification...');
602
+ const codeVerification = await comprehensiveProjectVerification(projectDir);
603
+ // Log comprehensive verification results
604
+ await logger.info('verification', 'code_quality_check', 'Code quality verification results', {
605
+ totalSourceFiles: codeVerification.codeVerification.totalSourceFiles,
606
+ totalLinesOfCode: codeVerification.codeVerification.totalLinesOfCode,
607
+ hasMainEntryPoint: codeVerification.codeVerification.hasMainEntryPoint,
608
+ hasTests: codeVerification.codeVerification.hasTests,
609
+ hasSubstantiveCode: codeVerification.codeVerification.hasSubstantiveCode,
610
+ issues: codeVerification.codeVerification.issues,
611
+ warnings: codeVerification.codeVerification.warnings,
612
+ });
613
+ // Display code quality results
614
+ onProgress?.('verification', `Code: ${codeVerification.codeVerification.totalSourceFiles} files, ` +
615
+ `${codeVerification.codeVerification.totalLinesOfCode} lines of code`);
616
+ if (codeVerification.codeVerification.issues.length > 0) {
617
+ for (const issue of codeVerification.codeVerification.issues) {
618
+ onProgress?.('verification-warning', `Code Issue: ${issue}`);
246
619
  }
247
- // Get next task
248
- nextTask = await getNextTask(projectDir);
249
620
  }
250
- // Check final status
251
- const progress = await getProgress(projectDir);
252
- if (failedTasks > 0) {
253
- state = await failProject(projectDir, `${failedTasks} tasks failed out of ${progress.totalTasks}`);
621
+ if (codeVerification.codeVerification.warnings.length > 0) {
622
+ for (const warning of codeVerification.codeVerification.warnings.slice(0, 3)) {
623
+ onProgress?.('verification-info', `Code Warning: ${warning}`);
624
+ }
625
+ }
626
+ // Summary
627
+ onProgress?.('verification-summary', `Verification complete: ${completedMilestones}/${state.milestones.length} milestones, ` +
628
+ `${completedTasks}/${allTasks.length} tasks, ` +
629
+ `${codeVerification.codeVerification.totalLinesOfCode} lines of code`);
630
+ // Check if genuinely complete
631
+ if (!codeVerification.isGenuinelyComplete) {
632
+ onProgress?.('verification-warning', 'WARNING: Project may not be genuinely complete. Code verification found issues.');
633
+ await logger.warn('verification', 'incomplete_code', 'Project may not be genuinely complete', {
634
+ taskComplete: codeVerification.taskVerification.isComplete,
635
+ codeQualityPassed: codeVerification.codeVerification.passed,
636
+ summary: codeVerification.summary,
637
+ });
638
+ }
639
+ // ============================================
640
+ // COMPREHENSIVE PROJECT VERIFICATION
641
+ // ============================================
642
+ onProgress?.('verification', 'Running comprehensive project verification...');
643
+ const comprehensiveReport = await runComprehensiveVerification(projectDir, (msg) => onProgress?.('verification', msg));
644
+ // Log verification results
645
+ for (const result of comprehensiveReport.results) {
646
+ if (!result.passed) {
647
+ const level = result.severity === 'error' ? 'verification-error' : 'verification-warning';
648
+ onProgress?.(level, `[${result.category}] ${result.message}`);
649
+ }
650
+ }
651
+ // Auto-fix fixable issues
652
+ if (comprehensiveReport.failedChecks > 0) {
653
+ const fixableCount = comprehensiveReport.results.filter(r => !r.passed && r.autoFixable).length;
654
+ if (fixableCount > 0) {
655
+ onProgress?.('verification', `Attempting to auto-fix ${fixableCount} issue(s)...`);
656
+ const fixed = await autoFixIssues(comprehensiveReport, (msg) => onProgress?.('verification', msg));
657
+ onProgress?.('verification', `Auto-fixed ${fixed} issue(s)`);
658
+ // Re-run verification after fixes
659
+ if (fixed > 0) {
660
+ onProgress?.('verification', 'Re-running verification after fixes...');
661
+ const reVerifyReport = await runComprehensiveVerification(projectDir);
662
+ if (reVerifyReport.failedChecks > 0) {
663
+ onProgress?.('verification-error', `${reVerifyReport.failedChecks} critical issue(s) remain after auto-fix`);
664
+ }
665
+ }
666
+ }
667
+ }
668
+ // Block completion if critical issues remain
669
+ if (comprehensiveReport.criticalIssues.length > 0) {
670
+ onProgress?.('verification-error', `BLOCKING: ${comprehensiveReport.criticalIssues.length} critical issue(s) found`);
671
+ for (const issue of comprehensiveReport.criticalIssues) {
672
+ onProgress?.('verification-error', ` - ${issue}`);
673
+ }
674
+ await logger.error('verification', 'critical_issues', 'Critical verification issues found', {
675
+ issues: comprehensiveReport.criticalIssues,
676
+ });
254
677
  return {
255
678
  success: false,
256
679
  state,
257
680
  completedTasks,
258
681
  failedTasks,
259
- error: `Execution completed with ${failedTasks} failed tasks`,
682
+ error: `Project verification failed: ${comprehensiveReport.criticalIssues.length} critical issues`,
260
683
  };
261
684
  }
262
- // All tasks complete
685
+ onProgress?.('verification', `Verification complete: ${comprehensiveReport.passedChecks}/${comprehensiveReport.totalChecks} checks passed`);
686
+ // ============================================
687
+ // GENERATE PROJECT README
688
+ // ============================================
689
+ onProgress?.('readme', 'Generating project README with setup and run instructions...');
690
+ const readmeResult = await generateProjectReadme(projectDir, state);
691
+ if (readmeResult.success) {
692
+ onProgress?.('readme', `README.md generated successfully`);
693
+ await logger.success('completion', 'readme_generated', 'Project README generated', {
694
+ path: readmeResult.path,
695
+ });
696
+ }
697
+ else {
698
+ onProgress?.('readme-warning', `Failed to generate README: ${readmeResult.error}`);
699
+ await logger.warn('completion', 'readme_failed', 'Failed to generate README', {
700
+ error: readmeResult.error,
701
+ });
702
+ }
703
+ // All milestones complete
263
704
  state = await completeProject(projectDir);
264
- onProgress?.('execution-complete', `Project complete! ${completedTasks} tasks executed successfully.`);
705
+ onProgress?.('execution-complete', `Project complete! ${completedMilestones} milestones, ${completedTasks} tasks executed successfully.`);
706
+ await logger.stageComplete('completion', 'Project execution completed successfully', {
707
+ completedMilestones: completedMilestones,
708
+ totalMilestones: state.milestones.length,
709
+ completedTasks: completedTasks,
710
+ totalTasks: state.milestones.reduce((sum, m) => sum + m.tasks.length, 0),
711
+ buildPassed: buildResult.success,
712
+ testsPassed: hasTests ? (await runTests(projectDir, state.language)).success : true,
713
+ });
265
714
  return {
266
715
  success: true,
267
716
  state,
@@ -272,6 +721,12 @@ export async function runExecutionMode(options) {
272
721
  catch (error) {
273
722
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
274
723
  onProgress?.('error', errorMessage);
724
+ await logger.stageFailed('execution', 'Execution Mode failed', errorMessage, {
725
+ errorType: error instanceof Error ? error.constructor.name : typeof error,
726
+ completedTasks: completedTasks,
727
+ failedTasks: failedTasks,
728
+ completedMilestones: completedMilestones,
729
+ });
275
730
  return {
276
731
  success: false,
277
732
  state: await loadProject(projectDir).catch(() => ({})),
@@ -288,27 +743,61 @@ export async function runExecutionMode(options) {
288
743
  * @returns Execution mode result
289
744
  */
290
745
  export async function resumeExecutionMode(options) {
291
- const state = await loadProject(options.projectDir);
292
- // Check current status
293
- if (state.status === 'complete') {
294
- return {
295
- success: true,
296
- state,
297
- completedTasks: state.milestones.flatMap((m) => m.tasks).filter((t) => t.status === 'complete').length,
298
- failedTasks: 0,
299
- };
746
+ const { projectDir, onProgress } = options;
747
+ let state = await loadProject(projectDir);
748
+ // Verify actual completion - don't trust status alone
749
+ const verification = await verifyProjectCompletion(projectDir);
750
+ const progress = verification.progress;
751
+ // Log current progress
752
+ onProgress?.('resume-analysis', `Current progress: ${progress.progressSummary}`);
753
+ // Check if actually complete
754
+ if (state.status === 'complete' || state.phase === 'complete') {
755
+ if (verification.isComplete) {
756
+ onProgress?.('resume-complete', 'Project is genuinely complete');
757
+ return {
758
+ success: true,
759
+ state,
760
+ completedTasks: progress.completedTasks,
761
+ failedTasks: 0,
762
+ };
763
+ }
764
+ // Status says complete but work is incomplete
765
+ onProgress?.('resume-mismatch', `Status mismatch detected: status='complete' but ${progress.completedTasks}/${progress.totalTasks} tasks done`);
766
+ // Reset incorrect status
767
+ state = await updateState(projectDir, {
768
+ status: 'in-progress',
769
+ phase: 'execution',
770
+ error: undefined,
771
+ });
772
+ onProgress?.('resume-reset', `Reset project status. Will continue with ${progress.pendingTasks + progress.failedTasks} remaining tasks`);
300
773
  }
301
774
  // Reset failed tasks to pending so they can be retried
302
- if (state.status === 'failed') {
775
+ if (state.status === 'failed' || progress.failedTasks > 0) {
303
776
  const updatedMilestones = state.milestones.map((m) => ({
304
777
  ...m,
778
+ // Also reset milestone status if needed
779
+ status: m.tasks.every(t => t.status === 'complete')
780
+ ? 'complete'
781
+ : m.tasks.some(t => t.status === 'complete' || t.status === 'in-progress')
782
+ ? 'in-progress'
783
+ : 'pending',
305
784
  tasks: m.tasks.map((t) => t.status === 'failed' ? { ...t, status: 'pending', error: undefined } : t),
306
785
  }));
307
- await updateState(options.projectDir, {
786
+ await updateState(projectDir, {
308
787
  milestones: updatedMilestones,
309
- status: 'pending',
788
+ status: 'in-progress',
310
789
  error: undefined,
311
790
  });
791
+ if (progress.failedTasks > 0) {
792
+ onProgress?.('resume-retry', `Reset ${progress.failedTasks} failed task(s) to pending for retry`);
793
+ }
794
+ }
795
+ // Show what will be worked on
796
+ if (progress.nextMilestone) {
797
+ onProgress?.('resume-next', `Next milestone: ${progress.nextMilestone.name}`);
798
+ }
799
+ if (progress.nextTask) {
800
+ onProgress?.('resume-next', `Next task: ${progress.nextTask.name} (in ${progress.nextTask.milestone})`);
312
801
  }
313
802
  return runExecutionMode(options);
314
803
  }