automagik-forge 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/README.md +143 -447
  2. package/dist/linux-x64/automagik-forge-mcp.zip +0 -0
  3. package/{npx-cli/automagik-forge-0.0.55.tgz → dist/linux-x64/automagik-forge.zip} +0 -0
  4. package/package.json +13 -23
  5. package/.cargo/config.toml +0 -13
  6. package/.claude/commands/commit.md +0 -376
  7. package/.claude/commands/prompt.md +0 -871
  8. package/.env.example +0 -20
  9. package/.github/actions/setup-node/action.yml +0 -29
  10. package/.github/images/automagik-logo.png +0 -0
  11. package/.github/workflows/pre-release.yml +0 -470
  12. package/.github/workflows/publish.yml +0 -145
  13. package/.github/workflows/test.yml +0 -63
  14. package/.mcp.json +0 -57
  15. package/AGENT.md +0 -40
  16. package/CLAUDE.md +0 -40
  17. package/CODE-OF-CONDUCT.md +0 -89
  18. package/Cargo.toml +0 -19
  19. package/Dockerfile +0 -43
  20. package/LICENSE +0 -201
  21. package/Makefile +0 -97
  22. package/backend/.sqlx/query-01b7e2bac1261d8be3d03c03df3e5220590da6c31c77f161074fc62752d63881.json +0 -12
  23. package/backend/.sqlx/query-03f2b02ba6dc5ea2b3cf6b1004caea0ad6bcc10ebd63f441d321a389f026e263.json +0 -12
  24. package/backend/.sqlx/query-0923b77d137a29fc54d399a873ff15fc4af894490bc65a4d344a7575cb0d8643.json +0 -12
  25. package/backend/.sqlx/query-0f808bcdb63c5f180836e448dd64c435c51758b2fc54a52ce9e67495b1ab200e.json +0 -68
  26. package/backend/.sqlx/query-1268afe9ca849daa6722e3df7ca8e9e61f0d37052e782bb5452ab8e1018d9b63.json +0 -12
  27. package/backend/.sqlx/query-1b082630a9622f8667ee7a9aba2c2d3176019a68c6bb83d33008594821415a57.json +0 -12
  28. package/backend/.sqlx/query-1c7b06ba1e112abf6b945a2ff08a0b40ec23f3738c2e7399f067b558cf8d490e.json +0 -12
  29. package/backend/.sqlx/query-1f619f01f46859a64ded531dd0ef61abacfe62e758abe7030a6aa745140b95ca.json +0 -104
  30. package/backend/.sqlx/query-1fca1ce14b4b20205364cd1f1f45ebe1d2e30cd745e59e189d56487b5639dfbb.json +0 -12
  31. package/backend/.sqlx/query-212828320e8d871ab9d83705a040b23bcf0393dc7252177fc539a74657f578ef.json +0 -32
  32. package/backend/.sqlx/query-290ce5c152be8d36e58ff42570f9157beb07ab9e77a03ec6fc30b4f56f9b8f6b.json +0 -56
  33. package/backend/.sqlx/query-2b471d2c2e8ffbe0cd42d2a91b814c0d79f9d09200f147e3cea33ba4ce673c8a.json +0 -68
  34. package/backend/.sqlx/query-354a48c705bb9bb2048c1b7f10fcb714e23f9db82b7a4ea6932486197b2ede6a.json +0 -92
  35. package/backend/.sqlx/query-36c9e3dd10648e94b949db5c91a774ecb1e10a899ef95da74066eccedca4d8b2.json +0 -12
  36. package/backend/.sqlx/query-36e4ba7bbd81b402d5a20b6005755eafbb174c8dda442081823406ac32809a94.json +0 -56
  37. package/backend/.sqlx/query-3a5b3c98a55ca183ab20c74708e3d7e579dda37972c059e7515c4ceee4bd8dd3.json +0 -62
  38. package/backend/.sqlx/query-3d0a1cabf2a52e9d90cdfd29c509ca89aeb448d0c1d2446c65cd43db40735e86.json +0 -62
  39. package/backend/.sqlx/query-3d6bd16fbce59efe30b7f67ea342e0e4ea6d1432389c02468ad79f1f742d4031.json +0 -56
  40. package/backend/.sqlx/query-4049ca413b285a05aca6b25385e9c8185575f01e9069e4e8581aa45d713f612f.json +0 -32
  41. package/backend/.sqlx/query-412bacd3477d86369082e90f52240407abce436cb81292d42b2dbe1e5c18eea1.json +0 -104
  42. package/backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json +0 -62
  43. package/backend/.sqlx/query-461cc1b0bb6fd909afc9dd2246e8526b3771cfbb0b22ae4b5d17b51af587b9e2.json +0 -56
  44. package/backend/.sqlx/query-58408c7a8cdeeda0bef359f1f9bd91299a339dc2b191462fc58c9736a56d5227.json +0 -92
  45. package/backend/.sqlx/query-5a886026d75d515c01f347cc203c8d99dd04c61dc468e2e4c5aa548436d13834.json +0 -62
  46. package/backend/.sqlx/query-5b902137b11022d2e1a5c4f6a9c83fec1a856c6a710aff831abd2382ede76b43.json +0 -12
  47. package/backend/.sqlx/query-5ed1238e52e59bb5f76c0f153fd99a14093f7ce2585bf9843585608f17ec575b.json +0 -104
  48. package/backend/.sqlx/query-6e8b860b14decfc2227dc57213f38442943d3fbef5c8418fd6b634c6e0f5e2ea.json +0 -104
  49. package/backend/.sqlx/query-6ec414276994c4ccb2433eaa5b1b342168557d17ddf5a52dac84cb1b59b9de8f.json +0 -68
  50. package/backend/.sqlx/query-6ecfa16d0cf825aacf233544b5baf151e9adfdca26c226ad71020d291fd802d5.json +0 -62
  51. package/backend/.sqlx/query-72509d252c39fce77520aa816cb2acbc1fb35dc2605e7be893610599b2427f2e.json +0 -62
  52. package/backend/.sqlx/query-75239b2da188f749707d77f3c1544332ca70db3d6d6743b2601dc0d167536437.json +0 -62
  53. package/backend/.sqlx/query-83d10e29f8478aff33434f9ac67068e013b888b953a2657e2bb72a6f619d04f2.json +0 -50
  54. package/backend/.sqlx/query-8610803360ea18b9b9d078a6981ea56abfbfe84e6354fc1d5ae4c622e01410ed.json +0 -68
  55. package/backend/.sqlx/query-86d03eb70eef39c59296416867f2ee66c9f7cd8b7f961fbda2f89fc0a1c442c2.json +0 -12
  56. package/backend/.sqlx/query-87d0feb5a6b442bad9c60068ea7569599cc6fc91a0e2692ecb42e93b03201b9d.json +0 -68
  57. package/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json +0 -12
  58. package/backend/.sqlx/query-8f01ebd64bdcde6a090479f14810d73ba23020e76fd70854ac57f2da251702c3.json +0 -12
  59. package/backend/.sqlx/query-90fd607fcb2dca72239ff25e618e21e174b195991eaa33722cbf5f76da84cfab.json +0 -62
  60. package/backend/.sqlx/query-92e8bdbcd80c5ff3db7a35cf79492048803ef305cbdef0d0a1fe5dc881ca8c71.json +0 -104
  61. package/backend/.sqlx/query-93a1605f90e9672dad29b472b6ad85fa9a55ea3ffa5abcb8724b09d61be254ca.json +0 -20
  62. package/backend/.sqlx/query-9472c8fb477958167f5fae40b85ac44252468c5226b2cdd7770f027332eed6d7.json +0 -104
  63. package/backend/.sqlx/query-96036c4f9e0f48bdc5a4a4588f0c5f288ac7aaa5425cac40fc33f337e1a351f2.json +0 -56
  64. package/backend/.sqlx/query-9edb2c01e91fd0f0fe7b56e988c7ae0393150f50be3f419a981e035c0121dfc7.json +0 -104
  65. package/backend/.sqlx/query-a157cf00616f703bfba21927f1eb1c9eec2a81c02da15f66efdba0b6c375de1b.json +0 -26
  66. package/backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json +0 -62
  67. package/backend/.sqlx/query-a5ba908419fb3e456bdd2daca41ba06cc3212ffffb8520fc7dbbcc8b60ada314.json +0 -12
  68. package/backend/.sqlx/query-a6d2961718dbc3b1a925e549f49a159c561bef58c105529275f274b27e2eba5b.json +0 -104
  69. package/backend/.sqlx/query-a9e93d5b09b29faf66e387e4d7596a792d81e75c4d3726e83c2963e8d7c9b56f.json +0 -104
  70. package/backend/.sqlx/query-ac5247c8d7fb86e4650c4b0eb9420031614c831b7b085083bac20c1af314c538.json +0 -12
  71. package/backend/.sqlx/query-afef9467be74c411c4cb119a8b2b1aea53049877dfc30cc60b486134ba4b4c9f.json +0 -68
  72. package/backend/.sqlx/query-b2b2c6b4d0b1a347b5c4cb63c3a46a265d4db53be9554989a814b069d0af82f2.json +0 -62
  73. package/backend/.sqlx/query-c50d2ff0b12e5bcc81e371089ee2d007e233e7db93aefba4fef08e7aa68f5ab7.json +0 -20
  74. package/backend/.sqlx/query-c614e6056b244ca07f1b9d44e7edc9d5819225c6f8d9e077070c6e518a17f50b.json +0 -12
  75. package/backend/.sqlx/query-c67259be8bf4ee0cfd32167b2aa3b7fe9192809181a8171bf1c2d6df731967ae.json +0 -12
  76. package/backend/.sqlx/query-d2d0a1b985ebbca6a2b3e882a221a219f3199890fa640afc946ef1a792d6d8de.json +0 -12
  77. package/backend/.sqlx/query-d30aa5786757f32bf2b9c5fe51a45e506c71c28c5994e430d9b0546adb15ffa2.json +0 -20
  78. package/backend/.sqlx/query-d3b9ea1de1576af71b312924ce7f4ea8ae5dbe2ac138ea3b4470f2d5cd734846.json +0 -12
  79. package/backend/.sqlx/query-ed8456646fa69ddd412441955f06ff22bfb790f29466450735e0b8bb1bc4ec94.json +0 -12
  80. package/backend/Cargo.toml +0 -71
  81. package/backend/build.rs +0 -32
  82. package/backend/migrations/20250617183714_init.sql +0 -44
  83. package/backend/migrations/20250620212427_execution_processes.sql +0 -25
  84. package/backend/migrations/20250620214100_remove_stdout_stderr_from_task_attempts.sql +0 -28
  85. package/backend/migrations/20250621120000_relate_activities_to_execution_processes.sql +0 -23
  86. package/backend/migrations/20250623120000_executor_sessions.sql +0 -17
  87. package/backend/migrations/20250623130000_add_executor_type_to_execution_processes.sql +0 -4
  88. package/backend/migrations/20250625000000_add_dev_script_to_projects.sql +0 -4
  89. package/backend/migrations/20250701000000_add_branch_to_task_attempts.sql +0 -2
  90. package/backend/migrations/20250701000001_add_pr_tracking_to_task_attempts.sql +0 -5
  91. package/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql +0 -2
  92. package/backend/migrations/20250708000000_add_base_branch_to_task_attempts.sql +0 -2
  93. package/backend/migrations/20250709000000_add_worktree_deleted_flag.sql +0 -2
  94. package/backend/migrations/20250710000000_add_setup_completion.sql +0 -3
  95. package/backend/migrations/20250715154859_add_task_templates.sql +0 -25
  96. package/backend/migrations/20250716143725_add_default_templates.sql +0 -174
  97. package/backend/migrations/20250716161432_update_executor_names_to_kebab_case.sql +0 -20
  98. package/backend/migrations/20250716170000_add_parent_task_to_tasks.sql +0 -7
  99. package/backend/migrations/20250717000000_drop_task_attempt_activities.sql +0 -9
  100. package/backend/migrations/20250719000000_add_cleanup_script_to_projects.sql +0 -2
  101. package/backend/migrations/20250720000000_add_cleanupscript_to_process_type_constraint.sql +0 -25
  102. package/backend/migrations/20250723000000_add_wish_to_tasks.sql +0 -7
  103. package/backend/migrations/20250724000000_remove_unique_wish_constraint.sql +0 -5
  104. package/backend/scripts/toast-notification.ps1 +0 -23
  105. package/backend/sounds/abstract-sound1.wav +0 -0
  106. package/backend/sounds/abstract-sound2.wav +0 -0
  107. package/backend/sounds/abstract-sound3.wav +0 -0
  108. package/backend/sounds/abstract-sound4.wav +0 -0
  109. package/backend/sounds/cow-mooing.wav +0 -0
  110. package/backend/sounds/phone-vibration.wav +0 -0
  111. package/backend/sounds/rooster.wav +0 -0
  112. package/backend/src/app_state.rs +0 -218
  113. package/backend/src/bin/generate_types.rs +0 -189
  114. package/backend/src/bin/mcp_task_server.rs +0 -191
  115. package/backend/src/execution_monitor.rs +0 -1193
  116. package/backend/src/executor.rs +0 -1053
  117. package/backend/src/executors/amp.rs +0 -697
  118. package/backend/src/executors/ccr.rs +0 -91
  119. package/backend/src/executors/charm_opencode.rs +0 -113
  120. package/backend/src/executors/claude.rs +0 -887
  121. package/backend/src/executors/cleanup_script.rs +0 -124
  122. package/backend/src/executors/dev_server.rs +0 -53
  123. package/backend/src/executors/echo.rs +0 -79
  124. package/backend/src/executors/gemini/config.rs +0 -67
  125. package/backend/src/executors/gemini/streaming.rs +0 -363
  126. package/backend/src/executors/gemini.rs +0 -765
  127. package/backend/src/executors/mod.rs +0 -23
  128. package/backend/src/executors/opencode_ai.rs +0 -113
  129. package/backend/src/executors/setup_script.rs +0 -130
  130. package/backend/src/executors/sst_opencode/filter.rs +0 -184
  131. package/backend/src/executors/sst_opencode/tools.rs +0 -139
  132. package/backend/src/executors/sst_opencode.rs +0 -756
  133. package/backend/src/lib.rs +0 -45
  134. package/backend/src/main.rs +0 -324
  135. package/backend/src/mcp/mod.rs +0 -1
  136. package/backend/src/mcp/task_server.rs +0 -850
  137. package/backend/src/middleware/mod.rs +0 -3
  138. package/backend/src/middleware/model_loaders.rs +0 -242
  139. package/backend/src/models/api_response.rs +0 -36
  140. package/backend/src/models/config.rs +0 -375
  141. package/backend/src/models/execution_process.rs +0 -430
  142. package/backend/src/models/executor_session.rs +0 -225
  143. package/backend/src/models/mod.rs +0 -12
  144. package/backend/src/models/project.rs +0 -356
  145. package/backend/src/models/task.rs +0 -345
  146. package/backend/src/models/task_attempt.rs +0 -1214
  147. package/backend/src/models/task_template.rs +0 -146
  148. package/backend/src/openapi.rs +0 -93
  149. package/backend/src/routes/auth.rs +0 -297
  150. package/backend/src/routes/config.rs +0 -385
  151. package/backend/src/routes/filesystem.rs +0 -228
  152. package/backend/src/routes/health.rs +0 -16
  153. package/backend/src/routes/mod.rs +0 -9
  154. package/backend/src/routes/projects.rs +0 -562
  155. package/backend/src/routes/stream.rs +0 -244
  156. package/backend/src/routes/task_attempts.rs +0 -1172
  157. package/backend/src/routes/task_templates.rs +0 -229
  158. package/backend/src/routes/tasks.rs +0 -353
  159. package/backend/src/services/analytics.rs +0 -216
  160. package/backend/src/services/git_service.rs +0 -1321
  161. package/backend/src/services/github_service.rs +0 -307
  162. package/backend/src/services/mod.rs +0 -13
  163. package/backend/src/services/notification_service.rs +0 -263
  164. package/backend/src/services/pr_monitor.rs +0 -214
  165. package/backend/src/services/process_service.rs +0 -940
  166. package/backend/src/utils/path.rs +0 -96
  167. package/backend/src/utils/shell.rs +0 -19
  168. package/backend/src/utils/text.rs +0 -24
  169. package/backend/src/utils/worktree_manager.rs +0 -578
  170. package/backend/src/utils.rs +0 -125
  171. package/backend/test.db +0 -0
  172. package/build-npm-package.sh +0 -61
  173. package/dev_assets_seed/config.json +0 -19
  174. package/frontend/.eslintrc.json +0 -25
  175. package/frontend/.prettierrc.json +0 -8
  176. package/frontend/components.json +0 -17
  177. package/frontend/index.html +0 -19
  178. package/frontend/package-lock.json +0 -7321
  179. package/frontend/package.json +0 -61
  180. package/frontend/postcss.config.js +0 -6
  181. package/frontend/public/android-chrome-192x192.png +0 -0
  182. package/frontend/public/android-chrome-512x512.png +0 -0
  183. package/frontend/public/apple-touch-icon.png +0 -0
  184. package/frontend/public/automagik-forge-logo-dark.svg +0 -3
  185. package/frontend/public/automagik-forge-logo.svg +0 -3
  186. package/frontend/public/automagik-forge-screenshot-overview.png +0 -0
  187. package/frontend/public/favicon-16x16.png +0 -0
  188. package/frontend/public/favicon-32x32.png +0 -0
  189. package/frontend/public/favicon.ico +0 -0
  190. package/frontend/public/site.webmanifest +0 -1
  191. package/frontend/public/viba-kanban-favicon.png +0 -0
  192. package/frontend/src/App.tsx +0 -157
  193. package/frontend/src/components/DisclaimerDialog.tsx +0 -106
  194. package/frontend/src/components/GitHubLoginDialog.tsx +0 -314
  195. package/frontend/src/components/OnboardingDialog.tsx +0 -185
  196. package/frontend/src/components/PrivacyOptInDialog.tsx +0 -130
  197. package/frontend/src/components/ProvidePatDialog.tsx +0 -98
  198. package/frontend/src/components/TaskTemplateManager.tsx +0 -336
  199. package/frontend/src/components/config-provider.tsx +0 -119
  200. package/frontend/src/components/context/TaskDetailsContextProvider.tsx +0 -470
  201. package/frontend/src/components/context/taskDetailsContext.ts +0 -125
  202. package/frontend/src/components/keyboard-shortcuts-demo.tsx +0 -35
  203. package/frontend/src/components/layout/navbar.tsx +0 -86
  204. package/frontend/src/components/logo.tsx +0 -44
  205. package/frontend/src/components/projects/ProjectCard.tsx +0 -155
  206. package/frontend/src/components/projects/project-detail.tsx +0 -251
  207. package/frontend/src/components/projects/project-form-fields.tsx +0 -238
  208. package/frontend/src/components/projects/project-form.tsx +0 -301
  209. package/frontend/src/components/projects/project-list.tsx +0 -200
  210. package/frontend/src/components/projects/projects-page.tsx +0 -20
  211. package/frontend/src/components/tasks/BranchSelector.tsx +0 -169
  212. package/frontend/src/components/tasks/DeleteFileConfirmationDialog.tsx +0 -94
  213. package/frontend/src/components/tasks/EditorSelectionDialog.tsx +0 -119
  214. package/frontend/src/components/tasks/TaskCard.tsx +0 -154
  215. package/frontend/src/components/tasks/TaskDetails/CollapsibleToolbar.tsx +0 -33
  216. package/frontend/src/components/tasks/TaskDetails/DiffCard.tsx +0 -109
  217. package/frontend/src/components/tasks/TaskDetails/DiffChunkSection.tsx +0 -135
  218. package/frontend/src/components/tasks/TaskDetails/DiffFile.tsx +0 -296
  219. package/frontend/src/components/tasks/TaskDetails/DiffTab.tsx +0 -32
  220. package/frontend/src/components/tasks/TaskDetails/DisplayConversationEntry.tsx +0 -392
  221. package/frontend/src/components/tasks/TaskDetails/LogsTab/Conversation.tsx +0 -256
  222. package/frontend/src/components/tasks/TaskDetails/LogsTab/ConversationEntry.tsx +0 -56
  223. package/frontend/src/components/tasks/TaskDetails/LogsTab/NormalizedConversationViewer.tsx +0 -92
  224. package/frontend/src/components/tasks/TaskDetails/LogsTab/Prompt.tsx +0 -22
  225. package/frontend/src/components/tasks/TaskDetails/LogsTab/SetupScriptRunning.tsx +0 -49
  226. package/frontend/src/components/tasks/TaskDetails/LogsTab.tsx +0 -186
  227. package/frontend/src/components/tasks/TaskDetails/ProcessesTab.tsx +0 -288
  228. package/frontend/src/components/tasks/TaskDetails/RelatedTasksTab.tsx +0 -216
  229. package/frontend/src/components/tasks/TaskDetails/TabNavigation.tsx +0 -93
  230. package/frontend/src/components/tasks/TaskDetailsHeader.tsx +0 -169
  231. package/frontend/src/components/tasks/TaskDetailsPanel.tsx +0 -126
  232. package/frontend/src/components/tasks/TaskDetailsToolbar.tsx +0 -302
  233. package/frontend/src/components/tasks/TaskFollowUpSection.tsx +0 -130
  234. package/frontend/src/components/tasks/TaskFormDialog.tsx +0 -400
  235. package/frontend/src/components/tasks/TaskKanbanBoard.tsx +0 -180
  236. package/frontend/src/components/tasks/Toolbar/CreateAttempt.tsx +0 -259
  237. package/frontend/src/components/tasks/Toolbar/CreatePRDialog.tsx +0 -243
  238. package/frontend/src/components/tasks/Toolbar/CurrentAttempt.tsx +0 -899
  239. package/frontend/src/components/tasks/index.ts +0 -2
  240. package/frontend/src/components/theme-provider.tsx +0 -82
  241. package/frontend/src/components/theme-toggle.tsx +0 -36
  242. package/frontend/src/components/ui/alert.tsx +0 -59
  243. package/frontend/src/components/ui/auto-expanding-textarea.tsx +0 -70
  244. package/frontend/src/components/ui/badge.tsx +0 -36
  245. package/frontend/src/components/ui/button.tsx +0 -56
  246. package/frontend/src/components/ui/card.tsx +0 -86
  247. package/frontend/src/components/ui/checkbox.tsx +0 -44
  248. package/frontend/src/components/ui/chip.tsx +0 -25
  249. package/frontend/src/components/ui/dialog.tsx +0 -124
  250. package/frontend/src/components/ui/dropdown-menu.tsx +0 -198
  251. package/frontend/src/components/ui/file-search-textarea.tsx +0 -292
  252. package/frontend/src/components/ui/folder-picker.tsx +0 -279
  253. package/frontend/src/components/ui/input.tsx +0 -25
  254. package/frontend/src/components/ui/label.tsx +0 -24
  255. package/frontend/src/components/ui/loader.tsx +0 -26
  256. package/frontend/src/components/ui/markdown-renderer.tsx +0 -75
  257. package/frontend/src/components/ui/select.tsx +0 -160
  258. package/frontend/src/components/ui/separator.tsx +0 -31
  259. package/frontend/src/components/ui/shadcn-io/kanban/index.tsx +0 -185
  260. package/frontend/src/components/ui/table.tsx +0 -117
  261. package/frontend/src/components/ui/tabs.tsx +0 -53
  262. package/frontend/src/components/ui/textarea.tsx +0 -22
  263. package/frontend/src/components/ui/tooltip.tsx +0 -28
  264. package/frontend/src/hooks/useNormalizedConversation.ts +0 -440
  265. package/frontend/src/index.css +0 -225
  266. package/frontend/src/lib/api.ts +0 -630
  267. package/frontend/src/lib/keyboard-shortcuts.ts +0 -266
  268. package/frontend/src/lib/responsive-config.ts +0 -70
  269. package/frontend/src/lib/types.ts +0 -39
  270. package/frontend/src/lib/utils.ts +0 -10
  271. package/frontend/src/main.tsx +0 -50
  272. package/frontend/src/pages/McpServers.tsx +0 -418
  273. package/frontend/src/pages/Settings.tsx +0 -610
  274. package/frontend/src/pages/project-tasks.tsx +0 -575
  275. package/frontend/src/pages/projects.tsx +0 -18
  276. package/frontend/src/vite-env.d.ts +0 -1
  277. package/frontend/tailwind.config.js +0 -125
  278. package/frontend/tsconfig.json +0 -26
  279. package/frontend/tsconfig.node.json +0 -10
  280. package/frontend/vite.config.ts +0 -33
  281. package/npx-cli/README.md +0 -159
  282. package/npx-cli/automagik-forge-0.1.0.tgz +0 -0
  283. package/npx-cli/automagik-forge-0.1.10.tgz +0 -0
  284. package/npx-cli/package.json +0 -17
  285. package/npx-cli/vibe-kanban-0.0.55.tgz +0 -0
  286. package/pnpm-workspace.yaml +0 -2
  287. package/rust-toolchain.toml +0 -11
  288. package/rustfmt.toml +0 -3
  289. package/scripts/load-env.js +0 -43
  290. package/scripts/mcp_test.js +0 -374
  291. package/scripts/prepare-db.js +0 -45
  292. package/scripts/setup-dev-environment.js +0 -274
  293. package/scripts/start-mcp-sse.js +0 -70
  294. package/scripts/test-debug.js +0 -32
  295. package/scripts/test-mcp-sse.js +0 -138
  296. package/scripts/test-simple.js +0 -44
  297. package/scripts/test-wish-final.js +0 -179
  298. package/scripts/test-wish-system.js +0 -221
  299. package/shared/types.ts +0 -182
  300. package/test-npm-package.sh +0 -42
  301. /package/{npx-cli/bin → bin}/cli.js +0 -0
