@pixelbyte-software/pixcode 1.30.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 (336) hide show
  1. package/LICENSE +718 -0
  2. package/README.de.md +248 -0
  3. package/README.ja.md +240 -0
  4. package/README.ko.md +240 -0
  5. package/README.md +285 -0
  6. package/README.ru.md +248 -0
  7. package/README.tr.md +250 -0
  8. package/README.zh-CN.md +240 -0
  9. package/dist/api-docs.html +879 -0
  10. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  11. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  12. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  13. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  14. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  15. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  16. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  17. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  18. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  19. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  20. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  21. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  22. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  23. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  24. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  25. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  26. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  27. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  28. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  29. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  30. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  31. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  32. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  33. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  34. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  35. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  36. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  37. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  38. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  39. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  40. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  41. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  42. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  43. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  44. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  45. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  46. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  47. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  48. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  49. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  50. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  51. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  52. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  53. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  54. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  55. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  56. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  57. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  58. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  59. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  60. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  61. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  62. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  63. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  64. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  65. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  66. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  67. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  68. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  69. package/dist/assets/index-C2c9QNwK.css +32 -0
  70. package/dist/assets/index-DyXDZED-.js +1277 -0
  71. package/dist/assets/vendor-codemirror-NA4v81it.js +41 -0
  72. package/dist/assets/vendor-react-D7WwDXvu.js +59 -0
  73. package/dist/assets/vendor-xterm-CJZjLICi.js +66 -0
  74. package/dist/clear-cache.html +85 -0
  75. package/dist/convert-icons.md +53 -0
  76. package/dist/favicon.png +0 -0
  77. package/dist/favicon.svg +9 -0
  78. package/dist/generate-icons.js +49 -0
  79. package/dist/icons/claude-ai-icon.svg +1 -0
  80. package/dist/icons/codex-white.svg +3 -0
  81. package/dist/icons/codex.svg +3 -0
  82. package/dist/icons/cursor-white.svg +12 -0
  83. package/dist/icons/cursor.svg +1 -0
  84. package/dist/icons/gemini-ai-icon.svg +1 -0
  85. package/dist/icons/icon-128x128.png +0 -0
  86. package/dist/icons/icon-128x128.svg +12 -0
  87. package/dist/icons/icon-144x144.png +0 -0
  88. package/dist/icons/icon-144x144.svg +12 -0
  89. package/dist/icons/icon-152x152.png +0 -0
  90. package/dist/icons/icon-152x152.svg +12 -0
  91. package/dist/icons/icon-192x192.png +0 -0
  92. package/dist/icons/icon-192x192.svg +12 -0
  93. package/dist/icons/icon-384x384.png +0 -0
  94. package/dist/icons/icon-384x384.svg +12 -0
  95. package/dist/icons/icon-512x512.png +0 -0
  96. package/dist/icons/icon-512x512.svg +12 -0
  97. package/dist/icons/icon-72x72.png +0 -0
  98. package/dist/icons/icon-72x72.svg +12 -0
  99. package/dist/icons/icon-96x96.png +0 -0
  100. package/dist/icons/icon-96x96.svg +12 -0
  101. package/dist/icons/icon-template.svg +12 -0
  102. package/dist/index.html +52 -0
  103. package/dist/logo-128.png +0 -0
  104. package/dist/logo-256.png +0 -0
  105. package/dist/logo-32.png +0 -0
  106. package/dist/logo-512.png +0 -0
  107. package/dist/logo-64.png +0 -0
  108. package/dist/logo.svg +17 -0
  109. package/dist/manifest.json +61 -0
  110. package/dist/screenshots/cli-selection.png +0 -0
  111. package/dist/screenshots/desktop-main.png +0 -0
  112. package/dist/screenshots/mobile-chat.png +0 -0
  113. package/dist/screenshots/tools-modal.png +0 -0
  114. package/dist/sw.js +124 -0
  115. package/dist-server/server/claude-sdk.js +709 -0
  116. package/dist-server/server/claude-sdk.js.map +1 -0
  117. package/dist-server/server/cli.js +854 -0
  118. package/dist-server/server/cli.js.map +1 -0
  119. package/dist-server/server/constants/config.js +6 -0
  120. package/dist-server/server/constants/config.js.map +1 -0
  121. package/dist-server/server/cursor-cli.js +277 -0
  122. package/dist-server/server/cursor-cli.js.map +1 -0
  123. package/dist-server/server/daemon/manager.js +486 -0
  124. package/dist-server/server/daemon/manager.js.map +1 -0
  125. package/dist-server/server/daemon-manager.js +823 -0
  126. package/dist-server/server/daemon-manager.js.map +1 -0
  127. package/dist-server/server/database/db.js +535 -0
  128. package/dist-server/server/database/db.js.map +1 -0
  129. package/dist-server/server/database/schema.js +97 -0
  130. package/dist-server/server/database/schema.js.map +1 -0
  131. package/dist-server/server/gemini-cli.js +408 -0
  132. package/dist-server/server/gemini-cli.js.map +1 -0
  133. package/dist-server/server/gemini-response-handler.js +72 -0
  134. package/dist-server/server/gemini-response-handler.js.map +1 -0
  135. package/dist-server/server/index.js +2325 -0
  136. package/dist-server/server/index.js.map +1 -0
  137. package/dist-server/server/load-env.js +32 -0
  138. package/dist-server/server/load-env.js.map +1 -0
  139. package/dist-server/server/middleware/auth.js +111 -0
  140. package/dist-server/server/middleware/auth.js.map +1 -0
  141. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +103 -0
  142. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
  143. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
  144. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
  145. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +266 -0
  146. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
  147. package/dist-server/server/modules/providers/list/claude/claude.provider.js +13 -0
  148. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
  149. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
  150. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
  151. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
  152. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
  153. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +282 -0
  154. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
  155. package/dist-server/server/modules/providers/list/codex/codex.provider.js +13 -0
  156. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
  157. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
  158. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
  159. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
  160. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
  161. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +369 -0
  162. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
  163. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +13 -0
  164. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
  165. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +131 -0
  166. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -0
  167. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +82 -0
  168. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +1 -0
  169. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +207 -0
  170. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -0
  171. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +13 -0
  172. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -0
  173. package/dist-server/server/modules/providers/provider.registry.js +31 -0
  174. package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
  175. package/dist-server/server/modules/providers/provider.routes.js +159 -0
  176. package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
  177. package/dist-server/server/modules/providers/services/mcp.service.js +69 -0
  178. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
  179. package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
  180. package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
  181. package/dist-server/server/modules/providers/services/sessions.service.js +29 -0
  182. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
  183. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +14 -0
  184. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
  185. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
  186. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
  187. package/dist-server/server/modules/providers/tests/mcp.test.js +250 -0
  188. package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
  189. package/dist-server/server/openai-codex.js +373 -0
  190. package/dist-server/server/openai-codex.js.map +1 -0
  191. package/dist-server/server/projects.js +2492 -0
  192. package/dist-server/server/projects.js.map +1 -0
  193. package/dist-server/server/routes/agent.js +1147 -0
  194. package/dist-server/server/routes/agent.js.map +1 -0
  195. package/dist-server/server/routes/auth.js +117 -0
  196. package/dist-server/server/routes/auth.js.map +1 -0
  197. package/dist-server/server/routes/cli-auth.js +25 -0
  198. package/dist-server/server/routes/cli-auth.js.map +1 -0
  199. package/dist-server/server/routes/codex.js +18 -0
  200. package/dist-server/server/routes/codex.js.map +1 -0
  201. package/dist-server/server/routes/commands.js +487 -0
  202. package/dist-server/server/routes/commands.js.map +1 -0
  203. package/dist-server/server/routes/cursor.js +49 -0
  204. package/dist-server/server/routes/cursor.js.map +1 -0
  205. package/dist-server/server/routes/gemini.js +21 -0
  206. package/dist-server/server/routes/gemini.js.map +1 -0
  207. package/dist-server/server/routes/git.js +1259 -0
  208. package/dist-server/server/routes/git.js.map +1 -0
  209. package/dist-server/server/routes/mcp-utils.js +29 -0
  210. package/dist-server/server/routes/mcp-utils.js.map +1 -0
  211. package/dist-server/server/routes/messages.js +56 -0
  212. package/dist-server/server/routes/messages.js.map +1 -0
  213. package/dist-server/server/routes/plugins.js +266 -0
  214. package/dist-server/server/routes/plugins.js.map +1 -0
  215. package/dist-server/server/routes/projects.js +566 -0
  216. package/dist-server/server/routes/projects.js.map +1 -0
  217. package/dist-server/server/routes/settings.js +259 -0
  218. package/dist-server/server/routes/settings.js.map +1 -0
  219. package/dist-server/server/routes/taskmaster.js +1373 -0
  220. package/dist-server/server/routes/taskmaster.js.map +1 -0
  221. package/dist-server/server/routes/user.js +115 -0
  222. package/dist-server/server/routes/user.js.map +1 -0
  223. package/dist-server/server/services/notification-orchestrator.js +177 -0
  224. package/dist-server/server/services/notification-orchestrator.js.map +1 -0
  225. package/dist-server/server/services/vapid-keys.js +26 -0
  226. package/dist-server/server/services/vapid-keys.js.map +1 -0
  227. package/dist-server/server/sessionManager.js +194 -0
  228. package/dist-server/server/sessionManager.js.map +1 -0
  229. package/dist-server/server/shared/interfaces.js +2 -0
  230. package/dist-server/server/shared/interfaces.js.map +1 -0
  231. package/dist-server/server/shared/types.js +3 -0
  232. package/dist-server/server/shared/types.js.map +1 -0
  233. package/dist-server/server/shared/utils.js +150 -0
  234. package/dist-server/server/shared/utils.js.map +1 -0
  235. package/dist-server/server/utils/colors.js +20 -0
  236. package/dist-server/server/utils/colors.js.map +1 -0
  237. package/dist-server/server/utils/commandParser.js +255 -0
  238. package/dist-server/server/utils/commandParser.js.map +1 -0
  239. package/dist-server/server/utils/frontmatter.js +16 -0
  240. package/dist-server/server/utils/frontmatter.js.map +1 -0
  241. package/dist-server/server/utils/gitConfig.js +36 -0
  242. package/dist-server/server/utils/gitConfig.js.map +1 -0
  243. package/dist-server/server/utils/mcp-detector.js +134 -0
  244. package/dist-server/server/utils/mcp-detector.js.map +1 -0
  245. package/dist-server/server/utils/plugin-loader.js +413 -0
  246. package/dist-server/server/utils/plugin-loader.js.map +1 -0
  247. package/dist-server/server/utils/plugin-process-manager.js +163 -0
  248. package/dist-server/server/utils/plugin-process-manager.js.map +1 -0
  249. package/dist-server/server/utils/runtime-paths.js +30 -0
  250. package/dist-server/server/utils/runtime-paths.js.map +1 -0
  251. package/dist-server/server/utils/taskmaster-websocket.js +118 -0
  252. package/dist-server/server/utils/taskmaster-websocket.js.map +1 -0
  253. package/dist-server/server/utils/url-detection.js +58 -0
  254. package/dist-server/server/utils/url-detection.js.map +1 -0
  255. package/dist-server/server/vite-daemon.js +75 -0
  256. package/dist-server/server/vite-daemon.js.map +1 -0
  257. package/dist-server/shared/modelConstants.js +90 -0
  258. package/dist-server/shared/modelConstants.js.map +1 -0
  259. package/dist-server/shared/networkHosts.js +20 -0
  260. package/dist-server/shared/networkHosts.js.map +1 -0
  261. package/package.json +168 -0
  262. package/scripts/fix-node-pty.js +67 -0
  263. package/server/claude-sdk.js +834 -0
  264. package/server/cli.js +937 -0
  265. package/server/constants/config.js +5 -0
  266. package/server/cursor-cli.js +342 -0
  267. package/server/daemon/manager.js +564 -0
  268. package/server/daemon-manager.js +920 -0
  269. package/server/database/db.js +593 -0
  270. package/server/database/schema.js +102 -0
  271. package/server/gemini-cli.js +469 -0
  272. package/server/gemini-response-handler.js +79 -0
  273. package/server/index.js +2557 -0
  274. package/server/load-env.js +34 -0
  275. package/server/middleware/auth.js +132 -0
  276. package/server/modules/providers/list/claude/claude-auth.provider.ts +123 -0
  277. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
  278. package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -0
  279. package/server/modules/providers/list/claude/claude.provider.ts +15 -0
  280. package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
  281. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
  282. package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -0
  283. package/server/modules/providers/list/codex/codex.provider.ts +15 -0
  284. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
  285. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
  286. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -0
  287. package/server/modules/providers/list/cursor/cursor.provider.ts +15 -0
  288. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +151 -0
  289. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -0
  290. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -0
  291. package/server/modules/providers/list/gemini/gemini.provider.ts +15 -0
  292. package/server/modules/providers/provider.registry.ts +36 -0
  293. package/server/modules/providers/provider.routes.ts +217 -0
  294. package/server/modules/providers/services/mcp.service.ts +94 -0
  295. package/server/modules/providers/services/provider-auth.service.ts +26 -0
  296. package/server/modules/providers/services/sessions.service.ts +45 -0
  297. package/server/modules/providers/shared/base/abstract.provider.ts +20 -0
  298. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
  299. package/server/modules/providers/tests/mcp.test.ts +293 -0
  300. package/server/openai-codex.js +426 -0
  301. package/server/projects.js +2792 -0
  302. package/server/routes/agent.js +1245 -0
  303. package/server/routes/auth.js +135 -0
  304. package/server/routes/cli-auth.js +27 -0
  305. package/server/routes/codex.js +19 -0
  306. package/server/routes/commands.js +554 -0
  307. package/server/routes/cursor.js +52 -0
  308. package/server/routes/gemini.js +24 -0
  309. package/server/routes/git.js +1488 -0
  310. package/server/routes/mcp-utils.js +31 -0
  311. package/server/routes/messages.js +61 -0
  312. package/server/routes/plugins.js +307 -0
  313. package/server/routes/projects.js +627 -0
  314. package/server/routes/settings.js +286 -0
  315. package/server/routes/taskmaster.js +1471 -0
  316. package/server/routes/user.js +123 -0
  317. package/server/services/notification-orchestrator.js +227 -0
  318. package/server/services/vapid-keys.js +35 -0
  319. package/server/sessionManager.js +226 -0
  320. package/server/shared/interfaces.ts +54 -0
  321. package/server/shared/types.ts +172 -0
  322. package/server/shared/utils.ts +193 -0
  323. package/server/tsconfig.json +36 -0
  324. package/server/utils/colors.js +21 -0
  325. package/server/utils/commandParser.js +303 -0
  326. package/server/utils/frontmatter.js +18 -0
  327. package/server/utils/gitConfig.js +34 -0
  328. package/server/utils/mcp-detector.js +147 -0
  329. package/server/utils/plugin-loader.js +457 -0
  330. package/server/utils/plugin-process-manager.js +184 -0
  331. package/server/utils/runtime-paths.js +37 -0
  332. package/server/utils/taskmaster-websocket.js +129 -0
  333. package/server/utils/url-detection.js +71 -0
  334. package/server/vite-daemon.js +78 -0
  335. package/shared/modelConstants.js +97 -0
  336. package/shared/networkHosts.js +22 -0
