task-o-matic-core 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 (447) hide show
  1. package/README.md +646 -0
  2. package/dist/index.d.ts +27 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +46 -0
  5. package/dist/lib/ai-service/ai-operations.d.ts +45 -0
  6. package/dist/lib/ai-service/ai-operations.d.ts.map +1 -0
  7. package/dist/lib/ai-service/ai-operations.js +60 -0
  8. package/dist/lib/ai-service/base-operations.d.ts +43 -0
  9. package/dist/lib/ai-service/base-operations.d.ts.map +1 -0
  10. package/dist/lib/ai-service/base-operations.js +119 -0
  11. package/dist/lib/ai-service/documentation-operations.d.ts +18 -0
  12. package/dist/lib/ai-service/documentation-operations.d.ts.map +1 -0
  13. package/dist/lib/ai-service/documentation-operations.js +308 -0
  14. package/dist/lib/ai-service/filesystem-tools.d.ts +69 -0
  15. package/dist/lib/ai-service/filesystem-tools.d.ts.map +1 -0
  16. package/dist/lib/ai-service/filesystem-tools.js +70 -0
  17. package/dist/lib/ai-service/json-parser.d.ts +34 -0
  18. package/dist/lib/ai-service/json-parser.d.ts.map +1 -0
  19. package/dist/lib/ai-service/json-parser.js +177 -0
  20. package/dist/lib/ai-service/mcp-client.d.ts +9 -0
  21. package/dist/lib/ai-service/mcp-client.d.ts.map +1 -0
  22. package/dist/lib/ai-service/mcp-client.js +48 -0
  23. package/dist/lib/ai-service/model-provider.d.ts +12 -0
  24. package/dist/lib/ai-service/model-provider.d.ts.map +1 -0
  25. package/dist/lib/ai-service/model-provider.js +146 -0
  26. package/dist/lib/ai-service/prd-operations.d.ts +25 -0
  27. package/dist/lib/ai-service/prd-operations.d.ts.map +1 -0
  28. package/dist/lib/ai-service/prd-operations.js +592 -0
  29. package/dist/lib/ai-service/research-tools.d.ts +4 -0
  30. package/dist/lib/ai-service/research-tools.d.ts.map +1 -0
  31. package/dist/lib/ai-service/research-tools.js +8 -0
  32. package/dist/lib/ai-service/retry-handler.d.ts +8 -0
  33. package/dist/lib/ai-service/retry-handler.d.ts.map +1 -0
  34. package/dist/lib/ai-service/retry-handler.js +63 -0
  35. package/dist/lib/ai-service/task-operations.d.ts +13 -0
  36. package/dist/lib/ai-service/task-operations.d.ts.map +1 -0
  37. package/dist/lib/ai-service/task-operations.js +220 -0
  38. package/dist/lib/benchmark/registry.d.ts +11 -0
  39. package/dist/lib/benchmark/registry.d.ts.map +1 -0
  40. package/dist/lib/benchmark/registry.js +212 -0
  41. package/dist/lib/benchmark/runner.d.ts +6 -0
  42. package/dist/lib/benchmark/runner.d.ts.map +1 -0
  43. package/dist/lib/benchmark/runner.js +150 -0
  44. package/dist/lib/benchmark/storage.d.ts +13 -0
  45. package/dist/lib/benchmark/storage.d.ts.map +1 -0
  46. package/dist/lib/benchmark/storage.js +100 -0
  47. package/dist/lib/benchmark/types.d.ts +104 -0
  48. package/dist/lib/benchmark/types.d.ts.map +1 -0
  49. package/dist/lib/benchmark/types.js +2 -0
  50. package/dist/lib/better-t-stack-cli.d.ts +50 -0
  51. package/dist/lib/better-t-stack-cli.d.ts.map +1 -0
  52. package/dist/lib/better-t-stack-cli.js +428 -0
  53. package/dist/lib/bootstrap/cli-bootstrap.d.ts +14 -0
  54. package/dist/lib/bootstrap/cli-bootstrap.d.ts.map +1 -0
  55. package/dist/lib/bootstrap/cli-bootstrap.js +322 -0
  56. package/dist/lib/bootstrap/index.d.ts +3 -0
  57. package/dist/lib/bootstrap/index.d.ts.map +1 -0
  58. package/dist/lib/bootstrap/index.js +18 -0
  59. package/dist/lib/bootstrap/medusa-bootstrap.d.ts +14 -0
  60. package/dist/lib/bootstrap/medusa-bootstrap.d.ts.map +1 -0
  61. package/dist/lib/bootstrap/medusa-bootstrap.js +215 -0
  62. package/dist/lib/config-validation.d.ts +215 -0
  63. package/dist/lib/config-validation.d.ts.map +1 -0
  64. package/dist/lib/config-validation.js +254 -0
  65. package/dist/lib/config.d.ts +55 -0
  66. package/dist/lib/config.d.ts.map +1 -0
  67. package/dist/lib/config.js +351 -0
  68. package/dist/lib/context-builder.d.ts +66 -0
  69. package/dist/lib/context-builder.d.ts.map +1 -0
  70. package/dist/lib/context-builder.js +322 -0
  71. package/dist/lib/executors/claude-code-executor.d.ts +9 -0
  72. package/dist/lib/executors/claude-code-executor.d.ts.map +1 -0
  73. package/dist/lib/executors/claude-code-executor.js +69 -0
  74. package/dist/lib/executors/codex-executor.d.ts +9 -0
  75. package/dist/lib/executors/codex-executor.d.ts.map +1 -0
  76. package/dist/lib/executors/codex-executor.js +73 -0
  77. package/dist/lib/executors/executor-factory.d.ts +5 -0
  78. package/dist/lib/executors/executor-factory.d.ts.map +1 -0
  79. package/dist/lib/executors/executor-factory.js +27 -0
  80. package/dist/lib/executors/gemini-executor.d.ts +9 -0
  81. package/dist/lib/executors/gemini-executor.d.ts.map +1 -0
  82. package/dist/lib/executors/gemini-executor.js +67 -0
  83. package/dist/lib/executors/kilo-executor.d.ts +9 -0
  84. package/dist/lib/executors/kilo-executor.d.ts.map +1 -0
  85. package/dist/lib/executors/kilo-executor.js +69 -0
  86. package/dist/lib/executors/opencode-executor.d.ts +9 -0
  87. package/dist/lib/executors/opencode-executor.d.ts.map +1 -0
  88. package/dist/lib/executors/opencode-executor.js +67 -0
  89. package/dist/lib/git-utils.d.ts +88 -0
  90. package/dist/lib/git-utils.d.ts.map +1 -0
  91. package/dist/lib/git-utils.js +242 -0
  92. package/dist/lib/hooks.d.ts +73 -0
  93. package/dist/lib/hooks.d.ts.map +1 -0
  94. package/dist/lib/hooks.js +62 -0
  95. package/dist/lib/index.d.ts +100 -0
  96. package/dist/lib/index.d.ts.map +1 -0
  97. package/dist/lib/index.js +143 -0
  98. package/dist/lib/logger.d.ts +20 -0
  99. package/dist/lib/logger.d.ts.map +1 -0
  100. package/dist/lib/logger.js +32 -0
  101. package/dist/lib/notifications.d.ts +7 -0
  102. package/dist/lib/notifications.d.ts.map +1 -0
  103. package/dist/lib/notifications.js +81 -0
  104. package/dist/lib/prompt-builder.d.ts +70 -0
  105. package/dist/lib/prompt-builder.d.ts.map +1 -0
  106. package/dist/lib/prompt-builder.js +344 -0
  107. package/dist/lib/prompt-registry.d.ts +22 -0
  108. package/dist/lib/prompt-registry.d.ts.map +1 -0
  109. package/dist/lib/prompt-registry.js +409 -0
  110. package/dist/lib/provider-defaults.json +32 -0
  111. package/dist/lib/storage/file-system.d.ts +57 -0
  112. package/dist/lib/storage/file-system.d.ts.map +1 -0
  113. package/dist/lib/storage/file-system.js +638 -0
  114. package/dist/lib/storage/storage-callbacks.d.ts +17 -0
  115. package/dist/lib/storage/storage-callbacks.d.ts.map +1 -0
  116. package/dist/lib/storage/storage-callbacks.js +94 -0
  117. package/dist/lib/storage/types.d.ts +43 -0
  118. package/dist/lib/storage/types.d.ts.map +1 -0
  119. package/dist/lib/storage/types.js +2 -0
  120. package/dist/lib/task-execution-core.d.ts +7 -0
  121. package/dist/lib/task-execution-core.d.ts.map +1 -0
  122. package/dist/lib/task-execution-core.js +381 -0
  123. package/dist/lib/task-execution.d.ts +7 -0
  124. package/dist/lib/task-execution.d.ts.map +1 -0
  125. package/dist/lib/task-execution.js +40 -0
  126. package/dist/lib/task-loop-execution.d.ts +7 -0
  127. package/dist/lib/task-loop-execution.d.ts.map +1 -0
  128. package/dist/lib/task-loop-execution.js +156 -0
  129. package/dist/lib/task-planning.d.ts +29 -0
  130. package/dist/lib/task-planning.d.ts.map +1 -0
  131. package/dist/lib/task-planning.js +103 -0
  132. package/dist/lib/task-review.d.ts +27 -0
  133. package/dist/lib/task-review.d.ts.map +1 -0
  134. package/dist/lib/task-review.js +103 -0
  135. package/dist/lib/validation.d.ts +26 -0
  136. package/dist/lib/validation.d.ts.map +1 -0
  137. package/dist/lib/validation.js +98 -0
  138. package/dist/prompts/documentation-detection.d.ts +2 -0
  139. package/dist/prompts/documentation-detection.d.ts.map +1 -0
  140. package/dist/prompts/documentation-detection.js +24 -0
  141. package/dist/prompts/documentation-recap.d.ts +3 -0
  142. package/dist/prompts/documentation-recap.d.ts.map +1 -0
  143. package/dist/prompts/documentation-recap.js +13 -0
  144. package/dist/prompts/index.d.ts +15 -0
  145. package/dist/prompts/index.d.ts.map +1 -0
  146. package/dist/prompts/index.js +30 -0
  147. package/dist/prompts/prd-combination.d.ts +2 -0
  148. package/dist/prompts/prd-combination.d.ts.map +1 -0
  149. package/dist/prompts/prd-combination.js +35 -0
  150. package/dist/prompts/prd-generation.d.ts +2 -0
  151. package/dist/prompts/prd-generation.d.ts.map +1 -0
  152. package/dist/prompts/prd-generation.js +49 -0
  153. package/dist/prompts/prd-parsing.d.ts +3 -0
  154. package/dist/prompts/prd-parsing.d.ts.map +1 -0
  155. package/dist/prompts/prd-parsing.js +172 -0
  156. package/dist/prompts/prd-question-answer.d.ts +3 -0
  157. package/dist/prompts/prd-question-answer.d.ts.map +1 -0
  158. package/dist/prompts/prd-question-answer.js +27 -0
  159. package/dist/prompts/prd-question.d.ts +3 -0
  160. package/dist/prompts/prd-question.d.ts.map +1 -0
  161. package/dist/prompts/prd-question.js +40 -0
  162. package/dist/prompts/prd-rework.d.ts +3 -0
  163. package/dist/prompts/prd-rework.d.ts.map +1 -0
  164. package/dist/prompts/prd-rework.js +81 -0
  165. package/dist/prompts/prd-suggest-stack.d.ts +3 -0
  166. package/dist/prompts/prd-suggest-stack.d.ts.map +1 -0
  167. package/dist/prompts/prd-suggest-stack.js +99 -0
  168. package/dist/prompts/task-breakdown.d.ts +3 -0
  169. package/dist/prompts/task-breakdown.d.ts.map +1 -0
  170. package/dist/prompts/task-breakdown.js +151 -0
  171. package/dist/prompts/task-enhancement.d.ts +3 -0
  172. package/dist/prompts/task-enhancement.d.ts.map +1 -0
  173. package/dist/prompts/task-enhancement.js +140 -0
  174. package/dist/prompts/task-execution.d.ts +3 -0
  175. package/dist/prompts/task-execution.d.ts.map +1 -0
  176. package/dist/prompts/task-execution.js +24 -0
  177. package/dist/prompts/task-planning.d.ts +3 -0
  178. package/dist/prompts/task-planning.d.ts.map +1 -0
  179. package/dist/prompts/task-planning.js +66 -0
  180. package/dist/prompts/workflow-assistance.d.ts +32 -0
  181. package/dist/prompts/workflow-assistance.d.ts.map +1 -0
  182. package/dist/prompts/workflow-assistance.js +130 -0
  183. package/dist/prompts/workflow-prompts.d.ts +9 -0
  184. package/dist/prompts/workflow-prompts.d.ts.map +1 -0
  185. package/dist/prompts/workflow-prompts.js +93 -0
  186. package/dist/services/benchmark.d.ts +26 -0
  187. package/dist/services/benchmark.d.ts.map +1 -0
  188. package/dist/services/benchmark.js +343 -0
  189. package/dist/services/prd.d.ts +136 -0
  190. package/dist/services/prd.d.ts.map +1 -0
  191. package/dist/services/prd.js +550 -0
  192. package/dist/services/tasks.d.ts +388 -0
  193. package/dist/services/tasks.d.ts.map +1 -0
  194. package/dist/services/tasks.js +1150 -0
  195. package/dist/services/workflow-ai-assistant.d.ts +74 -0
  196. package/dist/services/workflow-ai-assistant.d.ts.map +1 -0
  197. package/dist/services/workflow-ai-assistant.js +175 -0
  198. package/dist/services/workflow-benchmark.d.ts +34 -0
  199. package/dist/services/workflow-benchmark.d.ts.map +1 -0
  200. package/dist/services/workflow-benchmark.js +318 -0
  201. package/dist/services/workflow.d.ts +107 -0
  202. package/dist/services/workflow.d.ts.map +1 -0
  203. package/dist/services/workflow.js +580 -0
  204. package/dist/test/hooks.test.d.ts +2 -0
  205. package/dist/test/hooks.test.d.ts.map +1 -0
  206. package/dist/test/hooks.test.js +67 -0
  207. package/dist/test/integration/callbacks.test.d.ts +2 -0
  208. package/dist/test/integration/callbacks.test.d.ts.map +1 -0
  209. package/dist/test/integration/callbacks.test.js +64 -0
  210. package/dist/test/lib/ai-service/task-operations.test.d.ts +2 -0
  211. package/dist/test/lib/ai-service/task-operations.test.d.ts.map +1 -0
  212. package/dist/test/lib/ai-service/task-operations.test.js +362 -0
  213. package/dist/test/lib/config.test.d.ts +2 -0
  214. package/dist/test/lib/config.test.d.ts.map +1 -0
  215. package/dist/test/lib/config.test.js +128 -0
  216. package/dist/test/lib/git-utils.test.d.ts +2 -0
  217. package/dist/test/lib/git-utils.test.d.ts.map +1 -0
  218. package/dist/test/lib/git-utils.test.js +168 -0
  219. package/dist/test/mocks/mock-ai-operations.d.ts +15 -0
  220. package/dist/test/mocks/mock-ai-operations.d.ts.map +1 -0
  221. package/dist/test/mocks/mock-ai-operations.js +107 -0
  222. package/dist/test/mocks/mock-context-builder.d.ts +10 -0
  223. package/dist/test/mocks/mock-context-builder.d.ts.map +1 -0
  224. package/dist/test/mocks/mock-context-builder.js +81 -0
  225. package/dist/test/mocks/mock-model-provider.d.ts +7 -0
  226. package/dist/test/mocks/mock-model-provider.d.ts.map +1 -0
  227. package/dist/test/mocks/mock-model-provider.js +21 -0
  228. package/dist/test/mocks/mock-service-factory.d.ts +11 -0
  229. package/dist/test/mocks/mock-service-factory.d.ts.map +1 -0
  230. package/dist/test/mocks/mock-service-factory.js +61 -0
  231. package/dist/test/mocks/mock-storage.d.ts +50 -0
  232. package/dist/test/mocks/mock-storage.d.ts.map +1 -0
  233. package/dist/test/mocks/mock-storage.js +145 -0
  234. package/dist/test/model-parsing.test.d.ts +2 -0
  235. package/dist/test/model-parsing.test.d.ts.map +1 -0
  236. package/dist/test/model-parsing.test.js +73 -0
  237. package/dist/test/services/task-service.test.d.ts +2 -0
  238. package/dist/test/services/task-service.test.d.ts.map +1 -0
  239. package/dist/test/services/task-service.test.js +459 -0
  240. package/dist/test/storage.test.d.ts +2 -0
  241. package/dist/test/storage.test.d.ts.map +1 -0
  242. package/dist/test/storage.test.js +207 -0
  243. package/dist/test/task-loop-git.test.d.ts +2 -0
  244. package/dist/test/task-loop-git.test.d.ts.map +1 -0
  245. package/dist/test/task-loop-git.test.js +95 -0
  246. package/dist/test/test-mock-setup.d.ts +26 -0
  247. package/dist/test/test-mock-setup.d.ts.map +1 -0
  248. package/dist/test/test-mock-setup.js +41 -0
  249. package/dist/test/test-setup.d.ts +9 -0
  250. package/dist/test/test-setup.d.ts.map +1 -0
  251. package/dist/test/test-setup.js +44 -0
  252. package/dist/test/test-utils.d.ts +22 -0
  253. package/dist/test/test-utils.d.ts.map +1 -0
  254. package/dist/test/test-utils.js +37 -0
  255. package/dist/test/utils/ai-operation-utility.test.d.ts +2 -0
  256. package/dist/test/utils/ai-operation-utility.test.d.ts.map +1 -0
  257. package/dist/test/utils/ai-operation-utility.test.js +290 -0
  258. package/dist/test/utils/error-handling.test.d.ts +2 -0
  259. package/dist/test/utils/error-handling.test.d.ts.map +1 -0
  260. package/dist/test/utils/error-handling.test.js +231 -0
  261. package/dist/test/utils/file-utils.test.d.ts +2 -0
  262. package/dist/test/utils/file-utils.test.d.ts.map +1 -0
  263. package/dist/test/utils/file-utils.test.js +76 -0
  264. package/dist/test/utils/id-generator.test.d.ts +2 -0
  265. package/dist/test/utils/id-generator.test.d.ts.map +1 -0
  266. package/dist/test/utils/id-generator.test.js +41 -0
  267. package/dist/test/utils/model-parser.test.d.ts +2 -0
  268. package/dist/test/utils/model-parser.test.d.ts.map +1 -0
  269. package/dist/test/utils/model-parser.test.js +65 -0
  270. package/dist/test/validation.test.d.ts +2 -0
  271. package/dist/test/validation.test.d.ts.map +1 -0
  272. package/dist/test/validation.test.js +22 -0
  273. package/dist/types/callbacks.d.ts +30 -0
  274. package/dist/types/callbacks.d.ts.map +1 -0
  275. package/dist/types/callbacks.js +2 -0
  276. package/dist/types/index.d.ts +435 -0
  277. package/dist/types/index.d.ts.map +1 -0
  278. package/dist/types/index.js +30 -0
  279. package/dist/types/mcp.d.ts +3 -0
  280. package/dist/types/mcp.d.ts.map +1 -0
  281. package/dist/types/mcp.js +3 -0
  282. package/dist/types/options.d.ts +112 -0
  283. package/dist/types/options.d.ts.map +1 -0
  284. package/dist/types/options.js +2 -0
  285. package/dist/types/results.d.ts +200 -0
  286. package/dist/types/results.d.ts.map +1 -0
  287. package/dist/types/results.js +2 -0
  288. package/dist/types/workflow-options.d.ts +82 -0
  289. package/dist/types/workflow-options.d.ts.map +1 -0
  290. package/dist/types/workflow-options.js +2 -0
  291. package/dist/types/workflow-results.d.ts +82 -0
  292. package/dist/types/workflow-results.d.ts.map +1 -0
  293. package/dist/types/workflow-results.js +2 -0
  294. package/dist/utils/ai-config-builder.d.ts +14 -0
  295. package/dist/utils/ai-config-builder.d.ts.map +1 -0
  296. package/dist/utils/ai-config-builder.js +22 -0
  297. package/dist/utils/ai-operation-utility.d.ts +142 -0
  298. package/dist/utils/ai-operation-utility.d.ts.map +1 -0
  299. package/dist/utils/ai-operation-utility.js +303 -0
  300. package/dist/utils/ai-service-factory.d.ts +34 -0
  301. package/dist/utils/ai-service-factory.d.ts.map +1 -0
  302. package/dist/utils/ai-service-factory.js +99 -0
  303. package/dist/utils/error-utils.d.ts +70 -0
  304. package/dist/utils/error-utils.d.ts.map +1 -0
  305. package/dist/utils/error-utils.js +104 -0
  306. package/dist/utils/file-utils.d.ts +107 -0
  307. package/dist/utils/file-utils.d.ts.map +1 -0
  308. package/dist/utils/file-utils.js +171 -0
  309. package/dist/utils/id-generator.d.ts +92 -0
  310. package/dist/utils/id-generator.d.ts.map +1 -0
  311. package/dist/utils/id-generator.js +146 -0
  312. package/dist/utils/metadata-utils.d.ts +40 -0
  313. package/dist/utils/metadata-utils.d.ts.map +1 -0
  314. package/dist/utils/metadata-utils.js +43 -0
  315. package/dist/utils/model-executor-parser.d.ts +38 -0
  316. package/dist/utils/model-executor-parser.d.ts.map +1 -0
  317. package/dist/utils/model-executor-parser.js +69 -0
  318. package/dist/utils/model-parser.d.ts +6 -0
  319. package/dist/utils/model-parser.d.ts.map +1 -0
  320. package/dist/utils/model-parser.js +49 -0
  321. package/dist/utils/stack-formatter.d.ts +12 -0
  322. package/dist/utils/stack-formatter.d.ts.map +1 -0
  323. package/dist/utils/stack-formatter.js +36 -0
  324. package/dist/utils/storage-utils.d.ts +49 -0
  325. package/dist/utils/storage-utils.d.ts.map +1 -0
  326. package/dist/utils/storage-utils.js +80 -0
  327. package/dist/utils/streaming-utils.d.ts +38 -0
  328. package/dist/utils/streaming-utils.d.ts.map +1 -0
  329. package/dist/utils/streaming-utils.js +64 -0
  330. package/dist/utils/task-o-matic-error.d.ts +206 -0
  331. package/dist/utils/task-o-matic-error.d.ts.map +1 -0
  332. package/dist/utils/task-o-matic-error.js +304 -0
  333. package/package.json +40 -0
  334. package/src/index.ts +36 -0
  335. package/src/lib/ai-service/ai-operations.ts +310 -0
  336. package/src/lib/ai-service/base-operations.ts +139 -0
  337. package/src/lib/ai-service/documentation-operations.ts +438 -0
  338. package/src/lib/ai-service/filesystem-tools.ts +73 -0
  339. package/src/lib/ai-service/gemini-proxy.ts.bak +52 -0
  340. package/src/lib/ai-service/json-parser.ts +203 -0
  341. package/src/lib/ai-service/mcp-client.ts +54 -0
  342. package/src/lib/ai-service/model-provider.ts +192 -0
  343. package/src/lib/ai-service/prd-operations.ts +854 -0
  344. package/src/lib/ai-service/research-tools.ts +207 -0
  345. package/src/lib/ai-service/retry-handler.ts +89 -0
  346. package/src/lib/ai-service/task-operations.ts +342 -0
  347. package/src/lib/benchmark/registry.ts +307 -0
  348. package/src/lib/benchmark/runner.ts +190 -0
  349. package/src/lib/benchmark/storage.ts +140 -0
  350. package/src/lib/benchmark/types.ts +121 -0
  351. package/src/lib/better-t-stack-cli.ts +524 -0
  352. package/src/lib/bootstrap/cli-bootstrap.ts +397 -0
  353. package/src/lib/bootstrap/index.ts +2 -0
  354. package/src/lib/bootstrap/medusa-bootstrap.ts +261 -0
  355. package/src/lib/config-validation.ts +278 -0
  356. package/src/lib/config.ts +435 -0
  357. package/src/lib/context-builder.ts +383 -0
  358. package/src/lib/executors/claude-code-executor.ts +83 -0
  359. package/src/lib/executors/codex-executor.ts +85 -0
  360. package/src/lib/executors/executor-factory.ts +28 -0
  361. package/src/lib/executors/gemini-executor.ts +80 -0
  362. package/src/lib/executors/kilo-executor.ts +83 -0
  363. package/src/lib/executors/opencode-executor.ts +81 -0
  364. package/src/lib/git-utils.ts +334 -0
  365. package/src/lib/hooks.ts +121 -0
  366. package/src/lib/index.ts +166 -0
  367. package/src/lib/logger.ts +43 -0
  368. package/src/lib/notifications.ts +103 -0
  369. package/src/lib/prompt-builder.ts +471 -0
  370. package/src/lib/prompt-registry.ts +491 -0
  371. package/src/lib/provider-defaults.json +32 -0
  372. package/src/lib/storage/file-system.ts +864 -0
  373. package/src/lib/storage/storage-callbacks.ts +120 -0
  374. package/src/lib/storage/types.ts +58 -0
  375. package/src/lib/task-execution-core.ts +591 -0
  376. package/src/lib/task-execution.ts +59 -0
  377. package/src/lib/task-loop-execution.ts +214 -0
  378. package/src/lib/task-planning.ts +157 -0
  379. package/src/lib/task-review.ts +138 -0
  380. package/src/lib/validation.ts +140 -0
  381. package/src/prompts/documentation-detection.ts +21 -0
  382. package/src/prompts/documentation-recap.ts +11 -0
  383. package/src/prompts/index.ts +14 -0
  384. package/src/prompts/prd-combination.ts +32 -0
  385. package/src/prompts/prd-generation.ts +46 -0
  386. package/src/prompts/prd-parsing.ts +170 -0
  387. package/src/prompts/prd-question-answer.ts +25 -0
  388. package/src/prompts/prd-question.ts +38 -0
  389. package/src/prompts/prd-rework.ts +79 -0
  390. package/src/prompts/prd-suggest-stack.ts +97 -0
  391. package/src/prompts/task-breakdown.ts +149 -0
  392. package/src/prompts/task-enhancement.ts +138 -0
  393. package/src/prompts/task-execution.ts +22 -0
  394. package/src/prompts/task-planning.ts +64 -0
  395. package/src/prompts/workflow-assistance.ts +151 -0
  396. package/src/prompts/workflow-prompts.ts +97 -0
  397. package/src/services/benchmark.ts +433 -0
  398. package/src/services/prd.ts +845 -0
  399. package/src/services/tasks.ts +1515 -0
  400. package/src/services/workflow-ai-assistant.ts +298 -0
  401. package/src/services/workflow-benchmark.ts +339 -0
  402. package/src/services/workflow.ts +779 -0
  403. package/src/test/hooks.test.ts +77 -0
  404. package/src/test/integration/callbacks.test.ts +39 -0
  405. package/src/test/lib/ai-service/task-operations.test.ts +430 -0
  406. package/src/test/lib/config.test.ts +150 -0
  407. package/src/test/lib/git-utils.test.ts +198 -0
  408. package/src/test/mocks/mock-ai-operations.ts +205 -0
  409. package/src/test/mocks/mock-context-builder.ts +84 -0
  410. package/src/test/mocks/mock-model-provider.ts +21 -0
  411. package/src/test/mocks/mock-service-factory.ts +64 -0
  412. package/src/test/mocks/mock-storage.ts +204 -0
  413. package/src/test/model-parsing.test.ts +78 -0
  414. package/src/test/services/task-service.test.ts +551 -0
  415. package/src/test/storage.test.ts +206 -0
  416. package/src/test/task-loop-git.test.ts +142 -0
  417. package/src/test/test-mock-setup.ts +46 -0
  418. package/src/test/test-setup.ts +48 -0
  419. package/src/test/test-utils.ts +45 -0
  420. package/src/test/utils/ai-operation-utility.test.ts +306 -0
  421. package/src/test/utils/error-handling.test.ts +241 -0
  422. package/src/test/utils/file-utils.test.ts +80 -0
  423. package/src/test/utils/id-generator.test.ts +44 -0
  424. package/src/test/utils/model-parser.test.ts +67 -0
  425. package/src/test/validation.test.ts +19 -0
  426. package/src/types/callbacks.ts +14 -0
  427. package/src/types/index.ts +628 -0
  428. package/src/types/mcp.ts +5 -0
  429. package/src/types/options.ts +165 -0
  430. package/src/types/results.ts +216 -0
  431. package/src/types/workflow-options.ts +113 -0
  432. package/src/types/workflow-results.ts +87 -0
  433. package/src/utils/ai-config-builder.ts +33 -0
  434. package/src/utils/ai-operation-utility.ts +380 -0
  435. package/src/utils/ai-service-factory.ts +125 -0
  436. package/src/utils/error-utils.ts +124 -0
  437. package/src/utils/file-utils.ts +197 -0
  438. package/src/utils/id-generator.ts +168 -0
  439. package/src/utils/metadata-utils.ts +48 -0
  440. package/src/utils/model-executor-parser.ts +80 -0
  441. package/src/utils/model-parser.ts +58 -0
  442. package/src/utils/stack-formatter.ts +53 -0
  443. package/src/utils/storage-utils.ts +94 -0
  444. package/src/utils/streaming-utils.ts +91 -0
  445. package/src/utils/task-o-matic-error.ts +393 -0
  446. package/tsconfig.json +20 -0
  447. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,779 @@
