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.
- package/README.md +143 -447
- package/dist/linux-x64/automagik-forge-mcp.zip +0 -0
- package/{npx-cli/automagik-forge-0.0.55.tgz → dist/linux-x64/automagik-forge.zip} +0 -0
- package/package.json +13 -23
- package/.cargo/config.toml +0 -13
- package/.claude/commands/commit.md +0 -376
- package/.claude/commands/prompt.md +0 -871
- package/.env.example +0 -20
- package/.github/actions/setup-node/action.yml +0 -29
- package/.github/images/automagik-logo.png +0 -0
- package/.github/workflows/pre-release.yml +0 -470
- package/.github/workflows/publish.yml +0 -145
- package/.github/workflows/test.yml +0 -63
- package/.mcp.json +0 -57
- package/AGENT.md +0 -40
- package/CLAUDE.md +0 -40
- package/CODE-OF-CONDUCT.md +0 -89
- package/Cargo.toml +0 -19
- package/Dockerfile +0 -43
- package/LICENSE +0 -201
- package/Makefile +0 -97
- package/backend/.sqlx/query-01b7e2bac1261d8be3d03c03df3e5220590da6c31c77f161074fc62752d63881.json +0 -12
- package/backend/.sqlx/query-03f2b02ba6dc5ea2b3cf6b1004caea0ad6bcc10ebd63f441d321a389f026e263.json +0 -12
- package/backend/.sqlx/query-0923b77d137a29fc54d399a873ff15fc4af894490bc65a4d344a7575cb0d8643.json +0 -12
- package/backend/.sqlx/query-0f808bcdb63c5f180836e448dd64c435c51758b2fc54a52ce9e67495b1ab200e.json +0 -68
- package/backend/.sqlx/query-1268afe9ca849daa6722e3df7ca8e9e61f0d37052e782bb5452ab8e1018d9b63.json +0 -12
- package/backend/.sqlx/query-1b082630a9622f8667ee7a9aba2c2d3176019a68c6bb83d33008594821415a57.json +0 -12
- package/backend/.sqlx/query-1c7b06ba1e112abf6b945a2ff08a0b40ec23f3738c2e7399f067b558cf8d490e.json +0 -12
- package/backend/.sqlx/query-1f619f01f46859a64ded531dd0ef61abacfe62e758abe7030a6aa745140b95ca.json +0 -104
- package/backend/.sqlx/query-1fca1ce14b4b20205364cd1f1f45ebe1d2e30cd745e59e189d56487b5639dfbb.json +0 -12
- package/backend/.sqlx/query-212828320e8d871ab9d83705a040b23bcf0393dc7252177fc539a74657f578ef.json +0 -32
- package/backend/.sqlx/query-290ce5c152be8d36e58ff42570f9157beb07ab9e77a03ec6fc30b4f56f9b8f6b.json +0 -56
- package/backend/.sqlx/query-2b471d2c2e8ffbe0cd42d2a91b814c0d79f9d09200f147e3cea33ba4ce673c8a.json +0 -68
- package/backend/.sqlx/query-354a48c705bb9bb2048c1b7f10fcb714e23f9db82b7a4ea6932486197b2ede6a.json +0 -92
- package/backend/.sqlx/query-36c9e3dd10648e94b949db5c91a774ecb1e10a899ef95da74066eccedca4d8b2.json +0 -12
- package/backend/.sqlx/query-36e4ba7bbd81b402d5a20b6005755eafbb174c8dda442081823406ac32809a94.json +0 -56
- package/backend/.sqlx/query-3a5b3c98a55ca183ab20c74708e3d7e579dda37972c059e7515c4ceee4bd8dd3.json +0 -62
- package/backend/.sqlx/query-3d0a1cabf2a52e9d90cdfd29c509ca89aeb448d0c1d2446c65cd43db40735e86.json +0 -62
- package/backend/.sqlx/query-3d6bd16fbce59efe30b7f67ea342e0e4ea6d1432389c02468ad79f1f742d4031.json +0 -56
- package/backend/.sqlx/query-4049ca413b285a05aca6b25385e9c8185575f01e9069e4e8581aa45d713f612f.json +0 -32
- package/backend/.sqlx/query-412bacd3477d86369082e90f52240407abce436cb81292d42b2dbe1e5c18eea1.json +0 -104
- package/backend/.sqlx/query-417a8b1ff4e51de82aea0159a3b97932224dc325b23476cb84153d690227fd8b.json +0 -62
- package/backend/.sqlx/query-461cc1b0bb6fd909afc9dd2246e8526b3771cfbb0b22ae4b5d17b51af587b9e2.json +0 -56
- package/backend/.sqlx/query-58408c7a8cdeeda0bef359f1f9bd91299a339dc2b191462fc58c9736a56d5227.json +0 -92
- package/backend/.sqlx/query-5a886026d75d515c01f347cc203c8d99dd04c61dc468e2e4c5aa548436d13834.json +0 -62
- package/backend/.sqlx/query-5b902137b11022d2e1a5c4f6a9c83fec1a856c6a710aff831abd2382ede76b43.json +0 -12
- package/backend/.sqlx/query-5ed1238e52e59bb5f76c0f153fd99a14093f7ce2585bf9843585608f17ec575b.json +0 -104
- package/backend/.sqlx/query-6e8b860b14decfc2227dc57213f38442943d3fbef5c8418fd6b634c6e0f5e2ea.json +0 -104
- package/backend/.sqlx/query-6ec414276994c4ccb2433eaa5b1b342168557d17ddf5a52dac84cb1b59b9de8f.json +0 -68
- package/backend/.sqlx/query-6ecfa16d0cf825aacf233544b5baf151e9adfdca26c226ad71020d291fd802d5.json +0 -62
- package/backend/.sqlx/query-72509d252c39fce77520aa816cb2acbc1fb35dc2605e7be893610599b2427f2e.json +0 -62
- package/backend/.sqlx/query-75239b2da188f749707d77f3c1544332ca70db3d6d6743b2601dc0d167536437.json +0 -62
- package/backend/.sqlx/query-83d10e29f8478aff33434f9ac67068e013b888b953a2657e2bb72a6f619d04f2.json +0 -50
- package/backend/.sqlx/query-8610803360ea18b9b9d078a6981ea56abfbfe84e6354fc1d5ae4c622e01410ed.json +0 -68
- package/backend/.sqlx/query-86d03eb70eef39c59296416867f2ee66c9f7cd8b7f961fbda2f89fc0a1c442c2.json +0 -12
- package/backend/.sqlx/query-87d0feb5a6b442bad9c60068ea7569599cc6fc91a0e2692ecb42e93b03201b9d.json +0 -68
- package/backend/.sqlx/query-8a67b3b3337248f06a57bdf8a908f7ef23177431eaed82dc08c94c3e5944340e.json +0 -12
- package/backend/.sqlx/query-8f01ebd64bdcde6a090479f14810d73ba23020e76fd70854ac57f2da251702c3.json +0 -12
- package/backend/.sqlx/query-90fd607fcb2dca72239ff25e618e21e174b195991eaa33722cbf5f76da84cfab.json +0 -62
- package/backend/.sqlx/query-92e8bdbcd80c5ff3db7a35cf79492048803ef305cbdef0d0a1fe5dc881ca8c71.json +0 -104
- package/backend/.sqlx/query-93a1605f90e9672dad29b472b6ad85fa9a55ea3ffa5abcb8724b09d61be254ca.json +0 -20
- package/backend/.sqlx/query-9472c8fb477958167f5fae40b85ac44252468c5226b2cdd7770f027332eed6d7.json +0 -104
- package/backend/.sqlx/query-96036c4f9e0f48bdc5a4a4588f0c5f288ac7aaa5425cac40fc33f337e1a351f2.json +0 -56
- package/backend/.sqlx/query-9edb2c01e91fd0f0fe7b56e988c7ae0393150f50be3f419a981e035c0121dfc7.json +0 -104
- package/backend/.sqlx/query-a157cf00616f703bfba21927f1eb1c9eec2a81c02da15f66efdba0b6c375de1b.json +0 -26
- package/backend/.sqlx/query-a31fff84f3b8e532fd1160447d89d700f06ae08821fee00c9a5b60492b05259c.json +0 -62
- package/backend/.sqlx/query-a5ba908419fb3e456bdd2daca41ba06cc3212ffffb8520fc7dbbcc8b60ada314.json +0 -12
- package/backend/.sqlx/query-a6d2961718dbc3b1a925e549f49a159c561bef58c105529275f274b27e2eba5b.json +0 -104
- package/backend/.sqlx/query-a9e93d5b09b29faf66e387e4d7596a792d81e75c4d3726e83c2963e8d7c9b56f.json +0 -104
- package/backend/.sqlx/query-ac5247c8d7fb86e4650c4b0eb9420031614c831b7b085083bac20c1af314c538.json +0 -12
- package/backend/.sqlx/query-afef9467be74c411c4cb119a8b2b1aea53049877dfc30cc60b486134ba4b4c9f.json +0 -68
- package/backend/.sqlx/query-b2b2c6b4d0b1a347b5c4cb63c3a46a265d4db53be9554989a814b069d0af82f2.json +0 -62
- package/backend/.sqlx/query-c50d2ff0b12e5bcc81e371089ee2d007e233e7db93aefba4fef08e7aa68f5ab7.json +0 -20
- package/backend/.sqlx/query-c614e6056b244ca07f1b9d44e7edc9d5819225c6f8d9e077070c6e518a17f50b.json +0 -12
- package/backend/.sqlx/query-c67259be8bf4ee0cfd32167b2aa3b7fe9192809181a8171bf1c2d6df731967ae.json +0 -12
- package/backend/.sqlx/query-d2d0a1b985ebbca6a2b3e882a221a219f3199890fa640afc946ef1a792d6d8de.json +0 -12
- package/backend/.sqlx/query-d30aa5786757f32bf2b9c5fe51a45e506c71c28c5994e430d9b0546adb15ffa2.json +0 -20
- package/backend/.sqlx/query-d3b9ea1de1576af71b312924ce7f4ea8ae5dbe2ac138ea3b4470f2d5cd734846.json +0 -12
- package/backend/.sqlx/query-ed8456646fa69ddd412441955f06ff22bfb790f29466450735e0b8bb1bc4ec94.json +0 -12
- package/backend/Cargo.toml +0 -71
- package/backend/build.rs +0 -32
- package/backend/migrations/20250617183714_init.sql +0 -44
- package/backend/migrations/20250620212427_execution_processes.sql +0 -25
- package/backend/migrations/20250620214100_remove_stdout_stderr_from_task_attempts.sql +0 -28
- package/backend/migrations/20250621120000_relate_activities_to_execution_processes.sql +0 -23
- package/backend/migrations/20250623120000_executor_sessions.sql +0 -17
- package/backend/migrations/20250623130000_add_executor_type_to_execution_processes.sql +0 -4
- package/backend/migrations/20250625000000_add_dev_script_to_projects.sql +0 -4
- package/backend/migrations/20250701000000_add_branch_to_task_attempts.sql +0 -2
- package/backend/migrations/20250701000001_add_pr_tracking_to_task_attempts.sql +0 -5
- package/backend/migrations/20250701120000_add_assistant_message_to_executor_sessions.sql +0 -2
- package/backend/migrations/20250708000000_add_base_branch_to_task_attempts.sql +0 -2
- package/backend/migrations/20250709000000_add_worktree_deleted_flag.sql +0 -2
- package/backend/migrations/20250710000000_add_setup_completion.sql +0 -3
- package/backend/migrations/20250715154859_add_task_templates.sql +0 -25
- package/backend/migrations/20250716143725_add_default_templates.sql +0 -174
- package/backend/migrations/20250716161432_update_executor_names_to_kebab_case.sql +0 -20
- package/backend/migrations/20250716170000_add_parent_task_to_tasks.sql +0 -7
- package/backend/migrations/20250717000000_drop_task_attempt_activities.sql +0 -9
- package/backend/migrations/20250719000000_add_cleanup_script_to_projects.sql +0 -2
- package/backend/migrations/20250720000000_add_cleanupscript_to_process_type_constraint.sql +0 -25
- package/backend/migrations/20250723000000_add_wish_to_tasks.sql +0 -7
- package/backend/migrations/20250724000000_remove_unique_wish_constraint.sql +0 -5
- package/backend/scripts/toast-notification.ps1 +0 -23
- 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 +0 -218
- package/backend/src/bin/generate_types.rs +0 -189
- package/backend/src/bin/mcp_task_server.rs +0 -191
- package/backend/src/execution_monitor.rs +0 -1193
- package/backend/src/executor.rs +0 -1053
- package/backend/src/executors/amp.rs +0 -697
- package/backend/src/executors/ccr.rs +0 -91
- package/backend/src/executors/charm_opencode.rs +0 -113
- package/backend/src/executors/claude.rs +0 -887
- package/backend/src/executors/cleanup_script.rs +0 -124
- package/backend/src/executors/dev_server.rs +0 -53
- package/backend/src/executors/echo.rs +0 -79
- package/backend/src/executors/gemini/config.rs +0 -67
- package/backend/src/executors/gemini/streaming.rs +0 -363
- package/backend/src/executors/gemini.rs +0 -765
- package/backend/src/executors/mod.rs +0 -23
- package/backend/src/executors/opencode_ai.rs +0 -113
- package/backend/src/executors/setup_script.rs +0 -130
- package/backend/src/executors/sst_opencode/filter.rs +0 -184
- package/backend/src/executors/sst_opencode/tools.rs +0 -139
- package/backend/src/executors/sst_opencode.rs +0 -756
- package/backend/src/lib.rs +0 -45
- package/backend/src/main.rs +0 -324
- package/backend/src/mcp/mod.rs +0 -1
- package/backend/src/mcp/task_server.rs +0 -850
- package/backend/src/middleware/mod.rs +0 -3
- package/backend/src/middleware/model_loaders.rs +0 -242
- package/backend/src/models/api_response.rs +0 -36
- package/backend/src/models/config.rs +0 -375
- package/backend/src/models/execution_process.rs +0 -430
- package/backend/src/models/executor_session.rs +0 -225
- package/backend/src/models/mod.rs +0 -12
- package/backend/src/models/project.rs +0 -356
- package/backend/src/models/task.rs +0 -345
- package/backend/src/models/task_attempt.rs +0 -1214
- package/backend/src/models/task_template.rs +0 -146
- package/backend/src/openapi.rs +0 -93
- package/backend/src/routes/auth.rs +0 -297
- package/backend/src/routes/config.rs +0 -385
- package/backend/src/routes/filesystem.rs +0 -228
- package/backend/src/routes/health.rs +0 -16
- package/backend/src/routes/mod.rs +0 -9
- package/backend/src/routes/projects.rs +0 -562
- package/backend/src/routes/stream.rs +0 -244
- package/backend/src/routes/task_attempts.rs +0 -1172
- package/backend/src/routes/task_templates.rs +0 -229
- package/backend/src/routes/tasks.rs +0 -353
- package/backend/src/services/analytics.rs +0 -216
- package/backend/src/services/git_service.rs +0 -1321
- package/backend/src/services/github_service.rs +0 -307
- package/backend/src/services/mod.rs +0 -13
- package/backend/src/services/notification_service.rs +0 -263
- package/backend/src/services/pr_monitor.rs +0 -214
- package/backend/src/services/process_service.rs +0 -940
- package/backend/src/utils/path.rs +0 -96
- package/backend/src/utils/shell.rs +0 -19
- package/backend/src/utils/text.rs +0 -24
- package/backend/src/utils/worktree_manager.rs +0 -578
- package/backend/src/utils.rs +0 -125
- package/backend/test.db +0 -0
- package/build-npm-package.sh +0 -61
- package/dev_assets_seed/config.json +0 -19
- package/frontend/.eslintrc.json +0 -25
- package/frontend/.prettierrc.json +0 -8
- package/frontend/components.json +0 -17
- package/frontend/index.html +0 -19
- package/frontend/package-lock.json +0 -7321
- package/frontend/package.json +0 -61
- package/frontend/postcss.config.js +0 -6
- 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 +0 -3
- package/frontend/public/automagik-forge-logo.svg +0 -3
- 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 +0 -1
- package/frontend/public/viba-kanban-favicon.png +0 -0
- package/frontend/src/App.tsx +0 -157
- package/frontend/src/components/DisclaimerDialog.tsx +0 -106
- package/frontend/src/components/GitHubLoginDialog.tsx +0 -314
- package/frontend/src/components/OnboardingDialog.tsx +0 -185
- package/frontend/src/components/PrivacyOptInDialog.tsx +0 -130
- package/frontend/src/components/ProvidePatDialog.tsx +0 -98
- package/frontend/src/components/TaskTemplateManager.tsx +0 -336
- package/frontend/src/components/config-provider.tsx +0 -119
- package/frontend/src/components/context/TaskDetailsContextProvider.tsx +0 -470
- package/frontend/src/components/context/taskDetailsContext.ts +0 -125
- package/frontend/src/components/keyboard-shortcuts-demo.tsx +0 -35
- package/frontend/src/components/layout/navbar.tsx +0 -86
- package/frontend/src/components/logo.tsx +0 -44
- package/frontend/src/components/projects/ProjectCard.tsx +0 -155
- package/frontend/src/components/projects/project-detail.tsx +0 -251
- package/frontend/src/components/projects/project-form-fields.tsx +0 -238
- package/frontend/src/components/projects/project-form.tsx +0 -301
- package/frontend/src/components/projects/project-list.tsx +0 -200
- package/frontend/src/components/projects/projects-page.tsx +0 -20
- package/frontend/src/components/tasks/BranchSelector.tsx +0 -169
- package/frontend/src/components/tasks/DeleteFileConfirmationDialog.tsx +0 -94
- package/frontend/src/components/tasks/EditorSelectionDialog.tsx +0 -119
- package/frontend/src/components/tasks/TaskCard.tsx +0 -154
- package/frontend/src/components/tasks/TaskDetails/CollapsibleToolbar.tsx +0 -33
- package/frontend/src/components/tasks/TaskDetails/DiffCard.tsx +0 -109
- package/frontend/src/components/tasks/TaskDetails/DiffChunkSection.tsx +0 -135
- package/frontend/src/components/tasks/TaskDetails/DiffFile.tsx +0 -296
- package/frontend/src/components/tasks/TaskDetails/DiffTab.tsx +0 -32
- package/frontend/src/components/tasks/TaskDetails/DisplayConversationEntry.tsx +0 -392
- package/frontend/src/components/tasks/TaskDetails/LogsTab/Conversation.tsx +0 -256
- package/frontend/src/components/tasks/TaskDetails/LogsTab/ConversationEntry.tsx +0 -56
- package/frontend/src/components/tasks/TaskDetails/LogsTab/NormalizedConversationViewer.tsx +0 -92
- package/frontend/src/components/tasks/TaskDetails/LogsTab/Prompt.tsx +0 -22
- package/frontend/src/components/tasks/TaskDetails/LogsTab/SetupScriptRunning.tsx +0 -49
- package/frontend/src/components/tasks/TaskDetails/LogsTab.tsx +0 -186
- package/frontend/src/components/tasks/TaskDetails/ProcessesTab.tsx +0 -288
- package/frontend/src/components/tasks/TaskDetails/RelatedTasksTab.tsx +0 -216
- package/frontend/src/components/tasks/TaskDetails/TabNavigation.tsx +0 -93
- package/frontend/src/components/tasks/TaskDetailsHeader.tsx +0 -169
- package/frontend/src/components/tasks/TaskDetailsPanel.tsx +0 -126
- package/frontend/src/components/tasks/TaskDetailsToolbar.tsx +0 -302
- package/frontend/src/components/tasks/TaskFollowUpSection.tsx +0 -130
- package/frontend/src/components/tasks/TaskFormDialog.tsx +0 -400
- package/frontend/src/components/tasks/TaskKanbanBoard.tsx +0 -180
- package/frontend/src/components/tasks/Toolbar/CreateAttempt.tsx +0 -259
- package/frontend/src/components/tasks/Toolbar/CreatePRDialog.tsx +0 -243
- package/frontend/src/components/tasks/Toolbar/CurrentAttempt.tsx +0 -899
- package/frontend/src/components/tasks/index.ts +0 -2
- package/frontend/src/components/theme-provider.tsx +0 -82
- package/frontend/src/components/theme-toggle.tsx +0 -36
- package/frontend/src/components/ui/alert.tsx +0 -59
- package/frontend/src/components/ui/auto-expanding-textarea.tsx +0 -70
- package/frontend/src/components/ui/badge.tsx +0 -36
- package/frontend/src/components/ui/button.tsx +0 -56
- package/frontend/src/components/ui/card.tsx +0 -86
- package/frontend/src/components/ui/checkbox.tsx +0 -44
- package/frontend/src/components/ui/chip.tsx +0 -25
- package/frontend/src/components/ui/dialog.tsx +0 -124
- package/frontend/src/components/ui/dropdown-menu.tsx +0 -198
- package/frontend/src/components/ui/file-search-textarea.tsx +0 -292
- package/frontend/src/components/ui/folder-picker.tsx +0 -279
- package/frontend/src/components/ui/input.tsx +0 -25
- package/frontend/src/components/ui/label.tsx +0 -24
- package/frontend/src/components/ui/loader.tsx +0 -26
- package/frontend/src/components/ui/markdown-renderer.tsx +0 -75
- package/frontend/src/components/ui/select.tsx +0 -160
- package/frontend/src/components/ui/separator.tsx +0 -31
- package/frontend/src/components/ui/shadcn-io/kanban/index.tsx +0 -185
- package/frontend/src/components/ui/table.tsx +0 -117
- package/frontend/src/components/ui/tabs.tsx +0 -53
- package/frontend/src/components/ui/textarea.tsx +0 -22
- package/frontend/src/components/ui/tooltip.tsx +0 -28
- package/frontend/src/hooks/useNormalizedConversation.ts +0 -440
- package/frontend/src/index.css +0 -225
- package/frontend/src/lib/api.ts +0 -630
- package/frontend/src/lib/keyboard-shortcuts.ts +0 -266
- package/frontend/src/lib/responsive-config.ts +0 -70
- package/frontend/src/lib/types.ts +0 -39
- package/frontend/src/lib/utils.ts +0 -10
- package/frontend/src/main.tsx +0 -50
- package/frontend/src/pages/McpServers.tsx +0 -418
- package/frontend/src/pages/Settings.tsx +0 -610
- package/frontend/src/pages/project-tasks.tsx +0 -575
- package/frontend/src/pages/projects.tsx +0 -18
- package/frontend/src/vite-env.d.ts +0 -1
- package/frontend/tailwind.config.js +0 -125
- package/frontend/tsconfig.json +0 -26
- package/frontend/tsconfig.node.json +0 -10
- package/frontend/vite.config.ts +0 -33
- package/npx-cli/README.md +0 -159
- package/npx-cli/automagik-forge-0.1.0.tgz +0 -0
- package/npx-cli/automagik-forge-0.1.10.tgz +0 -0
- package/npx-cli/package.json +0 -17
- package/npx-cli/vibe-kanban-0.0.55.tgz +0 -0
- package/pnpm-workspace.yaml +0 -2
- package/rust-toolchain.toml +0 -11
- package/rustfmt.toml +0 -3
- package/scripts/load-env.js +0 -43
- package/scripts/mcp_test.js +0 -374
- package/scripts/prepare-db.js +0 -45
- package/scripts/setup-dev-environment.js +0 -274
- package/scripts/start-mcp-sse.js +0 -70
- package/scripts/test-debug.js +0 -32
- package/scripts/test-mcp-sse.js +0 -138
- package/scripts/test-simple.js +0 -44
- package/scripts/test-wish-final.js +0 -179
- package/scripts/test-wish-system.js +0 -221
- package/shared/types.ts +0 -182
- package/test-npm-package.sh +0 -42
- /package/{npx-cli/bin → bin}/cli.js +0 -0
@@ -1,307 +0,0 @@
|
|
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
|
-
}
|
@@ -1,13 +0,0 @@
|
|
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;
|
@@ -1,263 +0,0 @@
|
|
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
|
-
}
|