popeye-cli 2.2.0 → 2.7.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 (323) hide show
  1. package/dist/adapters/gemini.d.ts +14 -0
  2. package/dist/adapters/gemini.d.ts.map +1 -1
  3. package/dist/adapters/gemini.js +41 -6
  4. package/dist/adapters/gemini.js.map +1 -1
  5. package/dist/adapters/grok.d.ts +14 -0
  6. package/dist/adapters/grok.d.ts.map +1 -1
  7. package/dist/adapters/grok.js +42 -6
  8. package/dist/adapters/grok.js.map +1 -1
  9. package/dist/adapters/openai.d.ts +10 -0
  10. package/dist/adapters/openai.d.ts.map +1 -1
  11. package/dist/adapters/openai.js +44 -5
  12. package/dist/adapters/openai.js.map +1 -1
  13. package/dist/cli/commands/create.js +1 -1
  14. package/dist/cli/commands/create.js.map +1 -1
  15. package/dist/cli/interactive.d.ts.map +1 -1
  16. package/dist/cli/interactive.js +324 -20
  17. package/dist/cli/interactive.js.map +1 -1
  18. package/dist/generators/all.d.ts.map +1 -1
  19. package/dist/generators/all.js +3 -2
  20. package/dist/generators/all.js.map +1 -1
  21. package/dist/generators/doc-parser.d.ts +21 -6
  22. package/dist/generators/doc-parser.d.ts.map +1 -1
  23. package/dist/generators/doc-parser.js +55 -4
  24. package/dist/generators/doc-parser.js.map +1 -1
  25. package/dist/generators/templates/fullstack.js +1 -1
  26. package/dist/generators/templates/website-components.js +1 -1
  27. package/dist/generators/templates/website-components.js.map +1 -1
  28. package/dist/generators/templates/website-config.d.ts +4 -1
  29. package/dist/generators/templates/website-config.d.ts.map +1 -1
  30. package/dist/generators/templates/website-config.js +17 -11
  31. package/dist/generators/templates/website-config.js.map +1 -1
  32. package/dist/generators/templates/website-conversion.js +1 -1
  33. package/dist/generators/templates/website-conversion.js.map +1 -1
  34. package/dist/generators/templates/website-landing.js +1 -1
  35. package/dist/generators/templates/website-landing.js.map +1 -1
  36. package/dist/generators/templates/website-layout.d.ts +36 -4
  37. package/dist/generators/templates/website-layout.d.ts.map +1 -1
  38. package/dist/generators/templates/website-layout.js +466 -23
  39. package/dist/generators/templates/website-layout.js.map +1 -1
  40. package/dist/generators/templates/website-pricing.js +1 -1
  41. package/dist/generators/templates/website-pricing.js.map +1 -1
  42. package/dist/generators/templates/website-sections.js +1 -1
  43. package/dist/generators/templates/website-sections.js.map +1 -1
  44. package/dist/generators/templates/website-seo.d.ts.map +1 -1
  45. package/dist/generators/templates/website-seo.js +4 -1
  46. package/dist/generators/templates/website-seo.js.map +1 -1
  47. package/dist/generators/templates/website.d.ts +1 -1
  48. package/dist/generators/templates/website.d.ts.map +1 -1
  49. package/dist/generators/templates/website.js +1 -1
  50. package/dist/generators/templates/website.js.map +1 -1
  51. package/dist/generators/website-content-ai.d.ts +52 -0
  52. package/dist/generators/website-content-ai.d.ts.map +1 -0
  53. package/dist/generators/website-content-ai.js +141 -0
  54. package/dist/generators/website-content-ai.js.map +1 -0
  55. package/dist/generators/website-content-scanner.d.ts +1 -1
  56. package/dist/generators/website-content-scanner.d.ts.map +1 -1
  57. package/dist/generators/website-content-scanner.js +98 -1
  58. package/dist/generators/website-content-scanner.js.map +1 -1
  59. package/dist/generators/website-context.d.ts +34 -1
  60. package/dist/generators/website-context.d.ts.map +1 -1
  61. package/dist/generators/website-context.js +131 -9
  62. package/dist/generators/website-context.js.map +1 -1
  63. package/dist/generators/website-debug.d.ts +12 -0
  64. package/dist/generators/website-debug.d.ts.map +1 -1
  65. package/dist/generators/website-debug.js +16 -0
  66. package/dist/generators/website-debug.js.map +1 -1
  67. package/dist/generators/website.d.ts.map +1 -1
  68. package/dist/generators/website.js +26 -4
  69. package/dist/generators/website.js.map +1 -1
  70. package/dist/pipeline/auto-recovery.d.ts +56 -0
  71. package/dist/pipeline/auto-recovery.d.ts.map +1 -0
  72. package/dist/pipeline/auto-recovery.js +185 -0
  73. package/dist/pipeline/auto-recovery.js.map +1 -0
  74. package/dist/pipeline/change-request.d.ts +39 -0
  75. package/dist/pipeline/change-request.d.ts.map +1 -1
  76. package/dist/pipeline/change-request.js +40 -1
  77. package/dist/pipeline/change-request.js.map +1 -1
  78. package/dist/pipeline/check-runner.d.ts +30 -1
  79. package/dist/pipeline/check-runner.d.ts.map +1 -1
  80. package/dist/pipeline/check-runner.js +122 -1
  81. package/dist/pipeline/check-runner.js.map +1 -1
  82. package/dist/pipeline/command-resolver.d.ts.map +1 -1
  83. package/dist/pipeline/command-resolver.js +33 -2
  84. package/dist/pipeline/command-resolver.js.map +1 -1
  85. package/dist/pipeline/consensus/arbitrator-query.d.ts +22 -0
  86. package/dist/pipeline/consensus/arbitrator-query.d.ts.map +1 -0
  87. package/dist/pipeline/consensus/arbitrator-query.js +70 -0
  88. package/dist/pipeline/consensus/arbitrator-query.js.map +1 -0
  89. package/dist/pipeline/consensus/consensus-runner.d.ts +131 -7
  90. package/dist/pipeline/consensus/consensus-runner.d.ts.map +1 -1
  91. package/dist/pipeline/consensus/consensus-runner.js +809 -35
  92. package/dist/pipeline/consensus/consensus-runner.js.map +1 -1
  93. package/dist/pipeline/cr-lifecycle.d.ts +42 -0
  94. package/dist/pipeline/cr-lifecycle.d.ts.map +1 -0
  95. package/dist/pipeline/cr-lifecycle.js +89 -0
  96. package/dist/pipeline/cr-lifecycle.js.map +1 -0
  97. package/dist/pipeline/gate-engine.d.ts +1 -0
  98. package/dist/pipeline/gate-engine.d.ts.map +1 -1
  99. package/dist/pipeline/gate-engine.js +26 -7
  100. package/dist/pipeline/gate-engine.js.map +1 -1
  101. package/dist/pipeline/orchestrator.d.ts +1 -1
  102. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  103. package/dist/pipeline/orchestrator.js +306 -16
  104. package/dist/pipeline/orchestrator.js.map +1 -1
  105. package/dist/pipeline/packets/consensus-packet-builder.d.ts +15 -4
  106. package/dist/pipeline/packets/consensus-packet-builder.d.ts.map +1 -1
  107. package/dist/pipeline/packets/consensus-packet-builder.js +29 -17
  108. package/dist/pipeline/packets/consensus-packet-builder.js.map +1 -1
  109. package/dist/pipeline/phases/architecture.d.ts.map +1 -1
  110. package/dist/pipeline/phases/architecture.js +5 -3
  111. package/dist/pipeline/phases/architecture.js.map +1 -1
  112. package/dist/pipeline/phases/audit.d.ts.map +1 -1
  113. package/dist/pipeline/phases/audit.js +5 -3
  114. package/dist/pipeline/phases/audit.js.map +1 -1
  115. package/dist/pipeline/phases/consensus-architecture.d.ts.map +1 -1
  116. package/dist/pipeline/phases/consensus-architecture.js +10 -1
  117. package/dist/pipeline/phases/consensus-architecture.js.map +1 -1
  118. package/dist/pipeline/phases/consensus-master-plan.d.ts.map +1 -1
  119. package/dist/pipeline/phases/consensus-master-plan.js +10 -3
  120. package/dist/pipeline/phases/consensus-master-plan.js.map +1 -1
  121. package/dist/pipeline/phases/consensus-role-plans.d.ts.map +1 -1
  122. package/dist/pipeline/phases/consensus-role-plans.js +10 -1
  123. package/dist/pipeline/phases/consensus-role-plans.js.map +1 -1
  124. package/dist/pipeline/phases/done.d.ts.map +1 -1
  125. package/dist/pipeline/phases/done.js +9 -4
  126. package/dist/pipeline/phases/done.js.map +1 -1
  127. package/dist/pipeline/phases/intake.d.ts.map +1 -1
  128. package/dist/pipeline/phases/intake.js +7 -3
  129. package/dist/pipeline/phases/intake.js.map +1 -1
  130. package/dist/pipeline/phases/phase-context.d.ts +2 -0
  131. package/dist/pipeline/phases/phase-context.d.ts.map +1 -1
  132. package/dist/pipeline/phases/phase-context.js +3 -1
  133. package/dist/pipeline/phases/phase-context.js.map +1 -1
  134. package/dist/pipeline/phases/production-gate.d.ts.map +1 -1
  135. package/dist/pipeline/phases/production-gate.js +28 -3
  136. package/dist/pipeline/phases/production-gate.js.map +1 -1
  137. package/dist/pipeline/phases/qa-validation.d.ts.map +1 -1
  138. package/dist/pipeline/phases/qa-validation.js +38 -5
  139. package/dist/pipeline/phases/qa-validation.js.map +1 -1
  140. package/dist/pipeline/phases/recovery-loop.d.ts +2 -0
  141. package/dist/pipeline/phases/recovery-loop.d.ts.map +1 -1
  142. package/dist/pipeline/phases/recovery-loop.js +200 -6
  143. package/dist/pipeline/phases/recovery-loop.js.map +1 -1
  144. package/dist/pipeline/phases/review.d.ts.map +1 -1
  145. package/dist/pipeline/phases/review.js +58 -28
  146. package/dist/pipeline/phases/review.js.map +1 -1
  147. package/dist/pipeline/phases/role-planning.d.ts.map +1 -1
  148. package/dist/pipeline/phases/role-planning.js +18 -2
  149. package/dist/pipeline/phases/role-planning.js.map +1 -1
  150. package/dist/pipeline/phases/stuck.d.ts.map +1 -1
  151. package/dist/pipeline/phases/stuck.js +10 -0
  152. package/dist/pipeline/phases/stuck.js.map +1 -1
  153. package/dist/pipeline/repo-snapshot.d.ts.map +1 -1
  154. package/dist/pipeline/repo-snapshot.js +3 -0
  155. package/dist/pipeline/repo-snapshot.js.map +1 -1
  156. package/dist/pipeline/role-execution-adapter.d.ts +2 -1
  157. package/dist/pipeline/role-execution-adapter.d.ts.map +1 -1
  158. package/dist/pipeline/role-execution-adapter.js +22 -7
  159. package/dist/pipeline/role-execution-adapter.js.map +1 -1
  160. package/dist/pipeline/skill-loader.d.ts +19 -0
  161. package/dist/pipeline/skill-loader.d.ts.map +1 -1
  162. package/dist/pipeline/skill-loader.js +22 -0
  163. package/dist/pipeline/skill-loader.js.map +1 -1
  164. package/dist/pipeline/skills/coverage-gate.d.ts +44 -0
  165. package/dist/pipeline/skills/coverage-gate.d.ts.map +1 -0
  166. package/dist/pipeline/skills/coverage-gate.js +143 -0
  167. package/dist/pipeline/skills/coverage-gate.js.map +1 -0
  168. package/dist/pipeline/skills/usage-registry.d.ts +48 -0
  169. package/dist/pipeline/skills/usage-registry.d.ts.map +1 -0
  170. package/dist/pipeline/skills/usage-registry.js +55 -0
  171. package/dist/pipeline/skills/usage-registry.js.map +1 -0
  172. package/dist/pipeline/strategy-context.d.ts +20 -0
  173. package/dist/pipeline/strategy-context.d.ts.map +1 -0
  174. package/dist/pipeline/strategy-context.js +55 -0
  175. package/dist/pipeline/strategy-context.js.map +1 -0
  176. package/dist/pipeline/type-defs/artifacts.d.ts +25 -5
  177. package/dist/pipeline/type-defs/artifacts.d.ts.map +1 -1
  178. package/dist/pipeline/type-defs/artifacts.js +4 -0
  179. package/dist/pipeline/type-defs/artifacts.js.map +1 -1
  180. package/dist/pipeline/type-defs/audit.d.ts +25 -13
  181. package/dist/pipeline/type-defs/audit.d.ts.map +1 -1
  182. package/dist/pipeline/type-defs/checks.d.ts +18 -8
  183. package/dist/pipeline/type-defs/checks.d.ts.map +1 -1
  184. package/dist/pipeline/type-defs/checks.js +4 -0
  185. package/dist/pipeline/type-defs/checks.js.map +1 -1
  186. package/dist/pipeline/type-defs/packets.d.ts +104 -18
  187. package/dist/pipeline/type-defs/packets.d.ts.map +1 -1
  188. package/dist/pipeline/type-defs/packets.js +17 -1
  189. package/dist/pipeline/type-defs/packets.js.map +1 -1
  190. package/dist/pipeline/type-defs/state.d.ts +160 -16
  191. package/dist/pipeline/type-defs/state.d.ts.map +1 -1
  192. package/dist/pipeline/type-defs/state.js +26 -1
  193. package/dist/pipeline/type-defs/state.js.map +1 -1
  194. package/dist/shared/text-utils.d.ts +23 -0
  195. package/dist/shared/text-utils.d.ts.map +1 -0
  196. package/dist/shared/text-utils.js +66 -0
  197. package/dist/shared/text-utils.js.map +1 -0
  198. package/dist/shared/website-strategy-format.d.ts +18 -0
  199. package/dist/shared/website-strategy-format.d.ts.map +1 -0
  200. package/dist/shared/website-strategy-format.js +47 -0
  201. package/dist/shared/website-strategy-format.js.map +1 -0
  202. package/dist/state/index.d.ts +2 -0
  203. package/dist/state/index.d.ts.map +1 -1
  204. package/dist/state/index.js +57 -8
  205. package/dist/state/index.js.map +1 -1
  206. package/dist/types/consensus.d.ts +1 -0
  207. package/dist/types/consensus.d.ts.map +1 -1
  208. package/dist/types/consensus.js.map +1 -1
  209. package/dist/types/website-strategy.d.ts +1 -1
  210. package/dist/types/workflow.d.ts +447 -0
  211. package/dist/types/workflow.d.ts.map +1 -1
  212. package/dist/types/workflow.js +3 -0
  213. package/dist/types/workflow.js.map +1 -1
  214. package/dist/upgrade/handlers.d.ts.map +1 -1
  215. package/dist/upgrade/handlers.js +6 -3
  216. package/dist/upgrade/handlers.js.map +1 -1
  217. package/dist/workflow/consensus.d.ts.map +1 -1
  218. package/dist/workflow/consensus.js +1 -0
  219. package/dist/workflow/consensus.js.map +1 -1
  220. package/dist/workflow/website-strategy.d.ts.map +1 -1
  221. package/dist/workflow/website-strategy.js +2 -29
  222. package/dist/workflow/website-strategy.js.map +1 -1
  223. package/dist/workflow/website-updater.d.ts.map +1 -1
  224. package/dist/workflow/website-updater.js +3 -2
  225. package/dist/workflow/website-updater.js.map +1 -1
  226. package/package.json +1 -1
  227. package/src/adapters/gemini.ts +51 -6
  228. package/src/adapters/grok.ts +51 -6
  229. package/src/adapters/openai.ts +53 -5
  230. package/src/cli/commands/create.ts +1 -1
  231. package/src/cli/interactive.ts +333 -19
  232. package/src/generators/all.ts +3 -2
  233. package/src/generators/doc-parser.ts +75 -15
  234. package/src/generators/templates/fullstack.ts +1 -1
  235. package/src/generators/templates/website-components.ts +1 -1
  236. package/src/generators/templates/website-config.ts +23 -11
  237. package/src/generators/templates/website-conversion.ts +1 -1
  238. package/src/generators/templates/website-landing.ts +1 -1
  239. package/src/generators/templates/website-layout.ts +491 -23
  240. package/src/generators/templates/website-pricing.ts +1 -1
  241. package/src/generators/templates/website-sections.ts +1 -1
  242. package/src/generators/templates/website-seo.ts +4 -1
  243. package/src/generators/templates/website.ts +3 -0
  244. package/src/generators/website-content-ai.ts +186 -0
  245. package/src/generators/website-content-scanner.ts +113 -1
  246. package/src/generators/website-context.ts +151 -12
  247. package/src/generators/website-debug.ts +26 -0
  248. package/src/generators/website.ts +28 -3
  249. package/src/pipeline/auto-recovery.ts +283 -0
  250. package/src/pipeline/change-request.ts +63 -1
  251. package/src/pipeline/check-runner.ts +141 -2
  252. package/src/pipeline/command-resolver.ts +34 -2
  253. package/src/pipeline/consensus/arbitrator-query.ts +101 -0
  254. package/src/pipeline/consensus/consensus-runner.ts +1099 -42
  255. package/src/pipeline/cr-lifecycle.ts +103 -0
  256. package/src/pipeline/gate-engine.ts +35 -7
  257. package/src/pipeline/orchestrator.ts +361 -16
  258. package/src/pipeline/packets/consensus-packet-builder.ts +44 -18
  259. package/src/pipeline/phases/architecture.ts +6 -3
  260. package/src/pipeline/phases/audit.ts +6 -3
  261. package/src/pipeline/phases/consensus-architecture.ts +10 -1
  262. package/src/pipeline/phases/consensus-master-plan.ts +10 -3
  263. package/src/pipeline/phases/consensus-role-plans.ts +10 -1
  264. package/src/pipeline/phases/done.ts +15 -4
  265. package/src/pipeline/phases/intake.ts +7 -3
  266. package/src/pipeline/phases/phase-context.ts +6 -1
  267. package/src/pipeline/phases/production-gate.ts +41 -3
  268. package/src/pipeline/phases/qa-validation.ts +51 -5
  269. package/src/pipeline/phases/recovery-loop.ts +229 -7
  270. package/src/pipeline/phases/review.ts +73 -30
  271. package/src/pipeline/phases/role-planning.ts +21 -2
  272. package/src/pipeline/phases/stuck.ts +10 -0
  273. package/src/pipeline/repo-snapshot.ts +3 -0
  274. package/src/pipeline/role-execution-adapter.ts +30 -4
  275. package/src/pipeline/skill-loader.ts +33 -0
  276. package/src/pipeline/skills/coverage-gate.ts +199 -0
  277. package/src/pipeline/skills/usage-registry.ts +87 -0
  278. package/src/pipeline/strategy-context.ts +60 -0
  279. package/src/pipeline/type-defs/artifacts.ts +4 -0
  280. package/src/pipeline/type-defs/checks.ts +4 -0
  281. package/src/pipeline/type-defs/packets.ts +18 -1
  282. package/src/pipeline/type-defs/state.ts +26 -1
  283. package/src/shared/text-utils.ts +70 -0
  284. package/src/shared/website-strategy-format.ts +56 -0
  285. package/src/state/index.ts +60 -8
  286. package/src/types/consensus.ts +1 -0
  287. package/src/types/workflow.ts +6 -0
  288. package/src/upgrade/handlers.ts +9 -3
  289. package/src/workflow/consensus.ts +1 -0
  290. package/src/workflow/website-strategy.ts +2 -36
  291. package/src/workflow/website-updater.ts +4 -2
  292. package/tests/adapters/gemini.test.ts +165 -0
  293. package/tests/adapters/grok.test.ts +137 -0
  294. package/tests/adapters/openai.test.ts +128 -0
  295. package/tests/generators/doc-parser.test.ts +88 -9
  296. package/tests/generators/quality-gate.test.ts +19 -3
  297. package/tests/generators/website-components.test.ts +34 -0
  298. package/tests/generators/website-content-ai.test.ts +308 -0
  299. package/tests/generators/website-content-scanner.test.ts +86 -0
  300. package/tests/generators/website-context.test.ts +3 -2
  301. package/tests/integration/smokestack-scaffold.test.ts +385 -0
  302. package/tests/pipeline/auto-recovery.test.ts +337 -0
  303. package/tests/pipeline/change-request.test.ts +70 -0
  304. package/tests/pipeline/command-resolver.test.ts +42 -0
  305. package/tests/pipeline/consensus/arbitrator-query.test.ts +107 -0
  306. package/tests/pipeline/consensus-runner.test.ts +1333 -10
  307. package/tests/pipeline/consensus-scoring.test.ts +602 -18
  308. package/tests/pipeline/gate-engine.test.ts +34 -0
  309. package/tests/pipeline/install-check.test.ts +261 -0
  310. package/tests/pipeline/orchestrator.test.ts +1506 -15
  311. package/tests/pipeline/packets/builders.test.ts +29 -6
  312. package/tests/pipeline/phases/role-planning.strategy.test.ts +204 -0
  313. package/tests/pipeline/pipeline-persistence.test.ts +230 -0
  314. package/tests/pipeline/recovery-loop-guidance.test.ts +280 -0
  315. package/tests/pipeline/role-execution-adapter.test.ts +88 -0
  316. package/tests/pipeline/skills/coverage-gate.test.ts +370 -0
  317. package/tests/pipeline/skills/usage-registry.test.ts +114 -0
  318. package/tests/pipeline/strategy-context.test.ts +148 -0
  319. package/tests/shared/text-utils.test.ts +155 -0
  320. package/tests/state/progress-analysis.test.ts +375 -0
  321. package/tests/upgrade/handlers.test.ts +33 -2
  322. package/tests/workflow/consensus.test.ts +6 -0
  323. package/tsconfig.json +1 -1
