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,1150 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.taskService = exports.TaskService = void 0;
37
+ exports.getTaskService = getTaskService;
38
+ const ai_service_factory_1 = require("../utils/ai-service-factory");
39
+ const stack_formatter_1 = require("../utils/stack-formatter");
40
+ const ai_config_builder_1 = require("../utils/ai-config-builder");
41
+ const hooks_1 = require("../lib/hooks");
42
+ const logger_1 = require("../lib/logger");
43
+ const streaming_utils_1 = require("../utils/streaming-utils");
44
+ const error_utils_1 = require("../utils/error-utils");
45
+ const id_generator_1 = require("../utils/id-generator");
46
+ const task_o_matic_error_1 = require("../utils/task-o-matic-error");
47
+ const metadata_utils_1 = require("../utils/metadata-utils");
48
+ /**
49
+ * TaskService - Centralized business logic for all task operations
50
+ *
51
+ * This service provides a comprehensive API for task management with AI-powered features.
52
+ * It's framework-agnostic and can be used by CLI, TUI, or Web applications.
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * import { TaskService } from "task-o-matic";
57
+ *
58
+ * // Initialize with default configuration
59
+ * const taskService = new TaskService();
60
+ *
61
+ * // Create a task with AI enhancement
62
+ * const result = await taskService.createTask({
63
+ * title: "Implement feature",
64
+ * content: "Feature description",
65
+ * aiEnhance: true,
66
+ * aiOptions: {
67
+ * provider: "anthropic",
68
+ * model: "claude-3-5-sonnet"
69
+ * }
70
+ * });
71
+ *
72
+ * // Or inject dependencies for testing
73
+ * const taskService = new TaskService({
74
+ * storage: mockStorage,
75
+ * aiOperations: mockAI,
76
+ * });
77
+ * ```
78
+ */
79
+ class TaskService {
80
+ storage;
81
+ aiOperations;
82
+ modelProvider;
83
+ contextBuilder;
84
+ hooks;
85
+ /**
86
+ * Create a new TaskService
87
+ *
88
+ * @param dependencies - Optional dependencies to inject (for testing)
89
+ */
90
+ constructor(dependencies = {}) {
91
+ // Use injected dependencies or fall back to singletons
92
+ this.storage = dependencies.storage ?? (0, ai_service_factory_1.getStorage)();
93
+ this.aiOperations = dependencies.aiOperations ?? (0, ai_service_factory_1.getAIOperations)();
94
+ this.modelProvider = dependencies.modelProvider ?? (0, ai_service_factory_1.getModelProvider)();
95
+ this.contextBuilder = dependencies.contextBuilder ?? (0, ai_service_factory_1.getContextBuilder)();
96
+ this.hooks = dependencies.hooks ?? hooks_1.hooks;
97
+ }
98
+ // ============================================================================
99
+ // CORE CRUD OPERATIONS
100
+ // ============================================================================
101
+ /**
102
+ * Creates a new task with optional AI enhancement
103
+ *
104
+ * @param input - Task creation parameters
105
+ * @param input.title - Task title (required, 1-255 characters)
106
+ * @param input.content - Task content/description (optional)
107
+ * @param input.parentId - Parent task ID for creating subtasks
108
+ * @param input.effort - Estimated effort ("small" | "medium" | "large")
109
+ * @param input.aiEnhance - Enable AI enhancement with Context7 documentation
110
+ * @param input.aiOptions - AI configuration override
111
+ * @param input.streamingOptions - Real-time streaming options
112
+ *
113
+ * @returns Promise resolving to task creation result
114
+ *
115
+ * @throws {TaskOMaticError} If task creation fails (e.g., AI operation errors, storage errors)
116
+ * @throws {Error} If input validation fails
117
+ *
118
+ * @example Basic task creation
119
+ * ```typescript
120
+ * const task = await taskService.createTask({
121
+ * title: "Fix authentication bug",
122
+ * content: "Users cannot login with valid credentials",
123
+ * aiEnhance: false
124
+ * });
125
+ * ```
126
+ *
127
+ * @example Task with AI enhancement
128
+ * ```typescript
129
+ * try {
130
+ * const enhancedTask = await taskService.createTask({
131
+ * title: "Design authentication system",
132
+ * content: "Implement OAuth2 + JWT authentication",
133
+ * aiEnhance: true,
134
+ * streamingOptions: {
135
+ * onChunk: (chunk) => console.log("AI:", chunk)
136
+ * }
137
+ * });
138
+ * console.log("Enhanced content:", enhancedTask.task.content);
139
+ * } catch (error) {
140
+ * if (error instanceof TaskOMaticError) {
141
+ * console.error("AI enhancement failed:", error.getDetails());
142
+ * }
143
+ * }
144
+ * ```
145
+ *
146
+ * @example Creating subtasks
147
+ * ```typescript
148
+ * const subtask = await taskService.createTask({
149
+ * title: "Implement OAuth2 flow",
150
+ * parentId: "1",
151
+ * effort: "medium"
152
+ * });
153
+ * ```
154
+ */
155
+ async createTask(input) {
156
+ const startTime = Date.now();
157
+ let content = input.content;
158
+ let aiMetadata;
159
+ if (input.aiEnhance) {
160
+ this.hooks.emit("task:progress", {
161
+ message: "Building context for task...",
162
+ type: "progress",
163
+ });
164
+ // Build context with error handling (Bug fix 2.2)
165
+ let context;
166
+ try {
167
+ context = await this.contextBuilder.buildContextForNewTask(input.title, input.content);
168
+ }
169
+ catch (error) {
170
+ // Log warning but don't fail task creation
171
+ logger_1.logger.warn(`Warning: Could not build context: ${(0, error_utils_1.getErrorMessage)(error)}`);
172
+ // Continue with empty context
173
+ context = { stack: undefined, existingResearch: {} };
174
+ }
175
+ const stackInfo = (0, stack_formatter_1.formatStackInfo)(context.stack);
176
+ const enhancementAIConfig = (0, ai_config_builder_1.buildAIConfig)(input.aiOptions);
177
+ this.hooks.emit("task:progress", {
178
+ message: "Enhancing task with AI documentation...",
179
+ type: "progress",
180
+ });
181
+ const taskDescription = input.content ?? "";
182
+ // Generate temporary ID for AI operations (Bug fix 2.6)
183
+ const tempTaskId = id_generator_1.TaskIDGenerator.generate();
184
+ content = await this.aiOperations.enhanceTaskWithDocumentation(tempTaskId, input.title, taskDescription, stackInfo, input.streamingOptions, undefined, enhancementAIConfig, context.existingResearch);
185
+ const aiConfig = this.modelProvider.getAIConfig();
186
+ aiMetadata = {
187
+ taskId: "",
188
+ aiGenerated: true,
189
+ aiPrompt: "Enhance task with relevant documentation using Context7 tools",
190
+ confidence: 0.9,
191
+ aiProvider: aiConfig.provider,
192
+ aiModel: aiConfig.model,
193
+ generatedAt: Date.now(),
194
+ };
195
+ }
196
+ this.hooks.emit("task:progress", {
197
+ message: "Saving task...",
198
+ type: "progress",
199
+ });
200
+ const task = await this.storage.createTask({
201
+ title: input.title,
202
+ description: input.content ?? "",
203
+ content,
204
+ parentId: input.parentId,
205
+ estimatedEffort: input.effort,
206
+ }, aiMetadata);
207
+ this.hooks.emit("task:progress", {
208
+ type: "completed",
209
+ message: "Task created successfully",
210
+ });
211
+ // Emit task:created event
212
+ await this.hooks.emit("task:created", { task });
213
+ return { success: true, task, aiMetadata };
214
+ }
215
+ /**
216
+ * List tasks with optional filtering
217
+ *
218
+ * @param filters - Filter criteria
219
+ * @param filters.status - Filter by task status ("todo", "in-progress", "completed")
220
+ * @param filters.tag - Filter by task tag
221
+ *
222
+ * @returns Promise resolving to array of matching tasks
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * // List all tasks
227
+ * const allTasks = await taskService.listTasks({});
228
+ *
229
+ * // List only completed tasks
230
+ * const completedTasks = await taskService.listTasks({ status: "completed" });
231
+ *
232
+ * // List tasks with specific tag
233
+ * const frontendTasks = await taskService.listTasks({ tag: "frontend" });
234
+ * ```
235
+ */
236
+ async listTasks(filters) {
237
+ const storage = this.storage;
238
+ const topLevelTasks = await storage.getTopLevelTasks();
239
+ let filteredTasks = topLevelTasks;
240
+ if (filters.status) {
241
+ filteredTasks = filteredTasks.filter((task) => task.status === filters.status);
242
+ }
243
+ if (filters.tag) {
244
+ const tagToFilter = filters.tag; // Type narrowing
245
+ filteredTasks = filteredTasks.filter((task) => task.tags && task.tags.includes(tagToFilter));
246
+ }
247
+ return filteredTasks;
248
+ }
249
+ async getTask(id) {
250
+ return await this.storage.getTask(id);
251
+ }
252
+ async getTaskContent(id) {
253
+ return await this.storage.getTaskContent(id);
254
+ }
255
+ async getTaskAIMetadata(id) {
256
+ return await this.storage.getTaskAIMetadata(id);
257
+ }
258
+ async getSubtasks(id) {
259
+ return await this.storage.getSubtasks(id);
260
+ }
261
+ async updateTask(id, updates) {
262
+ const storage = this.storage;
263
+ const existingTask = await storage.getTask(id);
264
+ if (!existingTask) {
265
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(id);
266
+ }
267
+ // Validate status transitions
268
+ if (updates.status) {
269
+ // Allow same-status transitions as no-ops (needed for retry flows)
270
+ if (updates.status === existingTask.status) {
271
+ // Remove status from updates - it's already correct
272
+ delete updates.status;
273
+ }
274
+ else {
275
+ const validTransitions = {
276
+ todo: ["in-progress", "completed"],
277
+ "in-progress": ["completed", "todo"],
278
+ completed: ["todo", "in-progress"],
279
+ };
280
+ if (!validTransitions[existingTask.status].includes(updates.status)) {
281
+ throw (0, task_o_matic_error_1.formatInvalidStatusTransitionError)(existingTask.status, updates.status);
282
+ }
283
+ }
284
+ }
285
+ const finalUpdates = { ...updates };
286
+ // Handle tags: convert comma-separated string to array and merge
287
+ if (typeof updates.tags === "string") {
288
+ const newTags = updates.tags.split(",").map((tag) => tag.trim());
289
+ const existingTags = existingTask.tags || [];
290
+ finalUpdates.tags = [...new Set([...existingTags, ...newTags])];
291
+ }
292
+ const updatedTask = await storage.updateTask(id, finalUpdates);
293
+ if (!updatedTask) {
294
+ throw (0, task_o_matic_error_1.formatStorageError)(`updateTask ${id}`);
295
+ }
296
+ // Emit task:updated event
297
+ await this.hooks.emit("task:updated", {
298
+ task: updatedTask,
299
+ changes: finalUpdates,
300
+ });
301
+ // Emit task:status-changed event if status changed
302
+ if (updates.status && updates.status !== existingTask.status) {
303
+ await this.hooks.emit("task:status-changed", {
304
+ task: updatedTask,
305
+ oldStatus: existingTask.status,
306
+ newStatus: updates.status,
307
+ });
308
+ }
309
+ return updatedTask;
310
+ }
311
+ async setTaskStatus(id, status) {
312
+ return await this.updateTask(id, { status });
313
+ }
314
+ async deleteTask(id, options = {}) {
315
+ const { cascade, force } = options;
316
+ const storage = this.storage;
317
+ const taskToDelete = await storage.getTask(id);
318
+ if (!taskToDelete) {
319
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(id);
320
+ }
321
+ const deleted = [];
322
+ const orphanedSubtasks = [];
323
+ // Get subtasks before deletion
324
+ const subtasks = await storage.getSubtasks(id);
325
+ if (subtasks.length > 0 && !cascade) {
326
+ if (!force) {
327
+ throw (0, task_o_matic_error_1.createStandardError)(task_o_matic_error_1.TaskOMaticErrorCodes.TASK_OPERATION_FAILED, `Cannot delete task with ${subtasks.length} subtasks`, {
328
+ context: `Task ${id} has ${subtasks.length} subtasks`,
329
+ suggestions: [
330
+ "Use --cascade flag to delete task and all subtasks",
331
+ "Use --force flag to delete task and orphan subtasks",
332
+ "Delete subtasks first, then delete parent task",
333
+ ],
334
+ metadata: { taskId: id, subtaskCount: subtasks.length },
335
+ });
336
+ }
337
+ // Orphan subtasks by removing parent reference
338
+ for (const subtask of subtasks) {
339
+ await storage.updateTask(subtask.id, { parentId: undefined });
340
+ orphanedSubtasks.push(subtask);
341
+ }
342
+ }
343
+ else if (cascade) {
344
+ // Recursively delete subtasks
345
+ for (const subtask of subtasks) {
346
+ const result = await this.deleteTask(subtask.id, {
347
+ cascade: true,
348
+ force: true,
349
+ });
350
+ deleted.push(...result.deleted);
351
+ orphanedSubtasks.push(...result.orphanedSubtasks);
352
+ }
353
+ }
354
+ // Delete the main task
355
+ const success = await storage.deleteTask(id);
356
+ if (success) {
357
+ deleted.push(taskToDelete);
358
+ // Emit task:deleted event
359
+ await this.hooks.emit("task:deleted", { taskId: id });
360
+ }
361
+ return { success: true, deleted, orphanedSubtasks };
362
+ }
363
+ // ============================================================================
364
+ // TAG OPERATIONS
365
+ // ============================================================================
366
+ async addTags(id, tags) {
367
+ const storage = this.storage;
368
+ const task = await storage.getTask(id);
369
+ if (!task) {
370
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(id);
371
+ }
372
+ const existingTags = task.tags || [];
373
+ const newTags = tags.filter((tag) => !existingTags.includes(tag));
374
+ if (newTags.length === 0) {
375
+ return task; // No new tags to add
376
+ }
377
+ const updatedTags = [...existingTags, ...newTags];
378
+ const updatedTask = await storage.updateTask(id, { tags: updatedTags });
379
+ if (!updatedTask) {
380
+ throw (0, task_o_matic_error_1.formatStorageError)(`add tags to task ${id}`);
381
+ }
382
+ return updatedTask;
383
+ }
384
+ async removeTags(id, tags) {
385
+ const storage = this.storage;
386
+ const task = await storage.getTask(id);
387
+ if (!task) {
388
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(id);
389
+ }
390
+ const existingTags = task.tags || [];
391
+ const updatedTags = existingTags.filter((tag) => !tags.includes(tag));
392
+ if (updatedTags.length === existingTags.length) {
393
+ return task; // No tags removed
394
+ }
395
+ const updatedTask = await storage.updateTask(id, { tags: updatedTags });
396
+ if (!updatedTask) {
397
+ throw (0, task_o_matic_error_1.formatStorageError)(`remove tags from task ${id}`);
398
+ }
399
+ return updatedTask;
400
+ }
401
+ // ============================================================================
402
+ // TASK NAVIGATION
403
+ // ============================================================================
404
+ /**
405
+ * Get the next task based on priority and filtering criteria
406
+ *
407
+ * @param filters - Filter and priority criteria
408
+ * @param filters.status - Filter by task status
409
+ * @param filters.tag - Filter by task tag
410
+ * @param filters.effort - Filter by estimated effort
411
+ * @param filters.priority - Priority strategy ("newest", "oldest", "effort", or default)
412
+ *
413
+ * @returns Promise resolving to the highest priority task or null if none found
414
+ *
415
+ * @example
416
+ * ```typescript
417
+ * // Get the next task by default priority (task ID order)
418
+ * const nextTask = await taskService.getNextTask({});
419
+ *
420
+ * // Get the newest task with "todo" status
421
+ * const newestTodo = await taskService.getNextTask({
422
+ * status: "todo",
423
+ * priority: "newest"
424
+ * });
425
+ *
426
+ * // Get the highest effort task with specific tag
427
+ * const highEffortTask = await taskService.getNextTask({
428
+ * tag: "backend",
429
+ * priority: "effort"
430
+ * });
431
+ * ```
432
+ */
433
+ async getNextTask(filters) {
434
+ const storage = this.storage;
435
+ const allTasks = await storage.getTasks();
436
+ // Filter by status and other criteria
437
+ let filteredTasks = allTasks.filter((task) => {
438
+ if (filters.status && task.status !== filters.status)
439
+ return false;
440
+ if (filters.tag && (!task.tags || !task.tags.includes(filters.tag)))
441
+ return false;
442
+ if (filters.effort && task.estimatedEffort !== filters.effort)
443
+ return false;
444
+ return true;
445
+ });
446
+ if (filteredTasks.length === 0)
447
+ return null;
448
+ // Sort based on priority
449
+ switch (filters.priority) {
450
+ case "newest":
451
+ return filteredTasks.sort((a, b) => b.createdAt - a.createdAt)[0];
452
+ case "oldest":
453
+ return filteredTasks.sort((a, b) => a.createdAt - b.createdAt)[0];
454
+ case "effort":
455
+ const effortOrder = { small: 1, medium: 2, large: 3 };
456
+ return filteredTasks.sort((a, b) => (effortOrder[a.estimatedEffort || "medium"] || 2) -
457
+ (effortOrder[b.estimatedEffort || "medium"] || 2))[0];
458
+ default:
459
+ // Default: task ID order (1, 1.1, 1.2, 2, 2.1, etc.)
460
+ return filteredTasks.sort((a, b) => a.id.localeCompare(b.id))[0];
461
+ }
462
+ }
463
+ async getTaskTree(rootId) {
464
+ const storage = this.storage;
465
+ if (rootId) {
466
+ // Return tree starting from specific task
467
+ const rootTask = await storage.getTask(rootId);
468
+ if (!rootTask) {
469
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(rootId);
470
+ }
471
+ // Get all subtasks recursively
472
+ const getAllSubtasks = async (task) => {
473
+ const subtasks = await storage.getSubtasks(task.id);
474
+ const allSubtasks = [];
475
+ for (const subtask of subtasks) {
476
+ allSubtasks.push(subtask);
477
+ const deeperSubtasks = await getAllSubtasks(subtask);
478
+ allSubtasks.push(...deeperSubtasks);
479
+ }
480
+ return allSubtasks;
481
+ };
482
+ const subtasks = await getAllSubtasks(rootTask);
483
+ return [rootTask, ...subtasks];
484
+ }
485
+ else {
486
+ // Return all top-level tasks and their subtasks
487
+ return await storage.getTasks();
488
+ }
489
+ }
490
+ // ============================================================================
491
+ // AI OPERATIONS
492
+ // ============================================================================
493
+ /**
494
+ * Enhance a task with AI-generated documentation using Context7
495
+ *
496
+ * Uses AI to enrich the task description with relevant documentation,
497
+ * code examples, and best practices from Context7 documentation sources.
498
+ *
499
+ * @param taskId - ID of the task to enhance
500
+ * @param aiOptions - Optional AI configuration overrides
501
+ * @param streamingOptions - Optional streaming callbacks for real-time feedback
502
+ * @returns Promise resolving to enhancement result with metrics
503
+ *
504
+ * @throws {Error} If task not found
505
+ * @throws {TaskOMaticError} If AI enhancement fails
506
+ *
507
+ * @example Basic enhancement
508
+ * ```typescript
509
+ * const result = await taskService.enhanceTask("1");
510
+ * console.log("Enhanced content:", result.enhancedContent);
511
+ * console.log("Took:", result.stats.duration, "ms");
512
+ * ```
513
+ *
514
+ * @example With streaming
515
+ * ```typescript
516
+ * try {
517
+ * const result = await taskService.enhanceTask("1", undefined, {
518
+ * onChunk: (chunk) => process.stdout.write(chunk)
519
+ * });
520
+ * console.log("\nEnhancement complete!");
521
+ * } catch (error) {
522
+ * if (error instanceof TaskOMaticError) {
523
+ * console.error("Enhancement failed:", error.getDetails());
524
+ * }
525
+ * }
526
+ * ```
527
+ */
528
+ async enhanceTask(taskId, aiOptions, streamingOptions) {
529
+ const startTime = Date.now();
530
+ this.hooks.emit("task:progress", {
531
+ message: "Starting task enhancement...",
532
+ type: "started",
533
+ });
534
+ const task = await this.storage.getTask(taskId);
535
+ if (!task) {
536
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(taskId);
537
+ }
538
+ this.hooks.emit("task:progress", {
539
+ message: "Building context...",
540
+ type: "progress",
541
+ });
542
+ const context = await this.contextBuilder.buildContext(taskId);
543
+ const stackInfo = (0, stack_formatter_1.formatStackInfo)(context.stack);
544
+ const enhancementAIConfig = (0, ai_config_builder_1.buildAIConfig)(aiOptions);
545
+ this.hooks.emit("task:progress", {
546
+ message: "Calling AI for enhancement...",
547
+ type: "progress",
548
+ });
549
+ // Use utility to wrap streaming options and capture metrics (DRY fix 1.1)
550
+ const aiStartTime = Date.now();
551
+ const { options: metricsStreamingOptions, getMetrics } = (0, streaming_utils_1.createMetricsStreamingOptions)(streamingOptions, aiStartTime);
552
+ const enhancedContent = await this.aiOperations.enhanceTaskWithDocumentation(task.id, task.title, task.description ?? "", stackInfo, metricsStreamingOptions, undefined, enhancementAIConfig, context.existingResearch);
553
+ // Extract metrics after AI call
554
+ const { tokenUsage, timeToFirstToken } = getMetrics();
555
+ this.hooks.emit("task:progress", {
556
+ message: "Saving enhanced content...",
557
+ type: "progress",
558
+ });
559
+ const originalLength = task.description?.length || 0;
560
+ if (enhancedContent.length > 200) {
561
+ const contentFile = await this.storage.saveEnhancedTaskContent(task.id, enhancedContent);
562
+ await this.storage.updateTask(task.id, {
563
+ contentFile,
564
+ description: task.description +
565
+ "\n\n🤖 AI-enhanced with Context7 documentation available.",
566
+ });
567
+ }
568
+ else {
569
+ await this.storage.updateTask(task.id, { description: enhancedContent });
570
+ }
571
+ const aiConfig = this.modelProvider.getAIConfig();
572
+ const aiMetadata = {
573
+ taskId: task.id,
574
+ aiGenerated: true,
575
+ aiPrompt: "Enhance task with Context7 documentation using MCP tools",
576
+ confidence: 0.9,
577
+ aiProvider: aiConfig.provider,
578
+ aiModel: aiConfig.model,
579
+ enhancedAt: Date.now(),
580
+ };
581
+ await this.storage.saveTaskAIMetadata(aiMetadata);
582
+ const duration = Date.now() - startTime;
583
+ this.hooks.emit("task:progress", {
584
+ message: "Task enhancement completed",
585
+ type: "completed",
586
+ });
587
+ return {
588
+ success: true,
589
+ task,
590
+ enhancedContent,
591
+ stats: {
592
+ originalLength,
593
+ enhancedLength: enhancedContent.length,
594
+ duration,
595
+ tokenUsage,
596
+ timeToFirstToken,
597
+ cost: undefined, // Cost calculation can be added later
598
+ },
599
+ metadata: {
600
+ aiProvider: aiConfig.provider,
601
+ aiModel: aiConfig.model,
602
+ confidence: 0.9,
603
+ },
604
+ };
605
+ }
606
+ /**
607
+ * Split a task into subtasks using AI
608
+ *
609
+ * Analyzes the task and breaks it down into smaller, actionable subtasks
610
+ * with estimated effort. Can optionally use filesystem tools to understand
611
+ * project structure when creating subtasks.
612
+ *
613
+ * @param taskId - ID of the task to split
614
+ * @param aiOptions - Optional AI configuration overrides
615
+ * @param promptOverride - Optional custom prompt
616
+ * @param messageOverride - Optional custom message
617
+ * @param streamingOptions - Optional streaming callbacks
618
+ * @param enableFilesystemTools - Enable filesystem analysis for context
619
+ * @returns Promise resolving to split result with created subtasks
620
+ *
621
+ * @throws {Error} If task not found or already has subtasks
622
+ * @throws {TaskOMaticError} If AI operation fails
623
+ *
624
+ * @example Basic task splitting
625
+ * ```typescript
626
+ * const result = await taskService.splitTask("1");
627
+ * console.log(`Created ${result.subtasks.length} subtasks`);
628
+ * result.subtasks.forEach(subtask => {
629
+ * console.log(`- ${subtask.title} (${subtask.estimatedEffort})`);
630
+ * });
631
+ * ```
632
+ *
633
+ * @example With filesystem tools for code analysis
634
+ * ```typescript
635
+ * try {
636
+ * const result = await taskService.splitTask(
637
+ * "1",
638
+ * undefined,
639
+ * undefined,
640
+ * undefined,
641
+ * { onChunk: (chunk) => console.log(chunk) },
642
+ * true // Enable filesystem tools
643
+ * );
644
+ * console.log("AI analyzed codebase to create subtasks");
645
+ * } catch (error) {
646
+ * if (error instanceof TaskOMaticError) {
647
+ * console.error("Split failed:", error.suggestions);
648
+ * }
649
+ * }
650
+ * ```
651
+ */
652
+ async splitTask(taskId, aiOptions, promptOverride, messageOverride, streamingOptions, enableFilesystemTools) {
653
+ const startTime = Date.now();
654
+ this.hooks.emit("task:progress", {
655
+ message: "Starting task breakdown...",
656
+ type: "started",
657
+ });
658
+ const task = await this.storage.getTask(taskId);
659
+ if (!task) {
660
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(taskId);
661
+ }
662
+ // Check if task already has subtasks
663
+ const existingSubtasks = await this.storage.getSubtasks(taskId);
664
+ if (existingSubtasks.length > 0) {
665
+ throw (0, task_o_matic_error_1.createStandardError)(task_o_matic_error_1.TaskOMaticErrorCodes.TASK_OPERATION_FAILED, `Task already has ${existingSubtasks.length} subtasks`, {
666
+ context: `Task "${task.title}" (${taskId}) already has subtasks`,
667
+ suggestions: [
668
+ "Use existing subtasks instead of splitting again",
669
+ "Delete existing subtasks first if you want to re-split",
670
+ "Consider editing existing subtasks instead",
671
+ ],
672
+ metadata: { taskId, subtaskCount: existingSubtasks.length },
673
+ });
674
+ }
675
+ this.hooks.emit("task:progress", {
676
+ message: "Building context...",
677
+ type: "progress",
678
+ });
679
+ // Build comprehensive context
680
+ const context = await this.contextBuilder.buildContext(taskId);
681
+ const stackInfo = (0, stack_formatter_1.formatStackInfo)(context.stack);
682
+ // Get full task content
683
+ const fullContent = context.task.fullContent || task.description || "";
684
+ const breakdownAIConfig = (0, ai_config_builder_1.buildAIConfig)(aiOptions);
685
+ this.hooks.emit("task:progress", {
686
+ message: "Calling AI to break down task...",
687
+ type: "progress",
688
+ });
689
+ // Use utility to wrap streaming options and capture metrics (DRY fix 1.1)
690
+ const aiStartTime = Date.now();
691
+ const { options: metricsStreamingOptions, getMetrics } = (0, streaming_utils_1.createMetricsStreamingOptions)(streamingOptions, aiStartTime);
692
+ // Use AI service to break down the task with enhanced context
693
+ const subtaskData = await this.aiOperations.breakdownTask(task, breakdownAIConfig, promptOverride, messageOverride, metricsStreamingOptions, undefined, fullContent, stackInfo, existingSubtasks, enableFilesystemTools);
694
+ // Extract metrics after AI call
695
+ const { tokenUsage, timeToFirstToken } = getMetrics();
696
+ this.hooks.emit("task:progress", {
697
+ message: `Creating ${subtaskData.length} subtasks...`,
698
+ type: "progress",
699
+ });
700
+ // Create subtasks and save AI metadata for each (Bug fix 2.3)
701
+ const createdSubtasks = [];
702
+ const aiConfig = this.modelProvider.getAIConfig();
703
+ const splitTimestamp = Date.now();
704
+ for (let i = 0; i < subtaskData.length; i++) {
705
+ const subtask = subtaskData[i];
706
+ this.hooks.emit("task:progress", {
707
+ message: `Creating subtask ${i + 1}/${subtaskData.length}: ${subtask.title}`,
708
+ type: "progress",
709
+ });
710
+ // console.log(
711
+ // `[DEBUG] Creating subtask ${i + 1}:`,
712
+ // JSON.stringify(subtask, null, 2)
713
+ // );
714
+ try {
715
+ const result = await this.createTask({
716
+ title: subtask.title,
717
+ content: subtask.content,
718
+ effort: subtask.estimatedEffort,
719
+ parentId: taskId,
720
+ });
721
+ createdSubtasks.push(result.task);
722
+ // Save AI metadata for each subtask (Bug fix 2.3)
723
+ const subtaskMetadata = {
724
+ ...(0, metadata_utils_1.createBaseAIMetadata)(result.task.id, aiConfig, promptOverride, "Split task into meaningful subtasks with full context and existing subtask awareness", 0.9),
725
+ splitAt: splitTimestamp,
726
+ parentTaskId: taskId,
727
+ subtaskIndex: i + 1,
728
+ };
729
+ await (0, ai_service_factory_1.getStorage)().saveTaskAIMetadata(subtaskMetadata);
730
+ }
731
+ catch (err) {
732
+ logger_1.logger.error(`[DEBUG] Failed to create subtask ${i + 1}: ${err}`);
733
+ throw err;
734
+ }
735
+ }
736
+ // Save AI metadata for parent task as well
737
+ const parentMetadata = {
738
+ ...(0, metadata_utils_1.createBaseAIMetadata)(task.id, aiConfig, promptOverride, "Split task into meaningful subtasks with full context and existing subtask awareness", 0.9),
739
+ splitAt: splitTimestamp,
740
+ subtasksCreated: createdSubtasks.length,
741
+ };
742
+ await (0, ai_service_factory_1.getStorage)().saveTaskAIMetadata(parentMetadata);
743
+ const duration = Date.now() - startTime;
744
+ this.hooks.emit("task:progress", {
745
+ message: `Task split into ${createdSubtasks.length} subtasks`,
746
+ type: "completed",
747
+ });
748
+ return {
749
+ success: true,
750
+ task,
751
+ subtasks: createdSubtasks,
752
+ stats: {
753
+ subtasksCreated: createdSubtasks.length,
754
+ duration,
755
+ tokenUsage,
756
+ timeToFirstToken,
757
+ cost: undefined, // Cost calculation can be added later
758
+ },
759
+ metadata: {
760
+ aiProvider: aiConfig.provider,
761
+ aiModel: aiConfig.model,
762
+ confidence: 0.9,
763
+ },
764
+ };
765
+ }
766
+ /**
767
+ * Analyze and fetch documentation for a task using Context7
768
+ *
769
+ * Analyzes the task content to identify required libraries and documentation,
770
+ * then fetches relevant documentation from Context7. Caches documentation
771
+ * for future use.
772
+ *
773
+ * @param taskId - ID of the task to document
774
+ * @param force - Force re-fetch even if documentation exists
775
+ * @param aiOptions - Optional AI configuration overrides
776
+ * @param streamingOptions - Optional streaming callbacks
777
+ * @returns Promise resolving to documentation analysis result
778
+ *
779
+ * @throws {Error} If task not found or content is empty
780
+ * @throws {TaskOMaticError} If AI operation fails
781
+ *
782
+ * @example Analyze documentation needs
783
+ * ```typescript
784
+ * const result = await taskService.documentTask("1");
785
+ * if (result.documentation) {
786
+ * console.log("Documentation fetched:");
787
+ * console.log(result.documentation.recap);
788
+ * console.log("Libraries:", result.documentation.libraries);
789
+ * }
790
+ * ```
791
+ *
792
+ * @example Force refresh documentation
793
+ * ```typescript
794
+ * try {
795
+ * const result = await taskService.documentTask("1", true);
796
+ * console.log(`Analyzed ${result.analysis.libraries.length} libraries`);
797
+ * } catch (error) {
798
+ * if (error instanceof TaskOMaticError) {
799
+ * console.error("Documentation fetch failed:", error.getDetails());
800
+ * }
801
+ * }
802
+ * ```
803
+ */
804
+ async documentTask(taskId, force = false, aiOptions, streamingOptions) {
805
+ const startTime = Date.now();
806
+ this.hooks.emit("task:progress", {
807
+ message: "Analyzing documentation needs...",
808
+ type: "started",
809
+ });
810
+ const task = await this.storage.getTask(taskId);
811
+ if (!task) {
812
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(taskId);
813
+ }
814
+ if (task.documentation && !force) {
815
+ if (this.contextBuilder.isDocumentationFresh(task.documentation)) {
816
+ this.hooks.emit("task:progress", {
817
+ message: "Documentation is fresh, skipping analysis",
818
+ type: "info",
819
+ });
820
+ return {
821
+ success: true,
822
+ task,
823
+ documentation: task.documentation,
824
+ stats: {
825
+ duration: Date.now() - startTime,
826
+ },
827
+ };
828
+ }
829
+ }
830
+ this.hooks.emit("task:progress", {
831
+ message: "Building context...",
832
+ type: "progress",
833
+ });
834
+ const context = await this.contextBuilder.buildContext(taskId);
835
+ const stackInfo = (0, stack_formatter_1.formatStackInfo)(context.stack);
836
+ const analysisAIConfig = (0, ai_config_builder_1.buildAIConfig)(aiOptions);
837
+ // Get full task content
838
+ const fullContent = context.task.fullContent || task.description;
839
+ if (!fullContent) {
840
+ throw (0, task_o_matic_error_1.createStandardError)(task_o_matic_error_1.TaskOMaticErrorCodes.INVALID_INPUT, "Task content is empty", {
841
+ context: `Task ${taskId} has no content to enhance`,
842
+ suggestions: [
843
+ "Add content to the task before enhancing",
844
+ "Provide task description or details",
845
+ ],
846
+ metadata: { taskId },
847
+ });
848
+ }
849
+ // Get existing documentations from all tasks
850
+ const tasks = await this.storage.getTasks();
851
+ const documentations = tasks.map((task) => task.documentation);
852
+ this.hooks.emit("task:progress", {
853
+ message: "Calling AI to analyze documentation needs...",
854
+ type: "progress",
855
+ });
856
+ // First analyze what documentation is needed
857
+ const analysis = await this.aiOperations.analyzeDocumentationNeeds(task.id, task.title, fullContent, stackInfo, streamingOptions, undefined, analysisAIConfig, documentations);
858
+ let documentation;
859
+ if (analysis.libraries.length > 0) {
860
+ this.hooks.emit("task:progress", {
861
+ message: `Fetching documentation for ${analysis.libraries.length} libraries...`,
862
+ type: "progress",
863
+ });
864
+ // Build research object from actual libraries
865
+ const research = {};
866
+ for (const lib of analysis.libraries) {
867
+ const sanitizedLibrary = this.storage.sanitizeForFilename(lib.name);
868
+ const sanitizedQuery = this.storage.sanitizeForFilename(lib.searchQuery);
869
+ const docFile = `docs/${sanitizedLibrary}/${sanitizedQuery}.md`;
870
+ if (!research[lib.name]) {
871
+ research[lib.name] = [];
872
+ }
873
+ research[lib.name].push({
874
+ query: lib.searchQuery,
875
+ doc: docFile,
876
+ });
877
+ }
878
+ this.hooks.emit("task:progress", {
879
+ message: "Generating documentation recap...",
880
+ type: "progress",
881
+ });
882
+ const recap = await this.aiOperations.generateDocumentationRecap(analysis.libraries, analysis.toolResults?.map((tr) => ({
883
+ library: tr.toolName,
884
+ content: JSON.stringify(tr.output),
885
+ })) || [], streamingOptions);
886
+ documentation = {
887
+ lastFetched: Date.now(),
888
+ libraries: analysis.libraries.map((lib) => lib.context7Id),
889
+ recap,
890
+ files: analysis.files || [],
891
+ research,
892
+ };
893
+ this.hooks.emit("task:progress", {
894
+ message: "Saving documentation...",
895
+ type: "progress",
896
+ });
897
+ await this.storage.updateTask(taskId, { documentation });
898
+ }
899
+ const duration = Date.now() - startTime;
900
+ this.hooks.emit("task:progress", {
901
+ message: "Documentation analysis completed",
902
+ type: "completed",
903
+ });
904
+ return {
905
+ success: true,
906
+ task,
907
+ analysis,
908
+ documentation,
909
+ stats: {
910
+ duration,
911
+ },
912
+ };
913
+ }
914
+ /**
915
+ * Generate an implementation plan for a task using AI
916
+ *
917
+ * Creates a detailed implementation plan with steps, considerations,
918
+ * and technical approach. Uses filesystem and Context7 tools to understand
919
+ * the project context and provide relevant suggestions.
920
+ *
921
+ * @param taskId - ID of the task to plan
922
+ * @param aiOptions - Optional AI configuration overrides
923
+ * @param streamingOptions - Optional streaming callbacks
924
+ * @returns Promise resolving to plan result with generated plan text
925
+ *
926
+ * @throws {Error} If task not found
927
+ * @throws {TaskOMaticError} If AI operation fails
928
+ *
929
+ * @example Basic implementation planning
930
+ * ```typescript
931
+ * const result = await taskService.planTask("1");
932
+ * console.log("Implementation Plan:");
933
+ * console.log(result.plan);
934
+ * console.log(`Generated in ${result.stats.duration}ms`);
935
+ * ```
936
+ *
937
+ * @example With streaming for real-time plan generation
938
+ * ```typescript
939
+ * try {
940
+ * const result = await taskService.planTask("1", undefined, {
941
+ * onChunk: (chunk) => {
942
+ * // Display plan as it's generated
943
+ * process.stdout.write(chunk);
944
+ * }
945
+ * });
946
+ * console.log("\n\nPlan saved to:", `plans/${result.task.id}.md`);
947
+ * } catch (error) {
948
+ * if (error instanceof TaskOMaticError) {
949
+ * console.error("Planning failed:", error.getDetails());
950
+ * }
951
+ * }
952
+ * ```
953
+ */
954
+ async planTask(taskId, aiOptions, streamingOptions) {
955
+ const startTime = Date.now();
956
+ this.hooks.emit("task:progress", {
957
+ message: "Creating implementation plan...",
958
+ type: "started",
959
+ });
960
+ const task = await this.storage.getTask(taskId);
961
+ if (!task) {
962
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(taskId);
963
+ }
964
+ const aiService = this.aiOperations;
965
+ const planAIConfig = (0, ai_config_builder_1.buildAIConfig)(aiOptions);
966
+ this.hooks.emit("task:progress", {
967
+ message: "Building task context...",
968
+ type: "progress",
969
+ });
970
+ // Build task context and details
971
+ let taskContext = `Task ID: ${task.id}\nTitle: ${task.title}\n`;
972
+ let taskDetails = `Description: ${task.description || "No description"}\n`;
973
+ // If this is a subtask, include parent task context
974
+ if (task.parentId) {
975
+ const parentTask = await (0, ai_service_factory_1.getStorage)().getTask(task.parentId);
976
+ if (parentTask) {
977
+ taskContext += `Parent Task ID: ${parentTask.id}\nParent Task Title: ${parentTask.title}\n`;
978
+ taskDetails += `Parent Task Description: ${parentTask.description || "No description"}\n`;
979
+ }
980
+ }
981
+ // If this is a task with subtasks, get subtask details
982
+ const subtasks = await (0, ai_service_factory_1.getStorage)().getSubtasks(taskId);
983
+ if (subtasks.length > 0) {
984
+ taskDetails += `\nSubtasks:\n`;
985
+ subtasks.forEach((subtask, index) => {
986
+ taskDetails += `${index + 1}. ${subtask.title} (${subtask.id})\n`;
987
+ taskDetails += ` ${subtask.description || "No description"}\n\n`;
988
+ });
989
+ }
990
+ this.hooks.emit("task:progress", {
991
+ message: "Calling AI to create plan...",
992
+ type: "progress",
993
+ });
994
+ // Use utility to wrap streaming options and capture metrics (DRY fix 1.1)
995
+ const aiStartTime = Date.now();
996
+ const { options: metricsStreamingOptions, getMetrics } = (0, streaming_utils_1.createMetricsStreamingOptions)(streamingOptions, aiStartTime);
997
+ const plan = await aiService.planTask(taskContext, taskDetails, planAIConfig, undefined, undefined, metricsStreamingOptions);
998
+ // Extract metrics after AI call
999
+ const { tokenUsage, timeToFirstToken } = getMetrics();
1000
+ this.hooks.emit("task:progress", {
1001
+ message: "Saving plan...",
1002
+ type: "progress",
1003
+ });
1004
+ // Save the plan to storage
1005
+ await this.storage.savePlan(taskId, plan);
1006
+ const duration = Date.now() - startTime;
1007
+ this.hooks.emit("task:progress", {
1008
+ message: "Implementation plan created",
1009
+ type: "completed",
1010
+ });
1011
+ const aiConfig = this.modelProvider.getAIConfig();
1012
+ return {
1013
+ success: true,
1014
+ task,
1015
+ plan,
1016
+ stats: {
1017
+ duration,
1018
+ tokenUsage,
1019
+ timeToFirstToken,
1020
+ cost: undefined, // Cost calculation can be added later
1021
+ },
1022
+ metadata: {
1023
+ aiProvider: aiConfig.provider,
1024
+ aiModel: aiConfig.model,
1025
+ },
1026
+ };
1027
+ }
1028
+ // ============================================================================
1029
+ // DOCUMENTATION OPERATIONS
1030
+ // ============================================================================
1031
+ async getTaskDocumentation(taskId) {
1032
+ return this.storage.getTaskDocumentation(taskId);
1033
+ }
1034
+ async addTaskDocumentationFromFile(taskId, filePath) {
1035
+ const task = await this.getTask(taskId);
1036
+ if (!task) {
1037
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(taskId);
1038
+ }
1039
+ try {
1040
+ const { readFileSync, existsSync } = await Promise.resolve().then(() => __importStar(require("fs")));
1041
+ const { resolve } = await Promise.resolve().then(() => __importStar(require("path")));
1042
+ const resolvedPath = resolve(filePath);
1043
+ if (!existsSync(resolvedPath)) {
1044
+ throw (0, task_o_matic_error_1.createStandardError)(task_o_matic_error_1.TaskOMaticErrorCodes.STORAGE_ERROR, `Documentation file not found: ${filePath}`, {
1045
+ context: `Tried to load documentation from ${resolvedPath}`,
1046
+ suggestions: [
1047
+ "Check that the file path is correct",
1048
+ "Ensure the file exists",
1049
+ "Use an absolute path or path relative to current directory",
1050
+ ],
1051
+ metadata: { filePath, resolvedPath },
1052
+ });
1053
+ }
1054
+ const content = readFileSync(resolvedPath, "utf-8");
1055
+ const savedPath = await this.storage.saveTaskDocumentation(taskId, content);
1056
+ return {
1057
+ filePath: savedPath,
1058
+ task,
1059
+ };
1060
+ }
1061
+ catch (error) {
1062
+ // Re-throw if already a TaskOMaticError
1063
+ if (error instanceof task_o_matic_error_1.TaskOMaticError) {
1064
+ throw error;
1065
+ }
1066
+ // Wrap other errors
1067
+ throw (0, task_o_matic_error_1.formatStorageError)("saveTaskDocumentation", error instanceof Error ? error : undefined);
1068
+ }
1069
+ }
1070
+ async setTaskPlan(taskId, planText, planFilePath) {
1071
+ const task = await this.getTask(taskId);
1072
+ if (!task) {
1073
+ throw (0, task_o_matic_error_1.formatTaskNotFoundError)(taskId);
1074
+ }
1075
+ let plan;
1076
+ if (planFilePath) {
1077
+ try {
1078
+ const { readFileSync, existsSync } = await Promise.resolve().then(() => __importStar(require("fs")));
1079
+ const { resolve } = await Promise.resolve().then(() => __importStar(require("path")));
1080
+ const resolvedPath = resolve(planFilePath);
1081
+ if (!existsSync(resolvedPath)) {
1082
+ throw (0, task_o_matic_error_1.createStandardError)(task_o_matic_error_1.TaskOMaticErrorCodes.STORAGE_ERROR, `Plan file not found: ${planFilePath}`, {
1083
+ context: `Tried to load plan from ${resolvedPath}`,
1084
+ suggestions: [
1085
+ "Check that the file path is correct",
1086
+ "Ensure the file exists",
1087
+ "Use an absolute path or path relative to current directory",
1088
+ ],
1089
+ metadata: { planFilePath, resolvedPath },
1090
+ });
1091
+ }
1092
+ plan = readFileSync(resolvedPath, "utf-8");
1093
+ }
1094
+ catch (error) {
1095
+ // Re-throw if already a TaskOMaticError
1096
+ if (error instanceof task_o_matic_error_1.TaskOMaticError) {
1097
+ throw error;
1098
+ }
1099
+ // Wrap other errors
1100
+ throw (0, task_o_matic_error_1.formatStorageError)("readFileSync", error instanceof Error ? error : undefined);
1101
+ }
1102
+ }
1103
+ else if (planText) {
1104
+ plan = planText;
1105
+ }
1106
+ else {
1107
+ throw (0, task_o_matic_error_1.createStandardError)(task_o_matic_error_1.TaskOMaticErrorCodes.INVALID_INPUT, "Either planText or planFilePath must be provided", {
1108
+ context: "setTaskPlan requires either planText or planFilePath parameter",
1109
+ suggestions: [
1110
+ "Provide planText parameter with the plan content",
1111
+ "Provide planFilePath parameter with path to plan file",
1112
+ ],
1113
+ metadata: { taskId },
1114
+ });
1115
+ }
1116
+ await this.storage.savePlan(taskId, plan);
1117
+ const planFile = `plans/${taskId}.md`;
1118
+ return {
1119
+ planFile,
1120
+ task,
1121
+ };
1122
+ }
1123
+ // ============================================================================
1124
+ // PLAN OPERATIONS
1125
+ // ============================================================================
1126
+ async getTaskPlan(taskId) {
1127
+ return this.storage.getPlan(taskId);
1128
+ }
1129
+ async listTaskPlans() {
1130
+ return this.storage.listPlans();
1131
+ }
1132
+ async deleteTaskPlan(taskId) {
1133
+ return this.storage.deletePlan(taskId);
1134
+ }
1135
+ }
1136
+ exports.TaskService = TaskService;
1137
+ // Lazy singleton instance - only created when first accessed
1138
+ let taskServiceInstance;
1139
+ function getTaskService() {
1140
+ if (!taskServiceInstance) {
1141
+ taskServiceInstance = new TaskService();
1142
+ }
1143
+ return taskServiceInstance;
1144
+ }
1145
+ // Backward compatibility: export as const but use getter
1146
+ exports.taskService = new Proxy({}, {
1147
+ get(target, prop) {
1148
+ return getTaskService()[prop];
1149
+ },
1150
+ });