@@ -0,0 +1,1373 @@
1
+ /**
2
+ * TASKMASTER API ROUTES
3
+ * ====================
4
+ *
5
+ * This module provides API endpoints for TaskMaster integration including:
6
+ * - .taskmaster folder detection in project directories
7
+ * - MCP server configuration detection
8
+ * - TaskMaster state and metadata management
9
+ */
10
+ import express from 'express';
11
+ import fs from 'fs';
12
+ import path from 'path';
13
+ import { promises as fsPromises } from 'fs';
14
+ import { spawn } from 'child_process';
15
+ import { extractProjectDirectory } from '../projects.js';
16
+ import { detectTaskMasterMCPServer } from '../utils/mcp-detector.js';
17
+ import { broadcastTaskMasterProjectUpdate, broadcastTaskMasterTasksUpdate } from '../utils/taskmaster-websocket.js';
18
+ const router = express.Router();
19
+ /**
20
+ * Check if TaskMaster CLI is installed globally
21
+ * @returns {Promise<Object>} Installation status result
22
+ */
23
+ async function checkTaskMasterInstallation() {
24
+ return new Promise((resolve) => {
25
+ // Check if task-master command is available
26
+ const child = spawn('which', ['task-master'], {
27
+ stdio: ['ignore', 'pipe', 'pipe'],
28
+ shell: true
29
+ });
30
+ let output = '';
31
+ let errorOutput = '';
32
+ child.stdout.on('data', (data) => {
33
+ output += data.toString();
34
+ });
35
+ child.stderr.on('data', (data) => {
36
+ errorOutput += data.toString();
37
+ });
38
+ child.on('close', (code) => {
39
+ if (code === 0 && output.trim()) {
40
+ // TaskMaster is installed, get version
41
+ const versionChild = spawn('task-master', ['--version'], {
42
+ stdio: ['ignore', 'pipe', 'pipe'],
43
+ shell: true
44
+ });
45
+ let versionOutput = '';
46
+ versionChild.stdout.on('data', (data) => {
47
+ versionOutput += data.toString();
48
+ });
49
+ versionChild.on('close', (versionCode) => {
50
+ resolve({
51
+ isInstalled: true,
52
+ installPath: output.trim(),
53
+ version: versionCode === 0 ? versionOutput.trim() : 'unknown',
54
+ reason: null
55
+ });
56
+ });
57
+ versionChild.on('error', () => {
58
+ resolve({
59
+ isInstalled: true,
60
+ installPath: output.trim(),
61
+ version: 'unknown',
62
+ reason: null
63
+ });
64
+ });
65
+ }
66
+ else {
67
+ resolve({
68
+ isInstalled: false,
69
+ installPath: null,
70
+ version: null,
71
+ reason: 'TaskMaster CLI not found in PATH'
72
+ });
73
+ }
74
+ });
75
+ child.on('error', (error) => {
76
+ resolve({
77
+ isInstalled: false,
78
+ installPath: null,
79
+ version: null,
80
+ reason: `Error checking installation: ${error.message}`
81
+ });
82
+ });
83
+ });
84
+ }
85
+ // API Routes
86
+ /**
87
+ * GET /api/taskmaster/installation-status
88
+ * Check if TaskMaster CLI is installed on the system
89
+ */
90
+ router.get('/installation-status', async (req, res) => {
91
+ try {
92
+ const installationStatus = await checkTaskMasterInstallation();
93
+ // Also check for MCP server configuration
94
+ const mcpStatus = await detectTaskMasterMCPServer();
95
+ res.json({
96
+ success: true,
97
+ installation: installationStatus,
98
+ mcpServer: mcpStatus,
99
+ isReady: installationStatus.isInstalled && mcpStatus.hasMCPServer
100
+ });
101
+ }
102
+ catch (error) {
103
+ console.error('Error checking TaskMaster installation:', error);
104
+ res.status(500).json({
105
+ success: false,
106
+ error: 'Failed to check TaskMaster installation status',
107
+ installation: {
108
+ isInstalled: false,
109
+ reason: `Server error: ${error.message}`
110
+ },
111
+ mcpServer: {
112
+ hasMCPServer: false,
113
+ reason: `Server error: ${error.message}`
114
+ },
115
+ isReady: false
116
+ });
117
+ }
118
+ });
119
+ /**
120
+ * GET /api/taskmaster/tasks/:projectName
121
+ * Load actual tasks from .taskmaster/tasks/tasks.json
122
+ */
123
+ router.get('/tasks/:projectName', async (req, res) => {
124
+ try {
125
+ const { projectName } = req.params;
126
+ // Get project path
127
+ let projectPath;
128
+ try {
129
+ projectPath = await extractProjectDirectory(projectName);
130
+ }
131
+ catch (error) {
132
+ return res.status(404).json({
133
+ error: 'Project not found',
134
+ message: `Project "${projectName}" does not exist`
135
+ });
136
+ }
137
+ const taskMasterPath = path.join(projectPath, '.taskmaster');
138
+ const tasksFilePath = path.join(taskMasterPath, 'tasks', 'tasks.json');
139
+ // Check if tasks file exists
140
+ try {
141
+ await fsPromises.access(tasksFilePath);
142
+ }
143
+ catch (error) {
144
+ return res.json({
145
+ projectName,
146
+ tasks: [],
147
+ message: 'No tasks.json file found'
148
+ });
149
+ }
150
+ // Read and parse tasks file
151
+ try {
152
+ const tasksContent = await fsPromises.readFile(tasksFilePath, 'utf8');
153
+ const tasksData = JSON.parse(tasksContent);
154
+ let tasks = [];
155
+ let currentTag = 'master';
156
+ // Handle both tagged and legacy formats
157
+ if (Array.isArray(tasksData)) {
158
+ // Legacy format
159
+ tasks = tasksData;
160
+ }
161
+ else if (tasksData.tasks) {
162
+ // Simple format with tasks array
163
+ tasks = tasksData.tasks;
164
+ }
165
+ else {
166
+ // Tagged format - get tasks from current tag or master
167
+ if (tasksData[currentTag] && tasksData[currentTag].tasks) {
168
+ tasks = tasksData[currentTag].tasks;
169
+ }
170
+ else if (tasksData.master && tasksData.master.tasks) {
171
+ tasks = tasksData.master.tasks;
172
+ }
173
+ else {
174
+ // Get tasks from first available tag
175
+ const firstTag = Object.keys(tasksData).find(key => tasksData[key].tasks && Array.isArray(tasksData[key].tasks));
176
+ if (firstTag) {
177
+ tasks = tasksData[firstTag].tasks;
178
+ currentTag = firstTag;
179
+ }
180
+ }
181
+ }
182
+ // Transform tasks to ensure all have required fields
183
+ const transformedTasks = tasks.map(task => ({
184
+ id: task.id,
185
+ title: task.title || 'Untitled Task',
186
+ description: task.description || '',
187
+ status: task.status || 'pending',
188
+ priority: task.priority || 'medium',
189
+ dependencies: task.dependencies || [],
190
+ createdAt: task.createdAt || task.created || new Date().toISOString(),
191
+ updatedAt: task.updatedAt || task.updated || new Date().toISOString(),
192
+ details: task.details || '',
193
+ testStrategy: task.testStrategy || task.test_strategy || '',
194
+ subtasks: task.subtasks || []
195
+ }));
196
+ res.json({
197
+ projectName,
198
+ projectPath,
199
+ tasks: transformedTasks,
200
+ currentTag,
201
+ totalTasks: transformedTasks.length,
202
+ tasksByStatus: {
203
+ pending: transformedTasks.filter(t => t.status === 'pending').length,
204
+ 'in-progress': transformedTasks.filter(t => t.status === 'in-progress').length,
205
+ done: transformedTasks.filter(t => t.status === 'done').length,
206
+ review: transformedTasks.filter(t => t.status === 'review').length,
207
+ deferred: transformedTasks.filter(t => t.status === 'deferred').length,
208
+ cancelled: transformedTasks.filter(t => t.status === 'cancelled').length
209
+ },
210
+ timestamp: new Date().toISOString()
211
+ });
212
+ }
213
+ catch (parseError) {
214
+ console.error('Failed to parse tasks.json:', parseError);
215
+ return res.status(500).json({
216
+ error: 'Failed to parse tasks file',
217
+ message: parseError.message
218
+ });
219
+ }
220
+ }
221
+ catch (error) {
222
+ console.error('TaskMaster tasks loading error:', error);
223
+ res.status(500).json({
224
+ error: 'Failed to load TaskMaster tasks',
225
+ message: error.message
226
+ });
227
+ }
228
+ });
229
+ /**
230
+ * GET /api/taskmaster/prd/:projectName
231
+ * List all PRD files in the project's .taskmaster/docs directory
232
+ */
233
+ router.get('/prd/:projectName', async (req, res) => {
234
+ try {
235
+ const { projectName } = req.params;
236
+ // Get project path
237
+ let projectPath;
238
+ try {
239
+ projectPath = await extractProjectDirectory(projectName);
240
+ }
241
+ catch (error) {
242
+ return res.status(404).json({
243
+ error: 'Project not found',
244
+ message: `Project "${projectName}" does not exist`
245
+ });
246
+ }
247
+ const docsPath = path.join(projectPath, '.taskmaster', 'docs');
248
+ // Check if docs directory exists
249
+ try {
250
+ await fsPromises.access(docsPath, fs.constants.R_OK);
251
+ }
252
+ catch (error) {
253
+ return res.json({
254
+ projectName,
255
+ prdFiles: [],
256
+ message: 'No .taskmaster/docs directory found'
257
+ });
258
+ }
259
+ // Read directory and filter for PRD files
260
+ try {
261
+ const files = await fsPromises.readdir(docsPath);
262
+ const prdFiles = [];
263
+ for (const file of files) {
264
+ const filePath = path.join(docsPath, file);
265
+ const stats = await fsPromises.stat(filePath);
266
+ if (stats.isFile() && (file.endsWith('.txt') || file.endsWith('.md'))) {
267
+ prdFiles.push({
268
+ name: file,
269
+ path: path.relative(projectPath, filePath),
270
+ size: stats.size,
271
+ modified: stats.mtime.toISOString(),
272
+ created: stats.birthtime.toISOString()
273
+ });
274
+ }
275
+ }
276
+ res.json({
277
+ projectName,
278
+ projectPath,
279
+ prdFiles: prdFiles.sort((a, b) => new Date(b.modified) - new Date(a.modified)),
280
+ timestamp: new Date().toISOString()
281
+ });
282
+ }
283
+ catch (readError) {
284
+ console.error('Error reading docs directory:', readError);
285
+ return res.status(500).json({
286
+ error: 'Failed to read PRD files',
287
+ message: readError.message
288
+ });
289
+ }
290
+ }
291
+ catch (error) {
292
+ console.error('PRD list error:', error);
293
+ res.status(500).json({
294
+ error: 'Failed to list PRD files',
295
+ message: error.message
296
+ });
297
+ }
298
+ });
299
+ /**
300
+ * POST /api/taskmaster/prd/:projectName
301
+ * Create or update a PRD file in the project's .taskmaster/docs directory
302
+ */
303
+ router.post('/prd/:projectName', async (req, res) => {
304
+ try {
305
+ const { projectName } = req.params;
306
+ const { fileName, content } = req.body;
307
+ if (!fileName || !content) {
308
+ return res.status(400).json({
309
+ error: 'Missing required fields',
310
+ message: 'fileName and content are required'
311
+ });
312
+ }
313
+ // Validate filename
314
+ if (!fileName.match(/^[\w\-. ]+\.(txt|md)$/)) {
315
+ return res.status(400).json({
316
+ error: 'Invalid filename',
317
+ message: 'Filename must end with .txt or .md and contain only alphanumeric characters, spaces, dots, and dashes'
318
+ });
319
+ }
320
+ // Get project path
321
+ let projectPath;
322
+ try {
323
+ projectPath = await extractProjectDirectory(projectName);
324
+ }
325
+ catch (error) {
326
+ return res.status(404).json({
327
+ error: 'Project not found',
328
+ message: `Project "${projectName}" does not exist`
329
+ });
330
+ }
331
+ const docsPath = path.join(projectPath, '.taskmaster', 'docs');
332
+ const filePath = path.join(docsPath, fileName);
333
+ // Ensure docs directory exists
334
+ try {
335
+ await fsPromises.mkdir(docsPath, { recursive: true });
336
+ }
337
+ catch (error) {
338
+ console.error('Failed to create docs directory:', error);
339
+ return res.status(500).json({
340
+ error: 'Failed to create directory',
341
+ message: error.message
342
+ });
343
+ }
344
+ // Write the PRD file
345
+ try {
346
+ await fsPromises.writeFile(filePath, content, 'utf8');
347
+ // Get file stats
348
+ const stats = await fsPromises.stat(filePath);
349
+ res.json({
350
+ projectName,
351
+ projectPath,
352
+ fileName,
353
+ filePath: path.relative(projectPath, filePath),
354
+ size: stats.size,
355
+ created: stats.birthtime.toISOString(),
356
+ modified: stats.mtime.toISOString(),
357
+ message: 'PRD file saved successfully',
358
+ timestamp: new Date().toISOString()
359
+ });
360
+ }
361
+ catch (writeError) {
362
+ console.error('Failed to write PRD file:', writeError);
363
+ return res.status(500).json({
364
+ error: 'Failed to write PRD file',
365
+ message: writeError.message
366
+ });
367
+ }
368
+ }
369
+ catch (error) {
370
+ console.error('PRD create/update error:', error);
371
+ res.status(500).json({
372
+ error: 'Failed to create/update PRD file',
373
+ message: error.message
374
+ });
375
+ }
376
+ });
377
+ /**
378
+ * GET /api/taskmaster/prd/:projectName/:fileName
379
+ * Get content of a specific PRD file
380
+ */
381
+ router.get('/prd/:projectName/:fileName', async (req, res) => {
382
+ try {
383
+ const { projectName, fileName } = req.params;
384
+ // Get project path
385
+ let projectPath;
386
+ try {
387
+ projectPath = await extractProjectDirectory(projectName);
388
+ }
389
+ catch (error) {
390
+ return res.status(404).json({
391
+ error: 'Project not found',
392
+ message: `Project "${projectName}" does not exist`
393
+ });
394
+ }
395
+ const filePath = path.join(projectPath, '.taskmaster', 'docs', fileName);
396
+ // Check if file exists
397
+ try {
398
+ await fsPromises.access(filePath, fs.constants.R_OK);
399
+ }
400
+ catch (error) {
401
+ return res.status(404).json({
402
+ error: 'PRD file not found',
403
+ message: `File "${fileName}" does not exist`
404
+ });
405
+ }
406
+ // Read file content
407
+ try {
408
+ const content = await fsPromises.readFile(filePath, 'utf8');
409
+ const stats = await fsPromises.stat(filePath);
410
+ res.json({
411
+ projectName,
412
+ projectPath,
413
+ fileName,
414
+ filePath: path.relative(projectPath, filePath),
415
+ content,
416
+ size: stats.size,
417
+ created: stats.birthtime.toISOString(),
418
+ modified: stats.mtime.toISOString(),
419
+ timestamp: new Date().toISOString()
420
+ });
421
+ }
422
+ catch (readError) {
423
+ console.error('Failed to read PRD file:', readError);
424
+ return res.status(500).json({
425
+ error: 'Failed to read PRD file',
426
+ message: readError.message
427
+ });
428
+ }
429
+ }
430
+ catch (error) {
431
+ console.error('PRD read error:', error);
432
+ res.status(500).json({
433
+ error: 'Failed to read PRD file',
434
+ message: error.message
435
+ });
436
+ }
437
+ });
438
+ /**
439
+ * POST /api/taskmaster/init/:projectName
440
+ * Initialize TaskMaster in a project
441
+ */
442
+ router.post('/init/:projectName', async (req, res) => {
443
+ try {
444
+ const { projectName } = req.params;
445
+ // Get project path
446
+ let projectPath;
447
+ try {
448
+ projectPath = await extractProjectDirectory(projectName);
449
+ }
450
+ catch (error) {
451
+ return res.status(404).json({
452
+ error: 'Project not found',
453
+ message: `Project "${projectName}" does not exist`
454
+ });
455
+ }
456
+ // Check if TaskMaster is already initialized
457
+ const taskMasterPath = path.join(projectPath, '.taskmaster');
458
+ try {
459
+ await fsPromises.access(taskMasterPath, fs.constants.F_OK);
460
+ return res.status(400).json({
461
+ error: 'TaskMaster already initialized',
462
+ message: 'TaskMaster is already configured for this project'
463
+ });
464
+ }
465
+ catch (error) {
466
+ // Directory doesn't exist, we can proceed
467
+ }
468
+ // Run taskmaster init command
469
+ const initProcess = spawn('npx', ['task-master', 'init'], {
470
+ cwd: projectPath,
471
+ stdio: ['pipe', 'pipe', 'pipe']
472
+ });
473
+ let stdout = '';
474
+ let stderr = '';
475
+ initProcess.stdout.on('data', (data) => {
476
+ stdout += data.toString();
477
+ });
478
+ initProcess.stderr.on('data', (data) => {
479
+ stderr += data.toString();
480
+ });
481
+ initProcess.on('close', (code) => {
482
+ if (code === 0) {
483
+ // Broadcast TaskMaster project update via WebSocket
484
+ if (req.app.locals.wss) {
485
+ broadcastTaskMasterProjectUpdate(req.app.locals.wss, projectName, { hasTaskmaster: true, status: 'initialized' });
486
+ }
487
+ res.json({
488
+ projectName,
489
+ projectPath,
490
+ message: 'TaskMaster initialized successfully',
491
+ output: stdout,
492
+ timestamp: new Date().toISOString()
493
+ });
494
+ }
495
+ else {
496
+ console.error('TaskMaster init failed:', stderr);
497
+ res.status(500).json({
498
+ error: 'Failed to initialize TaskMaster',
499
+ message: stderr || stdout,
500
+ code
501
+ });
502
+ }
503
+ });
504
+ // Send 'yes' responses to automated prompts
505
+ initProcess.stdin.write('yes\n');
506
+ initProcess.stdin.end();
507
+ }
508
+ catch (error) {
509
+ console.error('TaskMaster init error:', error);
510
+ res.status(500).json({
511
+ error: 'Failed to initialize TaskMaster',
512
+ message: error.message
513
+ });
514
+ }
515
+ });
516
+ /**
517
+ * POST /api/taskmaster/add-task/:projectName
518
+ * Add a new task to the project
519
+ */
520
+ router.post('/add-task/:projectName', async (req, res) => {
521
+ try {
522
+ const { projectName } = req.params;
523
+ const { prompt, title, description, priority = 'medium', dependencies } = req.body;
524
+ if (!prompt && (!title || !description)) {
525
+ return res.status(400).json({
526
+ error: 'Missing required parameters',
527
+ message: 'Either "prompt" or both "title" and "description" are required'
528
+ });
529
+ }
530
+ // Get project path
531
+ let projectPath;
532
+ try {
533
+ projectPath = await extractProjectDirectory(projectName);
534
+ }
535
+ catch (error) {
536
+ return res.status(404).json({
537
+ error: 'Project not found',
538
+ message: `Project "${projectName}" does not exist`
539
+ });
540
+ }
541
+ // Build the task-master add-task command
542
+ const args = ['task-master-ai', 'add-task'];
543
+ if (prompt) {
544
+ args.push('--prompt', prompt);
545
+ args.push('--research'); // Use research for AI-generated tasks
546
+ }
547
+ else {
548
+ args.push('--prompt', `Create a task titled "${title}" with description: ${description}`);
549
+ }
550
+ if (priority) {
551
+ args.push('--priority', priority);
552
+ }
553
+ if (dependencies) {
554
+ args.push('--dependencies', dependencies);
555
+ }
556
+ // Run task-master add-task command
557
+ const addTaskProcess = spawn('npx', args, {
558
+ cwd: projectPath,
559
+ stdio: ['pipe', 'pipe', 'pipe']
560
+ });
561
+ let stdout = '';
562
+ let stderr = '';
563
+ addTaskProcess.stdout.on('data', (data) => {
564
+ stdout += data.toString();
565
+ });
566
+ addTaskProcess.stderr.on('data', (data) => {
567
+ stderr += data.toString();
568
+ });
569
+ addTaskProcess.on('close', (code) => {
570
+ console.log('Add task process completed with code:', code);
571
+ console.log('Stdout:', stdout);
572
+ console.log('Stderr:', stderr);
573
+ if (code === 0) {
574
+ // Broadcast task update via WebSocket
575
+ if (req.app.locals.wss) {
576
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
577
+ }
578
+ res.json({
579
+ projectName,
580
+ projectPath,
581
+ message: 'Task added successfully',
582
+ output: stdout,
583
+ timestamp: new Date().toISOString()
584
+ });
585
+ }
586
+ else {
587
+ console.error('Add task failed:', stderr);
588
+ res.status(500).json({
589
+ error: 'Failed to add task',
590
+ message: stderr || stdout,
591
+ code
592
+ });
593
+ }
594
+ });
595
+ addTaskProcess.stdin.end();
596
+ }
597
+ catch (error) {
598
+ console.error('Add task error:', error);
599
+ res.status(500).json({
600
+ error: 'Failed to add task',
601
+ message: error.message
602
+ });
603
+ }
604
+ });
605
+ /**
606
+ * PUT /api/taskmaster/update-task/:projectName/:taskId
607
+ * Update a specific task using TaskMaster CLI
608
+ */
609
+ router.put('/update-task/:projectName/:taskId', async (req, res) => {
610
+ try {
611
+ const { projectName, taskId } = req.params;
612
+ const { title, description, status, priority, details } = req.body;
613
+ // Get project path
614
+ let projectPath;
615
+ try {
616
+ projectPath = await extractProjectDirectory(projectName);
617
+ }
618
+ catch (error) {
619
+ return res.status(404).json({
620
+ error: 'Project not found',
621
+ message: `Project "${projectName}" does not exist`
622
+ });
623
+ }
624
+ // If only updating status, use set-status command
625
+ if (status && Object.keys(req.body).length === 1) {
626
+ const setStatusProcess = spawn('npx', ['task-master-ai', 'set-status', `--id=${taskId}`, `--status=${status}`], {
627
+ cwd: projectPath,
628
+ stdio: ['pipe', 'pipe', 'pipe']
629
+ });
630
+ let stdout = '';
631
+ let stderr = '';
632
+ setStatusProcess.stdout.on('data', (data) => {
633
+ stdout += data.toString();
634
+ });
635
+ setStatusProcess.stderr.on('data', (data) => {
636
+ stderr += data.toString();
637
+ });
638
+ setStatusProcess.on('close', (code) => {
639
+ if (code === 0) {
640
+ // Broadcast task update via WebSocket
641
+ if (req.app.locals.wss) {
642
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
643
+ }
644
+ res.json({
645
+ projectName,
646
+ projectPath,
647
+ taskId,
648
+ message: 'Task status updated successfully',
649
+ output: stdout,
650
+ timestamp: new Date().toISOString()
651
+ });
652
+ }
653
+ else {
654
+ console.error('Set task status failed:', stderr);
655
+ res.status(500).json({
656
+ error: 'Failed to update task status',
657
+ message: stderr || stdout,
658
+ code
659
+ });
660
+ }
661
+ });
662
+ setStatusProcess.stdin.end();
663
+ }
664
+ else {
665
+ // For other updates, use update-task command with a prompt describing the changes
666
+ const updates = [];
667
+ if (title)
668
+ updates.push(`title: "${title}"`);
669
+ if (description)
670
+ updates.push(`description: "${description}"`);
671
+ if (priority)
672
+ updates.push(`priority: "${priority}"`);
673
+ if (details)
674
+ updates.push(`details: "${details}"`);
675
+ const prompt = `Update task with the following changes: ${updates.join(', ')}`;
676
+ const updateProcess = spawn('npx', ['task-master-ai', 'update-task', `--id=${taskId}`, `--prompt=${prompt}`], {
677
+ cwd: projectPath,
678
+ stdio: ['pipe', 'pipe', 'pipe']
679
+ });
680
+ let stdout = '';
681
+ let stderr = '';
682
+ updateProcess.stdout.on('data', (data) => {
683
+ stdout += data.toString();
684
+ });
685
+ updateProcess.stderr.on('data', (data) => {
686
+ stderr += data.toString();
687
+ });
688
+ updateProcess.on('close', (code) => {
689
+ if (code === 0) {
690
+ // Broadcast task update via WebSocket
691
+ if (req.app.locals.wss) {
692
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
693
+ }
694
+ res.json({
695
+ projectName,
696
+ projectPath,
697
+ taskId,
698
+ message: 'Task updated successfully',
699
+ output: stdout,
700
+ timestamp: new Date().toISOString()
701
+ });
702
+ }
703
+ else {
704
+ console.error('Update task failed:', stderr);
705
+ res.status(500).json({
706
+ error: 'Failed to update task',
707
+ message: stderr || stdout,
708
+ code
709
+ });
710
+ }
711
+ });
712
+ updateProcess.stdin.end();
713
+ }
714
+ }
715
+ catch (error) {
716
+ console.error('Update task error:', error);
717
+ res.status(500).json({
718
+ error: 'Failed to update task',
719
+ message: error.message
720
+ });
721
+ }
722
+ });
723
+ /**
724
+ * POST /api/taskmaster/parse-prd/:projectName
725
+ * Parse a PRD file to generate tasks
726
+ */
727
+ router.post('/parse-prd/:projectName', async (req, res) => {
728
+ try {
729
+ const { projectName } = req.params;
730
+ const { fileName = 'prd.txt', numTasks, append = false } = req.body;
731
+ // Get project path
732
+ let projectPath;
733
+ try {
734
+ projectPath = await extractProjectDirectory(projectName);
735
+ }
736
+ catch (error) {
737
+ return res.status(404).json({
738
+ error: 'Project not found',
739
+ message: `Project "${projectName}" does not exist`
740
+ });
741
+ }
742
+ const prdPath = path.join(projectPath, '.taskmaster', 'docs', fileName);
743
+ // Check if PRD file exists
744
+ try {
745
+ await fsPromises.access(prdPath, fs.constants.F_OK);
746
+ }
747
+ catch (error) {
748
+ return res.status(404).json({
749
+ error: 'PRD file not found',
750
+ message: `File "${fileName}" does not exist in .taskmaster/docs/`
751
+ });
752
+ }
753
+ // Build the command args
754
+ const args = ['task-master-ai', 'parse-prd', prdPath];
755
+ if (numTasks) {
756
+ args.push('--num-tasks', numTasks.toString());
757
+ }
758
+ if (append) {
759
+ args.push('--append');
760
+ }
761
+ args.push('--research'); // Use research for better PRD parsing
762
+ // Run task-master parse-prd command
763
+ const parsePRDProcess = spawn('npx', args, {
764
+ cwd: projectPath,
765
+ stdio: ['pipe', 'pipe', 'pipe']
766
+ });
767
+ let stdout = '';
768
+ let stderr = '';
769
+ parsePRDProcess.stdout.on('data', (data) => {
770
+ stdout += data.toString();
771
+ });
772
+ parsePRDProcess.stderr.on('data', (data) => {
773
+ stderr += data.toString();
774
+ });
775
+ parsePRDProcess.on('close', (code) => {
776
+ if (code === 0) {
777
+ // Broadcast task update via WebSocket
778
+ if (req.app.locals.wss) {
779
+ broadcastTaskMasterTasksUpdate(req.app.locals.wss, projectName);
780
+ }
781
+ res.json({
782
+ projectName,
783
+ projectPath,
784
+ prdFile: fileName,
785
+ message: 'PRD parsed and tasks generated successfully',
786
+ output: stdout,
787
+ timestamp: new Date().toISOString()
788
+ });
789
+ }
790
+ else {
791
+ console.error('Parse PRD failed:', stderr);
792
+ res.status(500).json({
793
+ error: 'Failed to parse PRD',
794
+ message: stderr || stdout,
795
+ code
796
+ });
797
+ }
798
+ });
799
+ parsePRDProcess.stdin.end();
800
+ }
801
+ catch (error) {
802
+ console.error('Parse PRD error:', error);
803
+ res.status(500).json({
804
+ error: 'Failed to parse PRD',
805
+ message: error.message
806
+ });
807
+ }
808
+ });
809
+ /**
810
+ * GET /api/taskmaster/prd-templates
811
+ * Get available PRD templates
812
+ */
813
+ router.get('/prd-templates', async (req, res) => {
814
+ try {
815
+ // Return built-in templates
816
+ const templates = [
817
+ {
818
+ id: 'web-app',
819
+ name: 'Web Application',
820
+ description: 'Template for web application projects with frontend and backend components',
821
+ category: 'web',
822
+ content: `# Product Requirements Document - Web Application
823
+
824
+ ## Overview
825
+ **Product Name:** [Your App Name]
826
+ **Version:** 1.0
827
+ **Date:** ${new Date().toISOString().split('T')[0]}
828
+ **Author:** [Your Name]
829
+
830
+ ## Executive Summary
831
+ Brief description of what this web application will do and why it's needed.
832
+
833
+ ## Product Goals
834
+ - Goal 1: [Specific measurable goal]
835
+ - Goal 2: [Specific measurable goal]
836
+ - Goal 3: [Specific measurable goal]
837
+
838
+ ## User Stories
839
+ ### Core Features
840
+ 1. **User Registration & Authentication**
841
+ - As a user, I want to create an account so I can access personalized features
842
+ - As a user, I want to log in securely so my data is protected
843
+ - As a user, I want to reset my password if I forget it
844
+
845
+ 2. **Main Application Features**
846
+ - As a user, I want to [core feature 1] so I can [benefit]
847
+ - As a user, I want to [core feature 2] so I can [benefit]
848
+ - As a user, I want to [core feature 3] so I can [benefit]
849
+
850
+ 3. **User Interface**
851
+ - As a user, I want a responsive design so I can use the app on any device
852
+ - As a user, I want intuitive navigation so I can easily find features
853
+
854
+ ## Technical Requirements
855
+ ### Frontend
856
+ - Framework: React/Vue/Angular or vanilla JavaScript
857
+ - Styling: CSS framework (Tailwind, Bootstrap, etc.)
858
+ - State Management: Redux/Vuex/Context API
859
+ - Build Tools: Webpack/Vite
860
+ - Testing: Jest/Vitest for unit tests
861
+
862
+ ### Backend
863
+ - Runtime: Node.js/Python/Java
864
+ - Database: PostgreSQL/MySQL/MongoDB
865
+ - API: RESTful API or GraphQL
866
+ - Authentication: JWT tokens
867
+ - Testing: Integration and unit tests
868
+
869
+ ### Infrastructure
870
+ - Hosting: Cloud provider (AWS, Azure, GCP)
871
+ - CI/CD: GitHub Actions/GitLab CI
872
+ - Monitoring: Application monitoring tools
873
+ - Security: HTTPS, input validation, rate limiting
874
+
875
+ ## Success Metrics
876
+ - User engagement metrics
877
+ - Performance benchmarks (load time < 2s)
878
+ - Error rates < 1%
879
+ - User satisfaction scores
880
+
881
+ ## Timeline
882
+ - Phase 1: Core functionality (4-6 weeks)
883
+ - Phase 2: Advanced features (2-4 weeks)
884
+ - Phase 3: Polish and launch (2 weeks)
885
+
886
+ ## Constraints & Assumptions
887
+ - Budget constraints
888
+ - Technical limitations
889
+ - Team size and expertise
890
+ - Timeline constraints`
891
+ },
892
+ {
893
+ id: 'api',
894
+ name: 'REST API',
895
+ description: 'Template for REST API development projects',
896
+ category: 'backend',
897
+ content: `# Product Requirements Document - REST API
898
+
899
+ ## Overview
900
+ **API Name:** [Your API Name]
901
+ **Version:** v1.0
902
+ **Date:** ${new Date().toISOString().split('T')[0]}
903
+ **Author:** [Your Name]
904
+
905
+ ## Executive Summary
906
+ Description of the API's purpose, target users, and primary use cases.
907
+
908
+ ## API Goals
909
+ - Goal 1: Provide secure data access
910
+ - Goal 2: Ensure scalable architecture
911
+ - Goal 3: Maintain high availability (99.9% uptime)
912
+
913
+ ## Functional Requirements
914
+ ### Core Endpoints
915
+ 1. **Authentication Endpoints**
916
+ - POST /api/auth/login - User authentication
917
+ - POST /api/auth/logout - User logout
918
+ - POST /api/auth/refresh - Token refresh
919
+ - POST /api/auth/register - User registration
920
+
921
+ 2. **Data Management Endpoints**
922
+ - GET /api/resources - List resources with pagination
923
+ - GET /api/resources/{id} - Get specific resource
924
+ - POST /api/resources - Create new resource
925
+ - PUT /api/resources/{id} - Update existing resource
926
+ - DELETE /api/resources/{id} - Delete resource
927
+
928
+ 3. **Administrative Endpoints**
929
+ - GET /api/admin/users - Manage users (admin only)
930
+ - GET /api/admin/analytics - System analytics
931
+ - POST /api/admin/backup - Trigger system backup
932
+
933
+ ## Technical Requirements
934
+ ### API Design
935
+ - RESTful architecture following OpenAPI 3.0 specification
936
+ - JSON request/response format
937
+ - Consistent error response format
938
+ - API versioning strategy
939
+
940
+ ### Authentication & Security
941
+ - JWT token-based authentication
942
+ - Role-based access control (RBAC)
943
+ - Rate limiting (100 requests/minute per user)
944
+ - Input validation and sanitization
945
+ - HTTPS enforcement
946
+
947
+ ### Database
948
+ - Database type: [PostgreSQL/MongoDB/MySQL]
949
+ - Connection pooling
950
+ - Database migrations
951
+ - Backup and recovery procedures
952
+
953
+ ### Performance Requirements
954
+ - Response time: < 200ms for 95% of requests
955
+ - Throughput: 1000+ requests/second
956
+ - Concurrent users: 10,000+
957
+ - Database query optimization
958
+
959
+ ### Documentation
960
+ - Auto-generated API documentation (Swagger/OpenAPI)
961
+ - Code examples for common use cases
962
+ - SDK development for major languages
963
+ - Postman collection for testing
964
+
965
+ ## Error Handling
966
+ - Standardized error codes and messages
967
+ - Proper HTTP status codes
968
+ - Detailed error logging
969
+ - Graceful degradation strategies
970
+
971
+ ## Testing Strategy
972
+ - Unit tests (80%+ coverage)
973
+ - Integration tests for all endpoints
974
+ - Load testing and performance testing
975
+ - Security testing (OWASP compliance)
976
+
977
+ ## Monitoring & Logging
978
+ - Application performance monitoring
979
+ - Error tracking and alerting
980
+ - Access logs and audit trails
981
+ - Health check endpoints
982
+
983
+ ## Deployment
984
+ - Containerized deployment (Docker)
985
+ - CI/CD pipeline setup
986
+ - Environment management (dev, staging, prod)
987
+ - Blue-green deployment strategy
988
+
989
+ ## Success Metrics
990
+ - API uptime > 99.9%
991
+ - Average response time < 200ms
992
+ - Zero critical security vulnerabilities
993
+ - Developer adoption metrics`
994
+ },
995
+ {
996
+ id: 'mobile-app',
997
+ name: 'Mobile Application',
998
+ description: 'Template for mobile app development projects (iOS/Android)',
999
+ category: 'mobile',
1000
+ content: `# Product Requirements Document - Mobile Application
1001
+
1002
+ ## Overview
1003
+ **App Name:** [Your App Name]
1004
+ **Platform:** iOS / Android / Cross-platform
1005
+ **Version:** 1.0
1006
+ **Date:** ${new Date().toISOString().split('T')[0]}
1007
+ **Author:** [Your Name]
1008
+
1009
+ ## Executive Summary
1010
+ Brief description of the mobile app's purpose, target audience, and key value proposition.
1011
+
1012
+ ## Product Goals
1013
+ - Goal 1: [Specific user engagement goal]
1014
+ - Goal 2: [Specific functionality goal]
1015
+ - Goal 3: [Specific performance goal]
1016
+
1017
+ ## User Stories
1018
+ ### Core Features
1019
+ 1. **Onboarding & Authentication**
1020
+ - As a new user, I want a simple onboarding process
1021
+ - As a user, I want to sign up with email or social media
1022
+ - As a user, I want biometric authentication for security
1023
+
1024
+ 2. **Main App Features**
1025
+ - As a user, I want [core feature 1] accessible from home screen
1026
+ - As a user, I want [core feature 2] to work offline
1027
+ - As a user, I want to sync data across devices
1028
+
1029
+ 3. **User Experience**
1030
+ - As a user, I want intuitive navigation patterns
1031
+ - As a user, I want fast loading times
1032
+ - As a user, I want accessibility features
1033
+
1034
+ ## Technical Requirements
1035
+ ### Mobile Development
1036
+ - **Cross-platform:** React Native / Flutter / Xamarin
1037
+ - **Native:** Swift (iOS) / Kotlin (Android)
1038
+ - **State Management:** Redux / MobX / Provider
1039
+ - **Navigation:** React Navigation / Flutter Navigation
1040
+
1041
+ ### Backend Integration
1042
+ - REST API or GraphQL integration
1043
+ - Real-time features (WebSockets/Push notifications)
1044
+ - Offline data synchronization
1045
+ - Background processing
1046
+
1047
+ ### Device Features
1048
+ - Camera and photo library access
1049
+ - GPS location services
1050
+ - Push notifications
1051
+ - Biometric authentication
1052
+ - Device storage
1053
+
1054
+ ### Performance Requirements
1055
+ - App launch time < 3 seconds
1056
+ - Screen transition animations < 300ms
1057
+ - Memory usage optimization
1058
+ - Battery usage optimization
1059
+
1060
+ ## Platform-Specific Considerations
1061
+ ### iOS Requirements
1062
+ - iOS 13.0+ minimum version
1063
+ - App Store guidelines compliance
1064
+ - iOS design guidelines (Human Interface Guidelines)
1065
+ - TestFlight beta testing
1066
+
1067
+ ### Android Requirements
1068
+ - Android 8.0+ (API level 26) minimum
1069
+ - Google Play Store guidelines
1070
+ - Material Design guidelines
1071
+ - Google Play Console testing
1072
+
1073
+ ## User Interface Design
1074
+ - Responsive design for different screen sizes
1075
+ - Dark mode support
1076
+ - Accessibility compliance (WCAG 2.1)
1077
+ - Consistent design system
1078
+
1079
+ ## Security & Privacy
1080
+ - Secure data storage (Keychain/Keystore)
1081
+ - API communication encryption
1082
+ - Privacy policy compliance (GDPR/CCPA)
1083
+ - App security best practices
1084
+
1085
+ ## Testing Strategy
1086
+ - Unit testing (80%+ coverage)
1087
+ - UI/E2E testing (Detox/Appium)
1088
+ - Device testing on multiple screen sizes
1089
+ - Performance testing
1090
+ - Security testing
1091
+
1092
+ ## App Store Deployment
1093
+ - App store optimization (ASO)
1094
+ - App icons and screenshots
1095
+ - Store listing content
1096
+ - Release management strategy
1097
+
1098
+ ## Analytics & Monitoring
1099
+ - User analytics (Firebase/Analytics)
1100
+ - Crash reporting (Crashlytics/Sentry)
1101
+ - Performance monitoring
1102
+ - User feedback collection
1103
+
1104
+ ## Success Metrics
1105
+ - App store ratings > 4.0
1106
+ - User retention rates
1107
+ - Daily/Monthly active users
1108
+ - App performance metrics
1109
+ - Conversion rates`
1110
+ },
1111
+ {
1112
+ id: 'data-analysis',
1113
+ name: 'Data Analysis Project',
1114
+ description: 'Template for data analysis and visualization projects',
1115
+ category: 'data',
1116
+ content: `# Product Requirements Document - Data Analysis Project
1117
+
1118
+ ## Overview
1119
+ **Project Name:** [Your Analysis Project]
1120
+ **Analysis Type:** [Descriptive/Predictive/Prescriptive]
1121
+ **Date:** ${new Date().toISOString().split('T')[0]}
1122
+ **Author:** [Your Name]
1123
+
1124
+ ## Executive Summary
1125
+ Description of the business problem, data sources, and expected insights.
1126
+
1127
+ ## Project Goals
1128
+ - Goal 1: [Specific business question to answer]
1129
+ - Goal 2: [Specific prediction to make]
1130
+ - Goal 3: [Specific recommendation to provide]
1131
+
1132
+ ## Business Requirements
1133
+ ### Key Questions
1134
+ 1. What patterns exist in the current data?
1135
+ 2. What factors influence [target variable]?
1136
+ 3. What predictions can be made for [future outcome]?
1137
+ 4. What recommendations can improve [business metric]?
1138
+
1139
+ ### Success Criteria
1140
+ - Actionable insights for stakeholders
1141
+ - Statistical significance in findings
1142
+ - Reproducible analysis pipeline
1143
+ - Clear visualization and reporting
1144
+
1145
+ ## Data Requirements
1146
+ ### Data Sources
1147
+ 1. **Primary Data**
1148
+ - Source: [Database/API/Files]
1149
+ - Format: [CSV/JSON/SQL]
1150
+ - Size: [Volume estimate]
1151
+ - Update frequency: [Real-time/Daily/Monthly]
1152
+
1153
+ 2. **External Data**
1154
+ - Third-party APIs
1155
+ - Public datasets
1156
+ - Market research data
1157
+
1158
+ ### Data Quality Requirements
1159
+ - Data completeness (< 5% missing values)
1160
+ - Data accuracy validation
1161
+ - Data consistency checks
1162
+ - Historical data availability
1163
+
1164
+ ## Technical Requirements
1165
+ ### Data Pipeline
1166
+ - Data extraction and ingestion
1167
+ - Data cleaning and preprocessing
1168
+ - Data transformation and feature engineering
1169
+ - Data validation and quality checks
1170
+
1171
+ ### Analysis Tools
1172
+ - **Programming:** Python/R/SQL
1173
+ - **Libraries:** pandas, numpy, scikit-learn, matplotlib
1174
+ - **Visualization:** Tableau, PowerBI, or custom dashboards
1175
+ - **Version Control:** Git for code and DVC for data
1176
+
1177
+ ### Computing Resources
1178
+ - Local development environment
1179
+ - Cloud computing (AWS/GCP/Azure) if needed
1180
+ - Database access and permissions
1181
+ - Storage requirements
1182
+
1183
+ ## Analysis Methodology
1184
+ ### Data Exploration
1185
+ 1. Descriptive statistics and data profiling
1186
+ 2. Data visualization and pattern identification
1187
+ 3. Correlation analysis
1188
+ 4. Outlier detection and handling
1189
+
1190
+ ### Statistical Analysis
1191
+ 1. Hypothesis formulation
1192
+ 2. Statistical testing
1193
+ 3. Confidence intervals
1194
+ 4. Effect size calculations
1195
+
1196
+ ### Machine Learning (if applicable)
1197
+ 1. Feature selection and engineering
1198
+ 2. Model selection and training
1199
+ 3. Cross-validation and evaluation
1200
+ 4. Model interpretation and explainability
1201
+
1202
+ ## Deliverables
1203
+ ### Reports
1204
+ - Executive summary for stakeholders
1205
+ - Technical analysis report
1206
+ - Data quality report
1207
+ - Methodology documentation
1208
+
1209
+ ### Visualizations
1210
+ - Interactive dashboards
1211
+ - Static charts and graphs
1212
+ - Data story presentations
1213
+ - Key findings infographics
1214
+
1215
+ ### Code & Documentation
1216
+ - Reproducible analysis scripts
1217
+ - Data pipeline code
1218
+ - Documentation and comments
1219
+ - Testing and validation code
1220
+
1221
+ ## Timeline
1222
+ - Phase 1: Data collection and exploration (2 weeks)
1223
+ - Phase 2: Analysis and modeling (3 weeks)
1224
+ - Phase 3: Reporting and visualization (1 week)
1225
+ - Phase 4: Stakeholder presentation (1 week)
1226
+
1227
+ ## Risks & Assumptions
1228
+ - Data availability and quality risks
1229
+ - Technical complexity assumptions
1230
+ - Resource and timeline constraints
1231
+ - Stakeholder engagement assumptions
1232
+
1233
+ ## Success Metrics
1234
+ - Stakeholder satisfaction with insights
1235
+ - Accuracy of predictions (if applicable)
1236
+ - Business impact of recommendations
1237
+ - Reproducibility of results`
1238
+ }
1239
+ ];
1240
+ res.json({
1241
+ templates,
1242
+ timestamp: new Date().toISOString()
1243
+ });
1244
+ }
1245
+ catch (error) {
1246
+ console.error('PRD templates error:', error);
1247
+ res.status(500).json({
1248
+ error: 'Failed to get PRD templates',
1249
+ message: error.message
1250
+ });
1251
+ }
1252
+ });
1253
+ /**
1254
+ * POST /api/taskmaster/apply-template/:projectName
1255
+ * Apply a PRD template to create a new PRD file
1256
+ */
1257
+ router.post('/apply-template/:projectName', async (req, res) => {
1258
+ try {
1259
+ const { projectName } = req.params;
1260
+ const { templateId, fileName = 'prd.txt', customizations = {} } = req.body;
1261
+ if (!templateId) {
1262
+ return res.status(400).json({
1263
+ error: 'Missing required parameter',
1264
+ message: 'templateId is required'
1265
+ });
1266
+ }
1267
+ // Get project path
1268
+ let projectPath;
1269
+ try {
1270
+ projectPath = await extractProjectDirectory(projectName);
1271
+ }
1272
+ catch (error) {
1273
+ return res.status(404).json({
1274
+ error: 'Project not found',
1275
+ message: `Project "${projectName}" does not exist`
1276
+ });
1277
+ }
1278
+ // Get the template content (this would normally fetch from the templates list)
1279
+ const templates = await getAvailableTemplates();
1280
+ const template = templates.find(t => t.id === templateId);
1281
+ if (!template) {
1282
+ return res.status(404).json({
1283
+ error: 'Template not found',
1284
+ message: `Template "${templateId}" does not exist`
1285
+ });
1286
+ }
1287
+ // Apply customizations to template content
1288
+ let content = template.content;
1289
+ // Replace placeholders with customizations
1290
+ for (const [key, value] of Object.entries(customizations)) {
1291
+ const placeholder = `[${key}]`;
1292
+ content = content.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'), value);
1293
+ }
1294
+ // Ensure .taskmaster/docs directory exists
1295
+ const docsDir = path.join(projectPath, '.taskmaster', 'docs');
1296
+ try {
1297
+ await fsPromises.mkdir(docsDir, { recursive: true });
1298
+ }
1299
+ catch (error) {
1300
+ console.error('Failed to create docs directory:', error);
1301
+ }
1302
+ const filePath = path.join(docsDir, fileName);
1303
+ // Write the template content to the file
1304
+ try {
1305
+ await fsPromises.writeFile(filePath, content, 'utf8');
1306
+ res.json({
1307
+ projectName,
1308
+ projectPath,
1309
+ templateId,
1310
+ templateName: template.name,
1311
+ fileName,
1312
+ filePath: filePath,
1313
+ message: 'PRD template applied successfully',
1314
+ timestamp: new Date().toISOString()
1315
+ });
1316
+ }
1317
+ catch (writeError) {
1318
+ console.error('Failed to write PRD template:', writeError);
1319
+ return res.status(500).json({
1320
+ error: 'Failed to write PRD template',
1321
+ message: writeError.message
1322
+ });
1323
+ }
1324
+ }
1325
+ catch (error) {
1326
+ console.error('Apply template error:', error);
1327
+ res.status(500).json({
1328
+ error: 'Failed to apply PRD template',
1329
+ message: error.message
1330
+ });
1331
+ }
1332
+ });
1333
+ // Helper function to get available templates
1334
+ async function getAvailableTemplates() {
1335
+ // This could be extended to read from files or database
1336
+ return [
1337
+ {
1338
+ id: 'web-app',
1339
+ name: 'Web Application',
1340
+ description: 'Template for web application projects',
1341
+ category: 'web',
1342
+ content: `# Product Requirements Document - Web Application
1343
+
1344
+ ## Overview
1345
+ **Product Name:** [Your App Name]
1346
+ **Version:** 1.0
1347
+ **Date:** ${new Date().toISOString().split('T')[0]}
1348
+ **Author:** [Your Name]
1349
+
1350
+ ## Executive Summary
1351
+ Brief description of what this web application will do and why it's needed.
1352
+
1353
+ ## User Stories
1354
+ 1. As a user, I want [feature] so I can [benefit]
1355
+ 2. As a user, I want [feature] so I can [benefit]
1356
+ 3. As a user, I want [feature] so I can [benefit]
1357
+
1358
+ ## Technical Requirements
1359
+ - Frontend framework
1360
+ - Backend services
1361
+ - Database requirements
1362
+ - Security considerations
1363
+
1364
+ ## Success Metrics
1365
+ - User engagement metrics
1366
+ - Performance benchmarks
1367
+ - Business objectives`
1368
+ },
1369
+ // Add other templates here if needed
1370
+ ];
1371
+ }
1372
+ export default router;
1373
+ //# sourceMappingURL=taskmaster.js.map