automagik-forge 0.1.11 → 0.1.13

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/.cargo/config.toml +13 -0
  2. package/.claude/commands/commit.md +376 -0
  3. package/.claude/commands/prompt.md +871 -0
  4. package/.env.example +20 -0
  5. package/.github/actions/setup-node/action.yml +29 -0
  6. package/.github/images/automagik-logo.png +0 -0
  7. package/.github/workflows/pre-release.yml +470 -0
  8. package/.github/workflows/publish.yml +145 -0
  9. package/.github/workflows/test.yml +63 -0
  10. package/.mcp.json +57 -0
  11. package/AGENT.md +40 -0
  12. package/CLAUDE.md +40 -0
  13. package/CODE-OF-CONDUCT.md +89 -0
  14. package/Cargo.toml +19 -0
  15. package/Dockerfile +43 -0
  16. package/LICENSE +201 -0
  17. package/Makefile +97 -0
  18. package/README.md +447 -143
  19. package/backend/.sqlx/query-01b7e2bac1261d8be3d03c03df3e5220590da6c31c77f161074fc62752d63881.json +12 -0
  20. package/backend/.sqlx/query-03f2b02ba6dc5ea2b3cf6b1004caea0ad6bcc10ebd63f441d321a389f026e263.json +12 -0
  21. package/backend/.sqlx/query-0923b77d137a29fc54d399a873ff15fc4af894490bc65a4d344a7575cb0d8643.json +12 -0
  22. package/backend/.sqlx/query-0f808bcdb63c5f180836e448dd64c435c51758b2fc54a52ce9e67495b1ab200e.json +68 -0
  23. package/backend/.sqlx/query-1268afe9ca849daa6722e3df7ca8e9e61f0d37052e782bb5452ab8e1018d9b63.json +12 -0
  24. package/backend/.sqlx/query-1b082630a9622f8667ee7a9aba2c2d3176019a68c6bb83d33008594821415a57.json +12 -0
  25. package/backend/.sqlx/query-1c7b06ba1e112abf6b945a2ff08a0b40ec23f3738c2e7399f067b558cf8d490e.json +12 -0
  26. package/backend/.sqlx/query-1f619f01f46859a64ded531dd0ef61abacfe62e758abe7030a6aa745140b95ca.json +104 -0
  27. package/backend/.sqlx/query-1fca1ce14b4b20205364cd1f1f45ebe1d2e30cd745e59e189d56487b5639dfbb.json +12 -0
  28. package/backend/.sqlx/query-212828320e8d871ab9d83705a040b23bcf0393dc7252177fc539a74657f578ef.json +32 -0
  29. package/backend/.sqlx/query-290ce5c152be8d36e58ff42570f9157beb07ab9e77a03ec6fc30b4f56f9b8f6b.json +56 -0
  30. package/backend/.sqlx/query-2b471d2c2e8ffbe0cd42d2a91b814c0d79f9d09200f147e3cea33ba4ce673c8a.json +68 -0
  31. package/backend/.sqlx/query-354a48c705bb9bb2048c1b7f10fcb714e23f9db82b7a4ea6932486197b2ede6a.json +92 -0
  32. package/backend/.sqlx/query-36c9e3dd10648e94b949db5c91a774ecb1e10a899ef95da74066eccedca4d8b2.json +12 -0
  33. package/backend/.sqlx/query-36e4ba7bbd81b402d5a20b6005755eafbb174c8dda442081823406ac32809a94.json +56 -0
  34. package/backend/.sqlx/query-3a5b3c98a55ca183ab20c74708e3d7e579dda37972c059e7515c4ceee4bd8dd3.json +62 -0
  35. package/backend/.sqlx/query-3d0a1cabf2a52e9d90cdfd29c509ca89aeb448d0c1d2446c65cd43db40735e86.json +62 -0
  36. package/backend/.sqlx/query-3d6bd16fbce59efe30b7f67ea342e0e4ea6d1432389c02468ad79f1f742d4031.json +56 -0
  37. package/backend/.sqlx/query-4049ca413b285a05aca6b25385e9c8185575f01e9069e4e8581aa45d713f612f.json +32 -0
  38. package/backend/.sqlx/query-412bacd3477d86369082e90f52240407abce436cb81292d42b2dbe1e5c18eea1.json +104 -0
  39. package/backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json +62 -0
  40. package/backend/.sqlx/query-461cc1b0bb6fd909afc9dd2246e8526b3771cfbb0b22ae4b5d17b51af587b9e2.json +56 -0
  41. package/backend/.sqlx/query-58408c7a8cdeeda0bef359f1f9bd91299a339dc2b191462fc58c9736a56d5227.json +92 -0
  42. package/backend/.sqlx/query-5a886026d75d515c01f347cc203c8d99dd04c61dc468e2e4c5aa548436d13834.json +62 -0
  43. package/backend/.sqlx/query-5b902137b11022d2e1a5c4f6a9c83fec1a856c6a710aff831abd2382ede76b43.json +12 -0
  44. package/backend/.sqlx/query-5ed1238e52e59bb5f76c0f153fd99a14093f7ce2585bf9843585608f17ec575b.json +104 -0
  45. package/backend/.sqlx/query-6e8b860b14decfc2227dc57213f38442943d3fbef5c8418fd6b634c6e0f5e2ea.json +104 -0
  46. package/backend/.sqlx/query-6ec414276994c4ccb2433eaa5b1b342168557d17ddf5a52dac84cb1b59b9de8f.json +68 -0
  47. package/backend/.sqlx/query-6ecfa16d0cf825aacf233544b5baf151e9adfdca26c226ad71020d291fd802d5.json +62 -0
  48. package/backend/.sqlx/query-72509d252c39fce77520aa816cb2acbc1fb35dc2605e7be893610599b2427f2e.json +62 -0
  49. package/backend/.sqlx/query-75239b2da188f749707d77f3c1544332ca70db3d6d6743b2601dc0d167536437.json +62 -0
  50. package/backend/.sqlx/query-83d10e29f8478aff33434f9ac67068e013b888b953a2657e2bb72a6f619d04f2.json +50 -0
  51. package/backend/.sqlx/query-8610803360ea18b9b9d078a6981ea56abfbfe84e6354fc1d5ae4c622e01410ed.json +68 -0
  52. package/backend/.sqlx/query-86d03eb70eef39c59296416867f2ee66c9f7cd8b7f961fbda2f89fc0a1c442c2.json +12 -0
  53. package/backend/.sqlx/query-87d0feb5a6b442bad9c60068ea7569599cc6fc91a0e2692ecb42e93b03201b9d.json +68 -0
  54. package/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json +12 -0
  55. package/backend/.sqlx/query-8f01ebd64bdcde6a090479f14810d73ba23020e76fd70854ac57f2da251702c3.json +12 -0
  56. package/backend/.sqlx/query-90fd607fcb2dca72239ff25e618e21e174b195991eaa33722cbf5f76da84cfab.json +62 -0
  57. package/backend/.sqlx/query-92e8bdbcd80c5ff3db7a35cf79492048803ef305cbdef0d0a1fe5dc881ca8c71.json +104 -0
  58. package/backend/.sqlx/query-93a1605f90e9672dad29b472b6ad85fa9a55ea3ffa5abcb8724b09d61be254ca.json +20 -0
  59. package/backend/.sqlx/query-9472c8fb477958167f5fae40b85ac44252468c5226b2cdd7770f027332eed6d7.json +104 -0
  60. package/backend/.sqlx/query-96036c4f9e0f48bdc5a4a4588f0c5f288ac7aaa5425cac40fc33f337e1a351f2.json +56 -0
  61. package/backend/.sqlx/query-9edb2c01e91fd0f0fe7b56e988c7ae0393150f50be3f419a981e035c0121dfc7.json +104 -0
  62. package/backend/.sqlx/query-a157cf00616f703bfba21927f1eb1c9eec2a81c02da15f66efdba0b6c375de1b.json +26 -0
  63. package/backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json +62 -0
  64. package/backend/.sqlx/query-a5ba908419fb3e456bdd2daca41ba06cc3212ffffb8520fc7dbbcc8b60ada314.json +12 -0
  65. package/backend/.sqlx/query-a6d2961718dbc3b1a925e549f49a159c561bef58c105529275f274b27e2eba5b.json +104 -0
  66. package/backend/.sqlx/query-a9e93d5b09b29faf66e387e4d7596a792d81e75c4d3726e83c2963e8d7c9b56f.json +104 -0
  67. package/backend/.sqlx/query-ac5247c8d7fb86e4650c4b0eb9420031614c831b7b085083bac20c1af314c538.json +12 -0
  68. package/backend/.sqlx/query-afef9467be74c411c4cb119a8b2b1aea53049877dfc30cc60b486134ba4b4c9f.json +68 -0
  69. package/backend/.sqlx/query-b2b2c6b4d0b1a347b5c4cb63c3a46a265d4db53be9554989a814b069d0af82f2.json +62 -0
  70. package/backend/.sqlx/query-c50d2ff0b12e5bcc81e371089ee2d007e233e7db93aefba4fef08e7aa68f5ab7.json +20 -0
  71. package/backend/.sqlx/query-c614e6056b244ca07f1b9d44e7edc9d5819225c6f8d9e077070c6e518a17f50b.json +12 -0
  72. package/backend/.sqlx/query-c67259be8bf4ee0cfd32167b2aa3b7fe9192809181a8171bf1c2d6df731967ae.json +12 -0
  73. package/backend/.sqlx/query-d2d0a1b985ebbca6a2b3e882a221a219f3199890fa640afc946ef1a792d6d8de.json +12 -0
  74. package/backend/.sqlx/query-d30aa5786757f32bf2b9c5fe51a45e506c71c28c5994e430d9b0546adb15ffa2.json +20 -0
  75. package/backend/.sqlx/query-d3b9ea1de1576af71b312924ce7f4ea8ae5dbe2ac138ea3b4470f2d5cd734846.json +12 -0
  76. package/backend/.sqlx/query-ed8456646fa69ddd412441955f06ff22bfb790f29466450735e0b8bb1bc4ec94.json +12 -0
  77. package/backend/Cargo.toml +71 -0
  78. package/backend/build.rs +32 -0
  79. package/backend/migrations/20250617183714_init.sql +44 -0
  80. package/backend/migrations/20250620212427_execution_processes.sql +25 -0
  81. package/backend/migrations/20250620214100_remove_stdout_stderr_from_task_attempts.sql +28 -0
  82. package/backend/migrations/20250621120000_relate_activities_to_execution_processes.sql +23 -0
  83. package/backend/migrations/20250623120000_executor_sessions.sql +17 -0
  84. package/backend/migrations/20250623130000_add_executor_type_to_execution_processes.sql +4 -0
  85. package/backend/migrations/20250625000000_add_dev_script_to_projects.sql +4 -0
  86. package/backend/migrations/20250701000000_add_branch_to_task_attempts.sql +2 -0
  87. package/backend/migrations/20250701000001_add_pr_tracking_to_task_attempts.sql +5 -0
  88. package/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql +2 -0
  89. package/backend/migrations/20250708000000_add_base_branch_to_task_attempts.sql +2 -0
  90. package/backend/migrations/20250709000000_add_worktree_deleted_flag.sql +2 -0
  91. package/backend/migrations/20250710000000_add_setup_completion.sql +3 -0
  92. package/backend/migrations/20250715154859_add_task_templates.sql +25 -0
  93. package/backend/migrations/20250716143725_add_default_templates.sql +174 -0
  94. package/backend/migrations/20250716161432_update_executor_names_to_kebab_case.sql +20 -0
  95. package/backend/migrations/20250716170000_add_parent_task_to_tasks.sql +7 -0
  96. package/backend/migrations/20250717000000_drop_task_attempt_activities.sql +9 -0
  97. package/backend/migrations/20250719000000_add_cleanup_script_to_projects.sql +2 -0
  98. package/backend/migrations/20250720000000_add_cleanupscript_to_process_type_constraint.sql +25 -0
  99. package/backend/migrations/20250723000000_add_wish_to_tasks.sql +7 -0
  100. package/backend/migrations/20250724000000_remove_unique_wish_constraint.sql +5 -0
  101. package/backend/scripts/toast-notification.ps1 +23 -0
  102. package/backend/sounds/abstract-sound1.wav +0 -0
  103. package/backend/sounds/abstract-sound2.wav +0 -0
  104. package/backend/sounds/abstract-sound3.wav +0 -0
  105. package/backend/sounds/abstract-sound4.wav +0 -0
  106. package/backend/sounds/cow-mooing.wav +0 -0
  107. package/backend/sounds/phone-vibration.wav +0 -0
  108. package/backend/sounds/rooster.wav +0 -0
  109. package/backend/src/app_state.rs +218 -0
  110. package/backend/src/bin/generate_types.rs +189 -0
  111. package/backend/src/bin/mcp_task_server.rs +191 -0
  112. package/backend/src/execution_monitor.rs +1193 -0
  113. package/backend/src/executor.rs +1053 -0
  114. package/backend/src/executors/amp.rs +697 -0
  115. package/backend/src/executors/ccr.rs +91 -0
  116. package/backend/src/executors/charm_opencode.rs +113 -0
  117. package/backend/src/executors/claude.rs +887 -0
  118. package/backend/src/executors/cleanup_script.rs +124 -0
  119. package/backend/src/executors/dev_server.rs +53 -0
  120. package/backend/src/executors/echo.rs +79 -0
  121. package/backend/src/executors/gemini/config.rs +67 -0
  122. package/backend/src/executors/gemini/streaming.rs +363 -0
  123. package/backend/src/executors/gemini.rs +765 -0
  124. package/backend/src/executors/mod.rs +23 -0
  125. package/backend/src/executors/opencode_ai.rs +113 -0
  126. package/backend/src/executors/setup_script.rs +130 -0
  127. package/backend/src/executors/sst_opencode/filter.rs +184 -0
  128. package/backend/src/executors/sst_opencode/tools.rs +139 -0
  129. package/backend/src/executors/sst_opencode.rs +756 -0
  130. package/backend/src/lib.rs +45 -0
  131. package/backend/src/main.rs +324 -0
  132. package/backend/src/mcp/mod.rs +1 -0
  133. package/backend/src/mcp/task_server.rs +850 -0
  134. package/backend/src/middleware/mod.rs +3 -0
  135. package/backend/src/middleware/model_loaders.rs +242 -0
  136. package/backend/src/models/api_response.rs +36 -0
  137. package/backend/src/models/config.rs +375 -0
  138. package/backend/src/models/execution_process.rs +430 -0
  139. package/backend/src/models/executor_session.rs +225 -0
  140. package/backend/src/models/mod.rs +12 -0
  141. package/backend/src/models/project.rs +356 -0
  142. package/backend/src/models/task.rs +345 -0
  143. package/backend/src/models/task_attempt.rs +1214 -0
  144. package/backend/src/models/task_template.rs +146 -0
  145. package/backend/src/openapi.rs +93 -0
  146. package/backend/src/routes/auth.rs +297 -0
  147. package/backend/src/routes/config.rs +385 -0
  148. package/backend/src/routes/filesystem.rs +228 -0
  149. package/backend/src/routes/health.rs +16 -0
  150. package/backend/src/routes/mod.rs +9 -0
  151. package/backend/src/routes/projects.rs +562 -0
  152. package/backend/src/routes/stream.rs +244 -0
  153. package/backend/src/routes/task_attempts.rs +1172 -0
  154. package/backend/src/routes/task_templates.rs +229 -0
  155. package/backend/src/routes/tasks.rs +353 -0
  156. package/backend/src/services/analytics.rs +216 -0
  157. package/backend/src/services/git_service.rs +1321 -0
  158. package/backend/src/services/github_service.rs +307 -0
  159. package/backend/src/services/mod.rs +13 -0
  160. package/backend/src/services/notification_service.rs +263 -0
  161. package/backend/src/services/pr_monitor.rs +214 -0
  162. package/backend/src/services/process_service.rs +940 -0
  163. package/backend/src/utils/path.rs +96 -0
  164. package/backend/src/utils/shell.rs +19 -0
  165. package/backend/src/utils/text.rs +24 -0
  166. package/backend/src/utils/worktree_manager.rs +578 -0
  167. package/backend/src/utils.rs +125 -0
  168. package/backend/test.db +0 -0
  169. package/build-npm-package.sh +61 -0
  170. package/dev_assets_seed/config.json +19 -0
  171. package/frontend/.eslintrc.json +25 -0
  172. package/frontend/.prettierrc.json +8 -0
  173. package/frontend/components.json +17 -0
  174. package/frontend/index.html +19 -0
  175. package/frontend/package-lock.json +7321 -0
  176. package/frontend/package.json +61 -0
  177. package/frontend/postcss.config.js +6 -0
  178. package/frontend/public/android-chrome-192x192.png +0 -0
  179. package/frontend/public/android-chrome-512x512.png +0 -0
  180. package/frontend/public/apple-touch-icon.png +0 -0
  181. package/frontend/public/automagik-forge-logo-dark.svg +3 -0
  182. package/frontend/public/automagik-forge-logo.svg +3 -0
  183. package/frontend/public/automagik-forge-screenshot-overview.png +0 -0
  184. package/frontend/public/favicon-16x16.png +0 -0
  185. package/frontend/public/favicon-32x32.png +0 -0
  186. package/frontend/public/favicon.ico +0 -0
  187. package/frontend/public/site.webmanifest +1 -0
  188. package/frontend/public/viba-kanban-favicon.png +0 -0
  189. package/frontend/src/App.tsx +157 -0
  190. package/frontend/src/components/DisclaimerDialog.tsx +106 -0
  191. package/frontend/src/components/GitHubLoginDialog.tsx +314 -0
  192. package/frontend/src/components/OnboardingDialog.tsx +185 -0
  193. package/frontend/src/components/PrivacyOptInDialog.tsx +130 -0
  194. package/frontend/src/components/ProvidePatDialog.tsx +98 -0
  195. package/frontend/src/components/TaskTemplateManager.tsx +336 -0
  196. package/frontend/src/components/config-provider.tsx +119 -0
  197. package/frontend/src/components/context/TaskDetailsContextProvider.tsx +470 -0
  198. package/frontend/src/components/context/taskDetailsContext.ts +125 -0
  199. package/frontend/src/components/keyboard-shortcuts-demo.tsx +35 -0
  200. package/frontend/src/components/layout/navbar.tsx +86 -0
  201. package/frontend/src/components/logo.tsx +44 -0
  202. package/frontend/src/components/projects/ProjectCard.tsx +155 -0
  203. package/frontend/src/components/projects/project-detail.tsx +251 -0
  204. package/frontend/src/components/projects/project-form-fields.tsx +238 -0
  205. package/frontend/src/components/projects/project-form.tsx +301 -0
  206. package/frontend/src/components/projects/project-list.tsx +200 -0
  207. package/frontend/src/components/projects/projects-page.tsx +20 -0
  208. package/frontend/src/components/tasks/BranchSelector.tsx +169 -0
  209. package/frontend/src/components/tasks/DeleteFileConfirmationDialog.tsx +94 -0
  210. package/frontend/src/components/tasks/EditorSelectionDialog.tsx +119 -0
  211. package/frontend/src/components/tasks/TaskCard.tsx +154 -0
  212. package/frontend/src/components/tasks/TaskDetails/CollapsibleToolbar.tsx +33 -0
  213. package/frontend/src/components/tasks/TaskDetails/DiffCard.tsx +109 -0
  214. package/frontend/src/components/tasks/TaskDetails/DiffChunkSection.tsx +135 -0
  215. package/frontend/src/components/tasks/TaskDetails/DiffFile.tsx +296 -0
  216. package/frontend/src/components/tasks/TaskDetails/DiffTab.tsx +32 -0
  217. package/frontend/src/components/tasks/TaskDetails/DisplayConversationEntry.tsx +392 -0
  218. package/frontend/src/components/tasks/TaskDetails/LogsTab/Conversation.tsx +256 -0
  219. package/frontend/src/components/tasks/TaskDetails/LogsTab/ConversationEntry.tsx +56 -0
  220. package/frontend/src/components/tasks/TaskDetails/LogsTab/NormalizedConversationViewer.tsx +92 -0
  221. package/frontend/src/components/tasks/TaskDetails/LogsTab/Prompt.tsx +22 -0
  222. package/frontend/src/components/tasks/TaskDetails/LogsTab/SetupScriptRunning.tsx +49 -0
  223. package/frontend/src/components/tasks/TaskDetails/LogsTab.tsx +186 -0
  224. package/frontend/src/components/tasks/TaskDetails/ProcessesTab.tsx +288 -0
  225. package/frontend/src/components/tasks/TaskDetails/RelatedTasksTab.tsx +216 -0
  226. package/frontend/src/components/tasks/TaskDetails/TabNavigation.tsx +93 -0
  227. package/frontend/src/components/tasks/TaskDetailsHeader.tsx +169 -0
  228. package/frontend/src/components/tasks/TaskDetailsPanel.tsx +126 -0
  229. package/frontend/src/components/tasks/TaskDetailsToolbar.tsx +302 -0
  230. package/frontend/src/components/tasks/TaskFollowUpSection.tsx +130 -0
  231. package/frontend/src/components/tasks/TaskFormDialog.tsx +400 -0
  232. package/frontend/src/components/tasks/TaskKanbanBoard.tsx +180 -0
  233. package/frontend/src/components/tasks/Toolbar/CreateAttempt.tsx +259 -0
  234. package/frontend/src/components/tasks/Toolbar/CreatePRDialog.tsx +243 -0
  235. package/frontend/src/components/tasks/Toolbar/CurrentAttempt.tsx +899 -0
  236. package/frontend/src/components/tasks/index.ts +2 -0
  237. package/frontend/src/components/theme-provider.tsx +82 -0
  238. package/frontend/src/components/theme-toggle.tsx +36 -0
  239. package/frontend/src/components/ui/alert.tsx +59 -0
  240. package/frontend/src/components/ui/auto-expanding-textarea.tsx +70 -0
  241. package/frontend/src/components/ui/badge.tsx +36 -0
  242. package/frontend/src/components/ui/button.tsx +56 -0
  243. package/frontend/src/components/ui/card.tsx +86 -0
  244. package/frontend/src/components/ui/checkbox.tsx +44 -0
  245. package/frontend/src/components/ui/chip.tsx +25 -0
  246. package/frontend/src/components/ui/dialog.tsx +124 -0
  247. package/frontend/src/components/ui/dropdown-menu.tsx +198 -0
  248. package/frontend/src/components/ui/file-search-textarea.tsx +292 -0
  249. package/frontend/src/components/ui/folder-picker.tsx +279 -0
  250. package/frontend/src/components/ui/input.tsx +25 -0
  251. package/frontend/src/components/ui/label.tsx +24 -0
  252. package/frontend/src/components/ui/loader.tsx +26 -0
  253. package/frontend/src/components/ui/markdown-renderer.tsx +75 -0
  254. package/frontend/src/components/ui/select.tsx +160 -0
  255. package/frontend/src/components/ui/separator.tsx +31 -0
  256. package/frontend/src/components/ui/shadcn-io/kanban/index.tsx +185 -0
  257. package/frontend/src/components/ui/table.tsx +117 -0
  258. package/frontend/src/components/ui/tabs.tsx +53 -0
  259. package/frontend/src/components/ui/textarea.tsx +22 -0
  260. package/frontend/src/components/ui/tooltip.tsx +28 -0
  261. package/frontend/src/hooks/useNormalizedConversation.ts +440 -0
  262. package/frontend/src/index.css +225 -0
  263. package/frontend/src/lib/api.ts +630 -0
  264. package/frontend/src/lib/keyboard-shortcuts.ts +266 -0
  265. package/frontend/src/lib/responsive-config.ts +70 -0
  266. package/frontend/src/lib/types.ts +39 -0
  267. package/frontend/src/lib/utils.ts +10 -0
  268. package/frontend/src/main.tsx +50 -0
  269. package/frontend/src/pages/McpServers.tsx +418 -0
  270. package/frontend/src/pages/Settings.tsx +610 -0
  271. package/frontend/src/pages/project-tasks.tsx +575 -0
  272. package/frontend/src/pages/projects.tsx +18 -0
  273. package/frontend/src/vite-env.d.ts +1 -0
  274. package/frontend/tailwind.config.js +125 -0
  275. package/frontend/tsconfig.json +26 -0
  276. package/frontend/tsconfig.node.json +10 -0
  277. package/frontend/vite.config.ts +33 -0
  278. package/npx-cli/README.md +159 -0
  279. package/npx-cli/automagik-forge-0.0.55.tgz +0 -0
  280. package/npx-cli/automagik-forge-0.1.0.tgz +0 -0
  281. package/{dist/linux-x64/automagik-forge.zip → npx-cli/automagik-forge-0.1.10.tgz} +0 -0
  282. package/npx-cli/package.json +17 -0
  283. package/npx-cli/vibe-kanban-0.0.55.tgz +0 -0
  284. package/package.json +23 -13
  285. package/pnpm-workspace.yaml +2 -0
  286. package/rust-toolchain.toml +11 -0
  287. package/rustfmt.toml +3 -0
  288. package/scripts/load-env.js +43 -0
  289. package/scripts/mcp_test.js +374 -0
  290. package/scripts/prepare-db.js +45 -0
  291. package/scripts/setup-dev-environment.js +274 -0
  292. package/scripts/start-mcp-sse.js +70 -0
  293. package/scripts/test-debug.js +32 -0
  294. package/scripts/test-mcp-sse.js +138 -0
  295. package/scripts/test-simple.js +44 -0
  296. package/scripts/test-wish-final.js +179 -0
  297. package/scripts/test-wish-system.js +221 -0
  298. package/shared/types.ts +182 -0
  299. package/test-npm-package.sh +42 -0
  300. package/dist/linux-x64/automagik-forge-mcp.zip +0 -0
  301. /package/{bin → npx-cli/bin}/cli.js +0 -0
