rafcode 1.0.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 (370) hide show
  1. package/.claude/settings.local.json +32 -0
  2. package/CLAUDE.md +187 -0
  3. package/LICENSE +21 -0
  4. package/RAF/001-raf-task-improvements/input.md +9 -0
  5. package/RAF/001-raf-task-improvements/outcomes/001-add-decisions-folder.md +21 -0
  6. package/RAF/001-raf-task-improvements/outcomes/002-fix-write-error-on-shutdown.md +22 -0
  7. package/RAF/001-raf-task-improvements/outcomes/003-stash-changes-on-failure.md +34 -0
  8. package/RAF/001-raf-task-improvements/outcomes/004-add-project-name-to-commits.md +28 -0
  9. package/RAF/001-raf-task-improvements/outcomes/005-add-running-time-display.md +36 -0
  10. package/RAF/001-raf-task-improvements/outcomes/006-add-task-name-to-logs.md +22 -0
  11. package/RAF/001-raf-task-improvements/outcomes/007-show-model-at-task-start.md +52 -0
  12. package/RAF/001-raf-task-improvements/outcomes/009-remove-editor-placeholder-text.md +20 -0
  13. package/RAF/001-raf-task-improvements/outcomes/SUMMARY.md +83 -0
  14. package/RAF/001-raf-task-improvements/plans/001-add-decisions-folder.md +38 -0
  15. package/RAF/001-raf-task-improvements/plans/002-fix-write-error-on-shutdown.md +33 -0
  16. package/RAF/001-raf-task-improvements/plans/003-stash-changes-on-failure.md +37 -0
  17. package/RAF/001-raf-task-improvements/plans/004-add-project-name-to-commits.md +34 -0
  18. package/RAF/001-raf-task-improvements/plans/005-add-running-time-display.md +39 -0
  19. package/RAF/001-raf-task-improvements/plans/006-add-task-name-to-logs.md +37 -0
  20. package/RAF/001-raf-task-improvements/plans/009-remove-editor-placeholder-text.md +34 -0
  21. package/RAF/002-raf-task-improvements-execution/decisions/DECISIONS.md +13 -0
  22. package/RAF/002-raf-task-improvements-execution/input.md +3 -0
  23. package/RAF/002-raf-task-improvements-execution/outcomes/001-commit-show-model-at-task-start.md +17 -0
  24. package/RAF/002-raf-task-improvements-execution/outcomes/002-delete-skipped-plan.md +23 -0
  25. package/RAF/002-raf-task-improvements-execution/outcomes/SUMMARY.md +32 -0
  26. package/RAF/002-raf-task-improvements-execution/plans/001-commit-show-model-at-task-start.md +37 -0
  27. package/RAF/002-raf-task-improvements-execution/plans/002-delete-skipped-plan.md +23 -0
  28. package/RAF/003-multi-project-execution/decisions/DECISIONS.md +68 -0
  29. package/RAF/003-multi-project-execution/input.md +6 -0
  30. package/RAF/003-multi-project-execution/outcomes/001-remove-state-json.md +52 -0
  31. package/RAF/003-multi-project-execution/outcomes/002-update-raf-status.md +50 -0
  32. package/RAF/003-multi-project-execution/outcomes/003-simplify-git-logic.md +35 -0
  33. package/RAF/003-multi-project-execution/outcomes/004-auto-commit-planning.md +43 -0
  34. package/RAF/003-multi-project-execution/outcomes/005-rerun-failed-tasks.md +43 -0
  35. package/RAF/003-multi-project-execution/outcomes/006-multi-project-execution.md +42 -0
  36. package/RAF/003-multi-project-execution/outcomes/007-verify-timeout.md +54 -0
  37. package/RAF/003-multi-project-execution/outcomes/008-move-decisions-file.md +38 -0
  38. package/RAF/003-multi-project-execution/outcomes/SUMMARY.md +79 -0
  39. package/RAF/003-multi-project-execution/plans/001-remove-state-json.md +71 -0
  40. package/RAF/003-multi-project-execution/plans/002-update-raf-status.md +65 -0
  41. package/RAF/003-multi-project-execution/plans/003-simplify-git-logic.md +74 -0
  42. package/RAF/003-multi-project-execution/plans/004-auto-commit-planning.md +57 -0
  43. package/RAF/003-multi-project-execution/plans/005-rerun-failed-tasks.md +69 -0
  44. package/RAF/003-multi-project-execution/plans/006-multi-project-execution.md +81 -0
  45. package/RAF/003-multi-project-execution/plans/007-verify-timeout.md +63 -0
  46. package/RAF/003-multi-project-execution/plans/008-move-decisions-file.md +78 -0
  47. package/RAF/004-task-naming-optimization/decisions.md +22 -0
  48. package/RAF/004-task-naming-optimization/input.md +6 -0
  49. package/RAF/004-task-naming-optimization/outcomes/001-remove-summary-file.md +17 -0
  50. package/RAF/004-task-naming-optimization/outcomes/002-base36-project-numbering.md +32 -0
  51. package/RAF/004-task-naming-optimization/outcomes/003-improve-haiku-prompt.md +20 -0
  52. package/RAF/004-task-naming-optimization/outcomes/SUMMARY.md +28 -0
  53. package/RAF/004-task-naming-optimization/plans/001-remove-summary-file.md +34 -0
  54. package/RAF/004-task-naming-optimization/plans/002-base36-project-numbering.md +56 -0
  55. package/RAF/004-task-naming-optimization/plans/003-improve-haiku-prompt.md +50 -0
  56. package/RAF/005-task-naming-improvements/decisions.md +60 -0
  57. package/RAF/005-task-naming-improvements/input.md +2 -0
  58. package/RAF/005-task-naming-improvements/outcomes/001-enhance-identifier-resolution.md +42 -0
  59. package/RAF/005-task-naming-improvements/outcomes/002-add-identifier-support-to-status.md +38 -0
  60. package/RAF/005-task-naming-improvements/outcomes/003-update-do-for-full-folder-names.md +44 -0
  61. package/RAF/005-task-naming-improvements/outcomes/004-implement-amend-flag-for-plan.md +55 -0
  62. package/RAF/005-task-naming-improvements/outcomes/005-commit-outcomes-on-complete.md +47 -0
  63. package/RAF/005-task-naming-improvements/outcomes/006-update-execution-prompt-commit-schema.md +40 -0
  64. package/RAF/005-task-naming-improvements/outcomes/007-allow-pending-task-amendments.md +38 -0
  65. package/RAF/005-task-naming-improvements/outcomes/008-fix-timeout-label.md +24 -0
  66. package/RAF/005-task-naming-improvements/plans/001-enhance-identifier-resolution.md +46 -0
  67. package/RAF/005-task-naming-improvements/plans/002-add-identifier-support-to-status.md +36 -0
  68. package/RAF/005-task-naming-improvements/plans/003-update-do-for-full-folder-names.md +38 -0
  69. package/RAF/005-task-naming-improvements/plans/004-implement-amend-flag-for-plan.md +67 -0
  70. package/RAF/005-task-naming-improvements/plans/005-commit-outcomes-on-complete.md +86 -0
  71. package/RAF/005-task-naming-improvements/plans/006-update-execution-prompt-commit-schema.md +60 -0
  72. package/RAF/005-task-naming-improvements/plans/007-allow-pending-task-amendments.md +60 -0
  73. package/RAF/005-task-naming-improvements/plans/008-fix-timeout-label.md +31 -0
  74. package/RAF/006-fix-double-summary-headers/decisions.md +28 -0
  75. package/RAF/006-fix-double-summary-headers/input.md +3 -0
  76. package/RAF/006-fix-double-summary-headers/outcomes/001-fix-double-summary-headers.md +29 -0
  77. package/RAF/006-fix-double-summary-headers/outcomes/002-update-readme-for-npm.md +31 -0
  78. package/RAF/006-fix-double-summary-headers/outcomes/003-npm-publish-instructions.md +30 -0
  79. package/RAF/006-fix-double-summary-headers/outcomes/004-flexible-project-lookup.md +47 -0
  80. package/RAF/006-fix-double-summary-headers/plans/001-fix-double-summary-headers.md +42 -0
  81. package/RAF/006-fix-double-summary-headers/plans/002-update-readme-for-npm.md +44 -0
  82. package/RAF/006-fix-double-summary-headers/plans/003-npm-publish-instructions.md +45 -0
  83. package/RAF/006-fix-double-summary-headers/plans/004-flexible-project-lookup.md +40 -0
  84. package/RAF/007-improve-outcome-format/decisions.md +28 -0
  85. package/RAF/007-improve-outcome-format/input.md +2 -0
  86. package/RAF/007-improve-outcome-format/outcomes/001-update-execution-prompt.md +10 -0
  87. package/RAF/007-improve-outcome-format/outcomes/002-update-state-derivation.md +17 -0
  88. package/RAF/007-improve-outcome-format/outcomes/003-update-do-command-outcome-handling.md +16 -0
  89. package/RAF/007-improve-outcome-format/outcomes/004-implement-failure-analysis.md +16 -0
  90. package/RAF/007-improve-outcome-format/outcomes/005-update-documentation.md +15 -0
  91. package/RAF/007-improve-outcome-format/plans/001-update-execution-prompt.md +36 -0
  92. package/RAF/007-improve-outcome-format/plans/002-update-state-derivation.md +35 -0
  93. package/RAF/007-improve-outcome-format/plans/003-update-do-command-outcome-handling.md +37 -0
  94. package/RAF/007-improve-outcome-format/plans/004-implement-failure-analysis.md +44 -0
  95. package/RAF/007-improve-outcome-format/plans/005-update-documentation.md +33 -0
  96. package/RAF/008-beautiful-do/decisions.md +31 -0
  97. package/RAF/008-beautiful-do/input.md +1 -0
  98. package/RAF/008-beautiful-do/outcomes/001-terminal-symbols.md +55 -0
  99. package/RAF/008-beautiful-do/outcomes/002-refactor-do-output.md +95 -0
  100. package/RAF/008-beautiful-do/outcomes/003-refactor-status-output.md +71 -0
  101. package/RAF/008-beautiful-do/outcomes/004-simplify-logger.md +53 -0
  102. package/RAF/008-beautiful-do/outcomes/005-add-tests.md +41 -0
  103. package/RAF/008-beautiful-do/plans/001-terminal-symbols.md +41 -0
  104. package/RAF/008-beautiful-do/plans/002-refactor-do-output.md +44 -0
  105. package/RAF/008-beautiful-do/plans/003-refactor-status-output.md +37 -0
  106. package/RAF/008-beautiful-do/plans/004-simplify-logger.md +32 -0
  107. package/RAF/008-beautiful-do/plans/005-add-tests.md +40 -0
  108. package/RAF/009-system-promt-ammend/decisions.md +13 -0
  109. package/RAF/009-system-promt-ammend/input.md +9 -0
  110. package/RAF/009-system-promt-ammend/outcomes/001-model-override.md +79 -0
  111. package/RAF/009-system-promt-ammend/outcomes/002-system-prompt-append.md +51 -0
  112. package/RAF/009-system-promt-ammend/outcomes/003-retry-context.md +60 -0
  113. package/RAF/009-system-promt-ammend/plans/001-model-override.md +61 -0
  114. package/RAF/009-system-promt-ammend/plans/002-system-prompt-append.md +56 -0
  115. package/RAF/009-system-promt-ammend/plans/003-retry-context.md +76 -0
  116. package/RAF/010-outcome-marker-fallback/decisions.md +19 -0
  117. package/RAF/010-outcome-marker-fallback/input.md +1 -0
  118. package/RAF/010-outcome-marker-fallback/outcomes/001-outcome-file-marker-fallback.md +35 -0
  119. package/RAF/010-outcome-marker-fallback/outcomes/002-creative-project-naming.md +47 -0
  120. package/RAF/010-outcome-marker-fallback/plans/001-outcome-file-marker-fallback.md +58 -0
  121. package/RAF/010-outcome-marker-fallback/plans/002-creative-project-naming.md +68 -0
  122. package/RAF/011-do-task-in-commit/decisions.md +22 -0
  123. package/RAF/011-do-task-in-commit/input.md +1 -0
  124. package/RAF/011-do-task-in-commit/outcomes/001-update-execution-prompt.md +54 -0
  125. package/RAF/011-do-task-in-commit/outcomes/002-update-tests.md +61 -0
  126. package/RAF/011-do-task-in-commit/outcomes/003-update-documentation.md +51 -0
  127. package/RAF/011-do-task-in-commit/plans/001-update-execution-prompt.md +46 -0
  128. package/RAF/011-do-task-in-commit/plans/002-update-tests.md +51 -0
  129. package/RAF/011-do-task-in-commit/plans/003-update-documentation.md +45 -0
  130. package/RAF/012-name-picker-buffet/decisions.md +40 -0
  131. package/RAF/012-name-picker-buffet/input.md +6 -0
  132. package/RAF/012-name-picker-buffet/outcomes/001-name-picker-for-raf-plan.md +49 -0
  133. package/RAF/012-name-picker-buffet/outcomes/002-interactive-project-picker-for-raf-do.md +49 -0
  134. package/RAF/012-name-picker-buffet/outcomes/003-raf-status-truncation.md +55 -0
  135. package/RAF/012-name-picker-buffet/outcomes/004-failure-reason-details.md +65 -0
  136. package/RAF/012-name-picker-buffet/outcomes/005-remove-raf-commits.md +57 -0
  137. package/RAF/012-name-picker-buffet/outcomes/006-update-execution-prompt-for-commits.md +47 -0
  138. package/RAF/012-name-picker-buffet/outcomes/007-fix-plan-mode-user-prompt.md +83 -0
  139. package/RAF/012-name-picker-buffet/outcomes/008-add-auto-flag-for-plan-mode.md +77 -0
  140. package/RAF/012-name-picker-buffet/plans/001-name-picker-for-raf-plan.md +47 -0
  141. package/RAF/012-name-picker-buffet/plans/002-interactive-project-picker-for-raf-do.md +43 -0
  142. package/RAF/012-name-picker-buffet/plans/003-raf-status-truncation.md +36 -0
  143. package/RAF/012-name-picker-buffet/plans/004-failure-reason-details.md +46 -0
  144. package/RAF/012-name-picker-buffet/plans/005-remove-raf-commits.md +42 -0
  145. package/RAF/012-name-picker-buffet/plans/006-update-execution-prompt-for-commits.md +47 -0
  146. package/RAF/012-name-picker-buffet/plans/007-fix-plan-mode-user-prompt.md +55 -0
  147. package/RAF/012-name-picker-buffet/plans/008-add-auto-flag-for-plan-mode.md +49 -0
  148. package/RAF/013-dependencies-watchdog/decisions.md +37 -0
  149. package/RAF/013-dependencies-watchdog/input.md +1 -0
  150. package/RAF/013-dependencies-watchdog/outcomes/001-define-dependency-syntax.md +56 -0
  151. package/RAF/013-dependencies-watchdog/outcomes/002-update-planning-prompts.md +60 -0
  152. package/RAF/013-dependencies-watchdog/outcomes/003-parse-dependencies-update-state.md +81 -0
  153. package/RAF/013-dependencies-watchdog/outcomes/004-implement-dependency-checking-in-do.md +116 -0
  154. package/RAF/013-dependencies-watchdog/outcomes/005-update-execution-prompts.md +75 -0
  155. package/RAF/013-dependencies-watchdog/outcomes/006-add-tests.md +100 -0
  156. package/RAF/013-dependencies-watchdog/outcomes/007-add-act-alias.md +46 -0
  157. package/RAF/013-dependencies-watchdog/outcomes/008-add-exit-message.md +52 -0
  158. package/RAF/013-dependencies-watchdog/plans/001-define-dependency-syntax.md +32 -0
  159. package/RAF/013-dependencies-watchdog/plans/002-update-planning-prompts.md +38 -0
  160. package/RAF/013-dependencies-watchdog/plans/003-parse-dependencies-update-state.md +46 -0
  161. package/RAF/013-dependencies-watchdog/plans/004-implement-dependency-checking-in-do.md +48 -0
  162. package/RAF/013-dependencies-watchdog/plans/005-update-execution-prompts.md +44 -0
  163. package/RAF/013-dependencies-watchdog/plans/006-add-tests.md +54 -0
  164. package/RAF/013-dependencies-watchdog/plans/007-add-act-alias.md +26 -0
  165. package/RAF/013-dependencies-watchdog/plans/008-add-exit-message.md +31 -0
  166. package/RAF/014-watchdog/decisions.md +16 -0
  167. package/RAF/014-watchdog/input.md +2 -0
  168. package/RAF/014-watchdog/outcomes/001-amend-flag-position.md +50 -0
  169. package/RAF/014-watchdog/outcomes/002-details-only-on-failure.md +58 -0
  170. package/RAF/014-watchdog/plans/001-amend-flag-position.md +34 -0
  171. package/RAF/014-watchdog/plans/002-details-only-on-failure.md +46 -0
  172. package/RAF/015-name-lottery/decisions.md +14 -0
  173. package/RAF/015-name-lottery/input.md +3 -0
  174. package/RAF/015-name-lottery/outcomes/001-auto-pick-project-name.md +31 -0
  175. package/RAF/015-name-lottery/outcomes/002-mention-plan-files-in-commit.md +23 -0
  176. package/RAF/015-name-lottery/outcomes/003-fix-input-md-in-amend-flow.md +44 -0
  177. package/RAF/015-name-lottery/plans/001-auto-pick-project-name.md +38 -0
  178. package/RAF/015-name-lottery/plans/002-mention-plan-files-in-commit.md +32 -0
  179. package/RAF/015-name-lottery/plans/003-fix-input-md-in-amend-flow.md +44 -0
  180. package/README.md +116 -0
  181. package/dist/commands/do.d.ts +12 -0
  182. package/dist/commands/do.d.ts.map +1 -0
  183. package/dist/commands/do.js +684 -0
  184. package/dist/commands/do.js.map +1 -0
  185. package/dist/commands/plan.d.ts +3 -0
  186. package/dist/commands/plan.d.ts.map +1 -0
  187. package/dist/commands/plan.js +345 -0
  188. package/dist/commands/plan.js.map +1 -0
  189. package/dist/commands/status.d.ts +3 -0
  190. package/dist/commands/status.d.ts.map +1 -0
  191. package/dist/commands/status.js +117 -0
  192. package/dist/commands/status.js.map +1 -0
  193. package/dist/core/claude-runner.d.ts +78 -0
  194. package/dist/core/claude-runner.d.ts.map +1 -0
  195. package/dist/core/claude-runner.js +297 -0
  196. package/dist/core/claude-runner.js.map +1 -0
  197. package/dist/core/editor.d.ts +10 -0
  198. package/dist/core/editor.d.ts.map +1 -0
  199. package/dist/core/editor.js +77 -0
  200. package/dist/core/editor.js.map +1 -0
  201. package/dist/core/failure-analyzer.d.ts +28 -0
  202. package/dist/core/failure-analyzer.d.ts.map +1 -0
  203. package/dist/core/failure-analyzer.js +305 -0
  204. package/dist/core/failure-analyzer.js.map +1 -0
  205. package/dist/core/git.d.ts +42 -0
  206. package/dist/core/git.d.ts.map +1 -0
  207. package/dist/core/git.js +148 -0
  208. package/dist/core/git.js.map +1 -0
  209. package/dist/core/project-manager.d.ts +72 -0
  210. package/dist/core/project-manager.d.ts.map +1 -0
  211. package/dist/core/project-manager.js +193 -0
  212. package/dist/core/project-manager.js.map +1 -0
  213. package/dist/core/retry-handler.d.ts +19 -0
  214. package/dist/core/retry-handler.d.ts.map +1 -0
  215. package/dist/core/retry-handler.js +51 -0
  216. package/dist/core/retry-handler.js.map +1 -0
  217. package/dist/core/shutdown-handler.d.ts +30 -0
  218. package/dist/core/shutdown-handler.d.ts.map +1 -0
  219. package/dist/core/shutdown-handler.js +79 -0
  220. package/dist/core/shutdown-handler.js.map +1 -0
  221. package/dist/core/state-derivation.d.ts +82 -0
  222. package/dist/core/state-derivation.d.ts.map +1 -0
  223. package/dist/core/state-derivation.js +271 -0
  224. package/dist/core/state-derivation.js.map +1 -0
  225. package/dist/core/state-manager.d.ts +54 -0
  226. package/dist/core/state-manager.d.ts.map +1 -0
  227. package/dist/core/state-manager.js +198 -0
  228. package/dist/core/state-manager.js.map +1 -0
  229. package/dist/index.d.ts +3 -0
  230. package/dist/index.d.ts.map +1 -0
  231. package/dist/index.js +16 -0
  232. package/dist/index.js.map +1 -0
  233. package/dist/parsers/output-parser.d.ts +19 -0
  234. package/dist/parsers/output-parser.d.ts.map +1 -0
  235. package/dist/parsers/output-parser.js +137 -0
  236. package/dist/parsers/output-parser.js.map +1 -0
  237. package/dist/prompts/amend.d.ts +20 -0
  238. package/dist/prompts/amend.d.ts.map +1 -0
  239. package/dist/prompts/amend.js +166 -0
  240. package/dist/prompts/amend.js.map +1 -0
  241. package/dist/prompts/execution.d.ts +30 -0
  242. package/dist/prompts/execution.d.ts.map +1 -0
  243. package/dist/prompts/execution.js +179 -0
  244. package/dist/prompts/execution.js.map +1 -0
  245. package/dist/prompts/planning.d.ts +15 -0
  246. package/dist/prompts/planning.d.ts.map +1 -0
  247. package/dist/prompts/planning.js +163 -0
  248. package/dist/prompts/planning.js.map +1 -0
  249. package/dist/types/config.d.ts +26 -0
  250. package/dist/types/config.d.ts.map +1 -0
  251. package/dist/types/config.js +7 -0
  252. package/dist/types/config.js.map +1 -0
  253. package/dist/types/state.d.ts +33 -0
  254. package/dist/types/state.d.ts.map +1 -0
  255. package/dist/types/state.js +28 -0
  256. package/dist/types/state.js.map +1 -0
  257. package/dist/ui/name-picker-subprocess.d.ts +11 -0
  258. package/dist/ui/name-picker-subprocess.d.ts.map +1 -0
  259. package/dist/ui/name-picker-subprocess.js +83 -0
  260. package/dist/ui/name-picker-subprocess.js.map +1 -0
  261. package/dist/ui/name-picker.d.ts +19 -0
  262. package/dist/ui/name-picker.d.ts.map +1 -0
  263. package/dist/ui/name-picker.js +173 -0
  264. package/dist/ui/name-picker.js.map +1 -0
  265. package/dist/ui/project-picker.d.ts +27 -0
  266. package/dist/ui/project-picker.d.ts.map +1 -0
  267. package/dist/ui/project-picker.js +58 -0
  268. package/dist/ui/project-picker.js.map +1 -0
  269. package/dist/utils/config.d.ts +24 -0
  270. package/dist/utils/config.d.ts.map +1 -0
  271. package/dist/utils/config.js +63 -0
  272. package/dist/utils/config.js.map +1 -0
  273. package/dist/utils/logger.d.ts +32 -0
  274. package/dist/utils/logger.d.ts.map +1 -0
  275. package/dist/utils/logger.js +60 -0
  276. package/dist/utils/logger.js.map +1 -0
  277. package/dist/utils/name-generator.d.ts +20 -0
  278. package/dist/utils/name-generator.d.ts.map +1 -0
  279. package/dist/utils/name-generator.js +183 -0
  280. package/dist/utils/name-generator.js.map +1 -0
  281. package/dist/utils/paths.d.ts +132 -0
  282. package/dist/utils/paths.d.ts.map +1 -0
  283. package/dist/utils/paths.js +412 -0
  284. package/dist/utils/paths.js.map +1 -0
  285. package/dist/utils/status-line.d.ts +14 -0
  286. package/dist/utils/status-line.d.ts.map +1 -0
  287. package/dist/utils/status-line.js +36 -0
  288. package/dist/utils/status-line.js.map +1 -0
  289. package/dist/utils/terminal-symbols.d.ts +50 -0
  290. package/dist/utils/terminal-symbols.d.ts.map +1 -0
  291. package/dist/utils/terminal-symbols.js +97 -0
  292. package/dist/utils/terminal-symbols.js.map +1 -0
  293. package/dist/utils/timer.d.ts +17 -0
  294. package/dist/utils/timer.d.ts.map +1 -0
  295. package/dist/utils/timer.js +56 -0
  296. package/dist/utils/timer.js.map +1 -0
  297. package/dist/utils/validation.d.ts +17 -0
  298. package/dist/utils/validation.d.ts.map +1 -0
  299. package/dist/utils/validation.js +106 -0
  300. package/dist/utils/validation.js.map +1 -0
  301. package/dist/utils/version.d.ts +2 -0
  302. package/dist/utils/version.d.ts.map +1 -0
  303. package/dist/utils/version.js +12 -0
  304. package/dist/utils/version.js.map +1 -0
  305. package/jest.config.ts +30 -0
  306. package/package.json +55 -0
  307. package/src/commands/do.ts +829 -0
  308. package/src/commands/plan.ts +422 -0
  309. package/src/commands/status.ts +146 -0
  310. package/src/core/claude-runner.ts +374 -0
  311. package/src/core/editor.ts +85 -0
  312. package/src/core/failure-analyzer.ts +372 -0
  313. package/src/core/git.ts +166 -0
  314. package/src/core/project-manager.ts +243 -0
  315. package/src/core/retry-handler.ts +72 -0
  316. package/src/core/shutdown-handler.ts +93 -0
  317. package/src/core/state-derivation.ts +343 -0
  318. package/src/index.ts +20 -0
  319. package/src/parsers/output-parser.ts +164 -0
  320. package/src/prompts/amend.ts +194 -0
  321. package/src/prompts/execution.ts +223 -0
  322. package/src/prompts/planning.ts +175 -0
  323. package/src/types/config.ts +35 -0
  324. package/src/ui/name-picker-subprocess.ts +96 -0
  325. package/src/ui/name-picker.ts +198 -0
  326. package/src/ui/project-picker.ts +80 -0
  327. package/src/utils/config.ts +69 -0
  328. package/src/utils/logger.ts +81 -0
  329. package/src/utils/name-generator.ts +211 -0
  330. package/src/utils/paths.ts +497 -0
  331. package/src/utils/status-line.ts +45 -0
  332. package/src/utils/terminal-symbols.ts +124 -0
  333. package/src/utils/timer.ts +64 -0
  334. package/src/utils/validation.ts +132 -0
  335. package/src/utils/version.ts +12 -0
  336. package/tests/unit/claude-runner-interactive.test.ts +343 -0
  337. package/tests/unit/claude-runner.test.ts +629 -0
  338. package/tests/unit/command-output.test.ts +295 -0
  339. package/tests/unit/config.test.ts +72 -0
  340. package/tests/unit/dependency-integration.test.ts +559 -0
  341. package/tests/unit/do-blocked-tasks.test.ts +323 -0
  342. package/tests/unit/do-command.test.ts +198 -0
  343. package/tests/unit/do-multiproject.test.ts +270 -0
  344. package/tests/unit/do-rerun.test.ts +270 -0
  345. package/tests/unit/execution-prompt.test.ts +406 -0
  346. package/tests/unit/failure-analyzer.test.ts +276 -0
  347. package/tests/unit/failure-history.test.ts +143 -0
  348. package/tests/unit/git-stash.test.ts +138 -0
  349. package/tests/unit/git.test.ts +80 -0
  350. package/tests/unit/logger.test.ts +132 -0
  351. package/tests/unit/name-generator.test.ts +283 -0
  352. package/tests/unit/name-picker.test.ts +179 -0
  353. package/tests/unit/outcome-content.test.ts +166 -0
  354. package/tests/unit/output-parser.test.ts +178 -0
  355. package/tests/unit/paths.test.ts +741 -0
  356. package/tests/unit/plan-command-amend-flag.test.ts +115 -0
  357. package/tests/unit/plan-command-amend-input.test.ts +156 -0
  358. package/tests/unit/plan-command-auto-flag.test.ts +112 -0
  359. package/tests/unit/plan-command.test.ts +580 -0
  360. package/tests/unit/planning-prompt.test.ts +137 -0
  361. package/tests/unit/project-manager.test.ts +265 -0
  362. package/tests/unit/project-picker.test.ts +338 -0
  363. package/tests/unit/retry-handler.test.ts +89 -0
  364. package/tests/unit/state-derivation.test.ts +714 -0
  365. package/tests/unit/status-command.test.ts +271 -0
  366. package/tests/unit/status-line.test.ts +92 -0
  367. package/tests/unit/terminal-symbols.test.ts +214 -0
  368. package/tests/unit/timer.test.ts +102 -0
  369. package/tests/unit/validation.test.ts +118 -0
  370. package/tsconfig.json +26 -0