1
+ import { existsSync, writeFileSync, mkdirSync, readFileSync } from "fs";
2
+ import { join, resolve } from "path";
3
+ import { configManager } from "../lib/config";
4
+ import { runBetterTStackCLI } from "../lib/better-t-stack-cli";
5
+ import { prdService } from "./prd";
6
+ import { taskService } from "./tasks";
7
+ import { workflowAIAssistant } from "./workflow-ai-assistant";
8
+ import { AIOptions } from "../utils/ai-config-builder";
9
+ import { StreamingOptions, Task } from "../types";
10
+ import { ProgressCallback } from "../types/callbacks";
11
+ import {
12
+ InitializeResult,
13
+ DefinePRDResult,
14
+ RefinePRDResult,
15
+ GenerateTasksResult,
16
+ SplitTasksResult,
17
+ } from "../types/workflow-results";
18
+ import {
19
+ createStandardError,
20
+ TaskOMaticErrorCodes,
21
+ } from "../utils/task-o-matic-error";
22
+ import { executeTaskLoop } from "../lib/task-loop-execution";
23
+ import { ExecuteLoopOptions, ExecuteLoopResult } from "../types";
24
+
25
+ /**
26
+ * WorkflowService - Business logic for workflow operations
27
+ * Extracts all workflow logic from the command layer for reusability
28
+ */
29
+ export class WorkflowService {
30
+ /**
31
+ * Step 1: Initialize Project
32
+ * Handles project initialization, AI configuration, and optional bootstrapping
33
+ */
34
+ async initializeProject(input: {
35
+ projectName: string;
36
+ projectDir?: string; // Optional, defaults to projectName in cwd
37
+ initMethod?: "quick" | "custom" | "ai";
38
+ projectDescription?: string;
39
+ aiOptions?: AIOptions;
40
+ stackConfig?: {
41
+ frontend?: string;
42
+ backend?: string;
43
+ database?: string;
44
+ auth?: boolean;
45
+ };
46
+ bootstrap?: boolean;
47
+ includeDocs?: boolean;
48
+ streamingOptions?: StreamingOptions;
49
+ callbacks?: ProgressCallback;
50
+ }): Promise<InitializeResult> {
51
+ input.callbacks?.onProgress?.({
52
+ type: "started",
53
+ message: "Initializing project...",
54
+ });
55
+
56
+ // Determine project directory
57
+ const projectDir =
58
+ input.projectDir || resolve(process.cwd(), input.projectName);
59
+
60
+ // Create project directory
61
+ if (!existsSync(projectDir)) {
62
+ mkdirSync(projectDir, { recursive: true });
63
+ input.callbacks?.onProgress?.({
64
+ type: "progress",
65
+ message: `Created directory: ${input.projectName}`,
66
+ });
67
+ }
68
+
69
+ // Switch to project directory
70
+ process.chdir(projectDir);
71
+ configManager.setWorkingDirectory(projectDir);
72
+ await configManager.load();
73
+
74
+ // Initialize task-o-matic directory structure
75
+ const taskOMaticDir = join(projectDir, ".task-o-matic");
76
+ if (!existsSync(taskOMaticDir)) {
77
+ mkdirSync(taskOMaticDir, { recursive: true });
78
+ ["tasks", "prd", "logs"].forEach((dir) => {
79
+ mkdirSync(join(taskOMaticDir, dir), { recursive: true });
80
+ });
81
+ }
82
+
83
+ input.callbacks?.onProgress?.({
84
+ type: "progress",
85
+ message: "Configuring AI settings...",
86
+ });
87
+
88
+ // Get AI configuration
89
+ const aiProvider = input.aiOptions?.aiProvider || "openrouter";
90
+ const aiModel =
91
+ input.aiOptions?.aiModel ||
92
+ (aiProvider === "openrouter"
93
+ ? "anthropic/claude-3.5-sonnet"
94
+ : aiProvider === "anthropic"
95
+ ? "claude-sonnet-4.5"
96
+ : "gpt-4o");
97
+ const apiKey = input.aiOptions?.aiKey || process.env.AI_API_KEY || "";
98
+
99
+ // Save AI config to .env
100
+ const envPath = join(projectDir, ".env");
101
+ let envContent = existsSync(envPath) ? readFileSync(envPath, "utf-8") : "";
102
+
103
+ if (!envContent.includes("AI_PROVIDER=")) {
104
+ envContent += `AI_PROVIDER=${aiProvider}\n`;
105
+ }
106
+ if (!envContent.includes("AI_MODEL=")) {
107
+ envContent += `AI_MODEL=${aiModel}\n`;
108
+ }
109
+ if (
110
+ input.aiOptions?.aiProviderUrl &&
111
+ !envContent.includes("AI_PROVIDER_URL=")
112
+ ) {
113
+ envContent += `AI_PROVIDER_URL=${input.aiOptions.aiProviderUrl}\n`;
114
+ }
115
+
116
+ const providerKeyName =
117
+ aiProvider === "openai"
118
+ ? "OPENAI_API_KEY"
119
+ : aiProvider === "anthropic"
120
+ ? "ANTHROPIC_API_KEY"
121
+ : aiProvider === "openrouter"
122
+ ? "OPENROUTER_API_KEY"
123
+ : "AI_API_KEY";
124
+
125
+ if (!envContent.includes(`${providerKeyName}=`)) {
126
+ envContent += `${providerKeyName}=${apiKey}\n`;
127
+ }
128
+
129
+ writeFileSync(envPath, envContent);
130
+
131
+ // Update process.env and ConfigManager
132
+ process.env.AI_PROVIDER = aiProvider;
133
+ process.env.AI_MODEL = aiModel;
134
+ process.env[providerKeyName] = apiKey;
135
+ if (input.aiOptions?.aiProviderUrl) {
136
+ process.env.AI_PROVIDER_URL = input.aiOptions.aiProviderUrl;
137
+ }
138
+
139
+ configManager.setAIConfig({
140
+ provider: aiProvider as any,
141
+ model: aiModel,
142
+ apiKey: apiKey,
143
+ baseURL: input.aiOptions?.aiProviderUrl,
144
+ });
145
+
146
+ // Determine stack configuration
147
+ let stackConfig: any = {
148
+ projectName: input.projectName,
149
+ aiProvider,
150
+ aiModel,
151
+ };
152
+
153
+ if (input.initMethod === "ai" && input.projectDescription) {
154
+ input.callbacks?.onProgress?.({
155
+ type: "progress",
156
+ message: "Getting AI recommendations for stack...",
157
+ });
158
+
159
+ stackConfig = await workflowAIAssistant.assistInitConfig({
160
+ userDescription: input.projectDescription,
161
+ aiOptions: input.aiOptions,
162
+ streamingOptions: input.streamingOptions,
163
+ });
164
+
165
+ // Override with user's choices
166
+ stackConfig.projectName = input.projectName;
167
+ stackConfig.aiProvider = aiProvider;
168
+ stackConfig.aiModel = aiModel;
169
+ } else if (input.initMethod === "quick") {
170
+ stackConfig = {
171
+ ...stackConfig,
172
+ frontend: "next",
173
+ backend: "hono",
174
+ database: "sqlite",
175
+ auth: true,
176
+ reasoning: "Modern, well-supported stack",
177
+ };
178
+ } else if (input.stackConfig) {
179
+ stackConfig = { ...stackConfig, ...input.stackConfig };
180
+ }
181
+
182
+ // Bootstrap if requested
183
+ let bootstrapped = false;
184
+ if (input.bootstrap && (stackConfig.frontend || stackConfig.backend)) {
185
+ input.callbacks?.onProgress?.({
186
+ type: "progress",
187
+ message: "Bootstrapping with Better-T-Stack...",
188
+ });
189
+
190
+ try {
191
+ const result = await runBetterTStackCLI(
192
+ {
193
+ projectName: ".",
194
+ frontend: stackConfig.frontend || "next",
195
+ backend: stackConfig.backend || "hono",
196
+ database: stackConfig.database || "sqlite",
197
+ noAuth: !stackConfig.auth,
198
+ orm: "drizzle",
199
+ packageManager: "npm",
200
+ runtime: "node",
201
+ noInstall: false,
202
+ noGit: false,
203
+ includeDocs: input.includeDocs,
204
+ },
205
+ projectDir
206
+ );
207
+
208
+ if (result.success) {
209
+ bootstrapped = true;
210
+
211
+ // Fix config file naming
212
+ const dotConfigPath = join(taskOMaticDir, ".-bts-config.json");
213
+ const realConfigPath = join(
214
+ taskOMaticDir,
215
+ `${input.projectName}-bts-config.json`
216
+ );
217
+ const stackConfigPath = join(taskOMaticDir, "stack.json");
218
+
219
+ if (existsSync(dotConfigPath)) {
220
+ const configContent = JSON.parse(
221
+ readFileSync(dotConfigPath, "utf-8")
222
+ );
223
+ configContent.projectName = input.projectName;
224
+
225
+ const newContent = JSON.stringify(configContent, null, 2);
226
+ writeFileSync(realConfigPath, newContent);
227
+ writeFileSync(stackConfigPath, newContent);
228
+
229
+ const { unlinkSync } = require("fs");
230
+ unlinkSync(dotConfigPath);
231
+ }
232
+ }
233
+ } catch (error) {
234
+ input.callbacks?.onError?.(
235
+ error instanceof Error ? error : new Error(String(error))
236
+ );
237
+ }
238
+ }
239
+
240
+ // Save configuration
241
+ configManager.save();
242
+
243
+ input.callbacks?.onProgress?.({
244
+ type: "completed",
245
+ message: "Project initialized successfully",
246
+ });
247
+
248
+ return {
249
+ success: true,
250
+ projectDir,
251
+ projectName: input.projectName,
252
+ aiConfig: {
253
+ provider: aiProvider,
254
+ model: aiModel,
255
+ key: apiKey,
256
+ },
257
+ stackConfig,
258
+ bootstrapped,
259
+ };
260
+ }
261
+
262
+ /**
263
+ * Step 2: Define PRD
264
+ * Handles PRD creation through various methods
265
+ */
266
+ async definePRD(input: {
267
+ method: "upload" | "manual" | "ai" | "skip";
268
+ prdFile?: string;
269
+ prdDescription?: string;
270
+ prdContent?: string;
271
+ projectDir: string;
272
+ aiOptions?: AIOptions;
273
+ streamingOptions?: StreamingOptions;
274
+ callbacks?: ProgressCallback;
275
+ // Multi-generation options
276
+ multiGeneration?: boolean;
277
+ multiGenerationModels?: Array<{ provider: string; model: string }>;
278
+ combineAI?: { provider: string; model: string };
279
+ }): Promise<DefinePRDResult> {
280
+ const startTime = Date.now();
281
+ let tokenUsage:
282
+ | { prompt: number; completion: number; total: number }
283
+ | undefined;
284
+ let timeToFirstToken: number | undefined;
285
+ let cost: number | undefined;
286
+
287
+ input.callbacks?.onProgress?.({
288
+ type: "started",
289
+ message: "Defining PRD...",
290
+ });
291
+
292
+ const taskOMaticDir = join(input.projectDir, ".task-o-matic");
293
+ const prdDir = join(taskOMaticDir, "prd");
294
+
295
+ if (!existsSync(prdDir)) {
296
+ mkdirSync(prdDir, { recursive: true });
297
+ }
298
+
299
+ if (input.method === "skip") {
300
+ return {
301
+ success: true,
302
+ prdFile: "",
303
+ prdContent: "",
304
+ method: "skip",
305
+ stats: {
306
+ duration: Date.now() - startTime,
307
+ },
308
+ };
309
+ }
310
+
311
+ let prdContent = "";
312
+ let prdFilename = "prd.md";
313
+
314
+ if (input.method === "upload" && input.prdFile) {
315
+ if (!existsSync(input.prdFile)) {
316
+ throw createStandardError(
317
+ TaskOMaticErrorCodes.INVALID_INPUT,
318
+ `PRD file not found: ${input.prdFile}`,
319
+ {
320
+ suggestions: [
321
+ "Verify the file path is correct",
322
+ "Check if file was moved or deleted",
323
+ ],
324
+ }
325
+ );
326
+ }
327
+ prdContent = readFileSync(input.prdFile, "utf-8");
328
+ prdFilename = input.prdFile.split("/").pop() || "prd.md";
329
+ } else if (input.method === "manual" && input.prdContent) {
330
+ prdContent = input.prdContent;
331
+ } else if (input.method === "ai" && input.prdDescription) {
332
+ // Check if multi-generation is requested
333
+ if (
334
+ input.multiGeneration &&
335
+ input.multiGenerationModels &&
336
+ input.multiGenerationModels.length > 1
337
+ ) {
338
+ // Multi-generation mode
339
+ const results: Array<{
340
+ path: string;
341
+ content: string;
342
+ stats: any;
343
+ modelId: string;
344
+ }> = [];
345
+
346
+ input.callbacks?.onProgress?.({
347
+ type: "progress",
348
+ message: `Generating ${input.multiGenerationModels.length} PRDs concurrently...`,
349
+ });
350
+
351
+ // Generate PRDs concurrently
352
+ const promises = input.multiGenerationModels.map(
353
+ async (modelConfig, index) => {
354
+ const modelId = `${modelConfig.provider}:${modelConfig.model}`;
355
+ const result = await prdService.generatePRD({
356
+ description: input.prdDescription!,
357
+ outputDir: prdDir,
358
+ filename: `prd-${
359
+ modelConfig.provider
360
+ }-${modelConfig.model.replace(/\//g, "-")}.md`,
361
+ aiOptions: {
362
+ aiProvider: modelConfig.provider,
363
+ aiModel: modelConfig.model,
364
+ },
365
+ callbacks: {
366
+ onProgress: (event) => {
367
+ // Only modify events that have a message property
368
+ if (
369
+ event.type !== "stream-chunk" &&
370
+ event.type !== "reasoning-chunk"
371
+ ) {
372
+ input.callbacks?.onProgress?.({
373
+ ...event,
374
+ message: `[${modelId}] ${event.message}`,
375
+ });
376
+ } else {
377
+ input.callbacks?.onProgress?.(event);
378
+ }
379
+ },
380
+ },
381
+ });
382
+
383
+ results.push({
384
+ path: result.path,
385
+ content: result.content,
386
+ stats: result.stats,
387
+ modelId,
388
+ });
389
+
390
+ return result;
391
+ }
392
+ );
393
+
394
+ await Promise.all(promises);
395
+
396
+ // Aggregate metrics
397
+ tokenUsage = {
398
+ prompt: results.reduce(
399
+ (sum, r) => sum + (r.stats.tokenUsage?.prompt || 0),
400
+ 0
401
+ ),
402
+ completion: results.reduce(
403
+ (sum, r) => sum + (r.stats.tokenUsage?.completion || 0),
404
+ 0
405
+ ),
406
+ total: results.reduce(
407
+ (sum, r) => sum + (r.stats.tokenUsage?.total || 0),
408
+ 0
409
+ ),
410
+ };
411
+ timeToFirstToken = Math.min(
412
+ ...results
413
+ .map((r) => r.stats.timeToFirstToken || Infinity)
414
+ .filter((t) => t !== Infinity)
415
+ );
416
+ cost = results.reduce((sum, r) => sum + (r.stats.cost || 0), 0);
417
+
418
+ // Combine if requested
419
+ if (input.combineAI) {
420
+ input.callbacks?.onProgress?.({
421
+ type: "progress",
422
+ message: "Combining PRDs into master PRD...",
423
+ });
424
+
425
+ const prdContents = results.map((r) => r.content);
426
+ const masterResult = await prdService.combinePRDs({
427
+ prds: prdContents,
428
+ originalDescription: input.prdDescription!,
429
+ outputDir: prdDir,
430
+ filename: "prd-master.md",
431
+ aiOptions: {
432
+ aiProvider: input.combineAI.provider,
433
+ aiModel: input.combineAI.model,
434
+ },
435
+ callbacks: input.callbacks,
436
+ });
437
+
438
+ prdContent = masterResult.content;
439
+ prdFilename = "prd-master.md";
440
+
441
+ // Add combination metrics
442
+ if (masterResult.stats.tokenUsage) {
443
+ tokenUsage.prompt += masterResult.stats.tokenUsage.prompt;
444
+ tokenUsage.completion += masterResult.stats.tokenUsage.completion;
445
+ tokenUsage.total += masterResult.stats.tokenUsage.total;
446
+ }
447
+ if (masterResult.stats.cost) {
448
+ cost = (cost || 0) + masterResult.stats.cost;
449
+ }
450
+ } else {
451
+ // Use the first generated PRD as the main one
452
+ prdContent = results[0].content;
453
+ prdFilename = `prd-${results[0].modelId
454
+ .replace(/:/g, "-")
455
+ .replace(/\//g, "-")}.md`;
456
+ }
457
+ } else {
458
+ // Single generation mode
459
+ const result = await prdService.generatePRD({
460
+ description: input.prdDescription,
461
+ outputDir: prdDir,
462
+ filename: prdFilename,
463
+ aiOptions: input.aiOptions,
464
+ streamingOptions: input.streamingOptions,
465
+ callbacks: input.callbacks,
466
+ });
467
+
468
+ prdContent = result.content;
469
+ tokenUsage = result.stats.tokenUsage;
470
+ timeToFirstToken = result.stats.timeToFirstToken;
471
+ cost = result.stats.cost;
472
+ }
473
+ }
474
+
475
+ // Save PRD if not already saved by AI service
476
+ const prdPath = join(prdDir, prdFilename);
477
+ if (input.method !== "ai") {
478
+ writeFileSync(prdPath, prdContent);
479
+
480
+ input.callbacks?.onProgress?.({
481
+ type: "completed",
482
+ message: `PRD saved to ${prdPath}`,
483
+ });
484
+ }
485
+
486
+ const stats = {
487
+ duration: Date.now() - startTime,
488
+ ...(tokenUsage && { tokenUsage }),
489
+ ...(timeToFirstToken && { timeToFirstToken }),
490
+ ...(cost && { cost }),
491
+ };
492
+
493
+ return {
494
+ success: true,
495
+ prdFile: prdPath,
496
+ prdContent,
497
+ method: input.method,
498
+ stats,
499
+ };
500
+ }
501
+
502
+ /**
503
+ * Step 3: Refine PRD
504
+ * Handles PRD refinement through manual or AI methods
505
+ */
506
+ async refinePRD(input: {
507
+ method: "manual" | "ai" | "skip";
508
+ prdFile: string;
509
+ prdContent?: string;
510
+ feedback?: string;
511
+ projectDir: string;
512
+ aiOptions?: AIOptions;
513
+ streamingOptions?: StreamingOptions;
514
+ callbacks?: ProgressCallback;
515
+ }): Promise<RefinePRDResult> {
516
+ const startTime = Date.now();
517
+ let tokenUsage:
518
+ | { prompt: number; completion: number; total: number }
519
+ | undefined;
520
+ let timeToFirstToken: number | undefined;
521
+ let cost: number | undefined;
522
+
523
+ input.callbacks?.onProgress?.({
524
+ type: "started",
525
+ message: "Refining PRD...",
526
+ });
527
+
528
+ if (input.method === "skip") {
529
+ return {
530
+ success: true,
531
+ prdFile: input.prdFile,
532
+ prdContent: input.prdContent || readFileSync(input.prdFile, "utf-8"),
533
+ stats: {
534
+ duration: Date.now() - startTime,
535
+ },
536
+ };
537
+ }
538
+
539
+ let refinedContent =
540
+ input.prdContent || readFileSync(input.prdFile, "utf-8");
541
+
542
+ if (input.method === "manual" && input.prdContent) {
543
+ refinedContent = input.prdContent;
544
+ } else if (input.method === "ai" && input.feedback) {
545
+ input.callbacks?.onProgress?.({
546
+ type: "progress",
547
+ message: "Refining PRD with AI...",
548
+ });
549
+
550
+ // Capture metrics for AI operations
551
+ const streamingOptions = {
552
+ ...input.streamingOptions,
553
+ onFinish: async (result: any) => {
554
+ if (result.usage) {
555
+ tokenUsage = {
556
+ prompt:
557
+ result.usage.inputTokens || result.usage.promptTokens || 0,
558
+ completion:
559
+ result.usage.outputTokens || result.usage.completionTokens || 0,
560
+ total: result.usage.totalTokens || 0,
561
+ };
562
+
563
+ // Calculate cost (simplified - would need proper pricing lookup)
564
+ if (tokenUsage.total > 0) {
565
+ cost = tokenUsage.total * 0.000001; // Placeholder cost calculation
566
+ }
567
+ }
568
+ // Call original onFinish if provided
569
+ input.streamingOptions?.onFinish?.(result);
570
+ },
571
+ onChunk: (chunk: string) => {
572
+ if (chunk && !timeToFirstToken) {
573
+ timeToFirstToken = Date.now() - startTime;
574
+ }
575
+ // Call original onChunk if provided
576
+ input.streamingOptions?.onChunk?.(chunk);
577
+ },
578
+ };
579
+
580
+ refinedContent = await workflowAIAssistant.assistPRDRefinement({
581
+ currentPRD: refinedContent,
582
+ userFeedback: input.feedback,
583
+ aiOptions: input.aiOptions,
584
+ streamingOptions,
585
+ });
586
+ }
587
+
588
+ // Save refined PRD
589
+ writeFileSync(input.prdFile, refinedContent);
590
+
591
+ input.callbacks?.onProgress?.({
592
+ type: "completed",
593
+ message: "PRD refined successfully",
594
+ });
595
+
596
+ const stats = {
597
+ duration: Date.now() - startTime,
598
+ ...(tokenUsage && { tokenUsage }),
599
+ ...(timeToFirstToken && { timeToFirstToken }),
600
+ ...(cost && { cost }),
601
+ };
602
+
603
+ return {
604
+ success: true,
605
+ prdFile: input.prdFile,
606
+ prdContent: refinedContent,
607
+ stats,
608
+ };
609
+ }
610
+
611
+ /**
612
+ * Step 4: Generate Tasks
613
+ * Generates tasks from PRD using the prdService
614
+ */
615
+ async generateTasks(input: {
616
+ prdFile: string;
617
+ method: "standard" | "ai";
618
+ customInstructions?: string;
619
+ projectDir: string;
620
+ aiOptions?: AIOptions;
621
+ streamingOptions?: StreamingOptions;
622
+ callbacks?: ProgressCallback;
623
+ }): Promise<GenerateTasksResult> {
624
+ const startTime = Date.now();
625
+ let tokenUsage:
626
+ | { prompt: number; completion: number; total: number }
627
+ | undefined;
628
+ let timeToFirstToken: number | undefined;
629
+ let cost: number | undefined;
630
+
631
+ input.callbacks?.onProgress?.({
632
+ type: "started",
633
+ message: "Generating tasks from PRD...",
634
+ });
635
+
636
+ // Capture metrics for AI operations
637
+ const streamingOptions = {
638
+ ...input.streamingOptions,
639
+ onFinish: async (result: any) => {
640
+ if (result.usage) {
641
+ tokenUsage = {
642
+ prompt: result.usage.inputTokens || result.usage.promptTokens || 0,
643
+ completion:
644
+ result.usage.outputTokens || result.usage.completionTokens || 0,
645
+ total: result.usage.totalTokens || 0,
646
+ };
647
+
648
+ // Calculate cost (simplified - would need proper pricing lookup)
649
+ if (tokenUsage.total > 0) {
650
+ cost = tokenUsage.total * 0.000001; // Placeholder cost calculation
651
+ }
652
+ }
653
+ // Call original onFinish if provided
654
+ input.streamingOptions?.onFinish?.(result);
655
+ },
656
+ onChunk: (chunk: string) => {
657
+ if (chunk && !timeToFirstToken) {
658
+ timeToFirstToken = Date.now() - startTime;
659
+ }
660
+ // Call original onChunk if provided
661
+ input.streamingOptions?.onChunk?.(chunk);
662
+ },
663
+ };
664
+
665
+ const result = await prdService.parsePRD({
666
+ file: input.prdFile,
667
+ workingDirectory: input.projectDir,
668
+ aiOptions: input.aiOptions,
669
+ messageOverride: input.customInstructions,
670
+ streamingOptions,
671
+ callbacks: input.callbacks,
672
+ });
673
+
674
+ const stats = {
675
+ tasksCreated: result.tasks.length,
676
+ duration: Date.now() - startTime,
677
+ ...(tokenUsage && { tokenUsage }),
678
+ ...(timeToFirstToken && { timeToFirstToken }),
679
+ ...(cost && { cost }),
680
+ };
681
+
682
+ return {
683
+ success: true,
684
+ tasks: result.tasks,
685
+ stats,
686
+ };
687
+ }
688
+
689
+ /**
690
+ * Step 5: Split Tasks
691
+ * Splits complex tasks into subtasks
692
+ */
693
+ async splitTasks(input: {
694
+ taskIds: string[];
695
+ splitMethod: "interactive" | "standard" | "custom";
696
+ customInstructions?: string;
697
+ aiOptions?: AIOptions;
698
+ streamingOptions?: StreamingOptions;
699
+ callbacks?: ProgressCallback;
700
+ }): Promise<SplitTasksResult> {
701
+ input.callbacks?.onProgress?.({
702
+ type: "started",
703
+ message: `Splitting ${input.taskIds.length} tasks...`,
704
+ });
705
+
706
+ const results: Array<{
707
+ taskId: string;
708
+ subtasks: Task[];
709
+ error?: string;
710
+ }> = [];
711
+
712
+ for (const taskId of input.taskIds) {
713
+ try {
714
+ input.callbacks?.onProgress?.({
715
+ type: "progress",
716
+ message: `Splitting task ${taskId}...`,
717
+ });
718
+
719
+ const result = await taskService.splitTask(
720
+ taskId,
721
+ input.aiOptions,
722
+ undefined, // promptOverride
723
+ input.customInstructions,
724
+ input.streamingOptions
725
+ );
726
+
727
+ results.push({
728
+ taskId,
729
+ subtasks: result.subtasks,
730
+ });
731
+ } catch (error) {
732
+ results.push({
733
+ taskId,
734
+ subtasks: [],
735
+ error: error instanceof Error ? error.message : String(error),
736
+ });
737
+ }
738
+ }
739
+
740
+ input.callbacks?.onProgress?.({
741
+ type: "completed",
742
+ message: "Task splitting completed",
743
+ });
744
+
745
+ return {
746
+ success: true,
747
+ results,
748
+ };
749
+ }
750
+
751
+ /**
752
+ * Step 6: Execute Tasks
753
+ * Executes the generated tasks using the task loop executor
754
+ */
755
+ async executeTasks(input: {
756
+ options: ExecuteLoopOptions;
757
+ callbacks?: ProgressCallback;
758
+ }): Promise<{ success: boolean; result: ExecuteLoopResult }> {
759
+ input.callbacks?.onProgress?.({
760
+ type: "started",
761
+ message: "Executing tasks...",
762
+ });
763
+
764
+ const result = await executeTaskLoop(input.options);
765
+
766
+ input.callbacks?.onProgress?.({
767
+ type: "completed",
768
+ message: `Execution complete: ${result.completedTasks} completed, ${result.failedTasks} failed`,
769
+ });
770
+
771
+ return {
772
+ success: result.failedTasks === 0,
773
+ result,
774
+ };
775
+ }
776
+ }
777
+
778
+ // Export singleton instance
779
+ export const workflowService = new WorkflowService();