@@ -0,0 +1,575 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { useNavigate, useParams } from 'react-router-dom';
3
+ import { Button } from '@/components/ui/button';
4
+ import { Card, CardContent } from '@/components/ui/card';
5
+ import { Input } from '@/components/ui/input';
6
+ import { FolderOpen, Plus, Settings, LibraryBig, Globe2 } from 'lucide-react';
7
+ import { Loader } from '@/components/ui/loader';
8
+ import { projectsApi, tasksApi, templatesApi } from '@/lib/api';
9
+ import { TaskFormDialog } from '@/components/tasks/TaskFormDialog';
10
+ import { ProjectForm } from '@/components/projects/project-form';
11
+ import { TaskTemplateManager } from '@/components/TaskTemplateManager';
12
+ import { useKeyboardShortcuts } from '@/lib/keyboard-shortcuts';
13
+ import {
14
+ DropdownMenu,
15
+ DropdownMenuContent,
16
+ DropdownMenuItem,
17
+ DropdownMenuTrigger,
18
+ DropdownMenuSeparator,
19
+ } from '@/components/ui/dropdown-menu';
20
+ import {
21
+ Dialog,
22
+ DialogContent,
23
+ DialogHeader,
24
+ DialogTitle,
25
+ DialogFooter,
26
+ } from '@/components/ui/dialog';
27
+
28
+ import {
29
+ getKanbanSectionClasses,
30
+ getMainContainerClasses,
31
+ } from '@/lib/responsive-config';
32
+
33
+ import TaskKanbanBoard from '@/components/tasks/TaskKanbanBoard';
34
+ import { TaskDetailsPanel } from '@/components/tasks/TaskDetailsPanel';
35
+ import type {
36
+ CreateTaskAndStart,
37
+ ExecutorConfig,
38
+ ProjectWithBranch,
39
+ TaskStatus,
40
+ TaskWithAttemptStatus,
41
+ TaskTemplate,
42
+ } from 'shared/types';
43
+ import type { DragEndEvent } from '@/components/ui/shadcn-io/kanban';
44
+
45
+ type Task = TaskWithAttemptStatus;
46
+
47
+ export function ProjectTasks() {
48
+ const { projectId, taskId } = useParams<{
49
+ projectId: string;
50
+ taskId?: string;
51
+ }>();
52
+ const navigate = useNavigate();
53
+ const [tasks, setTasks] = useState<Task[]>([]);
54
+ const [project, setProject] = useState<ProjectWithBranch | null>(null);
55
+ const [loading, setLoading] = useState(true);
56
+ const [error, setError] = useState<string | null>(null);
57
+ const [isTaskDialogOpen, setIsTaskDialogOpen] = useState(false);
58
+ const [editingTask, setEditingTask] = useState<Task | null>(null);
59
+ const [isProjectSettingsOpen, setIsProjectSettingsOpen] = useState(false);
60
+ const [searchQuery, setSearchQuery] = useState('');
61
+ const [templates, setTemplates] = useState<TaskTemplate[]>([]);
62
+ const [selectedTemplate, setSelectedTemplate] = useState<TaskTemplate | null>(
63
+ null
64
+ );
65
+
66
+ // Template management state
67
+ const [isTemplateManagerOpen, setIsTemplateManagerOpen] = useState(false);
68
+
69
+ // Panel state
70
+ const [selectedTask, setSelectedTask] = useState<Task | null>(null);
71
+ const [isPanelOpen, setIsPanelOpen] = useState(false);
72
+
73
+ // Define task creation handler
74
+ const handleCreateNewTask = useCallback(() => {
75
+ setEditingTask(null);
76
+ setSelectedTemplate(null);
77
+ setIsTaskDialogOpen(true);
78
+ }, []);
79
+
80
+ // Handle template selection
81
+ const handleTemplateSelect = useCallback((template: TaskTemplate) => {
82
+ setEditingTask(null);
83
+ setSelectedTemplate(template);
84
+ setIsTaskDialogOpen(true);
85
+ }, []);
86
+
87
+ const handleOpenInIDE = useCallback(async () => {
88
+ if (!projectId) return;
89
+
90
+ try {
91
+ await projectsApi.openEditor(projectId);
92
+ } catch (error) {
93
+ console.error('Failed to open project in IDE:', error);
94
+ setError('Failed to open project in IDE');
95
+ }
96
+ }, [projectId]);
97
+
98
+ const fetchProject = useCallback(async () => {
99
+ try {
100
+ const result = await projectsApi.getWithBranch(projectId!);
101
+ setProject(result);
102
+ } catch (err) {
103
+ setError('Failed to load project');
104
+ }
105
+ }, [projectId, navigate]);
106
+
107
+ const fetchTemplates = useCallback(async () => {
108
+ if (!projectId) return;
109
+
110
+ try {
111
+ const [projectTemplates, globalTemplates] = await Promise.all([
112
+ templatesApi.listByProject(projectId),
113
+ templatesApi.listGlobal(),
114
+ ]);
115
+
116
+ // Combine templates with project templates first
117
+ setTemplates([...projectTemplates, ...globalTemplates]);
118
+ } catch (err) {
119
+ console.error('Failed to fetch templates:', err);
120
+ }
121
+ }, [projectId]);
122
+
123
+ // Template management handlers
124
+ const handleOpenTemplateManager = useCallback(() => {
125
+ setIsTemplateManagerOpen(true);
126
+ }, []);
127
+
128
+ const handleCloseTemplateManager = useCallback(() => {
129
+ setIsTemplateManagerOpen(false);
130
+ fetchTemplates(); // Refresh templates list when closing
131
+ }, [fetchTemplates]);
132
+
133
+ const fetchTasks = useCallback(
134
+ async (skipLoading = false) => {
135
+ try {
136
+ if (!skipLoading) {
137
+ setLoading(true);
138
+ }
139
+ const result = await tasksApi.getAll(projectId!);
140
+ // Only update if data has actually changed
141
+ setTasks((prevTasks) => {
142
+ const newTasks = result;
143
+ if (JSON.stringify(prevTasks) === JSON.stringify(newTasks)) {
144
+ return prevTasks; // Return same reference to prevent re-render
145
+ }
146
+
147
+ setSelectedTask((prev) => {
148
+ if (!prev) return prev;
149
+
150
+ const updatedSelectedTask = newTasks.find(
151
+ (task) => task.id === prev.id
152
+ );
153
+
154
+ if (JSON.stringify(prev) === JSON.stringify(updatedSelectedTask))
155
+ return prev;
156
+ return updatedSelectedTask || prev;
157
+ });
158
+
159
+ return newTasks;
160
+ });
161
+ } catch (err) {
162
+ setError('Failed to load tasks');
163
+ } finally {
164
+ if (!skipLoading) {
165
+ setLoading(false);
166
+ }
167
+ }
168
+ },
169
+ [projectId]
170
+ );
171
+
172
+ const handleCreateTask = useCallback(
173
+ async (title: string, description: string) => {
174
+ try {
175
+ const createdTask = await tasksApi.create(projectId!, {
176
+ project_id: projectId!,
177
+ title,
178
+ description: description || null,
179
+ wish_id: title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''),
180
+ parent_task_attempt: null,
181
+ });
182
+ await fetchTasks();
183
+ // Open the newly created task in the details panel
184
+ navigate(`/projects/${projectId}/tasks/${createdTask.id}`, {
185
+ replace: true,
186
+ });
187
+ } catch (err) {
188
+ setError('Failed to create task');
189
+ }
190
+ },
191
+ [projectId, fetchTasks, navigate]
192
+ );
193
+
194
+ const handleCreateAndStartTask = useCallback(
195
+ async (title: string, description: string, executor?: ExecutorConfig) => {
196
+ try {
197
+ const payload: CreateTaskAndStart = {
198
+ project_id: projectId!,
199
+ title,
200
+ description: description || null,
201
+ wish_id: title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''),
202
+ parent_task_attempt: null,
203
+ executor: executor || null,
204
+ };
205
+ const result = await tasksApi.createAndStart(projectId!, payload);
206
+ await fetchTasks();
207
+ // Open the newly created task in the details panel
208
+ handleViewTaskDetails(result);
209
+ } catch (err) {
210
+ setError('Failed to create and start task');
211
+ }
212
+ },
213
+ [projectId, fetchTasks]
214
+ );
215
+
216
+ const handleUpdateTask = useCallback(
217
+ async (title: string, description: string, status: TaskStatus) => {
218
+ if (!editingTask) return;
219
+
220
+ try {
221
+ await tasksApi.update(projectId!, editingTask.id, {
222
+ title,
223
+ description: description || null,
224
+ status,
225
+ wish_id: editingTask.wish_id, // Keep existing wish_id
226
+ parent_task_attempt: null,
227
+ });
228
+ await fetchTasks();
229
+ setEditingTask(null);
230
+ } catch (err) {
231
+ setError('Failed to update task');
232
+ }
233
+ },
234
+ [projectId, editingTask, fetchTasks]
235
+ );
236
+
237
+ const handleDeleteTask = useCallback(
238
+ async (taskId: string) => {
239
+ if (!confirm('Are you sure you want to delete this task?')) return;
240
+
241
+ try {
242
+ await tasksApi.delete(projectId!, taskId);
243
+ await fetchTasks();
244
+ } catch (error) {
245
+ setError('Failed to delete task');
246
+ }
247
+ },
248
+ [projectId, fetchTasks]
249
+ );
250
+
251
+ const handleEditTask = useCallback((task: Task) => {
252
+ setEditingTask(task);
253
+ setIsTaskDialogOpen(true);
254
+ }, []);
255
+
256
+ const handleViewTaskDetails = useCallback(
257
+ (task: Task) => {
258
+ // setSelectedTask(task);
259
+ // setIsPanelOpen(true);
260
+ // Update URL to include task ID
261
+ navigate(`/projects/${projectId}/tasks/${task.id}`, { replace: true });
262
+ },
263
+ [projectId, navigate]
264
+ );
265
+
266
+ const handleClosePanel = useCallback(() => {
267
+ // setIsPanelOpen(false);
268
+ // setSelectedTask(null);
269
+ // Remove task ID from URL when closing panel
270
+ navigate(`/projects/${projectId}/tasks`, { replace: true });
271
+ }, [projectId, navigate]);
272
+
273
+ const handleProjectSettingsSuccess = useCallback(() => {
274
+ setIsProjectSettingsOpen(false);
275
+ fetchProject(); // Refresh project data after settings change
276
+ }, [fetchProject]);
277
+
278
+ const handleDragEnd = useCallback(
279
+ async (event: DragEndEvent) => {
280
+ const { active, over } = event;
281
+
282
+ if (!over || !active.data.current) return;
283
+
284
+ const taskId = active.id as string;
285
+ const newStatus = over.id as Task['status'];
286
+ const task = tasks.find((t) => t.id === taskId);
287
+
288
+ if (!task || task.status === newStatus) return;
289
+
290
+ // Optimistically update the UI immediately
291
+ const previousStatus = task.status;
292
+ setTasks((prev) =>
293
+ prev.map((t) => (t.id === taskId ? { ...t, status: newStatus } : t))
294
+ );
295
+
296
+ try {
297
+ await tasksApi.update(projectId!, taskId, {
298
+ title: task.title,
299
+ description: task.description,
300
+ status: newStatus,
301
+ wish_id: task.wish_id, // Keep existing wish_id
302
+ parent_task_attempt: task.parent_task_attempt,
303
+ });
304
+ } catch (err) {
305
+ // Revert the optimistic update if the API call failed
306
+ setTasks((prev) =>
307
+ prev.map((t) =>
308
+ t.id === taskId ? { ...t, status: previousStatus } : t
309
+ )
310
+ );
311
+ setError('Failed to update task status');
312
+ }
313
+ },
314
+ [projectId, tasks]
315
+ );
316
+
317
+ // Setup keyboard shortcuts
318
+ useKeyboardShortcuts({
319
+ navigate,
320
+ currentPath: `/projects/${projectId}/tasks`,
321
+ hasOpenDialog:
322
+ isTaskDialogOpen || isTemplateManagerOpen || isProjectSettingsOpen,
323
+ closeDialog: () => setIsTaskDialogOpen(false),
324
+ onC: handleCreateNewTask,
325
+ });
326
+
327
+ // Initialize data when projectId changes
328
+ useEffect(() => {
329
+ if (projectId) {
330
+ fetchProject();
331
+ fetchTasks();
332
+ fetchTemplates();
333
+
334
+ // Set up polling to refresh tasks every 5 seconds
335
+ const interval = setInterval(() => {
336
+ fetchTasks(true); // Skip loading spinner for polling
337
+ }, 2000);
338
+
339
+ // Cleanup interval on unmount
340
+ return () => clearInterval(interval);
341
+ }
342
+ }, [projectId]);
343
+
344
+ // Handle direct navigation to task URLs
345
+ useEffect(() => {
346
+ if (taskId && tasks.length > 0) {
347
+ const task = tasks.find((t) => t.id === taskId);
348
+ if (task) {
349
+ setSelectedTask((prev) => {
350
+ if (JSON.stringify(prev) === JSON.stringify(task)) return prev;
351
+ return task;
352
+ });
353
+ setIsPanelOpen(true);
354
+ } else {
355
+ // Task not found in current array - refetch to get latest data
356
+ fetchTasks(true);
357
+ }
358
+ } else if (taskId && tasks.length === 0 && !loading) {
359
+ // If we have a taskId but no tasks loaded, fetch tasks
360
+ fetchTasks();
361
+ } else if (!taskId) {
362
+ // Close panel when no taskId in URL
363
+ setIsPanelOpen(false);
364
+ setSelectedTask(null);
365
+ }
366
+ }, [taskId, tasks, loading, fetchTasks]);
367
+
368
+ if (loading) {
369
+ return <Loader message="Loading tasks..." size={32} className="py-8" />;
370
+ }
371
+
372
+ if (error) {
373
+ return <div className="text-center py-8 text-destructive">{error}</div>;
374
+ }
375
+
376
+ return (
377
+ <div className={getMainContainerClasses(isPanelOpen)}>
378
+ {/* Left Column - Kanban Section */}
379
+ <div className={getKanbanSectionClasses(isPanelOpen)}>
380
+ {/* Header */}
381
+
382
+ <div className="px-8 my-12 flex flex-row">
383
+ <div className="w-full flex items-center gap-3">
384
+ <h1 className="text-2xl font-bold">{project?.name || 'Project'}</h1>
385
+ {project?.current_branch && (
386
+ <span className="text-sm text-muted-foreground bg-muted px-2 py-1 rounded-md">
387
+ {project.current_branch}
388
+ </span>
389
+ )}
390
+ <Button
391
+ variant="ghost"
392
+ size="sm"
393
+ onClick={handleOpenInIDE}
394
+ className="h-8 w-8 p-0"
395
+ title="Open in IDE"
396
+ >
397
+ <FolderOpen className="h-4 w-4" />
398
+ </Button>
399
+ <Button
400
+ variant="ghost"
401
+ size="sm"
402
+ onClick={() => setIsProjectSettingsOpen(true)}
403
+ className="h-8 w-8 p-0"
404
+ title="Project Settings"
405
+ >
406
+ <Settings className="h-4 w-4" />
407
+ </Button>
408
+ </div>
409
+ <div className="flex items-center gap-3">
410
+ <Input
411
+ type="text"
412
+ placeholder="Search tasks..."
413
+ value={searchQuery}
414
+ onChange={(e) => setSearchQuery(e.target.value)}
415
+ className="w-64"
416
+ />
417
+ <Button onClick={handleCreateNewTask}>
418
+ <Plus className="h-4 w-4 mr-2" />
419
+ Add Task
420
+ </Button>
421
+ <DropdownMenu>
422
+ <DropdownMenuTrigger asChild>
423
+ <Button variant="outline" size="icon">
424
+ <LibraryBig className="h-4 w-4" />
425
+ </Button>
426
+ </DropdownMenuTrigger>
427
+ <DropdownMenuContent align="end" className="w-[250px]">
428
+ <DropdownMenuItem onClick={handleOpenTemplateManager}>
429
+ <Plus className="h-3 w-3 mr-2" />
430
+ Manage Templates
431
+ </DropdownMenuItem>
432
+ {templates.length > 0 && <DropdownMenuSeparator />}
433
+
434
+ {/* Project Templates */}
435
+ {templates.filter((t) => t.project_id !== null).length > 0 && (
436
+ <>
437
+ <div className="px-2 py-1.5 text-sm font-semibold text-muted-foreground">
438
+ Project Templates
439
+ </div>
440
+ {templates
441
+ .filter((t) => t.project_id !== null)
442
+ .map((template) => (
443
+ <DropdownMenuItem
444
+ key={template.id}
445
+ onClick={() => handleTemplateSelect(template)}
446
+ >
447
+ <span className="truncate">
448
+ {template.template_name}
449
+ </span>
450
+ </DropdownMenuItem>
451
+ ))}
452
+ </>
453
+ )}
454
+
455
+ {/* Separator if both types exist */}
456
+ {templates.filter((t) => t.project_id !== null).length > 0 &&
457
+ templates.filter((t) => t.project_id === null).length > 0 && (
458
+ <DropdownMenuSeparator />
459
+ )}
460
+
461
+ {/* Global Templates */}
462
+ {templates.filter((t) => t.project_id === null).length > 0 && (
463
+ <>
464
+ <div className="px-2 py-1.5 text-sm font-semibold text-muted-foreground">
465
+ Global Templates
466
+ </div>
467
+ {templates
468
+ .filter((t) => t.project_id === null)
469
+ .map((template) => (
470
+ <DropdownMenuItem
471
+ key={template.id}
472
+ onClick={() => handleTemplateSelect(template)}
473
+ >
474
+ <Globe2 className="h-3 w-3 mr-2 text-muted-foreground" />
475
+ <span className="truncate">
476
+ {template.template_name}
477
+ </span>
478
+ </DropdownMenuItem>
479
+ ))}
480
+ </>
481
+ )}
482
+ </DropdownMenuContent>
483
+ </DropdownMenu>
484
+ </div>
485
+ </div>
486
+
487
+ {/* Tasks View */}
488
+ {tasks.length === 0 ? (
489
+ <div className="max-w-7xl mx-auto">
490
+ <Card>
491
+ <CardContent className="text-center py-8">
492
+ <p className="text-muted-foreground">
493
+ No tasks found for this project.
494
+ </p>
495
+ <Button className="mt-4" onClick={handleCreateNewTask}>
496
+ <Plus className="h-4 w-4 mr-2" />
497
+ Create First Task
498
+ </Button>
499
+ </CardContent>
500
+ </Card>
501
+ </div>
502
+ ) : (
503
+ <div className="px-8 overflow-x-scroll my-4">
504
+ <div className="min-w-[900px] max-w-[2000px] relative py-1">
505
+ <TaskKanbanBoard
506
+ tasks={tasks}
507
+ searchQuery={searchQuery}
508
+ onDragEnd={handleDragEnd}
509
+ onEditTask={handleEditTask}
510
+ onDeleteTask={handleDeleteTask}
511
+ onViewTaskDetails={handleViewTaskDetails}
512
+ isPanelOpen={isPanelOpen}
513
+ />
514
+ </div>
515
+ </div>
516
+ )}
517
+ </div>
518
+
519
+ {/* Right Column - Task Details Panel */}
520
+ {isPanelOpen && (
521
+ <TaskDetailsPanel
522
+ task={selectedTask}
523
+ projectHasDevScript={!!project?.dev_script}
524
+ projectId={projectId!}
525
+ onClose={handleClosePanel}
526
+ onEditTask={handleEditTask}
527
+ onDeleteTask={handleDeleteTask}
528
+ isDialogOpen={isTaskDialogOpen || isProjectSettingsOpen}
529
+ />
530
+ )}
531
+
532
+ {/* Dialogs - rendered at main container level to avoid stacking issues */}
533
+ <TaskFormDialog
534
+ isOpen={isTaskDialogOpen}
535
+ onOpenChange={(open) => {
536
+ setIsTaskDialogOpen(open);
537
+ if (!open) {
538
+ setSelectedTemplate(null);
539
+ }
540
+ }}
541
+ task={editingTask}
542
+ projectId={projectId}
543
+ onCreateTask={handleCreateTask}
544
+ onCreateAndStartTask={handleCreateAndStartTask}
545
+ onUpdateTask={handleUpdateTask}
546
+ initialTemplate={selectedTemplate}
547
+ />
548
+
549
+ <ProjectForm
550
+ open={isProjectSettingsOpen}
551
+ onClose={() => setIsProjectSettingsOpen(false)}
552
+ onSuccess={handleProjectSettingsSuccess}
553
+ project={project}
554
+ />
555
+
556
+ {/* Template Manager Dialog */}
557
+ <Dialog
558
+ open={isTemplateManagerOpen}
559
+ onOpenChange={setIsTemplateManagerOpen}
560
+ >
561
+ <DialogContent className="sm:max-w-[800px] max-h-[80vh] overflow-y-auto">
562
+ <DialogHeader>
563
+ <DialogTitle>Manage Templates</DialogTitle>
564
+ </DialogHeader>
565
+ <div className="py-4">
566
+ <TaskTemplateManager projectId={projectId} />
567
+ </div>
568
+ <DialogFooter>
569
+ <Button onClick={handleCloseTemplateManager}>Done</Button>
570
+ </DialogFooter>
571
+ </DialogContent>
572
+ </Dialog>
573
+ </div>
574
+ );
575
+ }
@@ -0,0 +1,18 @@
1
+ import { useParams, useNavigate } from 'react-router-dom';
2
+ import { ProjectList } from '@/components/projects/project-list';
3
+ import { ProjectDetail } from '@/components/projects/project-detail';
4
+
5
+ export function Projects() {
6
+ const { projectId } = useParams<{ projectId: string }>();
7
+ const navigate = useNavigate();
8
+
9
+ const handleBack = () => {
10
+ navigate('/projects');
11
+ };
12
+
13
+ if (projectId) {
14
+ return <ProjectDetail projectId={projectId} onBack={handleBack} />;
15
+ }
16
+
17
+ return <ProjectList />;
18
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />