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.
- package/.cargo/config.toml +13 -0
- package/.claude/commands/commit.md +376 -0
- package/.claude/commands/prompt.md +871 -0
- package/.env.example +20 -0
- package/.github/actions/setup-node/action.yml +29 -0
- package/.github/images/automagik-logo.png +0 -0
- package/.github/workflows/pre-release.yml +470 -0
- package/.github/workflows/publish.yml +145 -0
- package/.github/workflows/test.yml +63 -0
- package/.mcp.json +57 -0
- package/AGENT.md +40 -0
- package/CLAUDE.md +40 -0
- package/CODE-OF-CONDUCT.md +89 -0
- package/Cargo.toml +19 -0
- package/Dockerfile +43 -0
- package/LICENSE +201 -0
- package/Makefile +97 -0
- package/README.md +447 -143
- package/backend/.sqlx/query-01b7e2bac1261d8be3d03c03df3e5220590da6c31c77f161074fc62752d63881.json +12 -0
- package/backend/.sqlx/query-03f2b02ba6dc5ea2b3cf6b1004caea0ad6bcc10ebd63f441d321a389f026e263.json +12 -0
- package/backend/.sqlx/query-0923b77d137a29fc54d399a873ff15fc4af894490bc65a4d344a7575cb0d8643.json +12 -0
- package/backend/.sqlx/query-0f808bcdb63c5f180836e448dd64c435c51758b2fc54a52ce9e67495b1ab200e.json +68 -0
- package/backend/.sqlx/query-1268afe9ca849daa6722e3df7ca8e9e61f0d37052e782bb5452ab8e1018d9b63.json +12 -0
- package/backend/.sqlx/query-1b082630a9622f8667ee7a9aba2c2d3176019a68c6bb83d33008594821415a57.json +12 -0
- package/backend/.sqlx/query-1c7b06ba1e112abf6b945a2ff08a0b40ec23f3738c2e7399f067b558cf8d490e.json +12 -0
- package/backend/.sqlx/query-1f619f01f46859a64ded531dd0ef61abacfe62e758abe7030a6aa745140b95ca.json +104 -0
- package/backend/.sqlx/query-1fca1ce14b4b20205364cd1f1f45ebe1d2e30cd745e59e189d56487b5639dfbb.json +12 -0
- package/backend/.sqlx/query-212828320e8d871ab9d83705a040b23bcf0393dc7252177fc539a74657f578ef.json +32 -0
- package/backend/.sqlx/query-290ce5c152be8d36e58ff42570f9157beb07ab9e77a03ec6fc30b4f56f9b8f6b.json +56 -0
- package/backend/.sqlx/query-2b471d2c2e8ffbe0cd42d2a91b814c0d79f9d09200f147e3cea33ba4ce673c8a.json +68 -0
- package/backend/.sqlx/query-354a48c705bb9bb2048c1b7f10fcb714e23f9db82b7a4ea6932486197b2ede6a.json +92 -0
- package/backend/.sqlx/query-36c9e3dd10648e94b949db5c91a774ecb1e10a899ef95da74066eccedca4d8b2.json +12 -0
- package/backend/.sqlx/query-36e4ba7bbd81b402d5a20b6005755eafbb174c8dda442081823406ac32809a94.json +56 -0
- package/backend/.sqlx/query-3a5b3c98a55ca183ab20c74708e3d7e579dda37972c059e7515c4ceee4bd8dd3.json +62 -0
- package/backend/.sqlx/query-3d0a1cabf2a52e9d90cdfd29c509ca89aeb448d0c1d2446c65cd43db40735e86.json +62 -0
- package/backend/.sqlx/query-3d6bd16fbce59efe30b7f67ea342e0e4ea6d1432389c02468ad79f1f742d4031.json +56 -0
- package/backend/.sqlx/query-4049ca413b285a05aca6b25385e9c8185575f01e9069e4e8581aa45d713f612f.json +32 -0
- package/backend/.sqlx/query-412bacd3477d86369082e90f52240407abce436cb81292d42b2dbe1e5c18eea1.json +104 -0
- package/backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json +62 -0
- package/backend/.sqlx/query-461cc1b0bb6fd909afc9dd2246e8526b3771cfbb0b22ae4b5d17b51af587b9e2.json +56 -0
- package/backend/.sqlx/query-58408c7a8cdeeda0bef359f1f9bd91299a339dc2b191462fc58c9736a56d5227.json +92 -0
- package/backend/.sqlx/query-5a886026d75d515c01f347cc203c8d99dd04c61dc468e2e4c5aa548436d13834.json +62 -0
- package/backend/.sqlx/query-5b902137b11022d2e1a5c4f6a9c83fec1a856c6a710aff831abd2382ede76b43.json +12 -0
- package/backend/.sqlx/query-5ed1238e52e59bb5f76c0f153fd99a14093f7ce2585bf9843585608f17ec575b.json +104 -0
- package/backend/.sqlx/query-6e8b860b14decfc2227dc57213f38442943d3fbef5c8418fd6b634c6e0f5e2ea.json +104 -0
- package/backend/.sqlx/query-6ec414276994c4ccb2433eaa5b1b342168557d17ddf5a52dac84cb1b59b9de8f.json +68 -0
- package/backend/.sqlx/query-6ecfa16d0cf825aacf233544b5baf151e9adfdca26c226ad71020d291fd802d5.json +62 -0
- package/backend/.sqlx/query-72509d252c39fce77520aa816cb2acbc1fb35dc2605e7be893610599b2427f2e.json +62 -0
- package/backend/.sqlx/query-75239b2da188f749707d77f3c1544332ca70db3d6d6743b2601dc0d167536437.json +62 -0
- package/backend/.sqlx/query-83d10e29f8478aff33434f9ac67068e013b888b953a2657e2bb72a6f619d04f2.json +50 -0
- package/backend/.sqlx/query-8610803360ea18b9b9d078a6981ea56abfbfe84e6354fc1d5ae4c622e01410ed.json +68 -0
- package/backend/.sqlx/query-86d03eb70eef39c59296416867f2ee66c9f7cd8b7f961fbda2f89fc0a1c442c2.json +12 -0
- package/backend/.sqlx/query-87d0feb5a6b442bad9c60068ea7569599cc6fc91a0e2692ecb42e93b03201b9d.json +68 -0
- package/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json +12 -0
- package/backend/.sqlx/query-8f01ebd64bdcde6a090479f14810d73ba23020e76fd70854ac57f2da251702c3.json +12 -0
- package/backend/.sqlx/query-90fd607fcb2dca72239ff25e618e21e174b195991eaa33722cbf5f76da84cfab.json +62 -0
- package/backend/.sqlx/query-92e8bdbcd80c5ff3db7a35cf79492048803ef305cbdef0d0a1fe5dc881ca8c71.json +104 -0
- package/backend/.sqlx/query-93a1605f90e9672dad29b472b6ad85fa9a55ea3ffa5abcb8724b09d61be254ca.json +20 -0
- package/backend/.sqlx/query-9472c8fb477958167f5fae40b85ac44252468c5226b2cdd7770f027332eed6d7.json +104 -0
- package/backend/.sqlx/query-96036c4f9e0f48bdc5a4a4588f0c5f288ac7aaa5425cac40fc33f337e1a351f2.json +56 -0
- package/backend/.sqlx/query-9edb2c01e91fd0f0fe7b56e988c7ae0393150f50be3f419a981e035c0121dfc7.json +104 -0
- package/backend/.sqlx/query-a157cf00616f703bfba21927f1eb1c9eec2a81c02da15f66efdba0b6c375de1b.json +26 -0
- package/backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json +62 -0
- package/backend/.sqlx/query-a5ba908419fb3e456bdd2daca41ba06cc3212ffffb8520fc7dbbcc8b60ada314.json +12 -0
- package/backend/.sqlx/query-a6d2961718dbc3b1a925e549f49a159c561bef58c105529275f274b27e2eba5b.json +104 -0
- package/backend/.sqlx/query-a9e93d5b09b29faf66e387e4d7596a792d81e75c4d3726e83c2963e8d7c9b56f.json +104 -0
- package/backend/.sqlx/query-ac5247c8d7fb86e4650c4b0eb9420031614c831b7b085083bac20c1af314c538.json +12 -0
- package/backend/.sqlx/query-afef9467be74c411c4cb119a8b2b1aea53049877dfc30cc60b486134ba4b4c9f.json +68 -0
- package/backend/.sqlx/query-b2b2c6b4d0b1a347b5c4cb63c3a46a265d4db53be9554989a814b069d0af82f2.json +62 -0
- package/backend/.sqlx/query-c50d2ff0b12e5bcc81e371089ee2d007e233e7db93aefba4fef08e7aa68f5ab7.json +20 -0
- package/backend/.sqlx/query-c614e6056b244ca07f1b9d44e7edc9d5819225c6f8d9e077070c6e518a17f50b.json +12 -0
- package/backend/.sqlx/query-c67259be8bf4ee0cfd32167b2aa3b7fe9192809181a8171bf1c2d6df731967ae.json +12 -0
- package/backend/.sqlx/query-d2d0a1b985ebbca6a2b3e882a221a219f3199890fa640afc946ef1a792d6d8de.json +12 -0
- package/backend/.sqlx/query-d30aa5786757f32bf2b9c5fe51a45e506c71c28c5994e430d9b0546adb15ffa2.json +20 -0
- package/backend/.sqlx/query-d3b9ea1de1576af71b312924ce7f4ea8ae5dbe2ac138ea3b4470f2d5cd734846.json +12 -0
- package/backend/.sqlx/query-ed8456646fa69ddd412441955f06ff22bfb790f29466450735e0b8bb1bc4ec94.json +12 -0
- package/backend/Cargo.toml +71 -0
- package/backend/build.rs +32 -0
- package/backend/migrations/20250617183714_init.sql +44 -0
- package/backend/migrations/20250620212427_execution_processes.sql +25 -0
- package/backend/migrations/20250620214100_remove_stdout_stderr_from_task_attempts.sql +28 -0
- package/backend/migrations/20250621120000_relate_activities_to_execution_processes.sql +23 -0
- package/backend/migrations/20250623120000_executor_sessions.sql +17 -0
- package/backend/migrations/20250623130000_add_executor_type_to_execution_processes.sql +4 -0
- package/backend/migrations/20250625000000_add_dev_script_to_projects.sql +4 -0
- package/backend/migrations/20250701000000_add_branch_to_task_attempts.sql +2 -0
- package/backend/migrations/20250701000001_add_pr_tracking_to_task_attempts.sql +5 -0
- package/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql +2 -0
- package/backend/migrations/20250708000000_add_base_branch_to_task_attempts.sql +2 -0
- package/backend/migrations/20250709000000_add_worktree_deleted_flag.sql +2 -0
- package/backend/migrations/20250710000000_add_setup_completion.sql +3 -0
- package/backend/migrations/20250715154859_add_task_templates.sql +25 -0
- package/backend/migrations/20250716143725_add_default_templates.sql +174 -0
- package/backend/migrations/20250716161432_update_executor_names_to_kebab_case.sql +20 -0
- package/backend/migrations/20250716170000_add_parent_task_to_tasks.sql +7 -0
- package/backend/migrations/20250717000000_drop_task_attempt_activities.sql +9 -0
- package/backend/migrations/20250719000000_add_cleanup_script_to_projects.sql +2 -0
- package/backend/migrations/20250720000000_add_cleanupscript_to_process_type_constraint.sql +25 -0
- package/backend/migrations/20250723000000_add_wish_to_tasks.sql +7 -0
- package/backend/migrations/20250724000000_remove_unique_wish_constraint.sql +5 -0
- package/backend/scripts/toast-notification.ps1 +23 -0
- package/backend/sounds/abstract-sound1.wav +0 -0
- package/backend/sounds/abstract-sound2.wav +0 -0
- package/backend/sounds/abstract-sound3.wav +0 -0
- package/backend/sounds/abstract-sound4.wav +0 -0
- package/backend/sounds/cow-mooing.wav +0 -0
- package/backend/sounds/phone-vibration.wav +0 -0
- package/backend/sounds/rooster.wav +0 -0
- package/backend/src/app_state.rs +218 -0
- package/backend/src/bin/generate_types.rs +189 -0
- package/backend/src/bin/mcp_task_server.rs +191 -0
- package/backend/src/execution_monitor.rs +1193 -0
- package/backend/src/executor.rs +1053 -0
- package/backend/src/executors/amp.rs +697 -0
- package/backend/src/executors/ccr.rs +91 -0
- package/backend/src/executors/charm_opencode.rs +113 -0
- package/backend/src/executors/claude.rs +887 -0
- package/backend/src/executors/cleanup_script.rs +124 -0
- package/backend/src/executors/dev_server.rs +53 -0
- package/backend/src/executors/echo.rs +79 -0
- package/backend/src/executors/gemini/config.rs +67 -0
- package/backend/src/executors/gemini/streaming.rs +363 -0
- package/backend/src/executors/gemini.rs +765 -0
- package/backend/src/executors/mod.rs +23 -0
- package/backend/src/executors/opencode_ai.rs +113 -0
- package/backend/src/executors/setup_script.rs +130 -0
- package/backend/src/executors/sst_opencode/filter.rs +184 -0
- package/backend/src/executors/sst_opencode/tools.rs +139 -0
- package/backend/src/executors/sst_opencode.rs +756 -0
- package/backend/src/lib.rs +45 -0
- package/backend/src/main.rs +324 -0
- package/backend/src/mcp/mod.rs +1 -0
- package/backend/src/mcp/task_server.rs +850 -0
- package/backend/src/middleware/mod.rs +3 -0
- package/backend/src/middleware/model_loaders.rs +242 -0
- package/backend/src/models/api_response.rs +36 -0
- package/backend/src/models/config.rs +375 -0
- package/backend/src/models/execution_process.rs +430 -0
- package/backend/src/models/executor_session.rs +225 -0
- package/backend/src/models/mod.rs +12 -0
- package/backend/src/models/project.rs +356 -0
- package/backend/src/models/task.rs +345 -0
- package/backend/src/models/task_attempt.rs +1214 -0
- package/backend/src/models/task_template.rs +146 -0
- package/backend/src/openapi.rs +93 -0
- package/backend/src/routes/auth.rs +297 -0
- package/backend/src/routes/config.rs +385 -0
- package/backend/src/routes/filesystem.rs +228 -0
- package/backend/src/routes/health.rs +16 -0
- package/backend/src/routes/mod.rs +9 -0
- package/backend/src/routes/projects.rs +562 -0
- package/backend/src/routes/stream.rs +244 -0
- package/backend/src/routes/task_attempts.rs +1172 -0
- package/backend/src/routes/task_templates.rs +229 -0
- package/backend/src/routes/tasks.rs +353 -0
- package/backend/src/services/analytics.rs +216 -0
- package/backend/src/services/git_service.rs +1321 -0
- package/backend/src/services/github_service.rs +307 -0
- package/backend/src/services/mod.rs +13 -0
- package/backend/src/services/notification_service.rs +263 -0
- package/backend/src/services/pr_monitor.rs +214 -0
- package/backend/src/services/process_service.rs +940 -0
- package/backend/src/utils/path.rs +96 -0
- package/backend/src/utils/shell.rs +19 -0
- package/backend/src/utils/text.rs +24 -0
- package/backend/src/utils/worktree_manager.rs +578 -0
- package/backend/src/utils.rs +125 -0
- package/backend/test.db +0 -0
- package/build-npm-package.sh +61 -0
- package/dev_assets_seed/config.json +19 -0
- package/frontend/.eslintrc.json +25 -0
- package/frontend/.prettierrc.json +8 -0
- package/frontend/components.json +17 -0
- package/frontend/index.html +19 -0
- package/frontend/package-lock.json +7321 -0
- package/frontend/package.json +61 -0
- package/frontend/postcss.config.js +6 -0
- package/frontend/public/android-chrome-192x192.png +0 -0
- package/frontend/public/android-chrome-512x512.png +0 -0
- package/frontend/public/apple-touch-icon.png +0 -0
- package/frontend/public/automagik-forge-logo-dark.svg +3 -0
- package/frontend/public/automagik-forge-logo.svg +3 -0
- package/frontend/public/automagik-forge-screenshot-overview.png +0 -0
- package/frontend/public/favicon-16x16.png +0 -0
- package/frontend/public/favicon-32x32.png +0 -0
- package/frontend/public/favicon.ico +0 -0
- package/frontend/public/site.webmanifest +1 -0
- package/frontend/public/viba-kanban-favicon.png +0 -0
- package/frontend/src/App.tsx +157 -0
- package/frontend/src/components/DisclaimerDialog.tsx +106 -0
- package/frontend/src/components/GitHubLoginDialog.tsx +314 -0
- package/frontend/src/components/OnboardingDialog.tsx +185 -0
- package/frontend/src/components/PrivacyOptInDialog.tsx +130 -0
- package/frontend/src/components/ProvidePatDialog.tsx +98 -0
- package/frontend/src/components/TaskTemplateManager.tsx +336 -0
- package/frontend/src/components/config-provider.tsx +119 -0
- package/frontend/src/components/context/TaskDetailsContextProvider.tsx +470 -0
- package/frontend/src/components/context/taskDetailsContext.ts +125 -0
- package/frontend/src/components/keyboard-shortcuts-demo.tsx +35 -0
- package/frontend/src/components/layout/navbar.tsx +86 -0
- package/frontend/src/components/logo.tsx +44 -0
- package/frontend/src/components/projects/ProjectCard.tsx +155 -0
- package/frontend/src/components/projects/project-detail.tsx +251 -0
- package/frontend/src/components/projects/project-form-fields.tsx +238 -0
- package/frontend/src/components/projects/project-form.tsx +301 -0
- package/frontend/src/components/projects/project-list.tsx +200 -0
- package/frontend/src/components/projects/projects-page.tsx +20 -0
- package/frontend/src/components/tasks/BranchSelector.tsx +169 -0
- package/frontend/src/components/tasks/DeleteFileConfirmationDialog.tsx +94 -0
- package/frontend/src/components/tasks/EditorSelectionDialog.tsx +119 -0
- package/frontend/src/components/tasks/TaskCard.tsx +154 -0
- package/frontend/src/components/tasks/TaskDetails/CollapsibleToolbar.tsx +33 -0
- package/frontend/src/components/tasks/TaskDetails/DiffCard.tsx +109 -0
- package/frontend/src/components/tasks/TaskDetails/DiffChunkSection.tsx +135 -0
- package/frontend/src/components/tasks/TaskDetails/DiffFile.tsx +296 -0
- package/frontend/src/components/tasks/TaskDetails/DiffTab.tsx +32 -0
- package/frontend/src/components/tasks/TaskDetails/DisplayConversationEntry.tsx +392 -0
- package/frontend/src/components/tasks/TaskDetails/LogsTab/Conversation.tsx +256 -0
- package/frontend/src/components/tasks/TaskDetails/LogsTab/ConversationEntry.tsx +56 -0
- package/frontend/src/components/tasks/TaskDetails/LogsTab/NormalizedConversationViewer.tsx +92 -0
- package/frontend/src/components/tasks/TaskDetails/LogsTab/Prompt.tsx +22 -0
- package/frontend/src/components/tasks/TaskDetails/LogsTab/SetupScriptRunning.tsx +49 -0
- package/frontend/src/components/tasks/TaskDetails/LogsTab.tsx +186 -0
- package/frontend/src/components/tasks/TaskDetails/ProcessesTab.tsx +288 -0
- package/frontend/src/components/tasks/TaskDetails/RelatedTasksTab.tsx +216 -0
- package/frontend/src/components/tasks/TaskDetails/TabNavigation.tsx +93 -0
- package/frontend/src/components/tasks/TaskDetailsHeader.tsx +169 -0
- package/frontend/src/components/tasks/TaskDetailsPanel.tsx +126 -0
- package/frontend/src/components/tasks/TaskDetailsToolbar.tsx +302 -0
- package/frontend/src/components/tasks/TaskFollowUpSection.tsx +130 -0
- package/frontend/src/components/tasks/TaskFormDialog.tsx +400 -0
- package/frontend/src/components/tasks/TaskKanbanBoard.tsx +180 -0
- package/frontend/src/components/tasks/Toolbar/CreateAttempt.tsx +259 -0
- package/frontend/src/components/tasks/Toolbar/CreatePRDialog.tsx +243 -0
- package/frontend/src/components/tasks/Toolbar/CurrentAttempt.tsx +899 -0
- package/frontend/src/components/tasks/index.ts +2 -0
- package/frontend/src/components/theme-provider.tsx +82 -0
- package/frontend/src/components/theme-toggle.tsx +36 -0
- package/frontend/src/components/ui/alert.tsx +59 -0
- package/frontend/src/components/ui/auto-expanding-textarea.tsx +70 -0
- package/frontend/src/components/ui/badge.tsx +36 -0
- package/frontend/src/components/ui/button.tsx +56 -0
- package/frontend/src/components/ui/card.tsx +86 -0
- package/frontend/src/components/ui/checkbox.tsx +44 -0
- package/frontend/src/components/ui/chip.tsx +25 -0
- package/frontend/src/components/ui/dialog.tsx +124 -0
- package/frontend/src/components/ui/dropdown-menu.tsx +198 -0
- package/frontend/src/components/ui/file-search-textarea.tsx +292 -0
- package/frontend/src/components/ui/folder-picker.tsx +279 -0
- package/frontend/src/components/ui/input.tsx +25 -0
- package/frontend/src/components/ui/label.tsx +24 -0
- package/frontend/src/components/ui/loader.tsx +26 -0
- package/frontend/src/components/ui/markdown-renderer.tsx +75 -0
- package/frontend/src/components/ui/select.tsx +160 -0
- package/frontend/src/components/ui/separator.tsx +31 -0
- package/frontend/src/components/ui/shadcn-io/kanban/index.tsx +185 -0
- package/frontend/src/components/ui/table.tsx +117 -0
- package/frontend/src/components/ui/tabs.tsx +53 -0
- package/frontend/src/components/ui/textarea.tsx +22 -0
- package/frontend/src/components/ui/tooltip.tsx +28 -0
- package/frontend/src/hooks/useNormalizedConversation.ts +440 -0
- package/frontend/src/index.css +225 -0
- package/frontend/src/lib/api.ts +630 -0
- package/frontend/src/lib/keyboard-shortcuts.ts +266 -0
- package/frontend/src/lib/responsive-config.ts +70 -0
- package/frontend/src/lib/types.ts +39 -0
- package/frontend/src/lib/utils.ts +10 -0
- package/frontend/src/main.tsx +50 -0
- package/frontend/src/pages/McpServers.tsx +418 -0
- package/frontend/src/pages/Settings.tsx +610 -0
- package/frontend/src/pages/project-tasks.tsx +575 -0
- package/frontend/src/pages/projects.tsx +18 -0
- package/frontend/src/vite-env.d.ts +1 -0
- package/frontend/tailwind.config.js +125 -0
- package/frontend/tsconfig.json +26 -0
- package/frontend/tsconfig.node.json +10 -0
- package/frontend/vite.config.ts +33 -0
- package/npx-cli/README.md +159 -0
- package/npx-cli/automagik-forge-0.0.55.tgz +0 -0
- package/npx-cli/automagik-forge-0.1.0.tgz +0 -0
- package/{dist/linux-x64/automagik-forge.zip → npx-cli/automagik-forge-0.1.10.tgz} +0 -0
- package/npx-cli/package.json +17 -0
- package/npx-cli/vibe-kanban-0.0.55.tgz +0 -0
- package/package.json +23 -13
- package/pnpm-workspace.yaml +2 -0
- package/rust-toolchain.toml +11 -0
- package/rustfmt.toml +3 -0
- package/scripts/load-env.js +43 -0
- package/scripts/mcp_test.js +374 -0
- package/scripts/prepare-db.js +45 -0
- package/scripts/setup-dev-environment.js +274 -0
- package/scripts/start-mcp-sse.js +70 -0
- package/scripts/test-debug.js +32 -0
- package/scripts/test-mcp-sse.js +138 -0
- package/scripts/test-simple.js +44 -0
- package/scripts/test-wish-final.js +179 -0
- package/scripts/test-wish-system.js +221 -0
- package/shared/types.ts +182 -0
- package/test-npm-package.sh +42 -0
- package/dist/linux-x64/automagik-forge-mcp.zip +0 -0
- /package/{bin → npx-cli/bin}/cli.js +0 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
-- Migration to update executor type names from snake_case/camelCase to kebab-case
|
2
|
+
-- This handles the change from charmopencode -> charm-opencode and setup_script -> setup-script
|
3
|
+
|
4
|
+
-- Update task_attempts.executor column
|
5
|
+
UPDATE task_attempts
|
6
|
+
SET executor = 'charm-opencode'
|
7
|
+
WHERE executor = 'charmopencode';
|
8
|
+
|
9
|
+
UPDATE task_attempts
|
10
|
+
SET executor = 'setup-script'
|
11
|
+
WHERE executor = 'setup_script';
|
12
|
+
|
13
|
+
-- Update execution_processes.executor_type column
|
14
|
+
UPDATE execution_processes
|
15
|
+
SET executor_type = 'charm-opencode'
|
16
|
+
WHERE executor_type = 'charmopencode';
|
17
|
+
|
18
|
+
UPDATE execution_processes
|
19
|
+
SET executor_type = 'setup-script'
|
20
|
+
WHERE executor_type = 'setup_script';
|
@@ -0,0 +1,7 @@
|
|
1
|
+
PRAGMA foreign_keys = ON;
|
2
|
+
|
3
|
+
-- Add parent_task_attempt column to tasks table
|
4
|
+
ALTER TABLE tasks ADD COLUMN parent_task_attempt BLOB REFERENCES task_attempts(id);
|
5
|
+
|
6
|
+
-- Create index for parent_task_attempt lookups
|
7
|
+
CREATE INDEX idx_tasks_parent_task_attempt ON tasks(parent_task_attempt);
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-- Migration to drop task_attempt_activities table
|
2
|
+
-- This removes the task attempt activity tracking functionality
|
3
|
+
|
4
|
+
-- Drop indexes first
|
5
|
+
DROP INDEX IF EXISTS idx_task_attempt_activities_execution_process_id;
|
6
|
+
DROP INDEX IF EXISTS idx_task_attempt_activities_created_at;
|
7
|
+
|
8
|
+
-- Drop the table
|
9
|
+
DROP TABLE IF EXISTS task_attempt_activities;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
-- 1. Add the replacement column with the wider CHECK
|
2
|
+
ALTER TABLE execution_processes
|
3
|
+
ADD COLUMN process_type_new TEXT NOT NULL DEFAULT 'setupscript'
|
4
|
+
CHECK (process_type_new IN ('setupscript',
|
5
|
+
'cleanupscript', -- new value 🎉
|
6
|
+
'codingagent',
|
7
|
+
'devserver'));
|
8
|
+
|
9
|
+
-- 2. Copy existing values across
|
10
|
+
UPDATE execution_processes
|
11
|
+
SET process_type_new = process_type;
|
12
|
+
|
13
|
+
-- 3. Drop any indexes that mention the old column
|
14
|
+
DROP INDEX IF EXISTS idx_execution_processes_type;
|
15
|
+
|
16
|
+
-- 4. Remove the old column (requires 3.35+)
|
17
|
+
ALTER TABLE execution_processes DROP COLUMN process_type;
|
18
|
+
|
19
|
+
-- 5. Rename the new column back to the canonical name
|
20
|
+
ALTER TABLE execution_processes
|
21
|
+
RENAME COLUMN process_type_new TO process_type;
|
22
|
+
|
23
|
+
-- 6. Re-create the index
|
24
|
+
CREATE INDEX idx_execution_processes_type
|
25
|
+
ON execution_processes(process_type);
|
@@ -0,0 +1,23 @@
|
|
1
|
+
param(
|
2
|
+
[Parameter(Mandatory=$true)]
|
3
|
+
[string]$Title,
|
4
|
+
|
5
|
+
[Parameter(Mandatory=$true)]
|
6
|
+
[string]$Message,
|
7
|
+
|
8
|
+
[Parameter(Mandatory=$false)]
|
9
|
+
[string]$AppName = "Automagik Forge"
|
10
|
+
)
|
11
|
+
|
12
|
+
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
|
13
|
+
$Template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
|
14
|
+
$RawXml = [xml] $Template.GetXml()
|
15
|
+
($RawXml.toast.visual.binding.text|where {$_.id -eq "1"}).AppendChild($RawXml.CreateTextNode($Title)) | Out-Null
|
16
|
+
($RawXml.toast.visual.binding.text|where {$_.id -eq "2"}).AppendChild($RawXml.CreateTextNode($Message)) | Out-Null
|
17
|
+
$SerializedXml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
18
|
+
$SerializedXml.LoadXml($RawXml.OuterXml)
|
19
|
+
$Toast = [Windows.UI.Notifications.ToastNotification]::new($SerializedXml)
|
20
|
+
$Toast.Tag = $AppName
|
21
|
+
$Toast.Group = $AppName
|
22
|
+
$Notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($AppName)
|
23
|
+
$Notifier.Show($Toast)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,218 @@
|
|
1
|
+
use std::{collections::HashMap, sync::Arc, time::Duration};
|
2
|
+
|
3
|
+
#[cfg(unix)]
|
4
|
+
use nix::{sys::signal::Signal, unistd::Pid};
|
5
|
+
use tokio::sync::{Mutex, RwLock as TokioRwLock};
|
6
|
+
use uuid::Uuid;
|
7
|
+
|
8
|
+
use crate::services::{generate_user_id, AnalyticsConfig, AnalyticsService};
|
9
|
+
|
10
|
+
#[derive(Debug)]
|
11
|
+
pub enum ExecutionType {
|
12
|
+
SetupScript,
|
13
|
+
CleanupScript,
|
14
|
+
CodingAgent,
|
15
|
+
DevServer,
|
16
|
+
}
|
17
|
+
|
18
|
+
#[derive(Debug)]
|
19
|
+
pub struct RunningExecution {
|
20
|
+
pub task_attempt_id: Uuid,
|
21
|
+
pub _execution_type: ExecutionType,
|
22
|
+
pub child: command_group::AsyncGroupChild,
|
23
|
+
}
|
24
|
+
|
25
|
+
#[derive(Debug, Clone)]
|
26
|
+
pub struct AppState {
|
27
|
+
running_executions: Arc<Mutex<HashMap<Uuid, RunningExecution>>>,
|
28
|
+
pub db_pool: sqlx::SqlitePool,
|
29
|
+
config: Arc<tokio::sync::RwLock<crate::models::config::Config>>,
|
30
|
+
pub analytics: Arc<TokioRwLock<AnalyticsService>>,
|
31
|
+
user_id: String,
|
32
|
+
}
|
33
|
+
|
34
|
+
impl AppState {
|
35
|
+
pub async fn new(
|
36
|
+
db_pool: sqlx::SqlitePool,
|
37
|
+
config: Arc<tokio::sync::RwLock<crate::models::config::Config>>,
|
38
|
+
) -> Self {
|
39
|
+
// Initialize analytics with user preferences
|
40
|
+
let user_enabled = {
|
41
|
+
let config_guard = config.read().await;
|
42
|
+
config_guard.analytics_enabled.unwrap_or(true)
|
43
|
+
};
|
44
|
+
|
45
|
+
let analytics_config = AnalyticsConfig::new(user_enabled);
|
46
|
+
let analytics = Arc::new(TokioRwLock::new(AnalyticsService::new(analytics_config)));
|
47
|
+
|
48
|
+
Self {
|
49
|
+
running_executions: Arc::new(Mutex::new(HashMap::new())),
|
50
|
+
db_pool,
|
51
|
+
config,
|
52
|
+
analytics,
|
53
|
+
user_id: generate_user_id(),
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
pub async fn update_analytics_config(&self, user_enabled: bool) {
|
58
|
+
// Check if analytics was disabled before this update
|
59
|
+
let was_analytics_disabled = {
|
60
|
+
let analytics = self.analytics.read().await;
|
61
|
+
!analytics.is_enabled()
|
62
|
+
};
|
63
|
+
|
64
|
+
let new_config = AnalyticsConfig::new(user_enabled);
|
65
|
+
let new_service = AnalyticsService::new(new_config);
|
66
|
+
let mut analytics = self.analytics.write().await;
|
67
|
+
*analytics = new_service;
|
68
|
+
|
69
|
+
// If analytics was disabled and is now enabled, fire a session_start event
|
70
|
+
if was_analytics_disabled && analytics.is_enabled() {
|
71
|
+
analytics.track_event(&self.user_id, "session_start", None);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
// Running executions getters
|
76
|
+
pub async fn has_running_execution(&self, attempt_id: Uuid) -> bool {
|
77
|
+
let executions = self.running_executions.lock().await;
|
78
|
+
executions
|
79
|
+
.values()
|
80
|
+
.any(|exec| exec.task_attempt_id == attempt_id)
|
81
|
+
}
|
82
|
+
|
83
|
+
pub async fn get_running_executions_for_monitor(&self) -> Vec<(Uuid, Uuid, bool, Option<i64>)> {
|
84
|
+
let mut executions = self.running_executions.lock().await;
|
85
|
+
let mut completed_executions = Vec::new();
|
86
|
+
|
87
|
+
for (execution_id, running_exec) in executions.iter_mut() {
|
88
|
+
match running_exec.child.try_wait() {
|
89
|
+
Ok(Some(status)) => {
|
90
|
+
let success = status.success();
|
91
|
+
let exit_code = status.code().map(|c| c as i64);
|
92
|
+
completed_executions.push((
|
93
|
+
*execution_id,
|
94
|
+
running_exec.task_attempt_id,
|
95
|
+
success,
|
96
|
+
exit_code,
|
97
|
+
));
|
98
|
+
}
|
99
|
+
Ok(None) => {
|
100
|
+
// Still running
|
101
|
+
}
|
102
|
+
Err(e) => {
|
103
|
+
tracing::error!("Error checking process status: {}", e);
|
104
|
+
completed_executions.push((
|
105
|
+
*execution_id,
|
106
|
+
running_exec.task_attempt_id,
|
107
|
+
false,
|
108
|
+
None,
|
109
|
+
));
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
// Remove completed executions from the map
|
115
|
+
for (execution_id, _, _, _) in &completed_executions {
|
116
|
+
executions.remove(execution_id);
|
117
|
+
}
|
118
|
+
|
119
|
+
completed_executions
|
120
|
+
}
|
121
|
+
|
122
|
+
// Running executions setters
|
123
|
+
pub async fn add_running_execution(&self, execution_id: Uuid, execution: RunningExecution) {
|
124
|
+
let mut executions = self.running_executions.lock().await;
|
125
|
+
executions.insert(execution_id, execution);
|
126
|
+
}
|
127
|
+
|
128
|
+
pub async fn stop_running_execution_by_id(
|
129
|
+
&self,
|
130
|
+
execution_id: Uuid,
|
131
|
+
) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
|
132
|
+
let mut executions = self.running_executions.lock().await;
|
133
|
+
let Some(exec) = executions.get_mut(&execution_id) else {
|
134
|
+
return Ok(false);
|
135
|
+
};
|
136
|
+
|
137
|
+
// hit the whole process group, not just the leader
|
138
|
+
#[cfg(unix)]
|
139
|
+
{
|
140
|
+
use nix::{sys::signal::killpg, unistd::getpgid};
|
141
|
+
|
142
|
+
let pgid = getpgid(Some(Pid::from_raw(exec.child.id().unwrap() as i32)))?;
|
143
|
+
for sig in [Signal::SIGINT, Signal::SIGTERM, Signal::SIGKILL] {
|
144
|
+
killpg(pgid, sig)?;
|
145
|
+
tokio::time::sleep(Duration::from_secs(2)).await;
|
146
|
+
if exec.child.try_wait()?.is_some() {
|
147
|
+
break; // gone!
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
// final fallback – command_group already targets the group
|
153
|
+
exec.child.kill().await.ok();
|
154
|
+
exec.child.wait().await.ok(); // reap
|
155
|
+
|
156
|
+
// only NOW remove it
|
157
|
+
executions.remove(&execution_id);
|
158
|
+
Ok(true)
|
159
|
+
}
|
160
|
+
|
161
|
+
// Config getters
|
162
|
+
pub async fn get_sound_alerts_enabled(&self) -> bool {
|
163
|
+
let config = self.config.read().await;
|
164
|
+
config.sound_alerts
|
165
|
+
}
|
166
|
+
|
167
|
+
pub async fn get_push_notifications_enabled(&self) -> bool {
|
168
|
+
let config = self.config.read().await;
|
169
|
+
config.push_notifications
|
170
|
+
}
|
171
|
+
|
172
|
+
pub async fn get_sound_file(&self) -> crate::models::config::SoundFile {
|
173
|
+
let config = self.config.read().await;
|
174
|
+
config.sound_file.clone()
|
175
|
+
}
|
176
|
+
|
177
|
+
pub fn get_config(&self) -> &Arc<tokio::sync::RwLock<crate::models::config::Config>> {
|
178
|
+
&self.config
|
179
|
+
}
|
180
|
+
|
181
|
+
pub async fn track_analytics_event(
|
182
|
+
&self,
|
183
|
+
event_name: &str,
|
184
|
+
properties: Option<serde_json::Value>,
|
185
|
+
) {
|
186
|
+
let analytics = self.analytics.read().await;
|
187
|
+
if analytics.is_enabled() {
|
188
|
+
analytics.track_event(&self.user_id, event_name, properties);
|
189
|
+
} else {
|
190
|
+
tracing::debug!("Analytics disabled, skipping event: {}", event_name);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
pub async fn update_sentry_scope(&self) {
|
195
|
+
let config = self.get_config().read().await;
|
196
|
+
let username = config.github.username.clone();
|
197
|
+
let email = config.github.primary_email.clone();
|
198
|
+
drop(config);
|
199
|
+
|
200
|
+
let sentry_user = if username.is_some() || email.is_some() {
|
201
|
+
sentry::User {
|
202
|
+
id: Some(self.user_id.clone()),
|
203
|
+
username,
|
204
|
+
email,
|
205
|
+
..Default::default()
|
206
|
+
}
|
207
|
+
} else {
|
208
|
+
sentry::User {
|
209
|
+
id: Some(self.user_id.clone()),
|
210
|
+
..Default::default()
|
211
|
+
}
|
212
|
+
};
|
213
|
+
|
214
|
+
sentry::configure_scope(|scope| {
|
215
|
+
scope.set_user(Some(sentry_user));
|
216
|
+
});
|
217
|
+
}
|
218
|
+
}
|
@@ -0,0 +1,189 @@
|
|
1
|
+
use std::{env, fs, path::Path};
|
2
|
+
|
3
|
+
use ts_rs::TS;
|
4
|
+
// in [build-dependencies]
|
5
|
+
|
6
|
+
fn generate_constants() -> String {
|
7
|
+
r#"// Generated constants
|
8
|
+
export const EXECUTOR_TYPES: string[] = [
|
9
|
+
"echo",
|
10
|
+
"claude",
|
11
|
+
"claude-plan",
|
12
|
+
"amp",
|
13
|
+
"gemini",
|
14
|
+
"charm-opencode",
|
15
|
+
"claude-code-router",
|
16
|
+
"sst-opencode",
|
17
|
+
"opencode-ai"
|
18
|
+
];
|
19
|
+
|
20
|
+
export const EDITOR_TYPES: EditorType[] = [
|
21
|
+
"vscode",
|
22
|
+
"cursor",
|
23
|
+
"windsurf",
|
24
|
+
"intellij",
|
25
|
+
"zed",
|
26
|
+
"custom"
|
27
|
+
];
|
28
|
+
|
29
|
+
export const EXECUTOR_LABELS: Record<string, string> = {
|
30
|
+
"echo": "Echo (Test Mode)",
|
31
|
+
"claude": "Claude Code",
|
32
|
+
"claude-plan": "Claude Code Plan",
|
33
|
+
"amp": "Amp",
|
34
|
+
"gemini": "Gemini",
|
35
|
+
"charm-opencode": "Charm Opencode",
|
36
|
+
"claude-code-router": "Claude Code Router",
|
37
|
+
"sst-opencode": "SST Opencode",
|
38
|
+
"opencode-ai": "OpenCode AI"
|
39
|
+
};
|
40
|
+
|
41
|
+
export const EDITOR_LABELS: Record<string, string> = {
|
42
|
+
"vscode": "VS Code",
|
43
|
+
"cursor": "Cursor",
|
44
|
+
"windsurf": "Windsurf",
|
45
|
+
"intellij": "IntelliJ IDEA",
|
46
|
+
"zed": "Zed",
|
47
|
+
"custom": "Custom"
|
48
|
+
};
|
49
|
+
|
50
|
+
export const SOUND_FILES: SoundFile[] = [
|
51
|
+
"abstract-sound1",
|
52
|
+
"abstract-sound2",
|
53
|
+
"abstract-sound3",
|
54
|
+
"abstract-sound4",
|
55
|
+
"cow-mooing",
|
56
|
+
"phone-vibration",
|
57
|
+
"rooster"
|
58
|
+
];
|
59
|
+
|
60
|
+
export const SOUND_LABELS: Record<string, string> = {
|
61
|
+
"abstract-sound1": "Gentle Chime",
|
62
|
+
"abstract-sound2": "Soft Bell",
|
63
|
+
"abstract-sound3": "Digital Tone",
|
64
|
+
"abstract-sound4": "Subtle Alert",
|
65
|
+
"cow-mooing": "Cow Mooing",
|
66
|
+
"phone-vibration": "Phone Vibration",
|
67
|
+
"rooster": "Rooster Call"
|
68
|
+
};"#
|
69
|
+
.to_string()
|
70
|
+
}
|
71
|
+
|
72
|
+
fn generate_types_content() -> String {
|
73
|
+
// 4. Friendly banner
|
74
|
+
const HEADER: &str =
|
75
|
+
"// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs).\n\
|
76
|
+
// Do not edit this file manually.\n\
|
77
|
+
// Auto-generated from Rust backend types using ts-rs\n\n";
|
78
|
+
|
79
|
+
// 5. Add `export` if it’s missing, then join
|
80
|
+
let decls = [
|
81
|
+
automagik_forge::models::ApiResponse::<()>::decl(),
|
82
|
+
automagik_forge::models::config::Config::decl(),
|
83
|
+
automagik_forge::models::config::ThemeMode::decl(),
|
84
|
+
automagik_forge::models::config::EditorConfig::decl(),
|
85
|
+
automagik_forge::models::config::GitHubConfig::decl(),
|
86
|
+
automagik_forge::models::config::EditorType::decl(),
|
87
|
+
automagik_forge::models::config::EditorConstants::decl(),
|
88
|
+
automagik_forge::models::config::SoundFile::decl(),
|
89
|
+
automagik_forge::models::config::SoundConstants::decl(),
|
90
|
+
automagik_forge::routes::config::ConfigConstants::decl(),
|
91
|
+
automagik_forge::executor::ExecutorConfig::decl(),
|
92
|
+
automagik_forge::executor::ExecutorConstants::decl(),
|
93
|
+
automagik_forge::models::project::CreateProject::decl(),
|
94
|
+
automagik_forge::models::project::Project::decl(),
|
95
|
+
automagik_forge::models::project::ProjectWithBranch::decl(),
|
96
|
+
automagik_forge::models::project::UpdateProject::decl(),
|
97
|
+
automagik_forge::models::project::SearchResult::decl(),
|
98
|
+
automagik_forge::models::project::SearchMatchType::decl(),
|
99
|
+
automagik_forge::models::project::GitBranch::decl(),
|
100
|
+
automagik_forge::models::project::CreateBranch::decl(),
|
101
|
+
automagik_forge::models::task::CreateTask::decl(),
|
102
|
+
automagik_forge::models::task::CreateTaskAndStart::decl(),
|
103
|
+
automagik_forge::models::task::TaskStatus::decl(),
|
104
|
+
automagik_forge::models::task::Task::decl(),
|
105
|
+
automagik_forge::models::task::TaskWithAttemptStatus::decl(),
|
106
|
+
automagik_forge::models::task::UpdateTask::decl(),
|
107
|
+
automagik_forge::models::task_template::TaskTemplate::decl(),
|
108
|
+
automagik_forge::models::task_template::CreateTaskTemplate::decl(),
|
109
|
+
automagik_forge::models::task_template::UpdateTaskTemplate::decl(),
|
110
|
+
automagik_forge::models::task_attempt::TaskAttemptStatus::decl(),
|
111
|
+
automagik_forge::models::task_attempt::TaskAttempt::decl(),
|
112
|
+
automagik_forge::models::task_attempt::CreateTaskAttempt::decl(),
|
113
|
+
automagik_forge::models::task_attempt::UpdateTaskAttempt::decl(),
|
114
|
+
automagik_forge::models::task_attempt::CreateFollowUpAttempt::decl(),
|
115
|
+
automagik_forge::routes::filesystem::DirectoryEntry::decl(),
|
116
|
+
automagik_forge::routes::filesystem::DirectoryListResponse::decl(),
|
117
|
+
automagik_forge::routes::auth::DeviceStartResponse::decl(),
|
118
|
+
automagik_forge::routes::task_attempts::ProcessLogsResponse::decl(),
|
119
|
+
automagik_forge::models::task_attempt::DiffChunkType::decl(),
|
120
|
+
automagik_forge::models::task_attempt::DiffChunk::decl(),
|
121
|
+
automagik_forge::models::task_attempt::FileDiff::decl(),
|
122
|
+
automagik_forge::models::task_attempt::WorktreeDiff::decl(),
|
123
|
+
automagik_forge::models::task_attempt::BranchStatus::decl(),
|
124
|
+
automagik_forge::models::task_attempt::ExecutionState::decl(),
|
125
|
+
automagik_forge::models::task_attempt::TaskAttemptState::decl(),
|
126
|
+
automagik_forge::models::execution_process::ExecutionProcess::decl(),
|
127
|
+
automagik_forge::models::execution_process::ExecutionProcessSummary::decl(),
|
128
|
+
automagik_forge::models::execution_process::ExecutionProcessStatus::decl(),
|
129
|
+
automagik_forge::models::execution_process::ExecutionProcessType::decl(),
|
130
|
+
automagik_forge::models::execution_process::CreateExecutionProcess::decl(),
|
131
|
+
automagik_forge::models::execution_process::UpdateExecutionProcess::decl(),
|
132
|
+
automagik_forge::models::executor_session::ExecutorSession::decl(),
|
133
|
+
automagik_forge::models::executor_session::CreateExecutorSession::decl(),
|
134
|
+
automagik_forge::models::executor_session::UpdateExecutorSession::decl(),
|
135
|
+
automagik_forge::executor::NormalizedConversation::decl(),
|
136
|
+
automagik_forge::executor::NormalizedEntry::decl(),
|
137
|
+
automagik_forge::executor::NormalizedEntryType::decl(),
|
138
|
+
automagik_forge::executor::ActionType::decl(),
|
139
|
+
];
|
140
|
+
|
141
|
+
let body = decls
|
142
|
+
.into_iter()
|
143
|
+
.map(|d| {
|
144
|
+
let trimmed = d.trim_start();
|
145
|
+
if trimmed.starts_with("export") {
|
146
|
+
d
|
147
|
+
} else {
|
148
|
+
format!("export {trimmed}")
|
149
|
+
}
|
150
|
+
})
|
151
|
+
.collect::<Vec<_>>()
|
152
|
+
.join("\n\n");
|
153
|
+
|
154
|
+
let constants = generate_constants();
|
155
|
+
format!("{HEADER}{body}\n\n{constants}")
|
156
|
+
}
|
157
|
+
|
158
|
+
fn main() {
|
159
|
+
let args: Vec<String> = env::args().collect();
|
160
|
+
let check_mode = args.iter().any(|arg| arg == "--check");
|
161
|
+
|
162
|
+
// 1. Make sure ../shared exists
|
163
|
+
let shared_path = Path::new("../shared");
|
164
|
+
fs::create_dir_all(shared_path).expect("cannot create ../shared");
|
165
|
+
|
166
|
+
println!("Generating TypeScript types…");
|
167
|
+
|
168
|
+
// 2. Let ts-rs write its per-type files here (handy for debugging)
|
169
|
+
env::set_var("TS_RS_EXPORT_DIR", shared_path.to_str().unwrap());
|
170
|
+
|
171
|
+
let generated = generate_types_content();
|
172
|
+
let types_path = shared_path.join("types.ts");
|
173
|
+
|
174
|
+
if check_mode {
|
175
|
+
// Read the current file
|
176
|
+
let current = fs::read_to_string(&types_path).unwrap_or_default();
|
177
|
+
if current == generated {
|
178
|
+
println!("✅ shared/types.ts is up to date.");
|
179
|
+
std::process::exit(0);
|
180
|
+
} else {
|
181
|
+
eprintln!("❌ shared/types.ts is not up to date. Please run 'npm run generate-types' and commit the changes.");
|
182
|
+
std::process::exit(1);
|
183
|
+
}
|
184
|
+
} else {
|
185
|
+
// Write the file as before
|
186
|
+
fs::write(&types_path, generated).expect("unable to write types.ts");
|
187
|
+
println!("✅ TypeScript types generated in ../shared/");
|
188
|
+
}
|
189
|
+
}
|