red64-cli 0.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 (354) hide show
  1. package/README.md +454 -0
  2. package/dist/cli/parseArgs.d.ts +16 -0
  3. package/dist/cli/parseArgs.d.ts.map +1 -0
  4. package/dist/cli/parseArgs.js +172 -0
  5. package/dist/cli/parseArgs.js.map +1 -0
  6. package/dist/cli/validateFlags.d.ts +22 -0
  7. package/dist/cli/validateFlags.d.ts.map +1 -0
  8. package/dist/cli/validateFlags.js +24 -0
  9. package/dist/cli/validateFlags.js.map +1 -0
  10. package/dist/cli.d.ts +7 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +90 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/components/App.d.ts +20 -0
  15. package/dist/components/App.d.ts.map +1 -0
  16. package/dist/components/App.js +35 -0
  17. package/dist/components/App.js.map +1 -0
  18. package/dist/components/CommandRouter.d.ts +21 -0
  19. package/dist/components/CommandRouter.d.ts.map +1 -0
  20. package/dist/components/CommandRouter.js +30 -0
  21. package/dist/components/CommandRouter.js.map +1 -0
  22. package/dist/components/GlobalConfig.d.ts +26 -0
  23. package/dist/components/GlobalConfig.d.ts.map +1 -0
  24. package/dist/components/GlobalConfig.js +30 -0
  25. package/dist/components/GlobalConfig.js.map +1 -0
  26. package/dist/components/index.d.ts +9 -0
  27. package/dist/components/index.d.ts.map +1 -0
  28. package/dist/components/index.js +9 -0
  29. package/dist/components/index.js.map +1 -0
  30. package/dist/components/init/CompleteStep.d.ts +11 -0
  31. package/dist/components/init/CompleteStep.d.ts.map +1 -0
  32. package/dist/components/init/CompleteStep.js +15 -0
  33. package/dist/components/init/CompleteStep.js.map +1 -0
  34. package/dist/components/init/ErrorStep.d.ts +14 -0
  35. package/dist/components/init/ErrorStep.d.ts.map +1 -0
  36. package/dist/components/init/ErrorStep.js +36 -0
  37. package/dist/components/init/ErrorStep.js.map +1 -0
  38. package/dist/components/init/FetchStep.d.ts +15 -0
  39. package/dist/components/init/FetchStep.d.ts.map +1 -0
  40. package/dist/components/init/FetchStep.js +33 -0
  41. package/dist/components/init/FetchStep.js.map +1 -0
  42. package/dist/components/init/SetupStep.d.ts +14 -0
  43. package/dist/components/init/SetupStep.d.ts.map +1 -0
  44. package/dist/components/init/SetupStep.js +78 -0
  45. package/dist/components/init/SetupStep.js.map +1 -0
  46. package/dist/components/init/SteeringStep.d.ts +12 -0
  47. package/dist/components/init/SteeringStep.d.ts.map +1 -0
  48. package/dist/components/init/SteeringStep.js +43 -0
  49. package/dist/components/init/SteeringStep.js.map +1 -0
  50. package/dist/components/init/WelcomeStep.d.ts +12 -0
  51. package/dist/components/init/WelcomeStep.d.ts.map +1 -0
  52. package/dist/components/init/WelcomeStep.js +52 -0
  53. package/dist/components/init/WelcomeStep.js.map +1 -0
  54. package/dist/components/init/index.d.ts +11 -0
  55. package/dist/components/init/index.d.ts.map +1 -0
  56. package/dist/components/init/index.js +10 -0
  57. package/dist/components/init/index.js.map +1 -0
  58. package/dist/components/init/types.d.ts +98 -0
  59. package/dist/components/init/types.d.ts.map +1 -0
  60. package/dist/components/init/types.js +6 -0
  61. package/dist/components/init/types.js.map +1 -0
  62. package/dist/components/screens/AbortScreen.d.ts +14 -0
  63. package/dist/components/screens/AbortScreen.d.ts.map +1 -0
  64. package/dist/components/screens/AbortScreen.js +181 -0
  65. package/dist/components/screens/AbortScreen.js.map +1 -0
  66. package/dist/components/screens/ApprovalScreen.d.ts +24 -0
  67. package/dist/components/screens/ApprovalScreen.d.ts.map +1 -0
  68. package/dist/components/screens/ApprovalScreen.js +82 -0
  69. package/dist/components/screens/ApprovalScreen.js.map +1 -0
  70. package/dist/components/screens/HelpScreen.d.ts +20 -0
  71. package/dist/components/screens/HelpScreen.d.ts.map +1 -0
  72. package/dist/components/screens/HelpScreen.js +70 -0
  73. package/dist/components/screens/HelpScreen.js.map +1 -0
  74. package/dist/components/screens/InitScreen.d.ts +15 -0
  75. package/dist/components/screens/InitScreen.d.ts.map +1 -0
  76. package/dist/components/screens/InitScreen.js +420 -0
  77. package/dist/components/screens/InitScreen.js.map +1 -0
  78. package/dist/components/screens/ListScreen.d.ts +14 -0
  79. package/dist/components/screens/ListScreen.d.ts.map +1 -0
  80. package/dist/components/screens/ListScreen.js +57 -0
  81. package/dist/components/screens/ListScreen.js.map +1 -0
  82. package/dist/components/screens/ProgressScreen.d.ts +26 -0
  83. package/dist/components/screens/ProgressScreen.d.ts.map +1 -0
  84. package/dist/components/screens/ProgressScreen.js +64 -0
  85. package/dist/components/screens/ProgressScreen.js.map +1 -0
  86. package/dist/components/screens/ResumeScreen.d.ts +14 -0
  87. package/dist/components/screens/ResumeScreen.d.ts.map +1 -0
  88. package/dist/components/screens/ResumeScreen.js +108 -0
  89. package/dist/components/screens/ResumeScreen.js.map +1 -0
  90. package/dist/components/screens/ScreenProps.d.ts +12 -0
  91. package/dist/components/screens/ScreenProps.d.ts.map +1 -0
  92. package/dist/components/screens/ScreenProps.js +5 -0
  93. package/dist/components/screens/ScreenProps.js.map +1 -0
  94. package/dist/components/screens/StartScreen.d.ts +26 -0
  95. package/dist/components/screens/StartScreen.d.ts.map +1 -0
  96. package/dist/components/screens/StartScreen.js +1021 -0
  97. package/dist/components/screens/StartScreen.js.map +1 -0
  98. package/dist/components/screens/StatusScreen.d.ts +14 -0
  99. package/dist/components/screens/StatusScreen.d.ts.map +1 -0
  100. package/dist/components/screens/StatusScreen.js +115 -0
  101. package/dist/components/screens/StatusScreen.js.map +1 -0
  102. package/dist/components/screens/index.d.ts +15 -0
  103. package/dist/components/screens/index.d.ts.map +1 -0
  104. package/dist/components/screens/index.js +12 -0
  105. package/dist/components/screens/index.js.map +1 -0
  106. package/dist/components/ui/ErrorBoundary.d.ts +34 -0
  107. package/dist/components/ui/ErrorBoundary.d.ts.map +1 -0
  108. package/dist/components/ui/ErrorBoundary.js +37 -0
  109. package/dist/components/ui/ErrorBoundary.js.map +1 -0
  110. package/dist/components/ui/ErrorDisplay.d.ts +20 -0
  111. package/dist/components/ui/ErrorDisplay.d.ts.map +1 -0
  112. package/dist/components/ui/ErrorDisplay.js +12 -0
  113. package/dist/components/ui/ErrorDisplay.js.map +1 -0
  114. package/dist/components/ui/ErrorRecoveryPrompt.d.ts +30 -0
  115. package/dist/components/ui/ErrorRecoveryPrompt.d.ts.map +1 -0
  116. package/dist/components/ui/ErrorRecoveryPrompt.js +66 -0
  117. package/dist/components/ui/ErrorRecoveryPrompt.js.map +1 -0
  118. package/dist/components/ui/FeatureSidebar.d.ts +27 -0
  119. package/dist/components/ui/FeatureSidebar.d.ts.map +1 -0
  120. package/dist/components/ui/FeatureSidebar.js +166 -0
  121. package/dist/components/ui/FeatureSidebar.js.map +1 -0
  122. package/dist/components/ui/FlowTable.d.ts +21 -0
  123. package/dist/components/ui/FlowTable.d.ts.map +1 -0
  124. package/dist/components/ui/FlowTable.js +105 -0
  125. package/dist/components/ui/FlowTable.js.map +1 -0
  126. package/dist/components/ui/Header.d.ts +20 -0
  127. package/dist/components/ui/Header.d.ts.map +1 -0
  128. package/dist/components/ui/Header.js +11 -0
  129. package/dist/components/ui/Header.js.map +1 -0
  130. package/dist/components/ui/OutputRegion.d.ts +20 -0
  131. package/dist/components/ui/OutputRegion.d.ts.map +1 -0
  132. package/dist/components/ui/OutputRegion.js +14 -0
  133. package/dist/components/ui/OutputRegion.js.map +1 -0
  134. package/dist/components/ui/PhaseProgressView.d.ts +23 -0
  135. package/dist/components/ui/PhaseProgressView.d.ts.map +1 -0
  136. package/dist/components/ui/PhaseProgressView.js +117 -0
  137. package/dist/components/ui/PhaseProgressView.js.map +1 -0
  138. package/dist/components/ui/ProgressBar.d.ts +20 -0
  139. package/dist/components/ui/ProgressBar.d.ts.map +1 -0
  140. package/dist/components/ui/ProgressBar.js +12 -0
  141. package/dist/components/ui/ProgressBar.js.map +1 -0
  142. package/dist/components/ui/SelectMenu.d.ts +27 -0
  143. package/dist/components/ui/SelectMenu.d.ts.map +1 -0
  144. package/dist/components/ui/SelectMenu.js +21 -0
  145. package/dist/components/ui/SelectMenu.js.map +1 -0
  146. package/dist/components/ui/Spinner.d.ts +18 -0
  147. package/dist/components/ui/Spinner.d.ts.map +1 -0
  148. package/dist/components/ui/Spinner.js +10 -0
  149. package/dist/components/ui/Spinner.js.map +1 -0
  150. package/dist/components/ui/StatusLine.d.ts +21 -0
  151. package/dist/components/ui/StatusLine.d.ts.map +1 -0
  152. package/dist/components/ui/StatusLine.js +30 -0
  153. package/dist/components/ui/StatusLine.js.map +1 -0
  154. package/dist/components/ui/index.d.ts +16 -0
  155. package/dist/components/ui/index.d.ts.map +1 -0
  156. package/dist/components/ui/index.js +16 -0
  157. package/dist/components/ui/index.js.map +1 -0
  158. package/dist/services/AgentInvoker.d.ts +20 -0
  159. package/dist/services/AgentInvoker.d.ts.map +1 -0
  160. package/dist/services/AgentInvoker.js +282 -0
  161. package/dist/services/AgentInvoker.js.map +1 -0
  162. package/dist/services/BranchService.d.ts +28 -0
  163. package/dist/services/BranchService.d.ts.map +1 -0
  164. package/dist/services/BranchService.js +114 -0
  165. package/dist/services/BranchService.js.map +1 -0
  166. package/dist/services/CacheService.d.ts +57 -0
  167. package/dist/services/CacheService.d.ts.map +1 -0
  168. package/dist/services/CacheService.js +208 -0
  169. package/dist/services/CacheService.js.map +1 -0
  170. package/dist/services/ClaudeErrorDetector.d.ts +45 -0
  171. package/dist/services/ClaudeErrorDetector.d.ts.map +1 -0
  172. package/dist/services/ClaudeErrorDetector.js +207 -0
  173. package/dist/services/ClaudeErrorDetector.js.map +1 -0
  174. package/dist/services/ClaudeHealthCheck.d.ts +37 -0
  175. package/dist/services/ClaudeHealthCheck.d.ts.map +1 -0
  176. package/dist/services/ClaudeHealthCheck.js +197 -0
  177. package/dist/services/ClaudeHealthCheck.js.map +1 -0
  178. package/dist/services/CommitService.d.ts +36 -0
  179. package/dist/services/CommitService.d.ts.map +1 -0
  180. package/dist/services/CommitService.js +159 -0
  181. package/dist/services/CommitService.js.map +1 -0
  182. package/dist/services/ConfigService.d.ts +49 -0
  183. package/dist/services/ConfigService.d.ts.map +1 -0
  184. package/dist/services/ConfigService.js +57 -0
  185. package/dist/services/ConfigService.js.map +1 -0
  186. package/dist/services/DockerRunner.d.ts +45 -0
  187. package/dist/services/DockerRunner.d.ts.map +1 -0
  188. package/dist/services/DockerRunner.js +170 -0
  189. package/dist/services/DockerRunner.js.map +1 -0
  190. package/dist/services/ExtendedFlowStateMachine.d.ts +31 -0
  191. package/dist/services/ExtendedFlowStateMachine.d.ts.map +1 -0
  192. package/dist/services/ExtendedFlowStateMachine.js +302 -0
  193. package/dist/services/ExtendedFlowStateMachine.js.map +1 -0
  194. package/dist/services/FeatureValidator.d.ts +26 -0
  195. package/dist/services/FeatureValidator.d.ts.map +1 -0
  196. package/dist/services/FeatureValidator.js +48 -0
  197. package/dist/services/FeatureValidator.js.map +1 -0
  198. package/dist/services/FlowStateMachine.d.ts +26 -0
  199. package/dist/services/FlowStateMachine.d.ts.map +1 -0
  200. package/dist/services/FlowStateMachine.js +177 -0
  201. package/dist/services/FlowStateMachine.js.map +1 -0
  202. package/dist/services/GitHubService.d.ts +72 -0
  203. package/dist/services/GitHubService.d.ts.map +1 -0
  204. package/dist/services/GitHubService.js +150 -0
  205. package/dist/services/GitHubService.js.map +1 -0
  206. package/dist/services/GitStatusChecker.d.ts +29 -0
  207. package/dist/services/GitStatusChecker.d.ts.map +1 -0
  208. package/dist/services/GitStatusChecker.js +127 -0
  209. package/dist/services/GitStatusChecker.js.map +1 -0
  210. package/dist/services/PRCreatorService.d.ts +59 -0
  211. package/dist/services/PRCreatorService.d.ts.map +1 -0
  212. package/dist/services/PRCreatorService.js +212 -0
  213. package/dist/services/PRCreatorService.js.map +1 -0
  214. package/dist/services/PRStatusFetcher.d.ts +39 -0
  215. package/dist/services/PRStatusFetcher.d.ts.map +1 -0
  216. package/dist/services/PRStatusFetcher.js +144 -0
  217. package/dist/services/PRStatusFetcher.js.map +1 -0
  218. package/dist/services/PhaseExecutor.d.ts +29 -0
  219. package/dist/services/PhaseExecutor.d.ts.map +1 -0
  220. package/dist/services/PhaseExecutor.js +125 -0
  221. package/dist/services/PhaseExecutor.js.map +1 -0
  222. package/dist/services/SpecInitService.d.ts +33 -0
  223. package/dist/services/SpecInitService.d.ts.map +1 -0
  224. package/dist/services/SpecInitService.js +168 -0
  225. package/dist/services/SpecInitService.js.map +1 -0
  226. package/dist/services/StateStore.d.ts +24 -0
  227. package/dist/services/StateStore.d.ts.map +1 -0
  228. package/dist/services/StateStore.js +171 -0
  229. package/dist/services/StateStore.js.map +1 -0
  230. package/dist/services/TaskParser.d.ts +44 -0
  231. package/dist/services/TaskParser.d.ts.map +1 -0
  232. package/dist/services/TaskParser.js +167 -0
  233. package/dist/services/TaskParser.js.map +1 -0
  234. package/dist/services/TaskRunner.d.ts +52 -0
  235. package/dist/services/TaskRunner.d.ts.map +1 -0
  236. package/dist/services/TaskRunner.js +135 -0
  237. package/dist/services/TaskRunner.js.map +1 -0
  238. package/dist/services/TemplateService.d.ts +73 -0
  239. package/dist/services/TemplateService.d.ts.map +1 -0
  240. package/dist/services/TemplateService.js +263 -0
  241. package/dist/services/TemplateService.js.map +1 -0
  242. package/dist/services/WorktreeService.d.ts +51 -0
  243. package/dist/services/WorktreeService.d.ts.map +1 -0
  244. package/dist/services/WorktreeService.js +204 -0
  245. package/dist/services/WorktreeService.js.map +1 -0
  246. package/dist/services/index.d.ts +25 -0
  247. package/dist/services/index.d.ts.map +1 -0
  248. package/dist/services/index.js +25 -0
  249. package/dist/services/index.js.map +1 -0
  250. package/dist/types/extended-flow.d.ts +167 -0
  251. package/dist/types/extended-flow.d.ts.map +1 -0
  252. package/dist/types/extended-flow.js +103 -0
  253. package/dist/types/extended-flow.js.map +1 -0
  254. package/dist/types/index.d.ts +210 -0
  255. package/dist/types/index.d.ts.map +1 -0
  256. package/dist/types/index.js +28 -0
  257. package/dist/types/index.js.map +1 -0
  258. package/dist/utils/git.d.ts +41 -0
  259. package/dist/utils/git.d.ts.map +1 -0
  260. package/dist/utils/git.js +68 -0
  261. package/dist/utils/git.js.map +1 -0
  262. package/dist/utils/index.d.ts +6 -0
  263. package/dist/utils/index.d.ts.map +1 -0
  264. package/dist/utils/index.js +6 -0
  265. package/dist/utils/index.js.map +1 -0
  266. package/dist/utils/paths.d.ts +30 -0
  267. package/dist/utils/paths.d.ts.map +1 -0
  268. package/dist/utils/paths.js +43 -0
  269. package/dist/utils/paths.js.map +1 -0
  270. package/framework/.red64/settings/rules/design-discovery-full.md +93 -0
  271. package/framework/.red64/settings/rules/design-discovery-light.md +49 -0
  272. package/framework/.red64/settings/rules/design-principles.md +182 -0
  273. package/framework/.red64/settings/rules/design-review.md +110 -0
  274. package/framework/.red64/settings/rules/ears-format.md +49 -0
  275. package/framework/.red64/settings/rules/gap-analysis.md +144 -0
  276. package/framework/.red64/settings/rules/steering-principles.md +90 -0
  277. package/framework/.red64/settings/rules/tasks-generation.md +131 -0
  278. package/framework/.red64/settings/rules/tasks-parallel-analysis.md +34 -0
  279. package/framework/.red64/settings/templates/flow-state.json +48 -0
  280. package/framework/.red64/settings/templates/specs/design.md +276 -0
  281. package/framework/.red64/settings/templates/specs/init.json +24 -0
  282. package/framework/.red64/settings/templates/specs/requirements-init.md +9 -0
  283. package/framework/.red64/settings/templates/specs/requirements.md +26 -0
  284. package/framework/.red64/settings/templates/specs/research.md +61 -0
  285. package/framework/.red64/settings/templates/specs/tasks.md +21 -0
  286. package/framework/.red64/settings/templates/steering/product.md +18 -0
  287. package/framework/.red64/settings/templates/steering/structure.md +41 -0
  288. package/framework/.red64/settings/templates/steering/tech.md +45 -0
  289. package/framework/.red64/settings/templates/steering-custom/api-standards.md +69 -0
  290. package/framework/.red64/settings/templates/steering-custom/authentication.md +67 -0
  291. package/framework/.red64/settings/templates/steering-custom/database.md +46 -0
  292. package/framework/.red64/settings/templates/steering-custom/deployment.md +54 -0
  293. package/framework/.red64/settings/templates/steering-custom/error-handling.md +59 -0
  294. package/framework/.red64/settings/templates/steering-custom/security.md +55 -0
  295. package/framework/.red64/settings/templates/steering-custom/testing.md +47 -0
  296. package/framework/agents/claude/.claude/agents/red64/spec-design.md +174 -0
  297. package/framework/agents/claude/.claude/agents/red64/spec-impl.md +120 -0
  298. package/framework/agents/claude/.claude/agents/red64/spec-requirements.md +102 -0
  299. package/framework/agents/claude/.claude/agents/red64/spec-tasks.md +141 -0
  300. package/framework/agents/claude/.claude/agents/red64/steering-custom.md +147 -0
  301. package/framework/agents/claude/.claude/agents/red64/steering.md +163 -0
  302. package/framework/agents/claude/.claude/agents/red64/validate-design.md +98 -0
  303. package/framework/agents/claude/.claude/agents/red64/validate-gap.md +99 -0
  304. package/framework/agents/claude/.claude/agents/red64/validate-impl.md +146 -0
  305. package/framework/agents/claude/.claude/commands/red64/spec-design.md +64 -0
  306. package/framework/agents/claude/.claude/commands/red64/spec-impl.md +68 -0
  307. package/framework/agents/claude/.claude/commands/red64/spec-init.md +65 -0
  308. package/framework/agents/claude/.claude/commands/red64/spec-quick.md +360 -0
  309. package/framework/agents/claude/.claude/commands/red64/spec-requirements.md +62 -0
  310. package/framework/agents/claude/.claude/commands/red64/spec-status.md +87 -0
  311. package/framework/agents/claude/.claude/commands/red64/spec-tasks.md +75 -0
  312. package/framework/agents/claude/.claude/commands/red64/steering-custom.md +59 -0
  313. package/framework/agents/claude/.claude/commands/red64/steering.md +62 -0
  314. package/framework/agents/claude/.claude/commands/red64/validate-design.md +59 -0
  315. package/framework/agents/claude/.claude/commands/red64/validate-gap.md +53 -0
  316. package/framework/agents/claude/.claude/commands/red64/validate-impl.md +68 -0
  317. package/framework/agents/claude/docs/CLAUDE.md +45 -0
  318. package/framework/agents/codex/.codex/agents/red64/spec-design.md +174 -0
  319. package/framework/agents/codex/.codex/agents/red64/spec-impl.md +120 -0
  320. package/framework/agents/codex/.codex/agents/red64/spec-requirements.md +102 -0
  321. package/framework/agents/codex/.codex/agents/red64/spec-tasks.md +141 -0
  322. package/framework/agents/codex/.codex/agents/red64/steering-custom.md +147 -0
  323. package/framework/agents/codex/.codex/agents/red64/steering.md +163 -0
  324. package/framework/agents/codex/.codex/agents/red64/validate-design.md +98 -0
  325. package/framework/agents/codex/.codex/agents/red64/validate-gap.md +99 -0
  326. package/framework/agents/codex/.codex/agents/red64/validate-impl.md +146 -0
  327. package/framework/agents/codex/.codex/commands/red64/spec-design.md +64 -0
  328. package/framework/agents/codex/.codex/commands/red64/spec-impl.md +68 -0
  329. package/framework/agents/codex/.codex/commands/red64/spec-init.md +65 -0
  330. package/framework/agents/codex/.codex/commands/red64/spec-quick.md +360 -0
  331. package/framework/agents/codex/.codex/commands/red64/spec-requirements.md +62 -0
  332. package/framework/agents/codex/.codex/commands/red64/spec-status.md +87 -0
  333. package/framework/agents/codex/.codex/commands/red64/spec-tasks.md +75 -0
  334. package/framework/agents/codex/.codex/commands/red64/steering-custom.md +59 -0
  335. package/framework/agents/codex/.codex/commands/red64/steering.md +62 -0
  336. package/framework/agents/codex/.codex/commands/red64/validate-design.md +59 -0
  337. package/framework/agents/codex/.codex/commands/red64/validate-gap.md +53 -0
  338. package/framework/agents/codex/.codex/commands/red64/validate-impl.md +68 -0
  339. package/framework/agents/codex/docs/AGENTS.md +68 -0
  340. package/framework/agents/gemini/commands.toml +607 -0
  341. package/framework/agents/gemini/docs/GEMINI.md +45 -0
  342. package/framework/stacks/generic/product.md +27 -0
  343. package/framework/stacks/generic/structure.md +46 -0
  344. package/framework/stacks/generic/tech.md +47 -0
  345. package/framework/stacks/node/product.md +27 -0
  346. package/framework/stacks/node/structure.md +82 -0
  347. package/framework/stacks/node/tech.md +63 -0
  348. package/framework/stacks/python/product.md +27 -0
  349. package/framework/stacks/python/structure.md +78 -0
  350. package/framework/stacks/python/tech.md +64 -0
  351. package/framework/stacks/react/product.md +27 -0
  352. package/framework/stacks/react/structure.md +76 -0
  353. package/framework/stacks/react/tech.md +65 -0
  354. package/package.json +47 -0
