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,307 @@
1
+ use std::time::Duration;
2
+
3
+ use octocrab::{Octocrab, OctocrabBuilder};
4
+ use serde::{Deserialize, Serialize};
5
+ use tokio::time::sleep;
6
+ use tracing::{info, warn};
7
+
8
+ #[derive(Debug)]
9
+ pub enum GitHubServiceError {
10
+ Client(octocrab::Error),
11
+ Auth(String),
12
+ Repository(String),
13
+ PullRequest(String),
14
+ Branch(String),
15
+ TokenInvalid,
16
+ }
17
+
18
+ impl std::fmt::Display for GitHubServiceError {
19
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20
+ match self {
21
+ GitHubServiceError::Client(e) => write!(f, "GitHub client error: {}", e),
22
+ GitHubServiceError::Auth(e) => write!(f, "Authentication error: {}", e),
23
+ GitHubServiceError::Repository(e) => write!(f, "Repository error: {}", e),
24
+ GitHubServiceError::PullRequest(e) => write!(f, "Pull request error: {}", e),
25
+ GitHubServiceError::Branch(e) => write!(f, "Branch error: {}", e),
26
+ GitHubServiceError::TokenInvalid => write!(f, "GitHub token is invalid or expired."),
27
+ }
28
+ }
29
+ }
30
+
31
+ impl std::error::Error for GitHubServiceError {}
32
+
33
+ impl From<octocrab::Error> for GitHubServiceError {
34
+ fn from(err: octocrab::Error) -> Self {
35
+ match &err {
36
+ octocrab::Error::GitHub { source, .. } => {
37
+ let status = source.status_code.as_u16();
38
+ let msg = source.message.to_ascii_lowercase();
39
+ if status == 401
40
+ || status == 403
41
+ || msg.contains("bad credentials")
42
+ || msg.contains("token expired")
43
+ {
44
+ GitHubServiceError::TokenInvalid
45
+ } else {
46
+ GitHubServiceError::Client(err)
47
+ }
48
+ }
49
+ _ => GitHubServiceError::Client(err),
50
+ }
51
+ }
52
+ }
53
+
54
+ #[derive(Debug, Clone)]
55
+ pub struct GitHubRepoInfo {
56
+ pub owner: String,
57
+ pub repo_name: String,
58
+ }
59
+
60
+ #[derive(Debug, Clone)]
61
+ pub struct CreatePrRequest {
62
+ pub title: String,
63
+ pub body: Option<String>,
64
+ pub head_branch: String,
65
+ pub base_branch: String,
66
+ }
67
+
68
+ #[derive(Debug, Clone, Serialize, Deserialize)]
69
+ pub struct PullRequestInfo {
70
+ pub number: i64,
71
+ pub url: String,
72
+ pub status: String,
73
+ pub merged: bool,
74
+ pub merged_at: Option<chrono::DateTime<chrono::Utc>>,
75
+ pub merge_commit_sha: Option<String>,
76
+ }
77
+
78
+ #[derive(Debug, Clone)]
79
+ pub struct GitHubService {
80
+ client: Octocrab,
81
+ retry_config: RetryConfig,
82
+ }
83
+
84
+ #[derive(Debug, Clone)]
85
+ pub struct RetryConfig {
86
+ pub max_retries: u32,
87
+ pub base_delay: Duration,
88
+ pub max_delay: Duration,
89
+ }
90
+
91
+ impl Default for RetryConfig {
92
+ fn default() -> Self {
93
+ Self {
94
+ max_retries: 3,
95
+ base_delay: Duration::from_secs(1),
96
+ max_delay: Duration::from_secs(30),
97
+ }
98
+ }
99
+ }
100
+
101
+ impl GitHubService {
102
+ /// Create a new GitHub service with authentication
103
+ pub fn new(github_token: &str) -> Result<Self, GitHubServiceError> {
104
+ let client = OctocrabBuilder::new()
105
+ .personal_token(github_token.to_string())
106
+ .build()
107
+ .map_err(|e| {
108
+ GitHubServiceError::Auth(format!("Failed to create GitHub client: {}", e))
109
+ })?;
110
+
111
+ Ok(Self {
112
+ client,
113
+ retry_config: RetryConfig::default(),
114
+ })
115
+ }
116
+
117
+ /// Create a pull request on GitHub
118
+ pub async fn create_pr(
119
+ &self,
120
+ repo_info: &GitHubRepoInfo,
121
+ request: &CreatePrRequest,
122
+ ) -> Result<PullRequestInfo, GitHubServiceError> {
123
+ self.with_retry(|| async { self.create_pr_internal(repo_info, request).await })
124
+ .await
125
+ }
126
+
127
+ async fn create_pr_internal(
128
+ &self,
129
+ repo_info: &GitHubRepoInfo,
130
+ request: &CreatePrRequest,
131
+ ) -> Result<PullRequestInfo, GitHubServiceError> {
132
+ // Verify repository access
133
+ self.client
134
+ .repos(&repo_info.owner, &repo_info.repo_name)
135
+ .get()
136
+ .await
137
+ .map_err(|e| {
138
+ GitHubServiceError::Repository(format!(
139
+ "Cannot access repository {}/{}: {}",
140
+ repo_info.owner, repo_info.repo_name, e
141
+ ))
142
+ })?;
143
+
144
+ // Check if the base branch exists
145
+ self.client
146
+ .repos(&repo_info.owner, &repo_info.repo_name)
147
+ .get_ref(&octocrab::params::repos::Reference::Branch(
148
+ request.base_branch.clone(),
149
+ ))
150
+ .await
151
+ .map_err(|e| {
152
+ GitHubServiceError::Branch(format!(
153
+ "Base branch '{}' does not exist: {}",
154
+ request.base_branch, e
155
+ ))
156
+ })?;
157
+
158
+ // Check if the head branch exists
159
+ self.client
160
+ .repos(&repo_info.owner, &repo_info.repo_name)
161
+ .get_ref(&octocrab::params::repos::Reference::Branch(
162
+ request.head_branch.clone(),
163
+ ))
164
+ .await
165
+ .map_err(|e| {
166
+ GitHubServiceError::Branch(format!(
167
+ "Head branch '{}' does not exist. Make sure the branch was pushed successfully: {}",
168
+ request.head_branch, e
169
+ ))
170
+ })?;
171
+
172
+ // Create the pull request
173
+ let pr = self
174
+ .client
175
+ .pulls(&repo_info.owner, &repo_info.repo_name)
176
+ .create(&request.title, &request.head_branch, &request.base_branch)
177
+ .body(request.body.as_deref().unwrap_or(""))
178
+ .send()
179
+ .await
180
+ .map_err(|e| match e {
181
+ octocrab::Error::GitHub { source, .. } => {
182
+ if source.status_code.as_u16() == 401
183
+ || source.status_code.as_u16() == 403
184
+ || source
185
+ .message
186
+ .to_ascii_lowercase()
187
+ .contains("bad credentials")
188
+ || source
189
+ .message
190
+ .to_ascii_lowercase()
191
+ .contains("token expired")
192
+ {
193
+ GitHubServiceError::TokenInvalid
194
+ } else {
195
+ GitHubServiceError::PullRequest(format!(
196
+ "GitHub API error: {} (status: {})",
197
+ source.message,
198
+ source.status_code.as_u16()
199
+ ))
200
+ }
201
+ }
202
+ _ => GitHubServiceError::PullRequest(format!("Failed to create PR: {}", e)),
203
+ })?;
204
+
205
+ let pr_info = PullRequestInfo {
206
+ number: pr.number as i64,
207
+ url: pr.html_url.map(|url| url.to_string()).unwrap_or_default(),
208
+ status: "open".to_string(),
209
+ merged: false,
210
+ merged_at: None,
211
+ merge_commit_sha: None,
212
+ };
213
+
214
+ info!(
215
+ "Created GitHub PR #{} for branch {} in {}/{}",
216
+ pr_info.number, request.head_branch, repo_info.owner, repo_info.repo_name
217
+ );
218
+
219
+ Ok(pr_info)
220
+ }
221
+
222
+ /// Update and get the status of a pull request
223
+ pub async fn update_pr_status(
224
+ &self,
225
+ repo_info: &GitHubRepoInfo,
226
+ pr_number: i64,
227
+ ) -> Result<PullRequestInfo, GitHubServiceError> {
228
+ self.with_retry(|| async { self.update_pr_status_internal(repo_info, pr_number).await })
229
+ .await
230
+ }
231
+
232
+ async fn update_pr_status_internal(
233
+ &self,
234
+ repo_info: &GitHubRepoInfo,
235
+ pr_number: i64,
236
+ ) -> Result<PullRequestInfo, GitHubServiceError> {
237
+ let pr = self
238
+ .client
239
+ .pulls(&repo_info.owner, &repo_info.repo_name)
240
+ .get(pr_number as u64)
241
+ .await
242
+ .map_err(|e| {
243
+ GitHubServiceError::PullRequest(format!("Failed to get PR #{}: {}", pr_number, e))
244
+ })?;
245
+
246
+ let status = match pr.state {
247
+ Some(octocrab::models::IssueState::Open) => "open",
248
+ Some(octocrab::models::IssueState::Closed) => {
249
+ if pr.merged_at.is_some() {
250
+ "merged"
251
+ } else {
252
+ "closed"
253
+ }
254
+ }
255
+ None => "unknown",
256
+ Some(_) => "unknown", // Handle any other states
257
+ };
258
+
259
+ let pr_info = PullRequestInfo {
260
+ number: pr.number as i64,
261
+ url: pr.html_url.map(|url| url.to_string()).unwrap_or_default(),
262
+ status: status.to_string(),
263
+ merged: pr.merged_at.is_some(),
264
+ merged_at: pr.merged_at.map(|dt| dt.naive_utc().and_utc()),
265
+ merge_commit_sha: pr.merge_commit_sha.clone(),
266
+ };
267
+
268
+ Ok(pr_info)
269
+ }
270
+
271
+ /// Retry wrapper for GitHub API calls with exponential backoff
272
+ async fn with_retry<F, Fut, T>(&self, operation: F) -> Result<T, GitHubServiceError>
273
+ where
274
+ F: Fn() -> Fut,
275
+ Fut: std::future::Future<Output = Result<T, GitHubServiceError>>,
276
+ {
277
+ let mut last_error = None;
278
+
279
+ for attempt in 0..=self.retry_config.max_retries {
280
+ match operation().await {
281
+ Ok(result) => return Ok(result),
282
+ Err(e) => {
283
+ last_error = Some(e);
284
+
285
+ if attempt < self.retry_config.max_retries {
286
+ let delay = std::cmp::min(
287
+ self.retry_config.base_delay * 2_u32.pow(attempt),
288
+ self.retry_config.max_delay,
289
+ );
290
+
291
+ warn!(
292
+ "GitHub API call failed (attempt {}/{}), retrying in {:?}: {}",
293
+ attempt + 1,
294
+ self.retry_config.max_retries + 1,
295
+ delay,
296
+ last_error.as_ref().unwrap()
297
+ );
298
+
299
+ sleep(delay).await;
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ Err(last_error.unwrap())
306
+ }
307
+ }
@@ -0,0 +1,13 @@
1
+ pub mod analytics;
2
+ pub mod git_service;
3
+ pub mod github_service;
4
+ pub mod notification_service;
5
+ pub mod pr_monitor;
6
+ pub mod process_service;
7
+
8
+ pub use analytics::{generate_user_id, AnalyticsConfig, AnalyticsService};
9
+ pub use git_service::{GitService, GitServiceError};
10
+ pub use github_service::{CreatePrRequest, GitHubRepoInfo, GitHubService, GitHubServiceError};
11
+ pub use notification_service::{NotificationConfig, NotificationService};
12
+ pub use pr_monitor::PrMonitorService;
13
+ pub use process_service::ProcessService;
@@ -0,0 +1,263 @@
1
+ use std::sync::OnceLock;
2
+
3
+ use crate::models::config::SoundFile;
4
+
5
+ /// Service for handling cross-platform notifications including sound alerts and push notifications
6
+ #[derive(Debug, Clone)]
7
+ pub struct NotificationService {
8
+ sound_enabled: bool,
9
+ push_enabled: bool,
10
+ }
11
+
12
+ /// Configuration for notifications
13
+ #[derive(Debug, Clone)]
14
+ pub struct NotificationConfig {
15
+ pub sound_enabled: bool,
16
+ pub push_enabled: bool,
17
+ }
18
+
19
+ impl Default for NotificationConfig {
20
+ fn default() -> Self {
21
+ Self {
22
+ sound_enabled: true,
23
+ push_enabled: true,
24
+ }
25
+ }
26
+ }
27
+
28
+ /// Cache for WSL root path from PowerShell
29
+ static WSL_ROOT_PATH_CACHE: OnceLock<Option<String>> = OnceLock::new();
30
+
31
+ impl NotificationService {
32
+ /// Create a new NotificationService with the given configuration
33
+ pub fn new(config: NotificationConfig) -> Self {
34
+ Self {
35
+ sound_enabled: config.sound_enabled,
36
+ push_enabled: config.push_enabled,
37
+ }
38
+ }
39
+
40
+ /// Send both sound and push notifications if enabled
41
+ pub async fn notify(&self, title: &str, message: &str, sound_file: &SoundFile) {
42
+ if self.sound_enabled {
43
+ self.play_sound_notification(sound_file).await;
44
+ }
45
+
46
+ if self.push_enabled {
47
+ self.send_push_notification(title, message).await;
48
+ }
49
+ }
50
+
51
+ /// Play a system sound notification across platforms
52
+ pub async fn play_sound_notification(&self, sound_file: &SoundFile) {
53
+ if !self.sound_enabled {
54
+ return;
55
+ }
56
+
57
+ let file_path = match sound_file.get_path().await {
58
+ Ok(path) => path,
59
+ Err(e) => {
60
+ tracing::error!("Failed to create cached sound file: {}", e);
61
+ return;
62
+ }
63
+ };
64
+
65
+ // Use platform-specific sound notification
66
+ // Note: spawn() calls are intentionally not awaited - sound notifications should be fire-and-forget
67
+ if cfg!(target_os = "macos") {
68
+ let _ = tokio::process::Command::new("afplay")
69
+ .arg(&file_path)
70
+ .spawn();
71
+ } else if cfg!(target_os = "linux") && !crate::utils::is_wsl2() {
72
+ // Try different Linux audio players
73
+ if tokio::process::Command::new("paplay")
74
+ .arg(&file_path)
75
+ .spawn()
76
+ .is_ok()
77
+ {
78
+ // Success with paplay
79
+ } else if tokio::process::Command::new("aplay")
80
+ .arg(&file_path)
81
+ .spawn()
82
+ .is_ok()
83
+ {
84
+ // Success with aplay
85
+ } else {
86
+ // Try system bell as fallback
87
+ let _ = tokio::process::Command::new("echo")
88
+ .arg("-e")
89
+ .arg("\\a")
90
+ .spawn();
91
+ }
92
+ } else if cfg!(target_os = "windows")
93
+ || (cfg!(target_os = "linux") && crate::utils::is_wsl2())
94
+ {
95
+ // Convert WSL path to Windows path if in WSL2
96
+ let file_path = if crate::utils::is_wsl2() {
97
+ if let Some(windows_path) = Self::wsl_to_windows_path(&file_path).await {
98
+ windows_path
99
+ } else {
100
+ file_path.to_string_lossy().to_string()
101
+ }
102
+ } else {
103
+ file_path.to_string_lossy().to_string()
104
+ };
105
+
106
+ let _ = tokio::process::Command::new("powershell.exe")
107
+ .arg("-c")
108
+ .arg(format!(
109
+ r#"(New-Object Media.SoundPlayer "{}").PlaySync()"#,
110
+ file_path
111
+ ))
112
+ .spawn();
113
+ }
114
+ }
115
+
116
+ /// Send a cross-platform push notification
117
+ pub async fn send_push_notification(&self, title: &str, message: &str) {
118
+ if !self.push_enabled {
119
+ return;
120
+ }
121
+
122
+ if cfg!(target_os = "macos") {
123
+ self.send_macos_notification(title, message).await;
124
+ } else if cfg!(target_os = "linux") && !crate::utils::is_wsl2() {
125
+ self.send_linux_notification(title, message).await;
126
+ } else if cfg!(target_os = "windows")
127
+ || (cfg!(target_os = "linux") && crate::utils::is_wsl2())
128
+ {
129
+ self.send_windows_notification(title, message).await;
130
+ }
131
+ }
132
+
133
+ /// Send macOS notification using osascript
134
+ async fn send_macos_notification(&self, title: &str, message: &str) {
135
+ let script = format!(
136
+ r#"display notification "{message}" with title "{title}" sound name "Glass""#,
137
+ message = message.replace('"', r#"\""#),
138
+ title = title.replace('"', r#"\""#)
139
+ );
140
+
141
+ let _ = tokio::process::Command::new("osascript")
142
+ .arg("-e")
143
+ .arg(script)
144
+ .spawn();
145
+ }
146
+
147
+ /// Send Linux notification using notify-rust
148
+ async fn send_linux_notification(&self, title: &str, message: &str) {
149
+ use notify_rust::Notification;
150
+
151
+ let title = title.to_string();
152
+ let message = message.to_string();
153
+
154
+ let _handle = tokio::task::spawn_blocking(move || {
155
+ if let Err(e) = Notification::new()
156
+ .summary(&title)
157
+ .body(&message)
158
+ .timeout(10000)
159
+ .show()
160
+ {
161
+ tracing::error!("Failed to send Linux notification: {}", e);
162
+ }
163
+ });
164
+ drop(_handle); // Don't await, fire-and-forget
165
+ }
166
+
167
+ /// Send Windows/WSL notification using PowerShell toast script
168
+ async fn send_windows_notification(&self, title: &str, message: &str) {
169
+ let script_path = match crate::utils::get_powershell_script().await {
170
+ Ok(path) => path,
171
+ Err(e) => {
172
+ tracing::error!("Failed to get PowerShell script: {}", e);
173
+ return;
174
+ }
175
+ };
176
+
177
+ // Convert WSL path to Windows path if in WSL2
178
+ let script_path_str = if crate::utils::is_wsl2() {
179
+ if let Some(windows_path) = Self::wsl_to_windows_path(&script_path).await {
180
+ windows_path
181
+ } else {
182
+ script_path.to_string_lossy().to_string()
183
+ }
184
+ } else {
185
+ script_path.to_string_lossy().to_string()
186
+ };
187
+
188
+ let _ = tokio::process::Command::new("powershell.exe")
189
+ .arg("-NoProfile")
190
+ .arg("-ExecutionPolicy")
191
+ .arg("Bypass")
192
+ .arg("-File")
193
+ .arg(script_path_str)
194
+ .arg("-Title")
195
+ .arg(title)
196
+ .arg("-Message")
197
+ .arg(message)
198
+ .spawn();
199
+ }
200
+
201
+ /// Get WSL root path via PowerShell (cached)
202
+ async fn get_wsl_root_path() -> Option<String> {
203
+ if let Some(cached) = WSL_ROOT_PATH_CACHE.get() {
204
+ return cached.clone();
205
+ }
206
+
207
+ match tokio::process::Command::new("powershell.exe")
208
+ .arg("-c")
209
+ .arg("(Get-Location).Path -replace '^.*::', ''")
210
+ .current_dir("/")
211
+ .output()
212
+ .await
213
+ {
214
+ Ok(output) => {
215
+ match String::from_utf8(output.stdout) {
216
+ Ok(pwd_str) => {
217
+ let pwd = pwd_str.trim();
218
+ tracing::info!("WSL root path detected: {}", pwd);
219
+
220
+ // Cache the result
221
+ let _ = WSL_ROOT_PATH_CACHE.set(Some(pwd.to_string()));
222
+ return Some(pwd.to_string());
223
+ }
224
+ Err(e) => {
225
+ tracing::error!("Failed to parse PowerShell pwd output as UTF-8: {}", e);
226
+ }
227
+ }
228
+ }
229
+ Err(e) => {
230
+ tracing::error!("Failed to execute PowerShell pwd command: {}", e);
231
+ }
232
+ }
233
+
234
+ // Cache the failure result
235
+ let _ = WSL_ROOT_PATH_CACHE.set(None);
236
+ None
237
+ }
238
+
239
+ /// Convert WSL path to Windows UNC path for PowerShell
240
+ async fn wsl_to_windows_path(wsl_path: &std::path::Path) -> Option<String> {
241
+ let path_str = wsl_path.to_string_lossy();
242
+
243
+ // Relative paths work fine as-is in PowerShell
244
+ if !path_str.starts_with('/') {
245
+ tracing::debug!("Using relative path as-is: {}", path_str);
246
+ return Some(path_str.to_string());
247
+ }
248
+
249
+ // Get cached WSL root path from PowerShell
250
+ if let Some(wsl_root) = Self::get_wsl_root_path().await {
251
+ // Simply concatenate WSL root with the absolute path - PowerShell doesn't mind /
252
+ let windows_path = format!("{}{}", wsl_root, path_str);
253
+ tracing::debug!("WSL path converted: {} -> {}", path_str, windows_path);
254
+ Some(windows_path)
255
+ } else {
256
+ tracing::error!(
257
+ "Failed to determine WSL root path for conversion: {}",
258
+ path_str
259
+ );
260
+ None
261
+ }
262
+ }
263
+ }