automagik-forge 0.1.13 → 0.1.14

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 (301) hide show
  1. package/README.md +143 -447
  2. package/dist/linux-x64/automagik-forge-mcp.zip +0 -0
  3. package/{npx-cli/automagik-forge-0.0.55.tgz → dist/linux-x64/automagik-forge.zip} +0 -0
  4. package/package.json +13 -23
  5. package/.cargo/config.toml +0 -13
  6. package/.claude/commands/commit.md +0 -376
  7. package/.claude/commands/prompt.md +0 -871
  8. package/.env.example +0 -20
  9. package/.github/actions/setup-node/action.yml +0 -29
  10. package/.github/images/automagik-logo.png +0 -0
  11. package/.github/workflows/pre-release.yml +0 -470
  12. package/.github/workflows/publish.yml +0 -145
  13. package/.github/workflows/test.yml +0 -63
  14. package/.mcp.json +0 -57
  15. package/AGENT.md +0 -40
  16. package/CLAUDE.md +0 -40
  17. package/CODE-OF-CONDUCT.md +0 -89
  18. package/Cargo.toml +0 -19
  19. package/Dockerfile +0 -43
  20. package/LICENSE +0 -201
  21. package/Makefile +0 -97
  22. package/backend/.sqlx/query-01b7e2bac1261d8be3d03c03df3e5220590da6c31c77f161074fc62752d63881.json +0 -12
  23. package/backend/.sqlx/query-03f2b02ba6dc5ea2b3cf6b1004caea0ad6bcc10ebd63f441d321a389f026e263.json +0 -12
  24. package/backend/.sqlx/query-0923b77d137a29fc54d399a873ff15fc4af894490bc65a4d344a7575cb0d8643.json +0 -12
  25. package/backend/.sqlx/query-0f808bcdb63c5f180836e448dd64c435c51758b2fc54a52ce9e67495b1ab200e.json +0 -68
  26. package/backend/.sqlx/query-1268afe9ca849daa6722e3df7ca8e9e61f0d37052e782bb5452ab8e1018d9b63.json +0 -12
  27. package/backend/.sqlx/query-1b082630a9622f8667ee7a9aba2c2d3176019a68c6bb83d33008594821415a57.json +0 -12
  28. package/backend/.sqlx/query-1c7b06ba1e112abf6b945a2ff08a0b40ec23f3738c2e7399f067b558cf8d490e.json +0 -12
  29. package/backend/.sqlx/query-1f619f01f46859a64ded531dd0ef61abacfe62e758abe7030a6aa745140b95ca.json +0 -104
  30. package/backend/.sqlx/query-1fca1ce14b4b20205364cd1f1f45ebe1d2e30cd745e59e189d56487b5639dfbb.json +0 -12
  31. package/backend/.sqlx/query-212828320e8d871ab9d83705a040b23bcf0393dc7252177fc539a74657f578ef.json +0 -32
  32. package/backend/.sqlx/query-290ce5c152be8d36e58ff42570f9157beb07ab9e77a03ec6fc30b4f56f9b8f6b.json +0 -56
  33. package/backend/.sqlx/query-2b471d2c2e8ffbe0cd42d2a91b814c0d79f9d09200f147e3cea33ba4ce673c8a.json +0 -68
  34. package/backend/.sqlx/query-354a48c705bb9bb2048c1b7f10fcb714e23f9db82b7a4ea6932486197b2ede6a.json +0 -92
  35. package/backend/.sqlx/query-36c9e3dd10648e94b949db5c91a774ecb1e10a899ef95da74066eccedca4d8b2.json +0 -12
  36. package/backend/.sqlx/query-36e4ba7bbd81b402d5a20b6005755eafbb174c8dda442081823406ac32809a94.json +0 -56
  37. package/backend/.sqlx/query-3a5b3c98a55ca183ab20c74708e3d7e579dda37972c059e7515c4ceee4bd8dd3.json +0 -62
  38. package/backend/.sqlx/query-3d0a1cabf2a52e9d90cdfd29c509ca89aeb448d0c1d2446c65cd43db40735e86.json +0 -62
  39. package/backend/.sqlx/query-3d6bd16fbce59efe30b7f67ea342e0e4ea6d1432389c02468ad79f1f742d4031.json +0 -56
  40. package/backend/.sqlx/query-4049ca413b285a05aca6b25385e9c8185575f01e9069e4e8581aa45d713f612f.json +0 -32
  41. package/backend/.sqlx/query-412bacd3477d86369082e90f52240407abce436cb81292d42b2dbe1e5c18eea1.json +0 -104
  42. package/backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json +0 -62
  43. package/backend/.sqlx/query-461cc1b0bb6fd909afc9dd2246e8526b3771cfbb0b22ae4b5d17b51af587b9e2.json +0 -56
  44. package/backend/.sqlx/query-58408c7a8cdeeda0bef359f1f9bd91299a339dc2b191462fc58c9736a56d5227.json +0 -92
  45. package/backend/.sqlx/query-5a886026d75d515c01f347cc203c8d99dd04c61dc468e2e4c5aa548436d13834.json +0 -62
  46. package/backend/.sqlx/query-5b902137b11022d2e1a5c4f6a9c83fec1a856c6a710aff831abd2382ede76b43.json +0 -12
  47. package/backend/.sqlx/query-5ed1238e52e59bb5f76c0f153fd99a14093f7ce2585bf9843585608f17ec575b.json +0 -104
  48. package/backend/.sqlx/query-6e8b860b14decfc2227dc57213f38442943d3fbef5c8418fd6b634c6e0f5e2ea.json +0 -104
  49. package/backend/.sqlx/query-6ec414276994c4ccb2433eaa5b1b342168557d17ddf5a52dac84cb1b59b9de8f.json +0 -68
  50. package/backend/.sqlx/query-6ecfa16d0cf825aacf233544b5baf151e9adfdca26c226ad71020d291fd802d5.json +0 -62
  51. package/backend/.sqlx/query-72509d252c39fce77520aa816cb2acbc1fb35dc2605e7be893610599b2427f2e.json +0 -62
  52. package/backend/.sqlx/query-75239b2da188f749707d77f3c1544332ca70db3d6d6743b2601dc0d167536437.json +0 -62
  53. package/backend/.sqlx/query-83d10e29f8478aff33434f9ac67068e013b888b953a2657e2bb72a6f619d04f2.json +0 -50
  54. package/backend/.sqlx/query-8610803360ea18b9b9d078a6981ea56abfbfe84e6354fc1d5ae4c622e01410ed.json +0 -68
  55. package/backend/.sqlx/query-86d03eb70eef39c59296416867f2ee66c9f7cd8b7f961fbda2f89fc0a1c442c2.json +0 -12
  56. package/backend/.sqlx/query-87d0feb5a6b442bad9c60068ea7569599cc6fc91a0e2692ecb42e93b03201b9d.json +0 -68
  57. package/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json +0 -12
  58. package/backend/.sqlx/query-8f01ebd64bdcde6a090479f14810d73ba23020e76fd70854ac57f2da251702c3.json +0 -12
  59. package/backend/.sqlx/query-90fd607fcb2dca72239ff25e618e21e174b195991eaa33722cbf5f76da84cfab.json +0 -62
  60. package/backend/.sqlx/query-92e8bdbcd80c5ff3db7a35cf79492048803ef305cbdef0d0a1fe5dc881ca8c71.json +0 -104
  61. package/backend/.sqlx/query-93a1605f90e9672dad29b472b6ad85fa9a55ea3ffa5abcb8724b09d61be254ca.json +0 -20
  62. package/backend/.sqlx/query-9472c8fb477958167f5fae40b85ac44252468c5226b2cdd7770f027332eed6d7.json +0 -104
  63. package/backend/.sqlx/query-96036c4f9e0f48bdc5a4a4588f0c5f288ac7aaa5425cac40fc33f337e1a351f2.json +0 -56
  64. package/backend/.sqlx/query-9edb2c01e91fd0f0fe7b56e988c7ae0393150f50be3f419a981e035c0121dfc7.json +0 -104
  65. package/backend/.sqlx/query-a157cf00616f703bfba21927f1eb1c9eec2a81c02da15f66efdba0b6c375de1b.json +0 -26
  66. package/backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json +0 -62
  67. package/backend/.sqlx/query-a5ba908419fb3e456bdd2daca41ba06cc3212ffffb8520fc7dbbcc8b60ada314.json +0 -12
  68. package/backend/.sqlx/query-a6d2961718dbc3b1a925e549f49a159c561bef58c105529275f274b27e2eba5b.json +0 -104
  69. package/backend/.sqlx/query-a9e93d5b09b29faf66e387e4d7596a792d81e75c4d3726e83c2963e8d7c9b56f.json +0 -104
  70. package/backend/.sqlx/query-ac5247c8d7fb86e4650c4b0eb9420031614c831b7b085083bac20c1af314c538.json +0 -12
  71. package/backend/.sqlx/query-afef9467be74c411c4cb119a8b2b1aea53049877dfc30cc60b486134ba4b4c9f.json +0 -68
  72. package/backend/.sqlx/query-b2b2c6b4d0b1a347b5c4cb63c3a46a265d4db53be9554989a814b069d0af82f2.json +0 -62
  73. package/backend/.sqlx/query-c50d2ff0b12e5bcc81e371089ee2d007e233e7db93aefba4fef08e7aa68f5ab7.json +0 -20
  74. package/backend/.sqlx/query-c614e6056b244ca07f1b9d44e7edc9d5819225c6f8d9e077070c6e518a17f50b.json +0 -12
  75. package/backend/.sqlx/query-c67259be8bf4ee0cfd32167b2aa3b7fe9192809181a8171bf1c2d6df731967ae.json +0 -12
  76. package/backend/.sqlx/query-d2d0a1b985ebbca6a2b3e882a221a219f3199890fa640afc946ef1a792d6d8de.json +0 -12
  77. package/backend/.sqlx/query-d30aa5786757f32bf2b9c5fe51a45e506c71c28c5994e430d9b0546adb15ffa2.json +0 -20
  78. package/backend/.sqlx/query-d3b9ea1de1576af71b312924ce7f4ea8ae5dbe2ac138ea3b4470f2d5cd734846.json +0 -12
  79. package/backend/.sqlx/query-ed8456646fa69ddd412441955f06ff22bfb790f29466450735e0b8bb1bc4ec94.json +0 -12
  80. package/backend/Cargo.toml +0 -71
  81. package/backend/build.rs +0 -32
  82. package/backend/migrations/20250617183714_init.sql +0 -44
  83. package/backend/migrations/20250620212427_execution_processes.sql +0 -25
  84. package/backend/migrations/20250620214100_remove_stdout_stderr_from_task_attempts.sql +0 -28
  85. package/backend/migrations/20250621120000_relate_activities_to_execution_processes.sql +0 -23
  86. package/backend/migrations/20250623120000_executor_sessions.sql +0 -17
  87. package/backend/migrations/20250623130000_add_executor_type_to_execution_processes.sql +0 -4
  88. package/backend/migrations/20250625000000_add_dev_script_to_projects.sql +0 -4
  89. package/backend/migrations/20250701000000_add_branch_to_task_attempts.sql +0 -2
  90. package/backend/migrations/20250701000001_add_pr_tracking_to_task_attempts.sql +0 -5
  91. package/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql +0 -2
  92. package/backend/migrations/20250708000000_add_base_branch_to_task_attempts.sql +0 -2
  93. package/backend/migrations/20250709000000_add_worktree_deleted_flag.sql +0 -2
  94. package/backend/migrations/20250710000000_add_setup_completion.sql +0 -3
  95. package/backend/migrations/20250715154859_add_task_templates.sql +0 -25
  96. package/backend/migrations/20250716143725_add_default_templates.sql +0 -174
  97. package/backend/migrations/20250716161432_update_executor_names_to_kebab_case.sql +0 -20
  98. package/backend/migrations/20250716170000_add_parent_task_to_tasks.sql +0 -7
  99. package/backend/migrations/20250717000000_drop_task_attempt_activities.sql +0 -9
  100. package/backend/migrations/20250719000000_add_cleanup_script_to_projects.sql +0 -2
  101. package/backend/migrations/20250720000000_add_cleanupscript_to_process_type_constraint.sql +0 -25
  102. package/backend/migrations/20250723000000_add_wish_to_tasks.sql +0 -7
  103. package/backend/migrations/20250724000000_remove_unique_wish_constraint.sql +0 -5
  104. package/backend/scripts/toast-notification.ps1 +0 -23
  105. package/backend/sounds/abstract-sound1.wav +0 -0
  106. package/backend/sounds/abstract-sound2.wav +0 -0
  107. package/backend/sounds/abstract-sound3.wav +0 -0
  108. package/backend/sounds/abstract-sound4.wav +0 -0
  109. package/backend/sounds/cow-mooing.wav +0 -0
  110. package/backend/sounds/phone-vibration.wav +0 -0
  111. package/backend/sounds/rooster.wav +0 -0
  112. package/backend/src/app_state.rs +0 -218
  113. package/backend/src/bin/generate_types.rs +0 -189
  114. package/backend/src/bin/mcp_task_server.rs +0 -191
  115. package/backend/src/execution_monitor.rs +0 -1193
  116. package/backend/src/executor.rs +0 -1053
  117. package/backend/src/executors/amp.rs +0 -697
  118. package/backend/src/executors/ccr.rs +0 -91
  119. package/backend/src/executors/charm_opencode.rs +0 -113
  120. package/backend/src/executors/claude.rs +0 -887
  121. package/backend/src/executors/cleanup_script.rs +0 -124
  122. package/backend/src/executors/dev_server.rs +0 -53
  123. package/backend/src/executors/echo.rs +0 -79
  124. package/backend/src/executors/gemini/config.rs +0 -67
  125. package/backend/src/executors/gemini/streaming.rs +0 -363
  126. package/backend/src/executors/gemini.rs +0 -765
  127. package/backend/src/executors/mod.rs +0 -23
  128. package/backend/src/executors/opencode_ai.rs +0 -113
  129. package/backend/src/executors/setup_script.rs +0 -130
  130. package/backend/src/executors/sst_opencode/filter.rs +0 -184
  131. package/backend/src/executors/sst_opencode/tools.rs +0 -139
  132. package/backend/src/executors/sst_opencode.rs +0 -756
  133. package/backend/src/lib.rs +0 -45
  134. package/backend/src/main.rs +0 -324
  135. package/backend/src/mcp/mod.rs +0 -1
  136. package/backend/src/mcp/task_server.rs +0 -850
  137. package/backend/src/middleware/mod.rs +0 -3
  138. package/backend/src/middleware/model_loaders.rs +0 -242
  139. package/backend/src/models/api_response.rs +0 -36
  140. package/backend/src/models/config.rs +0 -375
  141. package/backend/src/models/execution_process.rs +0 -430
  142. package/backend/src/models/executor_session.rs +0 -225
  143. package/backend/src/models/mod.rs +0 -12
  144. package/backend/src/models/project.rs +0 -356
  145. package/backend/src/models/task.rs +0 -345
  146. package/backend/src/models/task_attempt.rs +0 -1214
  147. package/backend/src/models/task_template.rs +0 -146
  148. package/backend/src/openapi.rs +0 -93
  149. package/backend/src/routes/auth.rs +0 -297
  150. package/backend/src/routes/config.rs +0 -385
  151. package/backend/src/routes/filesystem.rs +0 -228
  152. package/backend/src/routes/health.rs +0 -16
  153. package/backend/src/routes/mod.rs +0 -9
  154. package/backend/src/routes/projects.rs +0 -562
  155. package/backend/src/routes/stream.rs +0 -244
  156. package/backend/src/routes/task_attempts.rs +0 -1172
  157. package/backend/src/routes/task_templates.rs +0 -229
  158. package/backend/src/routes/tasks.rs +0 -353
  159. package/backend/src/services/analytics.rs +0 -216
  160. package/backend/src/services/git_service.rs +0 -1321
  161. package/backend/src/services/github_service.rs +0 -307
  162. package/backend/src/services/mod.rs +0 -13
  163. package/backend/src/services/notification_service.rs +0 -263
  164. package/backend/src/services/pr_monitor.rs +0 -214
  165. package/backend/src/services/process_service.rs +0 -940
  166. package/backend/src/utils/path.rs +0 -96
  167. package/backend/src/utils/shell.rs +0 -19
  168. package/backend/src/utils/text.rs +0 -24
  169. package/backend/src/utils/worktree_manager.rs +0 -578
  170. package/backend/src/utils.rs +0 -125
  171. package/backend/test.db +0 -0
  172. package/build-npm-package.sh +0 -61
  173. package/dev_assets_seed/config.json +0 -19
  174. package/frontend/.eslintrc.json +0 -25
  175. package/frontend/.prettierrc.json +0 -8
  176. package/frontend/components.json +0 -17
  177. package/frontend/index.html +0 -19
  178. package/frontend/package-lock.json +0 -7321
  179. package/frontend/package.json +0 -61
  180. package/frontend/postcss.config.js +0 -6
  181. package/frontend/public/android-chrome-192x192.png +0 -0
  182. package/frontend/public/android-chrome-512x512.png +0 -0
  183. package/frontend/public/apple-touch-icon.png +0 -0
  184. package/frontend/public/automagik-forge-logo-dark.svg +0 -3
  185. package/frontend/public/automagik-forge-logo.svg +0 -3
  186. package/frontend/public/automagik-forge-screenshot-overview.png +0 -0
  187. package/frontend/public/favicon-16x16.png +0 -0
  188. package/frontend/public/favicon-32x32.png +0 -0
  189. package/frontend/public/favicon.ico +0 -0
  190. package/frontend/public/site.webmanifest +0 -1
  191. package/frontend/public/viba-kanban-favicon.png +0 -0
  192. package/frontend/src/App.tsx +0 -157
  193. package/frontend/src/components/DisclaimerDialog.tsx +0 -106
  194. package/frontend/src/components/GitHubLoginDialog.tsx +0 -314
  195. package/frontend/src/components/OnboardingDialog.tsx +0 -185
  196. package/frontend/src/components/PrivacyOptInDialog.tsx +0 -130
  197. package/frontend/src/components/ProvidePatDialog.tsx +0 -98
  198. package/frontend/src/components/TaskTemplateManager.tsx +0 -336
  199. package/frontend/src/components/config-provider.tsx +0 -119
  200. package/frontend/src/components/context/TaskDetailsContextProvider.tsx +0 -470
  201. package/frontend/src/components/context/taskDetailsContext.ts +0 -125
  202. package/frontend/src/components/keyboard-shortcuts-demo.tsx +0 -35
  203. package/frontend/src/components/layout/navbar.tsx +0 -86
  204. package/frontend/src/components/logo.tsx +0 -44
  205. package/frontend/src/components/projects/ProjectCard.tsx +0 -155
  206. package/frontend/src/components/projects/project-detail.tsx +0 -251
  207. package/frontend/src/components/projects/project-form-fields.tsx +0 -238
  208. package/frontend/src/components/projects/project-form.tsx +0 -301
  209. package/frontend/src/components/projects/project-list.tsx +0 -200
  210. package/frontend/src/components/projects/projects-page.tsx +0 -20
  211. package/frontend/src/components/tasks/BranchSelector.tsx +0 -169
  212. package/frontend/src/components/tasks/DeleteFileConfirmationDialog.tsx +0 -94
  213. package/frontend/src/components/tasks/EditorSelectionDialog.tsx +0 -119
  214. package/frontend/src/components/tasks/TaskCard.tsx +0 -154
  215. package/frontend/src/components/tasks/TaskDetails/CollapsibleToolbar.tsx +0 -33
  216. package/frontend/src/components/tasks/TaskDetails/DiffCard.tsx +0 -109
  217. package/frontend/src/components/tasks/TaskDetails/DiffChunkSection.tsx +0 -135
  218. package/frontend/src/components/tasks/TaskDetails/DiffFile.tsx +0 -296
  219. package/frontend/src/components/tasks/TaskDetails/DiffTab.tsx +0 -32
  220. package/frontend/src/components/tasks/TaskDetails/DisplayConversationEntry.tsx +0 -392
  221. package/frontend/src/components/tasks/TaskDetails/LogsTab/Conversation.tsx +0 -256
  222. package/frontend/src/components/tasks/TaskDetails/LogsTab/ConversationEntry.tsx +0 -56
  223. package/frontend/src/components/tasks/TaskDetails/LogsTab/NormalizedConversationViewer.tsx +0 -92
  224. package/frontend/src/components/tasks/TaskDetails/LogsTab/Prompt.tsx +0 -22
  225. package/frontend/src/components/tasks/TaskDetails/LogsTab/SetupScriptRunning.tsx +0 -49
  226. package/frontend/src/components/tasks/TaskDetails/LogsTab.tsx +0 -186
  227. package/frontend/src/components/tasks/TaskDetails/ProcessesTab.tsx +0 -288
  228. package/frontend/src/components/tasks/TaskDetails/RelatedTasksTab.tsx +0 -216
  229. package/frontend/src/components/tasks/TaskDetails/TabNavigation.tsx +0 -93
  230. package/frontend/src/components/tasks/TaskDetailsHeader.tsx +0 -169
  231. package/frontend/src/components/tasks/TaskDetailsPanel.tsx +0 -126
  232. package/frontend/src/components/tasks/TaskDetailsToolbar.tsx +0 -302
  233. package/frontend/src/components/tasks/TaskFollowUpSection.tsx +0 -130
  234. package/frontend/src/components/tasks/TaskFormDialog.tsx +0 -400
  235. package/frontend/src/components/tasks/TaskKanbanBoard.tsx +0 -180
  236. package/frontend/src/components/tasks/Toolbar/CreateAttempt.tsx +0 -259
  237. package/frontend/src/components/tasks/Toolbar/CreatePRDialog.tsx +0 -243
  238. package/frontend/src/components/tasks/Toolbar/CurrentAttempt.tsx +0 -899
  239. package/frontend/src/components/tasks/index.ts +0 -2
  240. package/frontend/src/components/theme-provider.tsx +0 -82
  241. package/frontend/src/components/theme-toggle.tsx +0 -36
  242. package/frontend/src/components/ui/alert.tsx +0 -59
  243. package/frontend/src/components/ui/auto-expanding-textarea.tsx +0 -70
  244. package/frontend/src/components/ui/badge.tsx +0 -36
  245. package/frontend/src/components/ui/button.tsx +0 -56
  246. package/frontend/src/components/ui/card.tsx +0 -86
  247. package/frontend/src/components/ui/checkbox.tsx +0 -44
  248. package/frontend/src/components/ui/chip.tsx +0 -25
  249. package/frontend/src/components/ui/dialog.tsx +0 -124
  250. package/frontend/src/components/ui/dropdown-menu.tsx +0 -198
  251. package/frontend/src/components/ui/file-search-textarea.tsx +0 -292
  252. package/frontend/src/components/ui/folder-picker.tsx +0 -279
  253. package/frontend/src/components/ui/input.tsx +0 -25
  254. package/frontend/src/components/ui/label.tsx +0 -24
  255. package/frontend/src/components/ui/loader.tsx +0 -26
  256. package/frontend/src/components/ui/markdown-renderer.tsx +0 -75
  257. package/frontend/src/components/ui/select.tsx +0 -160
  258. package/frontend/src/components/ui/separator.tsx +0 -31
  259. package/frontend/src/components/ui/shadcn-io/kanban/index.tsx +0 -185
  260. package/frontend/src/components/ui/table.tsx +0 -117
  261. package/frontend/src/components/ui/tabs.tsx +0 -53
  262. package/frontend/src/components/ui/textarea.tsx +0 -22
  263. package/frontend/src/components/ui/tooltip.tsx +0 -28
  264. package/frontend/src/hooks/useNormalizedConversation.ts +0 -440
  265. package/frontend/src/index.css +0 -225
  266. package/frontend/src/lib/api.ts +0 -630
  267. package/frontend/src/lib/keyboard-shortcuts.ts +0 -266
  268. package/frontend/src/lib/responsive-config.ts +0 -70
  269. package/frontend/src/lib/types.ts +0 -39
  270. package/frontend/src/lib/utils.ts +0 -10
  271. package/frontend/src/main.tsx +0 -50
  272. package/frontend/src/pages/McpServers.tsx +0 -418
  273. package/frontend/src/pages/Settings.tsx +0 -610
  274. package/frontend/src/pages/project-tasks.tsx +0 -575
  275. package/frontend/src/pages/projects.tsx +0 -18
  276. package/frontend/src/vite-env.d.ts +0 -1
  277. package/frontend/tailwind.config.js +0 -125
  278. package/frontend/tsconfig.json +0 -26
  279. package/frontend/tsconfig.node.json +0 -10
  280. package/frontend/vite.config.ts +0 -33
  281. package/npx-cli/README.md +0 -159
  282. package/npx-cli/automagik-forge-0.1.0.tgz +0 -0
  283. package/npx-cli/automagik-forge-0.1.10.tgz +0 -0
  284. package/npx-cli/package.json +0 -17
  285. package/npx-cli/vibe-kanban-0.0.55.tgz +0 -0
  286. package/pnpm-workspace.yaml +0 -2
  287. package/rust-toolchain.toml +0 -11
  288. package/rustfmt.toml +0 -3
  289. package/scripts/load-env.js +0 -43
  290. package/scripts/mcp_test.js +0 -374
  291. package/scripts/prepare-db.js +0 -45
  292. package/scripts/setup-dev-environment.js +0 -274
  293. package/scripts/start-mcp-sse.js +0 -70
  294. package/scripts/test-debug.js +0 -32
  295. package/scripts/test-mcp-sse.js +0 -138
  296. package/scripts/test-simple.js +0 -44
  297. package/scripts/test-wish-final.js +0 -179
  298. package/scripts/test-wish-system.js +0 -221
  299. package/shared/types.ts +0 -182
  300. package/test-npm-package.sh +0 -42
  301. /package/{npx-cli/bin → bin}/cli.js +0 -0