@@ -0,0 +1,684 @@
1
+ import * as fs from 'node:fs';
2
+ import { Command } from 'commander';
3
+ import { ProjectManager } from '../core/project-manager.js';
4
+ import { ClaudeRunner } from '../core/claude-runner.js';
5
+ import { shutdownHandler } from '../core/shutdown-handler.js';
6
+ import { stashChanges, hasUncommittedChanges } from '../core/git.js';
7
+ import { getExecutionPrompt } from '../prompts/execution.js';
8
+ import { parseOutput, isRetryableFailure } from '../parsers/output-parser.js';
9
+ import { validatePlansExist, resolveModelOption } from '../utils/validation.js';
10
+ import { getRafDir, extractProjectNumber, extractProjectName, extractTaskNameFromPlanFile, resolveProjectIdentifierWithDetails, getOutcomeFilePath } from '../utils/paths.js';
11
+ import { pickPendingProject, getPendingProjects } from '../ui/project-picker.js';
12
+ import { logger } from '../utils/logger.js';
13
+ import { getConfig } from '../utils/config.js';
14
+ import { createTaskTimer, formatElapsedTime } from '../utils/timer.js';
15
+ import { createStatusLine } from '../utils/status-line.js';
16
+ import { SYMBOLS, formatProjectHeader, formatSummary, formatTaskProgress, } from '../utils/terminal-symbols.js';
17
+ import { deriveProjectState, getNextExecutableTask, getDerivedStats, isProjectComplete, hasProjectFailed, parseOutcomeStatus, } from '../core/state-derivation.js';
18
+ import { analyzeFailure } from '../core/failure-analyzer.js';
19
+ /**
20
+ * Format failure history for console output.
21
+ * Shows attempts that failed before eventual success or final failure.
22
+ * Returns empty string if no failures occurred.
23
+ */
24
+ export function formatRetryHistoryForConsole(taskId, taskName, failureHistory, finalAttempt, success) {
25
+ if (failureHistory.length === 0) {
26
+ return '';
27
+ }
28
+ const lines = [];
29
+ const displayName = taskName !== taskId ? `${taskId} (${taskName})` : taskId;
30
+ lines.push(` Task ${displayName}:`);
31
+ for (const { attempt, reason } of failureHistory) {
32
+ lines.push(` Attempt ${attempt}: Failed - ${reason}`);
33
+ }
34
+ if (success) {
35
+ lines.push(` Attempt ${finalAttempt}: Succeeded`);
36
+ }
37
+ return lines.join('\n');
38
+ }
39
+ export function createDoCommand() {
40
+ const command = new Command('do')
41
+ .description('Execute planned tasks for one or more projects')
42
+ .alias('act')
43
+ .argument('[projects...]', 'Project identifier(s): number (3), name (my-project), or folder (001-my-project)')
44
+ .option('-t, --timeout <minutes>', 'Timeout per task in minutes', '60')
45
+ .option('-v, --verbose', 'Show full Claude output')
46
+ .option('-d, --debug', 'Save all logs and show debug output')
47
+ .option('-f, --force', 'Re-run all tasks regardless of status')
48
+ .option('-m, --model <name>', 'Claude model to use (sonnet, haiku, opus)')
49
+ .option('--sonnet', 'Use Sonnet model (shorthand for --model sonnet)')
50
+ .action(async (projects, options) => {
51
+ await runDoCommand(projects, options);
52
+ });
53
+ return command;
54
+ }
55
+ async function runDoCommand(projectIdentifiersArg, options) {
56
+ const rafDir = getRafDir();
57
+ let projectIdentifiers = projectIdentifiersArg;
58
+ // Validate and resolve model option
59
+ let model;
60
+ try {
61
+ model = resolveModelOption(options.model, options.sonnet);
62
+ }
63
+ catch (error) {
64
+ logger.error(error.message);
65
+ process.exit(1);
66
+ }
67
+ // Handle empty project list - show interactive picker
68
+ if (projectIdentifiers.length === 0) {
69
+ // Check if there are any pending projects
70
+ const pendingProjects = getPendingProjects(rafDir);
71
+ if (pendingProjects.length === 0) {
72
+ logger.info('No pending projects found.');
73
+ logger.info("Run 'raf plan' to create a new project.");
74
+ process.exit(0);
75
+ }
76
+ try {
77
+ const selectedProject = await pickPendingProject(rafDir);
78
+ if (!selectedProject) {
79
+ // This shouldn't happen since we already checked pendingProjects.length
80
+ logger.info('No pending projects found.');
81
+ process.exit(0);
82
+ }
83
+ // Use the selected project
84
+ projectIdentifiers = [selectedProject];
85
+ }
86
+ catch (error) {
87
+ // Handle Ctrl+C (user cancellation)
88
+ if (error instanceof Error && error.message.includes('User force closed')) {
89
+ process.exit(0);
90
+ }
91
+ throw error;
92
+ }
93
+ }
94
+ // Resolve all project identifiers and remove duplicates
95
+ const resolvedProjects = [];
96
+ const seenPaths = new Set();
97
+ const errors = [];
98
+ for (const identifier of projectIdentifiers) {
99
+ const result = resolveProjectIdentifierWithDetails(rafDir, identifier);
100
+ if (!result.path) {
101
+ if (result.error === 'ambiguous' && result.matches) {
102
+ const matchList = result.matches
103
+ .map((m) => ` - ${m.folder}`)
104
+ .join('\n');
105
+ errors.push({
106
+ identifier,
107
+ error: `Ambiguous project name. Multiple projects match:\n${matchList}\nPlease specify the project ID or full folder name.`,
108
+ });
109
+ }
110
+ else {
111
+ errors.push({ identifier, error: 'Project not found' });
112
+ }
113
+ continue;
114
+ }
115
+ const projectPath = result.path;
116
+ // Skip duplicates
117
+ if (seenPaths.has(projectPath)) {
118
+ logger.info(`Skipping duplicate: ${identifier}`);
119
+ continue;
120
+ }
121
+ seenPaths.add(projectPath);
122
+ const projectName = extractProjectName(projectPath) ?? identifier;
123
+ resolvedProjects.push({ identifier, path: projectPath, name: projectName });
124
+ }
125
+ // Report resolution errors
126
+ for (const { identifier, error } of errors) {
127
+ logger.error(`${identifier}: ${error}`);
128
+ }
129
+ if (resolvedProjects.length === 0) {
130
+ logger.error('No valid projects to execute.');
131
+ logger.info("Run 'raf status' to see available projects.");
132
+ process.exit(1);
133
+ }
134
+ // Get configuration
135
+ const config = getConfig();
136
+ const timeout = Number(options.timeout) || config.timeout;
137
+ const verbose = options.verbose ?? false;
138
+ const debug = options.debug ?? false;
139
+ const force = options.force ?? false;
140
+ const maxRetries = config.maxRetries;
141
+ const autoCommit = config.autoCommit;
142
+ // Configure logger
143
+ logger.configure({ verbose, debug });
144
+ // Log Claude model name once (verbose mode only for multi-project)
145
+ if (verbose && model && resolvedProjects.length > 1) {
146
+ logger.info(`Using model: ${model}`);
147
+ logger.newline();
148
+ }
149
+ // Execute projects
150
+ const results = [];
151
+ const isMultiProject = resolvedProjects.length > 1;
152
+ for (const [i, project] of resolvedProjects.entries()) {
153
+ if (isMultiProject && verbose) {
154
+ logger.info(`=== Project ${i + 1}/${resolvedProjects.length}: ${project.name} ===`);
155
+ logger.newline();
156
+ }
157
+ try {
158
+ const result = await executeSingleProject(project.path, project.name, {
159
+ timeout,
160
+ verbose,
161
+ debug,
162
+ force,
163
+ maxRetries,
164
+ autoCommit,
165
+ showModel: !isMultiProject, // Only show model for single project
166
+ model,
167
+ });
168
+ results.push(result);
169
+ }
170
+ catch (error) {
171
+ const errorMessage = error instanceof Error ? error.message : String(error);
172
+ results.push({
173
+ projectName: project.name,
174
+ projectPath: project.path,
175
+ success: false,
176
+ tasksCompleted: 0,
177
+ totalTasks: 0,
178
+ error: errorMessage,
179
+ });
180
+ logger.error(`Project ${project.name} failed: ${errorMessage}`);
181
+ }
182
+ if (isMultiProject && i < resolvedProjects.length - 1) {
183
+ logger.newline();
184
+ }
185
+ }
186
+ // Show multi-project summary
187
+ if (isMultiProject) {
188
+ printMultiProjectSummary(results, verbose);
189
+ }
190
+ // Exit with appropriate code
191
+ const anyFailed = results.some((r) => !r.success);
192
+ if (anyFailed) {
193
+ process.exit(1);
194
+ }
195
+ }
196
+ async function executeSingleProject(projectPath, projectName, options) {
197
+ const { timeout, verbose, debug, force, maxRetries, autoCommit, showModel, model } = options;
198
+ if (!validatePlansExist(projectPath)) {
199
+ return {
200
+ projectName,
201
+ projectPath,
202
+ success: false,
203
+ tasksCompleted: 0,
204
+ totalTasks: 0,
205
+ error: 'No plan files found. Run planning first.',
206
+ };
207
+ }
208
+ // Derive state from folder structure
209
+ let state = deriveProjectState(projectPath);
210
+ // Check if project is already complete
211
+ if (isProjectComplete(state) && !force) {
212
+ if (verbose) {
213
+ logger.info('All tasks completed. Use --force to re-run.');
214
+ }
215
+ else {
216
+ const stats = getDerivedStats(state);
217
+ logger.info(formatSummary(stats.completed, stats.failed, stats.pending, undefined, stats.blocked));
218
+ }
219
+ const stats = getDerivedStats(state);
220
+ return {
221
+ projectName,
222
+ projectPath,
223
+ success: true,
224
+ tasksCompleted: stats.completed,
225
+ totalTasks: stats.total,
226
+ };
227
+ }
228
+ // Set up shutdown handler
229
+ const claudeRunner = new ClaudeRunner({ model });
230
+ const projectManager = new ProjectManager();
231
+ shutdownHandler.init();
232
+ shutdownHandler.registerClaudeRunner(claudeRunner);
233
+ // Start project timer
234
+ const projectStartTime = Date.now();
235
+ if (verbose) {
236
+ logger.info(`Executing project: ${projectName}`);
237
+ logger.info(`Tasks: ${state.tasks.length}, Task timeout: ${timeout} minutes`);
238
+ // Log Claude model name
239
+ if (showModel && model) {
240
+ logger.info(`Using model: ${model}`);
241
+ }
242
+ logger.newline();
243
+ }
244
+ else {
245
+ // Minimal mode: show project header
246
+ logger.info(formatProjectHeader(projectName, state.tasks.length));
247
+ }
248
+ // Execute tasks
249
+ const totalTasks = state.tasks.length;
250
+ // Track tasks completed in this session (for force mode)
251
+ const completedInSession = new Set();
252
+ // Track retry history for console output at the end
253
+ const projectRetryHistory = [];
254
+ // Helper function to get the next task to process (including blocked tasks for outcome generation)
255
+ function getNextTaskToProcess(currentState) {
256
+ if (force) {
257
+ // Find first task that hasn't been executed in this session
258
+ for (const t of currentState.tasks) {
259
+ if (!completedInSession.has(t.id)) {
260
+ return t;
261
+ }
262
+ }
263
+ return null;
264
+ }
265
+ // Normal mode: first check for blocked tasks that need outcome files generated
266
+ for (const t of currentState.tasks) {
267
+ if (t.status === 'blocked') {
268
+ const outcomeFilePath = getOutcomeFilePath(projectPath, t.id, extractTaskNameFromPlanFile(t.planFile) ?? t.id);
269
+ // Only return blocked task if it doesn't have an outcome file yet
270
+ if (!fs.existsSync(outcomeFilePath)) {
271
+ return t;
272
+ }
273
+ }
274
+ }
275
+ // Then get next executable task (pending or failed)
276
+ return getNextExecutableTask(currentState);
277
+ }
278
+ /**
279
+ * Generate a blocked outcome file for a task.
280
+ * @param task - The blocked task
281
+ * @param taskState - Current state to find which dependencies caused the block
282
+ */
283
+ function generateBlockedOutcome(task, taskState) {
284
+ // Find which dependencies are failed or blocked
285
+ const failedDeps = [];
286
+ const blockedDeps = [];
287
+ for (const depId of task.dependencies) {
288
+ const depTask = taskState.tasks.find((t) => t.id === depId);
289
+ if (depTask) {
290
+ if (depTask.status === 'failed') {
291
+ failedDeps.push(depId);
292
+ }
293
+ else if (depTask.status === 'blocked') {
294
+ blockedDeps.push(depId);
295
+ }
296
+ }
297
+ }
298
+ const lines = [
299
+ `# Outcome: Task ${task.id} Blocked`,
300
+ '',
301
+ '## Summary',
302
+ '',
303
+ 'This task was automatically blocked because one or more of its dependencies failed or are blocked.',
304
+ '',
305
+ '## Blocking Dependencies',
306
+ '',
307
+ ];
308
+ if (failedDeps.length > 0) {
309
+ lines.push(`**Failed dependencies**: ${failedDeps.join(', ')}`);
310
+ }
311
+ if (blockedDeps.length > 0) {
312
+ lines.push(`**Blocked dependencies**: ${blockedDeps.join(', ')}`);
313
+ }
314
+ lines.push('');
315
+ lines.push(`**Task dependencies**: ${task.dependencies.join(', ')}`);
316
+ lines.push('');
317
+ lines.push('## Resolution');
318
+ lines.push('');
319
+ lines.push('To unblock this task:');
320
+ lines.push('1. Fix the failed dependency task(s)');
321
+ lines.push('2. Re-run the project with `raf do`');
322
+ lines.push('');
323
+ lines.push('<promise>BLOCKED</promise>');
324
+ return lines.join('\n');
325
+ }
326
+ let task = getNextTaskToProcess(state);
327
+ while (task) {
328
+ const taskIndex = state.tasks.findIndex((t) => t.id === task.id);
329
+ const taskNumber = taskIndex + 1;
330
+ const taskName = extractTaskNameFromPlanFile(task.planFile);
331
+ const displayName = taskName ?? task.id;
332
+ // Handle blocked tasks separately - skip Claude execution
333
+ if (task.status === 'blocked') {
334
+ // Find which dependency caused the block for the message
335
+ const failedOrBlockedDeps = task.dependencies.filter((depId) => {
336
+ const depTask = state.tasks.find((t) => t.id === depId);
337
+ return depTask && (depTask.status === 'failed' || depTask.status === 'blocked');
338
+ });
339
+ const blockingDep = failedOrBlockedDeps[0] ?? task.dependencies[0];
340
+ if (verbose) {
341
+ const taskContext = `[Task ${taskNumber}/${totalTasks}: ${displayName}]`;
342
+ logger.setContext(taskContext);
343
+ logger.warn(`Task ${task.id} blocked by failed dependency: ${blockingDep}`);
344
+ }
345
+ else {
346
+ // Minimal mode: show blocked task line with distinct symbol
347
+ logger.info(formatTaskProgress(taskNumber, totalTasks, 'blocked', displayName));
348
+ }
349
+ // Generate blocked outcome file
350
+ const blockedOutcome = generateBlockedOutcome(task, state);
351
+ projectManager.saveOutcome(projectPath, task.id, blockedOutcome);
352
+ completedInSession.add(task.id);
353
+ logger.clearContext();
354
+ // Re-derive state to cascade blocking to dependent tasks
355
+ state = deriveProjectState(projectPath);
356
+ task = getNextTaskToProcess(state);
357
+ continue;
358
+ }
359
+ if (verbose) {
360
+ const taskContext = `[Task ${taskNumber}/${totalTasks}: ${displayName}]`;
361
+ logger.setContext(taskContext);
362
+ // Log task execution status
363
+ if (task.status === 'failed') {
364
+ logger.info(`Retrying task ${task.id} (previously failed)...`);
365
+ }
366
+ else if (task.status === 'completed' && force) {
367
+ logger.info(`Re-running task ${task.id} (force mode)...`);
368
+ }
369
+ else {
370
+ logger.info(`Executing task ${task.id}...`);
371
+ }
372
+ }
373
+ // Get previous outcomes for context
374
+ const previousOutcomes = projectManager.readOutcomes(projectPath);
375
+ // Get dependency outcomes - filter to only include outcomes for tasks this task depends on
376
+ const dependencyIds = task.dependencies;
377
+ const dependencyOutcomes = dependencyIds.length > 0
378
+ ? previousOutcomes.filter((o) => dependencyIds.includes(o.taskId))
379
+ : [];
380
+ // Extract project number for commit message
381
+ const projectNumber = extractProjectNumber(projectPath) ?? '000';
382
+ // Compute outcome file path for this task
383
+ const outcomeFilePath = getOutcomeFilePath(projectPath, task.id, displayName);
384
+ // Execute with retries
385
+ let success = false;
386
+ let attempts = 0;
387
+ let lastOutput = '';
388
+ let failureReason = '';
389
+ // Track failure history for each attempt (attempt number -> reason)
390
+ const failureHistory = [];
391
+ // Set up timer for elapsed time tracking
392
+ const statusLine = createStatusLine();
393
+ const timer = createTaskTimer(verbose ? undefined : (elapsed) => {
394
+ // Show running status with task name and timer (updates in place)
395
+ statusLine.update(formatTaskProgress(taskNumber, totalTasks, 'running', displayName, elapsed));
396
+ });
397
+ timer.start();
398
+ while (!success && attempts < maxRetries) {
399
+ attempts++;
400
+ if (verbose && attempts > 1) {
401
+ logger.info(` Retry ${attempts}/${maxRetries}...`);
402
+ }
403
+ // Build execution prompt (inside loop to include retry context on retries)
404
+ // Check if previous outcome file exists for retry context
405
+ const previousOutcomeFileForRetry = attempts > 1 && fs.existsSync(outcomeFilePath)
406
+ ? outcomeFilePath
407
+ : undefined;
408
+ const prompt = getExecutionPrompt({
409
+ projectPath,
410
+ planPath: projectManager.getPlanPath(projectPath, task.planFile),
411
+ taskId: task.id,
412
+ taskNumber,
413
+ totalTasks,
414
+ previousOutcomes,
415
+ autoCommit,
416
+ projectNumber,
417
+ outcomeFilePath,
418
+ attemptNumber: attempts,
419
+ previousOutcomeFile: previousOutcomeFileForRetry,
420
+ dependencyIds,
421
+ dependencyOutcomes,
422
+ });
423
+ // Run Claude
424
+ const result = verbose
425
+ ? await claudeRunner.runVerbose(prompt, { timeout })
426
+ : await claudeRunner.run(prompt, { timeout });
427
+ lastOutput = result.output;
428
+ // Parse result
429
+ const parsed = parseOutput(result.output);
430
+ if (result.timedOut) {
431
+ failureReason = 'Task timed out';
432
+ failureHistory.push({ attempt: attempts, reason: failureReason });
433
+ if (!isRetryableFailure(parsed)) {
434
+ break;
435
+ }
436
+ continue;
437
+ }
438
+ if (result.contextOverflow || parsed.contextOverflow) {
439
+ failureReason = 'Context overflow - task too large';
440
+ failureHistory.push({ attempt: attempts, reason: failureReason });
441
+ break; // Not retryable
442
+ }
443
+ if (parsed.result === 'complete') {
444
+ success = true;
445
+ }
446
+ else if (parsed.result === 'failed') {
447
+ failureReason = parsed.failureReason ?? 'Unknown failure';
448
+ failureHistory.push({ attempt: attempts, reason: failureReason });
449
+ if (!isRetryableFailure(parsed)) {
450
+ break;
451
+ }
452
+ }
453
+ else {
454
+ // Unknown result - check outcome file as fallback
455
+ if (fs.existsSync(outcomeFilePath)) {
456
+ const outcomeContent = fs.readFileSync(outcomeFilePath, 'utf-8');
457
+ const outcomeStatus = parseOutcomeStatus(outcomeContent);
458
+ if (outcomeStatus === 'completed') {
459
+ success = true;
460
+ }
461
+ else if (outcomeStatus === 'failed') {
462
+ failureReason = 'Task failed (from outcome file)';
463
+ failureHistory.push({ attempt: attempts, reason: failureReason });
464
+ }
465
+ else {
466
+ failureReason = 'No completion marker found in output or outcome file';
467
+ failureHistory.push({ attempt: attempts, reason: failureReason });
468
+ }
469
+ }
470
+ else {
471
+ failureReason = 'No completion marker found';
472
+ failureHistory.push({ attempt: attempts, reason: failureReason });
473
+ }
474
+ }
475
+ }
476
+ // Stop timer and clear status line
477
+ const elapsedMs = timer.stop();
478
+ statusLine.clear();
479
+ const elapsedFormatted = formatElapsedTime(elapsedMs);
480
+ // Save log if debug mode or failure
481
+ if (debug || !success) {
482
+ projectManager.saveLog(projectPath, task.id, lastOutput);
483
+ }
484
+ // Track retry history if there were failures (for console output)
485
+ if (failureHistory.length > 0) {
486
+ projectRetryHistory.push({
487
+ taskId: task.id,
488
+ taskName: displayName,
489
+ failureHistory,
490
+ finalAttempt: attempts,
491
+ success,
492
+ });
493
+ }
494
+ if (success) {
495
+ // Check if Claude wrote an outcome file with valid marker
496
+ // If so, keep it as-is; otherwise create fallback
497
+ // NOTE: Successful outcomes do NOT get ## Details section appended
498
+ let outcomeContent;
499
+ const claudeWroteOutcome = fs.existsSync(outcomeFilePath);
500
+ if (claudeWroteOutcome) {
501
+ const existingContent = fs.readFileSync(outcomeFilePath, 'utf-8');
502
+ const status = parseOutcomeStatus(existingContent);
503
+ if (status === 'completed') {
504
+ // Claude wrote a valid outcome - keep it as-is (no metadata added)
505
+ outcomeContent = existingContent;
506
+ }
507
+ else {
508
+ // Outcome file exists but no valid COMPLETE marker - create fallback
509
+ outcomeContent = `## Status: SUCCESS
510
+
511
+ # Task ${task.id} - Completed
512
+
513
+ Task completed. No detailed report provided.
514
+
515
+ <promise>COMPLETE</promise>
516
+ `;
517
+ }
518
+ }
519
+ else {
520
+ // No outcome file - create fallback
521
+ outcomeContent = `## Status: SUCCESS
522
+
523
+ # Task ${task.id} - Completed
524
+
525
+ Task completed. No detailed report provided.
526
+
527
+ <promise>COMPLETE</promise>
528
+ `;
529
+ }
530
+ projectManager.saveOutcome(projectPath, task.id, outcomeContent);
531
+ if (verbose) {
532
+ logger.success(` Task ${task.id} completed (${elapsedFormatted})`);
533
+ }
534
+ else {
535
+ // Minimal mode: show completed task line
536
+ logger.info(formatTaskProgress(taskNumber, totalTasks, 'completed', displayName, elapsedMs));
537
+ }
538
+ completedInSession.add(task.id);
539
+ }
540
+ else {
541
+ // Stash any uncommitted changes on complete failure
542
+ let stashName;
543
+ if (hasUncommittedChanges()) {
544
+ const projectNum = extractProjectNumber(projectPath) ?? '000';
545
+ stashName = `raf-${projectNum}-task-${task.id}-failed`;
546
+ const stashed = stashChanges(stashName);
547
+ if (verbose && stashed) {
548
+ logger.info(` Changes stashed as: ${stashName}`);
549
+ }
550
+ }
551
+ if (verbose) {
552
+ logger.error(` Task ${task.id} failed: ${failureReason} (${elapsedFormatted})`);
553
+ logger.info(' Analyzing failure...');
554
+ }
555
+ else {
556
+ // Minimal mode: show failed task line
557
+ logger.info(formatTaskProgress(taskNumber, totalTasks, 'failed', displayName, elapsedMs));
558
+ }
559
+ // Analyze failure and generate structured report
560
+ const analysisReport = await analyzeFailure(lastOutput, failureReason, task.id);
561
+ // Save failure outcome with status marker, analysis, and details
562
+ // NOTE: Failed outcomes keep ## Details section for debugging
563
+ const outcomeContent = `## Status: FAILED
564
+
565
+ # Task ${task.id} - Failed
566
+
567
+ ${analysisReport}
568
+
569
+ ## Details
570
+ - Attempts: ${attempts}
571
+ - Elapsed time: ${elapsedFormatted}
572
+ - Failed at: ${new Date().toISOString()}
573
+ ${stashName ? `- Stash: ${stashName}` : ''}
574
+ `;
575
+ projectManager.saveOutcome(projectPath, task.id, outcomeContent);
576
+ }
577
+ if (verbose) {
578
+ logger.newline();
579
+ }
580
+ // Clear context before next task
581
+ logger.clearContext();
582
+ // Re-derive state to get updated task statuses
583
+ state = deriveProjectState(projectPath);
584
+ // Get next task to process
585
+ task = getNextTaskToProcess(state);
586
+ }
587
+ // Ensure context is cleared for summary
588
+ logger.clearContext();
589
+ // Get final stats
590
+ const stats = getDerivedStats(state);
591
+ const projectElapsedMs = Date.now() - projectStartTime;
592
+ if (isProjectComplete(state)) {
593
+ if (verbose) {
594
+ logger.success('All tasks completed!');
595
+ // Verbose summary
596
+ logger.newline();
597
+ logger.info('Summary:');
598
+ logger.info(` Completed: ${stats.completed}`);
599
+ logger.info(` Failed: ${stats.failed}`);
600
+ logger.info(` Blocked: ${stats.blocked}`);
601
+ logger.info(` Pending: ${stats.pending}`);
602
+ }
603
+ else {
604
+ // Minimal summary with elapsed time
605
+ logger.info(formatSummary(stats.completed, stats.failed, stats.pending, projectElapsedMs, stats.blocked));
606
+ }
607
+ }
608
+ else if (hasProjectFailed(state)) {
609
+ if (verbose) {
610
+ logger.warn('Some tasks failed.');
611
+ logger.newline();
612
+ logger.info('Summary:');
613
+ logger.info(` Completed: ${stats.completed}`);
614
+ logger.info(` Failed: ${stats.failed}`);
615
+ logger.info(` Blocked: ${stats.blocked}`);
616
+ logger.info(` Pending: ${stats.pending}`);
617
+ }
618
+ else {
619
+ // Minimal summary for failures
620
+ logger.info(formatSummary(stats.completed, stats.failed, stats.pending, projectElapsedMs, stats.blocked));
621
+ }
622
+ }
623
+ else {
624
+ // Project incomplete (pending tasks remain)
625
+ if (verbose) {
626
+ logger.newline();
627
+ logger.info('Summary:');
628
+ logger.info(` Completed: ${stats.completed}`);
629
+ logger.info(` Failed: ${stats.failed}`);
630
+ logger.info(` Blocked: ${stats.blocked}`);
631
+ logger.info(` Pending: ${stats.pending}`);
632
+ }
633
+ else {
634
+ logger.info(formatSummary(stats.completed, stats.failed, stats.pending, projectElapsedMs, stats.blocked));
635
+ }
636
+ }
637
+ // Show retry history for tasks that had failures (even if eventually successful)
638
+ if (projectRetryHistory.length > 0) {
639
+ logger.newline();
640
+ logger.info('Retry history:');
641
+ for (const history of projectRetryHistory) {
642
+ const retryOutput = formatRetryHistoryForConsole(history.taskId, history.taskName, history.failureHistory, history.finalAttempt, history.success);
643
+ if (retryOutput) {
644
+ logger.info(retryOutput);
645
+ }
646
+ }
647
+ }
648
+ return {
649
+ projectName,
650
+ projectPath,
651
+ success: stats.failed === 0 && stats.pending === 0,
652
+ tasksCompleted: stats.completed,
653
+ totalTasks: stats.total,
654
+ retryHistory: projectRetryHistory,
655
+ };
656
+ }
657
+ function printMultiProjectSummary(results, verbose) {
658
+ logger.newline();
659
+ if (verbose) {
660
+ logger.info('=== Multi-Project Summary ===');
661
+ logger.newline();
662
+ for (const result of results) {
663
+ const statusSymbol = result.success ? SYMBOLS.completed : SYMBOLS.failed;
664
+ const statusText = result.success
665
+ ? `Completed (${result.tasksCompleted}/${result.totalTasks} tasks)`
666
+ : result.error
667
+ ? `Error: ${result.error}`
668
+ : `Failed (${result.tasksCompleted}/${result.totalTasks} tasks)`;
669
+ logger.info(`${statusSymbol} ${result.projectName}: ${statusText}`);
670
+ }
671
+ const completed = results.filter((r) => r.success).length;
672
+ const failed = results.length - completed;
673
+ logger.newline();
674
+ logger.info(`Total: ${completed} completed, ${failed} failed`);
675
+ }
676
+ else {
677
+ // Minimal multi-project summary: just show each project result
678
+ for (const result of results) {
679
+ const symbol = result.success ? SYMBOLS.completed : SYMBOLS.failed;
680
+ logger.info(`${symbol} ${result.projectName}`);
681
+ }
682
+ }
683
+ }
684
+ //# sourceMappingURL=do.js.map