@@ -0,0 +1,1021 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Start screen component - orchestrates the spec-driven development flow
4
+ * Requirements: 4.2
5
+ *
6
+ * Flow:
7
+ * 1. Create git worktree for isolation
8
+ * 2. Initialize spec directory → commit
9
+ * 3. Generate requirements → commit
10
+ * 4. Approval gate
11
+ * 5. Generate design → commit
12
+ * 6. Approval gate
13
+ * 7. Generate tasks → commit
14
+ * 8. Approval gate
15
+ * 9. For each task: run spec-impl {task} → commit
16
+ * 10. Complete
17
+ */
18
+ import { useState, useEffect, useCallback, useRef } from 'react';
19
+ import { Box, Text, useApp } from 'ink';
20
+ import { Spinner, Select } from '@inkjs/ui';
21
+ import { createStateStore, createAgentInvoker, createExtendedFlowMachine, createWorktreeService, createCommitService, createTaskParser, createSpecInitService, createClaudeHealthCheck, createGitStatusChecker, createConfigService, sanitizeFeatureName } from '../../services/index.js';
22
+ import { FeatureSidebar } from '../ui/index.js';
23
+ import { join } from 'node:path';
24
+ import { appendFile, mkdir } from 'node:fs/promises';
25
+ /**
26
+ * Phase display information
27
+ */
28
+ const PHASE_LABELS = {
29
+ 'idle': { label: 'Idle', description: 'Ready to start' },
30
+ 'initializing': { label: 'Initializing', description: 'Setting up spec directory' },
31
+ 'requirements-generating': { label: 'Requirements', description: 'Generating requirements' },
32
+ 'requirements-approval': { label: 'Requirements Review', description: 'Review and approve requirements' },
33
+ 'gap-analysis': { label: 'Gap Analysis', description: 'Analyzing existing codebase' },
34
+ 'gap-review': { label: 'Gap Review', description: 'Review gap analysis' },
35
+ 'design-generating': { label: 'Design', description: 'Generating technical design' },
36
+ 'design-approval': { label: 'Design Review', description: 'Review and approve design' },
37
+ 'design-validation': { label: 'Design Validation', description: 'Validating design' },
38
+ 'design-validation-review': { label: 'Validation Review', description: 'Review design validation' },
39
+ 'tasks-generating': { label: 'Tasks', description: 'Generating implementation tasks' },
40
+ 'tasks-approval': { label: 'Tasks Review', description: 'Review and approve tasks' },
41
+ 'implementing': { label: 'Implementing', description: 'Executing implementation tasks' },
42
+ 'paused': { label: 'Paused', description: 'Flow paused' },
43
+ 'validation': { label: 'Validation', description: 'Validating implementation' },
44
+ 'pr': { label: 'Pull Request', description: 'Creating pull request' },
45
+ 'merge-decision': { label: 'Merge Decision', description: 'Decide whether to merge' },
46
+ 'complete': { label: 'Complete', description: 'Flow completed successfully' },
47
+ 'aborted': { label: 'Aborted', description: 'Flow was aborted' },
48
+ 'error': { label: 'Error', description: 'An error occurred' }
49
+ };
50
+ /**
51
+ * Approval options for review phases
52
+ */
53
+ const APPROVAL_OPTIONS = [
54
+ { value: 'approve', label: 'Approve and continue' },
55
+ { value: 'reject', label: 'Reject and regenerate' },
56
+ { value: 'pause', label: 'Pause flow' }
57
+ ];
58
+ /**
59
+ * Options when existing flow is detected
60
+ */
61
+ const EXISTING_FLOW_OPTIONS = [
62
+ { value: 'resume', label: 'Resume from where you left off' },
63
+ { value: 'restart', label: 'Start fresh (discard previous progress)' },
64
+ { value: 'abort', label: 'Cancel' }
65
+ ];
66
+ /**
67
+ * Options when uncommitted changes are detected
68
+ */
69
+ const UNCOMMITTED_CHANGES_OPTIONS = [
70
+ { value: 'commit', label: 'Commit changes (WIP) and continue' },
71
+ { value: 'discard', label: 'Discard changes and continue' },
72
+ { value: 'abort', label: 'Cancel' }
73
+ ];
74
+ /**
75
+ * Human-readable labels for Claude error codes
76
+ */
77
+ function getClaudeErrorLabel(code) {
78
+ const labels = {
79
+ CREDIT_EXHAUSTED: 'Insufficient Credits',
80
+ RATE_LIMITED: 'Rate Limited',
81
+ AUTH_FAILED: 'Authentication Failed',
82
+ MODEL_UNAVAILABLE: 'Service Unavailable',
83
+ CONTEXT_EXCEEDED: 'Context Too Large',
84
+ NETWORK_ERROR: 'Network Error',
85
+ PERMISSION_DENIED: 'Request Blocked',
86
+ UNKNOWN: 'Unknown Error'
87
+ };
88
+ return labels[code] ?? code;
89
+ }
90
+ /**
91
+ * Start screen - orchestrates the spec-driven development flow with:
92
+ * - Git worktree isolation
93
+ * - Commits after each phase
94
+ * - Task-by-task implementation with commits
95
+ */
96
+ export const StartScreen = ({ args, flags }) => {
97
+ const { exit } = useApp();
98
+ const featureName = args[0] ?? 'unnamed';
99
+ const description = args[1] ?? 'No description provided';
100
+ const mode = flags.brownfield ? 'brownfield' : 'greenfield';
101
+ const verbose = flags.verbose ?? false;
102
+ const repoPath = process.cwd();
103
+ // Initialize services
104
+ const servicesRef = useRef(null);
105
+ if (!servicesRef.current) {
106
+ const stateStore = createStateStore(repoPath);
107
+ const agentInvoker = createAgentInvoker();
108
+ const flowMachine = createExtendedFlowMachine();
109
+ const worktreeService = createWorktreeService();
110
+ const commitService = createCommitService();
111
+ const taskParser = createTaskParser();
112
+ const specInitService = createSpecInitService();
113
+ const healthCheck = createClaudeHealthCheck();
114
+ const gitStatusChecker = createGitStatusChecker();
115
+ const configService = createConfigService();
116
+ servicesRef.current = {
117
+ stateStore,
118
+ agentInvoker,
119
+ flowMachine,
120
+ worktreeService,
121
+ commitService,
122
+ taskParser,
123
+ specInitService,
124
+ healthCheck,
125
+ gitStatusChecker,
126
+ configService
127
+ };
128
+ }
129
+ const services = servicesRef.current;
130
+ // Log file path
131
+ const logFileRef = useRef(null);
132
+ // Initialize log file
133
+ const initLogFile = useCallback(async (workDir) => {
134
+ const logDir = join(workDir, '.red64', 'flows', sanitizeFeatureName(featureName));
135
+ await mkdir(logDir, { recursive: true });
136
+ const logPath = join(logDir, 'flow.log');
137
+ logFileRef.current = logPath;
138
+ // Write header
139
+ const header = `\n${'='.repeat(60)}\nFlow started: ${new Date().toISOString()}\nFeature: ${featureName}\nMode: ${mode}\n${'='.repeat(60)}\n\n`;
140
+ await appendFile(logPath, header);
141
+ return logPath;
142
+ }, [featureName, mode]);
143
+ // Log to file
144
+ const logToFile = useCallback(async (message) => {
145
+ if (logFileRef.current) {
146
+ const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
147
+ await appendFile(logFileRef.current, `[${timestamp}] ${message}\n`).catch(() => { });
148
+ }
149
+ }, []);
150
+ // Flow state
151
+ const [flowState, setFlowState] = useState({
152
+ phase: { type: 'idle' },
153
+ output: [],
154
+ error: null,
155
+ claudeError: null,
156
+ isExecuting: false,
157
+ isHealthChecking: false,
158
+ preStartStep: { type: 'checking' }, // Start by checking for existing flow
159
+ worktreePath: null,
160
+ currentTask: 0,
161
+ totalTasks: 0,
162
+ tasks: [],
163
+ resolvedFeatureName: null,
164
+ existingFlowState: null,
165
+ completedTasks: [], // Orchestrator-tracked completed task IDs
166
+ phaseMetrics: {}, // Phase timing metrics
167
+ commitCount: 0, // Number of commits for this feature
168
+ agent: 'claude' // Default, will be loaded from config
169
+ });
170
+ // Track if flow has been started
171
+ const flowStartedRef = useRef(false);
172
+ // Add output line (to screen and log file)
173
+ const addOutput = useCallback((line) => {
174
+ setFlowState(prev => ({
175
+ ...prev,
176
+ output: [...prev.output.slice(-50), line]
177
+ }));
178
+ // Also log to file
179
+ logToFile(line);
180
+ }, [logToFile]);
181
+ // Get working directory (worktree or repo)
182
+ const getWorkingDir = useCallback(() => {
183
+ return flowState.worktreePath ?? repoPath;
184
+ }, [flowState.worktreePath, repoPath]);
185
+ // Execute a Claude command
186
+ const executeCommand = useCallback(async (prompt, workDir) => {
187
+ const dir = workDir ?? getWorkingDir();
188
+ // Build tier config dir path
189
+ const tierConfigDir = flags.tier
190
+ ? `${process.env.HOME ?? '~'}/.claude-${flags.tier}`
191
+ : null;
192
+ // Always log command to file
193
+ await logToFile(`--- Executing command ---`);
194
+ await logToFile(`Command: claude -p "${prompt}"`);
195
+ await logToFile(`Working dir: ${dir}`);
196
+ if (flags.skipPermissions) {
197
+ await logToFile(`Flags: --dangerously-skip-permissions`);
198
+ }
199
+ if (tierConfigDir) {
200
+ await logToFile(`CLAUDE_CONFIG_DIR: ${tierConfigDir}`);
201
+ }
202
+ if (flags.sandbox) {
203
+ await logToFile(`Sandbox: Docker isolated mode`);
204
+ }
205
+ if (flags.model) {
206
+ await logToFile(`Model: ${flags.model}`);
207
+ }
208
+ // Verbose mode: also show on screen
209
+ if (verbose) {
210
+ addOutput(`[verbose] Command: claude -p "${prompt}"`);
211
+ addOutput(`[verbose] Working dir: ${dir}`);
212
+ if (flags.skipPermissions) {
213
+ addOutput(`[verbose] Flags: --dangerously-skip-permissions`);
214
+ }
215
+ if (tierConfigDir) {
216
+ addOutput(`[verbose] CLAUDE_CONFIG_DIR: ${tierConfigDir}`);
217
+ }
218
+ if (flags.sandbox) {
219
+ addOutput(`[verbose] Sandbox: Docker isolated mode`);
220
+ }
221
+ if (flags.model) {
222
+ addOutput(`[verbose] Model: ${flags.model}`);
223
+ }
224
+ }
225
+ setFlowState(prev => ({ ...prev, isExecuting: true, error: null, claudeError: null }));
226
+ const result = await services.agentInvoker.invoke({
227
+ prompt,
228
+ workingDirectory: dir,
229
+ skipPermissions: flags.skipPermissions ?? false,
230
+ tier: flags.tier,
231
+ model: flags.model,
232
+ sandbox: flags.sandbox ?? false,
233
+ onOutput: (chunk) => {
234
+ // Stream output in real-time
235
+ const lines = chunk.split('\n').filter(l => l.trim());
236
+ lines.forEach(line => addOutput(line));
237
+ },
238
+ onError: (chunk) => {
239
+ // Stream stderr in verbose mode
240
+ if (verbose) {
241
+ const lines = chunk.split('\n').filter(l => l.trim());
242
+ lines.forEach(line => addOutput(`[stderr] ${line}`));
243
+ }
244
+ }
245
+ });
246
+ setFlowState(prev => ({ ...prev, isExecuting: false }));
247
+ // Always log result to file
248
+ await logToFile(`Exit code: ${result.exitCode}`);
249
+ await logToFile(`Success: ${result.success}`);
250
+ if (result.timedOut) {
251
+ await logToFile(`Timed out: true`);
252
+ }
253
+ if (result.claudeError) {
254
+ await logToFile(`Claude Error: ${result.claudeError.code} - ${result.claudeError.message}`);
255
+ await logToFile(`Suggestion: ${result.claudeError.suggestion}`);
256
+ }
257
+ if (result.stdout) {
258
+ await logToFile(`--- stdout ---`);
259
+ await logToFile(result.stdout);
260
+ }
261
+ if (result.stderr) {
262
+ await logToFile(`--- stderr ---`);
263
+ await logToFile(result.stderr);
264
+ }
265
+ await logToFile(`--- end command ---\n`);
266
+ // Verbose mode: show result on screen
267
+ if (verbose) {
268
+ addOutput(`[verbose] Exit code: ${result.exitCode}`);
269
+ addOutput(`[verbose] Success: ${result.success}`);
270
+ if (result.timedOut) {
271
+ addOutput(`[verbose] Timed out: true`);
272
+ }
273
+ if (result.claudeError) {
274
+ addOutput(`[verbose] Claude Error: ${result.claudeError.code}`);
275
+ }
276
+ }
277
+ if (!result.success) {
278
+ // Use Claude error if detected, otherwise build generic error message
279
+ if (result.claudeError) {
280
+ const errorMsg = `${getClaudeErrorLabel(result.claudeError.code)}: ${result.claudeError.suggestion}`;
281
+ setFlowState(prev => ({ ...prev, error: errorMsg, claudeError: result.claudeError ?? null }));
282
+ return { success: false, output: result.stdout, error: errorMsg, claudeError: result.claudeError };
283
+ }
284
+ // Build generic error message
285
+ let errorMsg = 'Command failed';
286
+ if (result.timedOut) {
287
+ errorMsg = 'Command timed out (10 min limit)';
288
+ }
289
+ else if (result.stderr) {
290
+ errorMsg = result.stderr.trim().split('\n')[0]; // First line of stderr
291
+ }
292
+ else if (result.exitCode !== 0) {
293
+ errorMsg = `Command exited with code ${result.exitCode}`;
294
+ }
295
+ // In verbose mode, show full stderr on screen
296
+ if (verbose && result.stderr) {
297
+ addOutput(`[verbose] Full stderr:`);
298
+ result.stderr.split('\n').forEach(line => {
299
+ if (line.trim())
300
+ addOutput(` ${line}`);
301
+ });
302
+ }
303
+ setFlowState(prev => ({ ...prev, error: errorMsg }));
304
+ return { success: false, output: result.stdout, error: errorMsg };
305
+ }
306
+ return { success: true, output: result.stdout };
307
+ }, [services.agentInvoker, flags, verbose, getWorkingDir, addOutput, logToFile]);
308
+ // Commit changes with formatted message
309
+ const commitChanges = useCallback(async (message, workDir) => {
310
+ const dir = workDir ?? getWorkingDir();
311
+ addOutput(`Committing: ${message.split('\n')[0]}...`);
312
+ const result = await services.commitService.stageAndCommit(dir, message);
313
+ if (!result.success) {
314
+ addOutput(`Commit warning: ${result.error ?? 'No changes to commit'}`);
315
+ return true; // Continue even if nothing to commit
316
+ }
317
+ if (result.commitHash) {
318
+ addOutput(`Committed: ${result.commitHash.substring(0, 7)}`);
319
+ // Increment commit count
320
+ setFlowState(prev => ({ ...prev, commitCount: prev.commitCount + 1 }));
321
+ }
322
+ return true;
323
+ }, [services.commitService, getWorkingDir, addOutput]);
324
+ // Save flow state with task progress and phase metrics
325
+ const saveFlowState = useCallback(async (phase, workDir, completedTasksOverride) => {
326
+ const dir = workDir ?? getWorkingDir();
327
+ const stateStore = createStateStore(dir);
328
+ // Load existing state to preserve createdAt and merge data
329
+ const existingState = await stateStore.load(featureName);
330
+ // Use override if provided, otherwise use current state, otherwise preserve existing
331
+ const completedTasks = completedTasksOverride ?? flowState.completedTasks;
332
+ const state = {
333
+ feature: featureName,
334
+ phase: convertToFlowPhase(phase),
335
+ createdAt: existingState?.createdAt ?? new Date().toISOString(),
336
+ updatedAt: new Date().toISOString(),
337
+ history: existingState?.history ?? [],
338
+ metadata: {
339
+ description,
340
+ mode,
341
+ tier: flags.tier,
342
+ worktreePath: flowState.worktreePath ?? undefined,
343
+ resolvedFeatureName: flowState.resolvedFeatureName ?? undefined
344
+ },
345
+ // Orchestrator-controlled task progress
346
+ taskProgress: completedTasks.length > 0 || flowState.totalTasks > 0 ? {
347
+ completedTasks,
348
+ totalTasks: flowState.totalTasks
349
+ } : existingState?.taskProgress,
350
+ // Phase timing metrics
351
+ phaseMetrics: Object.keys(flowState.phaseMetrics).length > 0
352
+ ? { ...existingState?.phaseMetrics, ...flowState.phaseMetrics }
353
+ : existingState?.phaseMetrics
354
+ };
355
+ await stateStore.save(state);
356
+ }, [featureName, description, mode, flags.tier, flowState.worktreePath, flowState.resolvedFeatureName, flowState.completedTasks, flowState.totalTasks, flowState.phaseMetrics, getWorkingDir]);
357
+ // Transition to next phase
358
+ const transitionPhase = useCallback((event) => {
359
+ const nextPhase = services.flowMachine.send(event);
360
+ setFlowState(prev => ({ ...prev, phase: nextPhase }));
361
+ return nextPhase;
362
+ }, [services.flowMachine]);
363
+ // Check for existing flow on mount
364
+ useEffect(() => {
365
+ if (flowStartedRef.current)
366
+ return;
367
+ flowStartedRef.current = true;
368
+ const checkExistingFlow = async () => {
369
+ // Load config to get the agent setting
370
+ const config = await services.configService.load(repoPath);
371
+ if (config?.agent) {
372
+ setFlowState(prev => ({ ...prev, agent: config.agent }));
373
+ }
374
+ addOutput('Checking for existing flow...');
375
+ // Check if there's an existing flow state for this feature
376
+ // First check main repo, then check worktree if exists
377
+ let existingState = await services.stateStore.load(featureName);
378
+ // If not found in main repo, check if worktree exists and has state
379
+ if (!existingState) {
380
+ const worktreeCheck = await services.worktreeService.check(repoPath, featureName);
381
+ if (worktreeCheck.exists && worktreeCheck.path) {
382
+ const worktreeStateStore = createStateStore(worktreeCheck.path);
383
+ existingState = await worktreeStateStore.load(featureName);
384
+ if (existingState) {
385
+ addOutput(`Found state in worktree: ${worktreeCheck.path}`);
386
+ }
387
+ }
388
+ }
389
+ if (existingState && existingState.phase.type !== 'complete' && existingState.phase.type !== 'aborted') {
390
+ // Found an in-progress flow - check for uncommitted changes
391
+ const worktreePath = existingState.metadata.worktreePath ?? repoPath;
392
+ const gitStatus = await services.gitStatusChecker.check(worktreePath);
393
+ // Load task progress from state (source of truth)
394
+ const completedTasks = existingState.taskProgress?.completedTasks ?? [];
395
+ const totalTasks = existingState.taskProgress?.totalTasks ?? 0;
396
+ if (gitStatus.hasChanges) {
397
+ // Has uncommitted changes - prompt user first
398
+ setFlowState(prev => ({
399
+ ...prev,
400
+ preStartStep: { type: 'uncommitted-changes', existingState, gitStatus },
401
+ existingFlowState: existingState,
402
+ worktreePath: existingState.metadata.worktreePath ?? null,
403
+ resolvedFeatureName: existingState.metadata.resolvedFeatureName ?? null,
404
+ completedTasks: [...completedTasks],
405
+ totalTasks
406
+ }));
407
+ addOutput(`Found existing flow at phase: ${existingState.phase.type}`);
408
+ if (completedTasks.length > 0) {
409
+ addOutput(`Completed tasks: ${completedTasks.join(', ')}`);
410
+ }
411
+ addOutput(`Uncommitted changes detected: ${gitStatus.staged} staged, ${gitStatus.unstaged} unstaged, ${gitStatus.untracked} untracked`);
412
+ return;
413
+ }
414
+ // No uncommitted changes - prompt resume vs restart
415
+ setFlowState(prev => ({
416
+ ...prev,
417
+ preStartStep: { type: 'existing-flow-detected', existingState, gitStatus },
418
+ existingFlowState: existingState,
419
+ worktreePath: existingState.metadata.worktreePath ?? null,
420
+ resolvedFeatureName: existingState.metadata.resolvedFeatureName ?? null,
421
+ completedTasks: [...completedTasks],
422
+ totalTasks
423
+ }));
424
+ addOutput(`Found existing flow at phase: ${existingState.phase.type}`);
425
+ if (completedTasks.length > 0) {
426
+ addOutput(`Completed tasks: ${completedTasks.join(', ')}`);
427
+ }
428
+ return;
429
+ }
430
+ // No existing flow or flow is complete/aborted - proceed with fresh start
431
+ setFlowState(prev => ({ ...prev, preStartStep: { type: 'ready' } }));
432
+ await startFreshFlow();
433
+ };
434
+ checkExistingFlow();
435
+ }, []);
436
+ // Handle existing flow decision (resume vs restart)
437
+ const handleExistingFlowDecision = useCallback(async (decision) => {
438
+ if (decision === 'resume') {
439
+ await resumeExistingFlow();
440
+ }
441
+ else if (decision === 'restart') {
442
+ setFlowState(prev => ({ ...prev, preStartStep: { type: 'ready' }, existingFlowState: null }));
443
+ addOutput('Starting fresh flow...');
444
+ await startFreshFlow();
445
+ }
446
+ else if (decision === 'abort') {
447
+ exit();
448
+ }
449
+ }, [exit]);
450
+ // Handle uncommitted changes decision
451
+ const handleUncommittedChangesDecision = useCallback(async (decision) => {
452
+ const existingState = flowState.existingFlowState;
453
+ if (!existingState)
454
+ return;
455
+ const worktreePath = existingState.metadata.worktreePath ?? repoPath;
456
+ if (decision === 'commit') {
457
+ // Commit changes with WIP message
458
+ addOutput('Committing changes...');
459
+ const commitResult = await services.commitService.stageAndCommit(worktreePath, `WIP: ${featureName} - auto-commit before resume`);
460
+ if (commitResult.success) {
461
+ addOutput(`Committed: ${commitResult.commitHash?.substring(0, 7) ?? 'done'}`);
462
+ }
463
+ else {
464
+ addOutput(`Commit warning: ${commitResult.error ?? 'No changes to commit'}`);
465
+ }
466
+ // Now show resume vs restart choice
467
+ const gitStatus = await services.gitStatusChecker.check(worktreePath);
468
+ setFlowState(prev => ({
469
+ ...prev,
470
+ preStartStep: { type: 'existing-flow-detected', existingState, gitStatus }
471
+ }));
472
+ }
473
+ else if (decision === 'discard') {
474
+ // Discard changes using git checkout
475
+ addOutput('Discarding changes...');
476
+ const { spawn } = await import('node:child_process');
477
+ await new Promise((resolve) => {
478
+ const proc = spawn('git', ['checkout', '--', '.'], { cwd: worktreePath });
479
+ proc.on('close', () => {
480
+ // Also clean untracked files
481
+ const cleanProc = spawn('git', ['clean', '-fd'], { cwd: worktreePath });
482
+ cleanProc.on('close', () => resolve());
483
+ });
484
+ });
485
+ addOutput('Changes discarded');
486
+ // Now show resume vs restart choice
487
+ const gitStatus = await services.gitStatusChecker.check(worktreePath);
488
+ setFlowState(prev => ({
489
+ ...prev,
490
+ preStartStep: { type: 'existing-flow-detected', existingState, gitStatus }
491
+ }));
492
+ }
493
+ else if (decision === 'abort') {
494
+ exit();
495
+ }
496
+ }, [flowState.existingFlowState, services.commitService, services.gitStatusChecker, featureName, repoPath, exit, addOutput]);
497
+ // Resume from existing flow state
498
+ const resumeExistingFlow = useCallback(async () => {
499
+ const existingState = flowState.existingFlowState;
500
+ if (!existingState) {
501
+ addOutput('Error: No existing flow state to resume');
502
+ return;
503
+ }
504
+ const phaseType = existingState.phase.type;
505
+ addOutput(`Resuming from phase: ${phaseType}`);
506
+ // Initialize log file
507
+ const workDir = existingState.metadata.worktreePath ?? repoPath;
508
+ // Load initial commit count
509
+ const initialCommitCount = await services.commitService.countFeatureCommits(workDir);
510
+ setFlowState(prev => ({
511
+ ...prev,
512
+ preStartStep: { type: 'resuming', fromPhase: phaseType },
513
+ isHealthChecking: true,
514
+ commitCount: initialCommitCount
515
+ }));
516
+ await initLogFile(workDir);
517
+ // Run health check
518
+ addOutput('Checking Claude API status...');
519
+ const healthResult = await services.healthCheck.check({
520
+ tier: flags.tier,
521
+ sandbox: flags.sandbox,
522
+ timeoutMs: 30000
523
+ });
524
+ setFlowState(prev => ({ ...prev, isHealthChecking: false }));
525
+ if (!healthResult.healthy) {
526
+ const errorMsg = healthResult.error
527
+ ? `${getClaudeErrorLabel(healthResult.error.code)}: ${healthResult.error.suggestion}`
528
+ : healthResult.message;
529
+ setFlowState(prev => ({
530
+ ...prev,
531
+ error: errorMsg,
532
+ claudeError: healthResult.error ?? null,
533
+ phase: { type: 'error', feature: featureName, error: errorMsg }
534
+ }));
535
+ return;
536
+ }
537
+ addOutput(`API ready (${healthResult.durationMs}ms)`);
538
+ // Set up flow machine to the current phase
539
+ const effectiveName = existingState.metadata.resolvedFeatureName ?? sanitizeFeatureName(featureName);
540
+ // Update state with existing flow info
541
+ setFlowState(prev => ({
542
+ ...prev,
543
+ worktreePath: existingState.metadata.worktreePath ?? null,
544
+ resolvedFeatureName: effectiveName
545
+ }));
546
+ // Resume based on current phase
547
+ await resumeFromPhase(existingState.phase.type, workDir, effectiveName);
548
+ }, [flowState.existingFlowState, services.healthCheck, flags, featureName, repoPath, initLogFile, addOutput]);
549
+ // Resume from a specific phase
550
+ const resumeFromPhase = async (phaseType, workDir, effectiveName) => {
551
+ addOutput(`Continuing from ${phaseType}...`);
552
+ switch (phaseType) {
553
+ case 'requirements-review':
554
+ case 'requirements-approval':
555
+ // Waiting for approval - show approval UI
556
+ transitionPhase({ type: 'START', feature: featureName, description, mode });
557
+ transitionPhase({ type: 'PHASE_COMPLETE' }); // to requirements-generating
558
+ transitionPhase({ type: 'PHASE_COMPLETE' }); // to requirements-approval
559
+ break;
560
+ case 'design-generating':
561
+ // Resume design generation
562
+ transitionPhase({ type: 'START', feature: featureName, description, mode });
563
+ transitionPhase({ type: 'PHASE_COMPLETE' });
564
+ transitionPhase({ type: 'PHASE_COMPLETE' });
565
+ transitionPhase({ type: 'APPROVE' });
566
+ await runDesignPhase(workDir);
567
+ break;
568
+ case 'design-review':
569
+ case 'design-approval':
570
+ // Waiting for design approval
571
+ transitionPhase({ type: 'START', feature: featureName, description, mode });
572
+ transitionPhase({ type: 'PHASE_COMPLETE' });
573
+ transitionPhase({ type: 'PHASE_COMPLETE' });
574
+ transitionPhase({ type: 'APPROVE' });
575
+ transitionPhase({ type: 'PHASE_COMPLETE' });
576
+ break;
577
+ case 'tasks-generating':
578
+ // Resume tasks generation
579
+ transitionPhase({ type: 'START', feature: featureName, description, mode });
580
+ transitionPhase({ type: 'PHASE_COMPLETE' });
581
+ transitionPhase({ type: 'PHASE_COMPLETE' });
582
+ transitionPhase({ type: 'APPROVE' });
583
+ transitionPhase({ type: 'PHASE_COMPLETE' });
584
+ transitionPhase({ type: 'APPROVE' });
585
+ await runTasksPhase(workDir);
586
+ break;
587
+ case 'tasks-review':
588
+ case 'tasks-approval':
589
+ // Waiting for tasks approval - load ALL tasks
590
+ transitionPhase({ type: 'START', feature: featureName, description, mode });
591
+ transitionPhase({ type: 'PHASE_COMPLETE' });
592
+ transitionPhase({ type: 'PHASE_COMPLETE' });
593
+ transitionPhase({ type: 'APPROVE' });
594
+ transitionPhase({ type: 'PHASE_COMPLETE' });
595
+ transitionPhase({ type: 'APPROVE' });
596
+ transitionPhase({ type: 'PHASE_COMPLETE' });
597
+ {
598
+ // Load ALL tasks (not just pending by file checkbox)
599
+ const specDir = join(workDir, '.red64', 'specs', effectiveName);
600
+ const tasks = await services.taskParser.parse(specDir);
601
+ setFlowState(prev => ({
602
+ ...prev,
603
+ tasks,
604
+ totalTasks: tasks.length
605
+ }));
606
+ }
607
+ break;
608
+ case 'implementing':
609
+ // Resume implementation - use state.json.completedTasks as source of truth
610
+ transitionPhase({ type: 'START', feature: featureName, description, mode });
611
+ transitionPhase({ type: 'PHASE_COMPLETE' });
612
+ transitionPhase({ type: 'PHASE_COMPLETE' });
613
+ transitionPhase({ type: 'APPROVE' });
614
+ transitionPhase({ type: 'PHASE_COMPLETE' });
615
+ transitionPhase({ type: 'APPROVE' });
616
+ transitionPhase({ type: 'PHASE_COMPLETE' });
617
+ transitionPhase({ type: 'APPROVE' });
618
+ {
619
+ // Load ALL tasks from file
620
+ const implSpecDir = join(workDir, '.red64', 'specs', effectiveName);
621
+ const implTasks = await services.taskParser.parse(implSpecDir);
622
+ // Use state.json.completedTasks as source of truth (already loaded)
623
+ const completedTaskIds = flowState.completedTasks;
624
+ // Sync tasks.md checkboxes if out of sync with state.json
625
+ for (const taskId of completedTaskIds) {
626
+ const task = implTasks.find(t => t.id === taskId);
627
+ if (task && !task.completed) {
628
+ addOutput(`Syncing task ${taskId} checkbox in tasks.md`);
629
+ await services.taskParser.markTaskComplete(implSpecDir, taskId);
630
+ }
631
+ }
632
+ // Filter pending using state.json (source of truth)
633
+ const implPendingTasks = implTasks.filter(t => !completedTaskIds.includes(t.id));
634
+ setFlowState(prev => ({
635
+ ...prev,
636
+ tasks: implTasks,
637
+ totalTasks: implTasks.length
638
+ }));
639
+ if (implPendingTasks.length > 0) {
640
+ addOutput(`Resuming implementation: ${completedTaskIds.length} completed, ${implPendingTasks.length} pending`);
641
+ await runImplementation(workDir);
642
+ }
643
+ else {
644
+ addOutput('All tasks already completed!');
645
+ await completeFlow(workDir);
646
+ }
647
+ }
648
+ break;
649
+ default:
650
+ // For other phases, start fresh
651
+ addOutput(`Cannot resume from phase ${phaseType}, starting fresh...`);
652
+ await startFreshFlow();
653
+ }
654
+ };
655
+ // Start a fresh flow (original startFlow logic)
656
+ const startFreshFlow = async () => {
657
+ // Initialize log file first (in repo, will move to worktree if created)
658
+ const logPath = await initLogFile(repoPath);
659
+ addOutput(`Log file: ${logPath}`);
660
+ addOutput('');
661
+ // Run health check before starting
662
+ addOutput('Checking Claude API status...');
663
+ setFlowState(prev => ({ ...prev, isHealthChecking: true }));
664
+ const healthResult = await services.healthCheck.check({
665
+ tier: flags.tier,
666
+ sandbox: flags.sandbox,
667
+ timeoutMs: 30000
668
+ });
669
+ setFlowState(prev => ({ ...prev, isHealthChecking: false }));
670
+ if (!healthResult.healthy) {
671
+ await logToFile(`Health check failed: ${healthResult.message}`);
672
+ if (healthResult.error) {
673
+ await logToFile(`Error code: ${healthResult.error.code}`);
674
+ await logToFile(`Suggestion: ${healthResult.error.suggestion}`);
675
+ }
676
+ // Set error state with Claude error details
677
+ const errorMsg = healthResult.error
678
+ ? `${getClaudeErrorLabel(healthResult.error.code)}: ${healthResult.error.suggestion}`
679
+ : healthResult.message;
680
+ setFlowState(prev => ({
681
+ ...prev,
682
+ error: errorMsg,
683
+ claudeError: healthResult.error ?? null,
684
+ phase: { type: 'error', feature: featureName, error: errorMsg }
685
+ }));
686
+ return;
687
+ }
688
+ addOutput(`API ready (${healthResult.durationMs}ms)`);
689
+ addOutput('');
690
+ addOutput(`Starting flow: ${featureName}`);
691
+ addOutput(`Mode: ${mode}`);
692
+ addOutput('');
693
+ // Step 1: Create or reuse git worktree for isolation
694
+ addOutput('Setting up git worktree for feature isolation...');
695
+ // Check if worktree already exists
696
+ const existingWorktree = await services.worktreeService.check(repoPath, featureName);
697
+ let workDir = repoPath;
698
+ if (existingWorktree.exists) {
699
+ // Reuse existing worktree
700
+ workDir = existingWorktree.path;
701
+ setFlowState(prev => ({ ...prev, worktreePath: existingWorktree.path }));
702
+ addOutput(`Using existing worktree: ${existingWorktree.path}`);
703
+ addOutput(`Branch: ${existingWorktree.branch}`);
704
+ }
705
+ else {
706
+ // Create new worktree
707
+ const worktreeResult = await services.worktreeService.create(repoPath, featureName);
708
+ if (!worktreeResult.success) {
709
+ addOutput(`Worktree error: ${worktreeResult.error}`);
710
+ addOutput('Continuing without worktree isolation...');
711
+ // Continue without worktree
712
+ }
713
+ else {
714
+ workDir = worktreeResult.path;
715
+ setFlowState(prev => ({ ...prev, worktreePath: worktreeResult.path }));
716
+ addOutput(`Worktree created: ${worktreeResult.path}`);
717
+ addOutput(`Branch: feature/${sanitizeFeatureName(featureName)}`);
718
+ }
719
+ }
720
+ // Step 2: Transition to initializing
721
+ const initPhase = transitionPhase({
722
+ type: 'START',
723
+ feature: featureName,
724
+ description,
725
+ mode
726
+ });
727
+ await saveFlowState(initPhase, workDir);
728
+ // Initialize spec directory directly (no agent call needed)
729
+ addOutput('');
730
+ addOutput('Initializing spec directory...');
731
+ addOutput(`Working directory: ${workDir}`);
732
+ const initResult = await services.specInitService.init(workDir, featureName, description);
733
+ if (!initResult.success) {
734
+ transitionPhase({ type: 'ERROR', error: initResult.error ?? 'Initialization failed' });
735
+ return;
736
+ }
737
+ // IMPORTANT: Update the resolved feature name from spec-init result
738
+ // This ensures all subsequent commands use the correct feature name
739
+ setFlowState(prev => ({ ...prev, resolvedFeatureName: initResult.featureName }));
740
+ addOutput(`Spec directory: ${initResult.specDir}`);
741
+ addOutput(`Feature name: ${initResult.featureName}`);
742
+ // Commit init
743
+ await commitChanges(`initialize spec directory`, workDir);
744
+ // Step 3: Generate requirements - pass the resolved feature name
745
+ const reqPhase = transitionPhase({ type: 'PHASE_COMPLETE' });
746
+ await saveFlowState(reqPhase, workDir);
747
+ await runRequirementsPhase(workDir, initResult.featureName);
748
+ };
749
+ // Run requirements phase
750
+ const runRequirementsPhase = async (workDir, resolvedName) => {
751
+ // Use resolved name if provided, otherwise get from state or sanitize original
752
+ const effectiveName = resolvedName ?? flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName);
753
+ addOutput('');
754
+ addOutput('Generating requirements...');
755
+ const result = await executeCommand(`/red64:spec-requirements ${effectiveName} -y`, workDir);
756
+ if (!result.success) {
757
+ transitionPhase({ type: 'ERROR', error: result.error ?? 'Requirements generation failed' });
758
+ return;
759
+ }
760
+ // Commit requirements
761
+ await commitChanges(`generate requirements`, workDir);
762
+ // Transition to approval
763
+ const approvalPhase = transitionPhase({ type: 'PHASE_COMPLETE' });
764
+ await saveFlowState(approvalPhase, workDir);
765
+ };
766
+ // Run design phase
767
+ const runDesignPhase = async (workDir) => {
768
+ const effectiveName = flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName);
769
+ addOutput('');
770
+ addOutput('Generating technical design...');
771
+ const result = await executeCommand(`/red64:spec-design ${effectiveName} -y`, workDir);
772
+ if (!result.success) {
773
+ transitionPhase({ type: 'ERROR', error: result.error ?? 'Design generation failed' });
774
+ return;
775
+ }
776
+ // Commit design
777
+ await commitChanges(`generate technical design`, workDir);
778
+ // Transition to approval
779
+ const approvalPhase = transitionPhase({ type: 'PHASE_COMPLETE' });
780
+ await saveFlowState(approvalPhase, workDir);
781
+ };
782
+ // Run tasks phase
783
+ const runTasksPhase = async (workDir) => {
784
+ const effectiveName = flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName);
785
+ addOutput('');
786
+ addOutput('Generating implementation tasks...');
787
+ const result = await executeCommand(`/red64:spec-tasks ${effectiveName} -y`, workDir);
788
+ if (!result.success) {
789
+ transitionPhase({ type: 'ERROR', error: result.error ?? 'Tasks generation failed' });
790
+ return;
791
+ }
792
+ // Commit tasks
793
+ await commitChanges(`generate implementation tasks`, workDir);
794
+ // Parse tasks for implementation phase - use effective name for spec directory
795
+ const specDir = join(workDir, '.red64', 'specs', effectiveName);
796
+ const tasks = await services.taskParser.parse(specDir);
797
+ const pendingTasks = services.taskParser.getPendingTasks(tasks);
798
+ setFlowState(prev => ({
799
+ ...prev,
800
+ tasks: pendingTasks,
801
+ totalTasks: pendingTasks.length
802
+ }));
803
+ addOutput(`Found ${pendingTasks.length} tasks to implement`);
804
+ // Transition to approval
805
+ const approvalPhase = transitionPhase({ type: 'PHASE_COMPLETE' });
806
+ await saveFlowState(approvalPhase, workDir);
807
+ };
808
+ // Run implementation - one task at a time with commits
809
+ // ORCHESTRATOR-CONTROLLED: Marks tasks complete in both tasks.md and state.json
810
+ const runImplementation = async (workDir) => {
811
+ const { tasks, completedTasks: alreadyCompleted } = flowState;
812
+ const effectiveName = flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName);
813
+ const specDir = join(workDir, '.red64', 'specs', effectiveName);
814
+ // Filter out already completed tasks (from state.json, source of truth)
815
+ const pendingTasks = tasks.filter(t => !alreadyCompleted.includes(t.id));
816
+ if (pendingTasks.length === 0) {
817
+ addOutput('No tasks to implement');
818
+ transitionPhase({ type: 'PHASE_COMPLETE' });
819
+ await completeFlow(workDir);
820
+ return;
821
+ }
822
+ addOutput('');
823
+ addOutput('Starting implementation...');
824
+ addOutput(`Total tasks: ${tasks.length}, Pending: ${pendingTasks.length}`);
825
+ if (alreadyCompleted.length > 0) {
826
+ addOutput(`Already completed: ${alreadyCompleted.join(', ')}`);
827
+ }
828
+ addOutput('');
829
+ // Track completed tasks in this run
830
+ let currentCompleted = [...alreadyCompleted];
831
+ // Execute each pending task one at a time
832
+ for (let i = 0; i < pendingTasks.length; i++) {
833
+ const task = pendingTasks[i];
834
+ const overallIndex = tasks.findIndex(t => t.id === task.id);
835
+ const taskNum = overallIndex + 1;
836
+ setFlowState(prev => ({ ...prev, currentTask: taskNum }));
837
+ addOutput(`[${currentCompleted.length + 1}/${tasks.length}] Task ${task.id}: ${task.title}`);
838
+ // Run spec-impl for this specific task - use effective name
839
+ const result = await executeCommand(`/red64:spec-impl ${effectiveName} ${task.id} -y`, workDir);
840
+ if (!result.success) {
841
+ addOutput(`Task ${task.id} failed: ${result.error}`);
842
+ // Save progress so far before continuing
843
+ await saveFlowState(flowState.phase, workDir, currentCompleted);
844
+ // Continue to next task instead of failing entirely
845
+ continue;
846
+ }
847
+ // ORCHESTRATOR-CONTROLLED TASK COMPLETION:
848
+ // 1. Mark task complete in tasks.md
849
+ const markResult = await services.taskParser.markTaskComplete(specDir, task.id);
850
+ if (!markResult.success) {
851
+ addOutput(`Warning: Failed to mark task ${task.id} in tasks.md: ${markResult.error}`);
852
+ }
853
+ // 2. Update state with completed task
854
+ currentCompleted = [...currentCompleted, task.id];
855
+ setFlowState(prev => ({ ...prev, completedTasks: currentCompleted }));
856
+ // 3. Save state immediately (before commit, for crash recovery)
857
+ await saveFlowState(flowState.phase, workDir, currentCompleted);
858
+ // 4. Commit both tasks.md and state.json together
859
+ await commitChanges(services.commitService.formatTaskCommitMessage(effectiveName, taskNum, task.title), workDir);
860
+ addOutput(`Task ${task.id} completed`);
861
+ addOutput('');
862
+ }
863
+ // All tasks complete
864
+ addOutput('All tasks completed!');
865
+ await completeFlow(workDir);
866
+ };
867
+ // Complete the flow
868
+ const completeFlow = async (workDir) => {
869
+ const effectiveName = flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName);
870
+ const completePhase = { type: 'complete', feature: effectiveName };
871
+ transitionPhase({ type: 'PHASE_COMPLETE' });
872
+ await saveFlowState(completePhase, workDir);
873
+ addOutput('');
874
+ addOutput('Flow completed successfully!');
875
+ addOutput(`Worktree: ${flowState.worktreePath ?? 'none'}`);
876
+ addOutput(`Branch: feature/${sanitizeFeatureName(featureName)}`);
877
+ };
878
+ // Handle approval decision
879
+ const handleApproval = useCallback(async (decision) => {
880
+ const workDir = getWorkingDir();
881
+ const effectiveName = flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName);
882
+ if (decision === 'approve') {
883
+ const nextPhase = transitionPhase({ type: 'APPROVE' });
884
+ await saveFlowState(nextPhase, workDir);
885
+ // Route to appropriate next phase
886
+ switch (nextPhase.type) {
887
+ case 'design-generating':
888
+ await runDesignPhase(workDir);
889
+ break;
890
+ case 'tasks-generating':
891
+ await runTasksPhase(workDir);
892
+ break;
893
+ case 'implementing':
894
+ // Update spec.json to mark tasks as approved before implementation
895
+ addOutput('Marking tasks as approved...');
896
+ const approvalResult = await services.specInitService.updateTaskApproval(workDir, effectiveName);
897
+ if (!approvalResult.success) {
898
+ addOutput(`Warning: Failed to update spec.json: ${approvalResult.error}`);
899
+ }
900
+ await runImplementation(workDir);
901
+ break;
902
+ case 'gap-analysis':
903
+ // Brownfield: run gap analysis
904
+ addOutput('Running gap analysis...');
905
+ const gapResult = await executeCommand(`/red64:validate-gap ${effectiveName} -y`, workDir);
906
+ if (gapResult.success) {
907
+ await commitChanges(`gap analysis`, workDir);
908
+ }
909
+ transitionPhase({ type: 'PHASE_COMPLETE' });
910
+ break;
911
+ case 'design-validation':
912
+ // Brownfield: run design validation
913
+ addOutput('Validating design...');
914
+ const valResult = await executeCommand(`/red64:validate-design ${effectiveName} -y`, workDir);
915
+ if (valResult.success) {
916
+ await commitChanges(`design validation`, workDir);
917
+ }
918
+ transitionPhase({ type: 'PHASE_COMPLETE' });
919
+ break;
920
+ case 'complete':
921
+ await completeFlow(workDir);
922
+ break;
923
+ default:
924
+ addOutput(`Unexpected phase: ${nextPhase.type}`);
925
+ }
926
+ }
927
+ else if (decision === 'reject') {
928
+ const prevPhase = transitionPhase({ type: 'REJECT' });
929
+ await saveFlowState(prevPhase, workDir);
930
+ addOutput('Regenerating...');
931
+ // Re-run the appropriate generation phase
932
+ switch (prevPhase.type) {
933
+ case 'requirements-generating':
934
+ await runRequirementsPhase(workDir);
935
+ break;
936
+ case 'design-generating':
937
+ await runDesignPhase(workDir);
938
+ break;
939
+ case 'tasks-generating':
940
+ await runTasksPhase(workDir);
941
+ break;
942
+ }
943
+ }
944
+ else if (decision === 'pause') {
945
+ addOutput('Flow paused. Run the same start command to resume.');
946
+ addOutput(`Worktree: ${flowState.worktreePath ?? repoPath}`);
947
+ exit();
948
+ }
949
+ }, [flowState, transitionPhase, saveFlowState, getWorkingDir, exit]);
950
+ // Check if current phase is an approval phase
951
+ const isApprovalPhase = [
952
+ 'requirements-approval',
953
+ 'design-approval',
954
+ 'tasks-approval',
955
+ 'gap-review',
956
+ 'design-validation-review',
957
+ 'merge-decision'
958
+ ].includes(flowState.phase.type);
959
+ // Render phase indicator
960
+ const renderPhaseIndicator = () => {
961
+ const phaseInfo = PHASE_LABELS[flowState.phase.type] ?? { label: flowState.phase.type, description: '' };
962
+ return (_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: phaseInfo.label }), _jsxs(Text, { dimColor: true, children: [" - ", phaseInfo.description] }), flowState.currentTask > 0 && flowState.totalTasks > 0 && (_jsxs(Text, { dimColor: true, children: [" [", flowState.currentTask, "/", flowState.totalTasks, "]"] }))] }));
963
+ };
964
+ // Render terminal phases
965
+ if (flowState.phase.type === 'complete') {
966
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "green", children: "Flow Complete" }) }), _jsxs(Text, { children: ["Feature \"", featureName, "\" has been implemented."] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Spec: .red64/specs/", sanitizeFeatureName(featureName), "/"] }), _jsxs(Text, { dimColor: true, children: ["Branch: feature/", sanitizeFeatureName(featureName)] }), flowState.worktreePath && (_jsxs(Text, { dimColor: true, children: ["Worktree: ", flowState.worktreePath] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Next: Review changes and create a PR" }) })] })] }));
967
+ }
968
+ if (flowState.phase.type === 'error') {
969
+ const logPath = logFileRef.current ?? join(repoPath, '.red64', 'flows', sanitizeFeatureName(featureName), 'flow.log');
970
+ const claudeError = flowState.claudeError;
971
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "red", children: claudeError ? `API Error: ${getClaudeErrorLabel(claudeError.code)}` : 'Flow Error' }) }), claudeError ? (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: "red", children: claudeError.message }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "yellow", bold: true, children: "Suggestion: " }), _jsx(Text, { color: "yellow", children: claudeError.suggestion })] }), !claudeError.recoverable && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "red", dimColor: true, children: "This error requires manual intervention before retrying." }) }))] })) : (_jsx(Text, { color: "red", children: flowState.error ?? 'An unknown error occurred' })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["Feature: ", featureName] }), flowState.worktreePath && (_jsxs(Text, { dimColor: true, children: ["Worktree: ", flowState.worktreePath] })), !claudeError && (_jsxs(Text, { dimColor: true, children: ["Phase: ", flowState.phase.type] })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Log file:" }), _jsx(Text, { color: "yellow", children: logPath })] }), claudeError?.recoverable && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Run \"red64 start ", sanitizeFeatureName(featureName), "\" to retry."] }) }))] })] }));
972
+ }
973
+ if (flowState.phase.type === 'aborted') {
974
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "yellow", children: "Flow Aborted" }) }), _jsxs(Text, { children: ["Feature flow \"", featureName, "\" was aborted."] })] }));
975
+ }
976
+ // Should sidebar be shown?
977
+ const showSidebar = flowState.worktreePath !== null || flowState.phase.type !== 'idle';
978
+ return (_jsxs(Box, { flexDirection: "row", paddingX: 1, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: "red64 start" }), _jsxs(Text, { dimColor: true, children: [" - ", featureName] })] }), flowState.worktreePath && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { dimColor: true, children: ["Worktree: ", flowState.worktreePath] }) })), renderPhaseIndicator(), _jsx(Box, { flexDirection: "column", marginBottom: 1, children: flowState.output.slice(-10).map((line, i) => (_jsx(Text, { dimColor: i < flowState.output.length - 1, children: line }, i))) }), flowState.isHealthChecking && (_jsx(Box, { marginBottom: 1, children: _jsx(Spinner, { label: "Checking Claude API status..." }) })), flowState.isExecuting && !flowState.isHealthChecking && (_jsx(Box, { marginBottom: 1, children: _jsx(Spinner, { label: "Processing..." }) })), flowState.error && !flowState.isExecuting && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: flowState.error }) })), flowState.preStartStep.type === 'existing-flow-detected' && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Existing Flow Detected" }), _jsxs(Text, { dimColor: true, children: ["Phase: ", flowState.preStartStep.existingState.phase.type] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: EXISTING_FLOW_OPTIONS, onChange: handleExistingFlowDecision }) })] })), flowState.preStartStep.type === 'uncommitted-changes' && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Uncommitted Changes Detected" }), _jsxs(Text, { dimColor: true, children: [flowState.preStartStep.gitStatus.staged, " staged, ", flowState.preStartStep.gitStatus.unstaged, " unstaged, ", flowState.preStartStep.gitStatus.untracked, " untracked"] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: UNCOMMITTED_CHANGES_OPTIONS, onChange: handleUncommittedChangesDecision }) })] })), isApprovalPhase && !flowState.isExecuting && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, children: [_jsx(Text, { bold: true, children: "Review Required" }), _jsxs(Text, { dimColor: true, children: ["Review output in .red64/specs/", sanitizeFeatureName(featureName), "/"] }), _jsx(Box, { marginTop: 1, children: _jsx(Select, { options: APPROVAL_OPTIONS, onChange: handleApproval }) })] }))] }), showSidebar && (_jsx(FeatureSidebar, { featureName: flowState.resolvedFeatureName ?? sanitizeFeatureName(featureName), sandboxMode: flags.sandbox ?? false, currentPhase: flowState.phase.type, mode: mode, currentTask: flowState.currentTask, totalTasks: flowState.totalTasks, commitCount: flowState.commitCount, agent: flowState.agent, model: flags.model }))] }));
979
+ };
980
+ /**
981
+ * Convert ExtendedFlowPhase to FlowPhase for state persistence
982
+ */
983
+ function convertToFlowPhase(phase) {
984
+ switch (phase.type) {
985
+ case 'idle':
986
+ return { type: 'idle' };
987
+ case 'initializing':
988
+ return { type: 'initializing', feature: phase.feature, description: phase.description };
989
+ case 'requirements-generating':
990
+ return { type: 'requirements-generating', feature: phase.feature };
991
+ case 'requirements-approval':
992
+ return { type: 'requirements-review', feature: phase.feature };
993
+ case 'design-generating':
994
+ return { type: 'design-generating', feature: phase.feature };
995
+ case 'design-approval':
996
+ return { type: 'design-review', feature: phase.feature };
997
+ case 'tasks-generating':
998
+ return { type: 'tasks-generating', feature: phase.feature };
999
+ case 'tasks-approval':
1000
+ return { type: 'tasks-review', feature: phase.feature };
1001
+ case 'implementing':
1002
+ return {
1003
+ type: 'implementing',
1004
+ feature: phase.feature,
1005
+ currentTask: phase.currentTask,
1006
+ totalTasks: phase.totalTasks
1007
+ };
1008
+ case 'complete':
1009
+ return { type: 'complete', feature: phase.feature };
1010
+ case 'aborted':
1011
+ return { type: 'aborted', feature: phase.feature, reason: phase.reason };
1012
+ case 'error':
1013
+ return { type: 'error', feature: phase.feature, error: phase.error };
1014
+ default:
1015
+ if ('feature' in phase) {
1016
+ return { type: 'idle' };
1017
+ }
1018
+ return { type: 'idle' };
1019
+ }
1020
+ }
1021
+ //# sourceMappingURL=StartScreen.js.map