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,200 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import {
4
+ useKanbanKeyboardNavigation,
5
+ useKeyboardShortcuts,
6
+ } from '@/lib/keyboard-shortcuts';
7
+ import { Button } from '@/components/ui/button';
8
+ import { Card, CardContent } from '@/components/ui/card';
9
+ import { Alert, AlertDescription } from '@/components/ui/alert';
10
+ import { Project } from 'shared/types';
11
+ import { ProjectForm } from './project-form';
12
+ import { projectsApi } from '@/lib/api';
13
+ import { AlertCircle, Loader2, Plus } from 'lucide-react';
14
+ import ProjectCard from '@/components/projects/ProjectCard.tsx';
15
+
16
+ export function ProjectList() {
17
+ const navigate = useNavigate();
18
+ const [projects, setProjects] = useState<Project[]>([]);
19
+ const [loading, setLoading] = useState(false);
20
+ const [showForm, setShowForm] = useState(false);
21
+ const [editingProject, setEditingProject] = useState<Project | null>(null);
22
+ const [error, setError] = useState('');
23
+ const [focusedProjectId, setFocusedProjectId] = useState<string | null>(null);
24
+ const [focusedColumn, setFocusedColumn] = useState<string | null>(null);
25
+
26
+ const fetchProjects = async () => {
27
+ setLoading(true);
28
+ setError('');
29
+
30
+ try {
31
+ const result = await projectsApi.getAll();
32
+ setProjects(result);
33
+ } catch (error) {
34
+ console.error('Failed to fetch projects:', error);
35
+ setError('Failed to fetch projects');
36
+ } finally {
37
+ setLoading(false);
38
+ }
39
+ };
40
+
41
+ const handleFormSuccess = () => {
42
+ setShowForm(false);
43
+ setEditingProject(null);
44
+ fetchProjects();
45
+ };
46
+
47
+ // Group projects by grid columns (3 columns for lg, 2 for md, 1 for sm)
48
+ const getGridColumns = () => {
49
+ const screenWidth = window.innerWidth;
50
+ if (screenWidth >= 1024) return 3; // lg
51
+ if (screenWidth >= 768) return 2; // md
52
+ return 1; // sm
53
+ };
54
+
55
+ const groupProjectsByColumns = (projects: Project[], columns: number) => {
56
+ const grouped: Record<string, Project[]> = {};
57
+ for (let i = 0; i < columns; i++) {
58
+ grouped[`column-${i}`] = [];
59
+ }
60
+
61
+ projects.forEach((project, index) => {
62
+ const columnIndex = index % columns;
63
+ grouped[`column-${columnIndex}`].push(project);
64
+ });
65
+
66
+ return grouped;
67
+ };
68
+
69
+ const columns = getGridColumns();
70
+ const groupedProjects = groupProjectsByColumns(projects, columns);
71
+ const allColumnKeys = Object.keys(groupedProjects);
72
+
73
+ // Set initial focus when projects are loaded
74
+ useEffect(() => {
75
+ if (projects.length > 0 && !focusedProjectId) {
76
+ setFocusedProjectId(projects[0].id);
77
+ setFocusedColumn('column-0');
78
+ }
79
+ }, [projects, focusedProjectId]);
80
+
81
+ const handleViewProjectDetails = (project: Project) => {
82
+ navigate(`/projects/${project.id}/tasks`);
83
+ };
84
+
85
+ // Setup keyboard navigation
86
+ useKanbanKeyboardNavigation({
87
+ focusedTaskId: focusedProjectId,
88
+ setFocusedTaskId: setFocusedProjectId,
89
+ focusedStatus: focusedColumn,
90
+ setFocusedStatus: setFocusedColumn,
91
+ groupedTasks: groupedProjects,
92
+ filteredTasks: projects,
93
+ allTaskStatuses: allColumnKeys,
94
+ onViewTaskDetails: handleViewProjectDetails,
95
+ preserveIndexOnColumnSwitch: true,
96
+ });
97
+
98
+ useKeyboardShortcuts({
99
+ ignoreEscape: true,
100
+ onC: () => setShowForm(true),
101
+ navigate,
102
+ currentPath: '/projects',
103
+ });
104
+
105
+ // Handle window resize to update column layout
106
+ useEffect(() => {
107
+ const handleResize = () => {
108
+ // Reset focus when layout changes
109
+ if (focusedProjectId && projects.length > 0) {
110
+ const newColumns = getGridColumns();
111
+
112
+ // Find which column the focused project should be in
113
+ const focusedProject = projects.find((p) => p.id === focusedProjectId);
114
+ if (focusedProject) {
115
+ const projectIndex = projects.indexOf(focusedProject);
116
+ const newColumnIndex = projectIndex % newColumns;
117
+ setFocusedColumn(`column-${newColumnIndex}`);
118
+ }
119
+ }
120
+ };
121
+
122
+ window.addEventListener('resize', handleResize);
123
+ return () => window.removeEventListener('resize', handleResize);
124
+ }, [focusedProjectId, projects]);
125
+
126
+ useEffect(() => {
127
+ fetchProjects();
128
+ }, []);
129
+
130
+ return (
131
+ <div className="space-y-6 p-8">
132
+ <div className="flex justify-between items-center">
133
+ <div>
134
+ <h1 className="text-3xl font-bold tracking-tight">Projects</h1>
135
+ <p className="text-muted-foreground">
136
+ Manage your projects and track their progress
137
+ </p>
138
+ </div>
139
+ <Button onClick={() => setShowForm(true)}>
140
+ <Plus className="mr-2 h-4 w-4" />
141
+ Create Project
142
+ </Button>
143
+ </div>
144
+
145
+ {error && (
146
+ <Alert variant="destructive">
147
+ <AlertCircle className="h-4 w-4" />
148
+ <AlertDescription>{error}</AlertDescription>
149
+ </Alert>
150
+ )}
151
+
152
+ {loading ? (
153
+ <div className="flex items-center justify-center py-12">
154
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
155
+ Loading projects...
156
+ </div>
157
+ ) : projects.length === 0 ? (
158
+ <Card>
159
+ <CardContent className="py-12 text-center">
160
+ <div className="mx-auto flex h-12 w-12 items-center justify-center rounded-lg bg-muted">
161
+ <Plus className="h-6 w-6" />
162
+ </div>
163
+ <h3 className="mt-4 text-lg font-semibold">No projects yet</h3>
164
+ <p className="mt-2 text-sm text-muted-foreground">
165
+ Get started by creating your first project.
166
+ </p>
167
+ <Button className="mt-4" onClick={() => setShowForm(true)}>
168
+ <Plus className="mr-2 h-4 w-4" />
169
+ Create your first project
170
+ </Button>
171
+ </CardContent>
172
+ </Card>
173
+ ) : (
174
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
175
+ {projects.map((project) => (
176
+ <ProjectCard
177
+ key={project.id}
178
+ project={project}
179
+ isFocused={focusedProjectId === project.id}
180
+ setError={setError}
181
+ setEditingProject={setEditingProject}
182
+ setShowForm={setShowForm}
183
+ fetchProjects={fetchProjects}
184
+ />
185
+ ))}
186
+ </div>
187
+ )}
188
+
189
+ <ProjectForm
190
+ open={showForm}
191
+ onClose={() => {
192
+ setShowForm(false);
193
+ setEditingProject(null);
194
+ }}
195
+ onSuccess={handleFormSuccess}
196
+ project={editingProject}
197
+ />
198
+ </div>
199
+ );
200
+ }
@@ -0,0 +1,20 @@
1
+ import { useState } from 'react';
2
+ import { ProjectList } from './project-list';
3
+ import { ProjectDetail } from './project-detail';
4
+
5
+ export function ProjectsPage() {
6
+ const [selectedProjectId, setSelectedProjectId] = useState<string | null>(
7
+ null
8
+ );
9
+
10
+ if (selectedProjectId) {
11
+ return (
12
+ <ProjectDetail
13
+ projectId={selectedProjectId}
14
+ onBack={() => setSelectedProjectId(null)}
15
+ />
16
+ );
17
+ }
18
+
19
+ return <ProjectList />;
20
+ }
@@ -0,0 +1,169 @@
1
+ import { useState, useMemo, useRef } from 'react';
2
+ import { Button } from '@/components/ui/button.tsx';
3
+ import { ArrowDown, GitBranch as GitBranchIcon, Search } from 'lucide-react';
4
+ import {
5
+ DropdownMenu,
6
+ DropdownMenuContent,
7
+ DropdownMenuItem,
8
+ DropdownMenuSeparator,
9
+ DropdownMenuTrigger,
10
+ } from '@/components/ui/dropdown-menu.tsx';
11
+ import {
12
+ Tooltip,
13
+ TooltipContent,
14
+ TooltipProvider,
15
+ TooltipTrigger,
16
+ } from '@/components/ui/tooltip.tsx';
17
+ import { Input } from '@/components/ui/input.tsx';
18
+ import type { GitBranch } from 'shared/types.ts';
19
+
20
+ type Props = {
21
+ branches: GitBranch[];
22
+ selectedBranch: string | null;
23
+ onBranchSelect: (branch: string) => void;
24
+ placeholder?: string;
25
+ className?: string;
26
+ excludeCurrentBranch?: boolean;
27
+ };
28
+
29
+ function BranchSelector({
30
+ branches,
31
+ selectedBranch,
32
+ onBranchSelect,
33
+ placeholder = 'Select a branch',
34
+ className = '',
35
+ excludeCurrentBranch = false,
36
+ }: Props) {
37
+ const [branchSearchTerm, setBranchSearchTerm] = useState('');
38
+ const searchInputRef = useRef<HTMLInputElement>(null);
39
+
40
+ // Filter branches based on search term and options
41
+ const filteredBranches = useMemo(() => {
42
+ let filtered = branches;
43
+
44
+ // Don't filter out current branch, we'll handle it in the UI
45
+ if (branchSearchTerm.trim()) {
46
+ filtered = filtered.filter((branch) =>
47
+ branch.name.toLowerCase().includes(branchSearchTerm.toLowerCase())
48
+ );
49
+ }
50
+
51
+ return filtered;
52
+ }, [branches, branchSearchTerm]);
53
+
54
+ const displayName = useMemo(() => {
55
+ if (!selectedBranch) return placeholder;
56
+
57
+ // For remote branches, show just the branch name without the remote prefix
58
+ if (selectedBranch.includes('/')) {
59
+ const parts = selectedBranch.split('/');
60
+ return parts[parts.length - 1];
61
+ }
62
+ return selectedBranch;
63
+ }, [selectedBranch, placeholder]);
64
+
65
+ const handleBranchSelect = (branchName: string) => {
66
+ onBranchSelect(branchName);
67
+ setBranchSearchTerm('');
68
+ };
69
+
70
+ return (
71
+ <DropdownMenu>
72
+ <DropdownMenuTrigger asChild>
73
+ <Button
74
+ variant="outline"
75
+ size="sm"
76
+ className={`w-full justify-between text-xs ${className}`}
77
+ >
78
+ <div className="flex items-center gap-1.5">
79
+ <GitBranchIcon className="h-3 w-3" />
80
+ <span className="truncate">{displayName}</span>
81
+ </div>
82
+ <ArrowDown className="h-3 w-3" />
83
+ </Button>
84
+ </DropdownMenuTrigger>
85
+ <DropdownMenuContent className="w-80">
86
+ <div className="p-2">
87
+ <div className="relative">
88
+ <Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
89
+ <Input
90
+ ref={searchInputRef}
91
+ placeholder="Search branches..."
92
+ value={branchSearchTerm}
93
+ onChange={(e) => setBranchSearchTerm(e.target.value)}
94
+ className="pl-8"
95
+ onKeyDown={(e) => {
96
+ // Prevent the dropdown from closing when typing
97
+ e.stopPropagation();
98
+ }}
99
+ autoFocus
100
+ />
101
+ </div>
102
+ </div>
103
+ <DropdownMenuSeparator />
104
+ <div className="max-h-64 overflow-y-auto">
105
+ {filteredBranches.length === 0 ? (
106
+ <div className="p-2 text-sm text-muted-foreground text-center">
107
+ No branches found
108
+ </div>
109
+ ) : (
110
+ filteredBranches.map((branch) => {
111
+ const isCurrentAndExcluded =
112
+ excludeCurrentBranch && branch.is_current;
113
+
114
+ const menuItem = (
115
+ <DropdownMenuItem
116
+ key={branch.name}
117
+ onClick={() => {
118
+ if (!isCurrentAndExcluded) {
119
+ handleBranchSelect(branch.name);
120
+ }
121
+ }}
122
+ disabled={isCurrentAndExcluded}
123
+ className={`${selectedBranch === branch.name ? 'bg-accent' : ''} ${
124
+ isCurrentAndExcluded ? 'opacity-50 cursor-not-allowed' : ''
125
+ }`}
126
+ >
127
+ <div className="flex items-center justify-between w-full">
128
+ <span className={branch.is_current ? 'font-medium' : ''}>
129
+ {branch.name}
130
+ </span>
131
+ <div className="flex gap-1">
132
+ {branch.is_current && (
133
+ <span className="text-xs bg-green-100 text-green-800 px-1 rounded">
134
+ current
135
+ </span>
136
+ )}
137
+ {branch.is_remote && (
138
+ <span className="text-xs bg-blue-100 text-blue-800 px-1 rounded">
139
+ remote
140
+ </span>
141
+ )}
142
+ </div>
143
+ </div>
144
+ </DropdownMenuItem>
145
+ );
146
+
147
+ if (isCurrentAndExcluded) {
148
+ return (
149
+ <TooltipProvider key={branch.name}>
150
+ <Tooltip>
151
+ <TooltipTrigger asChild>{menuItem}</TooltipTrigger>
152
+ <TooltipContent>
153
+ <p>Cannot rebase a branch onto itself</p>
154
+ </TooltipContent>
155
+ </Tooltip>
156
+ </TooltipProvider>
157
+ );
158
+ }
159
+
160
+ return menuItem;
161
+ })
162
+ )}
163
+ </div>
164
+ </DropdownMenuContent>
165
+ </DropdownMenu>
166
+ );
167
+ }
168
+
169
+ export default BranchSelector;
@@ -0,0 +1,94 @@
1
+ import {
2
+ Dialog,
3
+ DialogContent,
4
+ DialogDescription,
5
+ DialogFooter,
6
+ DialogHeader,
7
+ DialogTitle,
8
+ } from '@/components/ui/dialog.tsx';
9
+ import { Button } from '@/components/ui/button.tsx';
10
+ import { attemptsApi } from '@/lib/api.ts';
11
+ import { useContext } from 'react';
12
+ import {
13
+ TaskDeletingFilesContext,
14
+ TaskDetailsContext,
15
+ TaskDiffContext,
16
+ TaskSelectedAttemptContext,
17
+ } from '@/components/context/taskDetailsContext.ts';
18
+
19
+ function DeleteFileConfirmationDialog() {
20
+ const { task, projectId } = useContext(TaskDetailsContext);
21
+ const { selectedAttempt } = useContext(TaskSelectedAttemptContext);
22
+ const { setDeletingFiles, fileToDelete, deletingFiles, setFileToDelete } =
23
+ useContext(TaskDeletingFilesContext);
24
+ const { fetchDiff, setDiffError } = useContext(TaskDiffContext);
25
+
26
+ const handleConfirmDelete = async () => {
27
+ if (!fileToDelete || !projectId || !task?.id || !selectedAttempt?.id)
28
+ return;
29
+
30
+ setDeletingFiles((prev) => new Set(prev).add(fileToDelete));
31
+
32
+ try {
33
+ await attemptsApi.deleteFile(
34
+ projectId!,
35
+ selectedAttempt.task_id,
36
+ selectedAttempt.id,
37
+ fileToDelete
38
+ );
39
+ await fetchDiff();
40
+ } catch (error: unknown) {
41
+ // @ts-expect-error it is type ApiError
42
+ setDiffError(error.message || 'Failed to delete file');
43
+ } finally {
44
+ setDeletingFiles((prev) => {
45
+ const newSet = new Set(prev);
46
+ newSet.delete(fileToDelete);
47
+ return newSet;
48
+ });
49
+ setFileToDelete(null);
50
+ }
51
+ };
52
+
53
+ const handleCancelDelete = () => {
54
+ setFileToDelete(null);
55
+ };
56
+
57
+ return (
58
+ <Dialog open={!!fileToDelete} onOpenChange={() => handleCancelDelete()}>
59
+ <DialogContent>
60
+ <DialogHeader>
61
+ <DialogTitle>Delete File</DialogTitle>
62
+ <DialogDescription>
63
+ Are you sure you want to delete the file{' '}
64
+ <span className="font-mono font-medium">"{fileToDelete}"</span>?
65
+ </DialogDescription>
66
+ </DialogHeader>
67
+ <div className="py-4">
68
+ <div className="bg-red-50 border border-red-200 rounded-md p-3">
69
+ <p className="text-sm text-red-800">
70
+ <strong>Warning:</strong> This action will permanently remove the
71
+ entire file from the worktree. This cannot be undone.
72
+ </p>
73
+ </div>
74
+ </div>
75
+ <DialogFooter>
76
+ <Button variant="outline" onClick={handleCancelDelete}>
77
+ Cancel
78
+ </Button>
79
+ <Button
80
+ variant="destructive"
81
+ onClick={handleConfirmDelete}
82
+ disabled={deletingFiles.has(fileToDelete || '')}
83
+ >
84
+ {deletingFiles.has(fileToDelete || '')
85
+ ? 'Deleting...'
86
+ : 'Delete File'}
87
+ </Button>
88
+ </DialogFooter>
89
+ </DialogContent>
90
+ </Dialog>
91
+ );
92
+ }
93
+
94
+ export default DeleteFileConfirmationDialog;
@@ -0,0 +1,119 @@
1
+ import { useContext, useState } from 'react';
2
+ import { Button } from '@/components/ui/button';
3
+ import {
4
+ Dialog,
5
+ DialogContent,
6
+ DialogDescription,
7
+ DialogFooter,
8
+ DialogHeader,
9
+ DialogTitle,
10
+ } from '@/components/ui/dialog';
11
+ import {
12
+ Select,
13
+ SelectContent,
14
+ SelectItem,
15
+ SelectTrigger,
16
+ SelectValue,
17
+ } from '@/components/ui/select';
18
+ import type { EditorType } from 'shared/types';
19
+ import { TaskDetailsContext } from '@/components/context/taskDetailsContext.ts';
20
+
21
+ interface EditorSelectionDialogProps {
22
+ isOpen: boolean;
23
+ onClose: () => void;
24
+ }
25
+
26
+ const editorOptions: {
27
+ value: EditorType;
28
+ label: string;
29
+ description: string;
30
+ }[] = [
31
+ {
32
+ value: 'vscode',
33
+ label: 'Visual Studio Code',
34
+ description: "Microsoft's popular code editor",
35
+ },
36
+ {
37
+ value: 'cursor',
38
+ label: 'Cursor',
39
+ description: 'AI-powered code editor',
40
+ },
41
+ {
42
+ value: 'windsurf',
43
+ label: 'Windsurf',
44
+ description: 'Modern code editor',
45
+ },
46
+ {
47
+ value: 'intellij',
48
+ label: 'IntelliJ IDEA',
49
+ description: 'JetBrains IDE',
50
+ },
51
+ {
52
+ value: 'zed',
53
+ label: 'Zed',
54
+ description: 'High-performance code editor',
55
+ },
56
+ {
57
+ value: 'custom',
58
+ label: 'Custom Editor',
59
+ description: 'Use your configured custom editor',
60
+ },
61
+ ];
62
+
63
+ export function EditorSelectionDialog({
64
+ isOpen,
65
+ onClose,
66
+ }: EditorSelectionDialogProps) {
67
+ const { handleOpenInEditor } = useContext(TaskDetailsContext);
68
+ const [selectedEditor, setSelectedEditor] = useState<EditorType>('vscode');
69
+
70
+ const handleConfirm = () => {
71
+ handleOpenInEditor(selectedEditor);
72
+ onClose();
73
+ };
74
+
75
+ return (
76
+ <Dialog open={isOpen} onOpenChange={onClose}>
77
+ <DialogContent className="sm:max-w-[425px]">
78
+ <DialogHeader>
79
+ <DialogTitle>Choose Editor</DialogTitle>
80
+ <DialogDescription>
81
+ The default editor failed to open. Please select an alternative
82
+ editor to open the task worktree.
83
+ </DialogDescription>
84
+ </DialogHeader>
85
+ <div className="grid gap-4 py-4">
86
+ <div className="space-y-2">
87
+ <label className="text-sm font-medium">Editor</label>
88
+ <Select
89
+ value={selectedEditor}
90
+ onValueChange={(value) => setSelectedEditor(value as EditorType)}
91
+ >
92
+ <SelectTrigger>
93
+ <SelectValue />
94
+ </SelectTrigger>
95
+ <SelectContent>
96
+ {editorOptions.map((option) => (
97
+ <SelectItem key={option.value} value={option.value}>
98
+ <div className="flex flex-col">
99
+ <span className="font-medium">{option.label}</span>
100
+ <span className="text-xs text-muted-foreground">
101
+ {option.description}
102
+ </span>
103
+ </div>
104
+ </SelectItem>
105
+ ))}
106
+ </SelectContent>
107
+ </Select>
108
+ </div>
109
+ </div>
110
+ <DialogFooter>
111
+ <Button variant="outline" onClick={onClose}>
112
+ Cancel
113
+ </Button>
114
+ <Button onClick={handleConfirm}>Open Editor</Button>
115
+ </DialogFooter>
116
+ </DialogContent>
117
+ </Dialog>
118
+ );
119
+ }