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,356 +0,0 @@
1
- use chrono::{DateTime, Utc};
2
- use git2::{BranchType, Repository};
3
- use serde::{Deserialize, Serialize};
4
- use sqlx::{FromRow, SqlitePool};
5
- use ts_rs::TS;
6
- use utoipa::ToSchema;
7
- use uuid::Uuid;
8
-
9
- #[derive(Debug, Clone, FromRow, Serialize, Deserialize, TS, ToSchema)]
10
- #[ts(export)]
11
- pub struct Project {
12
- pub id: Uuid,
13
- pub name: String,
14
- pub git_repo_path: String,
15
- pub setup_script: Option<String>,
16
- pub dev_script: Option<String>,
17
- pub cleanup_script: Option<String>,
18
-
19
- #[ts(type = "Date")]
20
- #[schema(value_type = String, format = DateTime)]
21
- pub created_at: DateTime<Utc>,
22
- #[ts(type = "Date")]
23
- #[schema(value_type = String, format = DateTime)]
24
- pub updated_at: DateTime<Utc>,
25
- }
26
-
27
- #[derive(Debug, Deserialize, TS, ToSchema)]
28
- #[ts(export)]
29
- pub struct CreateProject {
30
- pub name: String,
31
- pub git_repo_path: String,
32
- pub use_existing_repo: bool,
33
- pub setup_script: Option<String>,
34
- pub dev_script: Option<String>,
35
- pub cleanup_script: Option<String>,
36
- }
37
-
38
- #[derive(Debug, Deserialize, TS, ToSchema)]
39
- #[ts(export)]
40
- pub struct UpdateProject {
41
- pub name: Option<String>,
42
- pub git_repo_path: Option<String>,
43
- pub setup_script: Option<String>,
44
- pub dev_script: Option<String>,
45
- pub cleanup_script: Option<String>,
46
- }
47
-
48
- #[derive(Debug, Serialize, TS, ToSchema)]
49
- #[ts(export)]
50
- pub struct ProjectWithBranch {
51
- pub id: Uuid,
52
- pub name: String,
53
- pub git_repo_path: String,
54
- pub setup_script: Option<String>,
55
- pub dev_script: Option<String>,
56
- pub cleanup_script: Option<String>,
57
- pub current_branch: Option<String>,
58
-
59
- #[ts(type = "Date")]
60
- #[schema(value_type = String, format = DateTime)]
61
- pub created_at: DateTime<Utc>,
62
- #[ts(type = "Date")]
63
- #[schema(value_type = String, format = DateTime)]
64
- pub updated_at: DateTime<Utc>,
65
- }
66
-
67
- #[derive(Debug, Serialize, TS, ToSchema)]
68
- #[ts(export)]
69
- pub struct SearchResult {
70
- pub path: String,
71
- pub is_file: bool,
72
- pub match_type: SearchMatchType,
73
- }
74
-
75
- #[derive(Debug, Serialize, TS, ToSchema)]
76
- #[ts(export)]
77
- pub enum SearchMatchType {
78
- FileName,
79
- DirectoryName,
80
- FullPath,
81
- }
82
-
83
- #[derive(Debug, Serialize, TS, ToSchema)]
84
- #[ts(export)]
85
- pub struct GitBranch {
86
- pub name: String,
87
- pub is_current: bool,
88
- pub is_remote: bool,
89
- #[ts(type = "Date")]
90
- pub last_commit_date: DateTime<Utc>,
91
- }
92
-
93
- #[derive(Debug, Deserialize, TS, ToSchema)]
94
- #[ts(export)]
95
- pub struct CreateBranch {
96
- pub name: String,
97
- pub base_branch: Option<String>,
98
- }
99
-
100
- impl Project {
101
- pub async fn find_all(pool: &SqlitePool) -> Result<Vec<Self>, sqlx::Error> {
102
- sqlx::query_as!(
103
- Project,
104
- r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, dev_script, cleanup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects ORDER BY created_at DESC"#
105
- )
106
- .fetch_all(pool)
107
- .await
108
- }
109
-
110
- pub async fn find_by_id(pool: &SqlitePool, id: Uuid) -> Result<Option<Self>, sqlx::Error> {
111
- sqlx::query_as!(
112
- Project,
113
- r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, dev_script, cleanup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE id = $1"#,
114
- id
115
- )
116
- .fetch_optional(pool)
117
- .await
118
- }
119
-
120
- pub async fn find_by_git_repo_path(
121
- pool: &SqlitePool,
122
- git_repo_path: &str,
123
- ) -> Result<Option<Self>, sqlx::Error> {
124
- sqlx::query_as!(
125
- Project,
126
- r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, dev_script, cleanup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE git_repo_path = $1"#,
127
- git_repo_path
128
- )
129
- .fetch_optional(pool)
130
- .await
131
- }
132
-
133
- pub async fn find_by_git_repo_path_excluding_id(
134
- pool: &SqlitePool,
135
- git_repo_path: &str,
136
- exclude_id: Uuid,
137
- ) -> Result<Option<Self>, sqlx::Error> {
138
- sqlx::query_as!(
139
- Project,
140
- r#"SELECT id as "id!: Uuid", name, git_repo_path, setup_script, dev_script, cleanup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>" FROM projects WHERE git_repo_path = $1 AND id != $2"#,
141
- git_repo_path,
142
- exclude_id
143
- )
144
- .fetch_optional(pool)
145
- .await
146
- }
147
-
148
- pub async fn create(
149
- pool: &SqlitePool,
150
- data: &CreateProject,
151
- project_id: Uuid,
152
- ) -> Result<Self, sqlx::Error> {
153
- sqlx::query_as!(
154
- Project,
155
- r#"INSERT INTO projects (id, name, git_repo_path, setup_script, dev_script, cleanup_script) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id as "id!: Uuid", name, git_repo_path, setup_script, dev_script, cleanup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
156
- project_id,
157
- data.name,
158
- data.git_repo_path,
159
- data.setup_script,
160
- data.dev_script,
161
- data.cleanup_script
162
- )
163
- .fetch_one(pool)
164
- .await
165
- }
166
-
167
- pub async fn update(
168
- pool: &SqlitePool,
169
- id: Uuid,
170
- name: String,
171
- git_repo_path: String,
172
- setup_script: Option<String>,
173
- dev_script: Option<String>,
174
- cleanup_script: Option<String>,
175
- ) -> Result<Self, sqlx::Error> {
176
- sqlx::query_as!(
177
- Project,
178
- r#"UPDATE projects SET name = $2, git_repo_path = $3, setup_script = $4, dev_script = $5, cleanup_script = $6 WHERE id = $1 RETURNING id as "id!: Uuid", name, git_repo_path, setup_script, dev_script, cleanup_script, created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
179
- id,
180
- name,
181
- git_repo_path,
182
- setup_script,
183
- dev_script,
184
- cleanup_script
185
- )
186
- .fetch_one(pool)
187
- .await
188
- }
189
-
190
- pub async fn delete(pool: &SqlitePool, id: Uuid) -> Result<u64, sqlx::Error> {
191
- let result = sqlx::query!("DELETE FROM projects WHERE id = $1", id)
192
- .execute(pool)
193
- .await?;
194
- Ok(result.rows_affected())
195
- }
196
-
197
- pub async fn exists(pool: &SqlitePool, id: Uuid) -> Result<bool, sqlx::Error> {
198
- let result = sqlx::query!(
199
- r#"
200
- SELECT COUNT(*) as "count!: i64"
201
- FROM projects
202
- WHERE id = $1
203
- "#,
204
- id
205
- )
206
- .fetch_one(pool)
207
- .await?;
208
-
209
- Ok(result.count > 0)
210
- }
211
-
212
- pub fn get_current_branch(&self) -> Result<String, git2::Error> {
213
- let repo = Repository::open(&self.git_repo_path)?;
214
- let head = repo.head()?;
215
-
216
- if let Some(branch_name) = head.shorthand() {
217
- Ok(branch_name.to_string())
218
- } else {
219
- Ok("HEAD".to_string())
220
- }
221
- }
222
-
223
- pub fn with_branch_info(self) -> ProjectWithBranch {
224
- let current_branch = self.get_current_branch().ok();
225
-
226
- ProjectWithBranch {
227
- id: self.id,
228
- name: self.name,
229
- git_repo_path: self.git_repo_path,
230
- setup_script: self.setup_script,
231
- dev_script: self.dev_script,
232
- cleanup_script: self.cleanup_script,
233
- current_branch,
234
- created_at: self.created_at,
235
- updated_at: self.updated_at,
236
- }
237
- }
238
-
239
- pub fn get_all_branches(&self) -> Result<Vec<GitBranch>, git2::Error> {
240
- let repo = Repository::open(&self.git_repo_path)?;
241
- let current_branch = self.get_current_branch().unwrap_or_default();
242
- let mut branches = Vec::new();
243
-
244
- // Helper function to get last commit date for a branch
245
- let get_last_commit_date = |branch: &git2::Branch| -> Result<DateTime<Utc>, git2::Error> {
246
- if let Some(target) = branch.get().target() {
247
- if let Ok(commit) = repo.find_commit(target) {
248
- let timestamp = commit.time().seconds();
249
- return Ok(DateTime::from_timestamp(timestamp, 0).unwrap_or_else(Utc::now));
250
- }
251
- }
252
- Ok(Utc::now()) // Default to now if we can't get the commit date
253
- };
254
-
255
- // Get local branches
256
- let local_branches = repo.branches(Some(BranchType::Local))?;
257
- for branch_result in local_branches {
258
- let (branch, _) = branch_result?;
259
- if let Some(name) = branch.name()? {
260
- let last_commit_date = get_last_commit_date(&branch)?;
261
- branches.push(GitBranch {
262
- name: name.to_string(),
263
- is_current: name == current_branch,
264
- is_remote: false,
265
- last_commit_date,
266
- });
267
- }
268
- }
269
-
270
- // Get remote branches
271
- let remote_branches = repo.branches(Some(BranchType::Remote))?;
272
- for branch_result in remote_branches {
273
- let (branch, _) = branch_result?;
274
- if let Some(name) = branch.name()? {
275
- // Skip remote HEAD references
276
- if !name.ends_with("/HEAD") {
277
- let last_commit_date = get_last_commit_date(&branch)?;
278
- branches.push(GitBranch {
279
- name: name.to_string(),
280
- is_current: false,
281
- is_remote: true,
282
- last_commit_date,
283
- });
284
- }
285
- }
286
- }
287
-
288
- // Sort branches: current first, then by most recent commit date
289
- branches.sort_by(|a, b| {
290
- if a.is_current && !b.is_current {
291
- std::cmp::Ordering::Less
292
- } else if !a.is_current && b.is_current {
293
- std::cmp::Ordering::Greater
294
- } else {
295
- // Sort by most recent commit date (newest first)
296
- b.last_commit_date.cmp(&a.last_commit_date)
297
- }
298
- });
299
-
300
- Ok(branches)
301
- }
302
-
303
- pub fn create_branch(
304
- &self,
305
- branch_name: &str,
306
- base_branch: Option<&str>,
307
- ) -> Result<GitBranch, git2::Error> {
308
- let repo = Repository::open(&self.git_repo_path)?;
309
-
310
- // Get the base branch reference - default to current branch if not specified
311
- let base_branch_name = match base_branch {
312
- Some(name) => name.to_string(),
313
- None => self
314
- .get_current_branch()
315
- .unwrap_or_else(|_| "HEAD".to_string()),
316
- };
317
-
318
- // Find the base commit
319
- let base_commit = if base_branch_name == "HEAD" {
320
- repo.head()?.peel_to_commit()?
321
- } else {
322
- // Try to find the branch as local first, then remote
323
- let base_ref = if let Ok(local_ref) =
324
- repo.find_reference(&format!("refs/heads/{}", base_branch_name))
325
- {
326
- local_ref
327
- } else if let Ok(remote_ref) =
328
- repo.find_reference(&format!("refs/remotes/{}", base_branch_name))
329
- {
330
- remote_ref
331
- } else {
332
- return Err(git2::Error::from_str(&format!(
333
- "Base branch '{}' not found",
334
- base_branch_name
335
- )));
336
- };
337
- base_ref.peel_to_commit()?
338
- };
339
-
340
- // Create the new branch
341
- let _new_branch = repo.branch(branch_name, &base_commit, false)?;
342
-
343
- // Get the commit date for the new branch (same as base commit)
344
- let last_commit_date = {
345
- let timestamp = base_commit.time().seconds();
346
- DateTime::from_timestamp(timestamp, 0).unwrap_or_else(Utc::now)
347
- };
348
-
349
- Ok(GitBranch {
350
- name: branch_name.to_string(),
351
- is_current: false,
352
- is_remote: false,
353
- last_commit_date,
354
- })
355
- }
356
- }
@@ -1,345 +0,0 @@
1
- use chrono::{DateTime, Utc};
2
- use serde::{Deserialize, Serialize};
3
- use sqlx::{FromRow, SqlitePool, Type};
4
- use ts_rs::TS;
5
- use utoipa::ToSchema;
6
- use uuid::Uuid;
7
-
8
- #[derive(Debug, Clone, Type, Serialize, Deserialize, PartialEq, TS, ToSchema)]
9
- #[sqlx(type_name = "task_status", rename_all = "lowercase")]
10
- #[serde(rename_all = "lowercase")]
11
- #[ts(export)]
12
- pub enum TaskStatus {
13
- Todo,
14
- InProgress,
15
- InReview,
16
- Done,
17
- Cancelled,
18
- }
19
-
20
- #[derive(Debug, Clone, FromRow, Serialize, Deserialize, TS, ToSchema)]
21
- #[ts(export)]
22
- pub struct Task {
23
- pub id: Uuid,
24
- pub project_id: Uuid, // Foreign key to Project
25
- pub title: String,
26
- pub description: Option<String>,
27
- pub status: TaskStatus,
28
- pub wish_id: String, // Required: Grouping field for task organization
29
- pub parent_task_attempt: Option<Uuid>, // Foreign key to parent TaskAttempt
30
- pub created_at: DateTime<Utc>,
31
- pub updated_at: DateTime<Utc>,
32
- }
33
-
34
- #[derive(Debug, Clone, Serialize, Deserialize, TS, ToSchema)]
35
- #[ts(export)]
36
- pub struct TaskWithAttemptStatus {
37
- pub id: Uuid,
38
- pub project_id: Uuid,
39
- pub title: String,
40
- pub description: Option<String>,
41
- pub status: TaskStatus,
42
- pub wish_id: String,
43
- pub parent_task_attempt: Option<Uuid>,
44
- pub created_at: DateTime<Utc>,
45
- pub updated_at: DateTime<Utc>,
46
- pub has_in_progress_attempt: bool,
47
- pub has_merged_attempt: bool,
48
- pub last_attempt_failed: bool,
49
- pub latest_attempt_executor: Option<String>,
50
- }
51
-
52
- #[derive(Debug, Deserialize, TS, ToSchema)]
53
- #[ts(export)]
54
- pub struct CreateTask {
55
- pub project_id: Uuid,
56
- pub title: String,
57
- pub description: Option<String>,
58
- pub wish_id: String, // Required: Wish grouping identifier
59
- pub parent_task_attempt: Option<Uuid>,
60
- }
61
-
62
- #[derive(Debug, Deserialize, TS, ToSchema)]
63
- #[ts(export)]
64
- pub struct CreateTaskAndStart {
65
- pub project_id: Uuid,
66
- pub title: String,
67
- pub description: Option<String>,
68
- pub wish_id: String, // Required: Wish grouping identifier
69
- pub parent_task_attempt: Option<Uuid>,
70
- pub executor: Option<crate::executor::ExecutorConfig>,
71
- }
72
-
73
- #[derive(Debug, Deserialize, TS, ToSchema)]
74
- #[ts(export)]
75
- pub struct UpdateTask {
76
- pub title: Option<String>,
77
- pub description: Option<String>,
78
- pub status: Option<TaskStatus>,
79
- pub wish_id: Option<String>, // Optional: Can reassign wish
80
- pub parent_task_attempt: Option<Uuid>,
81
- }
82
-
83
- impl Task {
84
- pub async fn find_by_project_id_with_attempt_status(
85
- pool: &SqlitePool,
86
- project_id: Uuid,
87
- ) -> Result<Vec<TaskWithAttemptStatus>, sqlx::Error> {
88
- let records = sqlx::query!(
89
- r#"SELECT
90
- t.id AS "id!: Uuid",
91
- t.project_id AS "project_id!: Uuid",
92
- t.title,
93
- t.description,
94
- t.status AS "status!: TaskStatus",
95
- t.wish_id,
96
- t.parent_task_attempt AS "parent_task_attempt: Uuid",
97
- t.created_at AS "created_at!: DateTime<Utc>",
98
- t.updated_at AS "updated_at!: DateTime<Utc>",
99
-
100
- CASE WHEN EXISTS (
101
- SELECT 1
102
- FROM task_attempts ta
103
- JOIN execution_processes ep
104
- ON ep.task_attempt_id = ta.id
105
- WHERE ta.task_id = t.id
106
- AND ep.status = 'running'
107
- AND ep.process_type IN ('setupscript','cleanupscript','codingagent')
108
- LIMIT 1
109
- ) THEN 1 ELSE 0 END AS "has_in_progress_attempt!: i64",
110
-
111
- CASE WHEN EXISTS (
112
- SELECT 1
113
- FROM task_attempts ta
114
- WHERE ta.task_id = t.id
115
- AND ta.merge_commit IS NOT NULL
116
- LIMIT 1
117
- ) THEN 1 ELSE 0 END AS "has_merged_attempt!: i64",
118
-
119
- CASE WHEN (
120
- SELECT ep.status
121
- FROM task_attempts ta
122
- JOIN execution_processes ep
123
- ON ep.task_attempt_id = ta.id
124
- WHERE ta.task_id = t.id
125
- AND ep.process_type IN ('setupscript','cleanupscript','codingagent')
126
- ORDER BY ep.created_at DESC
127
- LIMIT 1
128
- ) IN ('failed','killed') THEN 1 ELSE 0 END
129
- AS "last_attempt_failed!: i64",
130
-
131
- ( SELECT ta.executor
132
- FROM task_attempts ta
133
- WHERE ta.task_id = t.id
134
- ORDER BY ta.created_at DESC
135
- LIMIT 1
136
- ) AS "latest_attempt_executor"
137
-
138
- FROM tasks t
139
- WHERE t.project_id = $1
140
- ORDER BY t.created_at DESC"#,
141
- project_id
142
- )
143
- .fetch_all(pool)
144
- .await?;
145
-
146
- let tasks = records
147
- .into_iter()
148
- .map(|rec| TaskWithAttemptStatus {
149
- id: rec.id,
150
- project_id: rec.project_id,
151
- title: rec.title,
152
- description: rec.description,
153
- status: rec.status,
154
- wish_id: rec.wish_id,
155
- parent_task_attempt: rec.parent_task_attempt,
156
- created_at: rec.created_at,
157
- updated_at: rec.updated_at,
158
- has_in_progress_attempt: rec.has_in_progress_attempt != 0,
159
- has_merged_attempt: rec.has_merged_attempt != 0,
160
- last_attempt_failed: rec.last_attempt_failed != 0,
161
- latest_attempt_executor: rec.latest_attempt_executor,
162
- })
163
- .collect();
164
-
165
- Ok(tasks)
166
- }
167
-
168
- pub async fn find_by_id(pool: &SqlitePool, id: Uuid) -> Result<Option<Self>, sqlx::Error> {
169
- sqlx::query_as!(
170
- Task,
171
- r#"SELECT id as "id!: Uuid", project_id as "project_id!: Uuid", title, description, status as "status!: TaskStatus", wish_id, parent_task_attempt as "parent_task_attempt: Uuid", created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>"
172
- FROM tasks
173
- WHERE id = $1"#,
174
- id
175
- )
176
- .fetch_optional(pool)
177
- .await
178
- }
179
-
180
- pub async fn find_by_id_and_project_id(
181
- pool: &SqlitePool,
182
- id: Uuid,
183
- project_id: Uuid,
184
- ) -> Result<Option<Self>, sqlx::Error> {
185
- sqlx::query_as!(
186
- Task,
187
- r#"SELECT id as "id!: Uuid", project_id as "project_id!: Uuid", title, description, status as "status!: TaskStatus", wish_id, parent_task_attempt as "parent_task_attempt: Uuid", created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>"
188
- FROM tasks
189
- WHERE id = $1 AND project_id = $2"#,
190
- id,
191
- project_id
192
- )
193
- .fetch_optional(pool)
194
- .await
195
- }
196
-
197
- pub async fn create(
198
- pool: &SqlitePool,
199
- data: &CreateTask,
200
- task_id: Uuid,
201
- ) -> Result<Self, sqlx::Error> {
202
- sqlx::query_as!(
203
- Task,
204
- r#"INSERT INTO tasks (id, project_id, title, description, status, wish_id, parent_task_attempt)
205
- VALUES ($1, $2, $3, $4, $5, $6, $7)
206
- RETURNING id as "id!: Uuid", project_id as "project_id!: Uuid", title, description, status as "status!: TaskStatus", wish_id, parent_task_attempt as "parent_task_attempt: Uuid", created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
207
- task_id,
208
- data.project_id,
209
- data.title,
210
- data.description,
211
- TaskStatus::Todo as TaskStatus,
212
- data.wish_id,
213
- data.parent_task_attempt
214
- )
215
- .fetch_one(pool)
216
- .await
217
- }
218
-
219
- pub async fn update(
220
- pool: &SqlitePool,
221
- id: Uuid,
222
- project_id: Uuid,
223
- title: String,
224
- description: Option<String>,
225
- status: TaskStatus,
226
- wish_id: String,
227
- parent_task_attempt: Option<Uuid>,
228
- ) -> Result<Self, sqlx::Error> {
229
- let status_value = status as TaskStatus;
230
- sqlx::query_as!(
231
- Task,
232
- r#"UPDATE tasks
233
- SET title = $3, description = $4, status = $5, wish_id = $6, parent_task_attempt = $7
234
- WHERE id = $1 AND project_id = $2
235
- RETURNING id as "id!: Uuid", project_id as "project_id!: Uuid", title, description, status as "status!: TaskStatus", wish_id, parent_task_attempt as "parent_task_attempt: Uuid", created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
236
- id,
237
- project_id,
238
- title,
239
- description,
240
- status_value,
241
- wish_id,
242
- parent_task_attempt
243
- )
244
- .fetch_one(pool)
245
- .await
246
- }
247
-
248
- pub async fn update_status(
249
- pool: &SqlitePool,
250
- id: Uuid,
251
- project_id: Uuid,
252
- status: TaskStatus,
253
- ) -> Result<(), sqlx::Error> {
254
- let status_value = status as TaskStatus;
255
- sqlx::query!(
256
- "UPDATE tasks SET status = $3, updated_at = CURRENT_TIMESTAMP WHERE id = $1 AND project_id = $2",
257
- id,
258
- project_id,
259
- status_value
260
- )
261
- .execute(pool)
262
- .await?;
263
- Ok(())
264
- }
265
-
266
- pub async fn delete(pool: &SqlitePool, id: Uuid, project_id: Uuid) -> Result<u64, sqlx::Error> {
267
- let result = sqlx::query!(
268
- "DELETE FROM tasks WHERE id = $1 AND project_id = $2",
269
- id,
270
- project_id
271
- )
272
- .execute(pool)
273
- .await?;
274
- Ok(result.rows_affected())
275
- }
276
-
277
- pub async fn exists(
278
- pool: &SqlitePool,
279
- id: Uuid,
280
- project_id: Uuid,
281
- ) -> Result<bool, sqlx::Error> {
282
- let result = sqlx::query!(
283
- "SELECT id as \"id!: Uuid\" FROM tasks WHERE id = $1 AND project_id = $2",
284
- id,
285
- project_id
286
- )
287
- .fetch_optional(pool)
288
- .await?;
289
- Ok(result.is_some())
290
- }
291
-
292
- pub async fn find_related_tasks_by_attempt_id(
293
- pool: &SqlitePool,
294
- attempt_id: Uuid,
295
- project_id: Uuid,
296
- ) -> Result<Vec<Self>, sqlx::Error> {
297
- // Find both children and parent for this attempt
298
- sqlx::query_as!(
299
- Task,
300
- r#"SELECT DISTINCT t.id as "id!: Uuid", t.project_id as "project_id!: Uuid", t.title, t.description, t.status as "status!: TaskStatus", t.wish_id, t.parent_task_attempt as "parent_task_attempt: Uuid", t.created_at as "created_at!: DateTime<Utc>", t.updated_at as "updated_at!: DateTime<Utc>"
301
- FROM tasks t
302
- WHERE (
303
- -- Find children: tasks that have this attempt as parent
304
- t.parent_task_attempt = $1 AND t.project_id = $2
305
- ) OR (
306
- -- Find parent: task that owns the parent attempt of current task
307
- EXISTS (
308
- SELECT 1 FROM tasks current_task
309
- JOIN task_attempts parent_attempt ON current_task.parent_task_attempt = parent_attempt.id
310
- WHERE parent_attempt.task_id = t.id
311
- AND parent_attempt.id = $1
312
- AND current_task.project_id = $2
313
- )
314
- )
315
- -- Exclude the current task itself to prevent circular references
316
- AND t.id != (SELECT task_id FROM task_attempts WHERE id = $1)
317
- ORDER BY t.created_at DESC"#,
318
- attempt_id,
319
- project_id
320
- )
321
- .fetch_all(pool)
322
- .await
323
- }
324
-
325
- pub async fn link_existing_tasks(
326
- pool: &SqlitePool,
327
- child_task_id: Uuid,
328
- parent_task_attempt: Uuid,
329
- project_id: Uuid,
330
- ) -> Result<Self, sqlx::Error> {
331
- sqlx::query_as!(
332
- Task,
333
- r#"UPDATE tasks
334
- SET parent_task_attempt = $1, updated_at = CURRENT_TIMESTAMP
335
- WHERE id = $2 AND project_id = $3
336
- RETURNING id as "id!: Uuid", project_id as "project_id!: Uuid", title, description, status as "status!: TaskStatus", wish_id, parent_task_attempt as "parent_task_attempt: Uuid", created_at as "created_at!: DateTime<Utc>", updated_at as "updated_at!: DateTime<Utc>""#,
337
- parent_task_attempt,
338
- child_task_id,
339
- project_id
340
- )
341
- .fetch_one(pool)
342
- .await
343
- }
344
-
345
- }