@@ -578,6 +578,10 @@ export interface ProjectProgressAnalysis {
578
578
  statusMismatch: boolean; // true if status='complete' but work is incomplete
579
579
  planMismatch: boolean; // true if plan file has more tasks than state
580
580
 
581
+ // Pipeline state (when applicable)
582
+ pipelinePhase?: string; // Current pipeline phase (e.g. 'DONE', 'STUCK', 'IMPLEMENTATION')
583
+ pipelineTerminal: boolean; // true if pipeline is in DONE or STUCK state
584
+
581
585
  // Milestone breakdown (from state)
582
586
  totalMilestones: number;
583
587
  completedMilestones: number;
@@ -780,14 +784,42 @@ export async function analyzeProjectProgress(projectDir: string): Promise<Projec
780
784
  : 0;
781
785
 
782
786
  // Determine if actually complete - must match plan if plan has more tasks
783
- const isActuallyComplete = totalMilestones > 0 &&
784
- completedMilestones === totalMilestones &&
785
- completedTasks === totalTasks &&
786
- !planMismatch; // Can't be complete if plan has more tasks
787
+ // v2.4.6: When no milestones/tasks exist in state but project was explicitly
788
+ // marked complete (status='complete' + phase='complete'), trust the status.
789
+ // completeProject() only sets both to 'complete' after build verification passes.
790
+ const noTrackingData = totalMilestones === 0 && totalTasks === 0;
791
+ const explicitlyCompleted = state.status === 'complete' && state.phase === 'complete';
792
+
793
+ // Pipeline state detection — pipeline truth overrides milestone truth.
794
+ // RECOVERY_LOOP is treated as stuck-like: the pipeline was interrupted mid-recovery
795
+ // and will just re-fail without new guidance.
796
+ const pipelinePhase = state.pipeline?.pipelinePhase;
797
+ const pipelineStuckLike = pipelinePhase === 'STUCK' || pipelinePhase === 'RECOVERY_LOOP';
798
+ const pipelineTerminal = pipelinePhase === 'DONE' || pipelineStuckLike;
799
+ const pipelineDone = pipelinePhase === 'DONE';
800
+
801
+ let isActuallyComplete: boolean;
802
+ if (noTrackingData && pipelinePhase) {
803
+ // Pipeline project: pipeline state is the source of truth.
804
+ // DONE = complete, STUCK = not complete.
805
+ // planMismatch is irrelevant — pipeline projects don't track milestones.
806
+ isActuallyComplete = pipelineDone;
807
+ } else if (noTrackingData) {
808
+ // Legacy project with no tracking: trust explicit completion only
809
+ isActuallyComplete = explicitlyCompleted && !planMismatch;
810
+ } else {
811
+ // Standard milestone-based: all milestones + tasks must be complete
812
+ isActuallyComplete = totalMilestones > 0 &&
813
+ completedMilestones === totalMilestones &&
814
+ completedTasks === totalTasks &&
815
+ !planMismatch; // Can't be complete if plan has more tasks
816
+ }
787
817
 
788
- // Check for status mismatch
818
+ // Check for status mismatch.
819
+ // Pipeline terminal states are handled separately — not "mismatches".
789
820
  const statusMismatch = (state.status === 'complete' || state.phase === 'complete') &&
790
- (!isActuallyComplete || planMismatch);
821
+ (!isActuallyComplete || planMismatch) &&
822
+ !pipelineTerminal;
791
823
 
792
824
  // Find next items to work on
793
825
  let nextMilestone: { id: string; name: string } | undefined;
@@ -836,6 +868,15 @@ export async function analyzeProjectProgress(projectDir: string): Promise<Projec
836
868
  if (planMismatch) {
837
869
  progressSummary = `PLAN MISMATCH: State has ${completedTasks}/${totalTasks} tasks but plan has ${planTaskCount} tasks. ` +
838
870
  `Only ${percentComplete}% of plan completed.`;
871
+ } else if (isActuallyComplete && pipelineDone && noTrackingData) {
872
+ progressSummary = 'Project completed via pipeline';
873
+ } else if (isActuallyComplete && noTrackingData) {
874
+ progressSummary = 'Project completed (no milestone tracking data)';
875
+ } else if (pipelineStuckLike) {
876
+ const failedAt = state.pipeline?.failedPhase ?? 'unknown';
877
+ const recoveryCount = state.pipeline?.recoveryCount ?? 0;
878
+ const label = pipelinePhase === 'RECOVERY_LOOP' ? 'PIPELINE STUCK (in recovery)' : 'PIPELINE STUCK';
879
+ progressSummary = `${label}: Failed at ${failedAt} after ${recoveryCount} recovery attempts`;
839
880
  } else if (isActuallyComplete) {
840
881
  progressSummary = `All ${totalTasks} tasks complete across ${totalMilestones} milestones`;
841
882
  } else if (statusMismatch) {
@@ -848,6 +889,8 @@ export async function analyzeProjectProgress(projectDir: string): Promise<Projec
848
889
  isActuallyComplete,
849
890
  statusMismatch,
850
891
  planMismatch,
892
+ pipelinePhase,
893
+ pipelineTerminal,
851
894
  totalMilestones,
852
895
  completedMilestones,
853
896
  inProgressMilestones,
@@ -927,6 +970,15 @@ export async function verifyProjectCompletion(projectDir: string): Promise<{
927
970
  * @returns Updated state
928
971
  */
929
972
  export async function resetIncompleteProject(projectDir: string): Promise<ProjectState> {
973
+ const current = await loadProject(projectDir);
974
+
975
+ // Pipeline projects should not be reset via legacy path —
976
+ // legacy reset changes phase/status but not pipeline.pipelinePhase,
977
+ // creating inconsistent state. Pipeline resume handles its own recovery.
978
+ if (current.pipeline?.pipelinePhase) {
979
+ return current;
980
+ }
981
+
930
982
  const verification = await verifyProjectCompletion(projectDir);
931
983
 
932
984
  if (verification.isComplete) {
@@ -955,8 +1007,8 @@ export async function resetIncompleteProject(projectDir: string): Promise<Projec
955
1007
  }
956
1008
 
957
1009
  // Reset any failed tasks to pending for retry
958
- const current = await loadProject(projectDir);
959
- const updatedMilestones = current.milestones.map(m => ({
1010
+ const latestState = await loadProject(projectDir);
1011
+ const updatedMilestones = latestState.milestones.map(m => ({
960
1012
  ...m,
961
1013
  // Reset milestone status if it was incorrectly marked complete
962
1014
  status: m.tasks.every(t => t.status === 'complete')
@@ -35,6 +35,7 @@ export interface ConsensusResult {
35
35
  analysis: string;
36
36
  strengths: string[];
37
37
  concerns: string[];
38
+ blockingIssues: string[];
38
39
  recommendations: string[];
39
40
  approved: boolean;
40
41
  rawResponse: string;
@@ -11,6 +11,8 @@ import type { TestPlanOutput } from './tester.js';
11
11
  import { TestPlanOutputSchema, TestVerdictSchema } from './tester.js';
12
12
  import type { DbConfig } from './database.js';
13
13
  import { DbConfigSchema } from './database.js';
14
+ import { PipelineStateSchema } from '../pipeline/types.js';
15
+ import type { PipelineState } from '../pipeline/types.js';
14
16
 
15
17
  /**
16
18
  * Workflow phases
@@ -244,6 +246,8 @@ export interface ProjectState {
244
246
  auditLastRunAt?: string;
245
247
  /** Unique identifier for the audit run */
246
248
  auditRunId?: string;
249
+ /** Pipeline execution state — persisted for resume across sessions (v2.4.5) */
250
+ pipeline?: PipelineState;
247
251
  }
248
252
 
249
253
  /**
@@ -271,6 +275,7 @@ export const ProjectStateSchema = z.object({
271
275
  analysis: z.string(),
272
276
  strengths: z.array(z.string()),
273
277
  concerns: z.array(z.string()),
278
+ blockingIssues: z.array(z.string()).default([]),
274
279
  recommendations: z.array(z.string()),
275
280
  approved: z.boolean(),
276
281
  rawResponse: z.string(),
@@ -296,6 +301,7 @@ export const ProjectStateSchema = z.object({
296
301
  auditRecoveryInProgress: z.boolean().optional(),
297
302
  auditLastRunAt: z.string().optional(),
298
303
  auditRunId: z.string().optional(),
304
+ pipeline: PipelineStateSchema.optional(),
299
305
  });
300
306
 
301
307
  /**
@@ -21,7 +21,7 @@ import {
21
21
  generateRootDockerCompose,
22
22
  } from '../generators/templates/fullstack.js';
23
23
  import { loadState, saveState } from '../state/persistence.js';
24
- import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext } from '../generators/website-context.js';
24
+ import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext, extractDocPathsFromText } from '../generators/website-context.js';
25
25
  import type { WebsiteContentContext } from '../generators/website-context.js';
26
26
  import { resolveWorkspaceRoot } from '../generators/workspace-root.js';
27
27
  import { loadWebsiteStrategy } from '../workflow/website-strategy.js';
@@ -61,11 +61,17 @@ export async function buildUpgradeContentContext(
61
61
  projectName: string,
62
62
  ): Promise<{ context?: WebsiteContentContext; warning?: string }> {
63
63
  try {
64
+ // Load state once for idea text + brand context
65
+ const state = await loadState(projectDir);
66
+
64
67
  // Build context from user docs (scans projectDir + parent via getScanDirectories)
65
- const context = await buildWebsiteContext(projectDir, projectName);
68
+ // Extract extra doc paths from state idea text if available
69
+ const extraDocPaths = state?.idea ? extractDocPathsFromText(state.idea) : [];
70
+ const context = await buildWebsiteContext(
71
+ projectDir, projectName, state?.specification ?? state?.idea, extraDocPaths,
72
+ );
66
73
 
67
74
  // Apply brand context from state if available
68
- const state = await loadState(projectDir);
69
75
  if (state?.brandContext?.primaryColor) {
70
76
  context.brand = { ...context.brand, primaryColor: state.brandContext.primaryColor };
71
77
  }
@@ -1176,6 +1176,7 @@ export async function runOptimizedConsensusProcess(
1176
1176
  score: combinedScore,
1177
1177
  analysis: combinedAnalysis,
1178
1178
  concerns: allConcerns,
1179
+ blockingIssues: [],
1179
1180
  recommendations: allRecommendations,
1180
1181
  approved: combinedScore >= threshold,
1181
1182
  strengths: [],
@@ -13,6 +13,7 @@ import type {
13
13
  BrandAssetsContract,
14
14
  } from '../types/website-strategy.js';
15
15
  import { WebsiteStrategySchema } from '../types/website-strategy.js';
16
+ import { formatWebsiteStrategy } from '../shared/website-strategy-format.js';
16
17
  import { createClient } from '../adapters/openai.js';
17
18
 
18
19
  /** File name for persisted strategy */
@@ -187,42 +188,7 @@ Respond with ONLY valid JSON, no markdown code fences or explanation.`;
187
188
  export function formatStrategyForPlanContext(
188
189
  strategy: WebsiteStrategyDocument
189
190
  ): string {
190
- const lines: string[] = [];
191
-
192
- lines.push(`### Target Customer`);
193
- lines.push(`- Persona: ${strategy.icp.primaryPersona}`);
194
- lines.push(`- Pain points: ${strategy.icp.painPoints.join(', ')}`);
195
- lines.push('');
196
-
197
- lines.push(`### Positioning`);
198
- lines.push(`- Category: ${strategy.positioning.category}`);
199
- lines.push(`- Value proposition: ${strategy.positioning.valueProposition}`);
200
- lines.push(`- Differentiators: ${strategy.positioning.differentiators.join(', ')}`);
201
- lines.push('');
202
-
203
- lines.push(`### Messaging`);
204
- lines.push(`- Headline: ${strategy.messaging.headline}`);
205
- lines.push(`- Subheadline: ${strategy.messaging.subheadline}`);
206
- lines.push('');
207
-
208
- lines.push(`### SEO Keywords`);
209
- lines.push(`- Primary: ${strategy.seoStrategy.primaryKeywords.join(', ')}`);
210
- lines.push(`- Secondary: ${strategy.seoStrategy.secondaryKeywords.join(', ')}`);
211
- lines.push('');
212
-
213
- lines.push(`### Site Architecture`);
214
- for (const page of strategy.siteArchitecture.pages) {
215
- lines.push(`- ${page.path} (${page.pageType}): ${page.purpose}`);
216
- }
217
- lines.push('');
218
-
219
- lines.push(`### Conversion Strategy`);
220
- lines.push(`- Primary CTA: "${strategy.conversionStrategy.primaryCta.text}" -> ${strategy.conversionStrategy.primaryCta.href}`);
221
- lines.push(`- Secondary CTA: "${strategy.conversionStrategy.secondaryCta.text}" -> ${strategy.conversionStrategy.secondaryCta.href}`);
222
- lines.push(`- Trust signals: ${strategy.conversionStrategy.trustSignals.join(', ')}`);
223
- lines.push(`- Lead capture: ${strategy.conversionStrategy.leadCapture}`);
224
-
225
- return lines.join('\n');
191
+ return formatWebsiteStrategy(strategy);
226
192
  }
227
193
 
228
194
  /**
@@ -9,7 +9,7 @@ import path from 'node:path';
9
9
  import type { ProjectState } from '../types/workflow.js';
10
10
  import type { OutputLanguage } from '../types/project.js';
11
11
  import { isWorkspace } from '../types/project.js';
12
- import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext } from '../generators/website-context.js';
12
+ import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext, extractDocPathsFromText } from '../generators/website-context.js';
13
13
  import { resolveWorkspaceRoot } from '../generators/workspace-root.js';
14
14
  import { generateWebsiteLandingPage } from '../generators/templates/website-landing.js';
15
15
  import { generateWebsitePricingPage } from '../generators/templates/website-pricing.js';
@@ -52,10 +52,12 @@ export async function updateWebsiteContent(
52
52
 
53
53
  // Build content context from user docs and specification
54
54
  const parentDir = path.dirname(projectDir);
55
+ const extraDocPaths = state.idea ? extractDocPathsFromText(state.idea) : [];
55
56
  const context = await buildWebsiteContext(
56
57
  parentDir,
57
58
  state.name,
58
- state.specification
59
+ state.specification,
60
+ extraDocPaths,
59
61
  );
60
62
 
61
63
  // Apply brand context from state if available
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Tests for Gemini adapter - parseConsensusResponse
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import { parseConsensusResponse } from '../../src/adapters/gemini.js';
7
+
8
+ describe('Gemini parseConsensusResponse', () => {
9
+ it('should parse a complete response with blocking issues', () => {
10
+ const response = `
11
+ ANALYSIS:
12
+ Well-structured plan with clear goals.
13
+
14
+ STRENGTHS:
15
+ - Good module separation
16
+ - Clear API design
17
+
18
+ CONCERNS:
19
+ - Consider adding rate limiting
20
+
21
+ BLOCKING_ISSUES:
22
+ - Missing authentication middleware
23
+ - No input validation strategy
24
+
25
+ RECOMMENDATIONS:
26
+ - Add rate limiting middleware
27
+
28
+ CONSENSUS: 72%
29
+ `;
30
+
31
+ const result = parseConsensusResponse(response);
32
+
33
+ expect(result.score).toBe(72);
34
+ expect(result.approved).toBe(false);
35
+ expect(result.concerns).toEqual(['Consider adding rate limiting']);
36
+ expect(result.blockingIssues).toEqual([
37
+ 'Missing authentication middleware',
38
+ 'No input validation strategy',
39
+ ]);
40
+ expect(result.recommendations).toEqual(['Add rate limiting middleware']);
41
+ });
42
+
43
+ it('should return empty blocking issues when "None"', () => {
44
+ const response = `
45
+ ANALYSIS:
46
+ Excellent plan.
47
+
48
+ STRENGTHS:
49
+ - Comprehensive coverage
50
+
51
+ CONCERNS:
52
+ - Minor naming inconsistencies
53
+
54
+ BLOCKING_ISSUES:
55
+ - None
56
+
57
+ RECOMMENDATIONS:
58
+ - Standardize naming conventions
59
+
60
+ CONSENSUS: 96%
61
+ `;
62
+
63
+ const result = parseConsensusResponse(response);
64
+
65
+ expect(result.score).toBe(96);
66
+ expect(result.approved).toBe(true);
67
+ expect(result.blockingIssues).toEqual([]);
68
+ expect(result.concerns).toHaveLength(1);
69
+ });
70
+
71
+ it('should handle missing BLOCKING_ISSUES section (backward compat)', () => {
72
+ const response = `
73
+ ANALYSIS:
74
+ Good plan overall.
75
+
76
+ STRENGTHS:
77
+ - Solid architecture design
78
+
79
+ CONCERNS:
80
+ - Some performance issue to watch
81
+
82
+ RECOMMENDATIONS:
83
+ - Optimize database queries
84
+
85
+ CONSENSUS: 88%
86
+ `;
87
+
88
+ const result = parseConsensusResponse(response);
89
+
90
+ expect(result.blockingIssues).toEqual([]);
91
+ expect(result.score).toBe(88);
92
+ });
93
+
94
+ it('should filter none-variant blocking issues like "No blocking issues found"', () => {
95
+ const response = `
96
+ ANALYSIS:
97
+ Good plan with solid foundation.
98
+
99
+ STRENGTHS:
100
+ - Clean design
101
+
102
+ CONCERNS:
103
+ - Minor performance concern
104
+
105
+ BLOCKING_ISSUES:
106
+ - No blocking issues found
107
+
108
+ RECOMMENDATIONS:
109
+ - Optimize queries
110
+
111
+ CONSENSUS: 91%
112
+ `;
113
+ const result = parseConsensusResponse(response);
114
+ expect(result.blockingIssues).toEqual([]);
115
+ });
116
+
117
+ it('should filter "None identified" from blocking issues', () => {
118
+ const response = `
119
+ ANALYSIS:
120
+ Thorough review complete.
121
+
122
+ STRENGTHS:
123
+ - Well-structured code
124
+
125
+ CONCERNS:
126
+ - Could use more tests
127
+
128
+ BLOCKING_ISSUES:
129
+ - None identified
130
+
131
+ RECOMMENDATIONS:
132
+ - Add integration tests
133
+
134
+ CONSENSUS: 89%
135
+ `;
136
+ const result = parseConsensusResponse(response);
137
+ expect(result.blockingIssues).toEqual([]);
138
+ });
139
+
140
+ it('should handle ALL-CAPS format for blocking issues', () => {
141
+ const response = `
142
+ ANALYSIS:
143
+ Detailed review of the plan.
144
+
145
+ STRENGTHS:
146
+ - Good structure
147
+
148
+ CONCERNS:
149
+ - Minor issue noted
150
+
151
+ BLOCKING_ISSUES:
152
+ - Critical security flaw
153
+
154
+ RECOMMENDATIONS:
155
+ - Fix security
156
+
157
+ CONSENSUS: 60%
158
+ `;
159
+
160
+ const result = parseConsensusResponse(response);
161
+
162
+ expect(result.blockingIssues).toEqual(['Critical security flaw']);
163
+ expect(result.recommendations).toEqual(['Fix security']);
164
+ });
165
+ });
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Tests for Grok adapter - parseConsensusResponse
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import { parseConsensusResponse } from '../../src/adapters/grok.js';
7
+
8
+ describe('Grok parseConsensusResponse', () => {
9
+ it('should parse a complete response with blocking issues', () => {
10
+ const response = `
11
+ ANALYSIS:
12
+ Solid plan with room for improvement.
13
+
14
+ STRENGTHS:
15
+ - Clean API design
16
+ - Good test coverage plan
17
+
18
+ CONCERNS:
19
+ - Consider adding monitoring
20
+
21
+ BLOCKING_ISSUES:
22
+ - Missing database migration strategy
23
+ - No rollback plan defined
24
+
25
+ RECOMMENDATIONS:
26
+ - Add observability layer
27
+
28
+ CONSENSUS: 70%
29
+ `;
30
+
31
+ const result = parseConsensusResponse(response);
32
+
33
+ expect(result.score).toBe(70);
34
+ expect(result.approved).toBe(false);
35
+ expect(result.concerns).toEqual(['Consider adding monitoring']);
36
+ expect(result.blockingIssues).toEqual([
37
+ 'Missing database migration strategy',
38
+ 'No rollback plan defined',
39
+ ]);
40
+ });
41
+
42
+ it('should return empty blocking issues when "None"', () => {
43
+ const response = `
44
+ ANALYSIS:
45
+ Great plan.
46
+
47
+ STRENGTHS:
48
+ - Well-structured
49
+
50
+ CONCERNS:
51
+ - Minor style inconsistencies
52
+
53
+ BLOCKING_ISSUES:
54
+ - None
55
+
56
+ RECOMMENDATIONS:
57
+ - Apply consistent formatting
58
+
59
+ CONSENSUS: 95%
60
+ `;
61
+
62
+ const result = parseConsensusResponse(response);
63
+
64
+ expect(result.score).toBe(95);
65
+ expect(result.approved).toBe(true);
66
+ expect(result.blockingIssues).toEqual([]);
67
+ });
68
+
69
+ it('should filter none-variant blocking issues like "No blocking issues found"', () => {
70
+ const response = `
71
+ ANALYSIS:
72
+ Solid implementation plan.
73
+
74
+ STRENGTHS:
75
+ - Good architecture
76
+
77
+ CONCERNS:
78
+ - Consider monitoring
79
+
80
+ BLOCKING_ISSUES:
81
+ - No blocking issues found
82
+
83
+ RECOMMENDATIONS:
84
+ - Add monitoring
85
+
86
+ CONSENSUS: 93%
87
+ `;
88
+ const result = parseConsensusResponse(response);
89
+ expect(result.blockingIssues).toEqual([]);
90
+ });
91
+
92
+ it('should filter "None identified" from blocking issues', () => {
93
+ const response = `
94
+ ANALYSIS:
95
+ Well-considered approach.
96
+
97
+ STRENGTHS:
98
+ - Comprehensive coverage
99
+
100
+ CONCERNS:
101
+ - Minor style issues
102
+
103
+ BLOCKING_ISSUES:
104
+ - None identified
105
+
106
+ RECOMMENDATIONS:
107
+ - Standardize formatting
108
+
109
+ CONSENSUS: 91%
110
+ `;
111
+ const result = parseConsensusResponse(response);
112
+ expect(result.blockingIssues).toEqual([]);
113
+ });
114
+
115
+ it('should handle missing BLOCKING_ISSUES section (backward compat)', () => {
116
+ const response = `
117
+ ANALYSIS:
118
+ Reasonable plan.
119
+
120
+ STRENGTHS:
121
+ - Good overall approach
122
+
123
+ CONCERNS:
124
+ - Needs more detail
125
+
126
+ RECOMMENDATIONS:
127
+ - Expand on implementation details
128
+
129
+ CONSENSUS: 82%
130
+ `;
131
+
132
+ const result = parseConsensusResponse(response);
133
+
134
+ expect(result.blockingIssues).toEqual([]);
135
+ expect(result.score).toBe(82);
136
+ });
137
+ });