@@ -1,578 +0,0 @@
1
- use std::{
2
- collections::HashMap,
3
- path::{Path, PathBuf},
4
- sync::{Arc, Mutex},
5
- };
6
-
7
- use git2::{Error as GitError, Repository, WorktreeAddOptions};
8
- use tracing::{debug, info, warn};
9
-
10
- // Global synchronization for worktree creation to prevent race conditions
11
- lazy_static::lazy_static! {
12
- static ref WORKTREE_CREATION_LOCKS: Arc<Mutex<HashMap<String, Arc<tokio::sync::Mutex<()>>>>> =
13
- Arc::new(Mutex::new(HashMap::new()));
14
- }
15
-
16
- pub struct WorktreeManager;
17
-
18
- impl WorktreeManager {
19
- /// Ensure worktree exists, recreating if necessary with proper synchronization
20
- /// This is the main entry point for ensuring a worktree exists and prevents race conditions
21
- pub async fn ensure_worktree_exists(
22
- repo_path: String,
23
- branch_name: String,
24
- worktree_path: PathBuf,
25
- ) -> Result<(), GitError> {
26
- let path_str = worktree_path.to_string_lossy().to_string();
27
-
28
- // Get or create a lock for this specific worktree path
29
- let lock = {
30
- let mut locks = WORKTREE_CREATION_LOCKS.lock().unwrap();
31
- locks
32
- .entry(path_str.clone())
33
- .or_insert_with(|| Arc::new(tokio::sync::Mutex::new(())))
34
- .clone()
35
- };
36
-
37
- // Acquire the lock for this specific worktree path
38
- let _guard = lock.lock().await;
39
-
40
- // Check if worktree already exists and is properly set up
41
- if Self::is_worktree_properly_set_up(&repo_path, &worktree_path).await? {
42
- debug!("Worktree already properly set up at path: {}", path_str);
43
- return Ok(());
44
- }
45
-
46
- // If worktree doesn't exist or isn't properly set up, recreate it
47
- info!("Worktree needs recreation at path: {}", path_str);
48
- Self::recreate_worktree_internal(repo_path, branch_name, worktree_path).await
49
- }
50
-
51
- /// Internal worktree recreation function (always recreates)
52
- async fn recreate_worktree_internal(
53
- repo_path: String,
54
- branch_name: String,
55
- worktree_path: PathBuf,
56
- ) -> Result<(), GitError> {
57
- let path_str = worktree_path.to_string_lossy().to_string();
58
- let branch_name_owned = branch_name.to_string();
59
- let worktree_path_owned = worktree_path.to_path_buf();
60
-
61
- // Use the provided repo path
62
- let git_repo_path = repo_path;
63
-
64
- // Get the worktree name for metadata operations
65
- let worktree_name = worktree_path
66
- .file_name()
67
- .and_then(|n| n.to_str())
68
- .ok_or_else(|| GitError::from_str("Invalid worktree path"))?
69
- .to_string();
70
-
71
- info!(
72
- "Creating worktree {} at path {}",
73
- branch_name_owned, path_str
74
- );
75
-
76
- // Step 1: Comprehensive cleanup of existing worktree and metadata (non-blocking)
77
- Self::comprehensive_worktree_cleanup_async(
78
- &git_repo_path,
79
- &worktree_path_owned,
80
- &worktree_name,
81
- )
82
- .await?;
83
-
84
- // Step 2: Ensure parent directory exists (non-blocking)
85
- if let Some(parent) = worktree_path_owned.parent() {
86
- let parent_path = parent.to_path_buf();
87
- tokio::task::spawn_blocking(move || std::fs::create_dir_all(&parent_path))
88
- .await
89
- .map_err(|e| GitError::from_str(&format!("Task join error: {}", e)))?
90
- .map_err(|e| {
91
- GitError::from_str(&format!("Failed to create parent directory: {}", e))
92
- })?;
93
- }
94
-
95
- // Step 3: Create the worktree with retry logic for metadata conflicts (non-blocking)
96
- Self::create_worktree_with_retry(
97
- &git_repo_path,
98
- &branch_name_owned,
99
- &worktree_path_owned,
100
- &worktree_name,
101
- &path_str,
102
- )
103
- .await
104
- }
105
-
106
- /// Check if a worktree is properly set up (filesystem + git metadata)
107
- async fn is_worktree_properly_set_up(
108
- repo_path: &str,
109
- worktree_path: &Path,
110
- ) -> Result<bool, GitError> {
111
- let repo_path = repo_path.to_string();
112
- let worktree_path = worktree_path.to_path_buf();
113
-
114
- tokio::task::spawn_blocking(move || {
115
- // Check 1: Filesystem path must exist
116
- if !worktree_path.exists() {
117
- return Ok(false);
118
- }
119
-
120
- // Check 2: Worktree must be registered in git metadata using find_worktree
121
- let repo = Repository::open(&repo_path)?;
122
- let worktree_name = worktree_path
123
- .file_name()
124
- .and_then(|n| n.to_str())
125
- .ok_or_else(|| GitError::from_str("Invalid worktree path"))?;
126
-
127
- // Try to find the worktree - if it exists and is valid, we're good
128
- match repo.find_worktree(worktree_name) {
129
- Ok(_) => Ok(true),
130
- Err(_) => Ok(false),
131
- }
132
- })
133
- .await
134
- .map_err(|e| GitError::from_str(&format!("Task join error: {}", e)))?
135
- }
136
-
137
- /// Try to remove a worktree registration from git
138
- fn try_remove_worktree(repo: &Repository, worktree_name: &str) -> Result<(), GitError> {
139
- let worktrees = repo.worktrees()?;
140
-
141
- for name in worktrees.iter().flatten() {
142
- if name == worktree_name {
143
- let worktree = repo.find_worktree(name)?;
144
- worktree.prune(None)?;
145
- debug!("Successfully removed worktree registration: {}", name);
146
- return Ok(());
147
- }
148
- }
149
-
150
- debug!("Worktree {} not found in git worktrees list", worktree_name);
151
- Ok(())
152
- }
153
-
154
- /// Comprehensive cleanup of worktree path and metadata to prevent "path exists" errors (blocking)
155
- fn comprehensive_worktree_cleanup(
156
- repo: &Repository,
157
- worktree_path: &Path,
158
- worktree_name: &str,
159
- ) -> Result<(), GitError> {
160
- debug!("Performing cleanup for worktree: {}", worktree_name);
161
-
162
- let git_repo_path = Self::get_git_repo_path(repo)?;
163
-
164
- // Step 1: Always try to remove worktree registration first (this may fail if not registered)
165
- if let Err(e) = Self::try_remove_worktree(repo, worktree_name) {
166
- debug!(
167
- "Worktree registration removal failed or not found (non-fatal): {}",
168
- e
169
- );
170
- }
171
-
172
- // Step 2: Always force cleanup metadata directory (proactive cleanup)
173
- if let Err(e) = Self::force_cleanup_worktree_metadata(&git_repo_path, worktree_name) {
174
- debug!("Metadata cleanup failed (non-fatal): {}", e);
175
- }
176
-
177
- // Step 3: Clean up physical worktree directory if it exists
178
- if worktree_path.exists() {
179
- debug!(
180
- "Removing existing worktree directory: {}",
181
- worktree_path.display()
182
- );
183
- std::fs::remove_dir_all(worktree_path).map_err(|e| {
184
- GitError::from_str(&format!(
185
- "Failed to remove existing directory {}: {}",
186
- worktree_path.display(),
187
- e
188
- ))
189
- })?;
190
- }
191
-
192
- debug!(
193
- "Comprehensive cleanup completed for worktree: {}",
194
- worktree_name
195
- );
196
- Ok(())
197
- }
198
-
199
- /// Async version of comprehensive cleanup to avoid blocking the main runtime
200
- async fn comprehensive_worktree_cleanup_async(
201
- git_repo_path: &str,
202
- worktree_path: &Path,
203
- worktree_name: &str,
204
- ) -> Result<(), GitError> {
205
- let git_repo_path_owned = git_repo_path.to_string();
206
- let worktree_path_owned = worktree_path.to_path_buf();
207
- let worktree_name_owned = worktree_name.to_string();
208
-
209
- // First, try to open the repository to see if it exists
210
- let repo_result = tokio::task::spawn_blocking({
211
- let git_repo_path = git_repo_path_owned.clone();
212
- move || Repository::open(&git_repo_path)
213
- })
214
- .await;
215
-
216
- match repo_result {
217
- Ok(Ok(repo)) => {
218
- // Repository exists, perform comprehensive cleanup
219
- tokio::task::spawn_blocking(move || {
220
- Self::comprehensive_worktree_cleanup(
221
- &repo,
222
- &worktree_path_owned,
223
- &worktree_name_owned,
224
- )
225
- })
226
- .await
227
- .map_err(|e| GitError::from_str(&format!("Task join error: {}", e)))?
228
- }
229
- Ok(Err(e)) => {
230
- // Repository doesn't exist (likely deleted project), fall back to simple cleanup
231
- debug!(
232
- "Failed to open repository at {}: {}. Falling back to simple cleanup for worktree at {}",
233
- git_repo_path_owned, e, worktree_path_owned.display()
234
- );
235
- Self::simple_worktree_cleanup(&worktree_path_owned).await?;
236
- Ok(())
237
- }
238
- Err(e) => Err(GitError::from_str(&format!("Task join error: {}", e))),
239
- }
240
- }
241
-
242
- /// Create worktree with retry logic in non-blocking manner
243
- async fn create_worktree_with_retry(
244
- git_repo_path: &str,
245
- branch_name: &str,
246
- worktree_path: &Path,
247
- worktree_name: &str,
248
- path_str: &str,
249
- ) -> Result<(), GitError> {
250
- let git_repo_path = git_repo_path.to_string();
251
- let branch_name = branch_name.to_string();
252
- let worktree_path = worktree_path.to_path_buf();
253
- let worktree_name = worktree_name.to_string();
254
- let path_str = path_str.to_string();
255
-
256
- tokio::task::spawn_blocking(move || {
257
- // Open repository in blocking context
258
- let repo = Repository::open(&git_repo_path)
259
- .map_err(|e| GitError::from_str(&format!("Failed to open repository: {}", e)))?;
260
-
261
- // Find the branch reference using the branch name
262
- let branch_ref = repo
263
- .find_branch(&branch_name, git2::BranchType::Local)
264
- .map_err(|e| {
265
- GitError::from_str(&format!("Branch '{}' not found: {}", branch_name, e))
266
- })?
267
- .into_reference();
268
-
269
- // Create worktree options
270
- let mut worktree_opts = WorktreeAddOptions::new();
271
- worktree_opts.reference(Some(&branch_ref));
272
-
273
- match repo.worktree(&branch_name, &worktree_path, Some(&worktree_opts)) {
274
- Ok(_) => {
275
- // Verify the worktree was actually created
276
- if !worktree_path.exists() {
277
- return Err(GitError::from_str(&format!(
278
- "Worktree creation reported success but path {} does not exist",
279
- path_str
280
- )));
281
- }
282
-
283
- info!(
284
- "Successfully created worktree {} at {}",
285
- branch_name, path_str
286
- );
287
-
288
- // Fix commondir for Windows/WSL compatibility
289
- if let Err(e) = Self::fix_worktree_commondir_for_windows_wsl(
290
- Path::new(&git_repo_path),
291
- &worktree_name,
292
- ) {
293
- warn!("Failed to fix worktree commondir for Windows/WSL: {}", e);
294
- }
295
-
296
- Ok(())
297
- }
298
- Err(e) if e.code() == git2::ErrorCode::Exists => {
299
- // Handle the specific "directory exists" error for metadata
300
- debug!(
301
- "Worktree metadata directory exists, attempting force cleanup: {}",
302
- e
303
- );
304
-
305
- // Force cleanup metadata and try one more time
306
- Self::force_cleanup_worktree_metadata(&git_repo_path, &worktree_name).map_err(
307
- |e| {
308
- GitError::from_str(&format!(
309
- "Failed to cleanup worktree metadata: {}",
310
- e
311
- ))
312
- },
313
- )?;
314
-
315
- // Try again after cleanup
316
- match repo.worktree(&branch_name, &worktree_path, Some(&worktree_opts)) {
317
- Ok(_) => {
318
- if !worktree_path.exists() {
319
- return Err(GitError::from_str(&format!(
320
- "Worktree creation reported success but path {} does not exist",
321
- path_str
322
- )));
323
- }
324
-
325
- info!(
326
- "Successfully created worktree {} at {} after metadata cleanup",
327
- branch_name, path_str
328
- );
329
-
330
- // Fix commondir for Windows/WSL compatibility
331
- if let Err(e) = Self::fix_worktree_commondir_for_windows_wsl(
332
- Path::new(&git_repo_path),
333
- &worktree_name,
334
- ) {
335
- warn!("Failed to fix worktree commondir for Windows/WSL: {}", e);
336
- }
337
-
338
- Ok(())
339
- }
340
- Err(retry_error) => {
341
- debug!(
342
- "Worktree creation failed even after metadata cleanup: {}",
343
- retry_error
344
- );
345
- Err(retry_error)
346
- }
347
- }
348
- }
349
- Err(e) => Err(e),
350
- }
351
- })
352
- .await
353
- .map_err(|e| GitError::from_str(&format!("Task join error: {}", e)))?
354
- }
355
-
356
- /// Get the git repository path
357
- fn get_git_repo_path(repo: &Repository) -> Result<String, GitError> {
358
- repo.workdir()
359
- .ok_or_else(|| GitError::from_str("Repository has no working directory"))?
360
- .to_str()
361
- .ok_or_else(|| GitError::from_str("Repository path is not valid UTF-8"))
362
- .map(|s| s.to_string())
363
- }
364
-
365
- /// Force cleanup worktree metadata directory
366
- fn force_cleanup_worktree_metadata(
367
- git_repo_path: &str,
368
- worktree_name: &str,
369
- ) -> Result<(), std::io::Error> {
370
- let git_worktree_metadata_path = Path::new(git_repo_path)
371
- .join(".git")
372
- .join("worktrees")
373
- .join(worktree_name);
374
-
375
- if git_worktree_metadata_path.exists() {
376
- debug!(
377
- "Force removing git worktree metadata: {}",
378
- git_worktree_metadata_path.display()
379
- );
380
- std::fs::remove_dir_all(&git_worktree_metadata_path)?;
381
- }
382
-
383
- Ok(())
384
- }
385
-
386
- /// Clean up a worktree path and its git metadata (non-blocking)
387
- /// If git_repo_path is None, attempts to infer it from the worktree itself
388
- pub async fn cleanup_worktree(
389
- worktree_path: &Path,
390
- git_repo_path: Option<&str>,
391
- ) -> Result<(), GitError> {
392
- let path_str = worktree_path.to_string_lossy().to_string();
393
-
394
- // Get the same lock to ensure we don't interfere with creation
395
- let lock = {
396
- let mut locks = WORKTREE_CREATION_LOCKS.lock().unwrap();
397
- locks
398
- .entry(path_str.clone())
399
- .or_insert_with(|| Arc::new(tokio::sync::Mutex::new(())))
400
- .clone()
401
- };
402
-
403
- let _guard = lock.lock().await;
404
-
405
- if let Some(worktree_name) = worktree_path.file_name().and_then(|n| n.to_str()) {
406
- // Try to determine the git repo path if not provided
407
- let resolved_repo_path = if let Some(repo_path) = git_repo_path {
408
- Some(repo_path.to_string())
409
- } else {
410
- Self::infer_git_repo_path(worktree_path).await
411
- };
412
-
413
- if let Some(repo_path) = resolved_repo_path {
414
- Self::comprehensive_worktree_cleanup_async(
415
- &repo_path,
416
- worktree_path,
417
- worktree_name,
418
- )
419
- .await?;
420
- } else {
421
- // Can't determine repo path, just clean up the worktree directory
422
- debug!(
423
- "Cannot determine git repo path for worktree {}, performing simple cleanup",
424
- path_str
425
- );
426
- Self::simple_worktree_cleanup(worktree_path).await?;
427
- }
428
- } else {
429
- return Err(GitError::from_str(
430
- "Invalid worktree path, cannot determine name",
431
- ));
432
- }
433
-
434
- Ok(())
435
- }
436
-
437
- /// Try to infer the git repository path from a worktree
438
- async fn infer_git_repo_path(worktree_path: &Path) -> Option<String> {
439
- // Try using git rev-parse --git-common-dir from within the worktree
440
- let worktree_path_owned = worktree_path.to_path_buf();
441
-
442
- tokio::task::spawn_blocking(move || {
443
- let (shell_cmd, shell_arg) = crate::utils::shell::get_shell_command();
444
- let git_command = "git rev-parse --git-common-dir";
445
-
446
- let output = std::process::Command::new(shell_cmd)
447
- .args([shell_arg, git_command])
448
- .current_dir(&worktree_path_owned)
449
- .output()
450
- .ok()?;
451
-
452
- if output.status.success() {
453
- let git_common_dir = String::from_utf8(output.stdout).ok()?.trim().to_string();
454
-
455
- // git-common-dir gives us the path to the .git directory
456
- // We need the working directory (parent of .git)
457
- let git_dir_path = std::path::Path::new(&git_common_dir);
458
- if git_dir_path.file_name() == Some(std::ffi::OsStr::new(".git")) {
459
- git_dir_path.parent()?.to_str().map(|s| s.to_string())
460
- } else {
461
- // In case of bare repo or unusual setup, use the git-common-dir as is
462
- Some(git_common_dir)
463
- }
464
- } else {
465
- None
466
- }
467
- })
468
- .await
469
- .ok()
470
- .flatten()
471
- }
472
-
473
- /// Simple worktree cleanup when we can't determine the main repo
474
- async fn simple_worktree_cleanup(worktree_path: &Path) -> Result<(), GitError> {
475
- let worktree_path_owned = worktree_path.to_path_buf();
476
-
477
- tokio::task::spawn_blocking(move || {
478
- if worktree_path_owned.exists() {
479
- std::fs::remove_dir_all(&worktree_path_owned).map_err(|e| {
480
- GitError::from_str(&format!(
481
- "Failed to remove worktree directory {}: {}",
482
- worktree_path_owned.display(),
483
- e
484
- ))
485
- })?;
486
- info!(
487
- "Removed worktree directory: {}",
488
- worktree_path_owned.display()
489
- );
490
- }
491
- Ok(())
492
- })
493
- .await
494
- .map_err(|e| GitError::from_str(&format!("Task join error: {}", e)))?
495
- }
496
-
497
- /// Rewrite worktree's commondir file to use relative paths for WSL compatibility
498
- ///
499
- /// This fixes Git repository corruption in WSL environments where git2/libgit2 creates
500
- /// worktrees with absolute WSL paths (/mnt/c/...) that Windows Git cannot understand.
501
- /// Git CLI creates relative paths (../../..) which work across both environments.
502
- ///
503
- /// References:
504
- /// - Git 2.48+ native support: https://git-scm.com/docs/git-config/2.48.0#Documentation/git-config.txt-worktreeuseRelativePaths
505
- /// - WSL worktree absolute path issue: https://github.com/git-ecosystem/git-credential-manager/issues/1789
506
- pub fn fix_worktree_commondir_for_windows_wsl(
507
- git_repo_path: &Path,
508
- worktree_name: &str,
509
- ) -> Result<(), std::io::Error> {
510
- if !cfg!(target_os = "linux") || !crate::utils::is_wsl2() {
511
- debug!("Skipping commondir fix for non-WSL2 environment");
512
- return Ok(());
513
- }
514
-
515
- let commondir_path = git_repo_path
516
- .join(".git")
517
- .join("worktrees")
518
- .join(worktree_name)
519
- .join("commondir");
520
-
521
- if !commondir_path.exists() {
522
- debug!(
523
- "commondir file does not exist: {}",
524
- commondir_path.display()
525
- );
526
- return Ok(());
527
- }
528
-
529
- // Read current commondir content
530
- let current_content = std::fs::read_to_string(&commondir_path)?.trim().to_string();
531
-
532
- debug!("Current commondir content: {}", current_content);
533
-
534
- // Skip if already relative
535
- if !Path::new(&current_content).is_absolute() {
536
- debug!("commondir already contains relative path, skipping");
537
- return Ok(());
538
- }
539
-
540
- // Calculate relative path from worktree metadata dir to repo .git dir
541
- let metadata_dir = commondir_path.parent().unwrap();
542
- let target_git_dir = Path::new(&current_content);
543
-
544
- if let Some(relative_path) = pathdiff::diff_paths(target_git_dir, metadata_dir) {
545
- let relative_path_str = relative_path.to_string_lossy();
546
-
547
- // Safety check: ensure the relative path resolves to the same absolute path
548
- let resolved_path = metadata_dir.join(&relative_path);
549
- if let (Ok(resolved_canonical), Ok(target_canonical)) =
550
- (resolved_path.canonicalize(), target_git_dir.canonicalize())
551
- {
552
- if resolved_canonical == target_canonical {
553
- // Write the relative path
554
- std::fs::write(&commondir_path, format!("{}\n", relative_path_str))?;
555
- info!(
556
- "Rewrote commondir to relative path: {} -> {}",
557
- current_content, relative_path_str
558
- );
559
- } else {
560
- warn!(
561
- "Safety check failed: relative path {} does not resolve to same target",
562
- relative_path_str
563
- );
564
- }
565
- } else {
566
- warn!("Failed to canonicalize paths for safety check");
567
- }
568
- } else {
569
- warn!(
570
- "Failed to calculate relative path from {} to {}",
571
- metadata_dir.display(),
572
- target_git_dir.display()
573
- );
574
- }
575
-
576
- Ok(())
577
- }
578
- }
@@ -1,125 +0,0 @@
1
- use std::{env, sync::OnceLock};
2
-
3
- pub mod path;
4
- pub mod shell;
5
- pub mod text;
6
- pub mod worktree_manager;
7
-
8
- const PROJECT_ROOT: &str = env!("CARGO_MANIFEST_DIR");
9
-
10
- /// Cache for WSL2 detection result
11
- static WSL2_CACHE: OnceLock<bool> = OnceLock::new();
12
-
13
- /// Check if running in WSL2 (cached)
14
- pub fn is_wsl2() -> bool {
15
- *WSL2_CACHE.get_or_init(|| {
16
- // Check for WSL environment variables
17
- if std::env::var("WSL_DISTRO_NAME").is_ok() || std::env::var("WSLENV").is_ok() {
18
- tracing::debug!("WSL2 detected via environment variables");
19
- return true;
20
- }
21
-
22
- // Check /proc/version for WSL2 signature
23
- if let Ok(version) = std::fs::read_to_string("/proc/version") {
24
- if version.contains("WSL2") || version.contains("microsoft") {
25
- tracing::debug!("WSL2 detected via /proc/version");
26
- return true;
27
- }
28
- }
29
-
30
- tracing::debug!("WSL2 not detected");
31
- false
32
- })
33
- }
34
-
35
- pub fn asset_dir() -> std::path::PathBuf {
36
- if cfg!(debug_assertions) {
37
- std::path::PathBuf::from(PROJECT_ROOT).join("../dev_assets")
38
- } else if cfg!(target_os = "windows") {
39
- dirs::data_dir()
40
- .expect("Could not find data directory")
41
- .join("automagik-forge")
42
- } else {
43
- dirs::home_dir()
44
- .expect("Could not find home directory")
45
- .join(".automagik-forge")
46
- }
47
-
48
- // ✔ Linux/macOS → ~/.automagik-forge
49
- // ✔ Windows → %APPDATA%\automagik-forge
50
- }
51
-
52
- pub fn config_path() -> std::path::PathBuf {
53
- asset_dir().join("config.json")
54
- }
55
-
56
- pub fn cache_dir() -> std::path::PathBuf {
57
- if cfg!(debug_assertions) {
58
- std::path::PathBuf::from(PROJECT_ROOT).join("../dev_assets/.cache")
59
- } else if cfg!(target_os = "windows") {
60
- dirs::cache_dir()
61
- .expect("Could not find cache directory")
62
- .join("automagik-forge")
63
- } else {
64
- dirs::home_dir()
65
- .expect("Could not find home directory")
66
- .join(".automagik-forge")
67
- .join("cache")
68
- }
69
-
70
- // ✔ Linux/macOS → ~/.automagik-forge/cache
71
- // ✔ Windows → %LOCALAPPDATA%\automagik-forge
72
- }
73
-
74
- /// Get or create cached PowerShell script file
75
- pub async fn get_powershell_script(
76
- ) -> Result<std::path::PathBuf, Box<dyn std::error::Error + Send + Sync>> {
77
- use std::io::Write;
78
-
79
- let cache_dir = cache_dir();
80
- let script_path = cache_dir.join("toast-notification.ps1");
81
-
82
- // Check if cached file already exists and is valid
83
- if script_path.exists() {
84
- // Verify file has content (basic validation)
85
- if let Ok(metadata) = std::fs::metadata(&script_path) {
86
- if metadata.len() > 0 {
87
- return Ok(script_path);
88
- }
89
- }
90
- }
91
-
92
- // File doesn't exist or is invalid, create it
93
- let script_content = crate::ScriptAssets::get("toast-notification.ps1")
94
- .ok_or("Embedded PowerShell script not found: toast-notification.ps1")?
95
- .data;
96
-
97
- // Ensure cache directory exists
98
- std::fs::create_dir_all(&cache_dir)
99
- .map_err(|e| format!("Failed to create cache directory: {}", e))?;
100
-
101
- let mut file = std::fs::File::create(&script_path)
102
- .map_err(|e| format!("Failed to create PowerShell script file: {}", e))?;
103
-
104
- file.write_all(&script_content)
105
- .map_err(|e| format!("Failed to write PowerShell script data: {}", e))?;
106
-
107
- drop(file); // Ensure file is closed
108
-
109
- Ok(script_path)
110
- }
111
-
112
- /// Open URL in browser with WSL2 support
113
- pub async fn open_browser(url: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
114
- if is_wsl2() {
115
- // In WSL2, use PowerShell to open the browser
116
- tokio::process::Command::new("powershell.exe")
117
- .arg("-Command")
118
- .arg(format!("Start-Process '{}'", url))
119
- .spawn()?;
120
- Ok(())
121
- } else {
122
- // Use the standard open crate for other platforms
123
- open::that(url).map_err(|e| e.into())
124
- }
125
- }