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,197 @@
1
+ import { existsSync, writeFileSync, mkdirSync, readFileSync } from "fs";
2
+ import { access, constants } from "fs/promises";
3
+ import { join, dirname } from "path";
4
+ import {
5
+ createStandardError,
6
+ TaskOMaticErrorCodes,
7
+ } from "./task-o-matic-error";
8
+ import { configManager } from "../lib/config";
9
+
10
+ /**
11
+ * Validates that a file exists at the given path (synchronous).
12
+ * Throws an error with a custom message if the file doesn't exist.
13
+ *
14
+ * @param filePath - Path to the file to validate
15
+ * @param customMessage - Optional custom error message
16
+ * @throws TaskOMaticError if file doesn't exist
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * validateFileExists("./config.json", "Configuration file not found");
21
+ * // Throws: TaskOMaticError with code INVALID_INPUT if file doesn't exist
22
+ * ```
23
+ */
24
+ export function validateFileExists(
25
+ filePath: string,
26
+ customMessage?: string
27
+ ): void {
28
+ if (!existsSync(filePath)) {
29
+ throw createStandardError(
30
+ TaskOMaticErrorCodes.INVALID_INPUT,
31
+ customMessage || `File not found: ${filePath}`,
32
+ {
33
+ suggestions: ["Verify the file path is correct."],
34
+ }
35
+ );
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Validates that a file exists at the given path (asynchronous).
41
+ * Throws an error with a custom message if the file doesn't exist.
42
+ *
43
+ * @param filePath - Path to the file to validate
44
+ * @param customMessage - Optional custom error message
45
+ * @throws TaskOMaticError if file doesn't exist
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * await validateFileExistsAsync("./data.json");
50
+ * // Throws: TaskOMaticError with code INVALID_INPUT if file doesn't exist
51
+ * ```
52
+ */
53
+ export async function validateFileExistsAsync(
54
+ filePath: string,
55
+ customMessage?: string
56
+ ): Promise<void> {
57
+ try {
58
+ await access(filePath, constants.F_OK);
59
+ } catch {
60
+ throw createStandardError(
61
+ TaskOMaticErrorCodes.INVALID_INPUT,
62
+ customMessage || `File not found: ${filePath}`,
63
+ {
64
+ suggestions: ["Verify the file path is correct."],
65
+ }
66
+ );
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Checks if a file exists at the given path (synchronous).
72
+ * Returns true if file exists, false otherwise.
73
+ * Unlike validateFileExists, this doesn't throw an error.
74
+ *
75
+ * @param filePath - Path to check
76
+ * @returns true if file exists, false otherwise
77
+ */
78
+ export function fileExists(filePath: string): boolean {
79
+ return existsSync(filePath);
80
+ }
81
+
82
+ /**
83
+ * Checks if a file exists at the given path (asynchronous).
84
+ * Returns true if file exists, false otherwise.
85
+ * Unlike validateFileExistsAsync, this doesn't throw an error.
86
+ *
87
+ * @param filePath - Path to check
88
+ * @returns Promise resolving to true if file exists, false otherwise
89
+ */
90
+ export async function fileExistsAsync(filePath: string): Promise<boolean> {
91
+ try {
92
+ await access(filePath, constants.F_OK);
93
+ return true;
94
+ } catch {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Saves a file to the PRD directory, ensuring the directory exists.
101
+ * If no output directory is specified, uses `.task-o-matic/prd/` by default.
102
+ *
103
+ * @param content - Content to write to the file
104
+ * @param filename - Filename (defaults to "prd.md")
105
+ * @param outputDir - Optional output directory override
106
+ * @returns Full path to the saved file
107
+ * @throws TaskOMaticError if file saving fails
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * // Save to default location (.task-o-matic/prd/prd.md)
112
+ * const path = savePRDFile("# My PRD\n...");
113
+ *
114
+ * // Save with custom filename
115
+ * const path = savePRDFile("# My PRD\n...", "custom-prd.md");
116
+ *
117
+ * // Save to custom directory
118
+ * const path = savePRDFile("# My PRD\n...", "prd.md", "./docs");
119
+ * ```
120
+ */
121
+ export function savePRDFile(
122
+ content: string,
123
+ filename: string = "prd.md",
124
+ outputDir?: string
125
+ ): string {
126
+ const taskOMaticDir = configManager.getTaskOMaticDir();
127
+ const prdDir = outputDir || join(taskOMaticDir, "prd");
128
+
129
+ if (!existsSync(prdDir)) {
130
+ mkdirSync(prdDir, { recursive: true });
131
+ }
132
+
133
+ const path = join(prdDir, filename);
134
+ writeFileSync(path, content);
135
+
136
+ return path;
137
+ }
138
+
139
+ /**
140
+ * Saves a stack configuration to a JSON file.
141
+ * If no output path is specified, saves to `.task-o-matic/stack.json`.
142
+ *
143
+ * @param config - BTSConfig object to save
144
+ * @param outputPath - Optional custom output path
145
+ * @returns Full path to the saved file
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * // Save to default location
150
+ * const path = saveStackFile(config);
151
+ *
152
+ * // Save to custom location
153
+ * const path = saveStackFile(config, "./my-project/stack.json");
154
+ * ```
155
+ */
156
+ export function saveStackFile(config: object, outputPath?: string): string {
157
+ const taskOMaticDir = configManager.getTaskOMaticDir();
158
+ const stackPath = outputPath || join(taskOMaticDir, "stack.json");
159
+
160
+ const dir = dirname(stackPath);
161
+ if (!existsSync(dir)) {
162
+ mkdirSync(dir, { recursive: true });
163
+ }
164
+
165
+ writeFileSync(stackPath, JSON.stringify(config, null, 2));
166
+ return stackPath;
167
+ }
168
+
169
+ /**
170
+ * Loads a stack configuration from a JSON file.
171
+ * If no input path is specified, loads from `.task-o-matic/stack.json`.
172
+ *
173
+ * @param inputPath - Optional custom input path
174
+ * @returns The parsed BTSConfig object, or null if file doesn't exist
175
+ *
176
+ * @example
177
+ * ```typescript
178
+ * // Load from default location
179
+ * const config = loadStackFile();
180
+ *
181
+ * // Load from custom location
182
+ * const config = loadStackFile("./my-project/stack.json");
183
+ * ```
184
+ */
185
+ export function loadStackFile<T = Record<string, unknown>>(
186
+ inputPath?: string
187
+ ): T | null {
188
+ const taskOMaticDir = configManager.getTaskOMaticDir();
189
+ const stackPath = inputPath || join(taskOMaticDir, "stack.json");
190
+
191
+ if (!existsSync(stackPath)) {
192
+ return null;
193
+ }
194
+
195
+ const content = readFileSync(stackPath, "utf-8");
196
+ return JSON.parse(content) as T;
197
+ }
@@ -0,0 +1,168 @@
1
+ import { randomBytes } from "crypto";
2
+ import {
3
+ createStandardError,
4
+ TaskOMaticErrorCodes,
5
+ } from "./task-o-matic-error";
6
+
7
+ /**
8
+ * Generates unique task IDs with consistent format.
9
+ * Uses timestamp + random hex for uniqueness.
10
+ */
11
+ export class TaskIDGenerator {
12
+ /**
13
+ * Generates a unique task ID with format: prefix-timestamp-random
14
+ *
15
+ * @param prefix - Prefix for the ID (default: "task")
16
+ * @returns Unique task ID
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const id = TaskIDGenerator.generate();
21
+ * // Returns: "task-1733750400000-a1b2c3d4"
22
+ *
23
+ * const customId = TaskIDGenerator.generate("subtask");
24
+ * // Returns: "subtask-1733750400000-e5f6g7h8"
25
+ * ```
26
+ */
27
+ static generate(prefix: string = "task"): string {
28
+ const timestamp = Date.now();
29
+ const random = randomBytes(4).toString("hex");
30
+ return `${prefix}-${timestamp}-${random}`;
31
+ }
32
+
33
+ /**
34
+ * Validates a task ID format.
35
+ * Accepts three formats:
36
+ * - Timestamped: "task-1234567890-abcd1234"
37
+ * - Hierarchical: "1.2.3"
38
+ * - Numeric: "123"
39
+ *
40
+ * @param id - Task ID to validate
41
+ * @returns true if ID format is valid
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * TaskIDGenerator.validate("task-1234-abcd"); // true
46
+ * TaskIDGenerator.validate("1.2.3"); // true
47
+ * TaskIDGenerator.validate("123"); // true
48
+ * TaskIDGenerator.validate("invalid!"); // false
49
+ * ```
50
+ */
51
+ static validate(id: string): boolean {
52
+ if (!id || typeof id !== "string") {
53
+ return false;
54
+ }
55
+
56
+ // Format 1: Timestamped (task-timestamp-random)
57
+ const timestampedPattern = /^[a-z]+-\d+-[a-f0-9]{8}$/;
58
+ if (timestampedPattern.test(id)) {
59
+ return true;
60
+ }
61
+
62
+ // Format 2: Hierarchical (1.2.3)
63
+ const hierarchicalPattern = /^[\d.]+$/;
64
+ if (hierarchicalPattern.test(id)) {
65
+ return true;
66
+ }
67
+
68
+ // Format 3: Numeric (123)
69
+ const numericPattern = /^\d+$/;
70
+ if (numericPattern.test(id)) {
71
+ return true;
72
+ }
73
+
74
+ return false;
75
+ }
76
+
77
+ /**
78
+ * Checks if an ID is unique within a set of existing IDs.
79
+ *
80
+ * @param id - ID to check
81
+ * @param existingIds - Set of existing IDs
82
+ * @returns true if ID is unique
83
+ */
84
+ static isUnique(id: string, existingIds: Set<string>): boolean {
85
+ return !existingIds.has(id);
86
+ }
87
+
88
+ /**
89
+ * Generates a unique ID that doesn't exist in the provided set.
90
+ * Retries up to maxAttempts times if collisions occur.
91
+ *
92
+ * @param existingIds - Set of existing IDs to avoid
93
+ * @param prefix - Prefix for the ID
94
+ * @param maxAttempts - Maximum number of generation attempts
95
+ * @returns Unique task ID
96
+ * @throws TaskOMaticError if unable to generate unique ID after maxAttempts
97
+ */
98
+ static generateUnique(
99
+ existingIds: Set<string>,
100
+ prefix: string = "task",
101
+ maxAttempts: number = 10
102
+ ): string {
103
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
104
+ const id = this.generate(prefix);
105
+ if (this.isUnique(id, existingIds)) {
106
+ return id;
107
+ }
108
+ }
109
+
110
+ throw createStandardError(
111
+ TaskOMaticErrorCodes.UNEXPECTED_ERROR,
112
+ `Failed to generate unique ID after ${maxAttempts} attempts`,
113
+ {
114
+ context: `Could not find a unique ID with prefix '${prefix}' after ${maxAttempts} attempts.`,
115
+ suggestions: [
116
+ "Increase maxAttempts if you have a very large number of tasks.",
117
+ ],
118
+ }
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Generates a hierarchical child ID from a parent ID.
124
+ * If parent is "1.2", generates "1.2.1", "1.2.2", etc.
125
+ *
126
+ * @param parentId - Parent task ID
127
+ * @param childIndex - Index of the child (1-based)
128
+ * @returns Child task ID
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * TaskIDGenerator.generateChildId("1", 1); // "1.1"
133
+ * TaskIDGenerator.generateChildId("1.2", 3); // "1.2.3"
134
+ * ```
135
+ */
136
+ static generateChildId(parentId: string, childIndex: number): string {
137
+ return `${parentId}.${childIndex}`;
138
+ }
139
+
140
+ /**
141
+ * Parses a hierarchical ID to extract parent ID and child index.
142
+ *
143
+ * @param id - Hierarchical task ID
144
+ * @returns Object with parentId and childIndex, or null if not hierarchical
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * TaskIDGenerator.parseHierarchicalId("1.2.3");
149
+ * // Returns: { parentId: "1.2", childIndex: 3 }
150
+ * ```
151
+ */
152
+ static parseHierarchicalId(
153
+ id: string
154
+ ): { parentId: string; childIndex: number } | null {
155
+ const parts = id.split(".");
156
+ if (parts.length < 2) {
157
+ return null;
158
+ }
159
+
160
+ const childIndex = parseInt(parts[parts.length - 1], 10);
161
+ if (isNaN(childIndex)) {
162
+ return null;
163
+ }
164
+
165
+ const parentId = parts.slice(0, -1).join(".");
166
+ return { parentId, childIndex };
167
+ }
168
+ }
@@ -0,0 +1,48 @@
1
+ import { AIConfig } from "../types";
2
+
3
+ /**
4
+ * Creates base AI metadata object with common fields.
5
+ * Caller can extend with operation-specific fields.
6
+ *
7
+ * @param taskId - The ID of the task
8
+ * @param aiConfig - AI configuration used for the operation
9
+ * @param promptOverride - Optional custom prompt override
10
+ * @param defaultPrompt - Default prompt if no override provided
11
+ * @param confidence - Confidence score (0-1) for the AI operation
12
+ * @returns Base metadata object
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const baseMetadata = createBaseAIMetadata(
17
+ * "task-123",
18
+ * { provider: "anthropic", model: "claude-sonnet-4.5" },
19
+ * undefined,
20
+ * "Split task into subtasks",
21
+ * 0.9
22
+ * );
23
+ *
24
+ * // Extend with operation-specific fields
25
+ * const subtaskMetadata = {
26
+ * ...baseMetadata,
27
+ * parentTaskId: "parent-123",
28
+ * subtaskIndex: 1
29
+ * };
30
+ * ```
31
+ */
32
+ export function createBaseAIMetadata(
33
+ taskId: string,
34
+ aiConfig: Partial<AIConfig>,
35
+ promptOverride?: string,
36
+ defaultPrompt: string = "AI-generated task",
37
+ confidence: number = 0.9
38
+ ) {
39
+ return {
40
+ taskId,
41
+ aiGenerated: true,
42
+ aiPrompt: promptOverride || defaultPrompt,
43
+ confidence,
44
+ aiProvider: aiConfig.provider,
45
+ aiModel: aiConfig.model,
46
+ generatedAt: Date.now(),
47
+ };
48
+ }
@@ -0,0 +1,80 @@
1
+ import { ExecutorTool, ModelAttemptConfig } from "../types";
2
+ import {
3
+ createStandardError,
4
+ TaskOMaticErrorCodes,
5
+ } from "./task-o-matic-error";
6
+
7
+ /**
8
+ * Valid executor tools
9
+ */
10
+ export const VALID_EXECUTORS: ExecutorTool[] = [
11
+ "opencode",
12
+ "claude",
13
+ "gemini",
14
+ "codex",
15
+ "kilo",
16
+ ];
17
+
18
+ /**
19
+ * Parse --try-models option into ModelAttemptConfig array
20
+ * Supports formats:
21
+ * - "model1,model2,model3" - just models (uses default executor)
22
+ * - "opencode:gpt-4o,claude:sonnet-4" - executor:model format
23
+ * - Mixed: "gpt-4o,claude:sonnet-4,gemini:gemini-2.0"
24
+ *
25
+ * @param value - Comma-separated model/executor specifications
26
+ * @returns Array of model attempt configurations
27
+ * @throws TaskOMaticError if an invalid executor is specified
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * parseTryModels("gpt-4o-mini,gpt-4o"); // [{ model: "gpt-4o-mini" }, { model: "gpt-4o" }]
32
+ * parseTryModels("opencode:gpt-4o,claude:sonnet-4"); // [{ executor: "opencode", model: "gpt-4o" }, ...]
33
+ * ```
34
+ */
35
+ export function parseTryModels(value: string): ModelAttemptConfig[] {
36
+ return value.split(",").map((item) => {
37
+ const trimmed = item.trim();
38
+
39
+ // Check if it includes executor specification (executor:model format)
40
+ if (trimmed.includes(":")) {
41
+ const [executor, model] = trimmed.split(":");
42
+
43
+ if (!VALID_EXECUTORS.includes(executor as ExecutorTool)) {
44
+ throw createStandardError(
45
+ TaskOMaticErrorCodes.INVALID_INPUT,
46
+ `Invalid executor "${executor}" in --try-models. Must be one of: ${VALID_EXECUTORS.join(
47
+ ", "
48
+ )}`
49
+ );
50
+ }
51
+
52
+ return {
53
+ executor: executor as ExecutorTool,
54
+ model: model.trim(),
55
+ };
56
+ }
57
+
58
+ // Just a model name - use default executor
59
+ return {
60
+ model: trimmed,
61
+ };
62
+ });
63
+ }
64
+
65
+ /**
66
+ * Validate that an executor name is valid
67
+ *
68
+ * @param executor - Executor name to validate
69
+ * @returns Type guard confirming executor is valid
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * if (validateExecutor(options.tool)) {
74
+ * // TypeScript knows options.tool is ExecutorTool
75
+ * }
76
+ * ```
77
+ */
78
+ export function validateExecutor(executor: string): executor is ExecutorTool {
79
+ return VALID_EXECUTORS.includes(executor as ExecutorTool);
80
+ }
@@ -0,0 +1,58 @@
1
+ import { isValidAIProvider } from "../lib/validation";
2
+
3
+ // Helper to parse model string ([provider:]model[;reasoning[=budget]])
4
+ export function parseModelString(modelStr: string): {
5
+ provider?: string;
6
+ model: string;
7
+ reasoning?: string;
8
+ } {
9
+ let processingStr = modelStr;
10
+ let reasoning: string | undefined;
11
+
12
+ // 1. Extract reasoning
13
+ // Format: ;reasoning or ;reasoning=1000
14
+ const reasoningMatch = processingStr.match(/;reasoning(?:=(\d+))?$/);
15
+ if (reasoningMatch) {
16
+ // If specific budget provided (group 1), use it.
17
+ // Otherwise default to "2000" as requested.
18
+ reasoning = reasoningMatch[1] ? reasoningMatch[1] : "2000";
19
+
20
+ // Remove the reasoning suffix from the string
21
+ processingStr = processingStr.substring(0, reasoningMatch.index);
22
+ }
23
+
24
+ // 2. Extract provider and model
25
+ // We look for the first colon.
26
+ const firstColonIndex = processingStr.indexOf(":");
27
+
28
+ if (firstColonIndex === -1) {
29
+ // No colon -> It's just a model name (provider inferred from env/defaults later)
30
+ return {
31
+ provider: undefined,
32
+ model: processingStr,
33
+ reasoning,
34
+ };
35
+ }
36
+
37
+ // Has colon. Check if the part before is a valid provider.
38
+ const potentialProvider = processingStr.substring(0, firstColonIndex);
39
+ const potentialModel = processingStr.substring(firstColonIndex + 1);
40
+
41
+ if (isValidAIProvider(potentialProvider)) {
42
+ // It is a known provider
43
+ return {
44
+ provider: potentialProvider,
45
+ model: potentialModel,
46
+ reasoning,
47
+ };
48
+ }
49
+
50
+ // Not a known provider. Treat the whole thing as the model name.
51
+ // This handles cases like "google/gemini...:free" where "google/gemini..." isn't a provider key.
52
+ // Or just "model:with:colons".
53
+ return {
54
+ provider: undefined,
55
+ model: processingStr,
56
+ reasoning,
57
+ };
58
+ }
@@ -0,0 +1,53 @@
1
+ import type { BTSFrontend } from "../types/index.js";
2
+
3
+ export interface StackInfo {
4
+ frontend: BTSFrontend | BTSFrontend[];
5
+ backend: string;
6
+ database: string;
7
+ orm: string;
8
+ auth: string;
9
+ addons: string[];
10
+ }
11
+
12
+ export function formatStackInfo(stack: StackInfo | null | undefined): string {
13
+ if (!stack) {
14
+ return "Not detected";
15
+ }
16
+
17
+ const frontendStr = Array.isArray(stack.frontend)
18
+ ? stack.frontend.join(", ")
19
+ : stack.frontend;
20
+
21
+ const parts = [
22
+ `Frontend: ${frontendStr}`,
23
+ `Backend: ${stack.backend}`
24
+ ];
25
+
26
+ if (stack.database !== 'none') {
27
+ parts.push(`Database: ${stack.database}`);
28
+ }
29
+
30
+ if (stack.orm !== 'none') {
31
+ parts.push(`ORM: ${stack.orm}`);
32
+ }
33
+
34
+ parts.push(`Auth: ${stack.auth}`);
35
+
36
+ if (stack.addons.length > 0) {
37
+ parts.push(`Addons: ${stack.addons.join(", ")}`);
38
+ }
39
+
40
+ return parts.join(", ");
41
+ }
42
+
43
+ export function formatStackForContext(stack: StackInfo | null | undefined): string {
44
+ if (!stack) {
45
+ return "";
46
+ }
47
+
48
+ const frontendStr = Array.isArray(stack.frontend)
49
+ ? stack.frontend.join(" + ")
50
+ : stack.frontend;
51
+
52
+ return `Technology Stack: ${frontendStr} + ${stack.backend} + ${stack.database}`;
53
+ }
@@ -0,0 +1,94 @@
1
+ import { Task } from "../types/index.js";
2
+ import {
3
+ createStandardError,
4
+ formatTaskNotFoundError,
5
+ TaskOMaticErrorCodes,
6
+ } from "./task-o-matic-error";
7
+
8
+ /**
9
+ * Ensures a task is not null, throwing an error if it is.
10
+ * Useful for enforcing null checks after storage operations.
11
+ *
12
+ * @param task - Task that may be null
13
+ * @param taskId - ID of the task for error message
14
+ * @returns The task if not null
15
+ * @throws TaskOMaticError if task is null
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const task = await storage.getTask(taskId);
20
+ * const validTask = requireTask(task, taskId);
21
+ * console.log(validTask.title); // Safe - never null
22
+ * ```
23
+ */
24
+ export function requireTask(task: Task | null, taskId: string): Task {
25
+ if (!task) {
26
+ throw formatTaskNotFoundError(taskId);
27
+ }
28
+ return task;
29
+ }
30
+
31
+ /**
32
+ * Ensures multiple tasks are not null, throwing an error if any is null.
33
+ *
34
+ * @param tasks - Array of tasks that may contain nulls
35
+ * @param context - Context for error message (e.g., "subtasks", "dependencies")
36
+ * @returns Array of tasks with nulls filtered out
37
+ * @throws TaskOMaticError if any task is null
38
+ */
39
+ export function requireTasks(
40
+ tasks: (Task | null)[],
41
+ context: string = "tasks"
42
+ ): Task[] {
43
+ const validTasks: Task[] = [];
44
+ const missingIds: string[] = [];
45
+
46
+ tasks.forEach((task, index) => {
47
+ if (!task) {
48
+ missingIds.push(`index ${index}`);
49
+ } else {
50
+ validTasks.push(task);
51
+ }
52
+ });
53
+
54
+ if (missingIds.length > 0) {
55
+ throw createStandardError(
56
+ TaskOMaticErrorCodes.STORAGE_INTEGRITY_ERROR,
57
+ `Missing ${context}: ${missingIds.join(", ")}`
58
+ );
59
+ }
60
+
61
+ return validTasks;
62
+ }
63
+
64
+ /**
65
+ * Filters out null tasks from an array, with type narrowing.
66
+ *
67
+ * @param tasks - Array of tasks that may contain nulls
68
+ * @returns Array of tasks with nulls removed
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const tasks = await Promise.all(ids.map(id => storage.getTask(id)));
73
+ * const validTasks = filterNullTasks(tasks);
74
+ * // validTasks has type Task[] (no null)
75
+ * ```
76
+ */
77
+ export function filterNullTasks(tasks: (Task | null)[]): Task[] {
78
+ return tasks.filter((task): task is Task => task !== null);
79
+ }
80
+
81
+ /**
82
+ * Validates that a task ID is a non-empty string.
83
+ *
84
+ * @param taskId - Task ID to validate
85
+ * @throws TaskOMaticError if task ID is invalid
86
+ */
87
+ export function validateTaskId(taskId: string): void {
88
+ if (!taskId || typeof taskId !== "string" || !taskId.trim()) {
89
+ throw createStandardError(
90
+ TaskOMaticErrorCodes.INVALID_INPUT,
91
+ "Invalid task ID: must be a non-empty string"
92
+ );
93
+ }
94
+ }