@@ -1,850 +0,0 @@
1
- use std::future::Future;
2
-
3
- use rmcp::{
4
- handler::server::tool::{Parameters, ToolRouter},
5
- model::{
6
- CallToolResult, Content, Implementation, ProtocolVersion, ServerCapabilities, ServerInfo,
7
- },
8
- schemars, tool, tool_handler, tool_router, ErrorData as RmcpError, ServerHandler,
9
- };
10
- use serde::{Deserialize, Serialize};
11
- use serde_json;
12
- use sqlx::SqlitePool;
13
- use uuid::Uuid;
14
-
15
- use crate::models::{
16
- project::Project,
17
- task::{CreateTask, Task, TaskStatus},
18
- };
19
-
20
- #[derive(Debug, Deserialize, schemars::JsonSchema)]
21
- pub struct CreateTaskRequest {
22
- #[schemars(description = "The ID of the project to create the task in")]
23
- pub project_id: String,
24
- #[schemars(description = "The title of the task")]
25
- pub title: String,
26
- #[schemars(description = "Description of the task")]
27
- pub description: String,
28
- #[schemars(description = "Wish identifier like 'refactor-authentication' or 'feature-dashboard'")]
29
- pub wish_id: String,
30
- }
31
-
32
- #[derive(Debug, Serialize, schemars::JsonSchema)]
33
- pub struct CreateTaskResponse {
34
- pub success: bool,
35
- pub task_id: String,
36
- pub message: String,
37
- }
38
-
39
- #[derive(Debug, Serialize, schemars::JsonSchema)]
40
- pub struct ProjectSummary {
41
- #[schemars(description = "The unique identifier of the project")]
42
- pub id: String,
43
- #[schemars(description = "The name of the project")]
44
- pub name: String,
45
- #[schemars(description = "The path to the git repository")]
46
- pub git_repo_path: String,
47
- #[schemars(description = "Optional setup script for the project")]
48
- pub setup_script: Option<String>,
49
- #[schemars(description = "Optional development script for the project")]
50
- pub dev_script: Option<String>,
51
- #[schemars(description = "Current git branch (if available)")]
52
- pub current_branch: Option<String>,
53
- #[schemars(description = "When the project was created")]
54
- pub created_at: String,
55
- #[schemars(description = "When the project was last updated")]
56
- pub updated_at: String,
57
- }
58
-
59
- #[derive(Debug, Serialize, schemars::JsonSchema)]
60
- pub struct ListProjectsResponse {
61
- pub success: bool,
62
- pub projects: Vec<ProjectSummary>,
63
- pub count: usize,
64
- }
65
-
66
- #[derive(Debug, Deserialize, schemars::JsonSchema)]
67
- pub struct ListTasksRequest {
68
- #[schemars(description = "Optional project ID filter")]
69
- pub project_id: Option<String>,
70
- #[schemars(
71
- description = "Optional status filter: 'todo', 'inprogress', 'inreview', 'done', 'cancelled'"
72
- )]
73
- pub status: Option<String>,
74
- #[schemars(description = "Optional wish ID filter - primary way to group tasks")]
75
- pub wish_id: Option<String>,
76
- #[schemars(description = "Maximum number of tasks to return (default: 50)")]
77
- pub limit: Option<i32>,
78
- }
79
-
80
- #[derive(Debug, Serialize, schemars::JsonSchema)]
81
- pub struct TaskSummary {
82
- #[schemars(description = "The unique identifier of the task")]
83
- pub id: String,
84
- #[schemars(description = "The title of the task")]
85
- pub title: String,
86
- #[schemars(description = "Optional description of the task")]
87
- pub description: Option<String>,
88
- #[schemars(description = "Current status of the task")]
89
- pub status: String,
90
- #[schemars(description = "Wish identifier for task grouping")]
91
- pub wish_id: String,
92
- #[schemars(description = "When the task was created")]
93
- pub created_at: String,
94
- #[schemars(description = "When the task was last updated")]
95
- pub updated_at: String,
96
- #[schemars(description = "Whether the task has an in-progress execution attempt")]
97
- pub has_in_progress_attempt: Option<bool>,
98
- #[schemars(description = "Whether the task has a merged execution attempt")]
99
- pub has_merged_attempt: Option<bool>,
100
- #[schemars(description = "Whether the last execution attempt failed")]
101
- pub last_attempt_failed: Option<bool>,
102
- }
103
-
104
- #[derive(Debug, Serialize, schemars::JsonSchema)]
105
- pub struct ListTasksResponse {
106
- pub success: bool,
107
- pub tasks: Vec<TaskSummary>,
108
- pub count: usize,
109
- pub project_id: String,
110
- pub project_name: Option<String>,
111
- pub applied_filters: ListTasksFilters,
112
- }
113
-
114
- #[derive(Debug, Serialize, schemars::JsonSchema)]
115
- pub struct ListTasksFilters {
116
- pub status: Option<String>,
117
- pub limit: i32,
118
- }
119
-
120
- fn parse_task_status(status_str: &str) -> Option<TaskStatus> {
121
- match status_str.to_lowercase().as_str() {
122
- "todo" => Some(TaskStatus::Todo),
123
- "inprogress" | "in-progress" | "in_progress" => Some(TaskStatus::InProgress),
124
- "inreview" | "in-review" | "in_review" => Some(TaskStatus::InReview),
125
- "done" | "completed" => Some(TaskStatus::Done),
126
- "cancelled" | "canceled" => Some(TaskStatus::Cancelled),
127
- _ => None,
128
- }
129
- }
130
-
131
- fn task_status_to_string(status: &TaskStatus) -> String {
132
- match status {
133
- TaskStatus::Todo => "todo".to_string(),
134
- TaskStatus::InProgress => "in-progress".to_string(),
135
- TaskStatus::InReview => "in-review".to_string(),
136
- TaskStatus::Done => "done".to_string(),
137
- TaskStatus::Cancelled => "cancelled".to_string(),
138
- }
139
- }
140
-
141
- #[derive(Debug, Deserialize, schemars::JsonSchema)]
142
- pub struct UpdateTaskRequest {
143
- #[schemars(description = "The unique ID of the task to update")]
144
- pub task_id: String,
145
- #[schemars(description = "Optional new title")]
146
- pub title: Option<String>,
147
- #[schemars(description = "Optional new description")]
148
- pub description: Option<String>,
149
- #[schemars(description = "Optional new status: 'todo', 'inprogress', 'inreview', 'done', 'cancelled'")]
150
- pub status: Option<String>,
151
- #[schemars(description = "Optional new wish assignment")]
152
- pub wish_id: Option<String>,
153
- }
154
-
155
- #[derive(Debug, Serialize, schemars::JsonSchema)]
156
- pub struct UpdateTaskResponse {
157
- pub success: bool,
158
- pub message: String,
159
- pub task: Option<TaskSummary>,
160
- }
161
-
162
- #[derive(Debug, Deserialize, schemars::JsonSchema)]
163
- pub struct DeleteTaskRequest {
164
- #[schemars(description = "The ID of the project containing the task")]
165
- pub project_id: String,
166
- #[schemars(description = "The ID of the task to delete")]
167
- pub task_id: String,
168
- }
169
-
170
- #[derive(Debug, Serialize, schemars::JsonSchema)]
171
- pub struct DeleteTaskResponse {
172
- pub success: bool,
173
- pub message: String,
174
- pub deleted_task_id: Option<String>,
175
- }
176
-
177
- #[derive(Debug, Serialize, schemars::JsonSchema)]
178
- pub struct SimpleTaskResponse {
179
- pub success: bool,
180
- pub message: String,
181
- pub task_title: String,
182
- pub new_status: Option<String>,
183
- }
184
-
185
- #[derive(Debug, Deserialize, schemars::JsonSchema)]
186
- pub struct GetTaskRequest {
187
- #[schemars(description = "The ID of the project containing the task")]
188
- pub project_id: String,
189
- #[schemars(description = "The ID of the task to retrieve")]
190
- pub task_id: String,
191
- }
192
-
193
- #[derive(Debug, Serialize, schemars::JsonSchema)]
194
- pub struct GetTaskResponse {
195
- pub success: bool,
196
- pub task: Option<TaskSummary>,
197
- pub project_name: Option<String>,
198
- }
199
-
200
- #[derive(Debug, Clone)]
201
- pub struct TaskServer {
202
- pub pool: SqlitePool,
203
- tool_router: ToolRouter<TaskServer>,
204
- }
205
-
206
- impl TaskServer {
207
- #[allow(dead_code)]
208
- pub fn new(pool: SqlitePool) -> Self {
209
- Self {
210
- pool,
211
- tool_router: Self::tool_router(),
212
- }
213
- }
214
- }
215
-
216
- #[tool_router]
217
- impl TaskServer {
218
- #[tool(
219
- description = "Create a new task/ticket in a project. Always pass the `project_id` of the project you want to create the task in - it is required!"
220
- )]
221
- async fn create_task(
222
- &self,
223
- Parameters(CreateTaskRequest {
224
- project_id,
225
- title,
226
- description,
227
- wish_id,
228
- }): Parameters<CreateTaskRequest>,
229
- ) -> Result<CallToolResult, RmcpError> {
230
- // Parse project_id from string to UUID
231
- let project_uuid = match Uuid::parse_str(&project_id) {
232
- Ok(uuid) => uuid,
233
- Err(_) => {
234
- let error_response = serde_json::json!({
235
- "success": false,
236
- "error": "Invalid project ID format. Must be a valid UUID.",
237
- "project_id": project_id
238
- });
239
- return Ok(CallToolResult::error(vec![Content::text(
240
- serde_json::to_string_pretty(&error_response)
241
- .unwrap_or_else(|_| "Invalid project ID format".to_string()),
242
- )]));
243
- }
244
- };
245
-
246
- // Check if project exists
247
- match Project::exists(&self.pool, project_uuid).await {
248
- Ok(false) => {
249
- let error_response = serde_json::json!({
250
- "success": false,
251
- "error": "Project not found",
252
- "project_id": project_id
253
- });
254
- return Ok(CallToolResult::error(vec![Content::text(
255
- serde_json::to_string_pretty(&error_response)
256
- .unwrap_or_else(|_| "Project not found".to_string()),
257
- )]));
258
- }
259
- Err(e) => {
260
- let error_response = serde_json::json!({
261
- "success": false,
262
- "error": "Failed to check project existence",
263
- "details": e.to_string(),
264
- "project_id": project_id
265
- });
266
- return Ok(CallToolResult::error(vec![Content::text(
267
- serde_json::to_string_pretty(&error_response)
268
- .unwrap_or_else(|_| "Database error".to_string()),
269
- )]));
270
- }
271
- Ok(true) => {}
272
- }
273
-
274
- let task_id = Uuid::new_v4();
275
- let create_task_data = CreateTask {
276
- project_id: project_uuid,
277
- title: title.clone(),
278
- description: Some(description.clone()),
279
- wish_id: wish_id.clone(),
280
- parent_task_attempt: None,
281
- };
282
-
283
- match Task::create(&self.pool, &create_task_data, task_id).await {
284
- Ok(_task) => {
285
- let success_response = CreateTaskResponse {
286
- success: true,
287
- task_id: task_id.to_string(),
288
- message: "Task created successfully".to_string(),
289
- };
290
- Ok(CallToolResult::success(vec![Content::text(
291
- serde_json::to_string_pretty(&success_response)
292
- .unwrap_or_else(|_| "Task created successfully".to_string()),
293
- )]))
294
- }
295
- Err(e) => {
296
- let error_message = e.to_string();
297
- let (user_error, details) = ("Failed to create task".to_string(), error_message.as_str());
298
-
299
- let error_response = serde_json::json!({
300
- "success": false,
301
- "error": user_error,
302
- "details": details,
303
- "project_id": project_id,
304
- "title": title,
305
- "wish_id": wish_id
306
- });
307
- Ok(CallToolResult::error(vec![Content::text(
308
- serde_json::to_string_pretty(&error_response)
309
- .unwrap_or_else(|_| "Failed to create task".to_string()),
310
- )]))
311
- }
312
- }
313
- }
314
-
315
- #[tool(description = "List all the available projects")]
316
- async fn list_projects(&self) -> Result<CallToolResult, RmcpError> {
317
- match Project::find_all(&self.pool).await {
318
- Ok(projects) => {
319
- let count = projects.len();
320
- let project_summaries: Vec<ProjectSummary> = projects
321
- .into_iter()
322
- .map(|project| {
323
- let project_with_branch = project.with_branch_info();
324
- ProjectSummary {
325
- id: project_with_branch.id.to_string(),
326
- name: project_with_branch.name,
327
- git_repo_path: project_with_branch.git_repo_path,
328
- setup_script: project_with_branch.setup_script,
329
- dev_script: project_with_branch.dev_script,
330
- current_branch: project_with_branch.current_branch,
331
- created_at: project_with_branch.created_at.to_rfc3339(),
332
- updated_at: project_with_branch.updated_at.to_rfc3339(),
333
- }
334
- })
335
- .collect();
336
-
337
- let response = ListProjectsResponse {
338
- success: true,
339
- projects: project_summaries,
340
- count,
341
- };
342
-
343
- Ok(CallToolResult::success(vec![Content::text(
344
- serde_json::to_string_pretty(&response)
345
- .unwrap_or_else(|_| "Failed to serialize projects".to_string()),
346
- )]))
347
- }
348
- Err(e) => {
349
- let error_response = serde_json::json!({
350
- "success": false,
351
- "error": "Failed to retrieve projects",
352
- "details": e.to_string()
353
- });
354
- Ok(CallToolResult::error(vec![Content::text(
355
- serde_json::to_string_pretty(&error_response)
356
- .unwrap_or_else(|_| "Database error".to_string()),
357
- )]))
358
- }
359
- }
360
- }
361
-
362
- #[tool(
363
- description = "List all the task/tickets in a project with optional filtering and execution status. `project_id` is required!"
364
- )]
365
- async fn list_tasks(
366
- &self,
367
- Parameters(ListTasksRequest {
368
- project_id,
369
- status,
370
- wish_id,
371
- limit,
372
- }): Parameters<ListTasksRequest>,
373
- ) -> Result<CallToolResult, RmcpError> {
374
- // Parse project_id if provided
375
- let project_uuid = if let Some(ref project_id_str) = project_id {
376
- match Uuid::parse_str(project_id_str) {
377
- Ok(uuid) => Some(uuid),
378
- Err(_) => {
379
- let error_response = serde_json::json!({
380
- "success": false,
381
- "error": "Invalid project ID format. Must be a valid UUID.",
382
- "project_id": project_id_str
383
- });
384
- return Ok(CallToolResult::error(vec![Content::text(
385
- serde_json::to_string_pretty(&error_response)
386
- .unwrap_or_else(|_| "Invalid project ID format".to_string()),
387
- )]));
388
- }
389
- }
390
- } else {
391
- None
392
- };
393
-
394
- let status_filter = if let Some(ref status_str) = status {
395
- match parse_task_status(status_str) {
396
- Some(status) => Some(status),
397
- None => {
398
- let error_response = serde_json::json!({
399
- "success": false,
400
- "error": "Invalid status filter. Valid values: 'todo', 'inprogress', 'inreview', 'done', 'cancelled'",
401
- "provided_status": status_str
402
- });
403
- return Ok(CallToolResult::error(vec![Content::text(
404
- serde_json::to_string_pretty(&error_response)
405
- .unwrap_or_else(|_| "Invalid status filter".to_string()),
406
- )]));
407
- }
408
- }
409
- } else {
410
- None
411
- };
412
-
413
- // For now, require project_id since we only have project-based queries
414
- let project_uuid_val = match project_uuid {
415
- Some(uuid) => uuid,
416
- None => {
417
- let error_response = serde_json::json!({
418
- "success": false,
419
- "error": "Project ID is required for listing tasks"
420
- });
421
- return Ok(CallToolResult::error(vec![Content::text(
422
- serde_json::to_string_pretty(&error_response)
423
- .unwrap_or_else(|_| "Project ID required".to_string()),
424
- )]));
425
- }
426
- };
427
-
428
- let project = match Project::find_by_id(&self.pool, project_uuid_val).await {
429
- Ok(Some(project)) => project,
430
- Ok(None) => {
431
- let error_response = serde_json::json!({
432
- "success": false,
433
- "error": "Project not found",
434
- "project_id": project_id
435
- });
436
- return Ok(CallToolResult::error(vec![Content::text(
437
- serde_json::to_string_pretty(&error_response)
438
- .unwrap_or_else(|_| "Project not found".to_string()),
439
- )]));
440
- }
441
- Err(e) => {
442
- let error_response = serde_json::json!({
443
- "success": false,
444
- "error": "Failed to check project existence",
445
- "details": e.to_string(),
446
- "project_id": project_id
447
- });
448
- return Ok(CallToolResult::error(vec![Content::text(
449
- serde_json::to_string_pretty(&error_response)
450
- .unwrap_or_else(|_| "Database error".to_string()),
451
- )]));
452
- }
453
- };
454
-
455
- let task_limit = limit.unwrap_or(50).clamp(1, 200); // Reasonable limits
456
-
457
- let tasks_result =
458
- Task::find_by_project_id_with_attempt_status(&self.pool, project_uuid_val).await;
459
-
460
- match tasks_result {
461
- Ok(tasks) => {
462
- let filtered_tasks: Vec<_> = tasks
463
- .into_iter()
464
- .filter(|task| {
465
- let status_match = if let Some(ref filter_status) = status_filter {
466
- &task.status == filter_status
467
- } else {
468
- true
469
- };
470
- let wish_match = if let Some(ref filter_wish) = wish_id {
471
- task.wish_id == *filter_wish
472
- } else {
473
- true
474
- };
475
- status_match && wish_match
476
- })
477
- .take(task_limit as usize)
478
- .collect();
479
-
480
- let task_summaries: Vec<TaskSummary> = filtered_tasks
481
- .into_iter()
482
- .map(|task| TaskSummary {
483
- id: task.id.to_string(),
484
- title: task.title,
485
- description: task.description,
486
- status: task_status_to_string(&task.status),
487
- wish_id: task.wish_id,
488
- created_at: task.created_at.to_rfc3339(),
489
- updated_at: task.updated_at.to_rfc3339(),
490
- has_in_progress_attempt: Some(task.has_in_progress_attempt),
491
- has_merged_attempt: Some(task.has_merged_attempt),
492
- last_attempt_failed: Some(task.last_attempt_failed),
493
- })
494
- .collect();
495
-
496
- let count = task_summaries.len();
497
- let response = ListTasksResponse {
498
- success: true,
499
- tasks: task_summaries,
500
- count,
501
- project_id: project_id.clone().unwrap_or_else(|| project_uuid_val.to_string()),
502
- project_name: Some(project.name),
503
- applied_filters: ListTasksFilters {
504
- status: status.clone(),
505
- limit: task_limit,
506
- },
507
- };
508
-
509
- Ok(CallToolResult::success(vec![Content::text(
510
- serde_json::to_string_pretty(&response)
511
- .unwrap_or_else(|_| "Failed to serialize tasks".to_string()),
512
- )]))
513
- }
514
- Err(e) => {
515
- let error_response = serde_json::json!({
516
- "success": false,
517
- "error": "Failed to retrieve tasks",
518
- "details": e.to_string(),
519
- "project_id": project_id
520
- });
521
- Ok(CallToolResult::error(vec![Content::text(
522
- serde_json::to_string_pretty(&error_response)
523
- .unwrap_or_else(|_| "Database error".to_string()),
524
- )]))
525
- }
526
- }
527
- }
528
-
529
- #[tool(
530
- description = "Update an existing task/ticket's title, description, or status. `project_id` and `task_id` are required! `title`, `description`, and `status` are optional."
531
- )]
532
- async fn update_task(
533
- &self,
534
- Parameters(UpdateTaskRequest {
535
- task_id,
536
- title,
537
- description,
538
- status,
539
- wish_id,
540
- }): Parameters<UpdateTaskRequest>,
541
- ) -> Result<CallToolResult, RmcpError> {
542
- let task_uuid = match Uuid::parse_str(&task_id) {
543
- Ok(uuid) => uuid,
544
- Err(_) => {
545
- let error_response = serde_json::json!({
546
- "success": false,
547
- "error": "Invalid task ID format. Must be a valid UUID.",
548
- "task_id": task_id
549
- });
550
- return Ok(CallToolResult::error(vec![Content::text(
551
- serde_json::to_string_pretty(&error_response).unwrap(),
552
- )]));
553
- }
554
- };
555
-
556
- let status_enum = if let Some(ref status_str) = status {
557
- match parse_task_status(status_str) {
558
- Some(status) => Some(status),
559
- None => {
560
- let error_response = serde_json::json!({
561
- "success": false,
562
- "error": "Invalid status. Valid values: 'todo', 'inprogress', 'inreview', 'done', 'cancelled'",
563
- "provided_status": status_str
564
- });
565
- return Ok(CallToolResult::error(vec![Content::text(
566
- serde_json::to_string_pretty(&error_response).unwrap(),
567
- )]));
568
- }
569
- }
570
- } else {
571
- None
572
- };
573
-
574
- let current_task = match Task::find_by_id(&self.pool, task_uuid).await {
575
- Ok(Some(task)) => task,
576
- Ok(None) => {
577
- let error_response = serde_json::json!({
578
- "success": false,
579
- "error": "Task not found",
580
- "task_id": task_id
581
- });
582
- return Ok(CallToolResult::error(vec![Content::text(
583
- serde_json::to_string_pretty(&error_response).unwrap(),
584
- )]));
585
- }
586
- Err(e) => {
587
- let error_response = serde_json::json!({
588
- "success": false,
589
- "error": "Failed to retrieve task",
590
- "details": e.to_string()
591
- });
592
- return Ok(CallToolResult::error(vec![Content::text(
593
- serde_json::to_string_pretty(&error_response).unwrap(),
594
- )]));
595
- }
596
- };
597
-
598
- let new_title = title.unwrap_or(current_task.title);
599
- let new_description = description.or(current_task.description);
600
- let new_status = status_enum.unwrap_or(current_task.status);
601
- let new_wish_id = wish_id.unwrap_or(current_task.wish_id);
602
- let new_parent_task_attempt = current_task.parent_task_attempt;
603
-
604
- match Task::update(
605
- &self.pool,
606
- task_uuid,
607
- current_task.project_id,
608
- new_title,
609
- new_description,
610
- new_status,
611
- new_wish_id,
612
- new_parent_task_attempt,
613
- )
614
- .await
615
- {
616
- Ok(updated_task) => {
617
- let task_summary = TaskSummary {
618
- id: updated_task.id.to_string(),
619
- title: updated_task.title,
620
- description: updated_task.description,
621
- status: task_status_to_string(&updated_task.status),
622
- wish_id: updated_task.wish_id,
623
- created_at: updated_task.created_at.to_rfc3339(),
624
- updated_at: updated_task.updated_at.to_rfc3339(),
625
- has_in_progress_attempt: None,
626
- has_merged_attempt: None,
627
- last_attempt_failed: None,
628
- };
629
-
630
- let response = UpdateTaskResponse {
631
- success: true,
632
- message: "Task updated successfully".to_string(),
633
- task: Some(task_summary),
634
- };
635
-
636
- Ok(CallToolResult::success(vec![Content::text(
637
- serde_json::to_string_pretty(&response).unwrap(),
638
- )]))
639
- }
640
- Err(e) => {
641
- let error_response = serde_json::json!({
642
- "success": false,
643
- "error": "Failed to update task",
644
- "details": e.to_string()
645
- });
646
- Ok(CallToolResult::error(vec![Content::text(
647
- serde_json::to_string_pretty(&error_response).unwrap(),
648
- )]))
649
- }
650
- }
651
- }
652
-
653
- #[tool(
654
- description = "Delete a task/ticket from a project. `project_id` and `task_id` are required!"
655
- )]
656
- async fn delete_task(
657
- &self,
658
- Parameters(DeleteTaskRequest {
659
- project_id,
660
- task_id,
661
- }): Parameters<DeleteTaskRequest>,
662
- ) -> Result<CallToolResult, RmcpError> {
663
- let project_uuid = match Uuid::parse_str(&project_id) {
664
- Ok(uuid) => uuid,
665
- Err(_) => {
666
- let error_response = serde_json::json!({
667
- "success": false,
668
- "error": "Invalid project ID format"
669
- });
670
- return Ok(CallToolResult::error(vec![Content::text(
671
- serde_json::to_string_pretty(&error_response).unwrap(),
672
- )]));
673
- }
674
- };
675
-
676
- let task_uuid = match Uuid::parse_str(&task_id) {
677
- Ok(uuid) => uuid,
678
- Err(_) => {
679
- let error_response = serde_json::json!({
680
- "success": false,
681
- "error": "Invalid task ID format"
682
- });
683
- return Ok(CallToolResult::error(vec![Content::text(
684
- serde_json::to_string_pretty(&error_response).unwrap(),
685
- )]));
686
- }
687
- };
688
-
689
- match Task::exists(&self.pool, task_uuid, project_uuid).await {
690
- Ok(true) => {
691
- // Delete the task
692
- match Task::delete(&self.pool, task_uuid, project_uuid).await {
693
- Ok(rows_affected) => {
694
- if rows_affected > 0 {
695
- let response = DeleteTaskResponse {
696
- success: true,
697
- message: "Task deleted successfully".to_string(),
698
- deleted_task_id: Some(task_id),
699
- };
700
- Ok(CallToolResult::success(vec![Content::text(
701
- serde_json::to_string_pretty(&response).unwrap(),
702
- )]))
703
- } else {
704
- let error_response = serde_json::json!({
705
- "success": false,
706
- "error": "Task not found or already deleted"
707
- });
708
- Ok(CallToolResult::error(vec![Content::text(
709
- serde_json::to_string_pretty(&error_response).unwrap(),
710
- )]))
711
- }
712
- }
713
- Err(e) => {
714
- let error_response = serde_json::json!({
715
- "success": false,
716
- "error": "Failed to delete task",
717
- "details": e.to_string()
718
- });
719
- Ok(CallToolResult::error(vec![Content::text(
720
- serde_json::to_string_pretty(&error_response).unwrap(),
721
- )]))
722
- }
723
- }
724
- }
725
- Ok(false) => {
726
- let error_response = serde_json::json!({
727
- "success": false,
728
- "error": "Task not found in the specified project"
729
- });
730
- Ok(CallToolResult::error(vec![Content::text(
731
- serde_json::to_string_pretty(&error_response).unwrap(),
732
- )]))
733
- }
734
- Err(e) => {
735
- let error_response = serde_json::json!({
736
- "success": false,
737
- "error": "Failed to check task existence",
738
- "details": e.to_string()
739
- });
740
- Ok(CallToolResult::error(vec![Content::text(
741
- serde_json::to_string_pretty(&error_response).unwrap(),
742
- )]))
743
- }
744
- }
745
- }
746
-
747
- #[tool(
748
- description = "Get detailed information about a specific task/ticket. `project_id` and `task_id` are required!"
749
- )]
750
- async fn get_task(
751
- &self,
752
- Parameters(GetTaskRequest {
753
- project_id,
754
- task_id,
755
- }): Parameters<GetTaskRequest>,
756
- ) -> Result<CallToolResult, RmcpError> {
757
- let project_uuid = match Uuid::parse_str(&project_id) {
758
- Ok(uuid) => uuid,
759
- Err(_) => {
760
- let error_response = serde_json::json!({
761
- "success": false,
762
- "error": "Invalid project ID format"
763
- });
764
- return Ok(CallToolResult::error(vec![Content::text(
765
- serde_json::to_string_pretty(&error_response).unwrap(),
766
- )]));
767
- }
768
- };
769
-
770
- let task_uuid = match Uuid::parse_str(&task_id) {
771
- Ok(uuid) => uuid,
772
- Err(_) => {
773
- let error_response = serde_json::json!({
774
- "success": false,
775
- "error": "Invalid task ID format"
776
- });
777
- return Ok(CallToolResult::error(vec![Content::text(
778
- serde_json::to_string_pretty(&error_response).unwrap(),
779
- )]));
780
- }
781
- };
782
-
783
- let task_result =
784
- Task::find_by_id_and_project_id(&self.pool, task_uuid, project_uuid).await;
785
- let project_result = Project::find_by_id(&self.pool, project_uuid).await;
786
-
787
- match (task_result, project_result) {
788
- (Ok(Some(task)), Ok(Some(project))) => {
789
- let task_summary = TaskSummary {
790
- id: task.id.to_string(),
791
- title: task.title,
792
- description: task.description,
793
- status: task_status_to_string(&task.status),
794
- wish_id: task.wish_id,
795
- created_at: task.created_at.to_rfc3339(),
796
- updated_at: task.updated_at.to_rfc3339(),
797
- has_in_progress_attempt: None,
798
- has_merged_attempt: None,
799
- last_attempt_failed: None,
800
- };
801
-
802
- let response = GetTaskResponse {
803
- success: true,
804
- task: Some(task_summary),
805
- project_name: Some(project.name),
806
- };
807
-
808
- Ok(CallToolResult::success(vec![Content::text(
809
- serde_json::to_string_pretty(&response).unwrap(),
810
- )]))
811
- }
812
- (Ok(None), _) | (_, Ok(None)) => {
813
- let error_response = serde_json::json!({
814
- "success": false,
815
- "error": "Task or project not found"
816
- });
817
- Ok(CallToolResult::error(vec![Content::text(
818
- serde_json::to_string_pretty(&error_response).unwrap(),
819
- )]))
820
- }
821
- (Err(e), _) | (_, Err(e)) => {
822
- let error_response = serde_json::json!({
823
- "success": false,
824
- "error": "Failed to retrieve task or project",
825
- "details": e.to_string()
826
- });
827
- Ok(CallToolResult::error(vec![Content::text(
828
- serde_json::to_string_pretty(&error_response).unwrap(),
829
- )]))
830
- }
831
- }
832
- }
833
- }
834
-
835
- #[tool_handler]
836
- impl ServerHandler for TaskServer {
837
- fn get_info(&self) -> ServerInfo {
838
- ServerInfo {
839
- protocol_version: ProtocolVersion::V_2025_03_26,
840
- capabilities: ServerCapabilities::builder()
841
- .enable_tools()
842
- .build(),
843
- server_info: Implementation {
844
- name: "automagik-forge".to_string(),
845
- version: "1.0.0".to_string(),
846
- },
847
- instructions: Some("A task and project management server. If you need to create or update tickets or tasks then use these tools. Most of them absolutely require that you pass the `project_id` of the project that you are currently working on. This should be provided to you. Call `list_tasks` to fetch the `task_ids` of all the tasks in a project`. TOOLS: 'list_projects', 'list_tasks', 'create_task', 'get_task', 'update_task', 'delete_task'. Make sure to pass `project_id` or `task_id` where required. You can use list tools to get the available ids.".to_string()),
848
- }
849
- }
850
- }