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,77 @@
1
+ import assert from "node:assert";
2
+ import { hooks } from "../lib/hooks";
3
+ import { Task } from "../types";
4
+
5
+ describe("HookRegistry", () => {
6
+ beforeEach(() => {
7
+ hooks.clear();
8
+ });
9
+
10
+ it("should register and call a listener", async () => {
11
+ let called = false;
12
+ const task = { id: "1", title: "Test Task" } as Task;
13
+
14
+ hooks.on("task:created", (payload) => {
15
+ assert.strictEqual(payload.task, task);
16
+ called = true;
17
+ });
18
+
19
+ await hooks.emit("task:created", { task });
20
+ assert.strictEqual(called, true);
21
+ });
22
+
23
+ it("should handle multiple listeners", async () => {
24
+ let count = 0;
25
+ const task = { id: "1", title: "Test Task" } as Task;
26
+
27
+ hooks.on("task:created", () => {
28
+ count++;
29
+ });
30
+ hooks.on("task:created", () => {
31
+ count++;
32
+ });
33
+
34
+ await hooks.emit("task:created", { task });
35
+ assert.strictEqual(count, 2);
36
+ });
37
+
38
+ it("should remove a listener", async () => {
39
+ let count = 0;
40
+ const handler = () => {
41
+ count++;
42
+ };
43
+ const task = { id: "1", title: "Test Task" } as Task;
44
+
45
+ hooks.on("task:created", handler);
46
+ hooks.off("task:created", handler);
47
+
48
+ await hooks.emit("task:created", { task });
49
+ assert.strictEqual(count, 0);
50
+ });
51
+
52
+ it("should not fail if a listener throws", async () => {
53
+ const task = { id: "1", title: "Test Task" } as Task;
54
+
55
+ // Suppress console.error for this test
56
+ const originalConsoleError = console.error;
57
+ console.error = () => {};
58
+
59
+ try {
60
+ hooks.on("task:created", () => {
61
+ throw new Error("Oops");
62
+ });
63
+
64
+ let secondCalled = false;
65
+ hooks.on("task:created", () => {
66
+ secondCalled = true;
67
+ });
68
+
69
+ // Should not throw
70
+ await hooks.emit("task:created", { task });
71
+ assert.strictEqual(secondCalled, true);
72
+ } finally {
73
+ // Restore console.error
74
+ console.error = originalConsoleError;
75
+ }
76
+ });
77
+ });
@@ -0,0 +1,39 @@
1
+ import { FileSystemStorage } from "../../lib/storage/file-system";
2
+ import { StorageCallbacks } from "../../lib/storage/storage-callbacks";
3
+ import * as assert from "assert";
4
+
5
+ describe("Callback Integration", () => {
6
+ it("should use custom storage callbacks", async () => {
7
+ const memoryStore = new Map<string, string>();
8
+
9
+ const callbacks: StorageCallbacks = {
10
+ read: async (key) => memoryStore.get(key) || null,
11
+ write: async (key, value) => {
12
+ memoryStore.set(key, value);
13
+ },
14
+ delete: async (key) => {
15
+ memoryStore.delete(key);
16
+ },
17
+ list: async (prefix) =>
18
+ Array.from(memoryStore.keys()).filter((k) =>
19
+ k.startsWith(prefix || "")
20
+ ),
21
+ exists: async (key) => memoryStore.has(key),
22
+ };
23
+
24
+ const storage = new FileSystemStorage(callbacks);
25
+
26
+ // Create task
27
+ const task = await storage.createTask({ title: "Test Task" });
28
+
29
+ // Verify it was written to memory store
30
+ assert.strictEqual(memoryStore.has("tasks.json"), true);
31
+ const data = JSON.parse(memoryStore.get("tasks.json")!);
32
+ assert.strictEqual(data.tasks.length, 1);
33
+ assert.strictEqual(data.tasks[0].title, "Test Task");
34
+
35
+ // Verify retrieval
36
+ const retrieved = await storage.getTask(task.id);
37
+ assert.strictEqual(retrieved?.id, task.id);
38
+ });
39
+ });
@@ -0,0 +1,430 @@
1
+ import * as assert from "assert";
2
+ import { TaskOperations } from "../../../lib/ai-service/task-operations";
3
+ import { Task } from "../../../types";
4
+ import { TaskOMaticError } from "../../../utils/task-o-matic-error";
5
+
6
+ /**
7
+ * ⚠️ CRITICAL: These integration tests use 100% MOCKS - ZERO real AI calls
8
+ * No API calls are made, no costs incurred, tests run fast
9
+ *
10
+ * These tests verify that TaskOperations properly integrates with AIOperationUtility
11
+ * and that errors propagate correctly through the stack.
12
+ */
13
+ describe("TaskOperations Integration Tests", () => {
14
+ let taskOps: TaskOperations;
15
+ let mockAIOperationUtility: any;
16
+
17
+ beforeEach(() => {
18
+ taskOps = new TaskOperations();
19
+
20
+ // Create mock AIOperationUtility - NO REAL AI CALLS
21
+ mockAIOperationUtility = {
22
+ executeAIOperation: async (
23
+ operationName: string,
24
+ operation: () => Promise<any>,
25
+ options?: any
26
+ ) => {
27
+ // Execute the operation and return mock metrics
28
+ const result = await operation();
29
+ return {
30
+ result,
31
+ metrics: {
32
+ duration: 100,
33
+ tokenUsage: {
34
+ prompt: 50,
35
+ completion: 25,
36
+ total: 75,
37
+ },
38
+ },
39
+ };
40
+ },
41
+ streamTextWithTools: async (
42
+ systemPrompt: string,
43
+ userMessage: string,
44
+ config?: any,
45
+ streamingOptions?: any,
46
+ tools?: any
47
+ ) => {
48
+ // Return mock JSON response
49
+ return JSON.stringify({
50
+ subtasks: [
51
+ {
52
+ title: "Mock subtask 1",
53
+ description: "Mock description 1",
54
+ effort: "small",
55
+ },
56
+ {
57
+ title: "Mock subtask 2",
58
+ description: "Mock description 2",
59
+ effort: "medium",
60
+ },
61
+ ],
62
+ });
63
+ },
64
+ streamText: async (
65
+ _prompt: string,
66
+ _config: any,
67
+ _systemPrompt: string,
68
+ _userMessage: string,
69
+ _streamingOptions?: any
70
+ ) => {
71
+ return "Mock enhanced content";
72
+ },
73
+ };
74
+
75
+ // Inject mock into TaskOperations
76
+ (taskOps as any).aiOperationUtility = mockAIOperationUtility;
77
+ });
78
+
79
+ describe("breakdownTask Integration", () => {
80
+ it("should successfully break down a task using AIOperationUtility", async () => {
81
+ const mockTask: Task = {
82
+ id: "test-task-1",
83
+ title: "Test Task",
84
+ description: "A task to break down",
85
+ status: "todo",
86
+ createdAt: Date.now(),
87
+ updatedAt: Date.now(),
88
+ };
89
+
90
+ const result = await taskOps.breakdownTask(mockTask);
91
+
92
+ // Verify result structure
93
+ assert.ok(Array.isArray(result));
94
+ assert.strictEqual(result.length, 2);
95
+ assert.strictEqual(result[0].title, "Mock subtask 1");
96
+ assert.strictEqual(result[0].content, "Mock description 1");
97
+ assert.strictEqual(result[0].estimatedEffort, "small");
98
+ });
99
+
100
+ it("should handle filesystem tools when enabled", async () => {
101
+ let toolsPassed = false;
102
+
103
+ // Override streamTextWithTools to capture tools parameter
104
+ mockAIOperationUtility.streamTextWithTools = async (
105
+ _systemPrompt: string,
106
+ _userMessage: string,
107
+ _config: any,
108
+ _streamingOptions: any,
109
+ tools: any
110
+ ) => {
111
+ if (tools && Object.keys(tools).length > 0) {
112
+ toolsPassed = true;
113
+ }
114
+ return JSON.stringify({
115
+ subtasks: [
116
+ {
117
+ title: "Subtask with tools",
118
+ description: "Used filesystem tools",
119
+ effort: "small",
120
+ },
121
+ ],
122
+ });
123
+ };
124
+
125
+ const mockTask: Task = {
126
+ id: "test-task-2",
127
+ title: "Task with tools",
128
+ status: "todo",
129
+ createdAt: Date.now(),
130
+ updatedAt: Date.now(),
131
+ };
132
+
133
+ const result = await taskOps.breakdownTask(
134
+ mockTask,
135
+ undefined,
136
+ undefined,
137
+ undefined,
138
+ undefined,
139
+ undefined,
140
+ undefined,
141
+ undefined,
142
+ undefined,
143
+ true // enableFilesystemTools
144
+ );
145
+
146
+ assert.ok(toolsPassed, "Filesystem tools should be passed when enabled");
147
+ assert.strictEqual(result.length, 1);
148
+ });
149
+
150
+ it("should propagate TaskOMaticError from AIOperationUtility", async () => {
151
+ // Mock AIOperationUtility to throw error
152
+ (taskOps as any).aiOperationUtility.executeAIOperation = async () => {
153
+ throw new TaskOMaticError("AI operation failed: Task breakdown", {
154
+ code: "AI_OPERATION_FAILED",
155
+ context: "Mock error context",
156
+ suggestions: ["Check AI configuration"],
157
+ });
158
+ };
159
+
160
+ const mockTask: Task = {
161
+ id: "test-task-error",
162
+ title: "Task that will fail",
163
+ status: "todo",
164
+ createdAt: Date.now(),
165
+ updatedAt: Date.now(),
166
+ };
167
+
168
+ try {
169
+ await taskOps.breakdownTask(mockTask);
170
+ assert.fail("Should have thrown TaskOMaticError");
171
+ } catch (error) {
172
+ assert.ok(error instanceof TaskOMaticError);
173
+ assert.strictEqual(
174
+ (error as TaskOMaticError).code,
175
+ "AI_OPERATION_FAILED"
176
+ );
177
+ assert.ok(
178
+ (error as TaskOMaticError).message.includes("Task breakdown")
179
+ );
180
+ }
181
+ });
182
+ });
183
+
184
+ describe("enhanceTask Integration", () => {
185
+ it("should successfully enhance a task using AIOperationUtility", async () => {
186
+ const result = await taskOps.enhanceTask(
187
+ "Test Task",
188
+ "Basic description"
189
+ );
190
+
191
+ // Verify result
192
+ assert.strictEqual(typeof result, "string");
193
+ assert.strictEqual(result, "Mock enhanced content");
194
+ });
195
+
196
+ it("should propagate errors from AIOperationUtility", async () => {
197
+ // Mock AIOperationUtility to throw error
198
+ (taskOps as any).aiOperationUtility.executeAIOperation = async () => {
199
+ throw new TaskOMaticError("AI operation failed: Task enhancement", {
200
+ code: "AI_OPERATION_FAILED",
201
+ context: "Enhancement failed",
202
+ suggestions: ["Retry with different parameters"],
203
+ });
204
+ };
205
+
206
+ try {
207
+ await taskOps.enhanceTask("Test", "Description");
208
+ assert.fail("Should have thrown TaskOMaticError");
209
+ } catch (error) {
210
+ assert.ok(error instanceof TaskOMaticError);
211
+ assert.ok(
212
+ (error as TaskOMaticError).message.includes("Task enhancement")
213
+ );
214
+ }
215
+ });
216
+ });
217
+
218
+ describe("planTask Integration", () => {
219
+ it("should successfully plan a task using AIOperationUtility", async () => {
220
+ // Mock streamTextWithTools to return plan
221
+ mockAIOperationUtility.streamTextWithTools = async () => {
222
+ return "Mock implementation plan:\n1. Step 1\n2. Step 2\n3. Step 3";
223
+ };
224
+
225
+ const result = await taskOps.planTask("Project context", "Task details");
226
+
227
+ // Verify result
228
+ assert.strictEqual(typeof result, "string");
229
+ assert.ok(result.includes("Mock implementation plan"));
230
+ assert.ok(result.includes("Step 1"));
231
+ });
232
+
233
+ it("should handle MCP tools and filesystem tools", async () => {
234
+ let toolsReceived = false;
235
+
236
+ mockAIOperationUtility.streamTextWithTools = async (
237
+ _systemPrompt: string,
238
+ _userMessage: string,
239
+ _config: any,
240
+ _streamingOptions: any,
241
+ tools: any
242
+ ) => {
243
+ if (tools && Object.keys(tools).length > 0) {
244
+ toolsReceived = true;
245
+ }
246
+ return "Plan with tools";
247
+ };
248
+
249
+ // Mock Context7Client to return MCP tools
250
+ const mockContext7Client = {
251
+ getMCPTools: async () => ({
252
+ mockTool: {
253
+ description: "Mock MCP tool",
254
+ parameters: {},
255
+ execute: async () => ({}),
256
+ },
257
+ }),
258
+ saveContext7Documentation: () => {},
259
+ };
260
+
261
+ (taskOps as any).context7Client = mockContext7Client;
262
+
263
+ const result = await taskOps.planTask("Context", "Details");
264
+
265
+ assert.ok(toolsReceived, "Tools should be passed to streamTextWithTools");
266
+ assert.strictEqual(result, "Plan with tools");
267
+ });
268
+
269
+ it("should propagate errors from AIOperationUtility", async () => {
270
+ // Mock AIOperationUtility to throw error
271
+ (taskOps as any).aiOperationUtility.executeAIOperation = async () => {
272
+ throw new TaskOMaticError("AI operation failed: Task planning", {
273
+ code: "AI_OPERATION_FAILED",
274
+ context: "Planning failed",
275
+ suggestions: ["Check task context"],
276
+ });
277
+ };
278
+
279
+ try {
280
+ await taskOps.planTask("Context", "Details");
281
+ assert.fail("Should have thrown TaskOMaticError");
282
+ } catch (error) {
283
+ assert.ok(error instanceof TaskOMaticError);
284
+ assert.ok((error as TaskOMaticError).message.includes("Task planning"));
285
+ }
286
+ });
287
+ });
288
+
289
+ describe("Metrics Flow", () => {
290
+ it("should return results from AIOperationUtility without exposing metrics", async () => {
291
+ // breakdownTask returns result.result directly, not the full AIOperationResult
292
+ const mockTask: Task = {
293
+ id: "metrics-test",
294
+ title: "Metrics test task",
295
+ status: "todo",
296
+ createdAt: Date.now(),
297
+ updatedAt: Date.now(),
298
+ };
299
+
300
+ const result = await taskOps.breakdownTask(mockTask);
301
+
302
+ // Verify we got the result, not the AIOperationResult wrapper
303
+ assert.ok(Array.isArray(result));
304
+ assert.ok(!("metrics" in result), "Should not expose metrics in result");
305
+ assert.ok(
306
+ !("result" in result),
307
+ "Should not expose AIOperationResult structure"
308
+ );
309
+ });
310
+ });
311
+
312
+ describe("Error Handling Integration", () => {
313
+ it("should wrap string errors in TaskOMaticError", async () => {
314
+ // Mock operation that throws string error
315
+ (taskOps as any).aiOperationUtility.executeAIOperation = async () => {
316
+ const error = new Error("String error was converted");
317
+ throw new TaskOMaticError("AI operation failed: Task breakdown", {
318
+ code: "AI_OPERATION_FAILED",
319
+ cause: error,
320
+ context: JSON.stringify({
321
+ operation: "Task breakdown",
322
+ error: "String error was converted",
323
+ }),
324
+ suggestions: ["Check AI configuration"],
325
+ });
326
+ };
327
+
328
+ const mockTask: Task = {
329
+ id: "string-error-test",
330
+ title: "Test",
331
+ status: "todo",
332
+ createdAt: Date.now(),
333
+ updatedAt: Date.now(),
334
+ };
335
+
336
+ try {
337
+ await taskOps.breakdownTask(mockTask);
338
+ assert.fail("Should have thrown");
339
+ } catch (error) {
340
+ assert.ok(error instanceof TaskOMaticError);
341
+ const taskError = error as TaskOMaticError;
342
+ assert.ok(taskError.cause instanceof Error);
343
+ }
344
+ });
345
+
346
+ it("should preserve error context and suggestions", async () => {
347
+ const mockError = new TaskOMaticError("Original error", {
348
+ code: "TEST_ERROR",
349
+ context: "Original context",
350
+ suggestions: ["Original suggestion 1", "Original suggestion 2"],
351
+ metadata: { testData: "test value" },
352
+ });
353
+
354
+ (taskOps as any).aiOperationUtility.executeAIOperation = async () => {
355
+ throw mockError;
356
+ };
357
+
358
+ const mockTask: Task = {
359
+ id: "context-test",
360
+ title: "Test",
361
+ status: "todo",
362
+ createdAt: Date.now(),
363
+ updatedAt: Date.now(),
364
+ };
365
+
366
+ try {
367
+ await taskOps.breakdownTask(mockTask);
368
+ assert.fail("Should have thrown");
369
+ } catch (error) {
370
+ assert.ok(error instanceof TaskOMaticError);
371
+ const taskError = error as TaskOMaticError;
372
+ assert.strictEqual(taskError.code, "TEST_ERROR");
373
+ assert.ok(taskError.context?.includes("Original context"));
374
+ assert.ok(Array.isArray(taskError.suggestions));
375
+ assert.ok(taskError.metadata?.testData === "test value");
376
+ }
377
+ });
378
+ });
379
+
380
+ describe("Streaming Options Integration", () => {
381
+ it("should pass streaming options through to AIOperationUtility", async () => {
382
+ let onChunkCalled = false;
383
+ let onFinishCalled = false;
384
+
385
+ const streamingOptions = {
386
+ onChunk: (chunk: string) => {
387
+ onChunkCalled = true;
388
+ },
389
+ onFinish: (result: any) => {
390
+ onFinishCalled = true;
391
+ },
392
+ };
393
+
394
+ // Mock to verify streaming options are passed
395
+ let receivedOptions: any;
396
+ (taskOps as any).aiOperationUtility.executeAIOperation = async (
397
+ _operationName: string,
398
+ operation: () => Promise<any>,
399
+ options: any
400
+ ) => {
401
+ receivedOptions = options;
402
+ const result = await operation();
403
+ return {
404
+ result,
405
+ metrics: { duration: 100 },
406
+ };
407
+ };
408
+
409
+ const mockTask: Task = {
410
+ id: "streaming-test",
411
+ title: "Test",
412
+ status: "todo",
413
+ createdAt: Date.now(),
414
+ updatedAt: Date.now(),
415
+ };
416
+
417
+ await taskOps.breakdownTask(
418
+ mockTask,
419
+ undefined,
420
+ undefined,
421
+ undefined,
422
+ streamingOptions
423
+ );
424
+
425
+ // Verify streaming options were passed
426
+ assert.ok(receivedOptions);
427
+ assert.ok(receivedOptions.streamingOptions);
428
+ });
429
+ });
430
+ });
@@ -0,0 +1,150 @@
1
+ import assert from "assert";
2
+ import { ConfigManager, Config, ConfigCallbacks } from "../../lib/config";
3
+ import { TaskOMaticErrorCodes } from "../../utils/task-o-matic-error";
4
+
5
+ describe("ConfigManager", () => {
6
+ let mockCallbacks: ConfigCallbacks;
7
+ let mockStorage: Record<string, string>;
8
+ let mockEnv: Record<string, string>;
9
+
10
+ beforeEach(() => {
11
+ mockStorage = {};
12
+ mockEnv = {};
13
+ mockCallbacks = {
14
+ read: async (key: string) => mockStorage[key] || null,
15
+ write: async (key: string, value: string) => {
16
+ mockStorage[key] = value;
17
+ },
18
+ getEnv: (key: string) => mockEnv[key],
19
+ };
20
+ });
21
+
22
+ it("should load default configuration when no config file exists", async () => {
23
+ const configManager = new ConfigManager(mockCallbacks);
24
+ const config = await configManager.load();
25
+
26
+ assert.strictEqual(config.ai.provider, "openrouter"); // Default
27
+ assert.strictEqual(config.ai.model, "z-ai/glm-4.6"); // Default
28
+ });
29
+
30
+ it("should load configuration from file", async () => {
31
+ const storedConfig: Config = {
32
+ ai: {
33
+ provider: "openai",
34
+ model: "gpt-4",
35
+ apiKey: "sk-test",
36
+ maxTokens: 1000,
37
+ temperature: 0.1,
38
+ },
39
+ };
40
+ mockStorage["config.json"] = JSON.stringify(storedConfig);
41
+
42
+ const configManager = new ConfigManager(mockCallbacks);
43
+ const config = await configManager.load();
44
+
45
+ assert.strictEqual(config.ai.provider, "openai");
46
+ assert.strictEqual(config.ai.model, "gpt-4");
47
+ assert.strictEqual(config.ai.apiKey, "sk-test");
48
+ });
49
+
50
+ it("should override config with environment variables", async () => {
51
+ const storedConfig: Config = {
52
+ ai: {
53
+ provider: "openai",
54
+ model: "gpt-4",
55
+ apiKey: "sk-test",
56
+ },
57
+ };
58
+ mockStorage["config.json"] = JSON.stringify(storedConfig);
59
+ mockEnv["AI_PROVIDER"] = "anthropic";
60
+ mockEnv["ANTHROPIC_API_KEY"] = "sk-ant-test";
61
+
62
+ // Note: ConfigManager loads defaults based on provider, but file config overrides defaults,
63
+ // and env config overrides file config?
64
+ // Let's check implementation:
65
+ // ... fileConfig ... envConfig
66
+ // ai: { ...defaultConfig.ai, ...fileConfig.ai, ...envConfig }
67
+ // So envConfig wins.
68
+
69
+ const configManager = new ConfigManager(mockCallbacks);
70
+ const config = await configManager.load();
71
+
72
+ assert.strictEqual(config.ai.provider, "anthropic");
73
+ assert.strictEqual(config.ai.apiKey, "sk-ant-test");
74
+ });
75
+
76
+ it("should validate configuration", async () => {
77
+ const configManager = new ConfigManager(mockCallbacks);
78
+
79
+ // Invalid provider
80
+ const result1 = configManager.validate({
81
+ ai: { provider: "invalid" as any, model: "test-model" },
82
+ });
83
+ assert.strictEqual(result1.valid, false);
84
+ assert.ok(result1.errors[0].includes("Invalid provider"));
85
+
86
+ // Valid provider
87
+ const result2 = configManager.validate({
88
+ ai: { provider: "openai", model: "gpt-5.2-mini" },
89
+ });
90
+ assert.strictEqual(result2.valid, true);
91
+ });
92
+
93
+ it("should save configuration", async () => {
94
+ const configManager = new ConfigManager(mockCallbacks);
95
+ await configManager.load(); // Load defaults
96
+
97
+ const newConfig: Config = {
98
+ ai: {
99
+ provider: "custom",
100
+ model: "my-model",
101
+ apiKey: "secret",
102
+ },
103
+ };
104
+ configManager.setConfig(newConfig);
105
+ await configManager.save();
106
+
107
+ const saved = JSON.parse(mockStorage["config.json"]);
108
+ assert.strictEqual(saved.ai.provider, "custom");
109
+ assert.strictEqual(saved.ai.model, "my-model");
110
+ });
111
+
112
+ it("should throw error when accessing config before load", () => {
113
+ const configManager = new ConfigManager(mockCallbacks);
114
+ assert.throws(
115
+ () => {
116
+ configManager.getConfig();
117
+ },
118
+ (err: any) => {
119
+ return err.code === TaskOMaticErrorCodes.CONFIGURATION_ERROR;
120
+ }
121
+ );
122
+ });
123
+
124
+ it("should set AI config partially and save", async () => {
125
+ const configManager = new ConfigManager(mockCallbacks);
126
+ await configManager.load();
127
+
128
+ await configManager.setAIConfig({
129
+ temperature: 0.9,
130
+ maxTokens: 500,
131
+ });
132
+
133
+ const saved = JSON.parse(mockStorage["config.json"]);
134
+ assert.strictEqual(saved.ai.temperature, 0.9);
135
+ assert.strictEqual(saved.ai.maxTokens, 500);
136
+ // Should preserve other defaults
137
+ assert.strictEqual(saved.ai.provider, "openrouter");
138
+ });
139
+
140
+ it("should update callbacks when changing working directory", () => {
141
+ const configManager = new ConfigManager();
142
+ const initialDir = configManager.getWorkingDirectory();
143
+
144
+ configManager.setWorkingDirectory("/new/path");
145
+ assert.notStrictEqual(configManager.getWorkingDirectory(), initialDir);
146
+
147
+ // Should reset config
148
+ assert.throws(() => configManager.getConfig());
149
+ });
150
+ });