From 549c8b5b138ef14aae4d6b2e91edbe4acd78d4da Mon Sep 17 00:00:00 2001 From: "954801926@qq.com" Date: Wed, 29 Jul 2026 23:36:41 +0800 Subject: [PATCH] chore: init main branch --- .gitignore | 15 + LICENSE | 21 + README.md | 633 ++ README_EN.md | 629 ++ docs/PROPOSAL-presets-and-usage.md | 625 ++ docs/VERIFICATION-CHECKLIST.md | 154 + docs/screenshots/dashboard.png | Bin 0 -> 106893 bytes docs/screenshots/provider-basic-info.png | Bin 0 -> 70488 bytes docs/screenshots/provider-model-mapping.png | Bin 0 -> 174697 bytes docs/screenshots/providers.png | Bin 0 -> 40975 bytes docs/screenshots/sessions.png | Bin 0 -> 139806 bytes index.html | 13 + package-lock.json | 2993 +++++++++ package.json | 35 + postcss.config.js | 6 + public/kimi.svg | 13 + scripts/fetch-models-dev.mjs | 57 + scripts/generate-icons.py | 110 + src-tauri/Cargo.lock | 5530 +++++++++++++++++ src-tauri/Cargo.toml | 35 + src-tauri/build.rs | 3 + src-tauri/capabilities/default.json | 12 + src-tauri/icons/128x128.png | Bin 0 -> 6621 bytes src-tauri/icons/128x128@2x.png | Bin 0 -> 15225 bytes src-tauri/icons/32x32.png | Bin 0 -> 1416 bytes src-tauri/icons/64x64.png | Bin 0 -> 1245 bytes src-tauri/icons/Square107x107Logo.png | Bin 0 -> 1968 bytes src-tauri/icons/Square142x142Logo.png | Bin 0 -> 2438 bytes src-tauri/icons/Square150x150Logo.png | Bin 0 -> 2520 bytes src-tauri/icons/Square284x284Logo.png | Bin 0 -> 4631 bytes src-tauri/icons/Square30x30Logo.png | Bin 0 -> 654 bytes src-tauri/icons/Square310x310Logo.png | Bin 0 -> 4995 bytes src-tauri/icons/Square44x44Logo.png | Bin 0 -> 874 bytes src-tauri/icons/Square71x71Logo.png | Bin 0 -> 1374 bytes src-tauri/icons/Square89x89Logo.png | Bin 0 -> 1575 bytes src-tauri/icons/StoreLogo.png | Bin 0 -> 980 bytes .../android/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../icons/android/mipmap-hdpi/ic_launcher.png | Bin 0 -> 993 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 2726 bytes .../android/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 1180 bytes .../icons/android/mipmap-mdpi/ic_launcher.png | Bin 0 -> 987 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 1960 bytes .../android/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 1126 bytes .../android/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 1788 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 3351 bytes .../mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 2219 bytes .../android/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 2668 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 5202 bytes .../mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 3259 bytes .../android/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 3302 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 7024 bytes .../mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 4172 bytes .../android/values/ic_launcher_background.xml | 4 + src-tauri/icons/icon-source.png | Bin 0 -> 15779 bytes src-tauri/icons/icon.icns | Bin 0 -> 45745 bytes src-tauri/icons/icon.ico | Bin 0 -> 1438 bytes src-tauri/icons/icon.png | Bin 0 -> 15225 bytes src-tauri/icons/ios/AppIcon-20x20@1x.png | Bin 0 -> 478 bytes src-tauri/icons/ios/AppIcon-20x20@2x-1.png | Bin 0 -> 810 bytes src-tauri/icons/ios/AppIcon-20x20@2x.png | Bin 0 -> 810 bytes src-tauri/icons/ios/AppIcon-20x20@3x.png | Bin 0 -> 1147 bytes src-tauri/icons/ios/AppIcon-29x29@1x.png | Bin 0 -> 634 bytes src-tauri/icons/ios/AppIcon-29x29@2x-1.png | Bin 0 -> 1068 bytes src-tauri/icons/ios/AppIcon-29x29@2x.png | Bin 0 -> 1068 bytes src-tauri/icons/ios/AppIcon-29x29@3x.png | Bin 0 -> 1586 bytes src-tauri/icons/ios/AppIcon-40x40@1x.png | Bin 0 -> 810 bytes src-tauri/icons/ios/AppIcon-40x40@2x-1.png | Bin 0 -> 1432 bytes src-tauri/icons/ios/AppIcon-40x40@2x.png | Bin 0 -> 1432 bytes src-tauri/icons/ios/AppIcon-40x40@3x.png | Bin 0 -> 2053 bytes src-tauri/icons/ios/AppIcon-512@2x.png | Bin 0 -> 14000 bytes src-tauri/icons/ios/AppIcon-60x60@2x.png | Bin 0 -> 2053 bytes src-tauri/icons/ios/AppIcon-60x60@3x.png | Bin 0 -> 2899 bytes src-tauri/icons/ios/AppIcon-76x76@1x.png | Bin 0 -> 1409 bytes src-tauri/icons/ios/AppIcon-76x76@2x.png | Bin 0 -> 2581 bytes src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png | Bin 0 -> 2764 bytes src-tauri/src/commands.rs | 859 +++ src-tauri/src/config_io.rs | 84 + src-tauri/src/dashboard.rs | 1419 +++++ src-tauri/src/db.rs | 338 + src-tauri/src/kimi_code_io.rs | 758 +++ src-tauri/src/lib.rs | 119 + src-tauri/src/main.rs | 5 + src-tauri/src/models.rs | 235 + src-tauri/src/pi_io.rs | 626 ++ src-tauri/src/profile_manager.rs | 2 + src-tauri/src/services/balance.rs | 326 + src-tauri/src/services/coding_plan.rs | 414 ++ src-tauri/src/services/mod.rs | 182 + src-tauri/src/services/usage_types.rs | 76 + src-tauri/src/validators.rs | 1 + src-tauri/tauri.conf.json | 43 + src/App.tsx | 802 +++ src/components/AgentSettingsPanel.tsx | 376 ++ src/components/IconPicker.tsx | 70 + src/components/PresetPickerModal.tsx | 201 + src/components/ProviderEdit.tsx | 812 +++ src/components/ProviderIcon.tsx | 137 + src/components/ProviderList.tsx | 313 + src/components/SettingsModal.tsx | 346 ++ src/components/UsageFooter.tsx | 310 + src/components/dashboard/DailyBars.tsx | 156 + src/components/dashboard/DailyDetailModal.tsx | 206 + src/components/dashboard/DashboardPage.tsx | 418 ++ src/components/dashboard/Heatmap.tsx | 255 + src/components/sessions/SessionsPage.tsx | 764 +++ src/config/providerPresets.ts | 427 ++ src/hooks/useConfig.ts | 89 + src/hooks/useDashboard.ts | 54 + src/hooks/useSessions.ts | 107 + src/hooks/useTheme.ts | 62 + src/hooks/useUpdateCheck.ts | 71 + src/i18n/en.ts | 366 ++ src/i18n/index.tsx | 82 + src/i18n/zh.ts | 363 ++ src/icons/brands.ts | 146 + src/icons/extracted/ClaudeApi.png | Bin 0 -> 17658 bytes src/icons/extracted/TeamoRouter-icon-dark.png | Bin 0 -> 1744 bytes src/icons/extracted/aicodemirror.svg | 19 + src/icons/extracted/aicoding.svg | 20 + src/icons/extracted/aihubmix-color.svg | 1 + src/icons/extracted/algocode.svg | 51 + src/icons/extracted/alibaba.svg | 1 + src/icons/extracted/amuxapi-icon.svg | 13 + src/icons/extracted/anthropic.svg | 1 + src/icons/extracted/apikeyfun.png | Bin 0 -> 1094 bytes src/icons/extracted/apinebula_icon.png | Bin 0 -> 6632 bytes src/icons/extracted/atlascloud_icon.png | Bin 0 -> 9604 bytes src/icons/extracted/aws.svg | 1 + src/icons/extracted/azure.svg | 1 + src/icons/extracted/baidu.svg | 1 + src/icons/extracted/bailian.svg | 1 + src/icons/extracted/bytedance.svg | 1 + src/icons/extracted/byteplus.png | Bin 0 -> 27347 bytes src/icons/extracted/catcoder.svg | 1 + src/icons/extracted/ccsub.svg | 4 + src/icons/extracted/chatglm.svg | 1 + src/icons/extracted/cherryin.png | Bin 0 -> 11327 bytes src/icons/extracted/claude.svg | 1 + src/icons/extracted/claudecn.png | Bin 0 -> 47341 bytes src/icons/extracted/claw.svg | 22 + src/icons/extracted/cloudflare.svg | 1 + src/icons/extracted/code0.png | Bin 0 -> 2323 bytes src/icons/extracted/cohere.svg | 1 + src/icons/extracted/copilot.svg | 1 + src/icons/extracted/crazyrouter.svg | 1 + src/icons/extracted/cubence.svg | 9 + src/icons/extracted/deepseek.svg | 1 + src/icons/extracted/doubao.svg | 1 + src/icons/extracted/eflowcode.png | Bin 0 -> 63679 bytes src/icons/extracted/etok.png | Bin 0 -> 42576 bytes src/icons/extracted/fenno-icon.webp | Bin 0 -> 33198 bytes src/icons/extracted/gemini.svg | 1 + src/icons/extracted/gemma.svg | 1 + src/icons/extracted/github.svg | 1 + src/icons/extracted/githubcopilot.svg | 1 + src/icons/extracted/google.svg | 1 + src/icons/extracted/googlecloud.svg | 1 + src/icons/extracted/grok.svg | 1 + src/icons/extracted/hermes.png | Bin 0 -> 39304 bytes src/icons/extracted/huawei.svg | 1 + src/icons/extracted/huggingface.svg | 1 + src/icons/extracted/hunyuan.svg | 1 + src/icons/extracted/huoshan.png | Bin 0 -> 35396 bytes src/icons/extracted/index.ts | 157 + src/icons/extracted/kimi.svg | 1 + src/icons/extracted/lioncc.svg | 6 + src/icons/extracted/longcat-color.svg | 1 + src/icons/extracted/mcp.svg | 1 + src/icons/extracted/meta.svg | 1 + src/icons/extracted/metadata.ts | 715 +++ src/icons/extracted/micu.svg | 23 + src/icons/extracted/midjourney.svg | 1 + src/icons/extracted/minimax.svg | 1 + src/icons/extracted/mistral.svg | 1 + src/icons/extracted/modelscope-color.svg | 1 + src/icons/extracted/nekocode-icon.png | Bin 0 -> 2852 bytes src/icons/extracted/newapi.svg | 1 + src/icons/extracted/notion.svg | 1 + src/icons/extracted/novita.svg | 11 + src/icons/extracted/nvidia.svg | 1 + src/icons/extracted/ollama.svg | 1 + src/icons/extracted/openai.svg | 1 + src/icons/extracted/opencode-logo-light.svg | 1 + src/icons/extracted/openrouter.svg | 1 + src/icons/extracted/packycode.svg | 1 + src/icons/extracted/palm.svg | 1 + src/icons/extracted/pateway.jpg | Bin 0 -> 7283 bytes src/icons/extracted/perplexity.svg | 1 + src/icons/extracted/pipellm.png | Bin 0 -> 1969 bytes src/icons/extracted/qiniu.png | Bin 0 -> 70218 bytes src/icons/extracted/qwen.svg | 1 + src/icons/extracted/rc.svg | 1 + src/icons/extracted/relaxcode.png | Bin 0 -> 41716 bytes src/icons/extracted/runapi.jpg | Bin 0 -> 9544 bytes src/icons/extracted/shengsuanyun.svg | 4 + src/icons/extracted/siliconflow.svg | 1 + src/icons/extracted/sssaicode.svg | 73 + src/icons/extracted/stability.svg | 1 + src/icons/extracted/stepfun.svg | 10 + src/icons/extracted/subrouter.svg | 30 + src/icons/extracted/sudocode-us.png | Bin 0 -> 37023 bytes src/icons/extracted/sudocode.png | Bin 0 -> 5437 bytes src/icons/extracted/tencent.svg | 1 + src/icons/extracted/ucloud.svg | 1 + src/icons/extracted/unity2.png | Bin 0 -> 61909 bytes src/icons/extracted/vercel.svg | 1 + src/icons/extracted/wenxin.svg | 1 + src/icons/extracted/xai.svg | 1 + src/icons/extracted/xiaomimimo.svg | 1 + src/icons/extracted/yi.svg | 1 + src/icons/extracted/zeroone.svg | 1 + src/icons/extracted/zetaapi-icon.png | Bin 0 -> 40569 bytes src/icons/extracted/zhipu.svg | 1 + src/icons/inference.ts | 31 + src/index.css | 70 + src/lib/agent-settings.ts | 88 + src/lib/dashboard-format.ts | 38 + src/lib/model-defaults.ts | 90 + src/lib/models-dev.json | 1866 ++++++ src/lib/models-dev.ts | 57 + src/lib/validation.ts | 86 + src/main.tsx | 53 + src/types/dashboard.ts | 110 + src/types/icon.ts | 16 + src/types/index.ts | 105 + src/types/sessions.ts | 61 + src/vite-env.d.ts | 1 + tailwind.config.js | 29 + tsconfig.json | 23 + tsconfig.node.json | 11 + vite.config.ts | 13 + 231 files changed, 27286 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 README_EN.md create mode 100644 docs/PROPOSAL-presets-and-usage.md create mode 100644 docs/VERIFICATION-CHECKLIST.md create mode 100644 docs/screenshots/dashboard.png create mode 100644 docs/screenshots/provider-basic-info.png create mode 100644 docs/screenshots/provider-model-mapping.png create mode 100644 docs/screenshots/providers.png create mode 100644 docs/screenshots/sessions.png create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 public/kimi.svg create mode 100644 scripts/fetch-models-dev.mjs create mode 100644 scripts/generate-icons.py create mode 100644 src-tauri/Cargo.lock create mode 100644 src-tauri/Cargo.toml create mode 100644 src-tauri/build.rs create mode 100644 src-tauri/capabilities/default.json create mode 100644 src-tauri/icons/128x128.png create mode 100644 src-tauri/icons/128x128@2x.png create mode 100644 src-tauri/icons/32x32.png create mode 100644 src-tauri/icons/64x64.png create mode 100644 src-tauri/icons/Square107x107Logo.png create mode 100644 src-tauri/icons/Square142x142Logo.png create mode 100644 src-tauri/icons/Square150x150Logo.png create mode 100644 src-tauri/icons/Square284x284Logo.png create mode 100644 src-tauri/icons/Square30x30Logo.png create mode 100644 src-tauri/icons/Square310x310Logo.png create mode 100644 src-tauri/icons/Square44x44Logo.png create mode 100644 src-tauri/icons/Square71x71Logo.png create mode 100644 src-tauri/icons/Square89x89Logo.png create mode 100644 src-tauri/icons/StoreLogo.png create mode 100644 src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 src-tauri/icons/android/mipmap-hdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-mdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 src-tauri/icons/android/values/ic_launcher_background.xml create mode 100644 src-tauri/icons/icon-source.png create mode 100644 src-tauri/icons/icon.icns create mode 100644 src-tauri/icons/icon.ico create mode 100644 src-tauri/icons/icon.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@2x-1.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-20x20@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@2x-1.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-29x29@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@2x-1.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-40x40@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-512@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-60x60@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-60x60@3x.png create mode 100644 src-tauri/icons/ios/AppIcon-76x76@1x.png create mode 100644 src-tauri/icons/ios/AppIcon-76x76@2x.png create mode 100644 src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png create mode 100644 src-tauri/src/commands.rs create mode 100644 src-tauri/src/config_io.rs create mode 100644 src-tauri/src/dashboard.rs create mode 100644 src-tauri/src/db.rs create mode 100644 src-tauri/src/kimi_code_io.rs create mode 100644 src-tauri/src/lib.rs create mode 100644 src-tauri/src/main.rs create mode 100644 src-tauri/src/models.rs create mode 100644 src-tauri/src/pi_io.rs create mode 100644 src-tauri/src/profile_manager.rs create mode 100644 src-tauri/src/services/balance.rs create mode 100644 src-tauri/src/services/coding_plan.rs create mode 100644 src-tauri/src/services/mod.rs create mode 100644 src-tauri/src/services/usage_types.rs create mode 100644 src-tauri/src/validators.rs create mode 100644 src-tauri/tauri.conf.json create mode 100644 src/App.tsx create mode 100644 src/components/AgentSettingsPanel.tsx create mode 100644 src/components/IconPicker.tsx create mode 100644 src/components/PresetPickerModal.tsx create mode 100644 src/components/ProviderEdit.tsx create mode 100644 src/components/ProviderIcon.tsx create mode 100644 src/components/ProviderList.tsx create mode 100644 src/components/SettingsModal.tsx create mode 100644 src/components/UsageFooter.tsx create mode 100644 src/components/dashboard/DailyBars.tsx create mode 100644 src/components/dashboard/DailyDetailModal.tsx create mode 100644 src/components/dashboard/DashboardPage.tsx create mode 100644 src/components/dashboard/Heatmap.tsx create mode 100644 src/components/sessions/SessionsPage.tsx create mode 100644 src/config/providerPresets.ts create mode 100644 src/hooks/useConfig.ts create mode 100644 src/hooks/useDashboard.ts create mode 100644 src/hooks/useSessions.ts create mode 100644 src/hooks/useTheme.ts create mode 100644 src/hooks/useUpdateCheck.ts create mode 100644 src/i18n/en.ts create mode 100644 src/i18n/index.tsx create mode 100644 src/i18n/zh.ts create mode 100644 src/icons/brands.ts create mode 100644 src/icons/extracted/ClaudeApi.png create mode 100644 src/icons/extracted/TeamoRouter-icon-dark.png create mode 100644 src/icons/extracted/aicodemirror.svg create mode 100644 src/icons/extracted/aicoding.svg create mode 100644 src/icons/extracted/aihubmix-color.svg create mode 100644 src/icons/extracted/algocode.svg create mode 100644 src/icons/extracted/alibaba.svg create mode 100644 src/icons/extracted/amuxapi-icon.svg create mode 100644 src/icons/extracted/anthropic.svg create mode 100644 src/icons/extracted/apikeyfun.png create mode 100644 src/icons/extracted/apinebula_icon.png create mode 100644 src/icons/extracted/atlascloud_icon.png create mode 100644 src/icons/extracted/aws.svg create mode 100644 src/icons/extracted/azure.svg create mode 100644 src/icons/extracted/baidu.svg create mode 100644 src/icons/extracted/bailian.svg create mode 100644 src/icons/extracted/bytedance.svg create mode 100644 src/icons/extracted/byteplus.png create mode 100644 src/icons/extracted/catcoder.svg create mode 100644 src/icons/extracted/ccsub.svg create mode 100644 src/icons/extracted/chatglm.svg create mode 100644 src/icons/extracted/cherryin.png create mode 100644 src/icons/extracted/claude.svg create mode 100644 src/icons/extracted/claudecn.png create mode 100644 src/icons/extracted/claw.svg create mode 100644 src/icons/extracted/cloudflare.svg create mode 100644 src/icons/extracted/code0.png create mode 100644 src/icons/extracted/cohere.svg create mode 100644 src/icons/extracted/copilot.svg create mode 100644 src/icons/extracted/crazyrouter.svg create mode 100644 src/icons/extracted/cubence.svg create mode 100644 src/icons/extracted/deepseek.svg create mode 100644 src/icons/extracted/doubao.svg create mode 100644 src/icons/extracted/eflowcode.png create mode 100644 src/icons/extracted/etok.png create mode 100644 src/icons/extracted/fenno-icon.webp create mode 100644 src/icons/extracted/gemini.svg create mode 100644 src/icons/extracted/gemma.svg create mode 100644 src/icons/extracted/github.svg create mode 100644 src/icons/extracted/githubcopilot.svg create mode 100644 src/icons/extracted/google.svg create mode 100644 src/icons/extracted/googlecloud.svg create mode 100644 src/icons/extracted/grok.svg create mode 100644 src/icons/extracted/hermes.png create mode 100644 src/icons/extracted/huawei.svg create mode 100644 src/icons/extracted/huggingface.svg create mode 100644 src/icons/extracted/hunyuan.svg create mode 100644 src/icons/extracted/huoshan.png create mode 100644 src/icons/extracted/index.ts create mode 100644 src/icons/extracted/kimi.svg create mode 100644 src/icons/extracted/lioncc.svg create mode 100644 src/icons/extracted/longcat-color.svg create mode 100644 src/icons/extracted/mcp.svg create mode 100644 src/icons/extracted/meta.svg create mode 100644 src/icons/extracted/metadata.ts create mode 100644 src/icons/extracted/micu.svg create mode 100644 src/icons/extracted/midjourney.svg create mode 100644 src/icons/extracted/minimax.svg create mode 100644 src/icons/extracted/mistral.svg create mode 100644 src/icons/extracted/modelscope-color.svg create mode 100644 src/icons/extracted/nekocode-icon.png create mode 100644 src/icons/extracted/newapi.svg create mode 100644 src/icons/extracted/notion.svg create mode 100644 src/icons/extracted/novita.svg create mode 100644 src/icons/extracted/nvidia.svg create mode 100644 src/icons/extracted/ollama.svg create mode 100644 src/icons/extracted/openai.svg create mode 100644 src/icons/extracted/opencode-logo-light.svg create mode 100644 src/icons/extracted/openrouter.svg create mode 100644 src/icons/extracted/packycode.svg create mode 100644 src/icons/extracted/palm.svg create mode 100644 src/icons/extracted/pateway.jpg create mode 100644 src/icons/extracted/perplexity.svg create mode 100644 src/icons/extracted/pipellm.png create mode 100644 src/icons/extracted/qiniu.png create mode 100644 src/icons/extracted/qwen.svg create mode 100644 src/icons/extracted/rc.svg create mode 100644 src/icons/extracted/relaxcode.png create mode 100644 src/icons/extracted/runapi.jpg create mode 100644 src/icons/extracted/shengsuanyun.svg create mode 100644 src/icons/extracted/siliconflow.svg create mode 100644 src/icons/extracted/sssaicode.svg create mode 100644 src/icons/extracted/stability.svg create mode 100644 src/icons/extracted/stepfun.svg create mode 100644 src/icons/extracted/subrouter.svg create mode 100644 src/icons/extracted/sudocode-us.png create mode 100644 src/icons/extracted/sudocode.png create mode 100644 src/icons/extracted/tencent.svg create mode 100644 src/icons/extracted/ucloud.svg create mode 100644 src/icons/extracted/unity2.png create mode 100644 src/icons/extracted/vercel.svg create mode 100644 src/icons/extracted/wenxin.svg create mode 100644 src/icons/extracted/xai.svg create mode 100644 src/icons/extracted/xiaomimimo.svg create mode 100644 src/icons/extracted/yi.svg create mode 100644 src/icons/extracted/zeroone.svg create mode 100644 src/icons/extracted/zetaapi-icon.png create mode 100644 src/icons/extracted/zhipu.svg create mode 100644 src/icons/inference.ts create mode 100644 src/index.css create mode 100644 src/lib/agent-settings.ts create mode 100644 src/lib/dashboard-format.ts create mode 100644 src/lib/model-defaults.ts create mode 100644 src/lib/models-dev.json create mode 100644 src/lib/models-dev.ts create mode 100644 src/lib/validation.ts create mode 100644 src/main.tsx create mode 100644 src/types/dashboard.ts create mode 100644 src/types/icon.ts create mode 100644 src/types/index.ts create mode 100644 src/types/sessions.ts create mode 100644 src/vite-env.d.ts create mode 100644 tailwind.config.js create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0942c13 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +node_modules/ +dist/ +src-tauri/target/ +src-tauri/gen/ +src-tauri/wix314-binaries/ +.vscode/ +*.log +.env* +.DS_Store +Thumbs.db +Snipaste_*.png +.worktrees/ + +# 内部设计规范与实施计划,仅供本地查阅,不入版本库 +docs/superpowers/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8410cd8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 CodingPlan.site + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..24f199e --- /dev/null +++ b/README.md @@ -0,0 +1,633 @@ +# Kimi Switch + +> Windows 桌面端的 **Kimi Code CLI** 配置管理器——统一管理多家 LLM 供应商、模型、图标、连通性、用量统计与版本更新。 + +[English](./README_EN.md) | **中文** + +[![Tauri](https://img.shields.io/badge/Tauri-v2-blue?logo=tauri)](https://tauri.app) +[![React](https://img.shields.io/badge/React-18-61dafb?logo=react)](https://react.dev) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.5-3178c6?logo=typescript)](https://www.typescriptlang.org) +[![Rust](https://img.shields.io/badge/Rust-2021-ed764d?logo=rust)](https://www.rust-lang.org) +[![Version](https://img.shields.io/badge/release-v0.5.2-brightgreen)](https://git.codingplan.site/admin/KimiCodeSwitch/releases) +[![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE) + +--- + +## 目录 + +- [这是什么](#这是什么) +- [核心特性](#核心特性) +- [界面预览](#界面预览) +- [架构总览](#架构总览) +- [功能详情](#功能详情) +- [支持的供应商类型](#支持的供应商类型) +- [数据存储位置](#数据存储位置) +- [快速上手](#快速上手) +- [开发指南](#开发指南) +- [键盘快捷键](#键盘快捷键) +- [国际化](#国际化) +- [测试](#测试) +- [打包发布](#打包发布) +- [发布历史](#发布历史) +- [常见问题](#常见问题) +- [已知限制与后续建议](#已知限制与后续建议) +- [安全提示](#安全提示) +- [致谢](#致谢) + +--- + +## 这是什么 + +**Kimi Switch** 是一个为 [Kimi Code CLI](https://github.com/MoonshotAI/kimi-code) 用户打造的 Windows 桌面配置管理工具。它把 `~/.kimi-code/config.toml` 的手改工作搬到图形界面里,并补上一系列 CLI 自身没提供的便利: + +- **多供应商统一管理**:Kimi / Anthropic / OpenAI / OpenAI Responses / Google GenAI / Vertex AI,一个界面搞定;新增的供应商会**自动提升到列表最前**,再切换不会覆盖丢失 +- **模型一键发现**:根据供应商 API 自动拉取可用模型列表,模型显示名、上下文大小、能力等**优先取自 models.dev** 缓存(缺字段时再由后端/UI 兜底) +- **连通性测试**:参考 cc-switch 语义对 `base_url` 发 GET 请求,显示延迟气泡(绿/橙/红),6 秒自动消失 +- **重复供应商**:一键深拷贝现有供应商及其模型,改 key 到 `xxx-copy` 即可二次定制 +- **图标系统**:内置 100+ 主流供应商品牌图标,参考 cc-switch 实现;无匹配的供应商自动按命名规则生成首字母默认图标 +- **用量仪表盘**:移植自 kimicode-dashboard,KPI / 热力图 / 按模型分色每日趋势 / 最近请求翻页 +- **会话管理**:按工作区浏览、预览、归档、批量删除 Kimi Code 会话 +- **版本更新**:进入应用时自动检测(可关闭),并支持一键下载安装 +- **主题/语言切换**:设置面板中切换深色/浅色/跟随系统,简体中文/English +- **Windows 友好**:单实例;最小化保留任务栏按钮;关闭按钮隐藏到托盘 + +## 核心特性 + +| 分类 | 功能 | +| --- | --- | +| **多供应商** | Kimi / Anthropic / OpenAI / OpenAI Responses / Google GenAI / Vertex AI | +| **多 Agent** | 主目标 Kimi Code,Pi 代码保留但 UI 隐藏 | +| **图标系统** | 100+ 品牌图标 + 首字母默认图标;图标选择器按 brands / inference 分类 | +| **快捷切换** | 新增或激活的供应商自动提升到列表最前;切换只改 `default_model`,不丢其他供应商 | +| **连通性测试** | 实测 `base_url` 延迟,绿/橙/红彩色气泡,6 秒自动消失 | +| **重复供应商** | 一键深拷贝供应商 + 全部模型,key 改 `xxx-copy` | +| **图标按钮操作** | 启用 / 编辑 / 复制 / 测试连通 / 删除 全图标化(lucide-react) | +| **模型映射** | 别名("provider/model" 形式)↔ 实际请求模型 ID,自定义显示名、上下文长度、1M 上下文声明、能力 | +| **自动上下文** | 拉取模型时 **API 返回 > models.dev ref > 正则兜底** 三级优先级自动适配 | +| **能力自动推导** | `image_in / video_in / tool_use` 全部由 models.dev 推得;UI 仅暴露 `thinking` 一个手动开关 | +| **全局设置** | `[thinking]` 表完整支持(enabled / effort / keep),仅 Kimi Code 生效 | +| **JSON 直编** | 高级用户可手动编辑完整配置 JSON,未知字段通过 `raw_other` 透传不丢 | +| **i18n / 主题** | 简体中文 / English;深色 / 浅色 / 跟随系统;设置持久化 | +| **自动备份** | 写入 `config.toml` 前自动备份,按时间戳命名,保留最近 7 天 | +| **快捷键** | Ctrl+S 保存、Ctrl+R 重载、Ctrl+O 打开配置目录 | +| **用量仪表盘** | 8 项 KPI、每日趋势(按模型分色堆叠)、全年热力图、最近请求翻页、双击柱状图查看模型分布 | +| **会话管理** | 按工作区浏览、归档/复活、批量删除;流式逐行预览(20MB 字节上限 + 500 字符折叠) | +| **版本更新** | 启动自动 + 每 8 小时周期 + 手动检查;下载进度条;下载完成后引导安装 | +| **未保存提示** | 关闭窗口前原生 `beforeunload` 提示 + 标题栏 `*` 前缀 | +| **窗口/托盘** | 最小化保留任务栏;关闭 X 隐藏到托盘;托盘左键始终显示并聚焦 | + +## 界面预览 + +**供应商列表**(浅色主题) + +![供应商列表](docs/screenshots/providers.png) + +展示当前激活的供应商、默认模型、延迟气泡、可用模型数量与品牌图标;支持快速切换、复制、测试连通、跳转官网、编辑、删除。 + +**编辑供应商 — 基本信息** + +![编辑供应商-基本信息](docs/screenshots/provider-basic-info.png) + +包括供应商名称、备注、官网链接、托管供应商开关、API 格式、API Key、请求地址。 + +**编辑供应商 — 模型映射** + +![编辑供应商-模型映射](docs/screenshots/provider-model-mapping.png) + +一张表管理全部模型映射:显示名、实际请求模型、上下文长度、1M 上下文声明、能力(仅"思考")、设为默认、删除。 + +**用量仪表盘** + +![用量仪表盘](docs/screenshots/dashboard.png) + +8 项 KPI(请求数、非缓存输入、输出、缓存读/写/命中、总 Token、预估费用)+ 全年热力图 + 每日用量趋势(按模型分色堆叠柱状图,贴底布局)+ 模型用量明细 + 最近请求(分页)。 + +**会话管理** + +![会话管理](docs/screenshots/sessions.png) + +按工作区隔离浏览 Kimi Code 会话,支持活跃/已归档/全部筛选;流式逐行预览(20MB 字节上限,500 字符折叠);归档/取消归档/批量删除。 + +## 架构总览 + +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Kimi Switch (Tauri v2) │ +│ │ +│ ┌──────────────────────────┐ ┌──────────────────────────────┐ │ +│ │ React Frontend (TS) │ │ Rust Backend (lib.rs) │ │ +│ │ │ │ │ │ +│ │ src/App.tsx │ │ src-tauri/src/ │ │ +│ │ src/components/ │◄──►│ ├── lib.rs │ │ +│ │ ProviderList │ │ ├── main.rs │ │ +│ │ ProviderEdit │ │ ├── commands.rs │ │ +│ │ AgentSettingsPanel │ │ ├── db.rs │ │ +│ │ SettingsModal │ │ ├── kimi_code_io.rs │ │ +│ │ ProviderIcon / │ │ ├── pi_io.rs (legacy) │ │ +│ │ IconPicker │ │ ├── config_io.rs │ │ +│ │ dashboard/ │ │ ├── models.rs │ │ +│ │ sessions/ │ │ ├── validators.rs │ │ +│ │ src/hooks/ │ │ ├── dashboard.rs │ │ +│ │ useConfig / Dashboard│ │ └── profile_manager.rs │ │ +│ │ / Sessions / Theme │ │ │ │ +│ │ / UpdateCheck │ │ │ │ +│ │ src/lib/ │ │ │ │ +│ │ models-dev.ts │ │ │ │ +│ │ model-defaults.ts │ │ │ │ +│ │ agent-settings.ts │ │ │ │ +│ │ src/icons/ │ │ │ │ +│ │ brands / inference / │ │ │ │ +│ │ extracted (cc-switch)│ │ │ │ +│ │ src/i18n/{zh,en}.ts │ │ │ │ +│ │ src/types/{...} │ │ │ │ +│ └──────────────────────────┘ └──────────────────────────────┘ │ +│ │ │ │ +└──────────────────┼──────────────────────────────────┼──────────────────┘ + │ │ + ▼ ▼ + ┌──────────────────────┐ ┌──────────────────────────┐ + │ SQLite │ │ Agent 原生配置 │ + │ ~/.kimi-switch/ │ │ ├─ ~/.kimi-code/ │ + │ kimi-switch.db │ │ │ └─ config.toml │ + │ (元数据 + 兜底) │ │ └─ ~/.pi/agent/ │ + │ + localStorage │ │ ├─ models.json │ + │ (主题/语言/检查) │ │ └─ settings.json │ + └──────────────────────┘ └──────────────────────────┘ + ▲ + │ + ┌──────────────────────────────┐ + │ models.dev 快照(前端) │ + │ src/lib/models-dev.json │ + │ + 脚本 scripts/fetch-models- │ + │ dev.mjs(可选定时刷新) │ + └──────────────────────────────┘ +``` + +**关键设计**: + +- **`config.toml` 是 Kimi Code 的权威来源**:所有供应商和模型始终全量保留,`default_model` 决定哪个生效(与 CLI 原生 `/provider` 行为一致)。切换时只改 `default_model`,新增的供应商会被自动提升到列表最前,不会被覆盖 +- **SQLite 只存 Kimi Switch 专有元数据**:备注、官网、每个 Agent 记住的默认模型(`settings` 表)。主题 / 语言 / 上次更新检查时间存在前端 `localStorage`(WebView2),不在 `~/.kimi-switch` 下。`config.toml` 不完整时 SQLite 兜底 +- **`raw_other` 透传未知字段**:含 `[oauth]` 段,前后往返不丢字段 +- **models.dev 快照**:来源于 `https://models.dev/api.json`,本地 JSON 缓存 → `capabilitiesFromRef` 推导 `thinking/image_in/video_in/tool_use`,`getModelRef` 推导 `max_context_size/display_name` +- **启动版本与配置目录**:`KIMI_CODE_HOME` / `PI_CODING_AGENT_DIR` 覆盖 Kimi Code / Pi 的目录;Kimi Switch 自己的数据目录固定为 `~/.kimi-switch`,暂无环境变量覆盖(详见 [数据存储位置](#数据存储位置)) + +## 功能详情 + +### 供应商优先级与切换 + +- **新增/激活自动提升到列表最前**:添加或切换供应商时会把它移到 `db.providers` 排序的第一位,UI 直接渲染最新顺序 +- **切换只改 `default_model`**:所有供应商写入 `config.toml`,但只有被切换的成为 `default_model`,与 Kimi Code CLI `/provider` 命令一致 +- **不会覆盖丢失**:通过 `/provider` 在 CLI 端增/改/删的供应商,加载时以 `config.toml` 为准,下一次保存时全部回写 + +### 图标系统 + +- 来自 cc-switch 的 `src/icons/extracted/` 库(100+ 主流供应商品牌图标) +- 找不到精确匹配的供应商时,按命名规则生成**首字母默认图标**(例如 `kimi-code` → `K`,`deepseek-v4` → `D`) +- `IconPicker` 内置 brands / inference 分类筛选;选中的图标保存到 `provider.icon` 字段 + +### 连通性测试 + +- 调 Rust 端 `test_connectivity` 命令:GET `provider.base_url`,任何 HTTP 响应 = 可达 +- 返回 `{ ok, latency_ms, status_code, error }` +- 前端以**彩色气泡**形式内联展示(绿/橙/红 + 毫秒),6 秒后自动消失 +- 测速气泡位置在"使用中/切换"按钮之前,不挡眼 + +### 重复供应商 + +- 点击"复制"图标按钮 → 深拷贝供应商 + 全部模型 +- `provider.name` 加 `-copy` 后缀,模型自动改 key 为 `xxx-copy` +- 立即持久化到 SQLite + `config.toml`,toast 提示 + +### 自动上下文与能力 + +- 拉取模型时 `max_context_size` 三级优先级:**API 响应 > models.dev ref > 正则兜底** +- models.dev ref → `capabilities = ["thinking","image_in","video_in","tool_use"]`(按字段真值选) +- UI 上**只暴露"思考"复选框**(其它能力自动写入但不便手动编辑——保持与 Kimi Code 语义一致:能力只追加不能移除) +- `always_thinking` 只能手动加(models.dev 推导不出来),但当前 UI 屏蔽;需要时改 `config.toml` 即可 + +### 能力 vs 思考开关 + +- **模型能力**(`capabilities`)= "能不能":决定模型是否支持思考,没声明 `thinking` 即使全局开关开着也不生效 +- **全局 `[thinking]`**(设置面板)= "要不要":新会话默认开/关、强度(low/medium/high/max)、保留思考内容 +- `always_thinking` 锁死为开,忽略全局开关 +- 全局配置仅 Kimi Code 生效 + +### 用量仪表盘 + +- 8 项 KPI、每日趋势(按模型分色堆叠,**贴底布局**)、全年热力图(按 Token 量 5 级着色)、最近请求(30 条/页) +- 双击每日趋势柱状图 → 弹出 `DailyDetailModal` 显示每个模型的用量分布 +- 数据源:`src-tauri/src/dashboard.rs` + `src/hooks/useDashboard.ts` + +### 会话管理 + +- 按工作区隔离浏览 Kimi Code 会话,支持活跃/已归档/全部筛选 +- 流式逐行预览(20MB 字节上限,500 字符折叠可展开) +- 归档 / 取消归档 / 批量删除 +- 早期版本的"闪崩"已通过流式读取 + 限制解决 + +### 设置面板 + +- **主题**:深色 / 浅色 / 跟随系统(`useTheme`,持久化到前端 `localStorage`) +- **语言**:简体中文 / English +- **版本**:当前版本 + 上次检查时间 +- **更新检查**:启动自动 + 每 8 小时周期 + 手动检查;下载带进度条;下载完成后引导安装 + +### 窗口与托盘 + +- **最小化**:保留任务栏按钮,不再被劫持到托盘 +- **关闭按钮(X)**:`prevent_close` + `hide` → 隐藏到托盘而非退出 +- **托盘菜单**:显示 / 退出 +- **托盘左键**:始终 `show + unminimize + focus`(不再 toggle hide) +- **第二次启动**:`single_instance` 插件接住,回前台 + 聚焦 + +## 支持的供应商类型 + +| 类型 | 标识符 | 默认 base_url | 模型发现 | 凭证 | +| --- | --- | --- | --- | --- | +| Kimi | `kimi` | `https://api.openai.com/v1` | ✅ OpenAI 协议 | `KIMI_API_KEY` 或 `env.KIMI_API_KEY` | +| Anthropic | `anthropic` | — | ✅ `/v1/models` | `ANTHROPIC_API_KEY` 或 `env` | +| OpenAI | `openai` | `https://api.openai.com/v1` | ✅ `/models` | `OPENAI_API_KEY` 或 `env` | +| OpenAI Responses | `openai_responses` | `https://api.openai.com/v1` | ✅ `/models` | `OPENAI_API_KEY` 或 `env` | +| Google GenAI | `google-genai` | `https://generativelanguage.googleapis.com` | ✅ `/v1beta/models` | `GOOGLE_API_KEY` 或 `env` | +| Vertex AI | `vertexai` | — | ⚠️ 待实现 | `VERTEXAI_API_KEY` + `GOOGLE_CLOUD_PROJECT` + `GOOGLE_CLOUD_LOCATION` | + +凭证优先级:`api_key` 字段 > `env` 表里的同名键。 + +## 数据存储位置 + +| 文件 | 用途 | 备份 | +| --- | --- | --- | +| `%USERPROFILE%\.kimi-switch\kimi-switch.db` | Kimi Switch 自己的 SQLite,存元数据(备注/官网/记住的默认模型 + 排序)+ 兜底 | — | +| `%USERPROFILE%\.kimi-code\config.toml` | Kimi Code CLI 的 TOML 配置(**权威数据源,切换/保存时写入**) | 同目录 `backups/config.toml.bak.{YYYYMMDD_HHMMSS}`,保留 7 天 | +| `%USERPROFILE%\.pi\agent\models.json` | Pi 的供应商+模型配置(**切换时写入**) | 同目录 `backups/models.json.bak.{YYYYMMDD_HHMMSS}`,保留 7 天 | +| `%USERPROFILE%\.pi\agent\settings.json` | Pi 的默认供应商/模型(**切换时写入**) | 同目录 `backups/settings.json.bak.{YYYYMMDD_HHMMSS}`,保留 7 天 | +| WebView2 `localStorage` | 前端状态:`kimi-switch-theme` / `kimi-switch-lang` / `kimi-switch-last-update-check` / `kimi-switch-agent` / `kimi-switch-dashboard-range`(主题 / 语言 / 上次更新检查 / 上次选中 Agent / 仪表盘时间范围) | — | +| `src/lib/models-dev.json` | models.dev `api.json` 快照(前端内置) | — | + +环境变量覆盖: + +- `KIMI_CODE_HOME` 覆盖 Kimi Code 配置目录(默认 `~/.kimi-code`) +- `PI_CODING_AGENT_DIR` 覆盖 Pi Agent 配置目录(默认 `~/.pi/agent`) +- Kimi Switch 自己的数据目录固定为 `~/.kimi-switch`,**暂无环境变量覆盖** + +## 快速上手 + +### 前置依赖 + +| 工具 | 版本 | 说明 | +| --- | --- | --- | +| Node.js | ≥ 18 | 前端构建 | +| Rust | stable 最新版(edition 2021) | Tauri 后端编译 | +| WebView2 Runtime | Windows 10/11 默认已装 | Tauri v2 运行时 | +| Microsoft C++ Build Tools | 最新版 | Rust 编译依赖 | +| WiX Toolset 3.14 | `src-tauri/wix314-binaries/` | MSI 打包(首次构建自动下载) | + +### 安装 + +```bash +npm install +``` + +### 开发模式(热重载) + +```bash +npm run tauri-dev +``` + +同时启动 Vite 开发服务器(端口 1420)和 Tauri 窗口;前端热重载,Rust 自动重编译。 + +### 仅前端开发(无 Tauri 窗口) + +```bash +npm run dev +``` + +适用于纯 UI 调试。 + +## 开发指南 + +### 项目结构 + +``` +. +├── src/ # React 前端 +│ ├── App.tsx # 主组件,路由 ProviderList/ProviderEdit + 仪表盘/会话 +│ ├── main.tsx # React 入口 + ErrorBoundary + I18nProvider +│ ├── components/ +│ │ ├── ProviderList.tsx # 供应商列表 + 切换 / 复制 / 测试连通 / 编辑 / 删除 +│ │ ├── ProviderEdit.tsx # 供应商编辑 + 模型映射 + JSON 直编 + 能力 +│ │ ├── AgentSettingsPanel.tsx # Kimi Code 全局设置(思考/循环/权限/钩子) +│ │ ├── SettingsModal.tsx # 设置弹窗(主题 / 语言 / 版本 / 检查更新) +│ │ ├── ProviderIcon.tsx # 供商品牌图标(带首字母兜底) +│ │ ├── IconPicker.tsx # 图标选择器(brands / inference 分类) +│ │ ├── dashboard/ # 用量仪表盘 +│ │ │ ├── DashboardPage.tsx +│ │ │ ├── DailyBars.tsx +│ │ │ ├── DailyDetailModal.tsx +│ │ │ └── Heatmap.tsx +│ │ └── sessions/ # 会话管理 +│ │ └── SessionsPage.tsx +│ ├── hooks/ +│ │ ├── useConfig.ts # 加载/保存配置 +│ │ ├── useDashboard.ts # 仪表盘数据 +│ │ ├── useSessions.ts # 会话数据 +│ │ ├── useTheme.ts # 主题切换 +│ │ └── useUpdateCheck.ts # 版本检查 + 下载 +│ ├── lib/ +│ │ ├── agent-settings.ts # AgentSettings 解析/序列化 +│ │ ├── model-defaults.ts # 模型默认上下文大小 +│ │ ├── models-dev.ts # models.dev 快照查找 + 能力映射 +│ │ ├── models-dev.json # 内置快照 +│ │ └── dashboard-format.ts # 仪表盘格式化 +│ ├── icons/ +│ │ ├── brands.ts # 品牌图标入口 +│ │ ├── inference.ts # 推理服务图标 +│ │ └── extracted/ # 来自 cc-switch 的图标库 +│ │ ├── index.ts +│ │ └── metadata.ts +│ ├── types/ +│ │ ├── index.ts # Provider/Model/Config +│ │ ├── dashboard.ts +│ │ ├── sessions.ts +│ │ └── icon.ts +│ ├── i18n/ +│ │ ├── zh.ts # 中文翻译(源) +│ │ ├── en.ts # 英文翻译 +│ │ └── index.tsx # useTranslation hook + Provider +│ └── index.css # Tailwind 入口 +│ +├── src-tauri/ # Rust 后端 +│ ├── src/ +│ │ ├── lib.rs # Tauri Builder + 托盘 + 窗口事件 + invoke_handler +│ │ ├── main.rs # 二进制入口 +│ │ ├── commands.rs # ~14 个 Tauri Command +│ │ ├── db.rs # SQLite 持久化 +│ │ ├── kimi_code_io.rs # ~/.kimi-code/config.toml 读写 +│ │ ├── pi_io.rs # ~/.pi/agent/*.json 读写(保留) +│ │ ├── config_io.rs # 文件备份工具 +│ │ ├── models.rs # Config/Provider/Model 数据结构 +│ │ ├── profile_manager.rs # 多 Profile 管理(占位) +│ │ ├── validators.rs # 配置校验 +│ │ └── dashboard.rs # 会话/用量数据聚合 +│ ├── capabilities/ # Tauri 权限声明 +│ ├── icons/ # 应用图标(脚本生成) +│ └── tauri.conf.json # Tauri 配置(窗口/打包/CSP) +│ +├── scripts/ +│ ├── fetch-models-dev.mjs # 刷新 models-dev.json 快照 +│ └── generate-icons.py # 从 SVG 生成各尺寸图标 +├── public/kimi.svg # 应用图标源(蓝紫渐变 π) +└── docs/ + ├── screenshots/ # README 引用的界面截图 + └── superpowers/ # 设计规范与实施计划 +``` + +### Tauri Commands(前端 ↔ 后端) + +| 命令 | 说明 | +| --- | --- | +| `load_agent_config_command(agent)` | 加载配置:Kimi Code 以 `config.toml` 为权威 + SQLite 补充;Pi 优先 SQLite | +| `save_agent_config_command(agent, config)` | 保存到 SQLite;Kimi Code 同时写入 `config.toml` | +| `activate_agent_config_command(agent)` | 全量写入 Agent 原生配置(Kimi Code 写全部供应商,`default_model` 决定生效项;Pi 仅写活跃供应商) | +| `open_agent_config_dir(agent)` | 打开 Agent 配置目录 | +| `get_app_version()` | 返回 `Cargo.toml` 版本号 | +| `list_provider_models(provider)` | 调供应商 API 拉取模型列表(异步,分页) | +| `test_connectivity(provider)` | GET `base_url` 测连通性,返回 `{ ok, latency_ms, status_code, error }` | +| `get_app_setting(key)` | 读取 App 设置(主题 / 语言 / 上次更新检查时间) | +| `set_app_setting(key, value)` | 写入 App 设置 | +| `check_for_update()` | 检查 GitHub releases,返回版本号 + 资产 URL | +| `download_update(url, path)` | 流式下载更新包,发 `download-progress` / `download-complete` 事件 | +| `open_installer(path)` | 用系统 shell 打开下载好的安装包 | +| `dashboard::get_paths()` / `get_prices()` / `get_summary()` / `list_sessions()` / `archive_session()` / `unarchive_session()` / `delete_session()` / `delete_workspace()` / `get_session_preview()` | 用量与会话相关 | +| `debug_log(message)` | 前端日志 → stderr(开发用) | + +### 添加新供应商类型 + +1. `src-tauri/src/models.rs` 的 `ProviderType` 枚举加新变体 +2. `default_base_url()` 加默认值 +3. `commands.rs::list_provider_models` 的 `match` 加分发 +4. `kimi_code_io.rs::provider_type_for_kimi_type` 加映射 +5. `src/components/ProviderEdit.tsx` 的 API 格式下拉加选项 +6. `src/i18n/{zh,en}.ts` 加 i18n 键 + +### 添加新 Tauri Command + +1. `src-tauri/src/commands.rs` 加 `#[tauri::command]` +2. `src-tauri/src/lib.rs` 的 `tauri::generate_handler![...]` 注册 +3. 前端 `import { invoke } from "@tauri-apps/api/core"` 调用 +4. `src-tauri/capabilities/default.json` 加权限(如需文件/网络) + +### 添加新模型能力 + +1. `src/components/ProviderEdit.tsx` 的 `KNOWN_CAPABILITIES` 加新键 +2. `CAPABILITY_LABELS` 加 i18n 映射 +3. `src/i18n/{zh,en}.ts` 加翻译 +4. `src/lib/models-dev.ts` 的 `capabilitiesFromRef` 加推导(若可从 models.dev 推) + +## 键盘快捷键 + +| 快捷键 | 作用 | +| --- | --- | +| `Ctrl + S` | 保存当前修改到 SQLite + `config.toml`(Kimi Code) | +| `Ctrl + R` | 重新读取配置(未保存时提示) | +| `Ctrl + O` | 打开当前 Agent 的配置目录 | + +## 国际化 + +- 翻译源:`src/i18n/zh.ts`(源) + `src/i18n/en.ts`(目标) +- 新增 key **先在 `zh.ts` 里加**,`en.ts` 的 `Record` 类型会自动校验缺失条目(编译时报错) +- `useTranslation` hook 暴露 `{ t, lang, setLang }` +- 运行时切换由 `SettingsModal` 提供,持久化到前端 `localStorage`(`kimi-switch-lang`) + +## 测试 + +### Rust 单元测试 + +```bash +cd src-tauri +cargo test +``` + +当前覆盖: + +- `kimi_code_io::tests` — TOML 导入/导出往返 +- `pi_io::tests` — JSON 往返,含 advanced fields(headers/compat/cost/extra) +- `validators::tests` — 配置校验 +- `dashboard::tests` — 用量聚合与时区处理 + +### 前端 + +暂未自动化测试,建议手动验证清单: + +- [ ] 切换供应商后默认模型正确回填 +- [ ] 添加新供应商自动提升到列表最前 +- [ ] 重复供应商生成的 key 不冲突 +- [ ] 测试连通性气泡在 6 秒后自动消失 +- [ ] 关闭 X 隐藏到托盘;最小化保留任务栏 +- [ ] 主题切换(深色 / 浅色 / 跟随系统)即时生效 +- [ ] 切换语言后 UI 文案立即更新 +- [ ] 启动检查更新 → 下载 → 引导安装 +- [ ] 拉取模型时 `max_context_size` 自动填充 +- [ ] 切换供应商后 Kimi Code 会话经 `/reload` + `/model` 选回默认(或 `/exit` 重开会话)后生效 + +## 打包发布 + +```bash +npm run tauri-build +``` + +产物位置: + +``` +src-tauri/target/release/bundle/msi/Kimi Switch__x64_en-US.msi +``` + +Windows 安装包(MSI),含 WebView2 bootstrapper 自动下载。`nsis` 已禁用,目前只产 MSI。 + +### 首次打包 + +首次运行会下载: + +- WiX Toolset 3.14 binaries → `src-tauri/wix314-binaries/` +- WebView2 bootstrapper → 打包进 MSI + +### 常见构建问题 + +- **`os error 5`**(WiX light 步骤):先 `taskkill //F //IM kimiswitch.exe` 杀掉占用进程后重试 +- **prebuild 拉 models.dev 超时**:属正常,本地快照兜底不影响构建 + +## 发布历史 + +### v0.5.1(最新) + +- 窗口/托盘:最小化保留任务栏;关闭 X 隐藏到托盘;托盘左键始终显示并聚焦 +- 模型用量表:模型列宽度自适应,长模型名完整显示不再截断 +- 模型能力编辑:只保留"思考",其余能力仍由 models.dev 自动推导 +- 模型映射表格:行分隔线改为主题感知,修复浅色模式突兀问题 + +### v0.5.0 + +- 供应商操作图标化(lucide-react):启用 / 编辑 / 复制 / 测试连通 / 删除 +- 重复供应商(深拷贝供应商 + 全部模型) +- 连通性测试(绿/橙/红气泡 + 6 秒自动消失) +- 每日趋势柱状图锚定到面板底部 + +### v0.4.1 + +- 模型发现分页(OpenAI / Anthropic / Google),减少大列表命中限制 + +### v0.4.0 + +- 完善的图标系统(移植自 cc-switch 图标库) +- 设置面板(主题、语言) +- 启动版本检查 + +### v0.3.0 + +[移植自 kimicode-dashboard](https://github.com/JochenYang/kimicode-dashboard): + +- 用量仪表盘:8 KPI、每日趋势、全年热力图、最近请求翻页 +- 会话管理:按工作区浏览、预览、归档、批量删除 +- 时区修复:`today` / 热力图 / `day_key` 改用本地日历日 +- Pi 选项隐藏 + +## 常见问题 + +**Q: 切换供应商后 Kimi Code 没生效?** +A: 需要分两步: +1. 在 Kimi Code 会话里执行 `/reload`,让 CLI 重新读取 `~/.kimi-code/config.toml`(此时模型**下拉列表**会刷新); +2. **再执行一次 `/model` 选回新的默认模型**,或者直接 `/exit` 重开会话。 + +仅 `/reload` **不会**把新的 `default_model` 自动套用到当前会话——这是 Kimi Code 的已知行为,详见下方[已知限制与后续建议](#已知限制与后续建议)。应用会在 UI 上提示这两步。 + +**Q: 切换会覆盖其他供应商吗?** +A: 不会。Kimi Code 的 `config.toml` 始终写入全部供应商,仅 `default_model` 决定生效项。这与 CLI 原生 `/provider` 行为一致。 + +**Q: 新增/激活的供应商位置怎么变?** +A: 自动提升到列表最前,UI 立即反映。 + +**Q: 为什么能力只显示"思考"?** +A: Kimi Code 语义上 `capabilities` 只追加不能移除,models.dev 已有自动推导,再手动暴露只会增加误操作风险。需要声明 `always_thinking` 等特殊值时直接编辑 `config.toml` 即可。 + +**Q: 改了配置但忘了保存就关了窗口?** +A: 关闭窗口前有原生 `beforeunload` 提示,标题栏也会显示 `*` 前缀。 + +**Q: 怎么备份/迁移我的配置?** +A: 对 Kimi Code,`config.toml` 本身就是全量权威,直接备份即可;`kimi-switch.db` 存备注 / 官网 / 排序,迁移时一并备份。主题 / 语言 / 上次更新检查时间存在前端 `localStorage`(WebView2),不是独立文件,迁移时通常无需单独处理。 + +**Q: Vertex AI 为什么不能拉取模型列表?** +A: Vertex 需要 GCP project / location 凭证,当前实现留 TODO,等 GCP SDK 集成后补。 + +**Q: 支持 macOS / Linux 吗?** +A: 代码不依赖 Windows 专属 API,但 `tauri.conf.json` 的 bundle 目标目前只配了 `msi`。理论上把 `bundle.targets` 改成 `["app", "dmg"]` 等即可跨平台,但未验证。 + +**Q: 怎么改主题 / 语言?** +A: 顶部齿轮 → 设置弹窗 → 主题 / 语言。保存到前端 `localStorage`(WebView2),重启后保持。 + +**Q: 把窗口关了怎么再打开?** +A: 关闭按钮(X)已改为隐藏到托盘。点击托盘图标(菜单栏 / 系统托盘)即可拉回;点击任务栏图标正常切换最小化/还原。 + +**Q: 检查更新是怎么触发的?** +A: 启动时静默检查一次,之后每 8 小时自动检查一次(无网络时静默失败,不弹错)。也可手动:设置弹窗 → 版本 → 检查更新。下载有进度条,下载完成后会有"打开安装包"按钮。 + +## 已知限制与后续建议 + +### `/reload` 不会切换当前会话的默认模型(Kimi Code 上游限制) + +**现象**:在 Kimi Switch 切换供应商后,`config.toml` 顶层的 `default_model` 已经被正确更新;回到 Kimi Code CLI 执行 `/reload`,模型**下拉列表**能列出新的默认模型,但**当前会话实际仍在使用旧模型**(底部状态栏显示的模型、真正发出的请求都没变)。 + +**根因**(已对照 Kimi Code 源码确认,不是 Kimi Switch 的 bug): + +- `/reload` 命令(`apps/kimi-code/src/tui/commands/reload.ts`)在刷新 `availableModels / availableProviders` 之后,**没有**把 `config.defaultModel` 重新套用到当前会话的 agent 上。 +- 会话当前的模型(`agent.config.modelAlias`)来自会话创建时的 `options.model ?? config.defaultModel`(`packages/agent-core/src/rpc/core-impl.ts:438-440`),并通过 `records.logRecord` 持久化进会话日志;`Agent.resume()` 调 `records.replay()` 时会**回放这些历史记录**,从而把模型恢复成"上次手动选的",而不是 `config.defaultModel`。 +- 单元测试(`apps/kimi-code/test/tui/commands/reload.test.ts:87-89`)也只断言"模型列表刷新了",没有任何"当前会话切到新默认模型"的断言——因为实现层就没做这一步。 +- 全仓检索 `FOLLOW_DEFAULT / reloadDefault / KIMI_CODE_RELOAD` 等关键字**零命中**,说明 Kimi Code 目前**没有**任何"reload 时跟随 default_model"的开关。 + +**Workaround(当前可用)**: + +1. `/reload` 后再执行 `/model`,手动选一次新默认模型;或 +2. `/exit` 退出会话再重开(重新走 `createSession` 路径,会把 `config.defaultModel` 套到新会话)。 + +**建议反馈给 Kimi Code 上游的修复点**: + +- 文件:`apps/kimi-code/src/tui/commands/reload.ts` 的 `handleReloadCommand`。 +- 位置:`applyRuntimeConfig(host, config)` 之后,补一段把 `config.defaultModel` 同步到当前会话 agent 的逻辑,例如: + ```ts + const newDefault = config.defaultModel; + const current = /* host.session 当前 agent 的 modelAlias */; + if (newDefault && newDefault !== current) { + await host.session.mainAgent.config.update({ modelAlias: newDefault }); + } + ``` +- 配套断言:在 `reload.test.ts` 增加对"reload 后会话当前模型 == 新 `defaultModel`"的测试,防回归。 +- 可选增强:暴露一个会话级"follow default on reload"开关,或当会话旧 alias 已被删除时自动回退到 `default_model`。 + +> 注:以上建议**尚未提交给官方**,记录于此供后续跟进。Kimi Switch 侧只能保证 `config.toml` 写入正确,无法绕开 Kimi Code 自身的 `/reload` 语义。 + +### 其它后续建议(按优先级) + +- **P1 — 模型别名规范**:早期裸名或 `-1/-2` 后缀的别名(如 `kimi-k3`、`glm-5-2-1`)已批量重命名为 `provider/model` 形式;新增供应商时建议**强制**采用规范命名,避免再出现补全后缀。可在保存前加一层 lint。 +- **P1 — 用量趋势多维度**:用量趋势已支持"模型用量趋势 / 供应商模型用量趋势"两个 Tab;后续可考虑增加"按工作区"或"按 Token / 按费用"的第三维度切换。 +- **P2 — 周期检查更新**:当前为启动 + 每 8 小时一次;后续可考虑做成可配置项(设置面板里设周期 / 关闭)。 +- **P2 — 跨平台**:目前只产 MSI,代码不依赖 Windows 专属 API;待 Tauri v2 的 macOS/Linux bundle 配置后即可验证。 +- **P3 — 配置校验增强**:`validators.rs` 当前偏基础,可补:`base_url` 合法性、`env` 与 `api_key` 互斥、`oauth` 段完整性。 + +## 安全提示 + +- API Key 明文存储在本地 SQLite 和 Agent 原生配置里——**不要在共享电脑上保存** +- 不要把 `kimi-switch.db`、`config.toml`、`models.json` 提交到 Git +- 应用 CSP 已收紧(`default-src 'self'`),但 WebView2 仍可能缓存表单内容,注意在公共电脑用完退出 + +--- + +## 致谢 + +用量仪表盘与会话管理功能基于 [kimicode-dashboard](https://github.com/JochenYang/kimicode-dashboard)(MIT 许可证,© JochenYang)移植。Rust 后端(`src-tauri/src/dashboard.rs`)、前端仪表盘(`src/components/dashboard/`)、会话管理页(`src/components/sessions/`)均源自该项目,感谢原作者的开源贡献。 + +供应商品牌图标资源(`src/icons/extracted/`)与图标选择器(`src/components/IconPicker.tsx`)参考自 [cc-switch](https://github.com/farion1231/cc-switch)(MIT 许可证,© Jason Young),感谢原作者的开源贡献。 + +供应商预设结构(`src/config/providerPresets.ts`)与余额/套餐查询实现(`src-tauri/src/services/`)同样参考自 [cc-switch](https://github.com/farion1231/cc-switch)(MIT 许可证,© Jason Young)。 + +--- + +许可证:MIT,详见 [LICENSE](./LICENSE)。Copyright (c) 2026 CodingPlan.site diff --git a/README_EN.md b/README_EN.md new file mode 100644 index 0000000..16d6b4f --- /dev/null +++ b/README_EN.md @@ -0,0 +1,629 @@ +# Kimi Switch + +> A Windows desktop **Kimi Code CLI** configuration manager — unify multi-provider LLM setup, models, icons, connectivity testing, usage analytics, and update checks in one place. + +**English** | [中文](./README.md) + +[![Tauri](https://img.shields.io/badge/Tauri-v2-blue?logo=tauri)](https://tauri.app) +[![React](https://img.shields.io/badge/React-18-61dafb?logo=react)](https://react.dev) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.5-3178c6?logo=typescript)](https://www.typescriptlang.org) +[![Rust](https://img.shields.io/badge/Rust-2021-ed764d?logo=rust)](https://www.rust-lang.org) +[![Version](https://img.shields.io/badge/release-v0.5.2-brightgreen)](https://git.codingplan.site/admin/KimiCodeSwitch/releases) +[![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE) + +--- + +## Table of Contents + +- [What Is This](#what-is-this) +- [Key Features](#key-features) +- [Screenshots](#screenshots) +- [Architecture Overview](#architecture-overview) +- [Feature Details](#feature-details) +- [Supported Provider Types](#supported-provider-types) +- [Data Storage Locations](#data-storage-locations) +- [Getting Started](#getting-started) +- [Development Guide](#development-guide) +- [Keyboard Shortcuts](#keyboard-shortcuts) +- [Internationalization](#internationalization) +- [Testing](#testing) +- [Build & Release](#build--release) +- [Release History](#release-history) +- [FAQ](#faq) +- [Known Limitations & Next Steps](#known-limitations--next-steps) +- [Security Notes](#security-notes) +- [Credits](#credits) + +--- + +## What Is This + +**Kimi Switch** is a Windows desktop configuration tool built for [Kimi Code CLI](https://github.com/MoonshotAI/kimi-code) users. It pulls the hand-editing of `~/.kimi-code/config.toml` into a GUI and adds a pile of conveniences the CLI itself doesn't ship: + +- **Unified multi-provider management** — Kimi / Anthropic / OpenAI / OpenAI Responses / Google GenAI / Vertex AI in one view; newly added providers are **automatically promoted to the top of the list**, and switching never overwrites or loses them +- **One-click model discovery** — fetch the available model list from the provider API; display names, context size, and capabilities **prefer the models.dev cache** (backend/UI fallback for missing fields) +- **Connectivity testing** — GET `base_url` (cc-switch semantics), with a coloured latency bubble (green / orange / red) that auto-dismisses in 6 seconds +- **Duplicate provider** — deep-copy an existing provider along with all its models in one click; the key becomes `xxx-copy` +- **Icon system** — 100+ first-party provider brand icons, adapted from cc-switch; unmatched providers get a deterministic initial-letter placeholder +- **Usage dashboard** — ported from kimicode-dashboard: KPIs / heatmap / per-model daily trend stacked bars / paginated recent requests +- **Session manager** — per-workspace browsing, preview, archive, and bulk delete for Kimi Code sessions +- **Update check** — auto-check on launch (toggleable) and one-click download + install +- **Theme / language** — dark / light / follow-system themes; Simplified Chinese / English +- **Windows polish** — single instance; minimize keeps the taskbar button; close hides to tray + +## Key Features + +| Category | Feature | +| --- | --- | +| **Multi-provider** | Kimi / Anthropic / OpenAI / OpenAI Responses / Google GenAI / Vertex AI | +| **Multi-agent** | Primary target is Kimi Code; Pi code is preserved but hidden from the UI | +| **Icon system** | 100+ first-party icons + initial-letter fallback; picker grouped by brands / inference | +| **Quick switch** | Added/activated providers move to the top of the list; switching only changes `default_model` and never drops other providers | +| **Connectivity test** | Real `base_url` latency, coloured bubble (green / orange / red), auto-dismiss in 6 seconds | +| **Duplicate provider** | Deep-copy a provider + all its models; key auto-suffixed to `xxx-copy` | +| **Iconified actions** | Activate / Edit / Duplicate / Test Connectivity / Delete via lucide-react | +| **Model mapping** | Alias (`"provider/model"`) ↔ real model ID, with display name, context size, 1M-context flag, and capabilities | +| **Auto context size** | On model fetch: **API response > models.dev ref > regex fallback** — three-tier priority | +| **Auto capabilities** | `image_in / video_in / tool_use` all derived from models.dev; UI only exposes `thinking` as a manual toggle | +| **Global settings** | Full `[thinking]` table (enabled / effort / keep); Kimi Code only | +| **Raw JSON editing** | Power users can hand-edit the full config; unknown fields pass through `raw_other` and never get dropped | +| **i18n / Theme** | Simplified Chinese / English; dark / light / follow-system; persisted | +| **Auto backup** | Before writing `config.toml`, backup with timestamp-based names kept 7 days | +| **Shortcuts** | `Ctrl+S` save, `Ctrl+R` reload, `Ctrl+O` open config dir | +| **Usage dashboard** | 8 KPIs, per-model stacked daily trend, full-year heatmap, paginated recent requests, double-click bars for per-model breakdown modal | +| **Session manager** | Per-workspace browsing, archive/unarchive, bulk delete; streaming line-by-line preview (20MB cap + 500-char collapse) | +| **Update check** | Auto-check on launch + every 8h periodic + manual; download progress bar; guided install after download | +| **Unsaved-changes prompt** | Native `beforeunload` warning + `*` prefix in title bar | +| **Window / tray** | Minimize keeps the taskbar button; close X hides to tray; tray left-click always shows + focuses | + +## Screenshots + +**Provider list** (light theme) + +![Provider list](docs/screenshots/providers.png) + +Active provider, default model, latency bubble, model count, and brand icons at a glance. Quick switch, copy, test connectivity, open website, edit, delete. + +**Edit provider — basic info** + +![Edit provider — basic info](docs/screenshots/provider-basic-info.png) + +Provider name, notes, official URL, managed-provider toggle, API format, API key, and base URL. + +**Edit provider — model mapping** + +![Edit provider — model mapping](docs/screenshots/provider-model-mapping.png) + +A single table for all model mappings: display name, real model ID, context length, 1M-context flag, capability (thinking only), default toggle, delete. + +**Usage dashboard** + +![Usage dashboard](docs/screenshots/dashboard.png) + +8 KPIs (requests, non-cached input, output, cache read / write / hit, total tokens, estimated cost) + full-year heatmap + per-model stacked daily trend (bottom-aligned) + per-model usage table + paginated recent requests. + +**Session manager** + +![Session manager](docs/screenshots/sessions.png) + +Per-workspace Kimi Code session browsing, active / archived / all filters; streaming line-by-line preview (20MB cap, 500-char collapse); archive/unarchive/bulk delete. + +## Architecture Overview + +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Kimi Switch (Tauri v2) │ +│ │ +│ ┌──────────────────────────┐ ┌──────────────────────────────┐ │ +│ │ React Frontend (TS) │ │ Rust Backend (lib.rs) │ │ +│ │ │ │ │ │ +│ │ src/App.tsx │ │ src-tauri/src/ │ │ +│ │ src/components/ │◄──►│ ├── lib.rs │ │ +│ │ ProviderList │ │ ├── main.rs │ │ +│ │ ProviderEdit │ │ ├── commands.rs │ │ +│ │ AgentSettingsPanel │ │ ├── db.rs │ │ +│ │ SettingsModal │ │ ├── kimi_code_io.rs │ │ +│ │ ProviderIcon / │ │ ├── pi_io.rs (legacy) │ │ +│ │ IconPicker │ │ ├── config_io.rs │ │ +│ │ dashboard/ │ │ ├── models.rs │ │ +│ │ sessions/ │ │ ├── validators.rs │ │ +│ │ src/hooks/ │ │ ├── dashboard.rs │ │ +│ │ useConfig / Dashboard│ │ └── profile_manager.rs │ │ +│ │ / Sessions / Theme │ │ │ │ +│ │ / UpdateCheck │ │ │ │ +│ │ src/lib/ │ │ │ │ +│ │ src/icons/ │ │ │ │ +│ │ src/i18n/{zh,en}.ts │ │ │ │ +│ │ src/types/{...} │ │ │ │ +│ └──────────────────────────┘ └──────────────────────────────┘ │ +│ │ │ │ +└──────────────────┼──────────────────────────────────┼──────────────────┘ + │ │ + ▼ ▼ + ┌──────────────────────┐ ┌──────────────────────────┐ + │ SQLite │ │ Agent native configs │ + │ ~/.kimi-switch/ │ │ ├─ ~/.kimi-code/ │ + │ kimi-switch.db │ │ │ └─ config.toml │ + │ (metadata + fallback)│ │ └─ ~/.pi/agent/ │ + │ + localStorage │ │ ├─ models.json │ + │ (theme / lang / │ │ └─ settings.json │ + │ update-check) │ │ │ + └──────────────────────┘ └──────────────────────────┘ + ▲ + │ + ┌──────────────────────────────┐ + │ models.dev snapshot (FE) │ + │ src/lib/models-dev.json │ + │ + scripts/fetch-models- │ + │ dev.mjs (optional refresh) │ + └──────────────────────────────┘ +``` + +**Key design points**: + +- **`config.toml` is the authoritative source for Kimi Code**: all providers and models are always written in full; `default_model` selects the active one (matching the CLI's native `/provider` behaviour). Switching only changes `default_model`; newly added providers are auto-promoted to the top of the list and never get overwritten +- **SQLite holds Kimi Switch-private metadata only**: notes, official URLs, per-agent remembered default model (the `settings` table), ordering. Theme / language / last-update-check live in frontend `localStorage` (WebView2), not under `~/.kimi-switch`. It acts as a fallback when `config.toml` is incomplete +- **`raw_other` passes unknown fields through untouched**, including `[oauth]` blocks — round-trips never drop fields +- **models.dev snapshot**: derived from `https://models.dev/api.json`, cached to a local JSON; `capabilitiesFromRef` derives `thinking / image_in / video_in / tool_use`, `getModelRef` derives `max_context_size / display_name` +- **Override env vars**: `KIMI_CODE_HOME` / `PI_CODING_AGENT_DIR` override the Kimi Code / Pi dirs; Kimi Switch's own data dir is fixed at `~/.kimi-switch` (no env override yet). See [Data Storage Locations](#data-storage-locations) + +## Feature Details + +### Provider priority & switching + +- **Auto-promote to top on add/activate**: when you add or switch a provider, it moves to the first position in `db.providers`; the UI renders the freshest order immediately +- **Switching only changes `default_model`**: all providers are written to `config.toml`, only the switched one becomes `default_model` — consistent with Kimi Code CLI's `/provider` +- **Never overwrites**: providers added/edited/deleted via the CLI's `/provider` are correctly reflected on load (config.toml wins), and fully persisted on next save + +### Icon system + +- Library adapted from cc-switch (`src/icons/extracted/`, 100+ first-party brand icons) +- Providers without an exact match get a deterministic **initial-letter placeholder** (e.g. `kimi-code` → `K`, `deepseek-v4` → `D`) +- `IconPicker` has brands / inference groups; the chosen icon is saved to `provider.icon` + +### Connectivity test + +- Backend `test_connectivity` command: GET `provider.base_url`; any HTTP response = reachable +- Returns `{ ok, latency_ms, status_code, error }` +- Frontend renders a **coloured bubble** (green / orange / red + ms) inline; auto-dismisses in 6 seconds +- The bubble sits before the "active / switch" button so it doesn't block the sight + +### Duplicate provider + +- Click the duplicate icon → deep-copy the provider + all its models +- `provider.name` gets a `-copy` suffix; model keys auto-suffix to `xxx-copy` +- Immediately persisted to SQLite + `config.toml`; toast confirmation + +### Auto context size & capabilities + +- On fetch, `max_context_size` priority: **API response > models.dev ref > regex fallback** +- models.dev ref → `capabilities = ["thinking","image_in","video_in","tool_use"]` (filtered by truthy fields) +- UI exposes **only the `thinking` checkbox**. Other capabilities are still auto-written but not manually editable — this matches Kimi Code's semantics: capabilities can only be added, never removed +- `always_thinking` can only be set manually (models.dev can't derive it). The UI hides it; edit `config.toml` directly when needed + +### Capability vs thinking switch + +- **Model capability** (`capabilities`) = "can it": declares whether the model supports thinking. Without `thinking`, the global switch has no effect on this model +- **Global `[thinking]`** (settings panel) = "do we want": new sessions default on/off, effort level (low/medium/high/max), and whether to keep thinking content +- `always_thinking` forces thinking on, ignoring the global switch +- Global settings apply to Kimi Code only + +### Usage dashboard + +- 8 KPIs, per-model stacked daily trend (**bottom-aligned layout**), full-year heatmap (5-level token colouring), paginated recent requests (30/page) +- Double-click a daily bar → `DailyDetailModal` with per-model breakdown +- Data source: `src-tauri/src/dashboard.rs` + `src/hooks/useDashboard.ts` + +### Session manager + +- Per-workspace Kimi Code session browsing, active / archived / all filters +- Streaming line-by-line preview (20MB cap, 500-char collapse with expand) +- Archive / unarchive / bulk delete +- Earlier "instant crash" issues fixed via streaming reads + size limits + +### Settings modal + +- **Theme**: dark / light / follow-system (`useTheme`, persisted to frontend `localStorage`) +- **Language**: Simplified Chinese / English +- **Version**: current version + last-checked timestamp +- **Update check**: launch auto + every 8h periodic + manual; download with progress bar; guided install after completion + +### Window & tray + +- **Minimize**: keeps the taskbar button (no longer hijacked to tray) +- **Close (X)**: `prevent_close` + `hide` → hides to tray instead of quitting +- **Tray menu**: Show / Quit +- **Tray left-click**: always `show + unminimize + focus` (no toggle hide) +- **Second launch**: `single_instance` plugin catches it, brings window to front and focuses + +## Supported Provider Types + +| Type | Identifier | Default base_url | Model discovery | Credentials | +| --- | --- | --- | --- | --- | +| Kimi | `kimi` | `https://api.openai.com/v1` | ✅ OpenAI protocol | `KIMI_API_KEY` or `env.KIMI_API_KEY` | +| Anthropic | `anthropic` | — | ✅ `/v1/models` | `ANTHROPIC_API_KEY` or `env` | +| OpenAI | `openai` | `https://api.openai.com/v1` | ✅ `/models` | `OPENAI_API_KEY` or `env` | +| OpenAI Responses | `openai_responses` | `https://api.openai.com/v1` | ✅ `/models` | `OPENAI_API_KEY` or `env` | +| Google GenAI | `google-genai` | `https://generativelanguage.googleapis.com` | ✅ `/v1beta/models` | `GOOGLE_API_KEY` or `env` | +| Vertex AI | `vertexai` | — | ⚠️ Not yet implemented | `VERTEXAI_API_KEY` + `GOOGLE_CLOUD_PROJECT` + `GOOGLE_CLOUD_LOCATION` | + +Credential precedence: `api_key` field > same-named key in `env` table. + +## Data Storage Locations + +| File | Purpose | Backup | +| --- | --- | --- | +| `%USERPROFILE%\.kimi-switch\kimi-switch.db` | Kimi Switch's own SQLite — metadata (notes / official URLs / remembered default model + ordering) + fallback | — | +| `%USERPROFILE%\.kimi-code\config.toml` | Kimi Code CLI TOML config (**authoritative source, written on switch/save**) | `backups/config.toml.bak.{YYYYMMDD_HHMMSS}` next to it, kept 7 days | +| `%USERPROFILE%\.pi\agent\models.json` | Pi provider + model config (**written on switch**) | `backups/models.json.bak.{YYYYMMDD_HHMMSS}` next to it, kept 7 days | +| `%USERPROFILE%\.pi\agent\settings.json` | Pi default provider/model (**written on switch**) | `backups/settings.json.bak.{YYYYMMDD_HHMMSS}` next to it, kept 7 days | +| WebView2 `localStorage` | Frontend state: `kimi-switch-theme` / `kimi-switch-lang` / `kimi-switch-last-update-check` / `kimi-switch-agent` / `kimi-switch-dashboard-range` (theme / language / last-update-check / last-selected agent / dashboard range) | — | +| `src/lib/models-dev.json` | models.dev `api.json` snapshot (bundled with the frontend) | — | + +Environment-variable overrides: + +- `KIMI_CODE_HOME` overrides the Kimi Code config dir (default `~/.kimi-code`) +- `PI_CODING_AGENT_DIR` overrides the Pi agent config dir (default `~/.pi/agent`) +- Kimi Switch's own data dir is fixed at `~/.kimi-switch` (**no env override yet**) + +## Getting Started + +### Prerequisites + +| Tool | Version | Purpose | +| --- | --- | --- | +| Node.js | ≥ 18 | Frontend build | +| Rust | Latest stable (edition 2021) | Tauri backend compilation | +| WebView2 Runtime | Bundled with Windows 10/11 | Tauri v2 runtime | +| Microsoft C++ Build Tools | Latest | Rust compile dependency | +| WiX Toolset 3.14 | `src-tauri/wix314-binaries/` | MSI bundling (auto-downloaded on first build) | + +### Install + +```bash +npm install +``` + +### Dev mode (hot reload) + +```bash +npm run tauri-dev +``` + +Starts both the Vite dev server (port 1420) and the Tauri window. Frontend edits hot-reload; Rust edits trigger a recompile. + +### Frontend-only dev (no Tauri window) + +```bash +npm run dev +``` + +Good for pure UI debugging. + +## Development Guide + +### Project structure + +``` +. +├── src/ # React frontend +│ ├── App.tsx # Root component routing provider list / edit / dashboard / sessions +│ ├── main.tsx # React entry + ErrorBoundary + I18nProvider +│ ├── components/ +│ │ ├── ProviderList.tsx # Provider list + switch / duplicate / test / edit / delete +│ │ ├── ProviderEdit.tsx # Edit provider + model mapping + raw JSON + capabilities +│ │ ├── AgentSettingsPanel.tsx # Kimi Code global settings (thinking / loop / permissions / hooks) +│ │ ├── SettingsModal.tsx # Settings modal (theme / language / version / update check) +│ │ ├── ProviderIcon.tsx # Provider brand icons (with initial-letter fallback) +│ │ ├── IconPicker.tsx # Icon picker (brands / inference groups) +│ │ ├── dashboard/ # Usage dashboard +│ │ │ ├── DashboardPage.tsx +│ │ │ ├── DailyBars.tsx +│ │ │ ├── DailyDetailModal.tsx +│ │ │ └── Heatmap.tsx +│ │ └── sessions/ # Session manager +│ │ └── SessionsPage.tsx +│ ├── hooks/ +│ │ ├── useConfig.ts # Config load/save +│ │ ├── useDashboard.ts # Dashboard data +│ │ ├── useSessions.ts # Session data +│ │ ├── useTheme.ts # Theme switch +│ │ └── useUpdateCheck.ts # Update check + download +│ ├── lib/ +│ │ ├── agent-settings.ts # AgentSettings parse/serialize +│ │ ├── model-defaults.ts # Default model context sizes +│ │ ├── models-dev.ts # models.dev snapshot lookup + capability mapping +│ │ ├── models-dev.json # Bundled snapshot +│ │ └── dashboard-format.ts # Dashboard formatting +│ ├── icons/ +│ │ ├── brands.ts # Brand icon entry +│ │ ├── inference.ts # Inference-service icons +│ │ └── extracted/ # Icon library adapted from cc-switch +│ │ ├── index.ts +│ │ └── metadata.ts +│ ├── types/ +│ │ ├── index.ts # Provider / Model / Config +│ │ ├── dashboard.ts +│ │ ├── sessions.ts +│ │ └── icon.ts +│ ├── i18n/ +│ │ ├── zh.ts # Chinese translations (source) +│ │ ├── en.ts # English translations +│ │ └── index.tsx # useTranslation hook + Provider +│ └── index.css # Tailwind entry +│ +├── src-tauri/ # Rust backend +│ ├── src/ +│ │ ├── lib.rs # Tauri Builder + tray + window events + invoke_handler +│ │ ├── main.rs # Binary entry +│ │ ├── commands.rs # ~14 Tauri commands +│ │ ├── db.rs # SQLite persistence +│ │ ├── kimi_code_io.rs # ~/.kimi-code/config.toml read/write +│ │ ├── pi_io.rs # ~/.pi/agent/*.json read/write (preserved) +│ │ ├── config_io.rs # File backup utilities +│ │ ├── models.rs # Config / Provider / Model data structures +│ │ ├── profile_manager.rs # Multi-profile management (stub) +│ │ ├── validators.rs # Config validation +│ │ └── dashboard.rs # Session / usage data aggregation +│ ├── capabilities/ # Tauri permission declarations +│ ├── icons/ # App icons (script-generated) +│ └── tauri.conf.json # Tauri config (window / bundle / CSP) +│ +├── scripts/ +│ ├── fetch-models-dev.mjs # Refresh models-dev.json snapshot +│ └── generate-icons.py # Generate all icon sizes from SVG +├── public/kimi.svg # App icon source (blue-purple gradient π) +└── docs/ + ├── screenshots/ # Screenshots referenced by the README + └── superpowers/ # Design specs & implementation plans +``` + +### Tauri commands (frontend ↔ backend) + +| Command | Description | +| --- | --- | +| `load_agent_config_command(agent)` | Load config: Kimi Code reads `config.toml` as authoritative + SQLite metadata; Pi reads SQLite first | +| `save_agent_config_command(agent, config)` | Save to SQLite; for Kimi Code also writes `config.toml` | +| `activate_agent_config_command(agent)` | Write to the agent's native config (Kimi Code writes all providers — `default_model` picks the active one; Pi writes only the active provider) | +| `open_agent_config_dir(agent)` | Open the agent's config dir in the system file manager | +| `get_app_version()` | Return the `Cargo.toml` version | +| `list_provider_models(provider)` | Fetch the model list from the provider API (async, paginated) | +| `test_connectivity(provider)` | GET `base_url` connectivity test, returns `{ ok, latency_ms, status_code, error }` | +| `get_app_setting(key)` | Read an app setting (theme / language / last-update-check) | +| `set_app_setting(key, value)` | Write an app setting | +| `check_for_update()` | Check GitHub releases; returns version + asset URL | +| `download_update(url, path)` | Stream-download the update; emits `download-progress` / `download-complete` events | +| `open_installer(path)` | Open the downloaded installer via the system shell | +| `dashboard::get_paths()` / `get_prices()` / `get_summary()` / `list_sessions()` / `archive_session()` / `unarchive_session()` / `delete_session()` / `delete_workspace()` / `get_session_preview()` | Dashboard & session commands | +| `debug_log(message)` | Forward frontend logs to stderr (dev use) | + +### Adding a new provider type + +1. Add a new variant to the `ProviderType` enum in `src-tauri/src/models.rs` +2. Add a default in `default_base_url()` +3. Add a dispatch arm in `commands.rs::list_provider_models` +4. Add a mapping in `kimi_code_io.rs::provider_type_for_kimi_type` +5. Add an option to the API-format dropdown in `src/components/ProviderEdit.tsx` +6. Add new i18n keys in `src/i18n/{zh,en}.ts` + +### Adding a new Tauri command + +1. Add a `#[tauri::command]` in `src-tauri/src/commands.rs` +2. Register it in `tauri::generate_handler![...]` in `src-tauri/src/lib.rs` +3. Call it from the frontend with `import { invoke } from "@tauri-apps/api/core"` +4. Add a permission in `src-tauri/capabilities/default.json` (if filesystem/network is needed) + +### Adding a new model capability + +1. Add a new key to `KNOWN_CAPABILITIES` in `src/components/ProviderEdit.tsx` +2. Add an i18n mapping in `CAPABILITY_LABELS` +3. Add translations in `src/i18n/{zh,en}.ts` +4. Add derivation in `capabilitiesFromRef` in `src/lib/models-dev.ts` (if it can be derived from models.dev) + +## Keyboard Shortcuts + +| Shortcut | Action | +| --- | --- | +| `Ctrl + S` | Save current changes to SQLite + `config.toml` (Kimi Code) | +| `Ctrl + R` | Reload config (prompts if unsaved) | +| `Ctrl + O` | Open the current agent's config dir | + +## Internationalization + +- Sources: `src/i18n/zh.ts` (source) + `src/i18n/en.ts` (target) +- When adding a key, **add it to `zh.ts` first** — the `Record` type in `en.ts` will flag missing entries at compile time +- `useTranslation` hook exposes `{ t, lang, setLang }` +- Runtime switch is provided by `SettingsModal`; persisted to frontend `localStorage` (`kimi-switch-lang`) + +## Testing + +### Rust unit tests + +```bash +cd src-tauri +cargo test +``` + +Currently covered: + +- `kimi_code_io::tests` — TOML import/export round-trips +- `pi_io::tests` — JSON round-trips, including advanced fields (headers / compat / cost / extra) +- `validators::tests` — Config validation +- `dashboard::tests` — Usage aggregation and timezone handling + +### Frontend + +No automated tests yet. Suggested manual checklist: + +- [ ] Default model restores correctly after switching providers +- [ ] Newly added providers auto-promote to the top of the list +- [ ] Duplicate provider generates non-conflicting keys +- [ ] Connectivity test bubble auto-dismisses after 6 seconds +- [ ] Close X hides to tray; minimize keeps taskbar button +- [ ] Theme switch (dark / light / follow-system) takes effect immediately +- [ ] Language switch updates UI text in place +- [ ] Update check → download → guided install +- [ ] `max_context_size` auto-fills on model fetch +- [ ] New default model takes effect after `/reload` + `/model` (or after `/exit` and restart) + +## Build & Release + +```bash +npm run tauri-build +``` + +Output: + +``` +src-tauri/target/release/bundle/msi/Kimi Switch__x64_en-US.msi +``` + +A Windows installer (MSI) with the WebView2 bootstrapper embedded for auto-download. `nsis` is disabled; only MSI is produced. + +### First build + +The first run downloads: + +- WiX Toolset 3.14 binaries → `src-tauri/wix314-binaries/` +- WebView2 bootstrapper → embedded into the MSI + +### Common build issues + +- **`os error 5`** (WiX light step): kill the process first with `taskkill //F //IM kimiswitch.exe`, then retry +- **prebuild times out pulling models.dev**: expected; the local snapshot keeps the build going + +## Release History + +### v0.5.1 (latest) + +- Window / tray: minimize keeps the taskbar button; close X hides to tray; tray left-click always shows + focuses +- Usage table: model column auto-width, long names no longer truncated +- Capability editor: only `thinking` exposed; other capabilities still auto-derived from models.dev +- Model mapping table: theme-aware row divider, no more harsh line in light mode + +### v0.5.0 + +- Iconified actions (lucide-react): activate / edit / duplicate / test / delete +- Duplicate provider (deep-copy a provider + all its models) +- Connectivity test (green / orange / red bubble + 6s auto-dismiss) +- Daily trend bars anchored to the panel bottom + +### v0.4.1 + +- Model discovery pagination (OpenAI / Anthropic / Google), fewer large-list limits hit + +### v0.4.0 + +- Polished icon system (library adapted from cc-switch) +- Settings modal (theme / language) +- Launch-time update check + +### v0.3.0 + +Ported from [kimicode-dashboard](https://github.com/JochenYang/kimicode-dashboard): + +- Dashboard: 8 KPIs, daily trend, full-year heatmap, paginated recent requests +- Session manager: per-workspace browsing, preview, archive, bulk delete +- Timezone fix: `today` / heatmap / `day_key` now use local calendar day +- Pi option hidden from the UI + +## FAQ + +**Q: Switching providers didn't take effect in Kimi Code?** +A: Two steps are required: +1. Run `/reload` inside the Kimi Code session so the CLI re-reads `~/.kimi-code/config.toml` (this refreshes the model **dropdown list**); +2. **Then run `/model` to pick the new default**, or simply `/exit` and restart the session. + +Running `/reload` alone **does not** apply the new `default_model` to the current session — this is a known Kimi Code behaviour, see [Known Limitations & Next Steps](#known-limitations--next-steps) below. The app surfaces both steps in its UI. + +**Q: Does switching overwrite other providers?** +A: No. Kimi Code's `config.toml` is always written with all providers, only `default_model` decides which one is active. This matches the CLI's native `/provider` behaviour. + +**Q: Where do new / activated providers go?** +A: They auto-promote to the top of the list; the UI reflects it immediately. + +**Q: Why does the capability editor only show "thinking"?** +A: Kimi Code's `capabilities` field can only be added to, not removed. models.dev already auto-derives the rest; exposing more manually would just invite mistakes. Edit `config.toml` directly when you need to set `always_thinking` or other special values. + +**Q: I edited the config but closed the window without saving?** +A: A native `beforeunload` prompt appears before closing, and the title bar shows a `*` prefix. + +**Q: How do I back up / migrate my config?** +A: For Kimi Code, `config.toml` itself is the authoritative full config — back it up directly. SQLite holds notes / official URLs / ordering, back it up too if you need that. Theme / language / last-update-check live in frontend `localStorage` (WebView2), not a standalone file, so they usually don't need separate handling on migration. + +**Q: Why can't Vertex AI fetch the model list?** +A: Vertex requires GCP project / location credentials. The current implementation leaves a TODO pending GCP SDK integration. + +**Q: macOS / Linux support?** +A: The code doesn't depend on Windows-only APIs, but `tauri.conf.json` only targets `msi` for bundling. In theory, changing `bundle.targets` to `["app", "dmg"]` etc. would enable cross-platform builds, but this is unverified. + +**Q: How do I change the theme / language?** +A: Top-right gear → Settings modal → Theme / Language. Saved to frontend `localStorage` (WebView2), persists across restarts. + +**Q: I closed the window — how do I get it back?** +A: The close X hides to the tray. Click the tray icon (menu bar / system tray) to bring it back; clicking the taskbar icon toggles minimize/restore normally. + +**Q: How is the update check triggered?** +A: It silently checks once on launch, then automatically every 8 hours (silent failure with no network, no error popup). You can also trigger it manually: Settings modal → Version → Update check. Downloads have a progress bar; once done, an "Open installer" button appears. + +## Known Limitations & Next Steps + +### `/reload` does not switch the active session's default model (Kimi Code upstream limitation) + +**Symptom**: After switching a provider in Kimi Switch, `default_model` at the top level of `config.toml` is correctly updated. Back in Kimi Code CLI you run `/reload`: the model **dropdown** now lists the new default, but the **current session still uses the old model** (status-bar model and the actual outgoing requests haven't changed). + +**Root cause** (verified against the Kimi Code source — **not** a Kimi Switch bug): + +- The `/reload` command (`apps/kimi-code/src/tui/commands/reload.ts`) refreshes `availableModels / availableProviders` but **never** re-applies `config.defaultModel` to the active session's agent. +- The session's current model (`agent.config.modelAlias`) comes from `options.model ?? config.defaultModel` at session-create time (`packages/agent-core/src/rpc/core-impl.ts:438-440`) and is persisted to the session log via `records.logRecord`. `Agent.resume()` then calls `records.replay()`, which **replays those records** — so the model snaps back to "what was last picked", not to `config.defaultModel`. +- The unit test (`apps/kimi-code/test/tui/commands/reload.test.ts:87-89`) only asserts "the model list refreshed"; there is **no** assertion that "the active session switched to the new default" — because the implementation never does that step. +- A repo-wide search for `FOLLOW_DEFAULT / reloadDefault / KIMI_CODE_RELOAD` yields **zero** hits, so Kimi Code has **no** "follow default on reload" toggle today. + +**Workaround (works today)**: + +1. After `/reload`, run `/model` and pick the new default manually; or +2. `/exit` and restart the session (the `createSession` path re-applies `config.defaultModel` to the fresh session). + +**Suggested upstream fix for Kimi Code**: + +- File: `apps/kimi-code/src/tui/commands/reload.ts`, in `handleReloadCommand`. +- Spot: right after `applyRuntimeConfig(host, config)`, add a sync of `config.defaultModel` to the active session's agent, e.g.: + ```ts + const newDefault = config.defaultModel; + const current = /* host.session's current agent modelAlias */; + if (newDefault && newDefault !== current) { + await host.session.mainAgent.config.update({ modelAlias: newDefault }); + } + ``` +- Matching test: add an assertion in `reload.test.ts` that "after reload, the session's active model == new `defaultModel`" to guard against regressions. +- Optional enhancement: expose a session-level "follow default on reload" toggle, or auto-fall-back to `default_model` when the session's previous alias has been deleted. + +> Note: this suggestion has **not** been filed upstream yet; it's recorded here for follow-up. Kimi Switch can only guarantee `config.toml` is written correctly — it cannot work around Kimi Code's own `/reload` semantics. + +### Other next-step suggestions (by priority) + +- **P1 — Model alias convention**: early bare-name or `-1/-2` suffixed aliases (e.g. `kimi-k3`, `glm-5-2-1`) have been bulk-renamed to the `provider/model` form; when adding a new provider, **force** this convention to prevent re-introducing suffixed fallbacks. Add a save-time lint. +- **P1 — Multi-dimensional usage trends**: the usage trend already supports two tabs ("model trend" / "provider×model trend"); a future third dimension (per-workspace, or switch the Y axis between tokens and cost) is worth considering. +- **P2 — Periodic update check**: currently launch + every 8h; consider making the cadence configurable (set period / disable in the settings modal). +- **P2 — Cross-platform**: only MSI is produced today, but the code has no Windows-only dependencies; once Tauri v2 macOS/Linux bundling is configured, it can be verified. +- **P3 — Stronger config validation**: `validators.rs` is fairly minimal today; worth adding: `base_url` validity, `env` vs `api_key` mutual-exclusivity, `oauth` block completeness. + +## Security Notes + +- API keys are stored in plaintext in local SQLite and agent native configs — **do not store them on shared computers** +- Do not commit `kimi-switch.db`, `config.toml`, or `models.json` to Git +- The app CSP is tightened (`default-src 'self'`), but WebView2 may still cache form content — log out when finished on public machines + +--- + +## Credits + +The usage dashboard and session manager are ported from [kimicode-dashboard](https://github.com/JochenYang/kimicode-dashboard) (MIT License, © JochenYang). The Rust backend (`src-tauri/src/dashboard.rs`), dashboard UI (`src/components/dashboard/`), and sessions page (`src/components/sessions/`) in this project are derived from that work. Many thanks to the original author. + +The provider brand icon library (`src/icons/extracted/`) and the icon picker (`src/components/IconPicker.tsx`) are adapted from [cc-switch](https://github.com/farion1231/cc-switch) (MIT License, © Jason Young). Many thanks to the original author. + +The provider presets structure (`src/config/providerPresets.ts`) and the balance/plan usage query implementation (`src-tauri/src/services/`) are likewise adapted from [cc-switch](https://github.com/farion1231/cc-switch) (MIT License, © Jason Young). + +--- + +License: MIT, see [LICENSE](./LICENSE). Copyright (c) 2026 CodingPlan.site diff --git a/docs/PROPOSAL-presets-and-usage.md b/docs/PROPOSAL-presets-and-usage.md new file mode 100644 index 0000000..4f62fc2 --- /dev/null +++ b/docs/PROPOSAL-presets-and-usage.md @@ -0,0 +1,625 @@ +# 提案:预设供应商 + 供应商账单查询 + +> **状态**:v0.4-draft(v0.3-draft 已实施;P0 全部落地,新增 v0.4 修订) +> **作者**:Kimi Switch 内部 +> **目标版本**:0.6.0 +> **参考**:cc-switch(MIT,© Jason Young)— 仅借鉴字段结构与 Rust 用量查询层模式 +> **Kimi Code 官方文档**:[providers 配置](https://www.kimi.com/code/docs/kimi-code-cli/configuration/providers.html)、[配置文件](https://www.kimi.com/code/docs/kimi-code-cli/configuration/config-files.html) + +--- + +## 一、背景与目标 + +当前 Kimi Switch 已有"添加供应商"入口(`src/App.tsx:141 handleAddProvider`)直接凭空造一个 `provider-N`,用户需要手填 base_url、provider_type、模型映射等十几个字段。新用户面对一份空白表单门槛很高。 + +同时,用量仪表盘(`src/components/dashboard/`)展示的是**本地会话日志**聚合出来的 token 消耗,与"供应商账户里还剩多少钱/套餐还剩多少"完全无关——后者才能告诉用户"今天是不是该充值了"。 + +**目标**: + +1. **预设供应商**:用户点"添加"时弹出预设选择面板,选中后表单字段自动填好(保留任意编辑权);支持至少 12 条主流国内/海外供应商。 +2. **供应商账单查询**:在 `ProviderList` 卡片底部展示余额/套餐剩余,调用供应商鉴权 API 实时拉取。 + +**非目标**: + +- 不做 OAuth 流程(Claude/Codex 官方订阅)—— 我们不接管 CLI 登录态。 +- 不做"用户自定义 JS 脚本"查询(rquickjs 依赖过重)。 +- 不做用量费用看板(已有本地仪表盘)。 + +--- + +## 二、参考:cc-switch 关键事实 + +### 2.1 预设供应商 + +- **位置**:纯前端 TS 数组,`src/config/*ProviderPresets.ts`,按目标 CLI 工具拆 8+1 个文件,每文件 22–73 条。 +- **数据契约**(`claudeProviderPresets.ts:25-74`): + - `name / nameKey(i18n) / websiteUrl / apiKeyUrl` + - `settingsConfig`(真正写进配置的对象,**结构因工具而异**:Claude 用 `ANTHROPIC_*` env、Codex 用 auth.json + TOML) + - `category`: `official | cn_official | third_party | aggregator` + - `isOfficial / isPartner / primePartner` + - `apiKeyField`(Claude 特有)、`endpointCandidates[]`、modelsUrl + - `theme / icon / iconColor / apiFormat` +- **触发**:`ProviderForm` 表单顶部内嵌 `ProviderPresetSelector`(grid 按钮 + 搜索 + 排序);选中即 `form.reset` 灌字段。 +- **模型清单来源**:硬编码写进 `settingsConfig.env` 或 `modelCatalog[]`;**不**走 models.dev,**不**在预设里调 API。动态拉模型是另一个独立按钮。 +- **许可证**:MIT,可直接借鉴字段结构与预设数据。 + +### 2.2 账单/用量查询 + +cc-switch 在 Rust 端实现了 6 套并行的查询层(详见 `src-tauri/src/services/`),与本项目相关的有 2 套: + +| 机制 | 文件 | 覆盖 | 关键端点 | +|---|---|---|---| +| **A. 余额查询** | `balance.rs` | DeepSeek / StepFun / SiliconFlow / OpenRouter / Novita | `GET {base_url}/user/balance` 等 | +| **B. Token Plan 套餐** | `coding_plan.rs` | **Kimi For Coding** / 智谱 GLM / MiniMax / 火山 / ZenMux | `GET https://api.kimi.com/coding/v1/usages` | + +**统一返回契约**(`balance.rs:1-10` 注释): + +```rust +struct UsageResult { + success: bool, + data: Option>, + error: Option, +} +struct UsageData { + plan_name: Option, + remaining: Option, + total: Option, + used: Option, + unit: Option, + is_valid: Option, + resets_at: Option, +} +``` + +**错误通道语义**(这套设计很成熟,建议照搬): + +- `Err(_)` = 瞬时失败(网络/超时/读体中断)→ 前端 retry + keep-last-good。 +- `Ok(success:false)` = 确定性失败(空 key / 401 / 非 2xx / JSON 解析失败)→ 直接透出错误文案。 + +**鉴权**:统一 `Authorization: Bearer `。 + +**路由**:`detect_provider(base_url)` 按子串匹配 → 调对应 `query_xxx`。 + +--- + +## 三、KimiSwitch 落点 + +| 现有结构 | 落点 | +|---|---| +| `src/App.tsx:141 handleAddProvider`(直接造空 `provider-N`)| 改为先打开 `PresetPickerModal` | +| `src/components/ProviderEdit.tsx` basic tab | 顶部加"切换预设"下拉(v1 不做) | +| `src-tauri/src/models.rs Provider` | 不动;预设转 Provider 由前端完成 | +| `src-tauri/src/commands.rs` | 新增 `query_provider_usage(base_url, api_key, usage_kind)` | +| `src-tauri/src/`(无 `services/`)| 新建 `services/{mod.rs, usage_types.rs, balance.rs, coding_plan.rs}` | +| `src/components/ProviderList.tsx` 卡片 | 卡片底部新增 `` | +| `src/i18n/{zh,en}.ts` | 加 i18n key(preset 名 / 账单相关) | +| `src/lib/models-dev.ts` | 复用:补全预设 model 的 `maxContextSize` / `capabilities` | + +**已有依赖**(已满足): + +- `Cargo.toml`: `reqwest = { version = "0.12", features = ["json","rustls-tls","stream"] }` ✅ +- `Cargo.toml`: `chrono = { version = "0.4", features = ["serde"] }` ✅ + +**私有字段存储约定**(**重要变更:v0.3 修订**): + +早前提议把 `usageKinds` 写进 `provider.raw_other["kimi-switch.usageKinds"]` 通过 `config.toml` 透传。**此方案否决**——`kimi-switch.` 前缀不是 Kimi Code 注册的 namespace,"安全"只是 Zod 非 strict + raw 透传的实现现状,无版本兼容承诺。 + +**v0.3 改为:** + +- `usageKinds` 存进 **SQLite** 的 `settings` 表(已有 per-agent 设置表,key 形式 `usage_kinds:`,值为 JSON 数组字符串,如 `["balance:deepseek"]` 或 `["plan:kimi_coding","balance:custom"]`) +- `load_agent_config_command` 在返回 config 时**自动合并** SQLite settings 中的 usageKinds 到每个 provider(前端消费时是无感的) +- Rust 端导出 `config.toml` 时**完全不写** `usageKinds` 字段 +- 卸载 / 退出登录 / 备份 `config.toml` 都不影响 `usageKinds`(独立存储) + +**优势**: + +1. 不污染用户的 Kimi Code 配置(终审 A8 解决) +2. 用户改 `provider_type` / `base_url` 后,Rust 端 `detect_provider(base_url)` 自动重新决定 `usageKinds`(B-D1 解决) +3. 旧用户升级 0.6.0 时,所有匹配 `detect_provider` host 列表的 provider **自动获得** `usageKinds`(B-D2 解决) +4. 数组形式让同一 provider 同时支持套餐 + 余额查询(如 SiliconFlow 未来加套餐) + +--- + +## 四、方案 1:预设供应商 + +### 4.1 数据模型 + +新建 `src/config/providerPresets.ts`: + +```ts +export interface ProviderPreset { + /** 唯一 key,作为默认 Provider name 使用,如 "deepseek" */ + id: string; + /** 显示名(中文/英文) */ + name: string; + /** i18n key,可选;存在时优先用 t(nameKey) */ + nameKey?: string; + /** 官网/拿 key 的链接 */ + websiteUrl?: string; + apiKeyUrl?: string; + /** 分类:排序 & 标签 */ + category: "official" | "cn_official" | "third_party" | "aggregator" | "custom"; + /** 真正写进 Provider 的字段 */ + providerType: ProviderType; + /** 预设 base_url;`null` 表示无默认值(如 Anthropic、CodingPlan.site)。 + * 当选中的 provider.type 对应的 `defaultBaseUrl()` 返回非空时, + * PresetPicker 会**用预设值覆盖它**,保存后以 `provider.base_url` 为唯一真相。 */ + baseUrl: string | null; + /** 复用现有 IconPicker 命名(无品牌图标时按 base_url 走首字母兜底) */ + icon?: string; + iconColor?: string; + /** 预填的模型映射(alias → model id)。 + * 数组第一个 ⇒ 设 default_model。 + * 数组为空时,default_model 留空,由用户通过「拉取模型」补齐。 + * + * **alias 强制规范**:`provider/${modelId}` 形式 —— 例如 `deepseek/deepseek-chat`。 + * 不能用裸 alias(如 `chat`),否则会破坏 `handleDuplicateProvider` 的 + * `alias.slice(name.length)` 推导:若 provider=`copy`,会得到空串, + * 复制时所有模型都写到 `copy` 上,后者覆盖前者。 */ + models: Array<{ + alias: string; + model: string; + /** 可选:覆写显示名;缺省走 models.dev 推导 */ + displayName?: string; + /** 可选:覆写 context;缺省走 models.dev [API→models.dev→正则] 三级 */ + maxContextSize?: number; + /** 默认 ["thinking"] */ + capabilities?: string[]; + }>; + /** 关联方案 2:账单查询类型;缺省时不查。 + * **v0.3 改为数组**:同一个供应商可能同时支持套餐 + 余额(如 SiliconFlow + * 既有平台余额又有套餐),数组形式让两端都查、UI 都展示。 + * 注意:`plan:volcengine` **不在 v1 union** —— Volcengine 套餐需独立 AK/SK + * (不是推理 api_key),需要额外的 `access_key_id / secret_access_key` 参数, + * v1 不支持,留待 P2。 */ + usageKinds?: ReadonlyArray< + | "balance:deepseek" | "balance:siliconflow" | "balance:openrouter" + | "balance:stepfun" | "balance:novita" + | "plan:kimi_coding" | "plan:zhipu" | "plan:minimax" + >; +} +export const providerPresets: ProviderPreset[] = [ /* … */ ]; +``` + +**`presetToProviderAndModels()` 显式转换契约**(v0.3 重要补充): + +```ts +export function presetToProviderAndModels(preset: ProviderPreset, options: { + existingProviderNames: Set; + existingModelAliases: Set; +}): { + provider: Provider; + models: Model[]; + defaultModel: string; // 用于写入 config.default_model + usageKinds: ReadonlyArray | undefined; // 用于写入 SQLite settings +} { + // Provider.name 冲突 → 追加 -2 / -3 + let name = preset.id; + let n = 2; + while (options.existingProviderNames.has(name)) name = `${preset.id}-${n++}`; + + // 模型 alias 冲突 → 追加 -2 / -3 + const models: Model[] = preset.models.map((m, i) => { + let alias = `${name}/${m.model}`; // 强制规范 + let k = 2; + while (options.existingModelAliases.has(alias)) alias = `${name}/${m.model}-${k++}`; + + // max_context_size 4 级优先级 + const ref = modelsDevRef(m.model); + const maxContextSize = + m.maxContextSize + ?? ref?.maxContextSize + ?? parseContextFromName(m.model) + ?? DEFAULT_MAX_CONTEXT_SIZE; // 256000 + + return { + alias, + provider: name, + model: m.model, + max_context_size: maxContextSize, + display_name: m.displayName ?? ref?.displayName ?? alias, + capabilities: m.capabilities ?? ref?.capabilities ?? ["thinking"], + supports_1m: maxContextSize >= 1_000_000, + raw_other: {}, + }; + }); + + const provider: Provider = { + name, + provider_type: preset.providerType, + base_url: preset.baseUrl, + api_key: null, // 用户补 + env: {}, + note: null, + official_url: preset.websiteUrl ?? null, + managed: false, + enabled: true, + icon: preset.icon ?? null, + icon_color: preset.iconColor ?? null, + raw_other: {}, + }; + + return { + provider, + models, + defaultModel: models[0]?.alias ?? "", + usageKinds: preset.usageKinds, + }; +} +``` + +**字段映射表**(明确每条字段从哪来): + +| Preset 字段 | Provider/Model 字段 | 备注 | +|---|---|---| +| `providerType` | `provider.provider_type` | 直透 | +| `baseUrl` | `provider.base_url` | `null` → 留空 | +| `websiteUrl` | `provider.official_url` | | +| `icon` | `provider.icon` | `null` → 走首字母兜底 | +| `iconColor` | `provider.icon_color` | | +| `models[].alias` | `models[].alias` | **强制 `${uniqueProviderName}/${modelId}`** | +| `models[].model` | `models[].model` | 直透 | +| `models[].displayName` | `models[].display_name` | 缺省走 models.dev | +| `models[].maxContextSize` | `models[].max_context_size` | 优先级链 | +| `models[].capabilities` | `models[].capabilities` | 缺省 `["thinking"]` | +| `id` | `provider.name` | 冲突 → `-2` | +| `usageKinds` | SQLite `settings` 表 | **不**写 `config.toml`;数组形式支持同一供应商多种查询 | + +### 4.2 v1 预设清单(15 条) + +| id | 供应商 | category | provider_type | base_url | icon | iconColor | usageKinds | 备注 | +|---|---|---|---|---|---|---|---|---| +| `anthropic` | Anthropic 官方 | official | anthropic | `null` | `anthropic` | — | — | 无默认 base_url;Kimi Code 自动走 `api.anthropic.com` | +| `kimi-coding` | Kimi Code 托管服务(会员订阅)| official | **kimi** | `https://api.kimi.com/coding/v1` | `kimi` | — | `[plan:kimi_coding]` | Kimi Code 托管服务走 `kimi` 类型(OpenAI 兼容 + Kimi identity headers + 视频上传)。Base URL 同时兼容 Anthropic 协议 `https://api.kimi.com/coding/`,但 preset 用 OpenAI 兼容路径 | +| `moonshot` | Moonshot Platform API(按量付费)| cn_official | **kimi** | `https://api.moonshot.ai/v1` | `kimi` | — | — | Moonshot 平台 API 密钥用户;官方文档明确 `kimi` 类型默认 base_url 即此(与 `.cn` 互为别名) | +| `deepseek` | DeepSeek | cn_official | openai | `https://api.deepseek.com/v1` | `deepseek` | — | `[balance:deepseek]` | — | +| `zhipu` | 智谱 GLM | cn_official | openai | `https://open.bigmodel.cn/api/paas/v4` | `zhipu` | — | `[plan:zhipu]` | — | +| `zai` | z.ai(智谱海外)| third_party | openai | `https://api.z.ai/api/paas/v4` | `zhipu` | — | `[plan:zhipu]` | — | +| `bailian` | 阿里百炼 | cn_official | openai | `https://dashscope.aliyuncs.com/compatible-mode/v1` | `bailian` | — | — | — | +| `minimax` | MiniMax | cn_official | openai | `https://api.minimaxi.com/v1` | `minimax` | — | `[plan:minimax]` | — | +| `stepfun` | StepFun(阶跃星辰)| cn_official | openai | `https://api.stepfun.com/v1` | `stepfun` | — | `[balance:stepfun]` | — | +| `siliconflow` | 硅基流动 | cn_official | openai | `https://api.siliconflow.cn/v1` | `siliconflow` | 显式补色(默认灰色)| `[balance:siliconflow]` | `siliconflow` 在 `src/icons/extracted/index.ts:93` 有 SVG,但 `metadata.ts` 没有;需显式 `iconColor` | +| `novita` | Novita AI | third_party | openai | `https://api.novita.ai/v3` | `novita` | — | `[balance:novita]` | 注意 `/v3`(非 `/v1`) | +| `openrouter` | OpenRouter | third_party | openai | `https://openrouter.ai/api/v1` | `openrouter` | — | `[balance:openrouter]` | — | +| `openai` | OpenAI 官方 | official | openai | `https://api.openai.com/v1` | `openai` | — | — | — | +| `google-genai` | Google AI Studio | official | google-genai | `https://generativelanguage.googleapis.com` | `google` | — | — | — | +| `volcengine` | 火山方舟(仅推理)| cn_official | openai | `https://ark.cn-beijing.volces.com/api/v3` | `huoshan` | — | — | **v1 不支持套餐查询**(需 AK/SK),仅作推理 fallback | + +**`codingplan`(自定义中转)v1 不做 preset**——价值低(无 base_url、无 usageKinds),与预设"一键填表"目标冲突。改在 `PresetPickerModal` 底部保留独立的"**+ 自定义配置**"按钮(来自空表单),与 cc-switch `ProviderPresetSelector.tsx:392-404` 一致。 + +**预估 icon 字段值校核**:上面表的 `icon` 值均来自 `src/icons/extracted/index.ts` 真实存在的 key;不能使用 `brands.ts` 推断 key 作显式 icon(两者命名空间不同)。P0 实现时若发现某个 key 不存在,需在 `src/icons/extracted/index.ts` 补 entry。 + +**模型清单里的 `maxContextSize` / `capabilities` 优先级**(与拉取模型同一体系): + +1. 预设内置值(`ProviderPreset.models[].maxContextSize / capabilities / displayName` — 若有) +2. `src/lib/models-dev.ts` 快照查找(`getModelRef`) +3. 正则兜底(`src/lib/model-defaults.ts`) +4. 全部 miss → **`DEFAULT_MAX_CONTEXT_SIZE`**(`src/lib/model-defaults.ts:1,83-89` 实际为 **256000**,不是 128000) + +> v0.3 修正:早期文档误写 128000;统一用 `DEFAULT_MAX_CONTEXT_SIZE` 常量,避免双源真相。 + +**预设里绝大多数模型只需放 `alias` + `model id`**;仅对 models-dev 快照无覆盖的新发模型(如国产首发)才填覆写字段。 + +### 4.3 UI 流程 + +**入口 A(v1 必做)`PresetPickerModal`**: + +``` +┌────────────────────────────────────────────────┐ +│ 选择预设供应商 [X] │ +├────────────────────────────────────────────────┤ +│ 🔍[搜索] [排序:原始│A-Z] │ +├────────────────────────────────────────────────┤ +│ [K] Kimi Coding [官方] │ +│ [A] Anthropic [官方] │ +│ [D] DeepSeek [国产] │ +│ [Z] 智谱 GLM [国产] │ +│ …(grid 150px×n) │ +│ [+自定义配置] │ +├────────────────────────────────────────────────┤ +│ 预设只是一键填表,后续可继续修改所有字段。 │ +└────────────────────────────────────────────────┘ +``` + +- 触发:① "添加"按钮 ② 顶部"+ 添加供应商" +- 选中预设后: + 1. 用预设 `id` 作为默认 `Provider.name`(冲突时尾部追加 `-2`、`-3`…) + 2. 把 `models[]` 转成 `Model` 加进 `config.models`,**每个 alias 逐一检测冲突**:alias 已存在 → 尾部追加 `-2` / `-3`;**第一个 model** 设为 `default_model`(经过去重后的 alias) + 3. 写入 `provider.raw_other["kimi-switch.usageKinds"] = usageKinds`(沿用 raw_other 私有字段约定) + 4. 跳到 `ProviderEdit` 让用户填 `api_key`(其余字段已预填) +- 分类徽章:官方 = 蓝、国产 = 绿、第三方 = 灰、聚合 = 紫 +- 网格自适应:`repeat(auto-fill, minmax(140px, 1fr))`,参考 cc-switch `ProviderPresetSelector.tsx:392` + +**入口 B(v2,可选)`ProviderEdit` 顶部"切换预设"下拉**:对已存在但想换预设的供应商也能用。 + +### 4.4 持久化约定 + +- **name 由预设 id 派生**,用户可后续在表单里改名(不要锁)。 +- **`usageKinds` 存进 SQLite settings 表**(key: `usage_kinds:`,值为 JSON 数组),不写进 `config.toml`。详见 §三"私有字段存储约定"。 +- **不使用** `raw_other` 存 usageKinds(v0.3 修订:避免污染 Kimi Code 配置 + 支持 Rust 端自动 host detect)。 + +--- + +## 五、方案 2:供应商账单查询 + +### 5.1 Rust 端 + +``` +src-tauri/src/ +├── services/ +│ ├── mod.rs // pub use + 统一入口 +│ ├── usage_types.rs // UsageResult / UsageData +│ ├── balance.rs // 余额类(5 家) +│ └── coding_plan.rs // 套餐类(5 家) +└── commands.rs // +#[tauri::command] query_provider_usage +``` + +**usage_types.rs**(**注意必须加 camelCase** —— 缺它前端 `resetsAt/planName/isValid` 全部错位): + +```rust +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct UsageData { + pub plan_name: Option, + pub remaining: Option, + pub total: Option, + pub used: Option, + pub unit: Option, + pub is_valid: Option, + pub resets_at: Option, +} +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct UsageResult { + pub success: bool, + pub data: Option>, + pub error: Option, +} +``` + +> **与 cc-switch 真实结构的差异**(重要):cc-switch 的 `UsageData` 在 `provider.rs:282-314` 还含 `extra: Option` / `invalid_message: Option`,**没有** `resets_at`(该字段在 `SubscriptionQuota.tiers[].resets_at`)。本方案**不"照抄"**,而是把套餐的 `tiers` 展平成数组 + 每项带 `resets_at` 字段,统一前端消费面。`SubscriptionQuota → UsageData[]` 的转换规则实现时需明确(每个 tier 一条 `UsageData`,`plan_name = tier.name`,`used/total/remaining/unit` 视情况映射)。 + +**balance.rs / coding_plan.rs**:直接 port cc-switch 实现的 5 家 + 5 家(~670 行 + ~2200 行)。重点实现: + +- `detect_provider(base_url) -> Option<...>`:按子串匹配 +- `query_xxx(api_key) -> Result`:分别处理 401、读体失败、解析失败 +- **读体失败和解析失败要区分**:先 `bytes().await` 拿到完整字节再 `serde_json::from_slice`(见 balance.rs:99-108 的注释,reqwest `.json()` 把读体错也包成 decode,会丢信息) + +**command.rs 新增**(**v0.3 修订 + v0.4 落实**:传 `provider_name` 让 Rust 端从 config 加载 key 与 usageKinds,避免 IPC 序列化 key): + +```rust +#[tauri::command] +pub async fn query_provider_usage( + agent: Agent, // v0.4 落实:项目 config 按 agent 隔离,必须传 + provider_name: String, + force_refresh: Option, // true = 跳过 5min 缓存 +) -> Result { + // 1. 从 config / SQLite 加载该 provider + // 2. 如果 api_key 为空 → 自动 fallback 到 provider.env 里的 + // expected_api_key_key(provider_type) 对应 key(v0.4 落实) + // 3. 读取 usageKinds: 优先 SQLite 显式设置(JSON 数组)→ fallback detect_provider(base_url) → success:false "unknown provider" + // 4. 对每个 kind 路由到对应 query_xxx,合并所有结果到一个 UsageData[] + // 5. 返回 UsageResult(data 含全部 kind 的条目) +} +``` + +**v0.4 重要**:Rust 端除 `provider.api_key` 外,**会兜底读取 `provider.env` 里的 `expected_api_key_key(provider_type)`**(如 Kimi 平台期望 `KIMI_API_KEY`)。这只读 env 用于实际查询,**不**写回 config.toml,给只配 env 不配 api_key 的用户兜底。 + +**重要**:前端**不**传 `api_key` / `usage_kind` / `base_url`。Rust 端统一从配置加载,杜绝: +- API key 经 IPC 序列化(终审 D4) +- 前端绕过 host 校验乱发请求(终审 D1) +- Rust detect 与前端规则矛盾(终审 D2) + +**Tauri 配置文件注册**(**v0.3 修订**:Rust reqwest 不走 Tauri HTTP plugin,不需 capability): + +1. `commands.rs` 加 `#[tauri::command]` ✅ +2. `lib.rs` 的 `tauri::generate_handler![…]` 追加 `query_provider_usage` +3. `capabilities/default.json` **无需改动**(现有 `test_connectivity` 同样用 Rust reqwest,不需 HTTP scope) + +**Tauri config**:`reqwest::get` 是 Rust 端发出,**不**走 WebView 网络栈,**不**需要改 CSP。 + +### 5.2 前端 + +**ProviderList 卡片底部的 ``**: + +``` +┌────────────────────────────────────────┐ +│ Kimi For Coding [使用中] │ +│ 默认: kimi-k2.7-code 3 models │ +├────────────────────────────────────────┤ +│ ⚡ 35% 已使用 · 5h 后重置 [刷新] │ ← 套餐类(green/orange/red) +└────────────────────────────────────────┘ + +┌────────────────────────────────────────┐ +│ DeepSeek [使用中] │ +│ 默认: deepseek-chat 2 models │ +├────────────────────────────────────────┤ +│ 💰 余额 ¥12.34 [刷新] │ ← 余额类 +└────────────────────────────────────────┘ +``` + +- 配色:<70% 绿 / 70-89% 橙 / ≥90% 红(对齐 cc-switch) +- **多 kind 渲染**:同一 provider 的 `usageKinds` 数组可能含多种(如 `[plan:kimi_coding, balance:custom]`);`UsageData[]` 每条独立渲染为一行,余额类显金额、套餐类显百分比+倒计时 +- 倒计时:前端 JS 算 `new Date(resetsAt) - Date.now()`,按区间显示"5h 后重置 / 3d 后重置"(绝对时间,Rust 端已转 ISO 8601,不依赖时区) +- 缓存:**5min stale TTL**(`force_refresh` 跳过)+ Manual 刷新(**v0.3 修订**:与 cc-switch `queries.ts:245-277` 对齐)。进入 ProviderList 时对有 usageKinds 的供应商并发查一次,**最多同时 3 个请求**(`Promise.allSettled` + 简易信号量),单请求超时 8 秒 +- 错误:网络错"网络异常"、401"API Key 无效"、其他"查询失败" —— 不阻塞主界面 +- 没 `usageKinds` 字段(undefined 或空数组)→ **完全不显示 footer,不发起任何请求** + +**状态机**(每个 provider 独立维护): + +| 当前状态 | 触发 | 行为 | +|---|---|---| +| `idle` | 首次进入 ProviderList | → `loading`(并发 ≤3) | +| `loading` | 响应到达 | `ok` → `success`;`err` → `error` | +| `success` | 用户点「刷新」 | → `loading`,保留上一次 `data` 做 ghost 展示 | +| `error` | 用户点「重试」 | → `loading` | +| `success`/`error` | 缓存超 30s,重新进入列表 | 自动 → `loading` | +| 任何 | 用户清空 `api_key` | → `idle`(不发起请求,见 §5.1 命令层检查) | + +**渲染**: + +- `loading`:骨架屏或上次数据的半透明 ghost +- `success`:余额/百分比 + 配色 + 重置倒计时 +- `error`:红色错误提示 + 「重试」按钮 +- `idle`:无(不渲染 UsageFooter) + +**触发与权限**(**v0.3 修订**): + +- 启动时**不**预查 +- 进入 ProviderList 视图时并发查 1 次(≤3 并发,8s 超时) +- 用户点"刷新"按钮才再次查(5min stale TTL) +- 全局开关:设置面板加"启动账单查询"开关,关闭后 Rust 端拒绝查询(默认开启) +- **前端不做 usageKinds 决策**:单纯 `invoke("query_provider_usage", { provider_name: "deepseek" })`,Rust 端返回 `success: false` 时客户端仅展示错误,不做 host 校验 + +### 5.3 与现有"用量仪表盘"的关系 + +- **现有仪表盘**:本地 SQLite 聚合的 token 计数 + 费用估算(基于 `models.dev` 价格) +- **新增账单查询**:供应商侧的余额/套餐 +- **不重复**:仪表盘 chip 区域不显示余额,余额只在 ProviderList 卡片底部 +- **联动**:可选地(v2)在仪表盘 KPI 加一个"供应商侧配额"卡,但 v1 不做 + +--- + +## 六、里程碑 + +| 阶段 | 内容 | 优先级 | +|---|---|---| +| **P0** | 方案 1:15 条预设 + `PresetPickerModal` + App 入口接入 | P0 | +| **P0** | 方案 2 骨架:`services/{usage_types,mod}.rs` + `query_provider_usage` 命令 + `UsageResult` + **camelCase 序列化** | P0 | +| **P0** | `query_provider_usage` 两层注册(commands.rs + lib.rs;**无 capabilities 变更**) + Rust 端 mock 测试 | P0 | +| **P0** | SQLite 改造:`usage_kinds:` 存 settings 表(JSON 数组);`load_agent_config_command` 合并回 config;export 时不写 usageKinds | P0 | +| **P0** | `detect_provider(base_url)` 启发式:迁移期旧用户自动获得 usageKinds | P0 | +| **P0** | 方案 2 前端:`` + 卡片接入 + 错误处理 + 配色 + 状态机 + 5min stale TTL | P0 | +| **P0** | **套餐类 v1:Kimi For Coding(`api.kimi.com/coding/v1/usages`)**(项目主题,优先) | P0 | +| **P0** | 余额类 v1:DeepSeek / SiliconFlow / OpenRouter(3 家) | P0 | +| **P0** | 前端手工验证 checklist(见 §十一 #20) | P0 | +| **P1** | 套餐类补全:智谱 GLM / MiniMax | P1 | +| **P1** | 余额类补全:StepFun / Novita | P1 | +| **P2** | `ProviderEdit` 顶部"切换预设"下拉(入口 B) | P2 | +| **P2** | 设置面板"启动账单查询"开关 | P2 | +| **P2** | 倒计时 i18n 友好格式化("5小时后" / "in 5h") | P2 | +| **P2** | Volcengine 套餐查询(独立 AK/SK 支持 + UI) | P2 | +| **P3** | 自定义 JS 脚本兜底(usage_script.rs + rquickjs) | P3 | +| **P3** | 仪表盘 KPI 加"供应商侧配额"卡 | P3 | + +--- + +## 七、许可证与引用 + +cc-switch 是 MIT(`D:/AIGC/cc-switch/LICENSE`),Rust 实现(`balance.rs` / `coding_plan.rs`)可直接移植;预设数据(base_url、模型 id 等公开信息)不构成版权客体。 + +**文件头添加**: + +```rust +// Adapted from cc-switch (MIT, © Jason Young) +// https://github.com/farion1231/cc-switch +``` + +**README 致谢段补一条**: + +> 供应商预设结构与余额/套餐查询实现参考自 [cc-switch](https://github.com/farion1231/cc-switch)(MIT,© Jason Young)。 + +**配置文件同步**:preset 名 i18n key 同样放 `src/i18n/{zh,en}.ts`。 + +--- + +## 八、风险与待确认 + +| 风险 | 缓解措施 | 状态 | +|---|---|---| +| 预设的 `id` 与用户已存在的 `provider.name` 冲突 | `presetToProviderAndModels()` 内 `while` 循环追加 `-2` / `-3` | ✅ | +| 模型 alias 冲突 | 强制 alias = `${name}/${modelId}`,冲突追加 `-2` / `-3` | ✅ | +| 裸 alias 破坏 `handleDuplicateProvider` | **强制规范**(§4.1 转换契约);`src/App.tsx:271` `alias.slice` 改造为 `startsWith` 显式判断 + 完整 re-prefix fallback(v0.4 落实) | ✅ | +| `usageKinds` 漂移(TS 端枚举与 Rust 端 enum 各自维护) | TS 端 enum + Rust 端 enum 各自声明;TS 端在 dev 模式加载 `providerPresets.ts` 时对每个 preset 的 usageKinds 做运行时断言(v0.4 新增 `SUPPORTED_USAGE_KINDS` Set + `import.meta.env.DEV` guard) | ✅(dev-only 断言)| +| Zhipu/MiniMax 的套餐端点可能限频 | 5min stale TTL + 失败 keep-last-good;网络错误自动 retry | ✅ | +| Kimi For Coding 套餐鉴权:官方文档已确认 `kimi` 类型 + `Authorization: Bearer ` 即可,与 cc-switch 实现一致 | ✅ 已核验([官方 providers 文档](https://www.kimi.com/code/docs/kimi-code-cli/configuration/providers.html))| ✅ | +| StepFun / Novita 的 base_url 匹配与现有 OpenAI 兼容克隆冲突 | `detect_provider` 在 `detect_provider_openai` 之前调用 | ✅ | +| `defaultBaseUrl` 与预设 base_url 双方有值 | 预设的 baseUrl **覆盖** `default_base_url()`;保存时以 `provider.base_url` 为唯一真相 | ✅ | +| provider 改 `base_url` / `provider_type` 后旧 usageKinds 错路由 | usageKinds 不显式存 provider 字段,Rust 端每次 `query_provider_usage` 重新 `detect_provider(base_url)` | ✅ | +| 旧用户升级 0.6.0 后无 usageKinds | Rust 端 `detect_provider(base_url)` 启发式作为 fallback,自动识别 DeepSeek / SiliconFlow / OpenRouter / StepFun / Novita / Kimi Coding / 智谱 / MiniMax | ✅ | +| API key 暴露:当前 edit UI 已持有明文 key,IPC invoke 序列化 key 是"再次"暴露面 | command 改为 `provider_name`,Rust 端从 config 加载 key,**不**经 IPC 传 key。错误/调试日志中严禁输出 key | ✅ | +| Tauri capability 是否需要 | Rust reqwest 不走 Tauri HTTP plugin,无 capability 变更需求 | ✅ | +| `usageKinds` 写进 config.toml 污染 Kimi Code 配置 | 存 SQLite settings 表(JSON 数组),export 时不写 | ✅ | +| 限额与套餐 UI 区分 | 按 `plan_name` 判断:`five_hour` / `weekly_limit` → 百分比+倒计时;其他 → 余额数值 | ✅ | +| Pi 与 KimiCode 同名 provider 共享 UsageFooter 缓存造成串扰 | v0.4 落实:模块级 cache key 改为 `${agent}:${providerName}`(UsageFooter.tsx:36) | ✅ | +| 用户用 env 配 key 但 `api_key` 字段为空 | v0.4 落实:Rust 端 `query_provider_usage` 兜底读 `provider.env[expected_api_key_key(provider_type)]` | ✅ | + +--- + +## 九、需要在开始前确认的决策点 + +**状态标签说明**: +- ✅ `代码已核验` —— 已对照源码确认可行 +- 🟡 `产品决策` —— 已选,但落地细节随实现调整 +- 🟠 `待真实 API 实测` —— 需真实 key 实测后才能标完成 +- ⚪ `待用户确认` —— 文档中给了倾向,但需用户最终决定 + +1. ✅ **预设触发方式**:先做入口 A(独立弹窗)。入口 B 推迟到 P2。 +2. 🟡 **预设的模型 maxContextSize / capabilities**:靠 models.dev 推导 + 预设可选覆写字段(§4.1 已明确 4 级优先级)。 +3. 🟡 **账单查询触发**:首次进入自动查(≤3 并发)+ 5min stale TTL + 刷新/重试按钮。 +4. 🟡 **Kimi For Coding 套餐**:P1(先 P0 跑通后再做)。 +5. ✅ **自定义 JS 脚本**:不做(rquickjs 过重)。 +6. 🟡 **预设 v1 清单**:15 条(不含 volcengine 套餐 + codingplan),够用。 +7. ✅ **usageKinds 持久化**:SQLite settings 表(JSON 数组,v0.3 修订),不写 config.toml。 +8. ✅ **kimi-coding preset 的 `provider_type`**:用 **`type: "kimi"`** + `base_url: "https://api.kimi.com/coding/v1"`。**官方文档已确认**:`kimi` 类型 = "对接 Moonshot AI 的 OpenAI 兼容接口,包括 Kimi Code 托管服务 + Kimi Platform API 密钥"。`moonshot` preset 同样用 `kimi` 类型(之前误写 `openai`,已修)。 +9. ⚪ **Volcengine 套餐 v1 不做的取舍**:v1 仅保留 volcengine 推理预设,去掉套餐查询。是否可接受? + +**用户实标 ✅ 决议后的项目**(待用户回复 8/9 后): + +--- + +## 十、附录:cc-switch 借鉴到的关键代码位置 + +- `src/config/claudeProviderPresets.ts:25-74` — `ProviderPreset` 接口 +- `src/config/codexProviderPresets.ts:13-46` — `CodexProviderPreset` 接口(带 modelCatalog) +- `src/components/providers/forms/ProviderPresetSelector.tsx:142-500` — Reference UI +- `src/components/providers/forms/ProviderForm.tsx:1794-1899` — `handlePresetChange` 字段注入逻辑 +- `src-tauri/src/services/balance.rs:1-454` — 余额查询完整实现(5 家) +- `src-tauri/src/services/coding_plan.rs:100-206` — Kimi For Coding 单家实现 +- `src-tauri/src/provider.rs` — `UsageResult` / `UsageData` 类型定义 +- `docs/user-manual/en/2-providers/2.5-usage-query.md` — 设计语义文档(中文版同路径) + +--- + +## 十一、自审发现的问题(v0.1 → v0.2 已修正) + +> 本节是第一轮自审发现的问题。v0.2 已全部修正或记录到正文 / §八风险表 / 对应章节。 +> +> 第三轮审核额外发现 20 项(6 阻塞 + 7 类型/语义 + 7 逻辑/边界),已直接修入正文,不在此重复。关键修正: +> - B1 「baseUrl: string → string | null」已修正(§4.1) +> - B2 「category 缺少 custom」已补(§4.1) +> - B3 「model alias 冲突检测」已补(§4.3 步骤 2) +> - B5 「三层注册清单」已补(§5.1) +> - B6 「并发控制 ≤3」已补(§5.2) +> - L1 「icon 补齐」已在 §4.2 表为预设加 `icon` 字段(值由 P0 实现时从现有 IconPicker 名映射表中读取) +> - L2 「models-dev 缺失回退 4 级优先级」已补(§4.2 底部) +> - L3 「状态机」已补(§5.2) +> - L5 「空 api_key 拒绝」已补(§5.1 命令层) +> - S4 「models 数组为空」已补(§4.1 注释) + +| # | 问题 | 状态 | +|---|---|---| +| 1 | **预设 `id` 与已有 provider.name 冲突** | ✅ §4.4 已解决 | +| 2 | **usageKinds 写进 raw_other 会进 config.toml** | ✅ §三 私有字段持久化约定已明确 `kimi-switch.` 命名空间 | +| 3 | **默认 base_url 来源双源** | ✅ §八·风险 #7 + §4.1 baseUrl 注释 | +| 4 | **TS 端 usageKinds 与 Rust 端 enum 漂移** | ✅ §八·风险 #2 | +| 5 | **Kimi For Coding 鉴权格式未实测** | ✅ §八·风险 #5:P1 前 curl 验证 | +| 6 | **StepFun/Novita base_url 与 OpenAI clone 冲突** | ✅ §八·风险 #6 | +| 7 | **倒计时 i18n 友好格式化** | → §六 P2 | +| 8 | **账单查询全局开关** | → §六 P2 | +| 9 | **入口 B 切换预设** | → §六 P2 | +| 10 | **model 字段名 vs Kimi Code 识别** | 核验后确认:`[models.alias]` 块与 `[providers.name]` 块独立,无冲突风险 ✅ | +| 11 | **图标名 → IconPicker 映射表** | → P0 实现时补 | +| 12 | **设置面板账单查询开关分组** | → §六 P2:放"设置"Tab 同一分组 | +| 13 | **模型 alias 命名规范** | ✅ §4.1 已明确 `provider/model` 形式 | +| 14 | **Moonshot 无余额 API → 不显示 footer** | ✅ §5.2:无 usageKinds = 不渲染 | +| 15 | **OpenAI 协议选择 `openai`** | ✅ 不暴露 `openai_responses` 让用户困惑 | +| 16 | **多端点候选 v1 不做** | ✅ | +| 17 | **extra_usage 字段简化** | ✅ §5.1 只留 `UsageData[]` | +| 18 | **is_valid: false 透出** | ✅ §5.1 类型已含 | +| 19 | **跨会话缓存 v1 不做** | ✅ 30s TTL 够用 | +| 20 | **测试覆盖 P0 必须** | ✅ 已加回 §六里程碑 | + +--- + +*文档结束 — v0.4-draft(v0.3 已实施 + v0.4 落实 4 项收尾:handleDuplicateProvider 兼容老 alias / UsageFooter cache 加 agent / dev 模式跨端断言 / env 兜底读 key)。配套人工回归清单见 [VERIFICATION-CHECKLIST.md](./VERIFICATION-CHECKLIST.md)。* diff --git a/docs/VERIFICATION-CHECKLIST.md b/docs/VERIFICATION-CHECKLIST.md new file mode 100644 index 0000000..0a87739 --- /dev/null +++ b/docs/VERIFICATION-CHECKLIST.md @@ -0,0 +1,154 @@ +# v0.6.0 手动验证 Checklist + +> 本文档是 [PROPOSAL-presets-and-usage.md](./PROPOSAL-presets-and-usage.md) P0 实施后的回归清单。 +> 覆盖 v0.6.0 新增的「预设供应商 + 供应商账单查询」功能,附带核心旧功能的回归项。 +> **不替代自动化测试**(项目尚无单测体系),仅作为每次发版前的人工冒烟与回归依据。 + +## 0. 测试环境准备 + +- [ ] 干净 config 目录(备份并删除 `%USERPROFILE%/.kimi-code/config.toml` 与 `%USERPROFILE%/.kimi-code/kimi-switch.db`) +- [ ] 至少 2 个真实 API Key:DeepSeek(余额)、Kimi For Coding(套餐,登录 kimi.com/code 拿 `sk-...` key);可选 OpenRouter(余额) +- [ ] 至少 1 个 OpenAI/Anthropic 兼容 key 作为非账单 provider 验证「不支持时不显示 footer」 + +--- + +## A. 预设供应商 + +### A1. 弹窗与入口 +- [ ] 主页点「+」按钮 → 弹出 `PresetPickerModal`,含 15 条预设 +- [ ] 搜索框输入「dee」/「kimi」/「glm」→ 实时过滤 +- [ ] 排序切换「原始 / A-Z」→ 顺序变化 +- [ ] 分类徽章配色:官方蓝 / 国产绿 / 第三方灰 / 聚合紫 +- [ ] 底部「+ 自定义配置」按钮 → 关闭弹窗,走原空表单流(生成 `provider-N`) +- [ ] Esc 键关闭弹窗 +- [ ] 点击遮罩关闭弹窗 +- [ ] 弹窗打开时背景滚动被锁 + +### A2. 选中预设 +- [ ] 选 kimi-coding → 卡片写入「kimi-coding」provider + `kimi-for-coding`、`kimi-k2.7-code` 模型,第一个设为 `default_model` +- [ ] provider 写入 `provider_type=kimi`,`base_url=https://api.kimi.com/coding/v1`,`api_key=null` +- [ ] usageKinds 持久化到 SQLite(验证方式:保存后重启 app,Kimi Coding 卡片底部仍出现账单区) +- [ ] 选 anthropic → `base_url` 为空(不写默认值) +- [ ] 选 google-genai → `provider_type=google-genai`,`base_url=https://generativelanguage.googleapis.com` +- [ ] 选 moonshot → `provider_type=kimi`,`base_url=https://api.moonshot.ai/v1`(Kimi 平台 API,按量付费) +- [ ] 选 zai → `provider_type=openai`,`base_url=https://api.z.ai/api/paas/v4` +- [ ] 选 volcengine → `provider_type=openai`,`base_url=https://ark.cn-beijing.volces.com/api/v3`,**无** usageKinds +- [ ] 选 bailian → 无 usageKinds(不显示账单区) + +### A3. 冲突处理 +- [ ] 已存在 `deepseek` provider → 选 deepseek preset 再次 → 新 provider 命名为 `deepseek-2`,模型 alias 全部带 `-2` +- [ ] 同 provider 内 alias 冲突 → 尾追加 `-2`/`-3` +- [ ] 切换不同预设(含同名模型 id)→ alias 强制 `${name}/${modelId}` 形式(**不**允许裸 alias) + +### A4. 预填字段展示 +- [ ] 选完预设后自动跳到 `ProviderEdit` 页 +- [ ] `api_key` 留空、其它字段已预填 +- [ ] 填入真实 key → Ctrl+S 保存 +- [ ] 返回列表 → 新 provider 卡片可见,可点「使用中」/「切换使用」按钮激活 + +### A5. config.toml 污染检查 +- [ ] 保存后打开 `%USERPROFILE%/.kimi-code/config.toml` → **不**含 `usageKinds` 字段 +- [ ] 修改 provider 的 `base_url` 触发保存 → config.toml 仍是新 `base_url`,**无** `usage_kinds` 键 + +### A6. 旧数据迁移 +- [ ] 用 v0.5.2 之前的 config(含裸 alias 如 `kimi-k3`、`glm-5-2-1`)启动 → app 正常加载 +- [ ] 触发「复制 provider」→ 新 provider 的 alias 重命名正确(**不**再出现 `kimi-coding-k3` 这种缺 `/` 的形式) + +--- + +## B. 供应商账单查询 + +### B1. 不支持时不渲染 +- [ ] Moonshot / Bailian / OpenAI / Google / Anthropic 卡片底部**无** UsageFooter +- [ ] 自定义空表单(`provider-N`)卡片底部**无** UsageFooter +- [ ] 后端 `query_provider_usage` 不会为这些 provider 触发 + +### B2. 支持时自动查询 +- [ ] 选 kimi-coding 预设、填 key、保存 → 卡片底部出现「⚡ N% 已使用 · 5h 后重置」 +- [ ] 选 deepseek 预设、填 key、保存 → 卡片底部出现「💰 余额 ¥X.XX」 +- [ ] 首次进入 ProviderList → 卡片并发查询,最多 3 个同时(DevTools network 可见) +- [ ] 单个 provider 查询超过 8 秒 → 卡片显示「网络异常 · 重试」,**不**阻塞其他 provider + +### B3. 5min 缓存 +- [ ] 查询成功后 5 分钟内重进 ProviderList → 不再发新请求(DevTools network 确认) +- [ ] 缓存过期后重进 → 自动重新查询(先 ghost 旧数据再后台拉新) +- [ ] 进程重启后 → 缓存清空(Rust 端内存 + 前端 module Map 都丢),首次进列表重新查 + +### B4. 手动刷新 +- [ ] 点卡片底部「刷新」图标 → 跳过缓存直接查 +- [ ] 刷新按钮 click 不会触发卡片「进入编辑」onClick(stopPropagation 验证) +- [ ] 刷新中按钮变转圈、禁用防重入 + +### B5. 错误处理 +- [ ] api_key 为空 → 卡片显示「API Key 无效」红字 + 重试按钮 +- [ ] api_key 错误(401)→ 卡片显示「API Key 无效」 +- [ ] 网络断开 / DNS 失败 → 卡片显示「网络异常」 + 重试按钮 +- [ ] 提供商返回非预期 JSON → 卡片显示「查询失败 · <错误文本>」 +- [ ] 错误状态保留旧数据作 ghost(半透明)+ 缓存仍写入错误 entry,TTL 内不重发 + +### B6. 多 kind 渲染 +- [ ] Kimi For Coding 有两层(`five_hour` + `weekly_limit`)→ 两行独立显示,前缀 `five_hour · ` / `weekly_limit · ` +- [ ] 套餐行配色:< 70% 已用 绿 / 70-89 橙 / ≥ 90 红 +- [ ] 倒计时:> 24h `Nd` / < 24h `Nh` / < 1h `Nm`;已过期显示「已重置」 +- [ ] 余额行:CNY→¥ / USD→$ / 其他原样 +- [ ] 同一 provider 同时有套餐 + 余额(v1 不存在这种组合,但 detect 启发式已支持)→ 两行都显示 + +### B7. SQLite 持久化 +- [ ] 保存预设后查 SQLite `settings` 表 → 存在 `usage_kinds:kimi-coding` 键,值为 `["plan:kimi_coding"]` +- [ ] 删除 provider → 下次 save 时对应 key 被删(避免脏数据) +- [ ] 卸载 app → 卸载时同步删除(验证方式:卸载后 `%USERPROFILE%/.kimi-code/` 不残留 `kimi-switch.db`) + +### B8. 真实 API 验证(**需真实 key**,按用户实有 key 勾选) +- [ ] DeepSeek `user/balance` → 返回 CNY 余额 +- [ ] Kimi For Coding `coding/v1/usages` → 返回 `five_hour` + `weekly_limit` 两层 +- [ ] OpenRouter `credits` → 返回 USD 余额 +- [ ] SiliconFlow `user/info` → 返回余额 +- [ ] StepFun `accounts` → 返回余额(已加在 P0 实施中,但任务里程碑归 P1) +- [ ] Novita `user/balance` → 注意 `/10000` 单位换算 +- [ ] Zhipu `glm/bigmodel` 套餐 → 返回百分比 + 重置时间 +- [ ] MiniMax 套餐 → 返回周桶用量 + +### B9. 跨 agent 隔离 +- [ ] KimiCode 与 Pi(虽然 UI 屏蔽)同名 provider 各自独立缓存不串 + +--- + +## C. 核心旧功能回归(v0.6.0 没动但要确认没破) + +- [ ] 切换使用按钮:点「使用中」→ 卡片高亮 + config.toml 写入 + `/reload` 提示 +- [ ] 复制 provider:alias 重命名正确(包括老数据非规范 alias) +- [ ] 删除 provider:关联模型一并删除 +- [ ] 编辑 provider:改名后关联模型 `m.provider` 同步更新 +- [ ] 测速按钮:弹气泡,6 秒后自动消失 +- [ ] 拉取模型:填入 base_url + key → 拉到的模型自动建 alias,max_context 走 models.dev +- [ ] 设置面板:主题切换、语言切换、检查更新、打开配置目录 +- [ ] 检查更新:启动时静默 + 8 小时一次 +- [ ] 用量仪表盘:模型用量趋势 / 供应商模型用量趋势 双 Tab、热力图、会话管理 +- [ ] 关闭按钮(X)隐藏到托盘 +- [ ] Ctrl+S / Ctrl+R / Ctrl+O 快捷键 + +--- + +## D. 构建与发布 + +- [ ] `npx tsc --noEmit` 0 error +- [ ] `cd src-tauri && cargo check` 0 error +- [ ] `cd src-tauri && cargo test` 全过(当前 26 用例) +- [ ] `npm run tauri-build` MSI 产物 `src-tauri/target/release/bundle/msi/Kimi Switch__x64_en-US.msi` +- [ ] MSI 静默安装后启动正常、config 迁移正常 +- [ ] 启动空白超时 5 秒有橙色提示 + +--- + +## E. 已知不验证项(设计层面注定做不到) + +- ⚪ Volcengine 套餐查询(v1 不支持,需独立 AK/SK,留 P2) +- ⚪ ZenMux(v1 不做) +- ⚪ `ProviderEdit` 顶部「切换预设」下拉(P2) +- ⚪ 仪表盘 KPI「供应商侧配额」卡(P3) +- ⚪ `/reload` 不会自动套用新 `default_model`(Kimi Code 上游限制,详见 README「已知限制」段) +- ⚪ 切换预设后自动激活新 provider(产品决策未定) + +--- + +*完成所有 ✓ 后再发版。任意一条 ✗ 都需定位并修复后重测。* diff --git a/docs/screenshots/dashboard.png b/docs/screenshots/dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..958030a87c90e3a09a3b5740998bc3be7d6df69c GIT binary patch literal 106893 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

    ATH4JYTnZ6*W80NiF|m088eZLq7aih5SONG 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%0A@|d2$Mdcb&sZXsy;rU|8#_2ybJ^U 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 Vw8J(-3V+!klA^L;n6Td0{|6$Xy^;U` literal 0 HcmV?d00001 diff --git a/docs/screenshots/provider-model-mapping.png b/docs/screenshots/provider-model-mapping.png new file mode 100644 index 0000000000000000000000000000000000000000..4013bea528ff7c1ee9dde0c638696b3c8ac870ae GIT binary patch literal 174697 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

      Rh3II`)5XM~Hj^=T3ZCJeQRkKTg~l~bXj{!D zI~g389xumuU2hHZ=cPon+MCkfMcT>nD|%sEZCLWx=X(KubTH`kvqbYeH#+DShE*t1 zuAQyy&0iz<1aCD$9c1S;HO>uY`}QwTbSA@Mxz0lc2Z_;?@LyPdx0eji&3&d`_;~PW zvI>+5yEj<V9(wc7f1d`NPDKUuP!LElh62@AchWbN8hJ+Jn?3s% zPokRT{GX5q{9E)%*GW%zX)&IEfPZ#U;0vbbuF&Yvafyc_36-+-2Ct2H(n-3L*q^`G z(=0nIT|Rl7wT3rrev82`f*dw zE@{QFfe5X3ok`g8ro$q{a@Fa6A`F0<7CpQN$e%AhDserKeh+B4NIOpaNVW3jN=Rib zGQ;~w@7nW?4^c^wbXm1L7mipBQrxhCilOTJhO-6%jr5&4gMnpc?H%zG0O0fTPe5So zdSZJBv|b6_ou+kwK6?0cchFkFqT=*hAM&@GwaPOnVxsq#x*?9W{AfL5ti^5SSdu#L zShZ{rwG%3)qsm`)qu^y$98xjb>4mos_$%laiu1Vl90g3oe5FA}&oTI!A73D=Pc}Pc zoHASkYenmH7B9`(cIEe8Ba6x(#tWn4Ohk?D-?gz+R=dAtWKR|6eZ(!x*P22S9Z(QJ zdJm%$Gbr&x;9X)Wzz3gz{E)uPG=qe^^|qPI@+4L2*@_S?-Tu^JKFsHaW~uL^X;LZ{weIhF=`PZ6mgnTPm@f-h zfBS@Ua%}}SwFP)S=p=4I`AA}SL`EEly@Wc7NP1sqvDeE@&^_!Xe?%)PBDnuDRJxdRRj*& zr|^Mo4>w4=bJe8)jJR;<*gTQt-v|vw8O?)@~(RDesLa_=B(rL|gM`HV_b5bL9>ty{%yMR~*HX785sj1~cb znR?sigi|CcEAGk4oi9bIy*N;N(|*IvM}Y(p_@Swm+}p4%wOG36$AF)M(oi6lMtb0* zf*fU00>iS8r+cMUq_^CltfJ0kWVsZD&Dbj3@jNR2rdGk%_*70M{_>ynKlRI(oww|8 zsgk9?*9A7*@osV|sdJ!IrjF8?T;Lx=kr+Z^Mqb{3DNO@NOy;~`G^6kz3&o#Kh#Y+- z(~z`(>z1L;*yKi5{qBjv0z*x_>S6}4j@H~!{gkS;mrPowk^hlqSwfX^j5m9?r{$)| zML9s9HT(l0JP<6a4gbcDsUIF6-@j7~@SKhbdoS?p$CDu&Bh}?(B;Lh2V9cg*2*qv3 z^PFBXzWr-F<1kj7)-iF6)>E{EPB*;;fmvj8N(FZR1AOH4A?}R+*q|4MHMjej?ZGz% zXZLe3!CuX;y*-Z%@6*R2Po?y7gFrQGAbi#25&*g>&@ie%VLx|2nzCznMR%1kLWBF*T>-oT@arOGQRRe^XtVL4(j zoAOeHp-8>C6XTC;Xw$%mIR&L(Gg|LNKDtv?NzuH1)Mc~WQ&C^_j~=x0RN2s!r@q(Q z5A^(0XVK`r5>or&JLR@~Ql~?p^Y-TLZ0H(H#dC49RsH9EM5}upz|!8Gi|&JlwN6|8 z`ea|J!)mXaezfAsVCUI+?|GNnyp}ESJD~p1 zFJXY9fSR?(AgeCGb|ZVR#+kYm+ou?R$g7M!V~c9@ik&^6pDF;Qed1dF)|T41DDk5} z?>fC2X7=+_*j=)!UC-jcLZfy>(;Kn00td6T)=*FvqU?+RT%-Cn}; z)0j#i5%W99IVv5}abGu!n8mIu(|q%xtmhqyJ!*j3I8Oo{Az#%Fr!-f#`;V>Jw1f({ zm*`!0jg&kJe~S!&67MaQ9Ip~suXItLQPCUdZ1eO;IyVpJMo=2 zGN~Dur161q#2yWXCoIMMcXkwj(d7@xE|rJI;coztSP06M@O8EcC_x7w_%ST8*i4N{ z7TvTdCg^8ijToTG^N{WnU*oiIlEirv+7Enmit&fPn&5}mPfSe|Rxc=dZjN8-el&2`R^hIsvi z!vr1^+_=Y_sLHn!f z0LR0vTFaU-E4#ey*E=noWd+6KZ5AqaL7-sJPUprwg}@wQMTT(kgqGppxE3c4;#Md0rg+rez4Rw$b-?9FzF%XTR;CkJvGYcq z1!FCq%L$jynfTS1z(l@52!k9%ADyqUN2xi3Jz5c;O@Fp6?6Tmz5{#hkMxaXJt((mf zWU9E8QXN^0Mk*EMN4Dh|4}A5i0Lo0O@?PFO;y%heN<=GZm_7@n59szS5Y)*iaIl##io zm_+7<(24w|7e5kI_8vFyFmkxF{w>_*&C&;?N+}ahMk=5T}&gO&?{2a z)8LC+MPhDX`&GQlS4+5*K4&>f)isilSrJtK;0WetPds!Kq<1&yI8=L4%Kdo4g`Ooh zH=XaNXLfb4b)2k4Zro14RqOevUMGnHU=Z5Z(fly25XbQ(xPZv7aA~ZSzq>Bp50|6k zb{_!LJCq%4r=ROaH*yY<)gtTp6qQY>JHe1jNXVey-5n*+ks$fBacJDO#{JPp{?;m! zWExj{rxs=~zsTi*u7GKOVl*^?tp59*MIe8#jhRx|_wOrAm^D$J{wN{jI@dKD$6&lS zz4O-NS~|#QCb=fe)V8^WJveEH>b4D~b4u-QY2puAdvo(=JrWXAr5O&bS>>DphUflX za=^2v@IHrHD?k$1Iw5mOI)e`er<~q#U99^|Yd7A{LfE?!SXr43i>xx=a$Ve==7}4k z{RJ~(rJm8dj!Cyha8@a8>Hc7Qj*J0Yrb$weY4VmYupDS$!37Yvk$1Od8ZYK|Tv`5J zxi)FWu@DqGBGX1KQWvh{FCjzq@UkTEkv|RnYa-S%ix`ZKI!m{Ei>cx*Dlv`QT z%S7|p*6x*P3buU~10JcD?2e90!EygifS`+L-~lM8kT-F_{=)d;Nu0MW%S6FD&ZPStvqO)=+eJmQ1&e zn(M<(2%1ow*!r5w=^J-SRZE!oCpJ#Mig{(l9 zsnHrVOn3Rp@#d52R>Y}L37!+VU-q2)27bG`Dez?%zcL@b$=)F_BfEGCQ1NDBtW*bm z9a`H!fQwxP{q0Z-@HS@P79fC(X2*`Lai)Y^up{1^O&+Q*Z$Q}jBWDeFifHSAy-(+~&$nDP8fg$6kE3oexazSknW6d3{ z5>o^^W`fkKx`zh)i_2xFtV$k4jO_-Pasn}n0DdQ~CrhQ7=>QT>&qsE+A}P5W7uD%x z5TQ$P&>H#&bdvoUEOnbm&Jk+hzVrURWgUMZ@1s*H_kH~o5Wtwhkh+VFagYxWa2YF` zT1$QJH2$#f7D&Drgy{0UwA#_GP9eU#fq5I(9DH#?jJdKf&A973FKqLK6SR;RlAUd;Z&lQ9I&c*l}-z^{Yt9Tz$Ri2zsE1;`65NPn2&c4^Fnes46V4T_5 z3R8XCCB%wpo6>j@pLhI#K4ucD!dc%rclK-@@D&gDqI;v&TLG3KQFP3VyJ%YODhAqT zqBnKzb*r9d1W6|idq0=Y`)cdZ*+j_uefI~=_Pnw-vJVU}`GFKIZT?F|O2=cF?Tn=Q zH;B(AJ5YhAZ4XUfycLt5VW@!hhKtys%yOFg{?@33BtjK2jvn)ptkHX^ zUpE=4aRdN>7SnqJGleR%oA&IQ{UE1Xt=-X|AlaU;0IQdYoC*&8HWf{l<+KT_koWNP zYmHVk0Qfq2SpU(eWM}&FiY1qG&|bIZYlgZdrpf!@_a<5^CLDsqE_?FcNjEoq&2BLH zNC>SfhhkE-bA2GO{&=}Lh{M{c?uzR`s>!U@kz^2 zVizt>=!gO)==1EcqIRJa6OdK{T>rU`&X#D2uH=Bf>b-WahfSaSCBrooUH$N!4iVO8 zW5{!f@E3ER`o56Ii(O&OCMI}=xdF<1Ek>S|S*a8hWHz$BcOL~)A@(WHMtzc*{hnr_%3q~2$|Kg`vj2Qu^qq0w^e+(7%hRFR#&d@sLU>mJ=~ z&8+Ef|H)ijPF)R&F0^AoK9>gsR3IUrnHHB>fgvH9zD;@ih{5MF)+hnW67J zoqkk3V*%zJ?!0~o%BCHJSfq>!dy09TDcA~EjZC%>Rni&bOTDNd0um$Blk1Io$#(X> za7qpfNpjUadsYF7cn4{Jyf}DK8|FjTDQ?bka*cLfC7R7=&_x1YkG7 zY2rOm4_wT(4-iXh8Fj<3K?!O)mCLXMFynZ4p4IHbZ{vR;K0q{K3WRwg>!ue1YNrvZ zjiMoK!Psd#X#nfD>&@t1uZ4D(8Dlgj;qga3+)T_zKEY!XgAO!Ut3WNvDN5ZjiL&RO({gH#x^O?-jV5I|0FoobXwo9 z*f$P#MBK}HnqXQGX#q-!M~!HR=s%1$%vsF6#{mph>C3_MU#GtRU76E9m7aIrfBT_Xvb-X0%?RCrJ?*sJeErS=`d_yN<{JL!d1Y{KPFhvn|? zGlx}^UYbqU-R+4;c6Qp_gNd9>GP6@LYISHU?#Z`QfUB#=-36oCmf)?>r{xoW7P}!4 z*OkOb@0UI8#zeT-T*}U`Pyl4VGQZBu){lY*jbExWLp1R$g{nrT^#&JB)Ue+Zm2EOa z*dA4jUoYe*(_!150P5}n5>*14ptu-`xs?!^fj>U82_$jq1Y;yb(}Q`=Z^<0;rR2^h z*jyiamDz~A${Hrj@Xbd^-Tm6&0Up25*HYd}U5w=1nOfiS-0NO)bWkW)+luwq_a9E2 zcQ2q@4Jb0R`oc4Mt4`jziaq#vPfhI4T&v=jQHOzQ%Oc^No@W9dir|X^y zw&&nXQ2Z5btB!euYPg`%d?*GbB)&5p3BcaD*3PIpIv(=!IuUyIEd^$D_DAL9e!AV6 z3c%xB>vhEAZDuRO@^Wu3p3}i8(j>0V1dGTWTRCw;XAwH=%1M;M~y3s!we@dKgf}oi3z4dYj4R3c;w?R$%G( zYOB^D0jVCZCtkvIAD>4@9JsAn+E;EK)0cE~t*vK&J}$Idt>{0m>5gihTF)X2nTHq5 zG1=4bICoXC8>TEl0;ZGp;B^~#NgjeevF{8?0VN8}Xr%0%*D6w_8XSz!z3w+Kb|Hb+ zA)y+?5cnHCpWy(%@4=S62Y&E3L$6*RUn_Es9XBYND}LizVKXWf9X{`hBR^v4J@gc` zlD%6;Fd*ldG2(bfp z7PlD)_-RCSB-TRz zvH)kU`QKOgc6FdkhsUxOUJ;U?Ry7~9E6z&ml?$*=v~v11cM(B8;7Js0o8{XEckzKS zk*_(DX0!$@32Z|`p9>{%JZ2TE93+aCJ&KByLI8(w7Wt{6OP0z-bSnEa$|=V!QF^WfiEeI5uvZ1AC2DpYCa-V8iQ%)-cm(Z5nxa#NJj2 z_~ztF9}qq4E{5)E%vaBY9rnIB@XuF7mc28z@IFp$-!+mq8(rHLJmS27W4{kdozelC zePR?!d`?D3rGifdyG$2LjTMsRi@R~s-O!- z1=xb#U{)=@zzVxut3a9sHl2_NZ8ss-|hnLOlo8)2zq@KI%4J2F7 z$*Ow-D`4ro|1rUcP1K5n>P@(7phq1|t|McULDmT_4-`weFD zFqOP$88t%zL~1@#=sS-cFkOtq-pU$Pg?k2S%98!CSORhYT!YC4QZN+__Bbtg%7hO2 zdt#nGdCheC)%)Z)gem9*w~(nGK%GH*YQghH4!F#nZRsXY*dLDJ0jSyvWu)BXTlS># zz_YDxd^GbisiQ|_$8cIut|PXm*5gpO!}?C|K}losyVx3IcP>>g$58EZNzvo|hs+;og8MwmvL|+C{@8R$!lY5x)rmv70$fehGmG&&c^Oa;m4F#`)mm z+e?FN!`Qr@YD%FYb3c71_V0TtflLI)r6(I|E(SfQH|=s$5XSPd!et9xs_K_fpAf+Q z+_d&PA}LDGp<}g?sddN3-c~xe%6xv;U;*Wau$=;#Iu;R;*I0r^sY-SQj}YirSJS)h zxK0z7cRwnvQM}6pGONYcVCSE0v-xfUw(ld60j*7e)uFUCs-EW)10>R4g%>XlZUD$m zq29}5S07Pky9@P;HwdM7`4PC&1_8t*F2Q={`cjTV_&58;;T>4S=x zjjaTk)agbp+^a5|vCgzkhxwP_ROoAXG&s^SS|GKNDL8|Lap zBcrM2| z3ICj`A^9WfyZKp>uHaCqQ2b@$G1gFtTSK80cWQd!b^yI5ou<+2U^WPfPt3iL|FY?| zi2{_yiL>~Y7U0uPZS+hpYtwD#gN@(Ipt}8jcNrf!unnrYLb>q#1sRz=gJ?=x(4`wu z^RieMt}c`3p?*z;BV{dSF21ojz7ct?mu~Lat(w_lZiBb@T@gsBb?|j;^ot)-_yfqm z`w$@QAfs=$c={1a?3!zCqNEWm@!~NZ;PY~n_sD*xdj~TAJfr)1CSx{K739OF_?y)L9>*2bNp_}x3A zFPlT>)x}k%OaihR4xTW^TFpNRA1u4+6Z;l*)*|!0rF9ocZcLTZ;iDOKVh;O_59vcf7rx^gDKJ&MU{bWsD9%8cLlOp4DW6{6HT|4o7VFt%6O;My0}Mi z^eO3G$pZ$!#*K;LPjjB)U9#m@+&kOe~j`7#_AO^=WM&o1Y32CLC@7m1-| zzH~Blc-{>!sSsQ2Bbz@2vkuD{{x{vgFS|=)q1Zu><<>hM2#CsMb0Y-SL1kT~d^ABw zZ^Xd*l8pFICeadGeG&MwvIJOR9EH_r#N{-K`4wvPR8*r8_*_ITx(K*7vA2JnKk|?j z<6pC411C(6kEeNfd3ky4d?c_wrZ8KtwJfYH6tdw(L^V_Shu052;R>68{l(;sg%NOx z>kFil?H@UnqsZiH&Wo~dex+F}#YUnEXQ+wgRu&f@+1>i0vZ_y*Al%b@>qUm7K#6U= z!X%CAxtspxZZFGKBq9E{N0LdXLDC4MTlyCXZDiXqIAeI`a$N^v90&h64CAfxFo}Qk zIdigQk77n}SH_`&ZX zu8H-9#53pRl}(2{{ea7!q=ru`ZNTbRNI4SAwIk3uM&w@UyLLtY+r)wWzi${M26{u2 zy}R4h%F0T;&6?Np3aMd>OfqZ0pkY&!Js+Qwkdxk(1SI938{>{3O^7ijq|EFgB zaZ}X0sD2AmQyi(Gz`(%DU;O`6>ptRtY=cyfe;%MXVlo~2D=#KfLXk614o^)+Mw_>1 z@<4kr-h?K0p{P)HxzV*ah@-ZvIz~*=AC&-2H+?o8TmoWpM+pf;0H1!U?>Ahae3%Ys z&ZVI%0Z!Y?PisCv_hvKr%{Oc5-;AY?X;5hX)MtoY1Kf=+2*^JAAoI*bBGnI;e{xFB zBCmz97TDB|%wrre`2F<~BizyVMJ7ZB8M{tI)#h{y3`go89%eg{hPj#^adu`o%lTb4 z=QM)&F}>h6-p1@eyRR=^rvO(NJFg1Sb^-miB*_lLSuy!WW@DkZ9Uc%A-g~*%blufW znw$3u3G~Pw1)-WFd*7mm4*D<@!3{;3&UtDLOuICB+^OW_{zXq68=In7a$bF7F5nUy#D zKbD4$YX9FsLl@O)bU;GbsVL2q4TG#JdhvC`em~q@c6G)>g=ku!922-RAp%(!f+$+n zbyBo{^$}*eGxYKl95IyMu~-;5-orB;^bV%Fe&G}r=@x>!PQ(Q6@InZVkDjl?eC1{= z-owqo7@J97bTiHBJ$T-GWj{T!>%3UwVyQMj`;^Hymaye?68ns`_ck62O&iTrTz|6O zaLFDs=GI{eNOGZ9i$T~)Ab)=_i774>X;XA+X>F>Gh3Zn*F* zX}&4>qZ-{ybh_#!sx0q;E zSNrfM(4>aQoIMwerymMHBcCgmPxvgwf7DZ5$cB>FcYi=~=W|(Ft>pt)qPi`H%d|u2 z&h2;)R5L^|j0^vTvjc(?*>jCXo;%Guvvitc{Phh(x;HI?#b>3|CqD)T^b01N8*RRr zp@=fBLRk(ew?ZK7wZ#)3OI3YelR;U#B7#5F+IgdFu{ZU0wUmXldqJ*NvxZ^0caG)e zb#(Mmxv-Ry|1+TYrP?nM;K~p)(#$C2h6eD(_<2vz@xk3G9g``25DK805&Qge`&X*Z zOaI~0#H9^kNm~?P-0wPi(24U9t~=QI$4}sJ=rITio2XvAxcbQrIT=46A_O4>kOXU@ zci5soU2w?*!ku8fhf0~HePi72&K{NALp7jmML)OH6+LtYQ+vPA#rPdC`p$nfo>3hU z9xVPGc*KxBgr4wlKC||8o>k~>?Xa2nC73@QK7qo$_QPIU+1~KiXbJUNA^WY^9$n8; z%lgsF);z)Tgn?NpcfpZ4{==s=`DN?o^|}o#^>ip~kJtf>tKUE-NJ;^Ky87Um zBr7+Olz=j~l{FY<@nlUYriE5WCvz{106{GRD9+@|fNXnIGP94ChHB$wgMi&uGb*<< zjR?^CL7dy#HlpW7kR_C^f7ySk2K&)kd%OGWJKy)-*|?qE081`$lM-2=0c5qe^nMT& zz^gcyK>0C_E%RAbVu+Y+NE{qoPiZE5%SD`KC-rpe4=zD*0B|>i%!%@|c}Gf}BocdS z%sivEzNuJGv%8dlg{kiz$=cUJ(&Oz~x;e}gWXMhUd<3aoNZETGEAD=t$rHR^vuU-) zMVJ&FWC1OfJQMnyU=va`^v-UA2)aY8sYIDg#!F(0PhMZxbXdx9PTXId{5yFzWSuVf z1!;)5VkhBbv?8>==w?WKWxF7MSdb`<=vd&m`Kk@URcksCSqFP^n~oYkIU3RIv=5v9 z$2#GTQ^-)j5tJrP^pdWc1@KNscJKniY{E+8#;sU6xo{?&Xn=KHe1wO$5sjUUPoxBr ze{0m)!rUY$n9h*PR-S}F*wFRSVveQVyW6;9c82A1r^4-%g(V+C{O=-ZM<4Q2;cl$| zi^9%yjWfImS-{)eJPKa=W;Da!W6fKhHfU1;?-Lzgel`jj9kYl2C=vD`cPx0;f%w+o zDBI~H8UqCntiTvOwzfdb0^G~bTEr4^^?P%`S+MrH`io525rql)?BmByRadyz9~<_jwr&^?k~C=_HUV7@*i_sv_6NH>}2G zxCW#(q`kS($#0!$m#+S?Lyh$QGH!FsA422OlzYagF*fVTL=SmZB zZE&QfX>N6OiFDAIymSy8p=poWy870Iz8Z`T*M@0Tl1rgy;lXEcimSbiA z+3ZQ;C1&D8!Ksn`yziIISrGXQhgfbKMjyCeaMJxn=A;}89Fxf|bgn_B`S#0AA=c2M zV7jv6X+ZhFuBHvhcaipRS<%xGMVKFXT|cWlYKzN4?9S4Qts89rrQGSo=JGzx(&6m{ zrH*_g4g9yXG@_?yax3n1&)|c{&En>L`7w=tJ#>DF~A5NU! zR1y#_}#+5LVsYB%C6=X>hOWkQJ>2C+<~*znVls)fQ&HP; zIm$E?Agq^}{fL*hlT$5S2sttpBUd(i-+|uku4pJmiunX#EP}P#Njcx-Wwx1EOm)uD zF5|&A6=w3|av}(1Gpr#2jsoiPd)-{>yjKRX!7a4ao{`?SdF2e)>9<%~iw#br&1y`@ z_Ce3#f zR$Ukg;$sqe@~Wzeh=?Dj1ph4OyK7Z0!qWLv1JR2jtG4kKfK8U=c|K3&n|%42N4f(~ z%&6`@OpD^Bh3Lb^^<`JPqzRWC3L*zEQa=8{khasU&kH;DCbbti1vj`(M^%Dd%IULu zSjX1`;g=mDqeOw-n8+O)-mJMpIJU_JxGk$I$c&>UTQVNyBDf7ifE(Sn2$2b?hU>MBs<@vAogjATc$!Qg$wzGsq%+ zOIP<`NjJqN6q`kjbdqDzmh1H8ODU|$kw-TnKneTgW&gNT$5H!epVN&|W2+b7RvdZ4 zHx2M1m67O9>;_p>5C-;Qrukuyx|FxO$En{rq88n%Lj-F;KA|@Nnx(sLYent%fT8*} zV$Pa1Yo}65%g&U&pi@arO*Yp=o2YdARU@?(YsM3;?9?l&#vQ(eOP7?aE>05vXMqN%|f`I3M*_Mi-Vd-qeTJ3U{@|H3z z9l>4N2nYqBi!nms3o^Q?JEX6lqg7|o&L+piBCNuqmcOK0yJ(GRL*1zaMtMKdUadRVeNIWS zF0$q)Q^JGL+gnB3r)#)E*PC|DHFayN-JEEWoO!?cIQ}#c%Ed_`JzTWT*>*ea9{Kt7 znCw7EFEy4@oVt351VUxQs;MIVuom@4KxGQGwc_>?SGf6>jP_Y8g6_Quz{Owx>zz}?oB!FZvp zt5kl`Pbn*zpR`UuXsi&t{!OFO+gBl8PrKivHF_?$w@f&`@b^W&JnIL(b>m+nP# z+S0tYL5F+UW63)?C{y0z)+-?wl|sVNpRd%>`HZu>+tg5stEDfivm0fv-TK(XHz~W;Tx%3IbxHsZ9JAo zBi!&YReVHiah$rqzWq6F${ zDaTE8QaCqcj{8vSh2wowM0_HzW2ic%O%zqG%Q3%bfY?gCr|<$N0JTAH|^nSE{nQ zx}2tY_^3X&BX&JIHU(ggv9!3Z}!+rTS^v z_+lBi!__Doh6@kEqm~nBVLXJ5ghjk#(5vX$E!8F5Js$dcOj~4n+~#y&?RlSbU75eR zJSs=kj%C(pI;ngCjA>hA@fg9^Y=+`?3tMz>|Dm&!eYA@e_M9MFJSeDS>4mpT#8%Z; zAD`Tokxn~Qhc?zmnhd8_1mxyL@?4R&NQ3jkv@{__nE?hBS%F9AM(#EGOS3pM74}$a z@y0M|Y)Wuevx*iQ3@^n_M%zCuE@z;Ak2nC6Uu*&Ia3k^7r^NBw6Q?o>RM0;su32IW>6B;-*osw?ZE-B zX3RIbT~nLmWlbzvk&+bod}zyfb$=^XSNgBLv#590Kza@_@nC3 z4Mz4~&iLd-@b4rh*J1!J$!K=Jy@KgL73Aj)cm4Ao-R8L5aw1u=4o(TtA zDcRT~raekPZHoLyhQvvRx1&Ui6+}(<`C0McI?(Xhh3Ir(b1b27$;!bf$Ah^3bY^g1Qc_pfcO5TV@9b{avk7yiKLunUESP&~!G&dQc~g4V z#j;rpOVa;`MCen84fqioT7Gbu{>(RyEM$ByeOA33g9pm|GRP9Iw{`(sK3u(|c0ny& z^E_iaxt3eTL{w2%FNS;&0bbunL#PA~Ieog*cy>bQjE@mvpxHq4ixeJW42|7`H`5C# zLJE!oimRuxN~zzRwX913um4OIuhNe?B19OWOb5M@d7)Z@VB=5!u~&h;i;G=$(asBq zS0h=Xvd#Xks?I<=$52hm%^|Dh;S-yhEoS0a{cKBFU9ziHZ?jkM=)rFEpNNlH^?B|$ zf{iP8@J=@xlf_B3Ivx1!ncV{p4!oIFvntUj@j724)GbOlgj9N;>-=d=^J~AN$sCyu zevYUme4k+Z#CbKXM>l^o`RZ6bAwxoeIZ_*w58;M}(gjm=@vmET=u0#O-HMAivKTg{||xt(*+N{EV|C+ougKoifb9nP}xDkzG5}# z#gtd$qnIZ*8qeL`PlWd=q@jH;rC+V^@W<%-_IN!Yqj@B)^{)#}BHx1}aHkwi^rB`Q z$N6(MsBOj=FYLD|sa`K&qOm4f7qACYDR_>{e1#i2m*WRlandbt-YH_2L``NI9{xO=l2R)2v=|QOY3CpW2pRmHK=pYUT(8bS)3A1_8R>$K@8qzGQ^ag)9j2<*;Z*`KUO zNZJ4R`Xq>&@nUU(9><%foJ{0}7Q6v*=) z6P`tOo9SgH!LiO?!Zl(3-;ZJ{go=A(<`ldLvJ@0;SP*tt7|xDZt~{Ov4;W$hlAaF? zZ))yB+3!0^Rob~7v{R4~S~?LT>-QjAWBDccDNv_74uo%skyLNY%}GO992|?Od*O=R zvZ3!Lu#u)xR6f4u7v;28A5|6AJtY}V2w?{%o4*7h>ceZQlHhj*Dd}NXMLWM$@oAy9 zFZ=|9kFTF=T#xN#(sp4dEbpT}`T4yLc=6>0?psW~+?5xRS((aNzZ>TJ5|Vd8OS1j$ zPDa9t%WxRaA#{v`_wdN30cyZcT4J83NoXhF2OR$8L7V@A$)VEk_2=Jqe<8oYUb&@! z2MZ!&y&5>aKRu5wEiH9kW@u7f(U@ztvE|Xc8Yv8SWmdeTlGKQ{H7cE$Y?Wo08=KpB zY>NUF?kwhsLg#{p+DDX$G@TCwlyu~t74)ACTF=ML#g+EzXS2P|G#Y|73zOF+CS!H6 zu@(@6$7t_`(%jBLr0*Td;__YZgRt!n=F6C5aw9uZ8Vho~ z7#*z!Z1kl|=lm>Iw$Pj%V-cmaeZ&A|Sba9^ULj$z#=VjF%(S3Fo~JL5Q`zE!OEiGr z$p`ryjDr-vbrW+$uUrxsTl|c%U{1O|^4w}?(4WrFciV`9?%3XUnQMDAgL5EST9+_E ztmrzqkv|;uxD81~G?9^>a2=iknJZl+U*?aM>P$mf*&{q9M{O(2@7Wc80bPpTf9j;! zL&IVBd8l0$Ro98~TM{x{Acq~bjruc|l^v%)Ec>=k+TvUdZ#6QYFkdneG_xVF#x<8- zRNpwSK6DrtJ{V9eN-2zAgxTB$R_HCqy>rG{l1T9AV{saf!7c*BeZ*S3do8__fkyDQ zS?j|iqv+=Lga?-nLWEV%pxmNZ1(DQ=k?tq7)0Z!M$q@TBXa!y51a*V%- zpu+euJLApH$|>`*Aq+f>MPD_Gy&5aPM-x8}SA~?5O?d=aKZl7M{?67AH)#-Uu#vF`!x;EpL<8Dgl1t12qK16SC#bkk zMP6MD2MCfa?dbJq)rP+QwffL57I6{pWr|Vcw4CPUd#t|(2@+4z+IHhB+_MZ;Yg^8G zAHkV|;8+#Ut2~iR&c!4 zq1|RIEK3%slnnMMYSj_3u3p#m_TKvvq;!9rpRzqdCOR~1*bt>r0{%G7bdWi^>XqYb zRGnZn()1sx#D_?o#}tg}$?@`}WS-H~pyt8aHPp``f(Og0!-N>JmL0 z9`_?I21E;3P+@kJd5&erezFxU$0fc;b1S&vj2!;V!TUsQaUzM z`wX_6+(krSrEoY#*xB-U+;HMscEVa1AJ?pa=OJq?xUVto+}nQmTSa61Suf9^=~MN7 zcTaIs1ycjuo4_<=m#=$fmOnVT~a$+&Mv3*G7nyo&*lWE*O zT$`WudY)*zu!z~>8P}fnga-&XrU+IYWcMB)FP}ec>5XsNws$<2AzJlE2_L%qKBq75 z;ZW`=wBIyn-=jT0UgzC2)p0#W60P5kW?i{&kL@SkjoOjy+P^{&K`ZFBKizNLl?~b; z;-U7@T%>RIs$CwXN)0r?s#uwJ*VZcEF^Z`Ty%|f5kmbUXU%*VX)smJHq`uv9>Z3D% z>P-bWK4+?5&Q;(KF$m%zU%&$dnnkTVDHg*Ho7tnZQ*`qO80^)qvQL+(sLPr#oaB5- zy%H#v_N9#5YnW>`?4IL~6TO5PHV>Nj#%9REa;$7gnWvT`&NIE_bik}mIuGy&f%ObH zR5}+N$;|vqiuzVdat(He7AZY7C#PFv0QVD4cEOV>@Pj21Dc6 zEqz+K3eO3h{^WhS*~WrAY2T!UH{;vnQfLvZw#=9US>uMB&cw{|gML<^d3?=Nc>k96 zUHAA9)!V<~h6++!%{91$XMLY#{j1#yHK{Kfv&PSDyfdUX#PFmea$aFMJIBtY_I?NZ zj<&U5sAfGiwc#8Wf|ZaOYGlFVQ`0)cOQnX9Q(vm>eC0`|Q!aZGtx*$LM-B%1n9QP& zY|+!vi$Vt2c)48`oTT2)fW(*F=@o*LQ2!Tz6aDc zeXy?EFJ1MOXk!n~ zY_J#syVP_K$x*Fm=E{d&nIL_f`x-e&`>9m8*s@3d%dCu~Li?|{piA}s$%0<%Mf#`J z%8k$vq`<&?BKurd_dWkRW2pNUaDz2`yAz;*70^ISP5pz}H(qO6W?HAfAq>^J$wQiB z+gM(F))jG@nK&_BXv}ku{MO}1=5=&3;&7+|jGH#6RO0!@sRDO96K7Zfl#k4O*0XG8Kv0%POyy1+? z6IRg`D=ntfUU;w7VzY$OuHm!gW%3!94|T3wv!PE{(Sc8pO6tkXC7KHkTeq^A=Jw4m zh%DJ+$HH2QKNK#l_yb!{BeI6W)=7!*e!Gb(bZcWjs+9V!4?at9OY<82^{_bOS`$1% zX4{^m{WR9Bw*7qrUL}Md_sAuZHuw3`UBJehcu=IIE|a%snPD8Jm5^crpxFAci+>I2 zu?ex4yW08OBeP9%-GQ0H@t2_BupD+<#(eMBNnhug1?n04Z)-P{sGx#swZ8+&>fgrl zct-nf&U7JhVX?htSOaV~=sai!*_`PxP)othaq4kTNcVh;sR0hyNFQgumZ>n8Dp!;G z$n(8<1b5I^DADIl!qMs?#se~58Ra)Y(&{d>3GSC&Dj^H&&u(CSA- z)joN`%e_ILfrs>>?HAK|LrD?;&A_8oArk zIATZ=nXrJ+cdCwZRP)m<)R|r6+&bw9=fvW}Xt!wGIjKgmjS}hmJ+GynV>6L_XdLk<=b`&){LK0(|)Dmw(b#bg;$^aL~N%LkUxiIY-am+bvw4T2;R-f4)Rb9kSX*JluTS zUC;=Zcc`jAp4<+0F*^n?2&Govr-M~$Q+Yp3>7K6y_F1R*+o&3m@y;}!g`-RFsGC-U(+YLPe%2le>yOYTmE5a4jTMIat{?jxF4^r$_btQ}`@q5K_h-)F*|V@1 zjP&C7*-?k&vg2OcMpzSt3f+BSN;2_r@_aL z`rB5W1mE;uWla{wc@JK*e)QyIRs22;Jy##pW6rXTmie@IRrV1z zugeUFIFUoSiWgfr4rr#`E+x-$U7ws~jL_@nZZ=rqv)j3<5MREl1arb4KLfKG}xwlE4xz-=RdK`kcE6Hpm)EU zT$_Ep3UR}^-NafP*jGi7~dgyo~Q(1r@6Kv zf(|}6YS}nn5?Eo&Z;3aB*7qSoaFmTH_bdmK$%L)Iyq~y6e)_J9`GTV6&{z#(_chs{5SE!^e1+2yXlT55;Y2y-kRD#btGF%b zO)dL`W?=Tylny-0VbA)4Y@FkyD#JmyHaH9|Hd2z=_M8>rL0wH!G_a5)H+t;_oWSWY_H3$fqfw9j7UB7dy6~!WwM2H}Rk3hb3rYLQ(h$y_=1LgJO^H zSOp;ow($qTEUWf!zPB_HCb-11b38hAOAqmghK+)*xy%2kR~Du&o7cR zHZ(M}9Hve&`kehHXM44KET1}FEQjzo0U-%u^mk^={$wUeEHXJ+T@JHY{8yYwF_DF$ zabp%WDMDvl-h^2S7~Bs>zq6{ZlDw3A^$!Hyhy@Nor;Ro4UiE0=%lwMRS^ukoVcd*`|LzyKK}h>(x*TFC@WT6 z`%6|rG@ie=At-+7Mf>O7pT7ixz~q0h>VH1zUHto(fq(Lw_&0+4&zEADf3oqf^gln) z@aJlMqt+3D4f?NF zod1k>C;Lx$_y6gE{RGEw7`HSo8d7&(U*FJB%z#xZ^rfDMAiSUm!SU%i6G?ieih7O7 z7jFL)G&J*JV)uzD#9x^})^#0lYB( ztci%gU|<+7XiF^OSd?}Y_~-Tn1^&&~*S|t5P=5LIo19#vBnp*W{HjUuA8M#$EP3t2>KTYzcZH&*W|q$gthyHv~lb;9C6P7D+^v|{!ag+FF(Mejp3;e z{Xbgurtb2h|7g{(WhR;7JpSRKq3XOm<5ta6#+{v=$~xmnR|W)W>*@>KiwYQxxhu~ zm6%nceMj-%^V3^b+VlgUCAnnmaDMvvIRA1w!+pVSim~2WgI%d~T6#n-^JtBHw8>s; z0sPr$VzhUHa*l?Al+cw;Lkb>~HIA(-EU5s1g7LsvQ)5?!kOVbNxjCOmXF=)1oyj(s zmzV{?bMSd}Pso1@Q1^lZ)Td2|7j;N0XyM*BwPLE%TU; zptrK2-pa<7{22b6B=u)#v|x!{ z`cS=0cJ)2#G-{+Q3D0$lTGu@TG{A0uyA~L6xM7s6Hpd6kCLFpEOV$?ETu&|ciAuF? z{6+wNE1UcZ4_2-!LIoqD;|R{%+V2TAWYdm zdkm}Pt*Gp#Y@+$)Yf393U#$IL#e6)Ep9F?1=E^wWT8E?7&I#{Xsx9|r=mj*pS|l~p z2`_!{Xcc+ETGi@9>sb)X$?B1@+U2TfBp>%tZ#As$&v&*!@ z;rga#M1)L^cxi=eHz#%{=T+`NjzFET$_2T>S^!_m_X7|}H0J9>}v2eKR8$(elj2c~xLr11iRJLj28x1U!WZ=c^4fysz8M=3a| zjhd_Q>z9TkI$)f7`YZX?vV3hFN%p4q>T$R;&V-(~^L0@V+4b(a!gj@4*HM>Vi+IrtM&%6mG2eci~mz*|>9LZq%?idSqOLLX^{+eK*QpC#5hxQ0S(+F!42{Af;aK zm8UkU73qfIW0PhNNibO8^x14~5rx1mgwgA9rKV7oHt6B%%^TA@IWFhssn#}D_Mgf3 zky7Y)Ed4N+I8!<0Q_K?cTXbXqKsnyZS<$a67PR=pH1ae*XcB;XoR`1xz`7j>1ZzUx zp0`t3=19~()*64gfpEAdYcfDf`pR&+ll+=SsyBN2|MH$SB9kDwkW`&O%A!9H$US{> z8jAEjp`4IYep=0yUg9xb$zK9oe>Knc33#zKj}Rm5gPc(*iSlUd*D2G|t7-mYRnO1~ z9~Zk$dnGt5A7|#mQ}Y(yCz4eS{tGl5>HU5?xIaw35G$SQSQHgGs66PsyXEal7IY5N z`i(+95;M7a=iM%0bu>c$>0K7$&|{Zb$kCqESQg4sUSeDSX7rf*ePEF4XC!TP&s(Et zCVA0c6fJH%)B_O`e0oJUD@1bHk^*2J0c|{$tt`(iNDH*|;d#5@`6#7IxzUS7WfR|A z6v*iv=r-X!m<$F2+oP)lxTCqR_E=c}Uff{NfWM_>6@Yu|gFKWaPw-b*%hXqL3Ixt( zJa#@8B4t~GiABv?kUK?F<#772xpMJ^uizcig(|Mk8Tp%PaIP4lVZnE(h(2`%j? zSo|jUJ^f?T>BkM-Z5RchzB5=;S7Ct|Ym>=`;`irgzYg{&b%)kjoFJY62pQyZ9e;|7(oUFxaGieAPyFVz!Ro=fPT8I>!sWb;B@O` zR)mntFzuN?H)1k&!N*<-@s<$fIx7BLv!;A*&*P&nT|s_kej4qcv6*wInTMX$PuG&{ z8w@P0ejea&r%kcL*SotX89L89%N1uN8#6Mu%ihVJkswg1_UqDOqeEl`)3Li{kB?Zp z*(2BGxXB%-V1lb<*|!Mb68-0^d@@YRVU>2QxBcL;Ny8AW1uNPFA%} z+2aD-6DoFd)J^md#o180p+2jwWo>o`PlF#aKM~Z}Fb5l5@|C^M+pPL9Am*dQeIMwH zI|H|3&(SsNSt6*(+&mCZB*}Ratftys#{nAc(k>EII-S0}KRXuUQ#$*hYbxbK+Q<96 zF!2RYe4Ax;2kk(idyf3>IA|P+vwOGlBEGo-BFUSyfIy5g#vuSuYL;0WGJ5w&fz8XT3Xu%2?$(?K;2WEwV$1N6v^d zj}3p1^;`OOV#dmWO-KG=j<38QY%b3*K4+qWQIz1fUiR~kdASs)_7qT|dcs`op=w7J z{}m68?=Km`W)3{~5T^aD;v& zN7!^dualkhd+a<|u_V~{GPd?NYm9`mJ59AlVma2LkZ)$X8$&jQdO<9EaR?|?h1s5& z7rxpF9sfM|u6LwPc~dH8OtnS?_7E;Lh<<6bLx&YDwltY*LFqGZiPcUNSW*!L`Uti$ zGOl&G+H!*+l_!-92_HT;y9wo#$AGN(4#ucwQ|FWT%JT4Km%riaCN#ZKYlzTol^2yn@ypu^hkU*~se*IuKr>Ax{VouX7;`*vDzI){c_vZW1OLOKv+Vv)jHxc^>Vc zAeP#8uNod39)vIqR4`wYKQ9l`Ya_MP*yTjl9QDGc7@4+hwProLnd<1uQ&rJgPcsv@ zn`fp_BD}K0lo&W-Dn{-PQ5`G1*55roX|QzT+GZ?W_pTcq*z<%YvQ`TT7g=Ugv+#Kj zrYDWgeSI$fP5Km~{rjEX_Z^!UU)R!6O;KQv0o!z4aUXTH3h_^JBr9io1Uov`_`}Hu(;vt@g#~ZjIs4s7CePN zZPp%BPL_;8yn>sp;E(1?>otU6pWQZiPf#x}T1!K_3=JFPio93+@h?N1F2v>n&k}}4 z_^bk7{4no}FA@66D28D6`HE-&Ch##-xbV!lts|VkXdT56=led#aBEjBF(>2MZ)hvE zyGgPt0gvs9v(+4*4n}B6fH6Ap;ZiJDQ3I!VjkLxQ6MM?Hk!>LlXpFv0B+Rw=xur-~ zCr2sT?kZ<@{;naupd<(@J?d?_T;|b!k$wVCXN`fQ!dS%np?kAi&1qFJL%C3`Txo{0 zaI|U)>lswJN9_mPqUM&%>)Zj+uN1wsPIc@9j=@^(RJPBdZXrHz2on&0&(_fnts@~W zTrzRC(*Z0dmM$ygwkflpHhHhe62&cYtZ?1E`9#{n7gOVE0z5y&1M1pX7Y&zn=qDBE zCd~>E`ug_E$8s5YzW~>a+v8l#jt5kzKUN#}Vgazp7uoH~MkO@^;_!u3%3%{M>8;mp z?|6=LP#4om`de{M7*FnfUzdN71v;(o95#RN`=z>ZSApS51z?~_ppdJDq=5#~rCe*r zukx<3qXQ_04fNe!Lq$4mloykUu{au@!^;hqy4sV>!L(a^NS=dt2%Fc>%3@p6mzU?E zssPc4SCd50DChI|#P(f{cg$xKg(I3A7?Q6mdVuAH8>7vRYqmiR=W;9Q7Rmf05pKq9 z!Z{aLqJ`10u(04$D**`cOzH%cP_~CtWrMODzY&D z)nT_@UzsuT?evHZ!9xqhVh@hVvY8Yz3u`L{LhZV{hk{4A3EN-jnk{4Ju7+4Ms#=HH zSuFI`+W3eZAdr?7leH-eip$K?!%Z9Ur<_s?%6pgUQ+4c?)2w#w2<{XVWy3mVEld1U zsPj?U9DD640BM-T%kV}^JaO!|r+Om8;`T0}{i?1r>zT;c?YrLb1By$+Ys!1a@;Iko;cXAi!F)0u@&+co z5c{NiBcbk6mI5DC=yQ}fPD*%&2XSy1VXf=*&YXFWNArHc_hYZoQKN%;`ByGlbR_{eo^P&jp-_;is-ry!CJwN)bK=GRJmTH7!cxfu@tWvbs=nJ^?{ zSb`W6H*6n=%Hhx0^qhX~5C9*%VsXt7FJz18Rl2yAXP4P$%Y12Ko`!1jb}83#MTkT` znFs(auJqbGzf&WEaJnQ^Qv%?1pUZng)#z7=sC>$VuVA20x{s*Ht%`T9v43(Go!te0 zeAKId5VOG2-kP))S3k@nJ3rE!5RlR8TYYz-5Q}`%X;jNcXDS}0pn89K=_9v*RF)t4 zGEn@_`1desm_gxH;KZLD`cp)}%f!XgXA?J@;>$A8WkqvAewQu3RmS1=VeR`jE!f`5 z>T<#m7BrI9>Kfa@et*pf?1`3Oj6DXVMLBe>EKJ8^i3Lwij|%P{=_3EGYbQht!9g`Z zo$1E+=}-E#^=gN+0ToiPkL-FZbk(#Lq-rh*dLsw!=F!%o5FtRex)#5&ziOy-c?+*W z?rX>8p@1pnf(0qb$Lv8*1wh*QRfm_+>}i@I>`hYY2;<0B`<{HN!pv>vu<>fGdxfw# z(3P1X?8#Iw9`bZ?8~Jc@vpIxAw?FyjeiH7Ald8VDj}M*A;7`>l8K%h&E|aSY zTp}$t*D7wyS7@qY|Q$zcI+aw2BDY>Y(0&FRY4Iw}yiX zk4$I4SwhZDl8?u+X`O;IZ9lt9CGR)1RDYLLw6%hgime7+5v_A0*`dhdWp;Vx@GeA9 zt*C%7ubPpJEZMB~>?%Oc!EX97`*^#z@TNULxIZEVb*RN40KN)+INQ5#J>7|dQ4mM` zc)fc~Qc+&4@wVDQLtdqO!1LzEeAnf82@5$hMaJ88hG{&l4{M_Zv#`w00DgC(Ww-58 z#mhs;-3;~7u37)wfL$OP8wWa>W4@wh(Umyf+{`*3O?j}GV_j=HC~1o1($|KgX^H@t zKlFvhBXcKXxV8K`nXkjcvPn!{94+BFdzAR$aFI}cw27x!qdBaDH|4{8tAb`K^yqe; z=hY>?Ov-uti1mJLa?9zVHWScj9bhJ5PGgan)>@%y*wkN4Xgo+$u|swzhw5J2*WkZ! zG$!NlX!%OVO_MV~LU**gZ)|2s{{E-6ZDki^EM6*amqsewW^8HV$i}c?yzlTdENO^n zyUyOW;;`e3WRXd)re@szGk^ci{)^7Hjw#^Ifc=fE39XWIP{_uzz*XJV_vN;8bG|SB zN7xld?37p&U5#nqEi>}>$j`dh=W03MV$oT~acsZ#Jh?@aT>&^xvEZ}B7cpsx=%ULT zn`#{cWQf_kmtK?AGnON_JdB0&dlUYU#)~ZsNT-U>v2>rEDqvcabs>>@t}`0_@O(IR zFtF96)~_ixdu$^e#iR4rMP})c6kNf^g>662)4HRe?mo#|`@|;wgSLjXo~7pjRE&1$ z;BKEckakuZQgYiHTB%3#v>s>v*9k7?Fy&qAT*^pE=#LdXui~N)03w0UNiP#o>7FZv zBIsgGuur?&4jA$>_AB(ZO$P(kO^~A=U|KBqLjsS?8~yAiG_Q%FMzIeWkflGeC?q7u zTOb!?Yd7Lk-9-j_MSn57fZDOyh0NNmN8uUfepfpeVZm8jFA`7hn=TicA6QuO@zHdz zH~TNxieDVZJuOX>aTe^t&#?c3@ZEb^iFqdWdM*mV8B$tx8=n&oU)AEzA2|dlU^2U? zY{J=G$L9?ZZ=*L1PG{dQ$4p;?KoMIBR&N}LN`Gdu!FwAnxJ7Mt)3-sj?F$eth50H8FPU3A$?IU#@{mDVjH98ZgR6 zV7o>}vAE{VJ6E1GXR`-u9=l-Ic2|~(BGirS{vFaz!}(Z1lypuU>vvLkP%X**p#DSyA zm_84UMg#aoGl$H>u%~tQ$MxloHii3u;!lZL1vWMcI8`^lSZvf*jpd4qzmBEGXY=J| z@Eo&Y--=Cq5q{CKTyv?>o;=AV7S`LM9+ zV1xXQaPMKbMyGva`08YU^}|w}SF(;IkVHsMQN)NU^>_@-yj7L-uI6-1lvu@C?2nL= zaa?r0r%l~zl&Df_ei z|DIVPqh*U?HhQ>=8xfKYw75chMrGs#+d=A|HyW3@xEvQ&uOA(g@5`^}-lg-=H{cwC zZT7j_a5>~klZO1d0CvSvOm?wLLEIISn~Hr6XSjwYbfxx*7$WYnjAZa}vA*eJg5G?_(4 zFH4BYTXp{C^IaSD_0AVCg{0Io@6~JZ>ut#B6@Fz1hiQC=m`hP@GRO?FxVad!54^jaqAAA_wu0WZ&uFFb_BdWru`9rd{E7)Ag2g65{rC5y$msC_!}&eyOuy^3yq)Wtd;9Iz%E6Ws?0hd&5pvzeyF^T8B> z5#Lu6z}5N;|b4A6~9 zI;MvZ;ghTI1F_KBIf4%ad){=liz+ie=6fO}wF=~9Yn%xY`FwBBnHeHo-1`udxV!XD zJ?`i@P256vWDQbBi=HpYr%|@Jy5F2^wt|FgMLCzL^2s)=$))UT07Hd%@$vD6y>}XS zi-V-QcOf2zh2A+rI>sZ=cOob!hw7NTnbxiYd!$d5+dyszKFJR0l;qbHjw9_Iy{Gk1 zqIj9EjXU{qu6NO#p;s z<=Io}HTQfa8u7KLS#uZeCv*I@<<39Fq|yE(7v5~H&+mz>4*=|u3=w5@&H#|W7V;Ur z+D)+BRr~<;4DU=`K;3Xx zk{SyDFy_Qu%UIy~~+wGg+4u9}H6-R)G)r9677 zU`6NEiOF)B+7JA6+~s3B8lG$8yoT{0mlO0Pw|(Dcw;|`+$$)aUd^rCF;XfqN0@dQb zg=iL+T+HZ{pp;n63hJicEc0zto|dJhZ99o3pO1Sd$Zb4z@%v5=P|@7ywYwJYThyJd zClu3X7l-kL0Jd7cJ+3D^S#LQs+7cudYI9)iC%%++3lv^dJLuxgX$e@gT)OHVTJym& zf>(w|@xpnt%1-Jw?#9NOs_N)k$lT@~@g=^^QNJ?z_6^g{nT_V0>qKOEO7D6oh$qCO&>=2zMb+CF zNyoCz9UdzVLWv@r*$5?g{h97l;kf+yd*DqO1Kkgsm?KxDt*&y@lo6l%-DNSl%gXyP zBk>*2YjHUw2rLCWA%%bT^p_P84YxchDI8LBH}f<7Bx*q~dN{%-F}(bd{rgPtiOxkQ zuWE+oP=bWbvlXraQJ6aB;sB%d>tr;DN|sgC<`_|98HLkyiSGtvc-MXi4MNB%cQ8Z+ zUw6S&btgbugQ!9lJf5TZWJ?+NR+;Tcfi2M09 zD$CdQc)rqQY760L_#|wzcIz#Zd%rLp+-b6}iEZnLrK4vE2ojpN8;S4f{eZ`<&3EQ5 z(nB15{?P%`>1~1TEu>QhnhF|Ngbo+A*S6O0jvemTT^83%0fD%LwEzcbz1Z%uf^3|0 zC|t=rA*imxbjwT3lSgfZFD|t)CsB91uT3+x^nQuaFQ(8Olv9WN|T58SiA>S4f zo8)eZ&$7-u?h;Y%@z>LQW%;ue8tU*iW9OQ=7{y0P#ADJQVn74TyiQ^Z*SkGn@dJct z%RJ6DC{G;7u;0eo9N_&h(<4Z_>G=^Y@^@0yu8M3uH<5p^zFxAShzqKrK^v0ND<0EA zFqlzo?~DW6Je<`fc2!C%m65@x)$a3WVB0DFUIw1v*CQb;|1l$;G<``j|ED|Qm4ib@ zb(a^zfY#mihit3LjRwN~r^|6vk2A`FxU!9Os}ngu*@$mUBORO1*}0 zwX5I;Pg}?LQkMHIG|$%=6&KJSkJWrfq2HyvQG;yI5YY0N8QK_qw0WOx3F$lL|GJKu z=6K8o`>Zm|^H7N{0eNEb(oa#BYI1>lTX326vE8YLE;UxNc?q|wgs_zSt$VG`s0uRj zh3w;8Kg@q=ahl6Ep=|A;=;-9VFFpIHHb1qY&^(Uz-c|6c?|oO}fs}VOHrnyj^@?jl z=u*X#3H0Pg`}v-nhMtXb%3BLEn9{%3CJ1U1sVSvoN4_EU^aeLY=xt66v8c?W&h5MY z!VE*ptp-!v)JNm1I=lpkdL2?^(T>Dh_%PdEy|tb!m_mXFIK=0{d*okn-CyszVl`@+ zF)CPT$>=8!=@1ZQdT-F9T(P!mY$*qNx^>Ok`5b2>*jsh3v=Mv97TYH9*uPXk+N&oZ z+Ynl0@F3jsK)yi<(n%&KgI>3{jGa1so0-F?^YN+b5)|Op>j{66qy!7Y%cl=;*&^}s ze$5aWvteK#W~wwqw$$C$pCiD4BIbbq4Ev7KlF1b8Z|2FburN1?LB*^&V7L|QFQJ!-fVWYZ<^yy$6U+5|1$Cks1!SQ(v8gH z+3aCM(x!bs^_Ru?9ZSm0i4<1AV72~4cQeDX4}ec~e)C%3d2kV_wup`l~CcZ18kAb;rWh^C35MDMVZasw}#39?%?zAr|1doC?CpOrK=fm9Vv-_ zKd0kdR3(?sVnX%^i?Cpl!ZetK>y5`(AP}vtIQkd30|40S{e3Idt#Yd&&>Rt8LF+-c z?*S>oJ}O4&$3UfT^D@0^rXq0!SgsCNlxM6F?j# zIyf%?%2da+vbS~Bh4%-yLy1!q3bh@D3PNiR8AKxAlEm=6z={`Wqy@Q^g z?k67;ASqAc;inH<-|kx-w=bn0O?V?N8ejN*2%1`Jym5v((TF&N6XSF++2CpmL5{bu z$G%j7RPFX!nPn>fuS73YTy_Kgr3Lsuk7NKs=vLOSTa9AI!;Ju9jV$*PCq`8D)yM)14DXB+ou?ZPUEPy@< z0=%+wUByHC`SXSHF>1?J0Oj`RxU0V>8BTuuuoK-v9=vUale31DnWNf>Trv(v=1^HM)?@mrpP>H z%^*Y2mI&Gbt)3;cPFt4AQwaF~Zr^z<=WB8DERv8aI{|8&5O}5s5%xECvA2mBB4gEQ zO^qh-4GgVMADPA}6v4$+D7_~&4sTw+%sWeNZp+&0zdK&0`-X?MiiGEtR!F7$)Id*8pW!C)MJq2Q!19m>J*O0(FVhIh< zsA<2cw*G}3luWwNh{!bgSoW*t0~Zz_Qhy&a*hW&jtZv3N^xOu2k#>t&hom8NypZMT z14B#Z(dxzyU36WnoLv<6aZXwNgP1j+dSz(=lh(Ttmul+n9gW25hr|dt1`=hmyJk<2c;ijC4lE zXUUv57`h!%s)^v#MBTX=86#zt0`(dpx8%L8T}5GYuqlI`edR=)QVHLlCaHCKUSfsu zk{Kl+8$o;2xC0?0sQRLRZy2N;pUXh}!*Z@n^Ox%IcV6}7NFieEFltd76073Gz&+Hsn8vs*1Pcf%40yXU(W(>E^?I$wnJ zdTybqXyOJ8m^~~p+tsfxSp~3QT0S)|_cGNakjm_751iQ9D{Y1M))5f)0W`w!0?EMxN_-Wpb!lG1p!*(aIfT9RS4$R!CE@GISC0h zGS1IHIIAV_s@FW;%z?b(&2`f%z&CeTp(9TljR}XfAJV>~0r*4>?qn_6(e5is>q9);ta-YZ)B^vn#Wy@Q{Qvld|E>6j zHxhpq4kt`6k>F}p2jA3<{elmlQs4F^SE_e6i%cgfVX$J!l-vFa(f?a2VEkXmd#k9p zmiFD37$ms6gvQ+=coG_ScXxM}UJ2H?y9L(w+=5sX1rOnpM?Rv!37kSQ%VYasWC^zS5r0rYdFla{os--1)jgL-4uz{IIbKlv=I{ zPwj`)J21JsD^b2FK&0+iFyehDlm0-^^%H+oi5p_RX7ExV)BKmQ@NUyDJ2}-QF+Xa6 zd(fqhl`#L!tpoE!EFWK%(k22EFeQr(Cb&IWhSr4RMzYqzIeyl#_q4z+fb&p_JJNPY zw~-r|8&eN&d`Z4#j-E4QY%S%A3kO%@a7HHbA({1!;489w^KVF40~(?!G!nXI(Nr`8 zJy4X#O&F0WUP%b|LxYd7?P15G{vWA6=_t&10sW7H8xAgfhmC{i(;F-N$dnWU#Ziy? zmp?A3uX$fnxOaSx|BtfXVBF)TGOphw(w!mmjSTfUj97qaqy8$Ez4{{-5B#rK{Pb7* zD{XD=u@6&`@}{(cF9$nSclDvh52PLgD=zq4=fnw@4hu42=J@;FOi6Cn6$( z9X3XZgei;vTU5`@Rm@2^>{0*v$0YUn@4|fkO%wd!^cor(^72v;L@eM`o>EAo??mC+ zg@Y?#j1ZexToiy&8h`a8Zlik;DzLqR`+-gEz02?yn_(&poiP7{PW--S8T3DFMaKry zA6i0F#FqYl&=PNOIAB=}*^^pd;$sz*W^;1|5m}A@sktAozrt?xuaIvSIDhpUH2htg z$(X+-`~Rf>W5B`xi&QX1uJ7J->UFUG=Rz=j`e}q|yk@aVFdCH*FR9~@FsRpj|u`EY{L=%Q%;9QC8} z?+0mPW22?LFllvJO?dtiUkk=BXhH03ZL7b3_nf~^MeH1o|K~D)D4yi62??g+;=QoO zY>@8i;-aCcDRkH(ld)=+`kQxvC054YmBfltZTsf-#qf8wbr~=)czu~`gczW4QZ-%kUQJitW&4I!;z>uBTO3NAH^S*jRB|vU z1PmBV^t&2jRz(bedE5)XuJ$}c+y4xquMdlP6|eE_ohV%`d$Iw;$~(KSedXI}gIa1$ zoxSfpcwl{*atjf+%+<04K(no7io*nU0-Z<~E)7L~J#;-Rh3u+94;j_HQw~sL9Xn$?7C|jICyRc?t#F>kU=~a7aJOy!LFu})1v`}9-e^%*v87X%ccK@PiG)(@O2m< zu5?g%sI)bzVDH~1;Ofajjlx6Xouo`6jwaM!-^J*memx_NDq&6gTS#I`Ng5Z?uJ)?y zUHgFeJ^zs7xAw@o;*-wx?!{(cNc!(Qf0Gimf0Gg=zex$7E+W*$8vddu2PL!1w~;>- zh%g$jh4ySeuJGS9{NdeD=d)B{>^ysE2uyf##Z0z3eSrXETl)eRx3nKz<<2MhD)*Xz z*@s6ISF{+$Z%FyTfOh@UC!ABvTzPxgZv=*kIMa-fUhC%0ET>o3ofnS`1=(OGcB91Y zPJvie7)h^t>aZAk-YD+{9@zr_E&d3!ebq%p?Rr6(NU;v56<%LtwPk+d=) z?7<^i;QeXku8B=_5~Oh`$Q*UyV}j&ghO9jCi=4F%Y5!LEM(0Ubbgv+|NA3J=#Jd!` zgFxGQ_VEfH6b<|a%QR)VV;0iIIX_%eQCHm_Js~$H%C;ighsjf@^1!>{5|~bE;AWxbT^(; zVGiW_HRAJS?Zx!bacQmuRVM7Gg%*yH!$;^>F#dB=3xAaLp3FVG--{T^k8dS30^nXU zGphN=d{uKq%E9fH$})OWs;kpudAI{Uu2C*Vgg^k0*JMr-TOWG$c#8;-M3c5%`}d<;^*yTO5s%=VL>O$ zDXzY3=5euc>>JmUG_T?}xs4x-M?DW@UT8H$nO+|f+7nCO6o-S$%*%ClI(@&9>_!}4 z>y-c0`f;M&ynH-ep20&H!lZLs@M}6rztCE(iDh0RzMy%8g1+m=N54`Sd0wO~_qpJ$4X0 z8;cKUH}ftycMD;FOnz=S%Utmn7Xtubsd-iA^{JQ$<5c)vEKnY-cb5oBptAsf1IG|{Z@;ih;cz1 zb7ZGNgQH?^Orse6O7V?qL08HBHhv9v2X%FQH7c*;f>S!MG-=_Y9_^&}WXxz)+;>)n z%1+i`)N#txTkTE~)A!XqZl#}-*Wm_-^IMM|rUi~qRk{rymAm!ku;s>dm@4H}y?BAzsp?(x=+Qidnh3Orun~ z)Q{4`^3CIMTciL0dcW-+AtUw9{FZuzt~uXhmiK3ViJ3n+++4F~S)>9uCw*_8*QSEW z{U0}Gd?1tZ#O62b_9UfFm@RB-YRZR#3@!zwzTHvUaq&ylnXK-KKe`hqgcugf`6!-@ zLT-0{f(_Kh>=zpiJB(M%S0+Zz4~rU<$V0)%cJpycmOBqCdi_X|S=U-mU!~=wik*Li zpUQ5Rs}+m!J-x9rwKGMEd2f_(*k}UaUpZloDi}}O1OjzNVWGsstyTR^^3XuncZ`1K z1=?udGuyJIgjv+m%@I?XriHNkYaQdDN`j z(e$Ng!te$GpZevpL+afgrn;o3AO^)m}226ftw9SYQ5vF z&D7_*T7qC)Mv(XNF^k!;DM2$%UQqR25*N2i2?9mlBM+4pLE8f!H30z;qbRhU2 zqqH$RZ+~dyuS=hGmEx~i6ENR=DJ~6w&~lg`ElM6X3Ugy()NX7|1~BU#_|lQf`vHZojH8>)^P2;I7Tt_a3$L3Sfznz%ngwb?dddeQCHmmiaPFKwM8-ae&DV zu1$^6{nVAUPzS~*Om@^3(DMq9U~2bb`Zo^arsJHeFCUXsciF&T350ER*c$eHzn;pr=EMeT?QPiQD+?`>{ z=>Nqp|(d+ z@6y@y)G!NZZPEidX_&8M0zH4E*?(AUqV~oWgNYrYxu&J}``9dYb>u~h;|jlm=l3cy zq%Ex`HaxU$F$7Teg>s$0w}E1z)RaDkSZnVu#%gmxSE7qrkgd z?zUhkC)25kB1i6z?QXCzk~BzCs&z3T-j~G~Bw%hkD~)y4wJp>kAc&jwvwph?9U~?D zmVxE)<=Ep{*4H6)E0M6&H$*bj|XxPAw|y0?Px2pNfF^5lgvqJ zP$3?#MUQ*>pwnS%ruo}8RrR%~qVi0gVJLdVgS7-c>E>-R1yhU1#)k>dk%2cZyM30f z0@IF1^MUbx4=O32J-vcGUa;IQ^FP-U5)QI+7&9cXc^He#j9e3WA74Q4CwhnUv1}HU z4zO;`*@?{Vb#5j(jEtc7o~rscPg%W#Dg+009f8KSs{G!_WZX6n9mT1G%EgVG>oS(t zNNAjkTcd=T-Uh++N=%Zxv8RjL&ON5YRhrGFnb4~scfau4Jw^5_4F-(I&k8jrU`2v~zLs7y*rUEU^TdOO(A&bFOaPCAYw zIrohYMO9_pUeolq7SZ|l>OwBWf+ZO;IyxGMla~?9qhP$?=3k$22F{%m%-u-c-1ZRJ zh@QW{O7QI@y8moF=5z}t!F0@jaZUP1>GroTA1>?THof-|BWo z*25vsOMm=coJV)?P3Bf6*C3|4B=S>j6Z$80b{jMt%1Ia>LAB>W>s52 z|259y(kU&+ru<{yRQc++3OdL-Ux*sZwW{t&u5M(mbt5N@_W1%>?WlxRV4#h=_NSo4 z+&4GZx3brJ-Nk`NpGxj9z2>YD+2f0m9CwC9SY$0BO77aF&Hh!w1M`IU){m;jW917c zKYDs*)!$+iz8T;tnb*m0m_r!kLk?plo_}Zr>I%Q(wY{pr!!} zAPrbFHqU2NK{#?R)SKs$>N&Oa%)974ENc3SZHq=TyY>Brs-rI6F&39;vAbs7_5*y{ z17l_uS)q0IQvtY$O+*d^`? zR=Mu^VX6yz8Nua8I5gDbfI}smBkz&0sZtd#bbwpFy-GyI2gwGH>XPZ+!rB~^rMgLi zZ*JRADK?8yF?Alo>MF{X=DU*`Cg&gZ)_><%*<1?P=<@f3(RD7^@Rt9W*DM64vwu|_yn*`B^^ zCLc9dtHi=cnXfE66s=AV0W*54loXF843Dby8;qpGB{-YLaNy zMbFLBts-epJyvlmV@vPTtE_5`EY@%F*XznD_JrXxR{RQVUoRt>FIW=1mi~U;U1cgKs19%4b-PM-{;H`31976)ql?^8aE&4NODPw#m2EJXE(oLd{Abk zao@H)lz+|#9lJ+qw%VPRgQzCocOd^n*y|9F?HI%{IiN%&RE^054mfizD!z!rcMszT zv+4~6Y?S~g#i$vT5hL+MQwt%Dd$TIepIW<&OUzvjg93+NA2+VX4Qq053CvXD?T2Vk z?3RC4HIY9JTC)yBIC(#w{!Q5N4-OQuufJDeC`R+$(aFx$X_G9&m;_Y>^QADA;1k`mR`4F#TQ$s>go?H^ z2f3W7K~d=dBh?GuWF_I{#9XT^X~AbR8@h{J*mdcoAK`*tSZG7!}`P`z(E%^ z&70vIdEY>U-$RoQ3oahb9U`8xiOt>JoHsyt4>GjhuKER`*6KwmT6S6H_uFKT_3vow zlT*e^%@$DDoMB)jvtH<2*E1R{v{)@oA^?%R$S6lWE|Gp=BSejw57b{3FZl@}GKhK9 z{6`D0E1lBB3Jp#^AanPEZ|vCkk8q=*Oc!#@Kc2RtawN zgbzPYx(~llaxGRocWpmSlg+xlBh7=YgNX2`Y$7$AdD-1+vnVC;8&beI!jssX4%#(U zR~-5){(Mt7H3$v2$r@9)JFiaxQkZvkY9l=Zvta*{fp>zgui!N!Xf0E*dow!fyYZJNA| zifk`^Np*T!q93PLJpK;)8;V&RYbTFmvXVa*R?Q!v$(b&one9Yvbomff!YrNdlNi$B z+m7t59B6TbH0897;d3`3_6< zUp?pTFOk93umzv%>UeUOBX)0E%~UG%Hg~Sj%ik;s#>F$cC}ymwW&}|JQX72y2RB(T zr{qce)rakx#etN?@!@Az?yfE-4!$(~dmyMsv4Yte=iwCG?rnVOVV(tb0nJMH)Yooj zE*APWwdDl+UK6&EjSF$3L!r@3TOOY^zBPy7+aU_>B%f)N?dZ8ahy4Ywy5piS%$bZ! z*L-KHq`d)_DGbNqipGijj-1&SJC79j$cko$9_rxR7p5f+nKx!3eJNG(mYKXf(*6%* zkb*BiCi2PoDc+) zanOOurXsy^)j)t>og806k(X_W3P~znq4~Y&$$_eJpQ@~xTwQ~;v};*4J5}j{uP_-+ z3FYDB`oQGSIIX3#Ru6D8BU)W#@#^aVjU+%*STLw-8e)t^i1{pPSH*s zbENV(&=gD7Ab0lHGx4?F!!H1#P!H$YtZhgaESv+XUPJBpXh9+S*E^uh^0LQ|j?Z(+dKn^ z`C!O;wYjw#x7nd0DV5!DO69?vT+BeXK%qpAKah>gGH0keWG{ZBd=K$x{?%f7GMDvc z&09WJ*ecd|x-boDX1p0L5t_T)^x_pA-=}7<`)&2dDQPzc)o*IlPd(?~^N?w+<;(;e z)Zl-yy?&UQ@GOBm0{0Ix>S^rHV2kyt`!+wf(wPjCD%{{=`)AjZyIX$yQ3avstrGSN z6O>DKKw|E57*YXLJGQ1QU|&#VLw4_eOYk#5U)XDB(@4*=HdPEhS^YWD?ZG5fZgRF` zIc3UC{p>I)$v3H)ZObRNAw?q+%WMcYq9EOvf3%Us?>u8{X2S17oPH_(0|gbJhc&Q6 zr_$n9!<)V>R(JEFnO4Ba0bFc!{pE5hA9dUO`e&VkETZ-GGh;EQi{^1FISC3CDPS#Y3trnGkXJqzi!`m&$^Si zzfQeUUAnBPZgNdonraJ~+RO|cbw$?Vm*rAC^QHg_{8Vy3)C)<@HrvWc8(eg4Z9D5hL+B<}49|G8BB!S_SJZIXKZ0C=YI-)-HUq?BieXDRVDOIH^y#ht8R}oJ$V}bdAtr7efNoIkj->KXTFi#6 zr)qafD6%yz2dQ>tAwLaOZT%DYsAr`qRJnCxmnTtf=S~|?Fd>;LlT!Ul(;-C*XW}Ox zuQ@NUt#<5{1&d@tB9QcOPW|HTOp$G;Y6rqHh;11AsdgTV-VdkVX^GRUVa{lh#AVTC*D8T(-qstR)eXOt zlb(N&#e{HFAkbTJhr4Qt#mEW7>KsCX1^1R)T2Z9hj+VTW{Yzic!B)5$&3c9GL3InU zJ(?xsh{W}mMyFoGscU03L;Z;#?1;MNh?)|cFvcj{US)<3_jbYF9hZ2+2{l}8cAd^u zn*)`IF=D1AUtVgaAaF^AHt9!*?tLB&yRbtR(Q(wOoiJHGQB40PPlKtr@OTx*#)DmT zrRT1+jgrzd;;Wk12bPECd-FE2O*k%wTgLUyapKGn_9Mo&399GU*5&si7Q^pl<0N&G z9+GpV;Nq=?}fZ?$p9>BgG!)7bc_GVu=jEoE(C9_+gc z-u`$7_m1G+%F{lQLp>{_;=vMzy9O&)3-YI`%6cgq?MZsKtAk&?iPd?WgV^hq6%`#8 z`b}|Tisg5-CmP+WCr}Gz^e_qeo@CCQtCviL$?jX58oBQKB5hPPm)Cg?k^XF#wb$7sJOc zts_9T>fWjGE4a_JnI|D57X!G#w>;Cjk!SU^U^<)^P9}UAb9Kyh$WU;IAN5^p)D|k< zpHRlj80$ZPIJ$gJTndg>_k9#Bs?5gE3A3{b_hxG&oraQ;W^g*30*WApP zKwxY<8S@RySY>)X%y2kc%++Pq_v&gV1;`l=LC5lxN5yx%Q}N1m{`HX5vm{uTaap91YL;97}MqQkuzXgL-FaAEhLT1{6W_?m75Fu=BBz>ss95%9P)m zz@_B0y=x}CkEAB_6U^68JXH_HEY7D!(h${B9`kLah>}K2ygnpQFZFg4xZISS6R+Ea zSS&^rcoh)VvI^`yI*emk)WMd|TBZsOtyjQnFVt2g`e7dfmM=#E`^RFUdWyaQnV3C- z^6W8o2J`(}F=n@l=3=6nMOvDZUwx8xhBK!t&cw1+e)_)WBbt;bW~^S2#K6x9#lo^2 z3%bz7ZYc1^m=(VmGct^7OsuDh$QD?#!SQt$@UDy*8+cpgR^{+LZ|o~ilead)&Nryt z#{ANj;sCN!O%vW~7e%aqi-O?zkzO9wakf5QiOn<`R#o@AJer>ZslDVO^glsr4Gr2g zj?NKHk#%(vOPYJqJip#8_{a!IpA{d!no4w~6UM`dz4R*Y8ha#WN?YxY$rC&oiOT#n zO&LN1Xd&uUPBDh2ncJ;L))IV4fZ(>0 zcCWSLe1^oo*)>I{zYjHmpkNSqH!MuzVyjLitu$(>GT62Pfhy^rCq!n-A<_$J=%D=+ zd^%VN?_nYJZX%8tS1uvF`4QJsf^JB&VmyoE#=hOO7sal2zjO6g(Ceha3>MH>76?+_ z_)F)i1r-3ma`sk7YYn_D5=9yWWrs>TO5SE>uX=&Z=7*Ab^kQm{;V~4ScBSK{htm=t zF9T_GcH2~)E+=R56IsfuS~6We(p%dNjFMm9R%=cp+FMKUKXJiggn{P49a(ZQkIp8{ z=)4Je8G9$`VqKfbJY3Upd{1}r;`5_37vwsHfp2D0<~5S(baZN84eD^L$si-SAFH7( zCX-ti@fh}p`hlfOv4dE~mb=@{G)^nbM-wq)sGmMJS<!2)LD3FgYIJclJ%q^h(uE z#&U#rW5{Ief8tsTn-ipJi%4$UZKH89>n@%^kmhhFZj=GSxE`hu@T_sC(CkR`%7B#g zPgFK6`%|A|*srGbBbSBgh*kUruIUH^l)rZ_P(uDq+<|oCOFZ$My7%PkGb}E01M~Nd z$@SsMcSj4UgTxm2X^;1(&*v)ye6kvHmu}3%Et9q1u1DZL+Lw%G(Ccss&pO(NPBQqE zpF_IHTyoO%+9!t3*UtFCY?*>wu<4Cd7$*4`z6w_~_n4}*a`yUH`u0QQK#>*>S#n{p*wV$beLfe8PkQ*6R zk~Re2p+|noZdFO13C`kPOQX{HRMe+$b`RiH1bkaRC}Jiy$PDmt_o zaHjiBubjG7a}5)FwG>y#34J6N~l_^fTBHk<(=_a#wEZJKK=8#=LCfq8*P8 z@oKuA1=O$Uv^1tH*^Dr4-9Q#|OBhdAGj#`deg$gF+GY0&sn}vqa0P)wtB27*R|T z1vJr3XbCrIm2o*hMxabmJ3=W443trmC?4YgWAjGWd>Z$VNY%E}8eu%Xipwogzx1`m zVW6Y+2)4D5_!x_9l|t*eaOh}`BtwFIvZ*)FF5(t%&1(_=8~gt9DA~4aox2{tN8z3n z8H`zyA@n`2_koWy?a7(m3qN-2%4i)sx)k78m#MuDo3H^FZFCe%i`F7qjR;*0*Y}$% zkHc%*j*mrBkMHD!Kwt?@$JiVMZQ0s*bZv>VEcgdi9=A9bg^erx#s50^i&ACD4@yF2PuS&b7}_w$74qe2;I%z9Y1^l+4bN~A4dSVx| z1o|YM*kw&gho5=K0~((8)P*LH%G>uIU8K;jtqOl4DhgLY^Y z*N4M)6KuStH+!Qw(j93Y3)3Q64juVdOGU)}W}8mqY)#h_;j2QxeQq{49Z4N{tsA-Y z!OKeV7b`^dwhPX3HtSfwzRkz1R-edM&&`Ru+BIyi8Z0d;oc~hf+?#MB?2#SU@gH>{ zvXf*SSpzdIjof8PtJ5Sqo$eLNOUvLY;{cQubV z_1WMYESoT&lx`8zxOQEJ`$*Jjc6O$EE?6W$b;QnMGc~`-v76-2hnM6)BL+TjjvFnC zWj~MVEl7yTWl~?JrU1}C+$LG$#bKiLlJKR(rYAbH39iic+PfT1mGX2^mB+o|6MmEY z&}glX^rCQd(kn?;SS4D2w_WM&@fwb^Bx3oZg*Cn!#iPez5%+Ftu^)j|n$ z-;0}RRoOzl9Ifg&cN9zTh2@mpsTSX=Vjv%mQ{{_dV_pg+fs0^(jk2a@1G}sFeC#!J zfS;BjZlkMvt~>(lrLQWW%3BXRkz)=0TJ}<(P!-dHI&?VbpkZlXyvK_sr7KvNdicte z&eF8pcbM_$nbI8grX)(C1wl%ROzFNLCoyp!weX%F!p>FANw4AS{c$r*UpY8Wk2o0m zjABW~^fW~0`v`w}Yq?OUztedYC8vz{*%Jrkm}5^CHq^s-mH+yClMK)?hXn(YF6TXB zk8WN%FQt@!P5M)BIXS_j(K4pBY3MGhYKhJ_cklQ1S+`xwq^aNAOA|ADg@RB#=%p5V zqeh3ae3;vA?3#~O2GcTZf3v7~6?(fVpV0&_7onL2U(Wk&ulelCQ8z(QNQ*Hq;6TXz zRVMtU?o+%<1-5-`0b=O%w$b@utBXvT7X+Hfu%bJ_6TX!p?`Zu}oD9o;2-kkHnZaur zf07b2BrHtYa<}t%VDqaAE1$%zW1JV8Y_TVXP$Aa?SRk{j*B|Se{y@ycP$e z);$_}ZIaad+~{x_h%@2CY+=_-QJQ3>JHqGF+>*2B^nAp3MJq^&wT(ydkUHXf>3SYO zhfIN*a{5SJ{4`z3LqUL{c^@1sUrQu*D65LI$y0r_p$F|x6Y#v15f?ig&Kk`ah1mIW zi%E6W5$qoq$}m`z(>JN90;w6VPD0`yhHYo_NOY}}upgKpfE^CpOJ4yDD8}8_} zD$=)ug)N0pAHE?9|_ z)=d%1IY|c<9{akg;001jxT8et)D9cY@o5CBUmgBpvJAC&dL4H8~ z)#%l=O~(62pNhG46ueQq79Qb6?rRB@PV-go(u1mN9XB7#`K5il@+DeY1@p{m5&^LY z1Fj@C@I}uGZ>w<`NEn7b`X7FH9vv*Ksz&Rv!e!SXDWlR1YB;3$pvEg+$| zs4bS_$YA>}Wn_1mHYv7aeQXF~pey#@`Mg!L$#TCOi3Qs`81=WG(sO6G17$xh&WNdJ zJ?F%NM;&2_{Nzh=RZM#Pot=@Ws7=Qs#MI_k#T}A5RXP)H9tZm$IweooF z@r`@kMiOwwb5Q&dSDO`|;RS(XV-Ros_Qu8o!aXcV^*cb$1C?)tKT#{4>X)~V*Tz0J zt7qveihBSG%&EV~6e5iZX6YBl{m$S^aV(?1{;MS{Ty{o%D@T3sDt$)% z^()drG5iz9~Gvg*8JSw-ZJ|Jd>cyv86ah>v)ZP-E=~j>zyBp%$l-2begP!*}xR#c3T4(uEM#<4REelzOdfC?IQS9UZO~-lncelfn z;*ST}#qt&#vpL4^X5!fddw;1qYp#`+L?=FaWFJh9)X-BWEiv2rz1K4taK;MPN)TXR@1W_M2uR( z78=S{>PsoI_^qk#hVG${v2UdsjxO$ysFPYp)|lU&8sg@66{yZ5FlJg)$?>^L%M+ku zZO?@*g2IIL&wiD_W(XanB_&?MN$YECYrlS>7dEcf2K^DSRoI7zX&5j+F|TU9LIDXG z^`E0sPr9+t2ps`Jmfu!a2t2RvE_#yyo9Qqr-eU8NP-nHx$p9Y+Dr9*iBl(?=EhB1H zDt0@6ztRv2)^-v)EIV@nU(sjIly!5+f|h+B#GtT!`tOS!g!NPtMChZgc2-e#Si7{;4`5GUl^>@l2^>t%6QA6~p@QoupCEN%30P+xm2CQ^Gh5P5L7LOdm&x>|o@zbeEC z5Y^mE;wN=e`fC-FfMnY3qS_;sZRSA72^WJc{qgmSmt@`$>93}-n5QYuOE3?`po-^n z>@YP#vDh$2wnEi>?Kv#9-XZhQC^A8(T&Yi8$tPw*pX&{QR=un$~VpkE3*&3h(IbS8FYHZ}@{FEwa20?$O~>Ldsc)9hv8qo^^(t z6HP^_7^~+YIOPig+@@>FEQ>awm?PSo17_SS8c9wJF^p&|*zqLt>dTw<=^_1>Zs)$v z=FJ9%1MypB(vM6r;PC!Ne`N1-VbUmdMZ>?SF-%DV0#+5<7lRkWk3zUFyK;vB+v1Wm zAOP}*e)+#(TkCxZUae#l0%4hutgrqeuD%2q5gF zd{Sb2^}Eoir8Rj`IFFnL%JKm)ZSUF_-ZO)&6lRz-7hNZa{I@8`R~_~X-;2n`vf%93 zNhwR!+d2dP0?y;B99|~=#ww(JMMQ*vj{;I&J{FhvAkOKcHz6GG2?J)2;lWqaIbhnP zZkj-+1|YvP{bep@ zZA}!{PrRe|fWewFG(By;rQ`x9;yK+Wa?(#y^RG9HhuLBqXr-egz1v7|Vh;Rju&)o? zZKSD@ywU~&eY<~oQX>dmA-~x`b!xaL`+a7Zj|zuKw!-9$G>p_?WE={~{QiFI+t}Rv zyqZ3XDy;+FXMCs3&0};QCj_qFluTx%90f)0h@48)SMo#4DFq^WGM>r2S8(`M*odMc zBAqbdC0wTJ4eA$~_P=mA__AuT-owGkk5=p5A^v!uDTh*lc82-PO7i1rNa)5jFbb!kNtZX ztOtaLM?~Nw_f#5o#%Iq51>Moa5Ip4N3`rrw`ww#)f7d|nVKs)mFU+NJXZ-JBKgZ|B z#)=hc`c0}56Yu5A&${9w{&7!&<@!OEcKXr%zuDn34gaU%&&TKg#qj6xf5GT3$o{9{ z&ri_*?FaUHU`C|EQc4O(3L_R47Od0KIKJIEIIyv|PZ~76KIW;ft3!49Z*3cZ*?r>Y z1_n~Qjd-}YxVa?f7jQB%GT?<@qsPEf$UFaTBNVccxPGm@{eAc*@qZr^D>iIGI1O(z z($iDd(xOWb5plRJW@BexbArgq$XHoh!#A<~H}eL56?1h$f~&W;x9_81Kyp^W$jHdu zo%iA4p_*EdfZ@M6;eO)5x>;IkYL$jfF}5oae2|J(uhDl|Sy_Z8ihpyl*5ES^*qE6u zPfmgvx4w+e&CN|tT9}y${UrIfng5mDZJ=mI9Y+Q0-BW}Y{xa0Y?3%BZkp4Xhz7{gB zDK{INrM)_S3D-{Wm0Ms)NdNDV?4J~b>o1xT5grZ;e{A6D=0-?BfC3w*|49ZGuz~A; z_*4bG|Cc9(W%>5}@8}Hs^w*QOSk4eLgWJJElZy^nJ!%MVa`U>p@7$UH&EP4SMdl-g zp3lXrDgQ}bX=o%VIyNC@&N)lpifFahWn>;nskiXZSo#fUN4NSeZE_>|dGG$}pJKql z`6C&By%AikFtnh0tG(A`eOVj)c*7W}|b1ikx}mJ-{nx-2Kdp?v#zHZ-a%lDP5C zsRi#L<5*}u7Zx)y@koH=vN@w_H)s88C8z|=*vx9+z|Eo+RQW^ggSf$T^aLR$=Db33 ze5QPh4cfm&WyKeyP~6%N<_;v4TE@q6VDc)hcN#0WDK$h{c+`JZ^XC73hD6ieJlH@N z9jyS9Cv=!xN2H`>Zd-7Vhl-bOq(7Kl<4_N4)K4*hu9sC(zuWC&OU^Hgc#eMtY>2zSXe7Ef03EIfJfJNr>{r4W=-pf7DgWBJEB$wB40AG*WzryZyPa+<8$mx)q`RaJbSU@(rJEze)v}0ALsI1nb~ca zH*;+-Ni($er*~pyjVMmf710e9uigj4b2ZmfWcE!@Eexian@h2`*3Z0^mad|-x3`i# zR+f$I>5x4Z?WGKM2<5iDyAQQDyS0L>dw{3QGR1(2b(7Khu}StNq3or(<2bS6>0r*^e3GiK%hpEcfSvU-C+t=CI zcAu#u*3elT)~TP?puhq*iWbWNv;2H2x-cf?vta2s{dw1?+@3gcLv6Y(V5YsCg#_mq zf_Qz+0JOfJpydKMKA4C)8GZkAeSd?U=U}PII~`AVl!Zn~JfF;0;@^V7$JH zY3mE8kbcM&$haYYp2c_s@NA#Qwdx-j1ho=9j%+_1b011qM%)f2ZYXVTkqSg|J}-)B zqr7$6#*no7V8~|wAkMH=id}Prb*T%ln|P!_^yBXG9MW`e@3}ek<0q_tNFNeiawQfV zs!f|7xp8*;ll<&ArAEB}wK68RJHJI&kdxza zjP85gJ}4oKchNq^BrQHTA&jP7?S2^&L5c!YX=1rMc4H%BUb@Su@8y?v*C9_e>Q~{E zk_rKj9+>*DK+u!pla#IH26Usw+)%nOfHtRA$6BL#XEFc);_Zaer}ghe^;fWH$ev@i z`k%(LlUt;7;~L2AVZn@Jd31PVO6FvhlRR~rXS*|GZq^2o`r?!2c-QbkEX}0$*M)Dc zmL?7O3+$LV6dw|e4QUc9v?KnBN&u^B0sh~&bB%u7Hqp7q&d_o{T>Oq#{JGkcU-+OJ za(u)@3D^=|lRsHoXX<=CT$sCZtN!2$E7!*PzSS8R46K`ui2V#GM9^Nh*TQ{2%FE(@ z7Htor2nSm*U?}dCpR?7`^afiNGSRf*#V%gjTtl-Tusoe_bN~ah*z+QD=71*BtZmOj>nU4fOZ#8A~oIaL%{?P|W+>CQ|Mm3T>&r|vc-{Y9>AU%zFFq4)nb zlOG=mcW9lnPFK(_%x5T%m&ExeZo3`%!7PB-?P-lx7QplK#=}Dr&T|4fs3je&7Ihx2 zUf|vxco`2fV#RyI9cT%%OuhnOz*?wtM?Aq4b%6|gix=;<>ZY1#uaExRXW&JY$LVLZ z;Sm}3ON}fFy+SW77ajB~`Kfh;efD5c_!H^#bI%vndbvaP34^h@6mcP7v##_Tn@_7D zDqfOv9%2uzqqj4IZgLoO~o~y7n#VWv-c5!gCYLc|=QE!2o;fJVYx!KAq(} zg|w074oD6b>^>K!L7=g@i;=MpMw)k?i2|Qc20WjJ6)e zjU46;^OHbf0wQSGl8a7$nf4@uQXw!oWGBn8HSYBuhz7Bk?VMwHq8yzAqklj2?EH*f zIc|a(3*&TU7HUb)alQl9RBK6r>aWYiXI zRa|uMY2$lcE;iV#&QLK!!0XkV)Tv;wrC1>|-1qe}&$MqPUw}T&^HJ#1kv_@% z#hm3r%k%u1s1xs-vYTEb`#L#y#t=#6I=jnpt?5|2=TYC-*p7$T4OudJtm2kLzpBF} zyjyqqGH+jd-m&S84NwaaG}m<<8eAUSMF|XU?B`gYZfOD6XEJ1*Jo?R+{HxN+s^zwDUwfY{Rban(kDYV2P7%zL- z22^09lG7Fx&?ZPu0wPI7L~^E)D6x?!u?-u^AV`i%rpXza&`QpTgr;erCFjt@2D-a$ z?fr`HIpd6PjPKrY?j85Xtsg)!s@AGCYt1>I`K(!U!3AV-IgO1vTahGmagdqt!~2Ob zsj*iVGR@wP(QEAL{(BC;(#z`mcD?cPum5bv%0Rq;e;do!UoZW~%}tl({xh}%k>lq2 zx`>dFkdDJQYGq|*5HtT5Z0QVxi3>je8(UtyeqGtu_vF7|%LP})u=anN;H6XJPxvqB z@`y~bxpIXn)aL39PEO7%R|ZHY{pY4=em(U+5Ed+&5!Y>0XX2nBdMWC!-s<>nBO_zu z{{okvDDLljaB*?z>9s}=5k(jo84V37#RUZmN=uoSn}0R=<%4C5MLFfTiCV8eU6{4C zwYnlJD>%Be3yv&R;7x)Itzf;DAnIC8o{7~}`-}fMB#;SVqR-9EwXs=z!qwZ>_Pck# z#v@x>TVLM>6aEG`iZM{=S4ZZb?xibc6&Du=`~Dk_Ts{B3sQ2oxYtAT8{=fL{KZxUh zQ}7$kjTV7VBbCN5om3=~oUJ;#R!JGQhNc{|yPOun{(pC4|U=7S0sHE?ALr)-=N8(}p*YUQ^%@)7K;R>P!om8YM z*Wi$1ZU-`tgP~!x;=p2rd+y}80G!wN;T*`c{X7_w(;tC>EDU2Tzp0MF-SXlMz3S~n z;kGnWguE!;uxq*Zb$#>7(XLn#Lr#F}{`NtkVhb8qqt^R_M8B1%p%HhT#uUBYPVMa* z=!709_E>0FQjfpdT$zce%MWEKR(_d$H*8bHg&}f4Ps1YrwAV9d6jDBC^>vJ;3pA5= zet$YTSPmuWDDSN_k5xy1WhT!?`)$9-%~r5AzOqFB8=FM)`KaQ3M`ABCUAR@5K}Tsw zxM9`&)?9Yd#l!3s$X9uF-FDPVzE{qh_qAdHuDQX~HH?YpQmt0SOLjYj(4M!_y41Nk z|F%+JECsE=K||&j=t-HX=yDU?9oHibX;hJ)osvOUGG$9IH%dAV7dPVgd`mWF z{{h4)2Q^io)A%l}srH4M`k^I=l7O`;R5wsxyp~?So{&og(NWsm7?hfqC zqlkqgQMzy@3d}Tb)*0JOyqZ|(eVr6WVFMkoUTjW+2HJzNLy@qvN)r{ z5BpDF?FD1_ZVg{AQ~gI$roY|S35;R&TZ+sow3~fAdLd9wjdzMsNi^A%Ff86E(-gEQ zB7Wu;2VII4pK0OyazmR4w00#}ZQQj_2fm=CG~6UbZlr|xNeU&s4PI_;v7eZz&849c zG$`T{bS7Q=HB$3e7m5;xZWY|je0x>(&CXG_pj)S=owAJ$nk$B5^qj9T1kupAHC*N6 za7DXV%!qj{<%Sg4Z_QHn^98%}`;FdeHpb7wgdR;9q#x~CbAVf1iOd^AS_hC<5qxvS`NOC$0&71d>*xKwXb zaESGJj7~J&^6ovWt7G)pXvB4QSv)~Hn0yEgq8N> zNOi>IpJGD)NQL3dg>WHk%D@rTA3z=h?fLE)%YOyXL15b)o$3-I2`i_VSSBf|{`&PFiZVRb!{Zs%kClyJZFW z$K_gC)!#U8Q9pig>jp)zV&JC-uhbsKOsx;xhxZMvuNz;Br_}tr-U<k8(5Nwq<5Y>wHS;2rEFN#Pkj2R zSIsj1sEQ^_V1r&Xr`~XYm(4%dsfU|#3kDn>>`-gqiCfMz(Hc14wc_Xe(`^RxIM!_6IhJZrzWiNyY!E3FU=S+D&jJ_0!CZ>>~H zw*HcXWBQ}ksb6UOc#Aq#131E|L56EPf6mNr3wP@4r=)$EIZ`oGl~WeJv*StrkCk`7 zzBf0%a_Y0C+Vvs7JT}2cQ`+~Jd4gJ6{Zi!u&R-WjVl@PL{(p`Kt6jf{U@evSQ!?#? zRK-8_wZLm$k3|2g$Q1Z@b|mjt_wPc6m0 zmE_!u@A&%r`_ zXYYkip{JFVyBaLQ4E9tnzP6-9_K)qn+Fv5IfBQB5!Kd5O*g}N8&&OK30U=uu#aVl= zt*$=&{EVsa)Mc`8s}KM7=7DF8z9P)dPF26!9(h-2x;-@k-Sqjh{BV_s-YHf3=!*I< z6B85oXwqqRCt3b0e({n5Td@y51=3sp>phT`hOJgvl@m7lw!adNUfc405N}C?qq4W)L8^&H9zmo!od+U*T2kFKeg+s zr1+Ndjl8%&fLNy#Xx7p5H97hHr);^apAHHgG6^q?(U|R~v~otS$M^=g2TIQD!b!9H zd>x(P;m+wD#SjSU22D4Ufr-wxb-S;0WN5I}A<9L^`Mp1s3g)+83xH*RTsLcN&2GZv zNK2F)9GqNoudGKV!kq7+H@Abk#JO>Xw>YS1`sXH24z^Uml8yfy4+^DZde`@?US%JU z4n0NM`lUR^trdh#G(R$VqM-QC!H>2!m*^M9oS^`jjfMugd6eavb=l?+W%WJcEKPLd zZ#0rX2lK_y;Q7?MJ2}PU)1p@b$~y=W7CZ0sdr*r_$nqa4AGx7EJ?XV@Ac0b47=`*d zZWpbUJ>JUTVBmpn`!T^wFarlvd=~uZlPM86tax}%3F z+ns8!5w~$9^g?HGiRE6qzSh1)FhkOS4E#Y!p4|xm!46xfJCzh@ygXH{Pmtw3UNOSvC^*;S%XJ9ML*d@oSC$>LUg|6CrW<9b8M4cdy6O#}6Q#2f`*>*Z?WUhxge^h_NM=^W?wGF|KYI^THR`xt>G@+q^y|;kA7!H;5 zyEa{3bkkD#ue&&`=Pj##N+Z~7&v|MdCYhRL=JSjkna9+d_h<3@VT}rNFLphD+3#wZWB#;w=69$#gRIxxI6C`IAlFUJ=2;cb`U2w;w)%)GSgrZJtEai?fID zq6@cPhd0Hk?7XM!^6-?)aUo>4R6^nf2sl&u&VsDR@5P923-KRSVtUg_Cp)m7!K1MaeW+Xi65P+PIqe;%Z8b8#6;)B(^n5pSX?nt+W8&v@In&%MCD}WP zD*N`bYPC|~dqZ(d(?x<%vb{Z3wds=K5@o+s+4C^nJkM9VJGg*(Dk?@VT$+kr$&~1F zXm80HYGXgmXv2)Nz~6j9O`|j%VbL~!vDAHY>SMm=&mLZ@=h-Ax4xnC?EiJ16WRuJM zF^z8AgZITt9uZ_1R=;K5^j4`Q`P=q6dU-m>3$Hfy$&@k)Kahpzt$#}8F7)=S~%7AZvLwh+#mOS2{UqmudiT*Xxm|5wk)!>{rcDCU(F6B-b=o6Cm z$w+5DcHC&l2)Pj~;z+{wIvik@GNf$2|32qEudQq*@j&(jojhn!c!>&m99ejb;7EpJ z>joK4a{(Ig$BX_jfq?ziA8e>D6r?s1nF+-Ql8Ra~Vw-C9BjW`~b3N}a&ekYHc#tW@RU(ucVm1`2Ur!J#; zRZ6&*$bPP*>0r+|+fdbrLji7imS9;k2QIr@^i<{$B9`)Vzg@6Bs`|BB}cB;7v`+|4+>bh+pGdC<FQQdx>jbAEZk#t%Jl zA)JsscAGu6IOZy`bCfzw2W=T%!NIAb_`KSM;*_J=yOz`Ac2QA%?pQ=|fZLvW6qrWp zw2Mo-yDN}>92(p;Pp^lwhMp{A;V(+2Ry-T5zqh_qQcU$YpL&0X2ZBaXh4FrmBg4A34CP0`BXXVX_qxuvG)ubzoN-08IJn$AdV&|W5Sg`r+y0n%2lI}b&(yOi zIJn_Yn9DW~>@|ucEWIio2aR#?&1*ak!;=uQiP^KREf1d{Pl& zwJbQ;D}QilN?VsUU}8K$-+)24B4DXVrBB=@oRNRcWt6eYD)QWm%`b zwmY{2H!A|88jlJ@N1+V`{tc)24ypkS;jM)9Vq8UdIL<4$4mLS_3icxerCqEUt%j|< z?@^+_CDLTfQ;swrcJ=AEcd^p<4kT4BG6=Jo>Rn5-=4a7w_DsbOZFu(X9rosh9if3f zA#9JH<8_*7`HwcFy&8P0&q%z0Uxj<&k^Z@MsPWO$^8)=pNA2ReM&xyyq0OTL%w_;` zM$aNAUlu!CCeO}M!-=ff(7>K!N#{-S1M;@!JGX27CB3Dk27h>e!VG6+TQvqhqK*m{ z&a?6h5u9Qky{eX;Rz3ad5k`1>=Ven(vmrSUm%LIMK~zG?D%Gkt00+Gn7bMO(7Zf|M zoBH*pwU136tM7K720{`T57&6Zmpr(-v84kf|H;wz1OIOy*Q8ARt7eZjHcEcnfGtKR zXSL6j$QEu6linNVM+fkEfy8^Hndh`&8I32HQLX#?D{Bn`0{$wBR^#Dv{V76yZsyn?`mI8UxAQs~ zr(WlEgcm|t0D(YL^j;)Xtsc+t!W8g4~^Ao#LHZ(N#d8pEWLFhZJ z$tn+gzn4IG`q6R)rDd@|E#dN8EL{|Npc32-2TSx~?*f+cDcr8bHoDAaZyohak4w1{ zx7911lgsk=-WEcBQN@TX>ZaXFua4w*$e5g{E3GH>PJ24T57V8l zU^Oe2C#R=Pjp=Li2BcMvWieGQ38J5gm;$dSb#t;?yK3~55dWjr@L4+z`mnCWo$vdi z92^j~qeVKu7O_&sV6Qf%y zK$CQPI+Jn1!M5#&OBnE4b7!o8{urT0{8U|g>*6^M4thCRyT5dZtKCdVw`cd&`R*LG zB+3*41%c<2dHwAAvvCpiq^Ea$@7SrM;g#PS3X5bIoqo<<0&;DH*X=!je<;5E=-H>^ zG=b|0sutr;Sr^d>0I`56iB}6+Pbj!;oOLBU?SSwoYu>AroehzAsACdSKd2BEugAW8#JbU)+LwuE;t<5jWAnmrP;o<Phw#xV@` z=iO%rNY}BkG0y|B(|Rt9o8e6{PR8{u9(st{5v--cD@xgHcA~|}7 z;`g^-&DCsSYC&#Nrp~pM^_UFap>=nu-5pnErpRMbfGJvoa3NhHH1pN{^!4?k)}W|c zYVSPL{%*0Rj1$s}Wn}(2(Cj4a2Gs=x)0^$Q9Lc#W$XRzOFb%ZjH!y)pT^%Gc`nmmv zrR481jEKl^a<*-4E$`1w5u~ueamPmC-uSG`t^Te0sS>L@=#MeD zEw2XC?nTdPu-oFQd#4;vstEGOiKj8fI!CRE=^@&~C`+OGd&~badt+-0`}zL9N%GhI zAhOB$IAUw2R@~eAc1}nc{s;B`p}h-t@6`JMWRe5AnI5WpxH)y@@(!(1dG3p3GkvdH z;^OG!e7oZWXaMHhw{MlUQH_m_dSdI#Lmgn^+#I&va>#Zz`${i8imtjt6-CCLJ6gzc z_7@VeTV9T7NnO6ZhR~1Iznx$9VtxBJuP5E=XQ3mCZkXRkl_~rT>s?6{j+8X@3-z?M zJuMEK#;NfW&6~wTRHp;}Mq6)E5klh)S#3@*Xy&S zwY4=X@EO|*K3|J0wgOqYIFRGduOd@xrNM@|)GGdBGPFWQH~ z8sN&B)OpzA3%|{JI=p#Mc3iq^A7*=F|K1g(utR()5B!Oub2EH1ZhBQ_e|AOlRq}`* zQtr>qw*j(8naDAL&9^P7tSFOua@_SXCJqjSbSK1_hEdMpYwXN)-O+xWfO^uLKY8mg z%5kIfx9C>dK{GepY@~feNU_s{{hcm>-$AHEn#&|KUE1nBhML{qf0dGOO5z|hX*l15 zWS9Tmkjhf3+dwD#)~mxQuVO>c0IA#9#0TG?HN9uic1c*BmqW;PzAKtjWnzsY@F9Bu z;ki=#F|{n=Q~vT>BJpieQQx2((3ok_6kKGe?R-Oew+|N1B-&$yC@8QS&Q;G#pD5JG zXg02Orj35y`hH`&X{}e_kcv@g{x6XSiVMUB7)4{*i;hWpYEz*NmmOC(lyFaz`&^lN z7FQolQnlmUwt7|qed9i1lISvRnCe`MbefUId3z4|&(ViG33!glu};~^J0`n!SLrJ$ zT1D%ki>#T0RP1G+Ny5M0Wt70rP*m7|jVTr)VCCw~^qTgTSY5~3GR$yq8m8kXR*QAh zx3k*4-*wXY7V7DY1dsTeL9~u`N>_1v!3@R?>mhPm_j)kR#|{vs>@1_!4LtHNL2f5y z^ks@ao_dk0N`{-XIz^94eg&|Z);wQ-DHeU{RGZzEWHVsjKFJ4Bu@aZFia{wqt+1e_ zU5l`KiEH-fub+?6kRv(vCyP?39js$4K^aR*N8^?8%%ZISgE%EK3{w;n|rD_V6o?S|rxLQWRKw#;}q4v8xy=GEHJ;Mn`eozg+{d)wZ= zzEhZVRkehODG?x2GA9IWYARFZvKlL`ld!Il^wdl^i3fe7(!IUN3_Vs8|P7dVO5IWK+ z;z5?bQtp+_RA!l(ywakk&-aE_C$(xJl>KU_?6zrG?}F6fB#oh=p-SXm?2{YAOM5A> z=I*;6l9Di!la5d;P`==5%!7@b1TzEzAu4m@asUw@DdT%kX96Z2tb-N;q;o+h0_yzb z%RY4`LjrTOG||EX%h*~N`&wZpPiSUGZ1%kSTq(L^_`**=yB z-n_fWyrp+(REPb5itWC^eVNO<{=VrxIV}c1s%A0N^kKoq_IJU$;59PTP*LJTLqdA& z)m1(yu~bI{QXhyGg5zGGaS05&OewkOU(Pv7QgQme&wP z@oTE_S$5nwTpe8l^|S-Mx~frGS*g^vv^Mqqdj$+fK6jByOhm+BA?PaO>h4hu49B0j zxU^JgPbfVC*>1@+FfTb56j^X^$y!82zjH134c8OWSyS}Mo+POUQd)*eFjS;sk*M?D zMHN4Gb#;AD#ftPlIcN>y+(LX4A$@uCjyqTM@-Zl&afli8c@})JQ8H>ubN5Sc6g~W) zr_V4jDxMlAax4vjlWU=SM#6(e=IE3$W??Yb>1d#-mWrRwyY$8Sm$%8G3pVu+NTJBo zwFC6Ua}_v&j*O8?REUASSV(ZJ0CYQWBkpU0M#h|J?T;MswGFI+{?ylqZ+Iz$=<0#4 zu0LIEjc{WiW-MXNwy*w^*KBdm9hb0LV9sr61V%dfc;z}#xA%bKCwcw4BnLE6CkGqe z-t`@5a3?uNb}seg@$pygqX^xD7I1))Ta7fJp9gi;*vLrs_ytIN+S)?>@a;)SNo!~r zVY`*OxTU_nUhmjIk%dY{P0gkCJ!Jq&j+@)I>qBKY+IoGwd@e?fpHXDF?-`F(Y}NF{ zjEh8#6V@57>aGGw+ilXKNdk@CJsP}vvUf`DUX*nL@Z;!cbU(>CD%jTc=E>p0RL^Xrh*o0 zb?`j`O=uDDa*kya4xkIzug0409`17Y$)4^1qtu+R3rBud*_egN)k(|{lYm2#L(3p* zgYcB=-=S+Xp;Q_O7~<=|LZosvaR^mVmVRkEyI)y33@3Z;!k&1KL$W7m+CZQID)PIF)En5^!MnJT5gqMH zZX2v$^DT|E^gl(d+1D8lvrcy9l7T6uRybV#O>k^KyrR$S7JPic)d%*}`o(^w z%9%&}y!ajpQOBJkMl?P3rtuGt-Y#-nN{{%)6TQ8CTwjTZ*~6Dddy=gP_&#JeWG-Ls z0=QB0b{*&|(hRkPWS#AENxFQ!OMG~~SDTS7$+zX;gzoRAU`!|2{%+D3>Sr~>kIT*r zIQ(+EVka8LI{2>d7yQZLGiz*nrM)|<4_(+j5>dyNTXrIJ0inf6Mqy-gb2GSJq!Ptu z*%2%PL1^n)};ncy1C!Zd`VnZmb8*B6xt#`pr4ibEu|*!aEWl3&*vq z7r=K!TPf4zv%lUo<gST2^D*9!h6ZCSHe+)F zs;nMwQR2bF?!Y%aI9a>i@XgY?6FGM5?VV}$E8M8EwT6XZnhkHsDi`gR-$dCHbBxwHb@-+g1+rG-PJ$_s^=Z`^~259aNg0(vF`B znT2!5*ZK*udAkLg{|4}J$#>`xQX5h2QdsKvls)E znq79?wceB;twis?n;FJ0#C4&i^nUO%4*un{!bNIUDJ#E?v107@Osi#&``TFXyTfYH zcPBk$#9dBp69W^5aa}V*UE971OPRkm`tH>4eikGh`?iZa@8d2992Wc1ZyaUU$nQ9a zHCdMyxvXa-G_#wvZ5-%7s>&=ZP2lT=6p8o}XjXWp{R$GUukA|?o6#o`Tk3kT^{-(a zf$ydo;(_W23)WGl(H#2Qud*HyNZeu#@qLZ;ep4gTq3k}s-#@J%@8{^AD;2Oa*&m<3 zn9xc79)0;V3S35-@T090OeY$=wn9TgD+gs8>g(-59HQ|4Dn+0OB*byN76vr?pF|Ai zrHvU6S8ZVBY8H?En&ac+|2B=+=Q6;8VW1$wx|m@^(qHSC@->h4Fr35m-ny=w**qj^ zcda~W6r$GDj@~yG-}=ffFu}#qY9nCkV*2@a|4P^tRGak=49aHUBRoH57K2I`+k3P> z-J*(0uXb)>+1+Ovg+(^62+mo)&GWL}jyTk45JSxB?c#5of}{H-fXvjV zhY{jWySlo@!B4W{`PkF^4=@}%n+=6ZR&BvEM@L5hp;K-Gn$o+#B)m8)XxYI4jj&Ck zRnolCp16j$Vv%$mzYE`69zvTLGii5ct6m?ja_ejp&q8TD9EA<|Y=@X$UuqU>%7(dN zU|WgxpKP{2FQo%BK#{~@f)~k3b-@AEcv!t7G$%?U#CIu19?YM;+}gyfA0MR*kec3iFaX(aZFi2>KNsOyN+U;NRO01CHwID6e$IIp9#P0MZ+W^wR7U ze;3@fY&-4a>?lCtXlzECK6|o~0f^as2!3R)Ul7+2*J~>S%=O9`|IIYVdETd()GXE{ z9UnP03C_iJash=l`VqmC2Sn_ZfnJ*02Iu{=6ewlOZWw>v{t0^Dz>DRM4UMMH!TO|} z@xQiTJCm(qV`F1!Y1tE&@lqLQeosex*l3{4c90E&nKo_k1jEtn#!L}=>x3(pFN5EQ zMU~6qetg!dzFl(unBdoNtv0MQYOu>ZfVQfl_fEAkbIf`JxJ)3gRgK_a-I9J<`8iAN zvfFB*TK~oGQHB*Zw@wky$F`R?NvO#0Y1U*P>92;1{5*!jh_rISpESYikH4QH$}|5n z=_X%P6}HwXCGbWVYg5hG>-Bfi)HHAWXY#@&=2DOw7#hzM4Y1 zh6!rcqCbUY-sN~)SC-gopUgAk!N~l{V1Ha(Ra5bX>99_a6LXPJa!LMU$LFTPg<6X4 zh2RGo$+Q4dphQ;zd}ltXbA!^^F%hHa zvv>uUf9_T;+o zNJQnICJF>aVTWL&Him}XM>h1j@DdJczqC>ta2vzSD%8^`B z7`>Kkuu*_OjnLrVG*9gsXVWLzVQLo(g; z8OxH)ydC?Qqll_Oow>5#%apdtfi)mCiJbbhL z5{2lo7HxB;(lMYo2j6WeXp4kr8fjGSZ*;^bk`(INMX@q(y~AUd$xuAbpcoy0qj;+UxX&D61rX1rp#v;ykk9RI)7L~J6u?di|jN9 zm&q-?$A8&=gwRQ+)Is^FB!%0zPNnRep?N{M$&)7WFFGW#s`Zr)eLx4co$PFphLZ8!O zOBCs<9*#GD4rc{kB#)|b+c8XqpABIGQqZbcLrZDnzBP|*_4U@9;7nD@Lu!uEg}e8|hd zxI{9JWic?SX!Mf(Jbx=gfI-rSZT;I)WX{%st}}nS8YQ89d<7;R$8(zSy1u!`uNpn` zL6BU&4&rf3-zDq2n_gF{&NvggjP!mPKDo%? zYcHns{RB6UhnZ?QiNBk<|IRsz(RX}&^Kuqd7UF$S8&Z-S#R@2H!i^aL#cL8ZyrKKL zj#KWpj70fN;_#SBv$fFcqQs%=)Nqd4e7rBy6aeY)cDf~~)6N7e3*y<`usJKq_PxMg z0%ZkDa1KEhxB`>h(8PJ{1%vv!ZC3S)^smz}MI5kt(Bp)Ki3PX=ut4WW!z1}8xb1~6 zs|+CU?v{ezawcA%GUmyn=Be6hESEES*U^phj{*Av}C0B z4T*5Yz8tj>xLNZ$5@odtnj?Xe62{?(Vl7?K8weJcpkj|pey%bAXQA|oohd`)IhaM&KOg=zA#So_~ zb2A9de(=I^|}bK*8r{ z2l6|G$eK~!#4N_8f-HX$yaH4zm|bkt9*|4}%#6g@U>&k(M2v|J(HY&wtiW1%?bor# za~*Pzc@RLtGFfibD{>oV6HUgMq%ZN7%sI%NUk{C=VK zq-W7q#H<=2@=K}IG4H7Xf|sOeG#<{=j*qgB0-pJH0-=&zg4g{wSb*T=S(ki1K6w=f zyg(-lfV9~IUgAq{GXX(Htbp1MUITK7@^P4hEA>I8Ht?lb>ZJNoA7Zz|8lceKDR&dw zacdb+3L$>5q5HN$f=`lQWyL4Za@-OZJFr$90kq~Ap#aKiSAaQ`6$mPN{@~SPu=kkn zq*6v;(O;e!&pryQsm`LBz+T*mdHZB>PpnowpgY$Ie4c9noNkl*SvBZ@Arf3_N6w9!Fw6SOKL*Z9nvM;LMruECR8kh6Id`4kMlOvPSv*x-Ts80@ z>)MGJ12@Va*pLaVR?}mD9u=3ESYyLzn^w&~_ikuvyqCf2p)kymLhtsQ z!R_Kv!_L8Dl+5PF44X$OLoKIrD42-+;`27<#lFDI-UrNcLx>O@A68YF$_!3 zA!a8^PU~as?p&glS% z1b-niAGLtmkk$pBZ!m+pd7n(dL_$@vl2D4Xa`J${OT0idS#ErS!0qQ$fjg+G1fm=@ zndjJ>BFNC{fP<$afOMu9ClY(rF1aM^Wme8zklhYw8vaN~NnSn9uj&zN%NI-83-VYc5Xiw~%1|FZx;e43pK;?U?LQwS# zvM1FfbPzSVSWE&BO?5qJf{uQaA`r?*$#y)76HizI&TZUQ`s}!Cl=F8SsH*f-vE-ro G+y4PDg^Z~H literal 0 HcmV?d00001 diff --git a/docs/screenshots/providers.png b/docs/screenshots/providers.png new file mode 100644 index 0000000000000000000000000000000000000000..8db158e3da615ffb1919aada6586a8bc15f5baea GIT binary patch literal 40975 zcmb@tXIN8N7ch$B2%`v01VQ>3nsgBXDFKxLBGSarJ7}bLLPtd)bO8Y+H0dq$7OM0f zdhflL0HFjzZf4Y(_s6|IzI*R^o+KydoW0lDtFOJ*2~ty0pt!+sgM@^HLh%{+B?$?c zHwnq_B!B!yykf~Sj3@qFw|}PNL_$K@^7rRT3@;@k3CUk1ir^=&+!D5D-1T2!FWWJF zU+M2uJbCh+!r_Y8{Z@WOC8YlI6-`?MRpq=XSG_Vh;TnEio}OVZ{}2N8>g{Tj zo~4_Uaw~`W)8Ebhj4?4LeY1LTdFQct^lOsHvBL#FPxRMAgVmm=Cp%+(>bqY28oUfh z9)`fTkb!J}9|;=RnMS$0#ckHsg`(FScIOtKNMcfkkAGJS)t#ay$=#REPdX8tdzCFx zd$!5x6BDa~IPSb>rnKIJ2IE?W~}24zO%LNtyG)| z;?ef2JqWvcouE}Y;!U5eQRG;{bv57YivtB44R_YRxlXcKX)%mtXhr~_1 z4|W;wspB+lOihau@CZ)x(}ak;4)|TK(sriCZf+?;MgWM^trX}RH>h#po$X8zccK;0 zWe1M+d?t@C)TzT&HV0;@BAat8z)f-AORq+Nj7&qa4{oEG zO6F*PKYO8*2He-D;;sqSzaQk4SG(z?#=FI-c& zg-!rOB0P_sW1F5ma$5a9jSI1D=<*% z_T6KYzBvE#<%2cOx8c%bnzp&aE?ZV45p?xbBojXR`-3i9s2iB2FQyin z>&}m^lauRJx+2NjeJFX3RbRD7=gDtj|h!>e+vuokMo^Mt=FPN zX>c74sz*UpWn^TaLSX?E3`9i4$CT}6s>@CMNUzC>CJYMbza7p0S}LH>h}+72ah2p9 z&t20tkv}D_64Aj<4rVC%;x@9H#BP;M?I^_wAQvp|1t08&ZnWC5uZJc<>m}3Xc3`in zoeXB5Lm>}yA33%rq**cpbH51Y1sepvau;a!ZVn{E!xCkfsI_@V)!Br|9?dqaTzMQS}7%5~<&bjq!Np4{#T(?P~E_|uxYIfGcT?SZKvqNwHguxQa`MGB~NRNc% zU3Cay>?X~(eH6(%k9UP0DM^EtG0XBk2GiyB8U94O&ll@76<&AH?$1wrepu%s7Dc(Q z)l=%%}tA1uNkqfcuyMiSl zd{xUU*h;6u`sK}i95YG`b40@hn>~W*>RIMtJ0mncE>DnXgvJ{GCKh%98gAmJ&sjyvNuDg3*+O-f1%P8~jW&W+5?otT*5j2354Kf|&@W5i$uGKH+05!G0o zYyS*-?4YQ~t&42y?#`>=dMR5{QnKx;U~fM(nbaZjxe_g}t6SYTZ{TYvGfWno`e<&@ z!eV2L0KNSKVC(DGugR`m8$RZ<4A07fT3YJTb7}L9lG6#q_v%0jb-&#UuB_BbllO_y zF438tM(uCG_!RM`(V*k1X3IRKYhp(d9Jzk01Merp8}rB7ZjW8$|Ko>=tj)-^tmElR zx%V1UWUq<*Bc#?X`b|23VRMoWftL%mDWve#_Q0NaLJS9=k!@@?eE&P}81 z1Om|4@kEcYO0E$t84X@q#w&6a=cQX$>$gQH&F+(T7Ui+Nn(HX(Z1gF zBvub>K0X6;-eEFimVLG7u{M9sm`^}xX+^F(P&BY)(E$MXqqqxcdQHpdf@a3u_zlU; zN$)MgOK2K4q8jB`4fz~x^5AuP!gS@H@qmm%pI%6URq#}mhwt;*aDEU+uUGG`223!q zMzUOrS{#F)R&`DPyaXN-Z?Kw}WXrt8T9RSZ!-uJw`0V916(Ll-Mo#&< zJr&Crq0H;_7BOMobq~i?x_<4a!rV~8?P*XGJPVk(k_<&L11JScWBHNYzTvWj1bu+c z$Th}EPnjM+(r;gwWn0W{AfCyvl|_u%pr(z+#prYUp3KGC z37nfs-aUv(=kORaDi{&!OfA%E6B<+#r2x&!%<53>jsg`p52c=u8{R#WY}fKV9a01U zip_Oey|F!Y94|_A&6)K}%=@lKRLqo0l%Me6QZ_nbRYlh*z06;HZs2$5!zDtI8=by} zJtewK5)CPDi1t1FsA#2*N|1TnbCPe@DijS1{$}G0cC>z4Jy#);btrMT`@l`D1@+~t z4ErjK^%kh3di&hmFHn=oRU>@a#?3iiY9oBp>!&HoUMfMyaJkT04DkZFaYlK8f($I$ zJ5IUsyqbg}v#~-_);*RPTL}Vm@{~+II~O;rK+vgj9%-BlpV&DT5OZyvjxg~JkZFcE-tsuI-CEN;U^n0uv+0YvR`b9!G-12O zYL`pNj`4i#vQeup=Vm0EQ9shl_etoS@W7KWgp0*AFg-F*;iAo=z4;O|*71}p{seFT z3^#jjpSR>RHlE5_Q~p(d{A?xi`xUBiTUYx=UttfB(7h&QsamZ&U^LR26aL{M9w(ZMWW3fc*v@n@NRz! zU0&xGhY^{~6Xw%px99}PIL=*vG?wB%jUl_I_qi~(Dcqnz#myc(=^r9vJ1b;vPncg- z1~2bE!K<`#-6V9Uyp#7y?lp?_!IU%@U5yLXwm~_4S__q~4o#zHrLc56rA1b8dtf9k za^m3YSfH4g#I)?9FUo%JB>>Rbm3Y>(a&2r~=0>^%lD#g!bUX^ep-GIq4-E3lKF$j z$=im-r@7`WT-vg@HDu`V+rf&747SeLL5Tyqp)SHEn{5)QksmaRrQRx*|9N;44fBHG zgktPgka@!RF+O;_o1ZK!dAiw%ecAtAm{VNO#8kmtm1hmvZHBS5p$=|j4=F5Ca|WLf z7~IFR)A2+v3*aq#Gd=(o*go09>o648$=oK@FWDhWIx{B5DWqig$7l%rZ7l^UW;h6; zHM<3*?>wiR3&v{B-RSb(sOgM+es0N1 zzjk|t12Z9BqH#%I2%g>*e#vKNTOPE|!n8zxC+=+EZf8~X?+$Lf2KpbAcaLU7z-NnR zwRb#l!}66EU)|f+Gy##)hOEy0!Ehnv9fnPOV_Gi!cbNTHa(D6ZeXoAmsBnbzumM>xyQGLxK3N=6YRT*SXW$~=iv31U{YPia9)rQ69zP$L-F>dnyg_qj>fz_l z{9CS>N}g18@Hqojdn{ z@@bfFfh;O7UK|}AF^O23XLufCj;m1$YgYpoaWh0ObHS2av^FLS9L$5pReVDxz!GUE$q*XSy=%JJ%XBm-fSV$a$PeYRCVtsQl$VM zBPs8V(&X*7b8O`_klY6VC@lI*h^5PDbXJ9RMmb1TLvHw{piNb2N%4p+jg1?8o$+lm z^GKwm75?ed$@AdS!PbqQlw*^yM5>EOpUh>+jTp4E{mKQNVu}p9yhBzQrY6SnJnEA% z0H8FzQHq=d&F9;07sdBzCa>B|tyGF|?#=M_PWp=q3@3_@&F|2uzi#`U`s;1v{!f;&VLxOc>Qv}_YLBbDb$f1_KX#9hI0o|#Je*3r3GaVM960oM3@ zK{euVobIss>npvi%&(nXDj9FGlIq64>42&Cj%04BJ`&Uk(CNwHQdy}h@!7Rui(hXw z9gve(-JB?D>EdI-FlOzP1;f*K;%kk~3x2UOEJ=Pb9%mo6` z{o?HG>Ar-^mGue`6)!J(F|YFayeXtF%iR~$%66LYdiAN(e3g7!?oubb-lBbX=Bga{ zF--P7aR^BEEA8PK5TT9ZgIZCxM&4xcgYrA0;rs({(YV!zHj!lBkh zfwTy%;i|h&rlflWZwyu|Rq>t9Vb7W&Rm4LcLS--Wlv+86qm0nt#z` zqKYr?>q6J`2V3R|F7TSo{V!&|N;lV~>cbkfj>15&LWF1bQZvj`h4wvo=4j`}|;I|iIFYRN#lBdwr7S5+Xr{mR} zwj2AIxN&J7Naqs{bQBjtkKzkql&td$yueFPo3zi+56{}aZeMrzuDr_Lm$Lvebjszxi7%#H4$mb>Uu3E81Q0@cLN!OD^GF%H2Fjv-yLvTNz~F)H^v9N# z7BUvM$Ka?abotwX#cn}5x`JADb@I4^8#niB1U-zw?G?ZhqTbrb>M37NHKV5|P?ARl zQ#G)iqoqt{8S8OZ{3^PbTyRG40iGEUxi5fI6TI$72T(rZ_W*<$f(yqK=76Ii6=Cf= zK;YNo!j`D$b&)#1O1Sv3YI}C3N8~iLxjgC%egficW$4pMh+GXXlx{d(y$cYUBZS** zYDlxzrcb$jlSm4NkMn2Vj1Gi9%WM@8&FlPJsVhF^I$|;LMo(>x1%Qqja40SwT!^)2 z1w@7lBPw(f*F28yJWxxw=h*y|t#XABKI5Jv84hY>zrz_^LJrk|yRK5!&3WZW^o4LG7^@tI;rOx6cGNSwuVjWTI zu=;_G6SlVtim%4Sr|;^Y_M$^xC%rUPz8N@TUJ(p8Uok{Q=?ePA2^3BSFimq^8j#M> zJ3va!co!){jI5wIL58}sS=Y7&C&h!yE#Fhx?dRvfEV59yE&tcenS9k)1g6C8f;=l(AEVR0S%Zj&!ynpC z6ZiM7EwzQIK9}GE^6QpqmzaMmU6s$^4t8^M`~Beo@A*Td=9U@+GMpO!qiNK^d$;KeO-b}N%Ev*unr+!xHeZh&o9K2T_NShQzpy_AJGx&{kV&FJ3~QSD!`LHAwLQfkcPouzlt{Yq(~HqQzKi zo|-2b*-yE?e_6&EfayaSU&6ND#hE9Ob@CE#7uV1XK!e|X77&Fe1##X zrswixae`pDosSYS-){z%ygnDqYnU6)x9IP$v4wS(W*<+V^}+;dxo>&J^=X*mx7(-L z2ju7SPG%CZ5X;%?3)1nSO0IxNWt0PKdv7)PIH9_tOPw$+Zg zu+oYrfyV?IHXv{!XY|DcV|0vI#+wD@?$fD{pPqnpd&Ye#np3oz3z&L9H4eL43Ie!F z=0W7f<}j%bI<=2KKx*3TlFP|-l8PSd7?Hw@%8gJs&Uw}RNeF*60(rXb+)^sbwmcr} zPiLEKZGBr6p=ztuezK|dR3DV^J;i>(ztE`h^) zdBocaR}&qm0oQ|k1SC?mxqj$acBO>$K4$y-73Raeq}a0gc?NSdISc&XMICpyP|Ctd@fXT% z-%rG>#rQnt8})oxu$Xp1ia)TqyI+Ihzmti`CNv3cD7 z-l#2$`<{WJVUhrSG0ti2uL#vlH<#Wr6FN&r|zch z?y{s%54gJp!L>{Hq8xbMbk6!I(%U{klFfP=ois>Wj+dkTgQGq+!a zGz0x(VBfN~!BP7z(@FBac$AUjFy-D`86<%tIxY$5zB zY_yiY5RGudijBuTmiHji8Rpr^J_B~HW^?p2#WRq&5<9nsV|t2H1ZN^Je*Nd}U-n;H z8=ySRp072_pN_muCJF-C@ZjZJ!ggiu| zqoKi@onu&Ej&~_xri=fm#HLX&eBK^`-HdhcuZS+F_n*lt%(%^Bx+%lR6i(|9T@_Z4 z;9)ymP#3SFN~`=>j;UR%2e+UW4o9Dl>iL1e;q5&acZD6VV@eJ56?Fv z%v4Chvtk?d$LQDH$~Y!&$^K;G5F$cwN%`9cZhRXIIBxV@ch^rtt{ zz{HwLt4X!L_YqvF55ExvaA(FIakG~|Aj4b=3ruQ`Z7>BO6tb)zEEA)>zuH@GPDcP5 z#Hr2c@Xyy~7IIjInK9u9Xnvfm5+Plg(#^;6%a!LE5^yqB~`khXMMI}HWwDq z_Tz69jHf=8woY@>ph{~3$56ruSFT=n)V1UPu;ZY8eLP%;0P z&CA@n{b}A{=3l)4^2#`@-vLJyC3gkGn9K96+766mqO1rvHb+NU$8?{2X>p2=GjDX> zz}e-roKds$>@a6%N~_t1`)AJ5d&9B&Mt6yB-I0sKj48d&Xb?3f17u!0(Rbl6+TC61 zKGeqAbJk?MkHH*E_&m5oj%6+{FJ~InPNzFOwqT1Lu(7b@AK>eVw~}@)cxPEBmElsr zJ!dgi`Z78GQg@;lo#wW#Ul8!a6Fin1?(IhnI!o9P%}Osqls2;Q>UpNYGa2{I7e_NN zIJ~AtkN%qzN1&4p>}P!TZc8UC+(y#HS`R5Z+}c|9?`182Cup5YPSV%m1jc#ppO?S8 z2+HBn4Q!J~;=%f38=Jm=x5|5_ zrg+(!mnWr#AH0~IHN0&DnVr^Ar-4A^(#?thxBCty&$9R=y53|tz_=qCPW5IM+uJ9SXc^RxJo z*VHI#pV-~iRWilg*r;sf3H&inb`dUC&rrC#L_42OK>s14G?%5FH+XSpXCyl^nOKNv zvgsDDZ8cSXAqBnf=IP;4@`y%^6apzNEmh`pdiLz_xtH6IiPW|>Rc&=DOY(2zKdscx zCst8(bSAKt3lg@*!KrTU?xeq;8WC7u{do9uX3}!33vYL>(TM7gDpR^~o5d6O`fc>ALWMK0zdDOyQ zLHIFMsrN=60)H6?l4-RYAKq~6e7;2}<#cE;mEw-mps~t?XM3<(^uMC8&I)kWkhRme z+H|1eYH$$!RW@KVpRTTCY9>VfcKd)F1(yESw(FkxSJamjQF5C40KF6VBCv;D~c|v1N~>+4!4m= zb<4i6sVNrSmoe))OHuB>1jVuk@~sqZ+sdxxPi)t?aDQ59`jWocfcjsm40Fi6G$!Km zPrWMYG*5Ij<^d@`2ad0mbNVB14qS3FFdE;DXxy1ME} zX%4Dc%ey9|csu#-&*`S$KK~<;s=(PqXKnGbjOtsef_(6iK4#jzuR%fPk@=symG1f6f3=({`&pe>$<0dVd&jasAgSu9(6;Z9*wGKf0NHY8A>W^4I-yQ&QA zLC;cG<9uUu@+RG#^Ie<1cAAZaR5&)T9cQ~gLMzRHsazqr->>>W{Zk#@F@6v}h72z9 zx=KDttT{eb1e(qr2^Oz>E{!A-IEuEAlvp3kz4zQbF!y^I*nCexqw?9XBvrthEPDPZ zliS4xD#DrW@Mi%K@Pkkbc>vWMiJu|+))CC8FjR0hXv4T?jEsCIFaUJ2#;+yXyAvkwm>phL!YEwn074(nAl9Ql>7WLSsjAlwno}<}e0XM2 zlv>yJwUzYc)u$n}_*fmMeS5dQ*MfLYUpyO%jRG{D=zR>QA z^Q&NR52jdB#fTPgJ=AhSWIsZgadb;=`KWS_xnB-6a&Z)Z&5}!(8+*T?%;Wg8UQUvN z=BXV=8S6nH%9DE{!dHmj6&Eci`y+k%n+CJfXWLDIEa#)Iit@yM|DB;lOEA^y&p+?{ zc@J3c0l>J}8nsq0pwQ8jGT5b2?r&lS!I;pO4Mqahs=AjYs;(~>-Y?X{FK4<&v5 zN^@sEf0e0nex}y3&sEm=drnMgCbA3>DsOc(P0bqht1}?G@D+r32xJZSyTxf7@H~&J zsV~h;SSzo}(VJHm^gZz6;4xSyo0EJIWm+%Eed~^kr{qLEne|ifc>MZB&SQ5c=mutRbcMR*sAgToXX7wZv4i8pl%)>n6{)KYf(khz&H&AjvS zs^VgeW8)S2(*^iDV6(PrzSka^RfB_|!WN~q_MQ~&!_8JPT`%nHg&p=+0D_gB5HHL< zQRkz7onU8h`ZbLwBYJMB)KmQEsT*QiXB}>xLV#X6xN#ic<{f>z; zc|B{9!`Yb^5Sd+%U!Dpp_I+`E?;=hish%k##6Uu(^Zu^i+r3m9Y+{!6nbFvq#3g>N zZT*im{Pk$lhKbwagmF8KKK|ORsq&ck`#&{k*u-CpX$^m5^U`&9yX2cUf@Znf-#2z3 z-4W&Vk0Qz~(n(+FZ>Lx|v8?CP4K?}~_C!OWs(3XjJ{ z{8oWH$*a1mKF3F)+U}QO1s(u^Z1m%^m9rZ8?g-w4)U~SS_VnKQ`)hx^$IFLx*jdb8 z?oJi+bNWc;D$>ui`##F-^Fkh8Jd8AnN&2}lK{D;O-Du$AAT!+a__oc<&glt{gVF(6 znec{<6;@XAUddteaW3AzSrNC@Y*@{%FX*N9lvoSgXPUo_-kU|&*Tu{!et-uDiNIcp z?ma&0F(^FZe(>~rO3)A~8SOS{pq6dwFFV+NTi{5)$i~jws@20`{Gg^tE8C#)vA-55 zuI{($m#9+gc$P2W(QYQUj6lOnh%7k0S0lN;Y@vWk8n=pR^%XC6NLyE+2tHC?pKF*C z!I2*dI;PA8Htbbfe&4a1@tz_L5%0bC?c{f@H(kF#2GTU-7&ij`R%w^h$_g^r80QYJ zT|@;_`z6G*G?+i@VyK7=R(W1Inr-={Uth{Wzy~aZ;I&_Ry0tNG!^PlSQ)8CWYk9k_ z-p$fR_-hFTsUIAUjYtoTZG6vx)p+3KwM}VeJeS>XD#l2I7;zpj2VnMZ+^6yVmxp|< zV~^-AUO`3{>>n{v&U}L;$<*p1hdNju%#6M!cB>4$eMoHUIb3OyNzDEH%L z`ip_Rso$FPM@sqs>Y>5=EL`$VUi~jdfdr?*@0q?$5LzsqeiI4VyI-ke-Ujb$=^sZW zR68bq`n8nrE?I7?dTv)rqUF=LPjhe&>mPZTXl9+~K6p#~76>=Y#yu1mbYJ+u`1-|m z7ob$UhUf4n_efrmK_DU4bQgT{_KyyHCAM7yXKY~v@6x^`lr7yN??X-7wEiAL)zvcQ zlo88v-LTZR!E0!=7iwRX>%YY?c126lf&0(|7b5)wn{6vSneemc(!cgC+5Mc;wUQmM! zyaj_bJ_&}vn-}iEbIDo99;uGJJrH|NnOG>^xk&b(Fre)N2GC`de<`?1rw_bM=uQxc zuf574peisQinuLDyu$T4;SrtAwm!?h?REBvJhjWH(}T4KgHQ-WgrQT$K*MwmU8SS` z*|c0Nm=oPf#$Ru6=RZN*^G_(*%w6Ef)Uw zVg0e^`Um>ylk!0Wha+o7E^$q_gjW{7Ibm)vuIOz4PmHY?X~~$ufo|;+Of!`a;&#FS z8HfLkh#ThK3LMaPT>OuWq|C=;)Fm`z>6u7@A|^&ho$uq)je1H=126KRrnjQ^!7{~x+8t8*XLXUD7Na6_5t z1|b?1@k@V>xKRJ<(0e5rb}uQoror^>Hw&7~hggl;yxA;MQK(kxgxpANyTbuhU~!^e zsj)%YH+Eyps=Vp6`6!9 zvc-v-_x@Bddowk;89NX@4?Db5t&;fgZp?006Y8)qT%(kQqoafL@U+(n&TQMJQ{>G$#?!0CNdhPR6J4j z9%pIqd|t+Hx9g=YLRh%(I#ij{a_8qV-brL3>U&u!%{XGE;>2Lm8JT5H#BBQ|2K5Wj zCX3u>SKD5d9PZmT+QjfWf9YvafqE;~Paq`Oc^_QD&=LZ#${_AeYtADy*%;(${x3u1 z0!e8TGZ2CNbJJR+T`8^be{ROa$tNRM{}~Al%%=HQemvv=t#>Wu^oX6WzrdvYpY5I~ zY7yV6X-Qp8>QPoH%P_DvHy3vt4xVEzeM+NV`*1hxVg23ecf@5$(NtP8|J)DBw(Ce# z?>0qpQEB&;xsu;-C120C*vN6v0_ThZAnK*e;v1AsCH&rTD{fleTlc(cESZ1it=U?Z z5-`_CEwOpatGSecsS>%>`H+Eo3}KtAnd{T9C^%#{V_?(* zv?`^Y46ggRTrTYLFFK+N?(eb84@?+sX_z_vq@S&^2;HazQ`GC&o}0zyd9H|8AYy0v z$hS!w(@srcVfJo5%0OPuV1`KBzR=D~krw`xKm~2(0JNN&#SuuV>FM-urX{}0mC(`A zhd*X~$EZlLf<}o)eZ5;TZOPOW%lnl+3ZW4u``uqu&&O(SR;mYSVWSELvlD+kiLVy% zH;f#Ee~o>jyo?stkFjTvqEt?^^yhW166xX+DR!4`mmgucOI#bj?g>19dvMRXLlnab zv{N&$esjXvc_e?J*`u72$_~IX3#=X6DYScz)Q!-sd-l%m_LicxPop^NT5>_9@|SXf zPJhJ;5tGA_J`ePhwW|VOy`)3pJ->T!PS?p*ltO(39Ah?VncYvCA4dcH462l0nwfT`TjO!-Oz3EvI5!P>(k9kRT&UR$$1#m1W@gD7+AFqH0$;sf9GPh`x$VT3sFo$nR&YtD z9Vo(5`T56@!>hjAXML0JxJ+>Y%R8)zVyg$lme~;VP6{%GaMqz$;Fqz!H5DuGFm$11h$S1C&_qJ;ArPua){6#85j- zSpTcMqU=^31<*nH3xy!6to?!*+PM(jodw-On{A~xo9h&`Yx>}|G6 z)REm>+ihjd#o~+8vBzhia_ch{AKg0N$pde{HmO-XFxb`3%h_zh>2S=A)iFT;@9>Yd z+xtm6E*yR7wHrpZOmtfIopEoB5&02I<(7v_UDH?E^-p)6do0_`NkJ24wOf)YF>I}I z?4N!l-*}lJml~=kyi~0wG776$89l(`d4%6<6no~UvYvnc9wiG6B6w}51ce;0lh&SM z5_AeFDI}_Q6Fu7mC5RnJ+AFl=WMMjps35_@^ zXF(O-p%E@>YM!9`HxmHL;ek-yAlic?ef5ygq zSkRf9U{ct3>4mmB>B!tLYwr`>+6~YNXHpIGyiS#Vc@Z%aICU;|8&C{Ad+2@lO-rEA z!i*ki!=J*7&0l6=xaIM#^-&HfkzJke>J!f&1*q)^04?ZNiygFsse(}nteIgO;R<(oU#^JXb) z@z`sJZ69e-?`Ca0C|qQYi}RIjSVWv38v%q0J)t-uyezrdo1|h4zUOnn~+}{mfw_2R(O0@9ghfp_WZe*X*VJ@!A11tqHn?a zm%rupoy4;0RL1X~mL>Q_4ux1quS3=5Tv8ehgWLe`E`^9;Z`9mlg_WnghzYdo z+ho#H2xLp6=#37esD&Cc$df@zIFz#uIpbiEt-ED?4_JOip7MZtA3G9at}n1MNDy?5 zezrbt!b~nO#g8ZLIw)6AwwWOcI|<&c$PDxZBD?M8k5ZDV!KWGHT9nUaH&@kaV|Sd6M0IHuPaqk6TPX;XtCy1!-Rvjk42RAGAc~x ziq|Y@x0-P(h9zeGo__LP53F`qF{Qgaht@T6;HO;tdiU>E*|TO0a{~Yt=@@0$7p1O5 za*WkIok0Q`bA`;X%i`!rrm&jAxQkT>nd&(=HfI1H)U?%`s&4n5X+_oD-=jfl?THdD zw5XseKa8mS@(66UatAdt`7)3=A)`gt7syAv*T>Bs=MK$rfe@ z7f4Ce6Q;`Gv`r^Xc`UMuc8NOa52Bu(EVe(3R`oB$nS<>k-#!GE#N|&O&a|BdQ6Fkv z*^8KAOWm6g(*7{zOe8x5T)bye*=+i4epd@W9uk);sZ}{Fm6o@}`z53xdaMXi*&BzB= z7t!i<<}*pX#q@ouwQXJNUc}JaT+gEj-H;!Bb0!n}P`Y>{gT`|WcCL?C8_n?^T-|#@ z!4L#DKMRgiZT_(1#msW5#mx-cBbb~F27>IAs0LzQzW&Ersx9SP?ov&h*U{kr+AGMn zEpXwV`Ax6t8dFh%VRShZ4i)ph7Co)K)k%!pkTV}X%={){rR!li9kc1B{C^j*Z!%Io z1}vlH0u*1g;+x;#PjM+lun%_h{dwhq>1{iw$}%P+B^adq3m@y_@iV7X zvbKgt7WVHPnx{`j>0Rn(FFgeT8=iza&A}_(@>CD%CEUN94EVF!sgU1NM9%NyS?_Gs z*iOVzlV&uW_B@`zbZ+~Nl0=r>zkU-+}4@y{K@C&H6z&v^K6^iJRkjXJq@~}6A4p}_q?;DS@1AS z4?DS&5k7=QP6%{k>`!Q43%H}}j4L)Em6|LKbq9W-d-hW)^MCqf!8`ofWRfk8jJppE zLvM6AYWFQ?9-pkgqVWDF=H*!m+{ROgNQ-UAT6zLI(f}DX3hO3Ti$oUe9d1I((F8>spU2v`G>MK20vO9StF98`t?R~r#Te)`3aZVM( z!rR>4W1w@d54)XL_AZQ$Jo9j1kq5SCYXNIG-xI?2jHg@7%2&ZlPh`R$@IT%^eoQTQ zP3{R88Q(}*{;qVWCT_fjtPV?LQkFtN<%_{ftW&fxFyk5ItER*cv&at=Po&@9neqaFGg&yZ3 z3#IE#PPNcmr!q|LXYStQrdt{W%!-wd!`zZMHJW!9UFvEpH#D_Io3OZMOEgpAx5!-u z_7FUOO0fF3(SANwzRfp|s+FW0tFZMgS!f-sZCpDM-zoA(pRXeX9yRn?WVrh!Te}rk zxSRuYu1;86Yd7SWw4-P5c;TzV>YAY~NIzMYG z2RU)z>wA$$0YSXX8NRKB$F?*`H)Q$2TzC*+1Uyn9cWlhrW31oA&yH}w^^y#yvHaKS zOnW5(`|TCarNbsaS?z;H_Y>b^S>M?LFS{vW*s{?`nqK&(G^5pAXMqnt!bZ97sJ-XV zY3XWQMqk6Dn9C5JfmzWtj1J%$UDBB?J|RLe`aIN=$Se3GhRfzd52ul?%$%*~t#FuXZR@bQReQ}=YI35ba7NRGL?k;Y&OFMRRcvmyMZpH;lP{ffR zgfsqmrkL*}<5GzBbd}u*GLb(KRx5+V2zim_H8Of`rvnxL6^gwS)r%HP+PaP zo!oZcifn21wY?m=()$d*<8!JIAgtB1zP8X|}auX7_-j~Yhk>SkBl z=A<&Cm_ke2X0L28+3}{n=j7Uim8i|xsF=^Iv(f4j4UZG|nvJ(TiHxq`*1ZxX!=CMI zJIVg~%8gRh*M=T;q_TD_I$?Mx2x7XYHZLLyj5tXThDl&`6ETmSH z3IYNmLV#2ekTEg_2uZ9|MGz2~lu8!aBp^0k zm#?Q={hAz=(OJ26OJoh1CV8Wt_zmN(+gC;cQ)lM*9-w!hyxO;8$4l3%r-^yn14B(+ z&i^)8;28vJj|2C%&7Vcgu}CQllgjZDAz|pz1v1ipvmmv%(1#=@XA9uIa&hEYnUo@Q`P%6DQ_5!+Rj#p%%X(r&UW8-MJzmbu ze}4~&^h#0cQp#(4;|a1xiQe`F@vX?ZvaXKRv`J4~!hxtIx<^_&irG)m%49cpqWaV{86zyrnOpUhWT~15ZM@A zy3ZxU6SaXRNL}sh^^OQHM}>Z{_C5K31({8dnd25%*KkH+>)9z@n< z*brfzd*EatD&#-OI`7Tu2iD7D#>5BfMX1`hfg}<;wb~W7SGzfWr$A_Hx4q;Z+SXx>WQcUJoA?OMyjVNS|uM6 z_s32?fiqJ+G=*h8b+G|;&QGNVmytmTO<3X z-K`r$<9}D13qnIy{^*X{*gePMc0n_t?8PDElI*m1+zCTz_~2Hpc5Ds=jf@ytd6cwd z@0^*Eg46dYS80Tk+XK$~lPhG}|>_Lwb`rnZ%^YT#Q(P5};oG)KrK;QjI!ODLi z_}urv{+B^cuBMr}DcW0f$*hoR(G(u)Yxm5J>00hGMC9g%<1R@>gC;#id4tzJUZrWP zXMoHP9f~89!w#Oj_Wns34k_HDduXKU#gnMP4rDLC>q;akql}s$?O1^>26^Hrve3gI zkTXatw#Tb_aWS6r`23N5*+;6heYQ%t7~?Ied?Sr6A!hk?Ux{&j^?Y4aRTtvtIo%Z; z9LUc&?`~!#AOA(C`VYR-l5$0+(V*JN>fvd#AA#6C3rbz+>`7e$v2@=s)T{N$k+Rt7 zrXri<+%a3YAY+%Oc}}VC0mV_&>&YW~{IUspF%heLQw=W%ILEx+PvyJ>E!$N+=7V~)m#u{H7 zcR{0kr9!~yXgasFqKHoK+UObXDd~RwMmx^~e?digkJWfJpvWZ4yFhA@b1w>Q*Ujr6 z4`?aK2zS*bUZ+mUKuI4e$G@`vK_h3ea&Z?&-UlGH^YC6B^_UqoRB1eqN*(XoPVW!3 z-FQVlFL+$Fzqz@2adGii>uy`a$1$(I-I*z87HETzM1HZ~jmdH5J~~P^J^y3yk?6II zRH_IY)PzP4Ttw3m*IwUd_IW=0E)Ma6)NX+29Q$fD=jdA5fEMjl{KIGR*{q(3AN2k5w~@1`0%BdQy` z6CRO~cKXN{+jBE%ff}-)leQBu$3T0}pwQzpJr$iYqRgx9Qc-NEeyK5RwL$CfzJ3@Y zGW>%E`Qn)b@CV^WRmo92XT#L@8>)@z(OD=UTTkz=VI2vU;Wt)a7aUMgWJ`Aa? zhtlb_G*QNFIe);Wtge#PVV<{oKg9yMHbUy!LkyWoenGmG?F@Rm#Jtzx8MhygLTgP7 z4=0{z=-BMHv1MA8yGR<14Q-#5JO?x;atqh%qN^r@fJ9j_Rl$$4Qo@BP82vyaK-l0ivD~X=qaM?9M3RX1=3hFJt%m4%2aHZN#74Nt zYID(ujcRi5>Qq8`n=Y=n!jX|V7P?VOsq_^?1Q+Jx6X}#V(2ld^#nU0UyDFcu_P~P& z%#@y4qt6X!Sp0%o#VC-C5GLl_tjexUd%vXhC!2HW^=T|4=}P;DEEf1D57gA!lIPX2 zvhLD%}_%bhTnLto*#RkJbL`9T&s8w4WDP}zJDMCvDdKFRYqBZG{Zhz zJ{i7PMy#TGtGgNt|FV!iZE7iI40%LX>OaCAncIGhYDbW4)Lc9~B8B|W8cof)vereV z&di@yC;3-}SqP*G$hnaPy>=#ce&k?U;~4a9o0=bS+2a5M}kPYH&y zZ0Ky={)=m7=QV9(vg_o8Ag+tZ?#g@}Bg;6SPvm4+f+3~tGVyNvBv_caA+WV(agT=( z!I`+O2QE>~Ev>x{&0k*))m9s#VxK-eEWC;Pcam#c#gV!9!pd52uyiCD6uP@OIx4E* zP@#tGLtO#IpbfFky_*-~`){as6iVodh80YeijnvHQUfs5TF3zLnm4_{2Ss59gs;}@ zQYwDI8iuw4bq%dWb-o9&S*=UYqHQt+Z7f`v^RE!xvS4N3Gx^B3?U~iw%{^^owL>&cRE&n!X(cUh{&qlP*vv)4oM0pio7dKl_ z8Jkw)e=#y&3s7p}P6V`e>)qe2?~iYnOe(r~`q1(MZI5ACB|0r8{gWl0#tgDxNAuO! z0~;yvABI}mJkDcV3~GxL`fc1pN-3t^g*A@}i9Z`AJuiD^FkI{!Nv>~{zh6~0DrtSM zFzK9lz27#xWVmBnFsXj|LhMA&!xTo^;{IZD1I@hQc9V!&3q4)(S#5`g0!tmM#Iv6I zGqLTGlGKeU{=YmJ3=f3{okCkiiA|^WFd|@-r=#GM);$(DRN`fNh2G7}5NvhYjAUMS zoanW=sGcTVQEUnvTzSO1aHbDvEZ5MeqyB1tePhyDQE0R+oa}L!C`@3$&oIh@&Ceu7 zOv?VsLJfJ!iAIDDSZVsLskJ%vHl9uqz^kv*4UWb7^hW%(Q()MtZyMES4m`16JdruM&4nIpN>cl(3uKT$g&ElKT34DbHv2 zE7&~1-nbe<3Sd%wYvEU}#Jv`4f*=zgQzZd0?9Vn-Oa_bd`u7(nF@hWmYWxzU>oN`L zicS{YT=QyxZ;q*4R6%y^?_93ws9BuAWUBbMVq+a5;eA&`424zPY2S$gHDxELf}Ue# z5ponZ*{XIQi>4kI<_gjb(djkyp=FD=Hy*3)rg)fA{S;4rzyx3jlE8@^_dEHxjh8v8 z8MhcUxqCdKm8l!Ef*FUio*v!E&ZK%g>{7p<#e+2HduisKX zWHR`5wV_^txN=kFxDywTes4?Jxem~|KpJB88T<$?K?uw23|d5*5(5I-oOJG`JRH4! zxV+anCFQ`0E?fb8#1@^TedxFoLZRV@PIr}jL#k>nK}u=vIG5=Qid_b46n9-O)pI^n zKu5=ntI>nShT5Px3Ac+Y5oB97Vu+Ux_vzVM<~7`l7y4C&nsxWhD?~_OG(R~o&gln? zR~B6$ll!ee8|9_Yx&|x*qrt8i5pBtO&)5xC8k|YCrqi49zt^?;kXg=_UNFt zq(rb8lo*H!rFp~Vd*zFD7=<89@hIc@yJBs~x=zk|TyVO~laOej(N$edVeK&VLAJ^JZNSh_#dVM5Ex7ur~W^nr5<1 z?MuDOO=u@jThyzeH145w);zJ0*t-rcX7yX?1#zWFgnaIB*F{JFL}&>(@FO}PGR-g)?_+B zpF_3EuJzli7r2=Q^$&o_F|!{2sF@~f=RaW6_d1UvlEN$T_SopohqZVQ!CfPQh}v)J z5jqEG^wqmdLq5@BKmyd3X;MECVj_^0M(P#Dd-zT_zwfSO6B3!exsLumAMV^1w>?$2 zX|@peya7q)np1pdcFOR)dl|MW(G8T?4{5o(YuFs|w#q6U$!YR}q*fi_P&{wUJsO_P zk@q0Wg(J(Z>%3amxJ8cEZA*l}u-p%;c@~mz%zrX`Mz)p=Qi;6UH&}`{G%|0)R*SOk zBJoc{<_$`vQ)~O~sP_@Fm)gQq z3NR@C)enpyWHW$Jo8kpiGfql9x~Kh>sge9eVC{bLCHm+cZ|S2uDSYbYSCDraTr zisLsq^$CpX)D5uEFdun^vjHX!r>1l(G~5f-Zb6ql1AzW3K*t!C#9iuJeytprPDe(` zUukK6XCx!rJE#{W5Sy3vO$@Ls0Uicw*FRf|bUA0&$58NCu^I#RuNz+UsK4Jtbkx+; zCF6gH^y__ZQk8SQ5c^!SqtMzDXlsedi&{(tHhHpTyyVf$tkXhGo>2zoNOLS2dBe%a znwjk053;D2E^v@!52$+la~nUAb4dWgF+4cpR!f@-9>lHvIv*ir?-QFwAX#t^aY@PL zlVQKjlJ0gIkIXxA;Q5%{o=K<=PYq6JYC0GlG!7CxB(Zyhp<;YIsS5w1ms#v6Lx@uJ z8myl`g=`N8e2w_d7D$;5s2khsX^Tb9_WX55dz>7> z#NF%AGB;mZaCi0*EwyQ8A537Kv$XV;{OfGlcVfZ0s`A<%vi*o_jYuTz`M8rnb5kT|YcXbgCjHU=yml%JpUj12NO&us3;Xu_|qRm2ou6 zRj!581l)ByEi9|zX+stMyB&m}mgN>u&lWOMKb5!%F*u;EMD%-Jt$Li1`qikgYO#kCf2iR`3xZA#gb!|=1a{iGSqczwBssouh$BY!EG+9ILG4nNE zv%yglt7qD%mYcUzKCa|aaFhriTh7ysl+>Nyk4A(OD~a1hV-wS^32#t@&0+ry7gk_j z^f`UqQqgZK-aV({a%kLKdT+-0dB84_yyRal=bw%nMu zB=iMhJpDHRdSfy_E2qj{y?TVPS1UQ#spA2mj})^x(1K0TJbHO_WM=Q`&O6(yuHbz$ z>?W1TUM?zIXL(;f!U7@KD&bFC$X*CyKNvYj`xD80u%?P7v#6Z#^?9?x@WJM@y5D?n z{R{g2^7g>DJ9hl3L7=YplBmA~B*25t?ST#?VP)GJ`xXsTiFeNozJFMGh7J#V8HA6! zbj8jtbYdW=R993B*4_h}f--)ifo4Pqu35 z{7GokU$B^-YoG$62w%gni-7qPe4PK$wtcLDy~B?p+WwY_R91?4Jd&O$xf8LMk0k~o zbdb0g^a)S?bXVO*6{IFU#OwQFi$y|G@WR*rVg=O)V>}95DD?-@%{-%^fAjFMi7g@jPXV)*8flN2pOz=EU&= zU8EUlNPuRr1~6LYAjGTgELcu%)`oHewlQFnLMe)|(q3AYBATl%>gE<^&rm2$3E`_R z6_f3TfhGB9*zdA;^i`ioH`@D{m8@@mDzU0KsX52m)TA8xIiJ4Xl7X>2>~7mti;k4P zI;^O;(~z(+gzHg@Wbzd6GQOg*k7prTn5&N4_Y;IfL)`1o2}>u(O%r>mhSchvht2r`-jpl?}wiE!Cx7^y2Kss zd}@$fBAF6eAB;h-bA8*d1Zz6ZLj2Z6ljki#$J1kDt+i6m`kvgVI~{8BBAhKqiATyb z?);>1lHc4^7$JLig|=*@c{bfP;g9tvA6L^%-pYfyQ{`t%sWYKR)xA&L7`Yi^HBp;M zCr@mH>07QBdyxrCtj+DB#AlPgYx~i#+i$6_0cDg%G3of*vP!_(sCELM5?V<3fs3@>Em=(g}B?3{L z8G!(@@ri0EAM)kt;PR#NzQ2Qu`HDydF!?f8Yi8@|>-AY|{Dq-Nz_xx2wWJ63W_Qxr zmR{D!)Ab5yw7lSUz!-nZ(q3N)F|23(T}asG#-`Qkvq%fI*5A41zd|^vi0zDn(_yU* zPesL)?LA62Vn?*WUSHsqToUDBzftXLT|}4+^^cj z?htTk@Zb^KsEIL?N>F11#>7#5HQt&$TuKx0A9{_Ia@yOYKDY#e@Vy`xLR0J#C7?D` zhy_x{ZtdRq@cLWu@fqdSB&~gYa_Q~l2lrOWilJeBVe%VS6v_mrEPH21(2~Dn2$uY` zk3eH>&;qn-+7Ic1$(qdyPO7R9R1~9!t06H!PD#LUeS7G}lxp@w0WP?&+}*P{n!ZOI z*6l6j-M62wu|`wbrwc1G&qES9#pWRU(kVk=aD z-S_IKUXYWab0QCxH4Y|Un0!!}UpRjDmZ=g*d?x9=3FF(YAAxIld)&%+t-^?JEp9T} zFXFWCX~MqkxX|Up7*1l{@x8o;RiEQ*`!w$j@BN0-_j{INWV_?o8`>q{4tyZo_oOI$ z`Zm}+40?HOtFkP*K|12K^G+#hb!w0fk9@a;)lOm+VpvBT=u356GUuc0jp28E{!zOonF}pI;zB`*f3<~hr?C4)~ zax|%hT`Nd5O>{m}1GORmls%a9{v2Y6lWnECXaCK;xJTAir0TH6KahtWJ5A~;(d?eH^^}G zN^X`)8~1$G-qoP5Lv)cA+6@G3*U`o^XY78;MTLd5897&x04f}(2lE4=w*A4{2*wcc zPB+QE612^GnGgUk~L38*D}uL}Og{FzRxKRk`%c^~LxPF?0MxxF+N zA|5dfg&;TDjMpiRJLyRu`V4~nq9cRlw^H(Y77=H|f|-J`j|P_jU=p=d2F%Y@P5>Sw z8%@}aNX~k1)%N~pn*vJI1HT9N!u%@}z;X7m#MTyr!tDyN4=Lz8EYS*9@!3Y&E@`sM z|5i0U(HQ1jg{c>}0w)iUn91K4*OrzuFJQgSFs#Q@%UGlxamNAaBoN(C)P^EY)QuS{-x3bnZWVJIIyU^>Wi=K?W$~mz`RaYqm_{&;S*xMzbv%^PmFN0q zTR&+Io03v5m;L#M5A(A;NybYSpn8)NP+#HOXe?XByaCSX8xUo~m!`kkans+~i}L^g zaux5^t_g2kP4FyWobCy8KLWq+QK%M8s=jziSN?Yl{e$IBBX;!A2=&c)i{PE^yFO@G zxD~0^;@7V&ML3H@-Q2-z?#u-czb~+9-4NsxL3?8YjRFR7i0IhTs@f;tvA|IC!9_D} z@w2%&XcB+Sgo8@#3n(p0T0&$CS1pWJ?!bFt?v1NyZy#d<1v2Hu%<9iUkx^oD^bx^m~JzSXXIFO zI-gqP0f;=*72TPV*-O6xwJ)=YC6m_8i^isZDz?4MA2YfHNu0;Q4^zas7c;p$1MtT3 z#}eR9c>^76l}*QvNukzQ!8u0kx;T0QMHQY0YtPA)XL*f|sT9XTBg@s*D!-ag&;cb- zQdl=R<*r>{(5mV zW069UZ@qa7{;u;;W!PMLKCr6C@_GoRQ)|5YK@JU_kxAn?H>;@M-Y#}{#AI^$gDw$Z1 zB?{^znQw9O@#+T3#YAWE-}A!?kMKUZ*3QySg>oBT@m z;qdyrwz@4}A8USE_eTx3rJ!es?U0z5pRq4ZFK}w)R|G_kRaNcxkaI@0_t)tXkQeRV zvL@%K9@)K6np54zC-aRKDGZIUf%Jua_Dp@L{?UKRpgk;Cf{WhJFE(^~1 z?gr8O2Ko=Eg3b4>DJjq4t9_+i-ifQLQh#Bos~2+%Wn<{dIVZI)5{AR#I7dca_nl^5sqN zJW2h0BahKekVZb?AMkzrUhonJ#9oBM)3vU-^Ydi>dz%BU zm=z8Vayg|tI`w$@10A6Vm(Ews`Y6F*(>diZ8ME@Qoln%E>03i9z4omV zx7S4;IAaSp-mbJZQrT}DHuo$@gMeZ^JaAHW$8py{T1pDQyGvU%%Mk8(!?rE!B`V1) zvn8{2>B!%DGYWej@p8dJTE7vewBuR*+*Xr9E{#9M>r_wsD?dX+t;Hs>X_lCF05MkF z?R$Q78f+$8EW9+!A7t*<-1}nn1MRyE_SlO6dn zRQ=@jS@%xL_3?}PV4J8FzM`oj7=pr8cC}yUCMzl$2M)YTtrBp$8VTpk+~a**3jf_8 zf!A1{jVFzLw@!6OOA6i7CI?efZk3T-rJ7e~yOi6M7iAH_Ngue*!|BUomF;>y|&xN(;HXpVDbseH>z(A5RUr>HMFOdwcCUs)~b7cdJ?0 z7tjTUM#ep>$bVrsWvyY;t+9^70wt<8j5AjC=lJ8Q!;N_y3Z~sU&J=@mSsYSy^>m-S zJo%_F`fb#RjpkzVD2d`WLU;lgO`lE1-lQgwdgqxMU0xQEBzq$p9Lh@5yGCviMDD7e zmw#9!c?KCJv1iX3BIH2e|Bn!(kE6Eh1`jAVtMBd59Y1Q|F>|BspVUWj|1R2%2_CGx zXcm=mftPd?8yyD^%;WRAg_h$H z2dZOqi-#5&6;Yc_KL+i^eD%h8s;kwkjPb{r;aycNEfuEO2Q99Se2&Z9!S%XpZRA*` zMfkZ8^24{Q1^Kh{^c$BMN(*~cjjyw}4GiiH0F$5;ZX>KI+sH&z-faU?sFBZyKD+up z6F2I-FiMo)P@}E+h2Mup86wJAmA_lx=Dk6{v?p#op*0h~K8e05l40dYreI zhfLn)pLGfP*o>)c>cPDp@-ms!*`ncT!_!Fd5D=VlK6LR9^mQX_VCMIwg0>U zcmb-ka?`_%j6Q8yy;=T;SrhXQKCgkZICQ&OqV~9_1pVpck(>S#8Rz}4=n|@6vF0%K z92UVCQ@>REX_Maj%Pq#3@C!947cMJ;ljPR1T%1?%pU+tvm}*y~B_?{pqL;?p4%Ze; z2CsiQwPsCOQ)Sv?knQZ4%j5L`Z`|oF?I)eyZ{ENWQ9jk&LZBbv@)-kBIHVqOJ@B1*pO=CetJr1! zI{+Y0tAr9AcM&@e{Nr+bq21Jx>lr zkAC<$ddaL1!$$|z(uT&z1KEd~oF2bZ?+11NXIwEyJq2seM@F{ zzvR+*X`9%J{`u4Yx~#wCAvpIX+s^|)KtBEQ&y7zT2L9=ff5ZWp5C6=De`W*VvG@lZ z|IrQqtHI#zuZ6Sh8LC$6=Y!rd)TU>dQ8m&(uKB~}iu%u*DOIP`eNOIkbLYE2OnBdh zpFAyPrQs*5Lcr!c{jSnY=LK5y2^YVnx;76?uK%tF$_%v7dR!p!`@Elq{OXYd54 zPxn=4nt;1NTnc-U|0QRXRn}mjmfN&1B)0TRJ%<8j?5-Vu%%LCtoJ-}2BVf8zQOsh= z4F1nE4i#?I7q4k4jh5T0U~z3nK9x?(_8x2G73H-YejH{67F^n1QA)6c^FDk@H8f)4 zXm5@?@vI^QZq_utM~jqRy&}$Iz>0D|r|}xeT|q+Z?DRFrydgmz;PFq7hl629$xYvZ#BU_9^a*xDgKiYSzIy^^a+-4!mD|ebArp@82@{SIU8}LpA+0eslU+L+>*2bh<;xE#BGR3l9~59ZB0Gl_3Q# z=}tA3d!C&uBpvB_=Ai;THhQz?-+I0a)_0*ju>0EefYRevyUu>I`0|DT5!n-Y;ErOp z{I?vga6Zivj>Zks*o;hu6}Iizr7tac_(fKKo&9vs=FLAkJ~N=Km@mWg05`Gw%e5x+ zvjE$XKIh&|dG=X0emM8Ju=h@ky~yYPwZPoF;!n$w9r1*tNW)Ifc~t-nK+f-A2X2hrCX%POWsb<)o-j1T=LEF#!o&+-=Zx6_VG zm@jpO4vPKs_9o7C+YBnf3-rFRS)UX8%>>~vh|lSem(S)^=sS8jc=cD*jf*Y@IP3%a zIkHPv1i*Q~pQ^TeN!&Vw&2ck?t>u4dV@xg1G)RZo)BrM=+WDns5ereP49k2X!>yr4 z7xh4y^|?D@wDh=~q9%P}6!ygRwb5M(Prr15c~k%zx|-B;&|hKW_b+9XEJR^*9Qmj3 z6eG92cA4TU0zA2(&qsMeL0)-H`g#Fg)j0x=L2gsCtXkVVBB>^loo3@x@nss~^odRS z0baTR(=<07y$ZKH;5yeWuPG9Q88n@_CBsmO@} zvY|geTA`oMaH!Cqtg^AH%5kjj+8JZ$NqeA`KlZsRES~rnddjL_>Q`LMYSL#!={RCH zZY|Yabin#Jc%5m`thng<^mA3#0{e-N-TQUj42c0c9yvn#A36cp)Er0b#f+iV`7a_v zvrE{SzTr3Ql^3Oi%~&gnsz!Ll7l0N{XZ1l|4v+g{_kY}p8|I5_+Q=!GpSKeckIx}I%jw4 z;zt4cU*4R5n($dG{WFaJi1I&k;h(wiA1w7BJopC>{=tKP@ZcXj*s57e0r{!KEsvI#mQ~6`2V7X9PuwfS z@XCA)C)=PN1mr|+u1x@rOrCQz!jVW#n`$5xQ&Z_K1>24eEBc!kTGz}H-<%q{A)G9T z_*fK;OrcO(p{V-GN|Y_#JfEn>>1Cer%2P_~1bYL?D)yedkQfne5J8h9A*Anrzw+mq zZtH}$WFRvTRpRYG@7SvWlKggs_wI2z?Zz>aq@O?ABcM<;uC=_ThLwN$p~!54;!VW_ z4Zr+rXNQegvS~yf=UKC!Q%=i#?)KKABcQ?4rb%0kvn4j9z;bim$v3;o);})W*95IV z^OEq~56INh+NIo1;M>mP@Zf2$qu-xwc8Rf2`fevsNA=~EEHf3{)1`y9KYX$<+-z&p zC(@>8LSwRs{N}r-@&fF~@BFBwq!d{0$p=dBs)4D0_GoM6{8vlOe=+@NdZ=?g8);70 zR97=^EBjf97P1{H-16OXb8|&W_{}VRqB?w~aXv%EIBDyJ6zZXy8@C$bq{Fs&Nc33P zM1a9*YP+JbsVr8~nKRuq92^V=!{cAz5#mc89?}pa;iYEN@Q4~~#hRh6x3tfHPJ)b9}L3w&1?enRG z^X8~f^7=0@c;|2r`s^nI!TWzb448I7bwrFjIi&!Syz5C<5erslB5PV&V#lAmx>q@K zPU0&n7|bg3k{HtS2(Dm*Xk_Hg`_0jjNW+DPhr>5Tl2LmN8>9pd9L|?@wej-avD{pQ zAtC9klhYt(IKmqU0(qCE1>;cpb7@8ys+PwqnuEtG{WEP^QF3H@dV0BirtMM@29DZG zQ8K5-G8VeC_tW@GK}w{&QUmXa2W}yfzK$N{Ji`uxWyM8!|J!fNH<;R++QVKW?U)OY ze3$B}_6qE=7_u_T0_Fp*f_v;|?P84Ob;{$nC9&{Al{V$?;DxEltPru!w!-dAc@=YW z5+^H82OmMQMWSpshfL~?#dIf=VU?^_w3u_6d5hRHUbzaw1$lL>k;X#C1TDgbQvAXP zm-`miFj;O6@U%Tf&vM*Ce9Yvn-GxGHlq4r~$vFfkO=WH(N9PeV8zG!t5Ss)YJbT(j z;l`-MTsHWA`s*c^E$a5p?^O|R%5he>&vIn{pr@xt8IrWVg6R#P-k8hL$#$_~zRhsY zv=M-eaJ(poU^clPMwb@bzy&cy+l%Jh<)~8NjHZJowkNK=d*Fq!ZHfi{0d9+!5s<2@ z@Imh${Gw9<+;&qZlSmuM8v2~}5a8Z?F9BU$U0okO45!1L9jYq=dYM(Fmpnb&;#TKz za)J0=>4vs~VRcE;D~7#+*NLjTEzL`_F9MPCYvL;OV{>D`2Db;Y^(t3`elq&?W4#T2 ztSHBgGDB@g^a#yqC*t1LLFJ#@5z-i9}sF3SEG1Bxs zV+6AxABUD+Ww)9_OXzxYYmVC+bK98kZE+`3-oDZ9tf9A?uT$Yym_E1LXG8-Jd3;iKWrQHsZhcIWNa80MpVF?YH@QH#m+%ou*K>DWTSP_NXM1y@CYHu^{=Y z+pk};SS%$yWRaWhPu~fto2X3N?d9K}zCcRv@Y&|ia?Yl+kRGu{hhiBp^1#vWbsJF6 zuE?`zR8&&6@Av2Lz8V_s@9*v~*q!5c$QVv@O0yl0-^`RFmWP-HUk%(bZc|zYWMshnyLS5tpAvA z8||T+gFh(VITnrIwpA~%P7(&vPc0o6RUygH1?hlfa?wR;$oNSYqraT9xrHue^F+ z@fI-c4;hys;D5D*PDW7M8~uOt_n&`qD%l#+6gh8#^*MAhe(la4m!N5t!c#(~yXDol zk-*6_fI|jAP~MmeoIkOO?%HrbAf)at^`QCtV?ypw_to`#+9fMnmvwU~6hYj1@;x}WsXYD|UzjlGUL-53yi@FMx3d zr!VvQ?1qHvgqag{&ipZJjRV4{)qDKKwW;t!M?t}uCAlw&8r}J^tmNzF;N_KU(LEz%a2RN zM$fc{?>lmz+qGepUu$uVpx2Jrtf|O6@$8Ngj7;ZAy6$D$#=5U6FH$WRD+`T6wq_z7 zjV>p=X@@V>sm3x@riCPtnm7zVLo5Eu<|PA>R{_#FQgmAHh=l77(a1;F8>xDLJ;B8; z$sz8d-fb)H^`axlV--1Pr9-BZerrARb?q{G0Vtl>GA1|&1a8qvZu?DwF|IJyvvWZ! z!tl^Z`ttNXasgZtAn!;HK8^fX0E!1<>$W z%4L~F%<{;FhKgC3>dE+#<4A$*&eE}Vs-oSfjS zPA*;}M}9pxSoCt2A**XT23lLn({6KeU_QmdXr*or>6s^ANH@Sih9&Us{N71uuzuym zlZ^7+M`9^L|5AjRn?vyHw~d}g(&@pfh|A4k{mtl@4*q;C()++>PZ-C*Y}`j?L>Dcm zN9ef zU9E8?w{P7^2<8mBv)yY-XOQ9R%tkKpLS`%iQubw z0mM85y`R2gq+0+EW1z3M`D|Fa84v{Ma(t{iGRT(l&Cr7m_qL1s_`99qgqk`u# zST2LLDjwMlMM(DcsmaP5w}5b8M1sqL4#dYKvect1Xs})6Ki_e3pdVE{HU&phisvxI z2ssM`BpyuV4~k~;kx7dhMOF*HogOY0zb~`Y$*o;~{Vkoq=X>;tB?EuPisu$+1?h8w z${uNE1h?oRyT`}kDsxvQ3MQGvqu#vzJ%B>J!R8CYG;E;c<^J(_ZV_D)BTFML2}xIj zKC@G;(edi+D(B*&fNB3s>2P_b;V>gg*_UUnT}s94$BtDx^{Sam226(I0WmBzha%Tr z35sK2TpBKDxCELsU&zSJ)`onX004=^%cb+XzCUn-Rn4_reDq2#rDw*<%2HEPk<#s0 zTM_|9xbo&sY(mKp7^Lw{I&qQS+8)fSX8wi3FJ{FOH>_jHtK(}We`T^CKtn@%j?p+k%wwg& z^Fs$`0xqoMn}3z4!E=VI<~j`t39>0R;X>zofw~Yjq)b7LaM$^I?B1j(yID4f+a~9J zCzuPKoS%uxT_(HOt0~+|GT(VocB!2GZSEjX|Xq}(F`AEujDzdcf0ZzIB@Y~9qI|>>y zIAM~uVHQr20D8!!U|cqKV`5?g&`bbdBFM$Q!1ULtXl-pB5<_!VDJ^=X!}+_O<+Mi3 zc3kbw?7TnS5zB_tHcM!zd5%({+iU{E#xzxrkSKhhKs_Pt5+o)j_0BY#ncFsAW!zyD zjy2Vyq6OLngm^_!WbA*o!ebvQ^x{$>g3A&%wBsd9w8fr{@90Bxew4fJIK#T;n)o;i z(9S0(Ap2!`HixVtIofWCaj#xM8Y9+mGgZ`$KoEQij4?*Y`XdCtBwXjL8H&R$lAXkz z_LGvZ>4(F^k~h$>15#y(`2F0p=iWj>VBcXrPW8?g{cYiuCzUJ_F1Lj6EAsuil0=!I zp`jn?k%nvy1W2Thr{`qCwNhJzRjdEd(q?Y1hnfb_+IDjM`$tx>4x;w}5$&vlIqOJy zRctqhrJ`t{5|}oQws{E(GFzl!P-LcQYE%N}o0#C^-v|<-^M~<4vVnaYIu&!Lqg{%m zxEzQv_R7H5`*!Q3%LiVAtCZX}Pe&WcD9<17_Z-h&an%ld^U1(H??!+NpW%| zd@y@9f7qc7B)O+}cgr9-{PGQc{w4~aBq>a{uEUI8@{zw&+r-~szur?Gh?J30TVvQs z&l0Pp25WPdVoOmbSU%4UY(q!L z#o9%2ltKgl)n|ZAv=O9SU$S*R;4CKg{{`>OP*WpZdE|D;R?@!PNK$WT?$x#R>PbF4 zlw9v!ynVhaf#H-La%jJ=xwv1ew5EWSxqbXj23&llwd9RJ`6QL^VgfhWH_6edZb16$(LA ztJfKKpG(pt0QVe;%1yOP4L&V_gOsa{{1r^6A(+!e zO8|&RD7j9};>P<1-%h-QfzH{b8a-e<-;+KI=#8>73O}WF=a6oFE$@(fo)l7}iTUV9 zX5szDy{h}RJ8Z5;)JeDAI0mI7MI5~z-^m-(lgO^P{&iqY(qDR<4MLt^ZC8)U6Q>>y z7r7se!A20(G_YZ!XSZR42XoyHnJzWlMk9HZGo|gJ9364PTKK2+F|*w`+q<$9Bxx0d zvV)S?W1{gJy-H(CXvb>XdJ7C&fmxBmB5gzlArl9*m1(x(9}MnC;5Spp8oUZv^7n!a z$WJ~pW;Q6v-nil->f^fam$HOu)3L<}Y4UBl=jC>i zE($vxzi(H(aE>@wec_#)a-OJ?I+#9_HqjD$J3@Aj@kH|D*jA{;rvRTD%Q2lVv1zu5 zZ614)`{3lzhf%32Z)9)gLS6h#*subt!%#AL27dv9`r*y*9;z%OAbBXT%U#Xse-?c} zqeWqT@&fLPb@mp2j0~avHMAIob*qlKUb=ikH`n2dIi~Cr=U5Yv0rOR3yZ8pE`>DG= zhcna0`Yk9lWZT@F5clzckO(ATqmutMq#leJRY@%QuygcNm_$6BJ&Eq92nY%dT~{Np zEQw8I@>NIT5K>yBa3XN+eYuJXBoSD0aJORd6>iK4&o*;2{E2uVNaaxU!oXRm#iN6^ z5470wQ=i*bU0)wQ*+8D{6n0_!Jq`2OGi@~x0;|8jU;R!?>wZWgGdC}As5_kma?GcIlONvMemZ1g$Nw!(=x36A*TCBcuTE0cY(BpD+!<%P KhTs3Z_5T6>=d;HE literal 0 HcmV?d00001 diff --git a/docs/screenshots/sessions.png b/docs/screenshots/sessions.png new file mode 100644 index 0000000000000000000000000000000000000000..93aa93c445df230b0d6d7603b76b28676155f2e0 GIT binary patch literal 139806 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000..f04854c --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Kimi Switch + + +

      + + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..97c95cf --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2993 @@ +{ + "name": "kimiswitch", + "version": "0.4.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "kimiswitch", + "version": "0.4.1", + "dependencies": { + "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-opener": "^2.5.0", + "@tauri-apps/plugin-shell": "^2.0.0", + "lucide-react": "^1.27.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@tauri-apps/cli": "^2.0.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.10", + "typescript": "^5.5.4", + "vite": "^5.4.2" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tauri-apps/api": { + "version": "2.11.1", + "resolved": "https://registry.npmmirror.com/@tauri-apps/api/-/api-2.11.1.tgz", + "integrity": "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==", + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli/-/cli-2.11.4.tgz", + "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.11.4", + "@tauri-apps/cli-darwin-x64": "2.11.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", + "@tauri-apps/cli-linux-arm64-musl": "2.11.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-musl": "2.11.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", + "@tauri-apps/cli-win32-x64-msvc": "2.11.4" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", + "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", + "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", + "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", + "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", + "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", + "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", + "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", + "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", + "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", + "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmmirror.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", + "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/plugin-opener": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.0.tgz", + "integrity": "sha512-B0LShOYae4CZjN8leiNDbnfjSrTwoZakqKaWpfoH6nXiJwt6Rgj6RnVIffG3DoJiKsffRhMkjmBV9VeilSb4TA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.8.0" + } + }, + "node_modules/@tauri-apps/plugin-shell": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@tauri-apps/plugin-shell/-/plugin-shell-2.3.5.tgz", + "integrity": "sha512-jewtULhiQ7lI7+owCKAjc8tYLJr92U16bPOeAa472LHJdgaibLP83NcfAF2e+wkEcA53FxKQAZ7byDzs2eeizg==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.10.1" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmmirror.com/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmmirror.com/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmmirror.com/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmmirror.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.5.2", + "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.5.2.tgz", + "integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.4", + "caniuse-lite": "^1.0.30001799", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.42", + "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz", + "integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.4", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001802", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001802.tgz", + "integrity": "sha512-vmv8ub2xwTNmljSKf82mtCk5JH7hC+YgzLj3P5zotvA0tPQ9016tdNNOG8WRca1IxOnhSsivB+J0z5FeE5LOUw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.387", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.387.tgz", + "integrity": "sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmmirror.com/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.27.0.tgz", + "integrity": "sha512-rJicGl/3Fly/E0rOH1YmPZ6e49JCnKknh1ox1vpHnkfjujAkKA6sqUZvH3MTAaXXjgexyUwgNwTJzTtYuAFYJw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.16", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.16.tgz", + "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.4", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmmirror.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..49ad049 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "kimiswitch", + "private": true, + "version": "0.6.0", + "type": "module", + "scripts": { + "dev": "vite", + "prebuild": "node scripts/fetch-models-dev.mjs || echo fetch-models-dev failed, using existing snapshot", + "build": "tsc && vite build", + "fetch-models-dev": "node scripts/fetch-models-dev.mjs", + "preview": "vite preview", + "tauri": "tauri", + "tauri-dev": "tauri dev", + "tauri-build": "tauri build" + }, + "dependencies": { + "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-opener": "^2.5.0", + "@tauri-apps/plugin-shell": "^2.0.0", + "lucide-react": "^1.27.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@tauri-apps/cli": "^2.0.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.10", + "typescript": "^5.5.4", + "vite": "^5.4.2" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/public/kimi.svg b/public/kimi.svg new file mode 100644 index 0000000..19f6884 --- /dev/null +++ b/public/kimi.svg @@ -0,0 +1,13 @@ + + + + + + + + + K + + + \ No newline at end of file diff --git a/scripts/fetch-models-dev.mjs b/scripts/fetch-models-dev.mjs new file mode 100644 index 0000000..2e41f4a --- /dev/null +++ b/scripts/fetch-models-dev.mjs @@ -0,0 +1,57 @@ +#!/usr/bin/env node +/** + * Fetch the latest model reference data from models.dev and write a compact + * snapshot to src/lib/models-dev.json. + * + * Run manually (`npm run fetch-models-dev`) or automatically before builds + * (`prebuild`). Requires network access to models.dev. + */ + +import { writeFile, mkdir } from "node:fs/promises"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const SOURCE_URL = "https://models.dev/models.json"; +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const OUTPUT = join(ROOT, "src", "lib", "models-dev.json"); + +const res = await fetch(SOURCE_URL, { + headers: { Accept: "application/json" }, + signal: AbortSignal.timeout(30_000), +}); +if (!res.ok) { + throw new Error(`GET ${SOURCE_URL} returned HTTP ${res.status}`); +} + +/** @type {Record} */ +const raw = await res.json(); + +// Keep only the fields the app needs; the raw file carries benchmarks, +// descriptions, etc. that would bloat the bundle. +const snapshot = {}; +for (const [key, m] of Object.entries(raw)) { + if (!m || typeof m !== "object") continue; + const entry = {}; + if (typeof m.name === "string") entry.name = m.name; + // context 0 means "not applicable" (image/audio models) — treat as missing + // so callers fall back to regex defaults instead of storing 0. + if (typeof m.limit?.context === "number" && m.limit.context > 0) { + entry.context = m.limit.context; + } + if (m.reasoning === true) entry.reasoning = true; + if (m.tool_call === true) entry.tool_call = true; + if (m.structured_output === true) entry.structured_output = true; + const input = m.modalities?.input; + if (Array.isArray(input)) { + if (input.includes("image")) entry.image = true; + if (input.includes("video")) entry.video = true; + } + snapshot[key] = entry; +} + +await mkdir(dirname(OUTPUT), { recursive: true }); +await writeFile(OUTPUT, JSON.stringify(snapshot, null, 2) + "\n", "utf8"); + +console.log( + `models-dev snapshot: ${Object.keys(snapshot).length} models -> ${OUTPUT}`, +); diff --git a/scripts/generate-icons.py b/scripts/generate-icons.py new file mode 100644 index 0000000..80e530e --- /dev/null +++ b/scripts/generate-icons.py @@ -0,0 +1,110 @@ +from PIL import Image, ImageDraw, ImageFont +import os + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT_DIR = os.path.join(ROOT, "src-tauri", "icons") +SVG_PATH = os.path.join(ROOT, "public", "kimi.svg") + +os.makedirs(OUT_DIR, exist_ok=True) +os.makedirs(os.path.dirname(SVG_PATH), exist_ok=True) + +# Brand colors: blue -> purple diagonal gradient +C_TOP = (59, 130, 246) # #3b82f6 +C_BOT = (139, 92, 246) # #8b5cf6 +DOT = (255, 255, 255, 230) + + +def lerp(a, b, t): + return int(a + (b - a) * t) + + +def rounded_mask(size, radius): + m = Image.new("L", (size, size), 0) + d = ImageDraw.Draw(m) + d.rounded_rectangle((0, 0, size - 1, size - 1), radius=radius, fill=255) + return m + + +def draw_icon(size): + # Render at 4x then downscale for smooth edges + S = size * 4 + img = Image.new("RGBA", (S, S), (0, 0, 0, 0)) + + # Diagonal gradient background + grad = Image.new("RGBA", (S, S)) + gd = ImageDraw.Draw(grad) + for y in range(S): + for x in range(0, S, 4): # step to speed up; visually identical after downscale + t = (x + y) / (2 * S) + gd.line([(x, y), (min(x + 3, S - 1), y)], + fill=(lerp(C_TOP[0], C_BOT[0], t), + lerp(C_TOP[1], C_BOT[1], t), + lerp(C_TOP[2], C_BOT[2], t), 255)) + img.paste(grad, (0, 0), rounded_mask(S, int(S * 0.22))) + + draw = ImageDraw.Draw(img) + + # Bold "K" + font_size = int(S * 0.52) + font = None + for name in ("segoeuib.ttf", "arialbd.ttf", "DejaVuSans-Bold.ttf"): + try: + font = ImageFont.truetype(name, font_size) + break + except Exception: + continue + if font is None: + font = ImageFont.load_default() + + bbox = draw.textbbox((0, 0), "K", font=font) + tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1] + # Optical center: shift slightly left/down to balance the toggle dot + x = (S - tw) // 2 - bbox[0] - int(S * 0.02) + y = (S - th) // 2 - bbox[1] + int(S * 0.02) + draw.text((x, y), "K", font=font, fill=(255, 255, 255, 255)) + + # Toggle dot (top-right) — the "switch" cue + cx, cy = int(S * 0.74), int(S * 0.26) + r = int(S * 0.075) + ring = int(S * 0.018) + draw.ellipse((cx - r - ring, cy - r - ring, cx + r + ring, cy + r + ring), + fill=(255, 255, 255, 90)) + draw.ellipse((cx - r, cy - r, cx + r, cy + r), fill=DOT) + + return img.resize((size, size), Image.LANCZOS) + + +# --- Tauri bundle icons --- +for s in (32, 128, 256): + img = draw_icon(s) + if s == 32: + img.save(os.path.join(OUT_DIR, "32x32.png")) + elif s == 128: + img.save(os.path.join(OUT_DIR, "128x128.png")) + draw_icon(256).save(os.path.join(OUT_DIR, "128x128@2x.png")) + else: + img.save(os.path.join(OUT_DIR, "icon.png")) + +# Multi-size ICO +ico_sizes = [(32, 32), (64, 64), (128, 128), (256, 256)] +imgs = [draw_icon(s[0]) for s in ico_sizes] +imgs[0].save(os.path.join(OUT_DIR, "icon.ico"), format="ICO", sizes=ico_sizes) + +# --- Web favicon / app SVG --- +svg = ''' + + + + + + + + K + + +''' +with open(SVG_PATH, "w", encoding="utf-8") as f: + f.write(svg) + +print("Icons generated.") diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock new file mode 100644 index 0000000..e8d0152 --- /dev/null +++ b/src-tauri/Cargo.lock @@ -0,0 +1,5530 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "async-signal" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "brotli" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.13.0", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.1", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.13.0", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.0", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.118", +] + +[[package]] +name = "ctor" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.118", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.118", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys 0.5.0", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.4.6", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.0", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "embed-resource" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 1.1.2+spec-1.1.0", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core", + "wasm-bindgen", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.13.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" +dependencies = [ + "log", + "markup5ever", +] + +[[package]] +name = "http" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +dependencies = [ + "byteorder", + "png 0.17.16", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.118", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.13.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "kimiswitch" +version = "0.6.0" +dependencies = [ + "anyhow", + "chrono", + "dirs 5.0.1", + "fs_extra", + "futures-util", + "indexmap 2.14.0", + "regex", + "reqwest 0.12.28", + "rusqlite", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin-opener", + "tauri-plugin-single-instance", + "toml 0.8.23", + "walkdir", +] + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +dependencies = [ + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "markup5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "muda" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.0", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.13.0", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.13.0", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.0", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.13.0", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.0", + "block2", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.13.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.0", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.13.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.13.0", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "open" +version = "5.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8d3b65c44123a56e0133d2cd06ce4361bd3ca99d41198b2f25e3c3db9b8b4a" +dependencies = [ + "dunce", + "is-wsl", + "libc", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plist" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" +dependencies = [ + "base64 0.22.1", + "indexmap 2.14.0", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.12+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.4.2", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.5.0", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags 2.13.0", + "chrono", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.118", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "selectors" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +dependencies = [ + "bitflags 2.13.0", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "socket2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "bytemuck", + "js-sys", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "tracing", + "wasm-bindgen", + "web-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "string_cache" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.23", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.35.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" +dependencies = [ + "bitflags 2.13.0", + "block2", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dbus", + "dispatch2", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "libc", + "log", + "ndk", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "once_cell", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs 6.0.0", + "dunce", + "embed_plist", + "getrandom 0.3.4", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest 0.13.4", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.18", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs 6.0.0", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png 0.17.16", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.118", + "tauri-utils", + "thiserror 2.0.18", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "walkdir", +] + +[[package]] +name = "tauri-plugin-opener" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e1bea14edce6b793a04e2417e3fd924b9bc4faae83cdee7d714156cceeed29" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation", + "open", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "url", + "windows", + "zbus", +] + +[[package]] +name = "tauri-plugin-single-instance" +version = "2.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3214becf9ef5783c0ae99a3bb25adf5353a7a16ebf53e74b909e29205735c6c" +dependencies = [ + "serde", + "serde_json", + "tauri", + "thiserror 2.0.18", + "tokio", + "tracing", + "windows-sys 0.60.2", + "zbus", +] + +[[package]] +name = "tauri-runtime" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dom_query", + "dunce", + "glob", + "http", + "infer", + "json-patch", + "log", + "memchr", + "phf", + "plist", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.18", + "toml 1.1.2+spec-1.1.0", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" +dependencies = [ + "dunce", + "embed-resource", + "toml 1.1.2+spec-1.1.0", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "tendril" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +dependencies = [ + "new_debug_unreachable", + "utf-8", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "time" +version = "0.3.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.3", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.3", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.0", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ba1e5f6b9ef9fd87e21b9c6f351554dbd717960089168fcfdef854686961dc" +dependencies = [ + "crossbeam-channel", + "dirs 6.0.0", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "uds_windows" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" +dependencies = [ + "memoffset", + "tempfile", + "windows-sys 0.61.2", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.118", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-roots" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +dependencies = [ + "thiserror 2.0.18", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wry" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dirs 6.0.0", + "dom_query", + "dpi", + "dunce", + "gdkx11", + "gtk", + "http", + "javascriptcore-rs", + "jni", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee682d202a77e4a9f3b2c2bdf48a7b28af5c08c34ddf66f98c93e5e39464285" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow 1.0.3", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf1bd45a81a103745b1757754762a26e8cd01e4532e4d6c8ec431624b80d1d6" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d" +dependencies = [ + "serde", + "winnow 1.0.3", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zvariant" +version = "5.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a192a0bde63360d77a7523c833d4b4ce6070a927e2c53246e4c540b1a3e27be0" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 1.0.3", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8535915cfa75547e559d8c68e8139909a4aeee076831e4ef7fc59d8172c4d6" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.118", + "winnow 1.0.3", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100644 index 0000000..a2ce5a9 --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "kimiswitch" +version = "0.6.0" +description = "Kimi Switch - model config manager" +authors = ["you"] +edition = "2021" + +[build-dependencies] +tauri-build = { version = "2.0.0", features = [] } + +[dependencies] +tauri = { version = "2.0.0", features = ["tray-icon"] } +tauri-plugin-opener = "2.0.0" +tauri-plugin-single-instance = "2.0.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +indexmap = { version = "2.2", features = ["serde"] } +chrono = { version = "0.4", features = ["serde"] } +anyhow = "1.0" +regex = "1" +walkdir = "2" +fs_extra = "1" +reqwest = { version = "0.12", features = ["json", "rustls-tls", "stream"], default-features = false } +futures-util = "0.3" +dirs = "5.0" +toml = "0.8" +rusqlite = { version = "0.32", features = ["bundled", "chrono"] } + +[lib] +name = "kimiswitch_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[features] +default = ["custom-protocol"] +custom-protocol = ["tauri/custom-protocol"] diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json new file mode 100644 index 0000000..620b328 --- /dev/null +++ b/src-tauri/capabilities/default.json @@ -0,0 +1,12 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Default capabilities for KimiSwitch", + "windows": ["main"], + "permissions": [ + "core:default", + "opener:allow-open-path", + "opener:allow-open-url", + "opener:allow-reveal-item-in-dir" + ] +} diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..7519dc875bae974fd779649940778462436de56a GIT binary patch literal 6621 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 b@Ui?q3a+yxe@Cpc00000NkvXXu0mjfqih-X literal 0 HcmV?d00001 diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d95f1c911dbe843814d18addc38323b934ade9 GIT binary patch literal 15225 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%0DN_UoFdTsg+}G+7$0Gp zeiiLzSHfgvk-4=cZmo9V|2G$XrkA~vci?Vsq561)dSQ})H6c)5!HX6l_?75b@r(3_ zo(&!Vj&-KOy#UpE2gOX#w^rvJBXl!60(z|eFvL=Ec!?e|kXi{6i6CsAQfJ|z=^KVv zFhVe4zGu+%n)fGx4Hde#iFsKXccOm{B62${OtV~QDA6Ewty&^}4W4>|da#f-_65kT z2Can?{{V_b>`WYn%YABmgYUaK^!uI2lf~LPowp~ebD!3&6nB`{(lbFyBxf3Ky|QazOCapG=E(&w`=!!2(nTK=HC0U}uh zL?|y>lD|PT#JfLo8(VV=h)Xd{sg_9^fyspKjx}~ofU->`$2JK`npZx>HwT9zQR{;b z>@xru4j613T3Roe=8ihQ?qG=<)JT`r6{^<~tL=lQ{Yre>71sg6y{+SbaD@@~Uo{3Q z?u)X=grqb*)hi~Q*9KIAkT;7_Y-F<@u&UcjWq%i#LN(tyclMxumuQs?u)HaWNVs*loeFv7d zSGYg_Xh5>I{<`QudGIH`amj6^NKuSd#k+o$UB<}>94Q2U+f&VmS^RsiNftOWOHRH@ zdr>(j&7Ue&Q)SFtfEFh)=pVcDwJ>;sV)~;khpsMn$89_~i_Wwc| zey8wVZ?Fk$aWPDyvrf9flJ<5aHps315;F}17}4;n|F1gf&;Rq)w}*pS zhLCZxQ86F3yLqL`c$}y(g#rQIlZIVXZjRALPU>KtjGy7-n;Hr{gZGomAV(KSc)pK- zG!dcXlCM`&Qm_;dMi5#)G#;q6&b|`aE4+SZJ?uRe-E6MVE>or`vj;wS*e+5>E`Gu? z@yMEmtMJN;)i@ti0M)q26PP9=KpA4}<(LX(5!3{_-gI6isJ>b|Uv~|;{nuo1X=#(x7@(SRb!0*qxQr>YJT#ATD3|y`_ z7Fj#1;jun-DogcYw}YVY@dR-ixQgIwoW!83qm*X#bq0HKy`

      O6J5|5f^Y4f0^?oJ^I(ydRlDy=k0p7K2kO8|y z9KZWZ{?OuZy(x0Ff>kw-`pctKFHp}j#)5T)IPbe=J~s5XYQAjkCM;G)8d%kIL4|4W z-!6Uw2n{bneD?1pJAP0|JjsbJ$Zm@z{4!&lfS0{crq+hCb7tq#tvCSGtKhPFMjzPM52teFB=P}BkOoKsSepm{pJwHzx3q$0;+N~ zKSF`woCcOLdTl3a2&+QC%lvW&<0Q(Yq#DsFAoNd=qLAHk<2AY(rjA#>@%c|w_;Y@T z)GohjpFgT}^oEv)>H7>{MWJEje!Vym3}CM3d1AzpWo6aK5s>!w@hqOwR{tal^xJv* z`*cw7m|(oR_O_88Fr3!;Oe%Cu{4)BEq5*!s{Z@gsSGmcaC0iG)^Zy;{*6LX3NRgx~ ze3FdY6MWIT98xP)SX0Rn+eS4Q@BgKR;ap;=AvF*4zWXB98WiL@M*N7=XpY{5F|H=B zgtq%8J0_%blg~hiqqI1r;D1)s00d2Wma$2P;IU3Pj-zg^|3il}9bI?Ep7K1;r)U%Y|4(qyW4YLf7p$T_q`Ux+jy(1$tf&#qS0vTLp;$8>M?qw1_52 zTEEwpf2m ze38^tBtenKMGwbV)cznc7$HrMWI{JiSm2>wZUPCB1RczVEhDHKJ-PB1EPh-h%$icy z>QY}sMISXJ-TSGq?J&n$b7fzyAX`aJpN-xREU%t>c0_eLr@+Uk_#{8L)iF>p;v>7P z=t-yB?2dChA=Wm67VjT1`R4|Rpba8Xf#8C_i6tV~1-Mg=IsHuZsql___TqXJebNsT3 zKgr^T(b3=nbtJV$KrldZ>0@TsKjds(d!Betvifni3&Ie5LR8G{y zvx5Y|JbJEYJl13UgrYk1RcO#93&YDEq>qlIpB^DKxdFFU{T|Q3`Cc95rklk(QQ(Qt z2i`Uuz<0tuG%le7w3OA|c0E7T)tu182MuR4%1Zq{l(B9eDs;KO6rl6^{d~|1@15z- zg`l4SuD)^yFBFz_8;Nr}?z=iy$!l8)zc5Y~MKZhB8CV?x&!e~G>?TFO8(A=SG!R_n z>ArDTA%%#WQcLPa$b`^5yU(*f#*L^@l|KZnZ6hA?}Lc^<=|4 zRtGEg{u}~KM58Ior_UB7$b>oTO$tSj~~cOC^ECh-80T~d3!s2e2s~oGoqG)?nU4W z5GcF#;RxbQ^_9_@PloA*0@9Yd2l1&%QZ$G%z^QI;Y_pNk70<1E|7u=xyPC{$cfAYx znS8o^3HN)+pGI1ho<*W9g@&Ajkii$6#_$ISl7C1XG}&~D$Z2Znbo4k7zTfV)WM#pG zYHf>BT32^SZD)r~E z#8|Q@dhLg}LH>uQx^grQP?hKYo@*ysxS9TT z@_Et>{wPf=I!jlMh3Fe5y%^h6qjG>x8G>x}C2ZMzc#%23cCYN+L=wReN$?m#U8=#C z^xD_%765(SS+PAg&dH;GFeR6!`Y~ct?#^FCq8c(MnFxkmgv_)IH1ko+ud8!k zS51HpG(pQ@BBW&&S^+I}BSQG!PR@yE&YYF~Nm#)*%PG8(gUXx1L~IIvcU9q`XuL)+ zgBqw<3G^D6K~~Z9XYN*5I=fSM*HzP z4{e)lY_|FIueQ6RHOXCa%1)r?aldlULULX~3B7SKzt!$+sH=$0u7~_ki zUvYb{U0;V!`~~`Oke*=|BTW>Mh=HzA>S;tvzPc>&x@I-3i}FL0b`bvCKt4&3(hRSj z0eFNoq2zMG{58UnEJ@LVXn4~!*NNh!YCpaBgy-{@r+wc(X-je=yUlJv+60AdPH|kt zD$kS_1?jSb(SzxU_v~&`=fI=4jy(2kEP zGi&Wt!B}>(cY$rtgq(;uv@+$CfxHlW+N&n;6t_zcpYqBUKc6g3`y~s&>dD+*TgB*`%N5)!LfHIgm-8CXs=*QGswo3> zF~sExx95TBo0f#5_j8NKo}%?6XDrM<0LJLG=w3~!Gj<>p#HWUz{c)%v*<-HAXseXY zJP1VfY1EU_SP@ZaarESZCQ==zHej?%Y;LF9{CRNG`fAi{7B}C>BPw~v75#BJZ@xqp z5N7c-1J%*52c{75mchza^BrAFJqJgZ^E%K<4TRJH(AWuOO+rMw-KI;=xt<7ma6_$N%j7pD)<@FCYvob0yQdSPbD{jL8 zY>gRf3vsJ)n}{KI-Y=A&>#gLLc|6v`vac>dCwGmV)WL!{QxwHOrOCUMnugnD0**|8 zvZCSfi+@i}K`Jfo@0S!+t0lRFbo%m0n;$g_7f3~cI(ed!K?>Q0$z@3emw`fgfkYFIWzzxO2^t0 z3ok)ApVT6L)A0If#b4q&qVuJzjzmN2dLZrY8gBg#?5nsMKGVI#N^p&mm8o zv3nd{E!GdxzS~u7R{^!SNcaej2N9AOj&aybLyA$Kg` zFp)J_SJ{oPf>cl7EzTOUq$mDU$GyLyx8L+_7p4+YlBwBAZwz+t5wR}EbGrxlVU}gs zIhM&V>9s=-u^>`3(*nh1&|LBPAjr@D*heX)GZs~U#ZH3JS&d&Q^0s&jf?5tie_H4| zQM;k0JPr~43noOalA8Q8c(CaSpH9!wlgr(Yu}fSk0{3MSVO2($W~!YSw52RfZ8H^` z9J@c-sDEO;nzN3l^z9w-kQC3S#oYx`)IUsK>s2u~F}os}=|mkV2E({`R`#H8&oX9j z328wD88C~5gby$QNuv~;rBSV2@Xe9Jh4nb7-TFntxLOV((L`0K78N@_PRvdOBPd;k zJDx@SI!KrXW;SAtR-1xMoZJ1wl4qg{l3cTQ6Wd>J@b6n5@aYOWqXG&yybI0S9afY+XYPt=4-M z#Rea`Y8;otcBvp}o|;5z$Pc-171Q~~Eti?Q#F+3wq4NE$C&g%$QIpn#5mD~zt@}!TVBKgW zZIY0zXyJ5n62uTFc4#1^Ae60MieO+7NbJK2h`@a0hrrY)sjReCV`sgH)q>?L;it7r zb?z04n8gV~3Q%bCukrESqD;`BA~!)ay^VV2<4|5dZc9Zd=x0tb#tJwml2E4rHh|zR zIQS$1tS=dBqBW|kfd3F)D#-Zdl${DniuFHa`AUv`&Q6M<0?uo_!Q8L&PjQ9OL|?-= zj1O}_`(V=Q^m{<>y<&OR3b0(Mo>SNK}g)!W(ed0N~V>Csjt?aXS}3w|j`6U7cW{?eZNd^v0aBHAo**$rWZRlP)OR zw?Awt0D!(qP|J8WK=zHKI-+$rOgRPLZoD4s=hr-DdH!?I6l`~L4#FrX_nYF1sadzQJvm6Oq{57 zYj?vHZHwEHw-aFh+_Nx*U^w{^{Z}6n{&NYN&B2 zm|@rrHE#5#ywiQGe0z{2Pj02OlN^}x1e0cZ-0AH@fMHIr$zzLkI5yyNYQgaPoA(~!A=CJNji{nVd-qVI5gdpp6`kSgR{*AhFhd5HR_tmE+_yuoM0tt*Tmwf63nb`f zf19hbNOzfN0|hfy1z3f@l0{f{xz2G#4>yT$zgSPCrl(|kYvCfs1=&f8QUtYprm^eA zvn>A@F_(OP7c`N&hGc?CL8QVZ3Dxnm(S*l>&EKmpaEo~!Pb8r5PO)B$U_=S0?~V~b z`QMAxN^`d!xv<&PSp0*rV2?rYaKTuw7<6z(m0XZLPyUKmNTGiCaqN2Eo|n z>0`_#tt3l>k5HZBP% zbc&UiGN`8GJ#Hm;!d|~`UZquD-W7h>X7SM21Bo!eK`EX^=X8)zahr$r1jFIG?__LG z2t=;+BjO| zME$@P+WklxR`wN_)8c|a_cw%vR6^8QfLABP^!7RTe>SvnG+PCcY%6 zSCjr!8E@?jmE=X_1JjVlUNw*CxY!EUOL)&)Q(uQe2d2g zO>cgu_18Y-d(BH~TBMCymr1q|6mj2bvsogY>!9-Tk}~=tR8M*>Nm`?7jCTKhm{Nna zOgD^;ll8S^lNh=~V{=e!TEhM?=f*`6epL}B>Q_$C2qSp=FY!j@=Y0NdPRA8bPkx9` zYK6q&ELq9VnS>wyXsSvxNOZlWnSL|2qQ^Mg{djJQ;qQ-~&~quQe@9Jqt8^EuEtcH% z>PbsUt{*Zk{K85F(B10#U9KO;7#^kV;NCubN=(#H*rL4=es^POi7^e`Elv*{qUW z>F${b!(*sm-$ww7@5mig68e1(DDOfnqEo(wcmt`K9AhdD%7sML;EX%o|I592X-x>m z(zlJ%YfMv8qs8gS@3jE-{I6NfCv#vYCNHy<9sd&(zT=Gvy^}0R=m{&i?q;kP--Uk# zx*4eI0Cv(?CZWZJ^Cd1Ng9YPit40rBb0p@b0K9P=SkUGM1j81?0yF&|UzJlt{@3M* z(EI3{RQXZ~MohdH=`5zhB65Zz5NY)d)Jcgm*AEqZwvQYO9@ zd=3e;_fopIxV8Um9US=AU8FCVt-JK;5Y)Pt%f&&eydf_=Aa zFAf$ueH;Unp^DpO#u;nkY!bS__}92~W2Ov|s_C#!|@c%Z~Fi+1!tNnHyxQW&_@ zNuFA)b#-a$>}Gioa8(IrPj3CJuY}mex{hNI%-pLvXN*VpJp8t9fe|mdBwA3_1{|a_ z8kASj@IqRjF6j5CnyZ8s$!K8d|N8-P0L{@a@O=+2xoAYI3HJwuoc1!N0f-9%R1`C+ z7n%?ddkcjxsF^Zd=M{J{E189Z%9#HL+!-B=(VN$BrRQ$8NCaI3dMopr8X>&dH0a+wM<;Gh-t516aA^WvSB%fcv$A7s^umblN;+filUfZ! zSW$j17$9&6A)UU{f)b(TQZ;({%edVm8B;y zJUbTC{1L?J&>(n|YIfC(`o*rvk^blbW1dHZ#yRPqjPgka$l}VL*9j;+Z5ge>AX zDWp>N6@~IkaGC}7Vn~7Neb=Pk0E`y(CUgk$)W@Y9n}Q3x^8zT&3??SuR!~#MImGU=gSv$U(k=w6XzuP{u%8%Uagqmv7w+SZ(42p zurVxRb`C1IQF9q&mZ2DiWkF}U=Eazr9(hTmb$5bh591Shfr{(S%15qtO(OR2jqRjh zRep2d?1qM+w4GsBmx7oF7#8%KgPCM~n@YuScc&L+4nA&K{9`>gdIF|!SNSweEWWK9 zB}JYJ(sz@_*a8rfH{ZX7mJ2V-lRGVHY^OkMChHL`S+avEDp49iD`u$Dw+IdqN1^?;&k)d3JgwUO;NfnpZ>j4S-L&BlKNEVg zDkE^E-{|)d8yGSV7ye4lmOVQAb+Fj#^>~3+mB6yw`H)hZ{qC zs)$gVM%!7P!lx2GqX3Fs+v~YPdXoB1%23AqH;8eqg4m#C^;3nPkn^D1AMzp5vlR0v zXW!$nxw?o;3Zf)126|er8R-s0|2B5gGoUcwO5aQWP}hMPgwJf_v~3sQ)Mh;2@eI_>v zBmBdt-wkDZ2r<6Dc>3~hhc@3MtPVI=SCQqQyHobussu4D0eTzmpGQcWei;LqjrpcH zZBQE}gZ!Pt`Wt1;62@gzX7kFLdW?z=XwsGg59@yoRvvXl`X74iF^Qp~%uerre{cnqN21I8?RVSq5VY@mdAm$7(}q)yXy zV3sl$g2lI|Ka!NUi}Q`VyjkTtK|>!3^2|61dcw7+P19R^15LqHW!qqsHI5V8mjGS!sU>maM4Nax0 z-j4DM&e^=i1@6`Vh++88J~w1hT@mD*(2?ieU2nvuS!y0g?Cf^YJUyh7r7RGnr{&;1 z^(uLx#frXt+T8z}`VBkj22i^ZxN^934l&TIJb&<_P@g!LeA<2pGQbGR*>{olQMJp| za{^8qQP;}Tf5|%Oe;gJZtL!`n8f~^@-%ERcz}^yU3ItXPmLO{pv;K5I%c-XvCEzmV;LW* zb(4ltyAr`~cSSr52x?V)!_w1Q+O_kYhbo#R#t=RjS-KS@)Ox+@12uN$c-epOe2_8zPzz{*!L( zqovzyc#_Co%#r$~vqkUFc;0GpZh`ZF0mZ>64kXOTz=B!Zfz^vnuAH=(SsIlWhqx#} z!O1h9aM{W4uS#Krhj$-qOj?{KwqDty{POd5j_fZ~Y1gi2z@)(x z?nKuT$@c<->NHLRsh_T(j5cn#Qhr#^bvO*OluDMXfr1y%i%yNldc*mFj`JFCLP0He zz$%~U^>6_ft3+ODlFk7EU55>26rZ%|s~m7|TUL@*G(9S5@25h{!N$6!`IE_%sA>j| ztwnUV5jGL0!WRK;`r03;N7(TW@#i_||*Zl7_ zukpU>`=QEhb}dtB)0o-qI1_PyF}~1LWoq{sM3nnsAg@Bt*|R~{zk%}7!hHfTW0|mw zwBY7mYlu_JQ%A0xo}#=Os|HH}mV;{pNZf9vODPMAwW!y>S%a&qt|4|Ipg(L{sV7s$ zQtotPGF!p`+xl3kw(;j#fe)wxOHC4p1Q&MR-#@f}bE+sAQUC44@KsvBn+NVxL~`97 zFX?rttyo1x{_*hoo1SAqrsRFw{#Lx24pAMRw4+micbb{!XpZY#%P>XOX~n&8^z0-w z)VRQ6obUg!y)#Mae{JFqGGNfu4x0XE`e-7dP-Z7^ZVK-(a9eM)L{>)S_S3zYxVMaN z_w=O7HDm(AUM3q9JuinW9q|Gx#H7#M-ktSJkL0#wa-Owi5eZ3or-Mjq&l(LHv zFKnMjC@S1irx4g8y~Y(pm`$N9pd=bJ9ONf4H{kiWmY?I%`?od4di}R1uaz9FeRo`= zAK>N%nOyGwz?5IDUw~{o%jg4P@82nTrcj8@509~zmKsAqAii0N)=mv{PFklksnFV% z3q}FUrkzA`M92jXQs)EEuP?~SPx{lJuk*Qlq^q|Nw`7mD9X(+4W`^jki^ZxiHRgc^Cg$69)W7+z-JNiE3an#I*>12^RV0ia?v`v3p{ literal 0 HcmV?d00001 diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..7b05c84f74b5836b2d6050f8ebe439a46ef105c7 GIT binary patch literal 1416 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 Hu0mjf?%Phq literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d494625e3bfe0a55b9e3aef34729d04577178ace GIT binary patch literal 1968 zcma)-YdjMQAIGp&o zB9S@b5DAt0X+16_bE#bBay-0$UOX@UzyIg+{e6C~zjugEwovdPFaQ96+S?IacYny< zNlWc!cxwy<0N5X8Pq1`njEYKFw>_+po$uamFR!LHRby(B1-X~7)FewyMET*Md-*$0 zSp;uyZ3UzzmRdvkHE030>KU-B*WGfdI?M^Wt$-@h%*XtpdFaVPQ_beW%QYw3ObgS3 z{&&rVn$4M(sFvF1&4tMc=3?BXzEf*&3+uFu8e|T4Se=~Mmtd_<0;Lmb?Lg_|9BI@Y zGD26bO&y`T$B!mh?{Pxy9^WnZ_-?t!cSqI10e&TlvE!4|q0f(!C4VePBPRYFM^l$4 z!_w<3U*YD*RRiBM`^vscdjdV0Fq^9*)a8pUT4xZwvG z+Q8XYUnC5{sMV=^@Fkl>Sz|~&yH|d$q{X)0OH-K!oi7Cqxhtp|R1`_-l4je!p-Ro2NkOw6jz)>Y)km(S)N1|5OpX&3{Y>hFRYG*s zB~Ukf@LJa+_a;#pD|P8L|LB%DE1pYOwk$+L`SaE0QuO6Y(N4SoM)`SFD`M)anY!cO z@&i*3ujRFzFSbpS+FVMf1G~F{R0m?}KVV89_vq6G3HQdCcpWs!O!CXKKGLz87k@Y^n~uR4PVjffcdcMe-1J@ilmh_4@Y1Ez#vv4Lf6<`S5!R&(Vp zgu*SsXLU&Lwo~)(me6miL#v5E{L43PvkKVuD3A~XofG!4uUEEEF9Lp=FTZ}qS))K2 zLWR>(;4I^RKDQ^l!z0E zMyyN5L<7!g#Ulm`WMnJ+2*G{GSnt;Z?4q%z%#8!ceK%<#U{BGxw!< zmP#Dy-1_jIiip)>hT}x!0Ks-mn1Y81Qi+uw}-4IILdFw9YuSE?w#d;MQThci{T^e*59=5P%mn zXsP>wY65B^vBD9emd42{ZYK;qKnADinZA3}b#$FIi8wd|M?3uTgSf3UlYZf*uw zjr*)9F5W1u$*=C7G}+*h+6LI8xqz%1J3$r;q+@ui9LDm}aA3EJG1+iI+{04@93$h? z@sgRKD-tpvsky5jvq8A!t~9zyxNjyFq%hU~I49?e>6jb$_qQ`6+5T!-YM0yIj$JdM znaBNe45g+R3(L$b_bjzRCY-^>5r->;*ekw^H=O3mTSdwTuZ|lCTnn>J#5~f<6ES~b z>+>C=7;7;f4O-2c?%O|g!+{!#GnVX#%v9_NZ)rFUc2&|Kz4CFoTUO?66X_B9iT(5* zEB8zU9}!z{KM=OkRb5TR?Sy(A7vFI{tz!=F(DkwAD85=Dtot?uxt*Kd{{$w)3ySe? z5>hUx1gG8E`BGP`CWZs;tx$iKn8@pplRfdAnaOXjhbhW^nBKLEnC!`U^C8=v2IeC; zdUfNVd_i%h;8Ta8Z{>B4>y^B1FZ=dxkg~#gNpxrNk9zcJ6%UJo_VKFBXx-1C>K7CX zC(^?_2L|fNnt>*9YAAxO);z0;F3&RD6jx7CF4Jy@q(lG(H%;9NX)20~leyU9yZacn1j`{Ha=jmNXZrpX z=1*^VOcn-L<^Rl1bxv8@xTL4|GH3bXkJxqwy4+W9`vGN8n<{xM5Jug%J{T4|%*1wO zRA%~^Ox&U*z9>r5?_k|m(N#I3sVt?(%IPMsO1pTOb9(KuB|BgU*LbRY@_g6Grg}Zx zCQQJOaLYa5KU&aj$}`;hI{4-Tt>A<{c-9e@IzALFEBduUKf}Bk@XOUCYx?RKZ2ii? z1OFa5xzuUTO7WIgDKOG3auSwwSC~3Z1UkQg)}CINK!V;&aug+CMp0pZMX!GkD!i~w zma?}PvkZT3bpCAb!>QNrI`ihlJpmnt=~t}+iz6g`3gSiSe(w$5ku2}M=S7+>W}vtb zX)7dmJ75NO*S8?PjLTa^yUU6O(p%pTDU8#I{y}wLw3v63sC9y|khC79eq8)c`_EoW#>o{r};l|4U?%D|(Xp_F-hz^6_001MIDx2sKvZg#QAUi=eLn literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..85865cdd3300700d2b0df19825ce3f3d61172e08 GIT binary patch literal 2438 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..edb080be770bc916e7bc2e88aa67b919bdaa0ac1 GIT binary patch literal 4631 zcmbtYc{G&m`{$)pBBhjOY$?hp6^3E5v{+J9mT3$o+o(*4iLrZCO4-K{V<~G2nVFaf zCHtPWk-fnfLc>g18h+2{{C?*>-+zARJ>Nf`bDr~D*Y&wS*XO>T>pu4tdBxmVY{$VJ z0s;bJrY7gF2?z*+`Omhkz?Xd-(J=vm-6N*w4XyBB=Z4)9ttO>EvYFu7v4ii)@&`4N4$DfKIU&C9FxkCNOzQiVlIIOi&hNQm zm^7S@TGIQ~k)Cd!1ooSkvB#``@PP{AlpX0jpM}8Dgh6h2nSsC2+g^erlxUem^aQ`CvBQEX139etwyeDMZz^k3C0df zpXAmIgN=|I&eo5f{W_*L7}dmCt(swJ+N;GW@Q(Yh+oR_LI*4aurX|vJHb8@Sg$8as zJ`xz+X2a8w3qIJy@h{%FP0fEs4Z1pL>sX96A5v5MFmxt!W;XPlYFulcZluR8L$CfF zhRf|P4?}w{vie_Xp_c=6pNB&Hw7cf6pK%z##YQ{Su#6K%-?)#^l$NTimaEkm9*_ux z8E*&I|DK80=X1U}aCzJI(YHx`+T<>DE3(-+n|4*%LM1|f;mh9PjPSANh9ccx_L6cC zP?#h)fAr@>ukQDg+=r^2I%8YC#ge5yTKBqgLOup2swwb zW|rUA@mNj0x`?qbdhcOqkHfvm!ocr8UPaKiIcv*9Z#5_#ZMW>E4{c;Y_M6}Rqa$(UI+e8)7aeH}!L` zjHV>iW162B#FUc{$S!KVL~e2_xQvwwmKrt+roiI_|Bz9EE~s&91;6D^`Cg=LaV`G~ zpk82#9dY>9%AV@_#k_NNGx0g6r3NQSkb1$JQbipmiBFA`T89}i4tZzyVtDr-N_jS9 zfA$%)d8*akMpe|!4oMKOZI;>ew%|sB<$OtP)g#e5Bkh^}bxIkAY1goo*RWHnoQVn3 zt60vmedZ=+UlQbSRP+f1o}+1Du8DwFxT6n%e07z9q9}db9_62rc9$j-Ve|&~IQnD+ z0REJIDWsXWosj;+G|^#Lg1;b8C!Z|U%*f?Te}t0xy&SY9$M#QU?k9B@Bv*{D%=y@t z<06g=k+OIy+5yQxfj=O_^m6G(tL{{=wq4jRfZ!Cl{vdX5@0?b zmDrIge5xX0%82Y(@YgnRasd*nbg67|o(W@ughezfqMtbXbOifqlVj;&WAZ$@RnSNZ zrr^_Cggr93=cGbm?jh*0#ymSPqc9MgvPyx>ipfLewd?Yv$gJ!ZjMSBN{dTjKz0Z};!~bC*DsM*)M_ztKV_@Ch0iVk%PHkVCeGhc zUylpdn9Rz|m(h>_d$~$>7b)XP@U3F%r{_idZ)pa~xos2YQzzn?)wRBD&Clk%DMP;( z+*W4(swuF{y>|(1jICJX(JQe!s)}=EUb#ZymdOZcSGA22bg{Hv$?{+)%M&`FvoUto zAEBQLSRdKEHM{Me{c4z|B-=SK50Zvq7Ak{YFknH%zsGu$p+0NgX)vvs{qH9e>KkH< ztrEV&3K_72g_+SE%^8YRN8Eu?? zH_lgCZpJ8Nx_J~q52VFs)#Ams#q`!%9^*}o;APxPw-CEqv;DX#6OlByv>)oKlHPRU zeVg_J z)9wqD3((5Go_sgeV0rDAgnX-nv9JoHsE$Q#Z*sS!l!t!{kvYn39XIiA^&8UjAGqbC zp3$Qa#gqVRWNAZt(A)_uwf?*UhzFO&^~<3(`jV{cZ+@nwq9Cuo?O+8_IgU5=cMrO< zglY`WHDI0$G)~!3Ezv&J>QMHb#PzQttwH53sXeap?^4-d8O4KobqVSrR&nCWH$22^ z472N}s`uMTZy4Y@{48Q?xT8Ia4mh78>7`0C}*E9KE-z0^+_SQ^g@=esbcT7l8MEXGF7B(;+IR-fw|e{(uCwYTFntC;q5@^l zwQ+sGK8NyT^cIsGGM47ny0RDDF}jo=qaps6jP_t%Px)GziytI91IawkaLT5se$kt1 zB2vN9Lr%mu_<%sOye>-n@z26O?)!GZMGU!weSIlY1$|N=7ngk~qy)Hdl6>s=r{A;L z=F6wvp^rhWtMeR)J8$kmmNX@QXuAj%g~@hy880x}176!j@LBbLrPr-7ZXV#wU`#e# z$nj4!5vwolL^3i%8qGBL-U9)QsI(HbP4H6k)#Ogxr@N#VO3;v&r^-GUo5i{UbN|`M z9262{+t*%%t-bN&sctkq**@I-9l z*z<)Eqk6LRM%Zybz1e;ZC^5c=_jH33rzjVigq8A!OTDedNW%hll~Lrir>W|X83Uh~ z!=9~GYC)Rh$aDFF$Z3Zb$&1vuT1KekyaT>B!(Y0}wZHNN112mIJZtl6Z<1-}JMZLj z3exiY4Lp7VV~|@fc^{`iX~D0>EYo$Pc%M`s;;0>^Co~XD9GBBJY>3*&ty~h$KA; zun8L6x>Avuz}2G0jcUvm7C%b?a+$P|3b0vud6`N{C^FqHE`O%&Y=4#Sl0#Qjby1VxANEr~AsE<%S`{;3T5WeH ziMt3gAUjhx1y87|;vMYei(UdO$Bl1K+y1f`o>gjAoxmGW%}>KS+d3n6{m2F~IJ!%I z_U}MXHTEP$+V>l>iH+~@CAmz{s|HdN#{|x_pM?%$rkxj!(ZBYL+Sa28vM?Rxz-ay+ z3N_7G6sImF{q6$S(Xg%*Ap62N1T;?^rLj{Y^k!d?-(O zAi|yqEKRd;@cjyhpi78bY6Mjp9dJ_K?~4KzbkjkPO&5zy8%f5K=hn>LTFUcveVO*~ zcZ-MvK9>NvRT|)G6>RVh^)uo{jiuO71RUk?C#X%19gAnLQfa+**cl8f!VUxmz8`rsEi?#Wl0wa+eDGkRXS9A1}tXXu|hD zD^gu0eevCtt$U6>c1*2&@pI6d%F>sI?N&<)kV6Fsog)5*g!R3_6?zr*CG2aC5lebf zq}mXorYsWc1hg&z%Bt#w1*(0(#xkMvZ1L});M=(%zapp2GEIM|y7&O*G}WI^=sX+K z=!3KLOV5-xB1@D6KMx|RfBZhJ6&f#>u^NY~Ep91N#aXXBzNbEZ$%Wsu<%x}3 zM==fFQ`Ll^+F~HO%D#u^qj3Z4YUmYKOgo2(XP);7XST#lfPCw_zJ~Nffvc4Heee0; zP#R|G0V~^r_oHyps(Q=}%{HEkPwqm^^yl!;%`ja0L-?FELN@5g3b}@eLZ*4j65r@I zC1kbo>t3Z8x2lEouD@g~6`B#W`S)R;yLQl89$C}@7s^OCh1v3NkgqB+Vr2cEjR)cEX4h($dWzn-lys!6Uxrol5y~n7b_ewyf#IQA$A!u zcF$hNK%RydV%>bjYYLWnh4ZA!v3q4?UVrw?Qd@fgDJ06C+^^9lKxqO!4OV}QO=iw; zrq0Z+cUcAO+BI|n@?iubHxF;JeEqeFEyej;uq*9|S(3;i9pvzKh1U1pRe-H^qvrhU z-Nm?XRdI6oE`sBI@IalawMoFmbMTXAf?m4H){-QTv}K;_cY=D)gx1Ul7=jjV$-Qg2 z+opAuG?3DfFcKU;tCbQ$)kuMW(+}?#j^ze5 z!7%<&xlM4k@O&-=8XGv))EQoX)|mKeAT!`RkHqc3pxN*++VoMcF~n*?+G+Bi!$SgB zj#RLJtH2E1b6%pBl|Et1w|J7u9e z3A#t(@q2}{H$w=I0`hEVp{iai{kJwjcO}r)JB8C@A!Gq)SKujv9wm8C?3Q@=M&Zm@ z;H32mKnqEoR`GGlwAn~rTeXa#YTFCh?bCI}N+)Lvz4|1=#Rn0#tmimMg*DU3SIJ#v zoXU9ZX^hLQh@@p0+Q@Neo4|`t8m+f6>Q!nrU2?{$UEUgx(NFGFp)HTxjS!N#j2!f_ zb|rU4!r5OcuBuPj>!epFCN<9A3Ed{n9q?faeCyocG+-*Zm2^2td;e98doN=QuH#hg z!nK;mO9ESHMgCab=_YC<`=v(_zDy^EvTsmec0OBjk*BEaM7sT4(SXpdkF7(c3fOB4 z8onN2^8j~V?FK}a6XyBLv^F`PF%|qI@d8~^|S07*qoM6N<$f=ypEHUIzs literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6d4ee6066ce1ebda1d3fc184fe556084a0add588 GIT binary patch literal 4995 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 Rz;JDw?Kwxwx?g|0`Ck(i-4y@; literal 0 HcmV?d00001 diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ef0ea8abb08b35baa2622d98d9c7a5f9fec86d48 GIT binary patch literal 874 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 Z{{i^{wBM+|!hZk&002ovPDHLkV1f%=-|_$e literal 0 HcmV?d00001 diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..9fb04926db278f37c75aa86448f1222c6e41dbe4 GIT binary patch literal 980 zcmV;_11tQAP)Lx zF%`gZ7ben*c5b8LR!=Ur@ zFa-XyM<7AY3-2BUxeP2*Amo5)1M5mOl+55TB}`4DgZ8LENRvK_)DY3Qz{X`d<`i=k zL9*LVY(#s!NQuz~A*bTD!1{$6)-2G}xks;DeEu$AXoDRhCp)_YcCHHH(1uX*{P|iN z-(!HGr-mQJ)bgI5aNwoOA8LXicC8NK;Cc^&t~zqdLhXwLCKWKaBICu*lFqUrLXaK4 zX`;T_LGgH|79p$KZz>3?i-R{zG`w^$F@N|FBMy=Z!j?|&zi#63YX?O>L5vs(>xK9l z9S9MZ9d7S66OFC@LW~TEq~LwssUHM2ggsRjn%+B@5b+m6)v534#QL?^UWhM01a@38 z(fq+hVV?gGzJpNn>g@I)4oHYT+0iWr;JXfiyqw`nkx>EZv49<=I*yiylEqE~ZtfJ0 z6PpY*(K-JQKxi^oEcME+rQJp4WmCx&va&@Qwk_B3O-4-TSq{=SnOnaK*z0+Fy(#?t?BQl4L|vsJ2*&6~<`xGW@AonHE@SW2M+8J)%!2bbz?CH={c%Puy1GDplp@?2J>R;ph` zB<&03G_Pt%;CZVTs$4@xX|v&7BC-)AO|)p`Pt{mTbCK_hXL0OX8}cQ^xIeWal4&H; z)K8uaz}q$#XYW}G%#zKZa;1*a`5HRpe9?FYL5P7i98_UzNV~F>Vk8)=pCx2lc2pZC zySP0E^QUnYDaJCOerc7%A%;5X)TeJkZ9dQ>*R}MK2^$O-9@zNU>B5ok^W{R!kTa*H zU8qR?OUba|{)b2_82iiZAo?DqA!#qx3zsVwBy41G^TA6kxvF6{gm15B7cokN_kA2|xmn03-m(Li+_YZh_h*qp@-T0000 + + + + \ No newline at end of file diff --git a/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..94619d27098227418ec36bef6a136311ff5862d3 GIT binary patch literal 993 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 JPDHLkV1n~%($@e0 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..83cd1ce4def50a38cf86a16252f5e4883c56cea8 GIT binary patch literal 1960 zcmai#c{~%0AIE2Vw#=}imZPYr94%$;n^q`KZeqr?6}degxr&%EX@*knBiEcu&Eet&#F-`DH?d42!Q`a~}Y(?@tR;v}45BQeI@Di1C7;r1Y? zgT9N@sNet3aWknyjZP8@W|yRm)fYWYtFyBciWBfyMPqwSh5GMkZqrwuvCYe=)}K_3 zxwFXrn$P{)Z9&=18sYr6;{)6M%i+xTU;gWuHy7p++mC3}2QahPaQc1COQc|Gn zYA6KgI$j0Rbq)WE@0GuJQtW@Y8tNC{EB||x6)gc|GUJ?lrZ4c-n3AK=%Q_Wj9t;)O zdo{R9Fu!!^$q|=cx8z>ZQOTFMUq^{t6$KUcvG|7Bf(ITZFu7>JNEuP>a+0R3gjq z0F8&{LrWmpGkQiBU#@(WCN8)}RqTGaTV=U6?h9pAXr zHcETM1U?;%0`t03@Zfh^e&HJ{?VqjJ-NxQaI(?aX1LnLFsH%HiAvjS%6} zuGCnWh{^*AUunS8e<92(PduZe1=O%^7lvfv+V+Z&qM@20ndrIh4&ikAdKU$*cwipU z_UqAns$?i@?}cFr?w;*+9N=jWJi9Vfu2gn&_F!+8C5Ln#gZ8j<+?`o)G=l0r2&{@k ziM3W2`^Dq&IQuy?;r5azWUUK8I#)4!TSj;$}-z^H-KCx$Q` zC(yOz(ERk?Mxf4cdqtY>_7Pd_Wf*?aM$TVgAS_51(R{xV;GDbCV+%`paq{D11#U@F zV=0#9%Yx2+yBRRDUM`Q73%wT#%U`KO4WV;FQo(Vxu11p?ZZR2+sZa1)&n+T?t!1$p zaIGv>VX<@$a`fAu`^7Vkci%nLQ(F0DprY$OcmKmL1Jsl4`Wz(TNLbv<>v~u#S`S2a z{;9I_`hxyp&f-dawD_#d#oK~3cc6QdNwR{!y5B8Px@0LZ`GjtnjLye|{4Gz+&##9> zDZLfyjo!0;oq@WdJ^2<+JByP%D=A#ANOy?Es@J{sMkHG|g4%?Z4U~uz++`%w#UN(y|nE~IXbH&`XTLyl3 zJxa~f*FVZx9Ku+mYG;$2QrTk0`QyjXWrnlOS%Aq%UG63c7!&3x4=U*HsXK7znmt{` zjyW$)k1yr*P%4buY9@Qjsy(dT(+Z8_+ZNkmE7?;DtjFmg$4|LjgNx1#FY{+g(gXR7 z^Q{z@`)#esL2l)d^O!-VV-BUur`|cT_MfNQDv7VNLSC7{9fG1V;*0ar_LWJnLM%H~ z5|Kw*Rk+qPa$g5A(wY&-AaG*C6rXZJMK^cDbg9F1H)NtHuAX@ZtqV& zXcgSW%?p#^k%bbAub9eS~nktmd@{CJ+(d)CuObpjIDz)T$C% z>o7PY6~%xi=U8<9f_K_sciCIRpm^fW|lP#>v*;7BdH`7AT~2UnS2n6cxfbpx&a^#`FV^?>HE!MlP)oiN56R#Hwb zkF=Y@JHVCIhd?xq&KCn>1JlNwDn?{ODxo%2;G(0yIYx4Am(tQFD74@{J_G*4p^5b@ z==+0D&C0vZjd~+tc{}C9Nl>c}-1Og_;)an8p@X|+XO4MmsE=)Nb;e)Kxp~!e+;2ia zJzE3?z7JoEV)OV7)3DhWp(7+!8V^(1E`fW&qUBKRV1kgzd372OFq}!7Qe6HW(DGUJ hf12w5YK%wyVS>pF)}{di9QF(hurRYWtvQb;{R^=pvjhMD literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..c2fcac1f02212f5c859666dd719e030fd9621296 GIT binary patch literal 1126 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..6c536fc047c573d7e5203272aaa39f7a8fbb2cc9 GIT binary patch literal 2219 zcmV;c2vqlpP)+5P~-zFk<3^ z@d8K`6@nomL?aaf2_+3EA_9sUD}{#ALU+$){QsGAw%ZGpZg)H9Y-f^9jk}!P^L_K* zzJKP74Q6N^wt>J9UTX0g5zP2* zy<{*0yj~)h0bVZ=+<>q5cQXULUTfe6e7*O>4fuNRiy7ecx+HGE*L%O*fUozyxdC7A z{c{7pUJ^`024dQfF|)rgcyI&0UJ|$gUoQzJ2E-`_nAu-=oLHo!*>1l^h~izl7~cVT z$Q6-tLB#-r5MXHMzTflz`=W1hASxZPV$Xh#zas4dWbh?&eptc+NG0+kMg-TTS6hbw zPp~dG?I9sHUcVyQ`JFnfK)VH4I6K?Z0MjnxaP#Fn3kCt#_=gXBkNZ%WQh@ard>gOb z+y-#xHI}@->nrdb{99%-{G5QT2RvvxE1)dVX%P^mrHRFy{WP;_7M{ZyI^#+X3u+Tx z-e14Rg`GcpFk%?Xf_JIlll3&61(hE$nb-yVsR;hV3Vg>?z+1ufUfb-zy4@~JsAkF~dHMn|k4)ar2A*aT z$k~~n13m#ClDTvff$zZRO7(?<0e)XNmP92?020Wj&H>csxE%tQfT#BfElE87Nwe$?Sugrf|>tUi-5(SrlH|?AI2m2 zX$QNhPY;Ov%kBntfQj(Sd`1D)2iTFxylM<90+R_*1(US&5*? zI{dc}FJizwc+!J$!{Y;ftZr*L6zD;mi*$gskJC+bpOoQ$C+_LqNfDPD(XvrdU~dAv^O~*R*oZjW#?v z(?+s{d|wy>2Hv71*Fv4F*B?ttOX%))LV+#pVi5tekSrph%#LQ!bx8z7p$HQ}Kls+k z943wCGS3gS{Ot!lcw%jbOgTeKp(3mryJm~-O`yilu?kkMNyL$WC~V{xEtjQ>J4y1K>x?EB!d)2SJ_-=y;};oB8m+pM>L;Pg;*FrXuL8v36sZi zx%w`OBt%?{!!?~jrFF4%lG4;Fw1Ol5`0&oRN`-R+!ic!xSRcGRH=(j5KYGt-;}LHI zpzmh?`x#nyOIpyD22TcUiUSlQ$Qp=*>6j5Mm~F#Zaz#7_1Vr@#chH9wkpK75THf8^ zz|kgOg6{_M1(EdBtb|ll&$R2)i+aN~_K&R$2hH?qyuah8d|12FRm%~r&VDc%($WW# zFmWWuc94%BgEhdmMi)NY=XU8U5D~N@j^cqEEX=Z)A)v4X2vv+#U{HP! zUC{yDU%-RiF+7;@q_EDfv9lRdWC@5{90+RzS_xNK2GZBB+3v`_2UH2mWGe7EPuHk; z(1g-;zB_OVwNr*itqWF&HYOEqW2=~~q(7>6vw|KmMA;F6UUyFdCXPbs`aBF83H>Hu zu&f}gYAI`>;7PNXfa<=nu3whmDH2Gg`0-aS+sGlHNgtX#j>9u3RirT>T*#<^Ei~*C zC8)%M~_HrI1{Y|^6w%gv*LrE5$18sotUl&qKG#*7;#GP#zB2h}nK z>*lsVYeK0ap`nY$N_CrRm+R9`%noH~-M6Ze#SKg7aX*n+8RrM0T5oA#A%Y{t5|Xof z+lETl7jbxacibOUpyP1`=1~QMeEp(U!f`CjAO_DB<)v^8NSq()Y981WH!;pwL1FRX zrF0@u9G@r6OYK;wxIN6<#DF+AWQ-LI90y*iC)CB|906X+#{|aV5C>lBXEjFs1Px}+ zkkLEQcqt#08HfAgrG8pz)bEFxll1gXBtDeR?v3K_Hm9i$mD5zsdBWyIZF8cwIa5C3 t1Qe5ys3rnN%>?tvGDCnFhJYbE{sR?%)5p?x2lD^`002ovPDHLkV1nZrB47Xj literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..bb07b4741510a3da71b8674a8e023b45c1882e21 GIT binary patch literal 2668 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..5a6ce52a368c582dc990800cb2aacf3c29809ee4 GIT binary patch literal 3259 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..0b8f73892e1bb50d59dfddbf64d59a5e2719f619 GIT binary patch literal 3302 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 A)c^nh literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..5d533f6f1e67f333ba3c1812376b55b865c3930e GIT binary patch literal 7024 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/android/values/ic_launcher_background.xml b/src-tauri/icons/android/values/ic_launcher_background.xml new file mode 100644 index 0000000..ea9c223 --- /dev/null +++ b/src-tauri/icons/android/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/src-tauri/icons/icon-source.png b/src-tauri/icons/icon-source.png new file mode 100644 index 0000000000000000000000000000000000000000..69abf33f0fa5bf8eb782a23cfef639e8d987786f GIT binary patch literal 15779 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 I-(j!(3%&H~bpQYW literal 0 HcmV?d00001 diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d0b55ea7f2fabfdc71d0c50efdbbf80c8a401297 GIT binary patch literal 1438 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%0DN_UoFdTsg+}G+7$0Gp zeiiLzSHfgvk-4=cZmo9V|2G$XrkA~vci?Vsq561)dSQ})H6c)5!HX6l_?75b@r(3_ zo(&!Vj&-KOy#UpE2gOX#w^rvJBXl!60(z|eFvL=Ec!?e|kXi{6i6CsAQfJ|z=^KVv zFhVe4zGu+%n)fGx4Hde#iFsKXccOm{B62${OtV~QDA6Ewty&^}4W4>|da#f-_65kT z2Can?{{V_b>`WYn%YABmgYUaK^!uI2lf~LPowp~ebD!3&6nB`{(lbFyBxf3Ky|QazOCapG=E(&w`=!!2(nTK=HC0U}uh zL?|y>lD|PT#JfLo8(VV=h)Xd{sg_9^fyspKjx}~ofU->`$2JK`npZx>HwT9zQR{;b z>@xru4j613T3Roe=8ihQ?qG=<)JT`r6{^<~tL=lQ{Yre>71sg6y{+SbaD@@~Uo{3Q z?u)X=grqb*)hi~Q*9KIAkT;7_Y-F<@u&UcjWq%i#LN(tyclMxumuQs?u)HaWNVs*loeFv7d zSGYg_Xh5>I{<`QudGIH`amj6^NKuSd#k+o$UB<}>94Q2U+f&VmS^RsiNftOWOHRH@ zdr>(j&7Ue&Q)SFtfEFh)=pVcDwJ>;sV)~;khpsMn$89_~i_Wwc| zey8wVZ?Fk$aWPDyvrf9flJ<5aHps315;F}17}4;n|F1gf&;Rq)w}*pS zhLCZxQ86F3yLqL`c$}y(g#rQIlZIVXZjRALPU>KtjGy7-n;Hr{gZGomAV(KSc)pK- zG!dcXlCM`&Qm_;dMi5#)G#;q6&b|`aE4+SZJ?uRe-E6MVE>or`vj;wS*e+5>E`Gu? z@yMEmtMJN;)i@ti0M)q26PP9=KpA4}<(LX(5!3{_-gI6isJ>b|Uv~|;{nuo1X=#(x7@(SRb!0*qxQr>YJT#ATD3|y`_ z7Fj#1;jun-DogcYw}YVY@dR-ixQgIwoW!83qm*X#bq0HKy`

      O6J5|5f^Y4f0^?oJ^I(ydRlDy=k0p7K2kO8|y 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-20x20@1x.png b/src-tauri/icons/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..3423d7b949d0d0cd3c88b6d26bc8349cc787f535 GIT binary patch literal 478 zcmV<40U`d0P)%A7NPzK6QeNb8t%o1b__ENP=O!5OZoT5l42^`lO^ber?$*lm1D8a!>5FIfB z#(->rV`JLH?ve!touqkDh_2G9aFyUA&ykt4Fgs*m@vwxaEJG|L5^+B&6ZI&t%^4FD z0|Cq*l<<<{h=&O(%%><)fGklCNDcYhf08*-Lvwd#k^vcE2rHlP#3(=tD)~9W%YTGVX!959ry$eV2xwBv)C$2y7 zRUy}c1P!9Nl!}`H!RN7!(Y^py$4%r*-18<8uW3^?cB+fw{*9sRYTl$ssZOF)zI|qj zmZof@+XZeOnW$1LEY94?gMa&Jcbo#%WsSU(9e5Hqf+D$C?@e%LMv9`xqV%Vd{{;OCLeH)Fr^W zDuL7cO=%h&@-dphtV=olKPbYjJ599hQGQQ8c=(=)zDSG^YH`ymq7*xxil!ebV~F|T zy82zT-*=>wC`1j42t=RJ03vFLe7NgZv4> zbnub^>J+}QJh)3eE^faeIEvgtQnajqxwIZ{HgRmXDeLoMw}ZQHy+y+%YLfgjmIYdO zDL6haKKZ!y+QX_9i-%hjAnTm%0!MckIJM85wl{Cmv3IkMpQMetRxCiFq{gBGIk;6- z$%#8QUXl>=In!ccHHowBVcsdT>=9(i;7P)1JbBN?(?K6sdR)W`&V$Q%o3uHHHyIucALp9)La z<17s#$)88u4B4rLSAK@!=9skA%5ND0m1Xf3RwJpz)K-ZFe>CNqrY`d3_d!^oZRUR$ o0fzF!^mlOzm;$DNDPYp`2XwJ678n)c*#H0l07*qoM6N<$f?M`;1ONa4 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-20x20@2x.png b/src-tauri/icons/ios/AppIcon-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5657b2852b254312e4630582d541555ab86961d8 GIT binary patch literal 810 zcmV+_1J(SAP)Y94?gMa&Jcbo#%WsSU(9e5Hqf+D$C?@e%LMv9`xqV%Vd{{;OCLeH)Fr^W zDuL7cO=%h&@-dphtV=olKPbYjJ599hQGQQ8c=(=)zDSG^YH`ymq7*xxil!ebV~F|T zy82zT-*=>wC`1j42t=RJ03vFLe7NgZv4> zbnub^>J+}QJh)3eE^faeIEvgtQnajqxwIZ{HgRmXDeLoMw}ZQHy+y+%YLfgjmIYdO zDL6haKKZ!y+QX_9i-%hjAnTm%0!MckIJM85wl{Cmv3IkMpQMetRxCiFq{gBGIk;6- z$%#8QUXl>=In!ccHHowBVcsdT>=9(i;7P)1JbBN?(?K6sdR)W`&V$Q%o3uHHHyIucALp9)La z<17s#$)88u4B4rLSAK@!=9skA%5ND0m1Xf3RwJpz)K-ZFe>CNqrY`d3_d!^oZRUR$ o0fzF!^mlOzm;$DNDPYp`2XwJ678n)c*#H0l07*qoM6N<$f?M`;1ONa4 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-20x20@3x.png b/src-tauri/icons/ios/AppIcon-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..426b951de7d94b17b833f31064c404bd125f5119 GIT binary patch literal 1147 zcmV->1cdvEP)~2r@bmjY3PtUkQXV;{AW}8$&Gu_bD)bD%OSL1Ej zJ*ROA4G)*tu)r4B0$X4UY=JGX1-8Hz*aBPN-T*7P9H;Y~B*6dKe{!z+*Rz(%iC&?= zTxe4kH+5Es`W24XHQxC)LW0Gb?>#W68DQ0*!uDG_ zpWQ#!#9ya1`n-HC6LxY|YyBt`wr9Y3uzydanx#1pmjK%n;5^tPrxH9Rnyt?pS z$BD$4F*Qvezhk|N`n)#6sU&a~plHUsKW|8>s1|8`*D4#Fs%S2^G;@{ax#i3$!LX2sLe zV4rIDrm{gZUL$+l4-Uro{&3SY2ME38dKZsx^>C&{e=Z%E8qMoe(7#_DjiiQdbwuR7 zXSey-be)Uo1(f2?<;O*xFNgsNTH})mUfUP7HP7+NLjhI|q&>2ti;^xRg8V^1wr}>0 z#pa^MnX1-FBXHOD0CNppcmV4uaHeTS@Hf7UOqYYHicx&q1{aTPF5aJ=vLLeRO5^-Z zJl)FG)3Whr`pQaBe&dCE0<2%>U~0ZNe|Cy?SI0?HP^K00yF}ec;nc)u5B}N29_c|7 zj^Cgl-hQ+Xm)BCQ7vaxdk+6iDl4klBQbuNt_zCH7u%_0_@MkvO_e$eF@RjlHPWQ+r=*&8>?3>!E5LwJ^(vfLPdxpp`)pQbe)SCRhg~0YwlS zwG<(m#zG50L`1Mil#5Bs-F}TTZ*TEC*^p-hx!2s@&hGqn{%_{L>-CO&A*}QA@DElC z`u{<7*$WL{sns8ns64KeV`z;hYoYOLVgWAl`Pq3wBQ6JC5lWONx^OVSP_Ku2^ewSe zH^&dtx5MD(sSpQtno{6pp>i)Ze+Tz?*xzFirDUt~_|8uYgrmDWj1C0Y+^O*FO$N_6 zXr$ty=ayLBI@$kH;ml{kv8sp5M*>W}PH|>DvavQF$jDLm8qTO0X87PES9qK&zj!#n z<5wxp--_UKOsdStVI$>W26DsnS99Q_7b(s$P+(<&tAc9Y$a$7`V0R8&;)c0;KbO>B z1+X+!WL<0!s@pZL4F;IzhS|V-H_RO!b7K+x1#^&U;smI)DcqS(aAK^E$)}0!W|3NE z*wc=oTnqz&m+v!-+>OxPp>X42jJLCd;X?s>wrXn}M!Vco$`jUjY-I35mR3yS((TBG zuk?p@RFc$@BNa;$>ZaCm+`*MUf0yF=gBaVo70&kgR%Yd*(xOK?H!8IAo))&4WIz|6 z8-J2mCz8EAx!1QcYqbV*pzo}3Vk*Ih8X;hFD8@rI4S)1rgwy+cY+)-D1y+(-mHjZ2 z88u935Anl@sHWT!7lWvT%H2y`q!ifCCLreowyE;__?n<;w*2carPeo63%bthD=I3{ UZ-ci9R{#J207*qoM6N<$g4u*G{Qv*} literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/src-tauri/icons/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..429a5af6313a6b0e4f5f40f451ec0c4894ce25fa GIT binary patch literal 1068 zcmV+{1k?M8P)KJcC1PB}kRXw`kl;it;lRZ*C$YuF2?qyjBoboW5X3=(1A-8Q zIf#UV#J-LMu`e^m%;@Uss?U30b@v#vo2u5G`QE9!y1(lB)%(Bqz4xjk)3!BB^Z|>Y zkC+D4pc+(zYETWTK{cob)u0-*n`VfX*OL08p0q}S*8Z_vt(7uQL4P@b=lQQKI(x+E z9xUG=I|Za%AK0TsCao=s^z3Hk40P-;fug8T7yiCZ;(L?q5|)7)6F^0|z~B-An{HOz z;$srEpJlgiR?a|O^5l-i7RHnt>izBuNu0Qq!oYq)eb(*;n85c&iCN=K>|GjD&}%~2Z<-g@XC7fQx?oprkl zS-qkK^2aZU)kkbR``}?VwHD2pRd z$ee@z4Jp%c{jScJ>xX)RED9bnr=T4{zWz#(lz6`Wlqd-aGB=>ohy2peTCNQF@{@

      ( z*%M8a#C(cN_gs~DGM^1871*-KLc);{h3rxGl9O(^u0C|J^-K~qPh1?j;V92?OE!Z% zUNt?6x@NyaDM(N*=vktd@4MJ^GO4zhp=AOGYf`xP#zQRPe`mv-D5g}H_?c*tc0qwM z7<+Q_siexR>{;G!Sf<;~CRJ=2>0jSYtsNH&83hzvGP?QPRsCcn-A{76#e3$9j~@11 zOsem&ghve$*f`%p6SZeXA%ey&k@aN8xWwZ|{Pdj^u0M8_gxR}uCz)6>HG;aPaN^Yn zw=!zKV`k6tP1t=tsj4O`U7u}QV4-q^L5+8dtP29Pv(k{^xHa2;&X+I`#n_V^uU0xy zi9!d>?4<)}f^hATi<7rgDvlEl57!Kpi5qCr5TsZC8)yc$j3x=yR~(uucr-oqGcU*L zyvY&N2Nk5{=T1tE9 z-PbM-Ty?U^s+jtKT~rUpqW=5dvWlSpP&Il;&j;9lDq!qzL#^dx#E`Wl=^(rsc;o&2 zqoj+JJ$@vSsgHSKJcC1PB}kRXw`kl;it;lRZ*C$YuF2?qyjBoboW5X3=(1A-8Q zIf#UV#J-LMu`e^m%;@Uss?U30b@v#vo2u5G`QE9!y1(lB)%(Bqz4xjk)3!BB^Z|>Y zkC+D4pc+(zYETWTK{cob)u0-*n`VfX*OL08p0q}S*8Z_vt(7uQL4P@b=lQQKI(x+E z9xUG=I|Za%AK0TsCao=s^z3Hk40P-;fug8T7yiCZ;(L?q5|)7)6F^0|z~B-An{HOz z;$srEpJlgiR?a|O^5l-i7RHnt>izBuNu0Qq!oYq)eb(*;n85c&iCN=K>|GjD&}%~2Z<-g@XC7fQx?oprkl zS-qkK^2aZU)kkbR``}?VwHD2pRd z$ee@z4Jp%c{jScJ>xX)RED9bnr=T4{zWz#(lz6`Wlqd-aGB=>ohy2peTCNQF@{@

      ( z*%M8a#C(cN_gs~DGM^1871*-KLc);{h3rxGl9O(^u0C|J^-K~qPh1?j;V92?OE!Z% zUNt?6x@NyaDM(N*=vktd@4MJ^GO4zhp=AOGYf`xP#zQRPe`mv-D5g}H_?c*tc0qwM z7<+Q_siexR>{;G!Sf<;~CRJ=2>0jSYtsNH&83hzvGP?QPRsCcn-A{76#e3$9j~@11 zOsem&ghve$*f`%p6SZeXA%ey&k@aN8xWwZ|{Pdj^u0M8_gxR}uCz)6>HG;aPaN^Yn zw=!zKV`k6tP1t=tsj4O`U7u}QV4-q^L5+8dtP29Pv(k{^xHa2;&X+I`#n_V^uU0xy zi9!d>?4<)}f^hATi<7rgDvlEl57!Kpi5qCr5TsZC8)yc$j3x=yR~(uucr-oqGcU*L zyvY&N2Nk5{=T1tE9 z-PbM-Ty?U^s+jtKT~rUpqW=5dvWlSpP&Il;&j;9lDq!qzL#^dx#E`Wl=^(rsc;o&2 zqoj+JJ$@vSsgHS}2P)1i$6vxk*@V zhsOOJDnh6TKfM)G)Kix2C+^r3b< zJ0o#jd$^T_1B#ppo4_AS$8vyJ{H-bA}ap9*U941xi1y*agX|ON#1GY`n5pEY?_x;JC zMnkY#!o~Dd6=8aVRjQ!nWCXXp?80xyBbZpJCs^&^V%m>&hPE!~1J+0~uY-R_uzZ6H zzn_Spx)O5Lv8PP&wYt*+Y`dJiSP57R1FGI~tc}CrmPj1a8?07vRUECGf|FN8Nhm-K zi=K+J$n;obXGe74sL`)DGMPl&%VP5oHRgYbBg9DSR4Os^^7{MKsF0P*y>=+(T zq}aEII4s-XLBoe$Nu3sBE$Z6U*V}S=h&*?QY9UOdSktdurnCsX`51?%K8cqu(5vw{ z0-it9ge8|-@K1-H@mH&l6ei%lY7V8`ijs*8wd}@5A9no`O7B(gL%Vx{4f8HAp}iZl zi@(}@9G-aWE>YFG?+s6W{cW>nF|lAVSo@JLlM951KUc>ZZgj*Ah?nabBe;FQqKEDf zb=VbedJ>*x^uWUrM_v1iX5&va5>aEYZL?Hr(Vug&nsv{4G1U3MSTY*L@zqcOrYUQt}ML#G;EW z`N&)UmL*)3*x>`SHjI8--3m6tYT(IaEB@1u(*Rw(~oTO`hCwsqIx#9){x8aqZxmVJUvd0QEJR8&uT>W zwq1mVw;SW^4JSEBwg*&;!q4hOwtUW`{{h@eJ03CBMQ1|ck5IBUCrkY+AU-Qv^A8;7 z(wp&oIHKY55bEDfcl5m1%A;nB7q|D1cy%GYC&CS~UwD+P!*z6H_U6ky7ue>+QhPCQ z55|mh85|KS$BqRf-eu16`Y)t-;b(d`kAmn2@%el2=)q(7jT!TMA|%KW*oTJaz}-O7 zGY8m<24lS`Bsz@=EX%ngYG(r4o=Qe=2`<4UBe(>Y;F1wsf=h782rj`TBe(>Y;F1ws kf=h782rj`TxMW%EKWNpF0j5ga?EnA(07*qoM6N<$g2t-+*8l(j literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-40x40@1x.png b/src-tauri/icons/ios/AppIcon-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..5657b2852b254312e4630582d541555ab86961d8 GIT binary patch literal 810 zcmV+_1J(SAP)Y94?gMa&Jcbo#%WsSU(9e5Hqf+D$C?@e%LMv9`xqV%Vd{{;OCLeH)Fr^W zDuL7cO=%h&@-dphtV=olKPbYjJ599hQGQQ8c=(=)zDSG^YH`ymq7*xxil!ebV~F|T zy82zT-*=>wC`1j42t=RJ03vFLe7NgZv4> zbnub^>J+}QJh)3eE^faeIEvgtQnajqxwIZ{HgRmXDeLoMw}ZQHy+y+%YLfgjmIYdO zDL6haKKZ!y+QX_9i-%hjAnTm%0!MckIJM85wl{Cmv3IkMpQMetRxCiFq{gBGIk;6- z$%#8QUXl>=In!ccHHowBVcsdT>=9(i;7P)1JbBN?(?K6sdR)W`&V$Q%o3uHHHyIucALp9)La z<17s#$)88u4B4rLSAK@!=9skA%5ND0m1Xf3RwJpz)K-ZFe>CNqrY`d3_d!^oZRUR$ o0fzF!^mlOzm;$DNDPYp`2XwJ678n)c*#H0l07*qoM6N<$f?M`;1ONa4 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/src-tauri/icons/ios/AppIcon-40x40@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3f173612cb0a2cbd72cd25677aeddb17c82dee37 GIT binary patch literal 1432 zcmV;J1!ww+P)~!p>^5?w&a_`#do0%p5o~?~ng; zd7t;0HG5W%3b0MsOh&)}86X2>fNTtq0Wv@a$i@H}AOmE8Yz&YAGC&5%#sC>017v`c zZ<<#5TAbsNmM-sC?G|A;_OluuAi;9|(!%JqWlVgb1aH(;f6MPlkJgNWD4GEvEimT+ z^Sd-WeX9*WPz!6ZfEPdYaOh}=R$DH(hSeH6Ffc4|caMcTt}>8w6~sV7o86}2z5PBu zI^ZK)<9$=BKvF|nM#KEMdd2(gS+!`8f<$fb?zzUo<2PGluJ1S;VC#22GS<|>i^P$n z3kQY85HLS1J&(Na9N^KtNY!MdyeB?zqI))74AiOw{#w>p4IU|s?x)LZZ}0W-$_^JD zt=gm{sHQ4o#)B6tZT*)XUj5udr-UaGg4ZwrtHLAK*A>7wc6)epkB38CV0Tw0twH=iX|nt)wN3hUUR#Rd0je29JS|VfN?`X0=jFFiB-4R#jXk| zElv<|e~+LMMAIm2;TT{k0N!w!5k2)}Y%}Gz=|3&7?Daej{837?1azM4BR+Pcg`u2C zl?wHGClFF0B?fBkpOjhn!M7az_*aOvy)N>eQY4i(6c_JYXky6%6NB=%L8i_Ci%nK? z&0~WC_pNu(*Do-)Q^S$t65=+uqHRUCQXUChbiQ6Z3z^mc2@EOe&jEq^B|L&SqXlrJ z@@C1*OWUijpem@!Ffej8$NcU~apx79o>sedFOVX7o zE)qmaDijZ|xKPJK*IO7IslO}N-G$eE=1B#HXm3G9SA}AuEzA6VStG9b*ew;^y1I7n zwI;5+#K2%q6n87r5+JG2HmkR!=)KOYhCM$A*z~nuENf!dC0Fj6sYfnfuXvb>Tz01O z3j)?5A-=ZD!*3@-<+6o%NO5xIQVVV{jTQKRnhoTlj+|&%wZ&6kT2~K(c=g2wmP>a& zRi}8EdVsMC+hu||bTo)g-r_^0IQBiV*uuhY14DTv9uFG=V7wclQ@4#@`Oz-LC@3&2 z+b?%yD`#&QU=^dH`#G7FM;)a$tpJyb@276D<&2C-G@&#Uz^FEqO`E>{5HIw)6~#EI zaq*=FmMyYmhbOss*l-FYwROtu`-vPL+I~1Fc5mVa1N9Uyzd*;ZlT19+>(Ra^)x@z& zOi+n5>Gkq<7svlqY6}9@(V_T9^&u7EUIOtjQGkY4>O#jZ7VRu*oHB|BGf&B8?CLFU zF*aJNGluRtI-Xr>NA;oBEN3F*Vk3^gFUP`)0n5`lOsHK?F>j{Ky8C|(qS=_678n@L ztIr|8-E%ZtDfi3=`)VKFtf?iJ43Ggb mKsE-*02v?yWMhDnV*df@i%HSKZu0000~!p>^5?w&a_`#do0%p5o~?~ng; zd7t;0HG5W%3b0MsOh&)}86X2>fNTtq0Wv@a$i@H}AOmE8Yz&YAGC&5%#sC>017v`c zZ<<#5TAbsNmM-sC?G|A;_OluuAi;9|(!%JqWlVgb1aH(;f6MPlkJgNWD4GEvEimT+ z^Sd-WeX9*WPz!6ZfEPdYaOh}=R$DH(hSeH6Ffc4|caMcTt}>8w6~sV7o86}2z5PBu zI^ZK)<9$=BKvF|nM#KEMdd2(gS+!`8f<$fb?zzUo<2PGluJ1S;VC#22GS<|>i^P$n z3kQY85HLS1J&(Na9N^KtNY!MdyeB?zqI))74AiOw{#w>p4IU|s?x)LZZ}0W-$_^JD zt=gm{sHQ4o#)B6tZT*)XUj5udr-UaGg4ZwrtHLAK*A>7wc6)epkB38CV0Tw0twH=iX|nt)wN3hUUR#Rd0je29JS|VfN?`X0=jFFiB-4R#jXk| zElv<|e~+LMMAIm2;TT{k0N!w!5k2)}Y%}Gz=|3&7?Daej{837?1azM4BR+Pcg`u2C zl?wHGClFF0B?fBkpOjhn!M7az_*aOvy)N>eQY4i(6c_JYXky6%6NB=%L8i_Ci%nK? z&0~WC_pNu(*Do-)Q^S$t65=+uqHRUCQXUChbiQ6Z3z^mc2@EOe&jEq^B|L&SqXlrJ z@@C1*OWUijpem@!Ffej8$NcU~apx79o>sedFOVX7o zE)qmaDijZ|xKPJK*IO7IslO}N-G$eE=1B#HXm3G9SA}AuEzA6VStG9b*ew;^y1I7n zwI;5+#K2%q6n87r5+JG2HmkR!=)KOYhCM$A*z~nuENf!dC0Fj6sYfnfuXvb>Tz01O z3j)?5A-=ZD!*3@-<+6o%NO5xIQVVV{jTQKRnhoTlj+|&%wZ&6kT2~K(c=g2wmP>a& zRi}8EdVsMC+hu||bTo)g-r_^0IQBiV*uuhY14DTv9uFG=V7wclQ@4#@`Oz-LC@3&2 z+b?%yD`#&QU=^dH`#G7FM;)a$tpJyb@276D<&2C-G@&#Uz^FEqO`E>{5HIw)6~#EI zaq*=FmMyYmhbOss*l-FYwROtu`-vPL+I~1Fc5mVa1N9Uyzd*;ZlT19+>(Ra^)x@z& zOi+n5>Gkq<7svlqY6}9@(V_T9^&u7EUIOtjQGkY4>O#jZ7VRu*oHB|BGf&B8?CLFU zF*aJNGluRtI-Xr>NA;oBEN3F*Vk3^gFUP`)0n5`lOsHK?F>j{Ky8C|(qS=_678n@L ztIr|8-E%ZtDfi3=`)VKFtf?iJ43Ggb mKsE-*02v?yWMhDnV*df@i%HSKZu0000+IcccyZ;ESiima!C>MR;FedwJqdQuH$r@>vAc#P~=EyF4bgmn<#|2 z-;?HGTT8U%HkoMjBALeNob#OLIqyI3bN=}LzQ51&{QmttpF6IYlS=a1@&Eup33bZh z?61E5ugFUOn$`hUEC4`e5ansmer$%padE8In$IivG>(?a`Je5Yj-M(A~@Y*nZFrgdNuqPnZ zv+zEk?enBO?KU_d|LerqUa7pP=33ttlDS~|lcNtbJQ;Fizd(Run%vV8R_HUIwo6A= z9(>oPTFW&Fbm)NW!a0-tz)d{?NAEvRkJUj zuqRuGz~Yz{*ddsUu^m79N?`W20|zBPr21-7>*M_s-p-}3zI?KF!x6kLk|5eKe~f)u z;jPBHT_Me9ldd>fhh+5c;5l}YnHYG*6lO57QWC!99;IfM5!^=t;o&Z4%4%0{$R+A7 zEXp+!{C`X$IEr51>(CvM!9z}uY;v^{Q!=8LwYmduE0VsAg6!(vo=eQ7(0n1ggXsB9 zRu@b~tRju~ANJR30MisYk=-0@sT;zDiC)0sw06;TAjC7o%vTHXq2B2}ygVu-%*LQ~ z63GB?<>@wl@j`aa?gH$)I`qe(dLZ3_C?1|0aFCb5``-Gf2P91SaLlZZ&St^s>n|tmvk3rG@o;KTks_RKjZz<S+M56DN__J>s2>rk zKzFBmRfTSYQR7V$cr99aSEl}?A2l%56Kg7HN212XS!J|iRN35aS0ydkij`(N}wID=TD|G;(OTolIpt$ z3qs!0i)w>JLlVTc)s>lAP2QWD00=pn79rL}D~G7( zq4h}=@@y5wbnY>{d>HV8lK1rLtT{ERcrNS21i`tOnP!upwEE&^_YzXMaQiYt>dJygsm>YBd@J1ff;yAM8j#>q@!Z1p6oz7&P8LXb5SJcJovAkZN)l zUhrEcM~hsm#NYDt)On%K#$i~Pg%i;_(M)XTd5nLlquzYc`T%x6GGw;3wCa0JjhuE| zA`12(6QP}eHa;v#`fB2a_tSqKNB`MsYl6+`w`~HO;YV^8q;7vf$vO41M$atw7fCde~<)Y$Mi5RCxdEO9V4ZPZs0y;yg^+A;fkR`*m+c144W2gQA6(bSHVU zm!*%_XN{&zQW`v3xUP{yt&{gI&5L60pMHE-M;jY1c)2+<@~NF7Bu?^!sB`3o`^yW9 z8JEDUeKq6T=@MW~0+0N3Yc3y0z?Q?UR}p#e_0tX4!U&VrOF=g8G5LAXh1d$@I(J7q&H#|H8WNp` zxgN$b!Y|v6uVb3bFg-GFO8P|0#_*`?o&2NDOLg8L_{W06**^+7_O4DJh(D_-V4G)uT*7U09bOh2KU1FEKm<6QYsbF_IgTyaQ?HMK5 z{K5QO^$pDvu+9<$;Iwn$9S^vM{*k8aN3$$!8JfSdKkL)(vIk0C-scrHE`|yvsxjt_ zwSHe09S?UyMhQHY`_N3=-k84PZ*e)U?xcv4TvX7QbJMWQc_BWc4%{bRf0{PiABeMi znN{&Kbi{Z}Q4+@s=Dy*U{~UQw^-=js7*LZ-{)|3=@PguUs?x6A6l_jA4A^?a4Fe0l z4=08mhSI(`jAX4YoufjGS^T2%IYlhQ$oek|Bj4aJNOX$qrBJA{fXv0<` vs|1CP8&Bm9>;B1n|JC9D=|w;)m9`Cp=+>-Dy)m%-rFQ@diE*etelh8v4Li&7 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-512@2x.png b/src-tauri/icons/ios/AppIcon-512@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9b37f2315c64acb46dfa141bfd7061ccca389bdc GIT binary patch literal 14000 zcmeHNcT`i^w@yI73gReIq|BhhC?F~#DAGm|QAbdu3qcT&PDJUDjLr-wO$QMLBsfTs z-a!z zUp1wEy|k^_W5I!{zM)AtUIv|Xm3+CwY=3)O^ zf7gRw6dwNg=SMDhlob4d`lm-cGV1GuOCe+bN#Ykv{#(MoPTen7{}#=^Mff-Pg6)=n zN%$A0e&ypgX#SNF5!1fK(a6|;OZc}q`kOWX7UAFE=>I_Ee{|OW2Z(UtrBUDqCSuf9 z_~RcRHIY$p9YOu$#P;I{TCe1cMh0 z$RPI_g@w3fA6*Zt3lC`2F|w&ptI>cZSTSXu->f4?1Q}D(_(E}rx1!rlQ_8jV49kbhTwgFeuX4*r0MiY<%(}W@2 zw=>2odLoai%k{)oHF~zEEjV(2cGalvmLN2H*j}>-+PgFowo!ikJc{RR40bZfG!)mg zCcnX=C)8%i{@|6EHTf~+IU+hE6zH+Ynn4c3OuJn-b@#;Mo{t>>O#=#VO&^yDgF0+J z^w{ls90Bbd5k_>;{Iv$Uuq*;)w{7xx7zT}bgsnQD*&~0ZmbGkb-R@73)C86sU_~B2 zNF2?+*-wu9{qst%TTkusa44FK#BrQ*OTzD|VC|MS)_-sNJaK_>D$d(Iym`z8%J8@mA0G}G+XusZfbUQgxig_)tFB-mpNgZ z8rBS%80dDQb$71;pk2ZB`6;N(k)KNwtb2fEFdr${Rx+c$W>afvKk;S@ZlVUqQC};} ze}&-XBGjRA*-MxMy}x{=2Qt1l4fStbiy(}UVI|X^h2K^qSQicftFem)Ysxt2Dh&+E z%F-$nzraVFcAUHEo*H#GCO1s>HMl>8F2!Jbl1z^;+*%c-8&g~&Qaeb2>YjfVMtW_x z>q!K3r{!~SGZ+jy6>~>7KZc*1W8dKbSHCXStI)ou{iG6rC^+^unanZShePeu-Km9@Ajux zy}p}|@YlvcH;pSyqEVuZ(!jHN*;QcRZ-qgLi^?oa$nuZvltJ12H;!u{x-s&bZ(N|E zP+KWmL@2bo_s}Z|i`#jr%AYY*qce^r-IEjDzs$+x!xqc>@+3(krB(F|jWzT`HU$}1 zE^tPiwD8oE4?NQB#o`3llt|1MB1+h<`XSG(lDLD-yP?p@mAPcc%YoTzQE;@F@%np9 zoA6x1=T`xJ)a4G_gU-%?KBSQNrBR?sfDLcp5;z7x`8H8Oi;k-Y$FUSin1?{hU20H< z9E@$T9qT^7s-rSghu+Ff$6jM{vnBoc@RIcTmoK;3{HU~x7lxj`T#y))UHAG-6^(lz z?ag-f zkqbo&0n!1`1(f{k4nrQ&87f{Wc3t6PoBG{c6`&G72ccOZz<``#I?0CzenXqerGB0n z6z^1ZC)(H=J1mF52IdWomf*fsY-D?9KFVp zbtbUwALT@+mys+8g${2KGmoHR?AeaxxzSk*NYncLsM%%r03~O{GYR)7P$zdN)b?WF zl^L@!IPEq{6F4Fix@2+PSU%7vWYwp2OH(dwCG>@uwE-*sSCx2sY}TS?7R_Ao_EyUB ztyo0>s4cdj*inUrzc$#i7b;F=+FjC17s~c^!9H z6Q0L3gbaA?u+)|s4UWAqtvr+6cW|lek4lcx+vVT>5H6{I2OIf0?zi?dsCa4$Q7{MA zD&~i;;JdM>EUOb zj9lM2F?Pw}%=@zBu%nXv)W#9Z%5m&uah6N{b+KchR=IS1HJ5LW^%jP1;l; zeadAmJQF*MFC{`2N_=Scy3d#Df*mjW5Z3(b*!u}eoJc?DUGVu8fX7Rx{1R4wDLbSa zkFmTaLT$nzi8e7o`z>|WgNf_~^ap9s(8YqIcU{|NXynClIaj~etFS}bmhlR?>A<&i zBpm@4$v;08=Wn}5!aKSD00I_@hIU9k!q}Z704%@}FiG4xqZlrEuR75HR8G#Tm(>j_ z!_9K>agI!G*b-2whUE~j5L9~CT-MbQMqfPBSaCCZz#`wrR`(FEXd zz{G?l<(k5_9id_C=?!^a8LlRUss5DU0%c*6`d+ zr4i3~olmVDGqy$e1(=;s0V9~GlUUP{2vW1~k9?#XhwBmjv>Hj|Poy`ILbxy4NiwY( zWcjMLDdXdOj@bTBFml)!mTK0g9_D^m+D2~@IWa_ZY zBUs#Q6E=KVdpK4(g4)AZnO8FX6o3Ry89-LGP}hk(VOsE-H`0`TD9x&~Zl$d1CG$MS zjn$I9Fh27CJ3dnV znRX2nob$V zf`o$mR!$H~=V`uiKEHg4jlwL(GFjCT_-J=RuOI-f7^LR#7wvHU0eTx`Jxiw$aLY06ZZ2j@i#>-+nXGmnF!Y*zZti*dYO z)V1V-ozYU?vYzdey5%0eV*_p){pv_31?Z#?7x;X;s%wABs&6w}1)HMCeDBL9L^n4yT0Vrf(^K`dY z6&Y9Bq6Mpir|FHqnyS)V&?#;Stz1Ab@j+9@OxSe=6A zyzs&Fys#O=@gXKq2vy>Rn7w_)j|scsC|WTi3kqlWP)p)QmP>jZu~)iXKM3hisci2b zVCnX0Nlt~9Yqa(wPy^v;tQrgRzHz2f>*YWdcRg)7jH$d1Hg2O+*)QE;P}I3cAA+U# z*TLP$CRtLV?UTYEN@tc)$5wtu1MBeC;}-lB91q<4-(Sgp1hysy7}uKLmF@V4c1Zer z`T6^~ad5}8c$)PFI=CX6Yo$9I0p*KHWYwn9ZU)WX%??OYR4>21jDnTM-x6K+mkuv4 zXr7XWMlhJL$Fs5gdmpOFUmyQIsq?B@V;B-q9!1}a(r{N(t#*8h>?{5;?t9bIsCwrT zPxCksjt@!*+!B78#w7!`H@dT@%@Crh(VeBUN{Pc2mb6@#ZVEx8dkk>{UWweR*G2(5 zk_$dzWvstq(`oNE6L>FAlNaQwb^0b`Ho=k2;Vq-o`NkbP5HdbdLRP3hq1Ewmd}4{H zyHtCIwNaC-K4d~H_CgSdS9+gXJAqv??7|!#lsWHKm3_)kd_eYyIZ^)n(N1TYKeFCPZ!-@!etd zV#RYTm|MM>4IF$i$(CUopz(^<5O5Bsl_X-n#fL)J|5F}?|EF3%@=yyNhGd2LM**+) z0efk3jMrSPdWVUqm`Sp+LstN5j{p}EMz>^guVn}(%-2a_bh#n3?a_gT6m)d=mDvRq zYx1AB5uo?&%It^Ay8D*88R-lQe5T%JqvPv8=>!G5R8%KM*0NEfY%*~lYEOjRqIDHx zu}!Bz^qT7UqO51P^ni5XLZM!2nMJQ;ZlLyKRy5_OV@F%?^_d;%@}x z*(g0)q55KRGIRN;*EOZ#{R^h}Ax|GYKYtHB4vcY6+fx=_;Vgu1pUO5>=pz;+JcgEM z_Ep?vVIxSLE~*-CY*|)Jg6iRr2?;Yr$ztNl9pBAj6NY#VR!&_udejf$3r>J1grQ8a z#h?iDe7*&cH?)CW*<5nPv{D!Bhwqc_v8`)MQ<@>_zB(3iKO&2PD|@A4F0@Znv_f*~ zRe+BFiXw-jM@^N;%oI#ib!u(M?6s9d15vk$lnosxp9a zWeJYDlWZAQi*cr(@Yl9y$)-%?T+b+b7|q7;j!QE{O^vacGd(Mp%I`s}3C03d^g;DD zNnU!Qys~phB>#+qCM@#fj?5-P>z7Xs6+6UVut`h}&aqG7g*n^6fmoFAvcDOXMDVgu8kU;_ zL1=#~i5iUtRieHdA>&V^d@EhW@G;CCo#ba;SW71+j%t?8m2s{6m+pblmA9a30q*V7 z9p3L+1BgkO@F|m#S-;sloBNXthH*`2a`q`dy9uYRQ&0eBB74BjCx#_6Yqpc?d|+KV zO7>WP#dYVx`+D450Lhxob_&;OydeEMcUr_~=NYA16D|1pKQxwy+D&COA}i~g#*DYZ zFni|E&a|cAn%{Y~lY=$xYm9v=>+a>t`RhrMbA%gp>Xas&tEWk!KJ_)wEcJbDzru@r zp@?$}!WDO4Ej%aD=lG|&5dd917w|#^Vl1CI_jrXAu=CY@NQbJd5~BSWQkUx}<@s1} z;!JLxFK6&;zbm9XBEwA^zxC&V*ZsivM@-7(mlpQwl<^{YR^3**!YX5snR)~#rh?Z> z<$TFJt@O6Z-#Wz(5je)>l-tOnKR8;%s%3VRV0bW{N7^P&v${fu|kBAjuM+&*pKAg_Se5TgsIF3n7%W; z)|d5mrSb4U+OiYBHBW3NStw=KBwz^;^R3$SzLg8nR}XsS(jc?TH$0T$pNzHOWk1-| zhJz!`UOvPEr;J+5YgJ%33ZF0GGV_>de3n*QYUy{M8vX4F7bi=S2&WO2t`Pw}f9+g$ z)vdcU$X89RT#zVXcyp`lPd87_sb=gduO}hUXcq=2DFdBnWpm$*OhMMsWb=@q_*sz0 zMSUgm=jnNDescPaZzg2&d`ZT(vrL`^OwxS~75Fqk$U9)5akA{Jjz2?MoCCGXs2LymqcxxJc#!+(xUV%P_iw8oDXL3Q?dh1Xz1%cuL(U z;#J4h3m%x>*yNi66`EwM^c?4vPZJH zkrA{dw|J-_^N-<}(RNUkS1NDv<^Jh5Wq4P>WoTqO;z>IVNz*VgdF(Aisq6R3{6|Z9 z#%QC~rQIJNGg8nUQ$x0hCrvU5p{X@^zfef2_b<7>$X0}_m%AQ{6;P?~VZKjgyJ=?JS);?EZs zUVZ$L*cwXcdxpwz?*8S&z@wFV1ekd5TBw2c7#ukc2vRh7ZtHXmOs6nSvnDGnRILdD zUMlNhz551P6uN!J~|hc@Y9{-RsqX3r~O10xAr432P9 zl9gDEWh6k8=Bl_&379}h%{ox6fpMDqrepNIp4up@=h(vCpE4KBpQsHCaL{q?@suGx zYNdDj3GMNs-)1Dpr%z5qf||}2 z=5td9;hv!F2h@JL8omNbG&s(ilV<@)%*{Uwbl31w4%Y@dP~a@5df=UD#-tcQp*o8? z-?9mrR2AY8gY6I7SdkuhV<;OnrqumytA~C?`C(WM&-7S?N!f7A|TgBnmU5RuVypF}#}=TjCBqoK`~`iS){-XjegwA?a;YT(R<_-4 zeG)p8=GV6(0TNAabgAJ{_TG`88sIq*s^)ba>~8>_+zS?rXtf!%aa}h_f?KB$xOKt< zhwdH->M*vcISvTOx!2MKYX_nogt>+Y+bAUGP}9W-Ky9l?5AdE?phqZhviEe=Bi*o) zfxZ}^xW;6Y2*H~`a6sn#5a@GO>BsYn4i!;_u4t8&_t%|YhO_wtzwXj(8LEueSbA2f zBE6snC(Cu34XbVOkDG!qJs>8%4&}V>eZ>*e@d{vzSHrsMP@p4#|} z=BSFzxrV#~k)0A{!{ZiAeh<1Vc}7WDR2PtNeVioaG9#>;1iguGrRj|kF~UTsMKNub zA5ox!zEhO8tlGo(eoCN>xdZB$MpV<>wTmf)#9#z^H_=mf?fQCL|W~XUaR;? zDO_kk)%d?+j}(jS+}yb9 zq=0&Xp`X8#0zfIE9k{qwa}CUxmh$~H-*}@&hCGrYg$MHP;Uz6GVIs3|R5Q&{=T!@K ziDgqjcK|Sw@Nrndq2}m`ynCq94p9gcU{F`3z@+VcqpSJ*cWtp#1g<9$5G-QQV!e6V zLF^xT+zW$bqW)crqJ{jenqbOLC60kRt%zD}Nzh;$42oEssC&7kB`?RS`E{BTx~S4( zkaRQ*ALB4bxpoUwB4K`?rrtu&bLl1j9sny49?icCU-7!byWRE<^k|!F4<8@F8v}S+Q_>hA3%hRG3sU+$lXBcpRMoHyGq8>XLa+-Rc0d9WGi4hKd zw)eo-chqBmm){covlP`!!wC1-uIr^;Rm<{wla5kjdB4M;M`MW_bCA446r8S=&UfXiEY~MYVC;dQrtFgtzO(i7W-!~|n{vqX<_&Pia96~xrl)n!qlTAIg zrhl3$Kbza~Fz`H*6g-Q|s%d9Wpn50X;dDL4EyHiNUl&5u__fdyeXV?BPE`=vw*XGP z*T35Gp{0Pd?dB7QDhQ$aC?i{fz|AUS^$-10a36xV7CV+)G&hT%n*^J<+^OVOo7iCN z@#!$MS>OVcshfTAB(d`Cg@r3@{Jt69?^yGq0~}Ep_7#J?E5y`s!skR%Af;oL;5uNdtWL{WXyZ|aE9$2IA4mYYLbrRerQQ5d;MNcwJjW9@lRhn@^ zk=|l>OiZvsY7V_z?qE~j>21NuSe_&ELw3x?Pw%ucUZ0vM&?cX#Z^~jPv-T1H%W9{> zvQ>i(J6*~a=(TEVfzS{(0;ggDqV9&TUfA#T^obzEvlnZ?G>7H~UHu+Cmocwfp}73O zrrZ*6EfRC*x%@C;Z%hMNX;`eFx^6Z7^xb#%UJkRjqXS6#2d0FpOj1@^C?kf<)2UQa zI!BnB3=TM(TR9x~2Rq_Nz}Y$|;%!vW8KF zU_^D{i%Yp9;^ZXq7t(DFnE!iHM2_K8XN>>D`rHOu*3}S@+q2|U#S2)mvg|sRZY3Pg$Iuh? zx&3g}Ln1NR^R(?z*&BPbk!|Gshk@1;XTE2L{P+3hTXz0%Ut%=UqI#pML%nT`ofQM6 zt0zcpjD@}=`p2@Bt2}IBuf_7cuY`jsNs3V6hnprx+fD0D5t`;HR51rV!5_RiXQ+Lt z^5>7|Omd|8PX2z1*-whOZ4w5Kf(7{kT36v};qRveuF>4Lreo(=Nu8bsWRB8leI^V0 zD!|!~NfL6%44TaX)&@Lqk^X4|J7tQD^mcrk57}-C+Zwoslj9xl4;Geq+yePW`Wxh* z!Zh6Gz-cycjQYXxo#kjgD&1q?zZJgmA?*fwpFRu(_+|s{a#Aq)NMJAY&fZYtjQ|$4 zb@`+((A#&e(qN~aTUyPm0>Io&7OUk+?()Jag3~}6w5On*w%F(HLki!s?NqZ4jcvjbM{m>9BPV=TedyF?;U0_1aB zr}IjY%8(U-mt8IyUA_KIHcu0;0S0Z;MFf0>>J)>)F*uHMlEq#4= zcfq~Z+U`cz9Qbyo@QX9i0|~-A_;T|@%FYHA1&3^OEflYM`sA6uvWENV4S~B4(&l!) zr0$M$x6tT67ZmFeKN6s!KFQdqKWN3TDciuE>bD+&>)^F}?daoX6Q@Rs%Te0rQ^HWi z&31_Dc)5UX$(k19S6mNr-Jc3YH+u6TGp>#|kjUQUE~xh zyI|0FLnX7SRt^g!q#-wSsH5Xdk($cG0#*s=?Z>?GL_>_Ja6OC;aG9#VOBe3@|n{?WR0h{ zZBY>&eoZV}dCmJ~rGmx7V%Qt+OkvEUM3$OFY9gb7;n=@S?{s&F@^cA0M4c4~eES-F zdtl()aUd8Lj%*^o;!zVG3g;jS;jsVn5$2b#6}}Fo0}qCEMoGaR|M-YUM#1eQ5;SC! z_rE<#A!ENz_}59qBNCCZ|CaEtQ}>J2zeV$J5dMX!U-|ei3ID>>uY3GTb^p~U{;R^j z!O`q|`VT}<@Xu$z{Rbjn`r;#u4^8m+IcccyZ;ESiima!C>MR;FedwJqdQuH$r@>vAc#P~=EyF4bgmn<#|2 z-;?HGTT8U%HkoMjBALeNob#OLIqyI3bN=}LzQ51&{QmttpF6IYlS=a1@&Eup33bZh z?61E5ugFUOn$`hUEC4`e5ansmer$%padE8In$IivG>(?a`Je5Yj-M(A~@Y*nZFrgdNuqPnZ zv+zEk?enBO?KU_d|LerqUa7pP=33ttlDS~|lcNtbJQ;Fizd(Run%vV8R_HUIwo6A= z9(>oPTFW&Fbm)NW!a0-tz)d{?NAEvRkJUj zuqRuGz~Yz{*ddsUu^m79N?`W20|zBPr21-7>*M_s-p-}3zI?KF!x6kLk|5eKe~f)u z;jPBHT_Me9ldd>fhh+5c;5l}YnHYG*6lO57QWC!99;IfM5!^=t;o&Z4%4%0{$R+A7 zEXp+!{C`X$IEr51>(CvM!9z}uY;v^{Q!=8LwYmduE0VsAg6!(vo=eQ7(0n1ggXsB9 zRu@b~tRju~ANJR30MisYk=-0@sT;zDiC)0sw06;TAjC7o%vTHXq2B2}ygVu-%*LQ~ z63GB?<>@wl@j`aa?gH$)I`qe(dLZ3_C?1|0aFCb5``-Gf2P91SaLlZZ&St^s>n|tmvk3rG@o;KTks_RKjZz<S+M56DN__J>s2>rk zKzFBmRfTSYQR7V$cr99aSEl}?A2l%56Kg7HN212XS!J|iRN35aS0ydkij`(N}wID=TD|G;(OTolIpt$ z3qs!0i)w>JLlVTc)s>lAP2QWD00=pn79rL}D~G7( zq4h}=@@y5wbnY>{d>HV8lK1rLtT{ERcrNS21i`tOnP!upwEE&^_YzXMaQiYt>dJygsm>YBd@J1ff;yAM8j#>q@!Z1p6oz7&P8LXb5SJcJovAkZN)l zUhrEcM~hsm#NYDt)On%K#$i~Pg%i;_(M)XTd5nLlquzYc`T%x6GGw;3wCa0JjhuE| zA`12(6QP}eHa;v#`fB2a_tSqKNB`MsYl6+`w`~HO;YV^8q;7vf$vO41M$atw7fCde~<)Y$Mi5RCxdEO9V4ZPZs0y;yg^+A;fkR`*m+c144W2gQA6(bSHVU zm!*%_XN{&zQW`v3xUP{yt&{gI&5L60pMHE-M;jY1c)2+<@~NF7Bu?^!sB`3o`^yW9 z8JEDUeKq6T=@MW~0+0N3Yc3y0z?Q?UR}p#e_0tX4!U&VrOF=g8G5LAXh1d$@I(J7q&H#|H8WNp` zxgN$b!Y|v6uVb3bFg-GFO8P|0#_*`?o&2NDOLg8L_{W06**^+7_O4DJh(D_-V4G)uT*7U09bOh2KU1FEKm<6QYsbF_IgTyaQ?HMK5 z{K5QO^$pDvu+9<$;Iwn$9S^vM{*k8aN3$$!8JfSdKkL)(vIk0C-scrHE`|yvsxjt_ zwSHe09S?UyMhQHY`_N3=-k84PZ*e)U?xcv4TvX7QbJMWQc_BWc4%{bRf0{PiABeMi znN{&Kbi{Z}Q4+@s=Dy*U{~UQw^-=js7*LZ-{)|3=@PguUs?x6A6l_jA4A^?a4Fe0l z4=08mhSI(`jAX4YoufjGS^T2%IYlhQ$oek|Bj4aJNOX$qrBJA{fXv0<` vs|1CP8&Bm9>;B1n|JC9D=|w;)m9`Cp=+>-Dy)m%-rFQ@diE*etelh8v4Li&7 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-60x60@3x.png b/src-tauri/icons/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..2306b3ae00453758e905e0e88ae4449d61a85cd3 GIT binary patch literal 2899 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 literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-76x76@1x.png b/src-tauri/icons/ios/AppIcon-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..e1b5cd15f661351e57f43ea8c3abec464c8a9372 GIT binary patch literal 1409 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 KJM(H&EaBhQp2~Ls literal 0 HcmV?d00001 diff --git a/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..40d0df9ef4ce193c88ba996a728762c29c506227 GIT binary patch literal 2764 zcmb7GX*e6`7S`!v=+wT{Qnj>{QjMjW+7+=YX)HmtYU@~XB`P98uU4(4K{X^qM+sU~ zqcql0wAQG`7E5%o)DpP~K?J=z&-|Zze|+bC&w0-BocH|s(yqCHP6*2j3kV3Du(z{z zKS0vY_v^6(8!h9sDj*=7Yj16NJ$8~=gwFJZ$o<)lW(};CPUSZ|x09BS$dm6DbOY3g zb}5TlqINC68i%Svy0oBYl_!$zKHmIO@Q}PC7HXYZ4+%f+p{0O=70P7vlzNB>dj;~L zF$>h`72aA=b5V^kGMLnCj9l1H=zZ|1=uR*)0Zm0xw~APSar}pvLw3q?2}kY`1bT#e zgzgdkB7ehA|NjgBQ?*ccU6}a?{Vff?(A%r@*Vf@-m|C{UIs;4QeiV)PI6Ym>f$#?) zeQP3)@PY;5Dt8$NRes8z#iyn&16Cu6mh*DvMp8p7K?^#Dd79x$?ajP^%`s|dDOvy` zMe+it){CQqIz?OLO8ITKu%(M$oB}Ypj%C?B%5o;^llyaKO`&-@Lvf$5&hNix6W)}A zPC+*C2B&vO=8v&i^0Ul^MAX6;MS$p* z73N>ac7^44%e;g^Lw%rUC(T?*V8=rJfGS)q{!Z^}-Q<8}wEUh~X-a}xjyYvfYwbZNuZCllOGnu zFZTQ~{6u=MW?-%E{WQwLB{Uu9x!n_*vZ+kI1zC}38Ov}pc?Y7OEJc#tw~k)u(3nOF?3<~ zLC-XbF020!yf9}1k(x#jl0Y<8;;yjDG1oTBDe!}#<>_+q%qQ_}m>|@RhW1rKo6bAF zPt-zw>Bih?6sKk4hT6UgLUs;H)5O+!o}J=|#S(F{BmhgM2NZhgeM?=PD9a$W?1t3B zM9Njv;p)}{B!5mImVQBAQKDc>rBd^&1@%D&Z%fvMS4h7(E}1_AJeX=Pv7Q>0PT>Mw z+ald_nuZz4xE^3Zzy*aA+~FS^a|-9zJANR8#U+7wopRZ9-e=lb-dL5@zmAJ7Z{*zT9lo7FI_>FKykf+SyI#X!BhuY$dhk{uN|oF<35+wT8# z;2zF96SZ5E zeh3JHp3y?5Tm`^hs+9Ye+BBwD)Q)~@nKf54`V=7knEcFRyw8oyv~U_M@RTM`H~IKW z-j!8CNHuhBuiuA7&1Ia{V=s!aHQ)}nWsg(@%3@5;e^9(5h@ZcmHV280;}84QnB3ON ze2J5$`0X2Q%*M~+73uogUBn(bu4K3%YN}?Y@%zrB8sAo`Y3ST3G7||rKZ1;*Dt7*w zy$?M|L!AR-3<0`rrr{Ob_mun%bMKt_Eol&ZY1GzrZ*s-?H-0M(p%*CQtDW^2VO1fu z-rOi1$Xs{@b7P!<)xGVAKFQdG!OpzT%rJK~8^aD0g5 z(^#3ow!e^}*)ERg8nHCw!0h)mIfXe9V{F zSpK&B@0An!gBxv(Xq7Saxl*ZM-`&c^wEV(dbUikk*rR#7>S=vy)S-6b-i!3e+n?NpB@I9FzL^ld{0h50Pt zBE%EVIN!fge|hdLFH2L*K4dqI0QOS2G9#t&V>NPonjqfZDph7wx()8OiXzlBoZy?GTno2LCNf0R zDicN&l`RM47A^I(tA&usAYgxegXR(Z1~@!RSXlH$(=&Qfv87>;)>{e45xd0 z)oq@gRf6Wc+hi7J5`=n{mX@2Z2@fgR$f|cqn}htJ^3kph_ZiMinMBo)Bsj}dJ%2i2 zt*0gCz7GPesZ~pRDEhP*d!j3NE_}3-W_~d_E5RC2OnksRn`_!MU)%i|`mUm*(~ISO z+JkrPM(tAZE((!^7-wu2GMM#&fd)Y*{Txb8-<((TY3 z`d`?IxM3DdC5NSxp%mXd#z-b@IGClso;QAJ%FzQh`i>^<(yjI5YKSK%4}Pfv_BJloHC8v1{tL7J BXe9su literal 0 HcmV?d00001 diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs new file mode 100644 index 0000000..d41b85e --- /dev/null +++ b/src-tauri/src/commands.rs @@ -0,0 +1,859 @@ +use crate::db; +use crate::models::{Agent, Config, DiscoveredModel, Model, Provider, ProviderType}; +use crate::pi_io; +use crate::services::{self, UsageKind, UsageResult}; +use indexmap::IndexMap; +use serde::Serialize; +use std::collections::HashMap; +use std::sync::{Mutex, OnceLock}; +use std::time::{Duration, Instant}; +use tauri_plugin_opener::OpenerExt; + +fn fmt_anyhow(err: anyhow::Error) -> String { + err.chain() + .map(|e| e.to_string()) + .collect::>() + .join(": ") +} + +#[tauri::command] +pub fn debug_log(message: String) { + eprintln!("[frontend] {}", message); +} + +/// SQLite settings key for a provider's billing/usage query kinds +/// (JSON array of kind strings, e.g. `["balance:deepseek"]`). +fn usage_kinds_key(provider_name: &str) -> String { + format!("usage_kinds:{provider_name}") +} + +/// Merge per-provider `usage_kinds` into a loaded config: explicit SQLite +/// settings first, host-based detection as fallback so existing installs get +/// billing support automatically. The field never enters config.toml. +fn merge_usage_kinds(config: &mut Config) { + for p in config.providers.values_mut() { + let from_settings = db::get_setting_pub(&usage_kinds_key(&p.name)) + .ok() + .flatten() + .and_then(|s| serde_json::from_str::>(&s).ok()) + .filter(|v| !v.is_empty()); + p.usage_kinds = from_settings.or_else(|| { + let kinds = services::detect_provider(&resolve_base_url(p)); + if kinds.is_empty() { + None + } else { + Some(kinds.iter().map(|k| k.as_str().to_string()).collect()) + } + }); + } +} + +fn load_pi_native_config() -> Result { + let file = pi_io::load_pi_models().map_err(fmt_anyhow)?; + let mut config = pi_io::pi_file_to_config(&file); + if config.default_model.is_none() { + if let Ok(settings) = pi_io::load_pi_settings() { + if let (Some(provider), Some(model_id)) = + (settings.default_provider, settings.default_model) + { + if let Some(alias) = config + .models + .values() + .find(|m| m.provider == provider && m.model == model_id) + { + config.default_model = Some(alias.alias.clone()); + } + } + } + } + Ok(config) +} + +#[tauri::command] +pub fn load_agent_config_command(agent: Agent) -> Result { + // Load Kimi Switch's own SQLite database (metadata + migration fallback). + let db_config = db::load_config(&agent).ok(); + + let mut config = match agent { + Agent::KimiCode => { + // config.toml is the authoritative source for provider/model data + // because the user can add or edit providers at any time via the + // CLI's /provider command. SQLite only enriches with Kimi + // Switch-private metadata (note, official_url, remembered default + // model) and fills gaps when config.toml is incomplete. + let mut config = crate::kimi_code_io::load_kimi_code_config_as_config() + .map_err(fmt_anyhow)?; + + if let Some(db) = &db_config { + // Enrich config.toml providers with SQLite metadata. + for (name, p) in config.providers.iter_mut() { + if let Some(db_p) = db.providers.get(name) { + p.note = db_p.note.clone(); + p.official_url = db_p.official_url.clone(); + // Restore Kimi Switch metadata that does not live in + // the agent's config.toml. + p.icon = db_p.icon.clone(); + p.icon_color = db_p.icon_color.clone(); + // Restore the remembered per-provider default model + // (Kimi-Switch-private, stored in raw_other). + if let Some(dm) = db_p.raw_other.get("default_model") { + match &mut p.raw_other { + serde_json::Value::Object(obj) => { + obj.insert("default_model".to_string(), dm.clone()); + } + _ => { + let mut obj = serde_json::Map::new(); + obj.insert("default_model".to_string(), dm.clone()); + p.raw_other = serde_json::Value::Object(obj); + } + } + } + } + } + // Migration safety: include providers/models that exist in + // SQLite but not in config.toml (e.g. after upgrading from the + // old single-provider-write behaviour). + for (name, p) in &db.providers { + config.providers.entry(name.clone()).or_insert_with(|| p.clone()); + } + for (alias, m) in &db.models { + config.models.entry(alias.clone()).or_insert_with(|| m.clone()); + } + } + + config + } + Agent::Pi => { + // Pi: SQLite first, fall back to native config on first use. + match db_config { + Some(config) if !config.providers.is_empty() => config, + _ => load_pi_native_config()?, + } + } + }; + + merge_usage_kinds(&mut config); + Ok(config) +} + +#[tauri::command] +pub fn save_agent_config_command(agent: Agent, config: Config) -> Result<(), String> { + // Save the full Kimi Switch configuration to local SQLite. + db::save_config(&agent, &config).map_err(fmt_anyhow)?; + // For Kimi Code, config.toml is the authoritative provider store, so + // persist changes there immediately — not only on activation. This + // ensures edits (Ctrl+S) survive a restart even without switching. + if matches!(agent, Agent::KimiCode) { + crate::kimi_code_io::save_config_as_kimi_code(&config).map_err(fmt_anyhow)?; + } + // Persist usage_kinds to the SQLite settings table (never config.toml; + // the field is skip_serializing and the TOML export is hand-built). + // None / empty array → delete the key. + for provider in config.providers.values() { + let key = usage_kinds_key(&provider.name); + match &provider.usage_kinds { + Some(kinds) if !kinds.is_empty() => { + let json = serde_json::to_string(kinds).map_err(|e| e.to_string())?; + db::set_setting_pub(&key, &json).map_err(fmt_anyhow)?; + } + _ => db::delete_setting_pub(&key).map_err(fmt_anyhow)?, + } + } + Ok(()) +} + +#[tauri::command] +pub fn activate_agent_config_command(agent: Agent) -> Result<(), String> { + match agent { + Agent::KimiCode => { + // No-op: save_agent_config_command already writes config.toml for + // Kimi Code. Avoiding a second write here prevents a redundant disk + // write + backup on every switch. + Ok(()) + } + Agent::Pi => { + // Load the full config from SQLite and write only the active + // provider to Pi's native config files. + let config = db::load_config(&agent).map_err(fmt_anyhow)?; + let active_config = build_active_config(&config); + let file = pi_io::config_to_pi_file(&active_config); + pi_io::save_pi_models(&file).map_err(fmt_anyhow)?; + + // Keep Pi's own default provider / model in sync so the switch is + // actually picked up on the next `pi` run. + let mut settings = pi_io::load_pi_settings().map_err(fmt_anyhow)?; + if let Some((provider_name, model_id)) = active_provider_and_model(&active_config) { + settings.default_provider = Some(provider_name); + settings.default_model = Some(model_id); + } + pi_io::save_pi_settings(&settings).map_err(fmt_anyhow) + } + } +} + +fn active_provider_and_model(config: &Config) -> Option<(String, String)> { + let alias = config.default_model.as_ref()?; + let model = config.models.get(alias)?; + Some((model.provider.clone(), model.model.clone())) +} + +fn build_active_config(config: &Config) -> Config { + // Used only by Pi: writes only the provider explicitly marked as active + // to Pi's native config so Pi follows Kimi Switch's selection instead of + // falling back to another provider. Kimi Code does not use this — it + // writes all providers and selects via default_model. + let providers: IndexMap = config + .providers + .iter() + .filter(|(_, p)| p.active) + .map(|(k, p)| (k.clone(), p.clone())) + .collect(); + + let active_provider_names: std::collections::HashSet<&str> = providers + .values() + .map(|p| p.name.as_str()) + .collect(); + + let models: IndexMap = config + .models + .iter() + .filter(|(_, m)| active_provider_names.contains(m.provider.as_str())) + .map(|(k, m)| (k.clone(), m.clone())) + .collect(); + + Config { + default_model: config.default_model.clone(), + providers, + models, + raw_other: config.raw_other.clone(), + } +} + +#[tauri::command] +pub fn open_agent_config_dir(app: tauri::AppHandle, agent: Agent) -> Result<(), String> { + let path = agent.config_dir(); + std::fs::create_dir_all(&path).map_err(|e| e.to_string())?; + let path_str = path.to_string_lossy().to_string(); + app.opener() + .open_path(&path_str, None::<&str>) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn get_app_version() -> String { + env!("CARGO_PKG_VERSION").to_string() +} + +/// Fetch available models from a provider's API. +#[tauri::command] +pub async fn list_provider_models(provider: Provider) -> Result, String> { + let api_key = resolve_api_key(&provider) + .ok_or_else(|| format!("Provider '{}' has no API key configured", provider.name))?; + + let base = resolve_base_url(&provider); + + match provider.provider_type { + ProviderType::Kimi | ProviderType::Openai | ProviderType::OpenaiResponses => { + fetch_openai_models(&base, &api_key).await + } + ProviderType::Anthropic => fetch_anthropic_models(&base, &api_key).await, + ProviderType::GoogleGenai => fetch_google_genai_models(&base, &api_key).await, + ProviderType::Vertexai => Err("Vertex AI model discovery requires GCP project/location configuration and is not yet supported".to_string()), + } +} + +/// Test reachability of a provider's base URL (cc-switch semantics): +/// any HTTP response counts as reachable; only network-layer errors fail. +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ConnectivityResult { + pub ok: bool, + pub latency_ms: u64, + pub status_code: Option, + pub error: Option, +} + +#[tauri::command] +pub async fn test_connectivity(provider: Provider) -> Result { + let base = resolve_base_url(&provider); + if base.trim().is_empty() { + return Ok(ConnectivityResult { + ok: false, + latency_ms: 0, + status_code: None, + error: Some("no base URL configured".to_string()), + }); + } + let client = reqwest::Client::builder() + .timeout(std::time::Duration::from_secs(8)) + .build() + .map_err(|e| format!("failed to build HTTP client: {e}"))?; + let start = std::time::Instant::now(); + match client.get(base.as_str()).send().await { + Ok(resp) => Ok(ConnectivityResult { + ok: true, + latency_ms: start.elapsed().as_millis() as u64, + status_code: Some(resp.status().as_u16()), + error: None, + }), + Err(e) => Ok(ConnectivityResult { + ok: false, + latency_ms: start.elapsed().as_millis() as u64, + status_code: None, + error: Some(if e.is_connect() { + "connection refused / DNS failed".to_string() + } else if e.is_timeout() { + "request timed out".to_string() + } else { + e.to_string() + }), + }), + } +} + +fn resolve_api_key(provider: &Provider) -> Option { + if provider.managed { + return Some("managed".to_string()); + } + if let Some(key) = &provider.api_key { + if !key.is_empty() { + return Some(key.clone()); + } + } + let env_key = expected_api_key_key(&provider.provider_type); + provider.env.get(env_key).filter(|s| !s.is_empty()).cloned() +} + +fn resolve_base_url(provider: &Provider) -> String { + provider + .base_url + .clone() + .filter(|s| !s.is_empty()) + .unwrap_or_else(|| { + provider + .provider_type + .default_base_url() + .unwrap_or("") + .to_string() + }) +} + +fn expected_api_key_key(provider_type: &ProviderType) -> &'static str { + match provider_type { + ProviderType::Kimi => "KIMI_API_KEY", + ProviderType::Anthropic => "ANTHROPIC_API_KEY", + ProviderType::Openai | ProviderType::OpenaiResponses => "OPENAI_API_KEY", + ProviderType::GoogleGenai => "GOOGLE_API_KEY", + ProviderType::Vertexai => "VERTEXAI_API_KEY", + } +} + +// ── OpenAI-compatible /models endpoint (with pagination) ───────────── + +async fn fetch_openai_models(base: &str, api_key: &str) -> Result, String> { + #[derive(serde::Deserialize)] + struct OaiModel { + id: String, + } + #[derive(serde::Deserialize)] + struct OaiList { + data: Vec, + #[serde(default)] + has_more: Option, + #[serde(default)] + last_id: Option, + #[serde(default)] + next_page_token: Option, + } + + let client = reqwest::Client::new(); + let root = base.trim_end_matches('/').to_string(); + let mut url = format!("{}/models", root); + let mut all: Vec = Vec::new(); + const MAX_PAGES: usize = 50; + + for _ in 0..MAX_PAGES { + let resp = client + .get(&url) + .bearer_auth(api_key) + .send() + .await + .map_err(|e| format!("HTTP request to {} failed: {e}", url))?; + if !resp.status().is_success() { + return Err(format!("{} returned HTTP {}", url, resp.status())); + } + let body: OaiList = resp + .json() + .await + .map_err(|e| format!("failed to parse response from {}: {e}", url))?; + all.extend(body.data); + + // OpenAI cursor pagination: has_more + last_id → ?after= + if body.has_more.unwrap_or(false) { + if let Some(last_id) = body.last_id.clone() { + url = format!("{}/models?after={}", root, last_id); + continue; + } + } + // Token-based pagination: next_page_token → ?page_token= + if let Some(token) = body.next_page_token.clone() { + if !token.is_empty() { + url = format!("{}/models?page_token={}", root, token); + continue; + } + } + break; + } + + let mut seen = std::collections::HashSet::new(); + Ok(all + .into_iter() + .filter(|m| seen.insert(m.id.clone())) + .map(|m| DiscoveredModel { + id: m.id, + display_name: None, + max_context_size: None, + }) + .collect()) +} + +// ── Anthropic /v1/models endpoint (with pagination) ────────────────── + +async fn fetch_anthropic_models(base: &str, api_key: &str) -> Result, String> { + #[derive(serde::Deserialize)] + struct AntModel { + id: String, + display_name: Option, + } + #[derive(serde::Deserialize)] + struct AntList { + data: Vec, + #[serde(default)] + has_more: Option, + #[serde(default)] + last_id: Option, + } + + let client = reqwest::Client::new(); + let root = base.trim_end_matches('/').to_string(); + let mut url = format!("{}/v1/models?limit=1000", root); + let mut all: Vec = Vec::new(); + const MAX_PAGES: usize = 20; + + for _ in 0..MAX_PAGES { + let resp = client + .get(&url) + .header("x-api-key", api_key) + .header("anthropic-version", "2023-06-01") + .send() + .await + .map_err(|e| format!("HTTP request to {} failed: {e}", url))?; + if !resp.status().is_success() { + return Err(format!("{} returned HTTP {}", url, resp.status())); + } + let body: AntList = resp + .json() + .await + .map_err(|e| format!("failed to parse response from {}: {e}", url))?; + let more = body.has_more.unwrap_or(false); + let cursor = body.last_id.clone(); + all.extend(body.data); + if !(more && cursor.is_some()) { + break; + } + url = format!("{}/v1/models?limit=1000&after_id={}", root, cursor.unwrap()); + } + + let mut seen = std::collections::HashSet::new(); + Ok(all + .into_iter() + .filter(|m| seen.insert(m.id.clone())) + .map(|m| DiscoveredModel { + id: m.id, + display_name: m.display_name, + max_context_size: None, + }) + .collect()) +} + +// ── Google GenAI /v1beta/models endpoint (with pagination) ─────────── + +async fn fetch_google_genai_models( + base: &str, + api_key: &str, +) -> Result, String> { + #[derive(serde::Deserialize)] + struct GglModel { + name: String, + #[serde(rename = "displayName")] + display_name: Option, + #[serde(rename = "outputTokenLimit")] + output_token_limit: Option, + } + #[derive(serde::Deserialize)] + struct GglList { + models: Vec, + #[serde(rename = "nextPageToken", default)] + next_page_token: Option, + } + + let client = reqwest::Client::new(); + let root = base.trim_end_matches('/').to_string(); + let mut url = format!("{}/v1beta/models?key={}&pageSize=1000", root, api_key); + let mut all: Vec = Vec::new(); + const MAX_PAGES: usize = 50; + + for _ in 0..MAX_PAGES { + let resp = client + .get(&url) + .send() + .await + .map_err(|e| format!("HTTP request to {} failed: {e}", url))?; + if !resp.status().is_success() { + return Err(format!("{} returned HTTP {}", url, resp.status())); + } + let body: GglList = resp + .json() + .await + .map_err(|e| format!("failed to parse response from {}: {e}", url))?; + let cursor = body.next_page_token.clone(); + all.extend(body.models); + match cursor { + Some(t) if !t.is_empty() => { + url = format!( + "{}/v1beta/models?key={}&pageSize=1000&pageToken={}", + root, api_key, t + ); + } + _ => break, + } + } + + let mut seen = std::collections::HashSet::new(); + Ok(all + .into_iter() + .filter(|m| seen.insert(m.name.clone())) + .map(|m| { + let id = m + .name + .strip_prefix("models/") + .unwrap_or(&m.name) + .to_string(); + DiscoveredModel { + id, + display_name: m.display_name, + max_context_size: m.output_token_limit, + } + }) + .collect()) +} + +// --------------------------------------------------------------------------- +// App settings (generic key/value via SQLite) +// --------------------------------------------------------------------------- + +#[tauri::command] +pub fn get_app_setting(key: String) -> Option { + db::get_setting_pub(&key).ok().flatten() +} + +#[tauri::command] +pub fn set_app_setting(key: String, value: String) -> Result<(), String> { + db::set_setting_pub(&key, &value).map_err(|e| e.to_string()) +} + +// --------------------------------------------------------------------------- +// Provider billing / usage query (cc-switch semantics) +// --------------------------------------------------------------------------- + +/// 5-minute in-memory cache keyed by (agent, provider_name). +/// Only successful results are cached; failures are always re-queryable. +const USAGE_CACHE_TTL: Duration = Duration::from_secs(300); + +type UsageCache = Mutex>; + +fn usage_cache() -> &'static UsageCache { + static CACHE: OnceLock = OnceLock::new(); + CACHE.get_or_init(|| Mutex::new(HashMap::new())) +} + +/// Query a provider's balance / plan quota. The frontend passes only the +/// provider name — base_url, api_key and usage kinds are all resolved here, +/// so the API key never crosses IPC and the host routing cannot be spoofed. +/// +/// Error channel semantics (cc-switch): +/// - `Err(_)` = transient failure (network/timeout/body read) → frontend +/// retries and keeps the last good value. +/// - `Ok(success:false)` = deterministic failure (no key / auth / non-2xx / +/// bad JSON / unsupported provider) → show the error text directly. +#[tauri::command] +pub async fn query_provider_usage( + agent: Agent, + provider_name: String, + force_refresh: Option, +) -> Result { + let cache_key = (agent.as_str().to_string(), provider_name.clone()); + + if !force_refresh.unwrap_or(false) { + let cached = usage_cache() + .lock() + .unwrap() + .get(&cache_key) + .and_then(|(ts, result)| (ts.elapsed() < USAGE_CACHE_TTL).then(|| result.clone())); + if let Some(result) = cached { + return Ok(result); + } + } + + // Load via the same path as load_agent_config_command so usage_kinds + // (SQLite merge + host-detect fallback) is already resolved. + let config = load_agent_config_command(agent)?; + let Some(provider) = config.providers.get(&provider_name) else { + return Ok(UsageResult::failure(format!( + "provider '{provider_name}' not found" + ))); + }; + + // The api_key only ever goes into request headers — never into logs, + // error messages, or the cache key. + let api_key = provider + .api_key + .clone() + .filter(|s| !s.trim().is_empty()) + .or_else(|| { + provider + .env + .get(expected_api_key_key(&provider.provider_type)) + .cloned() + .filter(|s| !s.is_empty()) + }); + let Some(api_key) = api_key else { + return Ok(UsageResult::failure(if provider.managed { + "provider uses managed OAuth; usage query requires an API key".to_string() + } else { + "no API key configured".to_string() + })); + }; + + let base_url = resolve_base_url(provider); + let kinds: Vec = provider + .usage_kinds + .as_ref() + .filter(|v| !v.is_empty()) + .map(|v| { + v.iter() + .filter_map(|s| s.parse::().ok()) + .collect::>() + }) + .filter(|v| !v.is_empty()) + .unwrap_or_else(|| services::detect_provider(&base_url)); + if kinds.is_empty() { + return Ok(UsageResult::failure( + "unsupported provider: no usage query available for this base URL".to_string(), + )); + } + + // A failing kind must not take down the others: collect successes, + // deterministic failures and transient failures separately. + let mut data: Vec = Vec::new(); + let mut errors: Vec = Vec::new(); + let mut transient: Vec = Vec::new(); + let mut any_success = false; + for kind in kinds { + match services::query_kind(kind, &base_url, &api_key).await { + Ok(result) if result.success => { + any_success = true; + if let Some(d) = result.data { + data.extend(d); + } + } + Ok(result) => { + if let Some(e) = result.error { + errors.push(format!("{}: {e}", kind.as_str())); + } + } + Err(e) => transient.push(format!("{}: {e}", kind.as_str())), + } + } + + if any_success { + let result = UsageResult { + success: true, + data: if data.is_empty() { None } else { Some(data) }, + error: if errors.is_empty() { + None + } else { + Some(errors.join("; ")) + }, + }; + usage_cache() + .lock() + .unwrap() + .insert(cache_key, (Instant::now(), result.clone())); + Ok(result) + } else if !transient.is_empty() { + // All kinds failed transiently → propagate Err so the frontend + // rejects and retries (keep-last-good). + Err(transient.join("; ")) + } else { + Ok(UsageResult::failure(errors.join("; "))) + } +} + +// --------------------------------------------------------------------------- +// Version check (lightweight: GET Gitea releases API, compare tag_name) +// --------------------------------------------------------------------------- + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct UpdateInfo { + pub current: String, + pub latest: String, + pub update_available: bool, + pub release_url: String, + pub download_url: Option, +} + +fn parse_version(s: &str) -> Vec { + s.trim_start_matches('v') + .split('.') + .filter_map(|p| p.parse::().ok()) + .collect() +} + +fn version_lt(current: &str, latest: &str) -> bool { + let c = parse_version(current); + let l = parse_version(latest); + for i in 0..c.len().max(l.len()) { + let cv = *c.get(i).unwrap_or(&0); + let lv = *l.get(i).unwrap_or(&0); + if cv < lv { + return true; + } + if cv > lv { + return false; + } + } + false +} + +#[tauri::command] +pub async fn check_for_update() -> Result { + let current = env!("CARGO_PKG_VERSION").to_string(); + let url = "https://git.codingplan.site/api/v1/repos/admin/KimiCodeSwitch/releases?limit=1"; + + let resp = reqwest::get(url) + .await + .map_err(|e| format!("request failed: {e}"))?; + + let releases: serde_json::Value = resp + .json() + .await + .map_err(|e| format!("parse failed: {e}"))?; + + let first = releases + .as_array() + .and_then(|a| a.first()) + .ok_or("no releases found")?; + + let latest = first + .get("tag_name") + .and_then(|v| v.as_str()) + .unwrap_or("0.0.0") + .to_string(); + + let release_url = first + .get("html_url") + .and_then(|v| v.as_str()) + .unwrap_or("") + .to_string(); + + let download_url = first + .get("assets") + .and_then(|a| a.as_array()) + .and_then(|a| a.first()) + .and_then(|a| a.get("browser_download_url")) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + let update_available = version_lt(¤t, &latest); + + Ok(UpdateInfo { + current, + latest, + update_available, + release_url, + download_url, + }) +} + +// --------------------------------------------------------------------------- +// Silent download with progress events +// --------------------------------------------------------------------------- + +#[tauri::command] +pub async fn download_update( + app: tauri::AppHandle, + url: String, +) -> Result { + use futures_util::StreamExt; + use std::io::Write; + use tauri::Emitter; + + let resp = reqwest::get(&url) + .await + .map_err(|e| format!("download request failed: {e}"))?; + + let total = resp.content_length().unwrap_or(0); + + let temp_dir = std::env::temp_dir(); + let file_path = temp_dir.join("KimiSwitch_update.msi"); + + let mut file = std::fs::File::create(&file_path) + .map_err(|e| format!("create temp file failed: {e}"))?; + + let mut downloaded: u64 = 0; + let mut stream = resp.bytes_stream(); + + while let Some(chunk_result) = stream.next().await { + let chunk = chunk_result.map_err(|e| format!("read chunk failed: {e}"))?; + file.write_all(&chunk) + .map_err(|e| format!("write failed: {e}"))?; + downloaded += chunk.len() as u64; + + let progress = if total > 0 { + ((downloaded as f64 / total as f64) * 100.0).min(100.0) as u32 + } else { + 0 + }; + + let _ = app.emit( + "download-progress", + serde_json::json!({ + "downloaded": downloaded, + "total": total, + "progress": progress, + }), + ); + } + + drop(file); + + let path_str = file_path.to_string_lossy().to_string(); + + let _ = app.emit( + "download-complete", + serde_json::json!({ "path": &path_str }), + ); + + Ok(path_str) +} + +/// Open the downloaded MSI installer using the system default handler. +#[tauri::command] +pub fn open_installer(app: tauri::AppHandle, path: String) -> Result<(), String> { + use tauri_plugin_opener::OpenerExt; + app.opener() + .open_path(&path, None::<&str>) + .map_err(|e| e.to_string()) +} \ No newline at end of file diff --git a/src-tauri/src/config_io.rs b/src-tauri/src/config_io.rs new file mode 100644 index 0000000..4699c86 --- /dev/null +++ b/src-tauri/src/config_io.rs @@ -0,0 +1,84 @@ +//! Configuration file I/O utilities for KimiSwitch. +//! Reads and writes the global config file and profile files. + +use std::path::{Path, PathBuf}; +use anyhow::{Context, Result}; +use chrono::{Duration, Local}; + +/// Creates a backup of `path` inside a `backups/` subdirectory next to the +/// original file, then removes backup files older than `retention_days`. +pub fn backup_file(path: &Path, retention_days: i64) -> Result { + if !path.exists() { + return Ok(PathBuf::new()); + } + + let parent = path.parent().context("path has no parent directory")?; + let backups_dir = parent.join("backups"); + std::fs::create_dir_all(&backups_dir) + .with_context(|| format!("failed to create backups directory {}", backups_dir.display()))?; + + let file_name = path.file_name().context("path has no file name")?; + let timestamp = Local::now().format("%Y%m%d_%H%M%S_%.3f").to_string(); + let backup_name = format!("{}.bak.{}", file_name.to_string_lossy(), timestamp); + let mut backup_path = backups_dir.join(&backup_name); + + if backup_path.exists() { + for n in 1..1000 { + let candidate = backups_dir.join(format!( + "{}.bak.{}.{:03}", + file_name.to_string_lossy(), + timestamp, + n + )); + if !candidate.exists() { + backup_path = candidate; + break; + } + } + } + + std::fs::copy(path, &backup_path).with_context(|| { + format!( + "failed to back up {} to {}", + path.display(), + backup_path.display() + ) + })?; + + cleanup_old_backups(&backups_dir, retention_days)?; + + Ok(backup_path) +} + +/// Removes backup files in `dir` older than `retention_days`, based on file +/// modification time. Only files whose names contain `.bak.` are deleted. +fn cleanup_old_backups(dir: &Path, retention_days: i64) -> Result<()> { + let cutoff = Local::now() - Duration::days(retention_days); + let entries = std::fs::read_dir(dir) + .with_context(|| format!("failed to read backups directory {}", dir.display()))?; + + for entry in entries { + let entry = entry.context("failed to read directory entry")?; + let path = entry.path(); + if !path.is_file() { + continue; + } + let name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + if !name.contains(".bak.") { + continue; + } + let metadata = entry + .metadata() + .with_context(|| format!("failed to read metadata for {}", path.display()))?; + let modified = metadata + .modified() + .with_context(|| format!("failed to read modified time for {}", path.display()))?; + let modified: chrono::DateTime = modified.into(); + if modified < cutoff { + std::fs::remove_file(&path) + .with_context(|| format!("failed to remove old backup {}", path.display()))?; + } + } + + Ok(()) +} diff --git a/src-tauri/src/dashboard.rs b/src-tauri/src/dashboard.rs new file mode 100644 index 0000000..930f67a --- /dev/null +++ b/src-tauri/src/dashboard.rs @@ -0,0 +1,1419 @@ +use chrono::{DateTime, Datelike, Local, TimeZone}; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fs; +use std::io::{BufRead, BufReader}; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; +use walkdir::WalkDir; + +// --------------------------------------------------------------------------- +// Types – match the Node API JSON shape exactly +// --------------------------------------------------------------------------- + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PathsResult { + pub current: String, + pub valid: bool, + pub candidates: Vec, + pub env: EnvInfo, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PathCandidate { + pub path: String, + pub valid: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EnvInfo { + #[serde(rename = "KIMI_CODE_HOME")] + pub kimi_code_home: Option, + #[serde(rename = "KIMI_MODEL_NAME")] + pub kimi_model_name: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PriceRow { + pub id: String, + pub cache_hit: f64, + pub input: f64, + pub output: f64, + pub context: u64, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PricesResult { + pub prices: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SummaryResult { + pub home: String, + pub valid: bool, + pub scanned_at: u64, + pub meta: ScanMeta, + pub model_map: ModelMapInfo, + pub range: String, + pub stats: RangeStats, + pub heatmap: HeatmapData, + pub all_models: Vec, + pub all_model_count: usize, + pub range_totals: HashMap, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ScanMeta { + pub files_scanned: usize, + pub lines_seen: usize, + pub record_count: usize, + pub home: String, + pub sessions_root: String, + pub errors: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ModelMapInfo { + pub default_model: Option, + pub env_model: Option, + pub alias_count: usize, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct EnvModelInfo { + pub name: String, + pub provider: Option, + pub model: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct RangeStats { + pub range: String, + pub totals: TotalsRow, + pub daily: Vec, + pub models: Vec, + pub recent: Vec, + pub recent_total: usize, + pub recent_limit: usize, +} + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TotalsRow { + pub requests: usize, + pub input_other: u64, + pub output: u64, + pub input_cache_read: u64, + pub input_cache_creation: u64, + pub cost_usd: f64, + pub total_tokens: u64, + pub cache_hit_rate: f64, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct DailyRow { + pub date: String, + pub requests: usize, + pub input_other: u64, + pub output: u64, + pub input_cache_read: u64, + pub input_cache_creation: u64, + pub cost_usd: f64, + pub total_tokens: u64, + pub cache_hit_rate: f64, + /// Per-model token breakdown for stacked-bar rendering + pub by_model: HashMap, + /// Per-provider token breakdown for stacked-bar rendering + pub by_provider: HashMap, + /// Per-provider, per-model nested token breakdown (provider → model → tokens), + /// used by the provider-tab drill-down detail. + pub by_provider_model: HashMap>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ModelRow { + pub model: String, + pub model_display: String, + pub model_resolved: String, + pub price_id: String, + pub cost_estimated: bool, + pub requests: usize, + pub input_other: u64, + pub output: u64, + pub input_cache_read: u64, + pub input_cache_creation: u64, + pub cost_usd: f64, + pub total_tokens: u64, + pub cache_hit_rate: f64, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct RecentRow { + pub time: u64, + pub model: String, + pub model_display: String, + pub model_resolved: String, + pub input_other: u64, + pub output: u64, + pub input_cache_read: u64, + pub input_cache_creation: u64, + pub total_tokens: u64, + pub cost_usd: f64, + pub cost_estimated: bool, + pub price_id: String, + pub from_env: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct AllModelRow { + pub model: String, + pub model_display: String, + pub requests: usize, + pub total_tokens: u64, + pub cost_usd: f64, + pub cost_estimated: bool, + pub cache_hit_rate: f64, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct HeatmapData { + pub weeks: usize, + pub start: String, + pub end: String, + pub max_tokens: u64, + pub cells: Vec, + pub month_labels: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct HeatmapCell { + pub date: String, + pub dow: usize, + pub week_index: usize, + pub requests: usize, + pub total_tokens: u64, + pub cost_usd: f64, + pub cache_hit_rate: f64, + pub level: usize, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct MonthLabel { + pub week_index: usize, + pub label: String, +} + +// Sessions types +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SessionsResult { + pub home: String, + pub archive_root: String, + pub workspaces: Vec, + pub sessions: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceRow { + pub id: String, + pub name: String, + pub root: Option, + pub created_at: Option, + pub last_opened_at: Option, + pub active_count: usize, + pub archived_count: usize, + pub empty: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SessionRow { + pub id: String, + pub workspace_id: String, + pub status: String, + pub title: Option, + pub work_dir: Option, + pub created_at: Option, + pub updated_at: Option, + pub bytes: u64, + pub files: usize, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ActionResponse { + pub ok: bool, + pub workspace_id: String, + pub session_id: String, + pub status: Option, + pub path: Option, + pub deleted: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PreviewResult { + pub workspace_id: String, + pub session_id: String, + pub status: String, + pub title: Option, + pub work_dir: Option, + pub created_at: Option, + pub updated_at: Option, + pub message_count: usize, + pub truncated: bool, + pub messages: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PreviewMessage { + pub role: String, + pub time: Option, + pub text: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceDeleteBody { + pub workspace_id: String, + pub confirm: Option, + pub force: Option, +} + +// --------------------------------------------------------------------------- +// App state +// --------------------------------------------------------------------------- +pub struct AppState { + pub scan_cache: Mutex, +} + +#[derive(Clone)] +pub struct ScanCache { + pub home: String, + pub scanned_at: u64, + pub records: Vec, + pub meta: ScanMeta, + pub model_map: ModelMapInfo, +} + +#[derive(Debug, Clone)] +pub struct UsageRecord { + pub time: u64, + pub model: String, + pub input_other: u64, + pub output: u64, + pub input_cache_read: u64, + pub input_cache_creation: u64, + pub cost_usd: f64, + pub cost_estimated: bool, + pub price_id: String, + pub model_resolved: String, + pub model_display: String, + pub provider: Option, + pub from_env: bool, +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +fn resolve_kimi_home(override_path: Option) -> PathBuf { + if let Some(p) = override_path { + if !p.trim().is_empty() { + return PathBuf::from(p); + } + } + if let Ok(env_home) = std::env::var("KIMI_CODE_HOME") { + if !env_home.trim().is_empty() { + return PathBuf::from(env_home); + } + } + let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")); + home.join(".kimi-code") +} + +fn is_kimi_home(dir: &Path) -> bool { + if !dir.exists() || !dir.is_dir() { + return false; + } + dir.join("config.toml").exists() || dir.join("sessions").exists() +} + +/// Build a legacy alias→provider map by merging the current config.toml with every +/// `config.toml.bak.*` snapshot (home root + backups/). Historical usage records may +/// reference model aliases that no longer exist in the current config (old bare or +/// `-N`-suffixed aliases); their provider is recovered from these snapshots. +fn build_alias_provider_map(home: &Path) -> HashMap { + let mut map: HashMap = HashMap::new(); + let mut candidates: Vec = Vec::new(); + let current = home.join("config.toml"); + if current.is_file() { + candidates.push(current); + } + for dir in [home.to_path_buf(), home.join("backups")] { + if let Ok(rd) = std::fs::read_dir(&dir) { + for e in rd.flatten() { + let name = e.file_name().to_string_lossy().to_string(); + if name.starts_with("config.toml.bak.") { + candidates.push(e.path()); + } + } + } + } + for path in candidates { + let content = match std::fs::read_to_string(&path) { + Ok(c) => c, + Err(_) => continue, + }; + let parsed: toml::Value = match toml::from_str(&content) { + Ok(v) => v, + Err(_) => continue, + }; + if let Some(models) = parsed.get("models").and_then(|m| m.as_table()) { + for (alias, m) in models { + if let Some(p) = m.get("provider").and_then(|p| p.as_str()) { + // Current config is parsed first and wins on conflict. + map.entry(alias.clone()).or_insert_with(|| p.to_string()); + } + } + } + } + map +} + +/// Resolve the provider for a usage record's raw model key: prefer the `provider/` +/// prefix, then fall back to the legacy alias→provider map (config + backups). +fn resolve_provider(model_raw: &str, map: &HashMap) -> Option { + let p = model_raw + .rsplit_once('/') + .map(|(prov, _)| prov.to_string()) + .or_else(|| map.get(model_raw).cloned()); + p.map(|x| normalize_provider(&x)) +} + +/// Normalize historical provider-name variants to the canonical name. +fn normalize_provider(p: &str) -> String { + match p { + "CodingPlanSite" => "CodingPlan.site".to_string(), + other => other.to_string(), + } +} + +fn sessions_root(home: &Path) -> PathBuf { + home.join("sessions") +} + +fn workspace_re() -> Regex { + Regex::new(r"^wd_[A-Za-z0-9._-]+$").unwrap() +} + +fn session_re() -> Regex { + Regex::new(r"^session_[0-9a-fA-F-]{8,}$").unwrap() +} + +fn safe_read_dir(path: &Path) -> Vec { + let mut entries = Vec::new(); + if let Ok(rd) = fs::read_dir(path) { + for e in rd.flatten() { + entries.push(e); + } + } + entries +} + +fn file_size_approx(path: &Path) -> (u64, usize) { + let mut total_bytes = 0u64; + let mut total_files = 0usize; + for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) { + if entry.file_type().is_file() { + if let Ok(meta) = entry.metadata() { + total_bytes += meta.len(); + total_files += 1; + } + } + } + (total_bytes, total_files) +} + +fn day_key(ts_ms: u64) -> String { + let secs = if ts_ms > 1e12 as u64 { ts_ms / 1000 } else { ts_ms }; + // Bucket by LOCAL calendar date (not UTC) so records around midnight stay on the correct day. + let local = Local + .timestamp_opt(secs as i64, 0) + .single() + .unwrap_or_else(|| DateTime::from_timestamp(secs as i64, 0).unwrap_or_default().with_timezone(&Local)); + format!("{:04}-{:02}-{:02}", local.year(), local.month(), local.day()) +} + +// --------------------------------------------------------------------------- +// Pricing +// --------------------------------------------------------------------------- + +fn list_prices() -> Vec { + vec![ + PriceRow { id: "kimi-k3".into(), cache_hit: 0.30, input: 3.00, output: 15.00, context: 1_048_576 }, + PriceRow { id: "kimi-k2.7-code".into(), cache_hit: 0.19, input: 0.95, output: 4.00, context: 262_144 }, + PriceRow { id: "kimi-k2.6".into(), cache_hit: 0.16, input: 0.95, output: 4.00, context: 262_144 }, + PriceRow { id: "kimi-k2.5".into(), cache_hit: 0.10, input: 0.60, output: 3.00, context: 262_144 }, + PriceRow { id: "kimi-k2-turbo".into(), cache_hit: 0.15, input: 1.15, output: 8.00, context: 262_144 }, + PriceRow { id: "kimi-k2".into(), cache_hit: 0.15, input: 0.60, output: 2.50, context: 262_144 }, + ] +} + +fn match_price(model_name: &str) -> (String, f64, f64, f64, bool) { + let bare = match model_name.rsplit_once('/') { + Some((_, b)) => b, + None => model_name, + }; + let bare_l = bare.to_ascii_lowercase(); + for p in &list_prices() { + let id_l = p.id.to_ascii_lowercase(); + if bare_l == id_l || bare_l.contains(&id_l) || id_l.contains(&bare_l) { + return (p.id.clone(), p.cache_hit, p.input, p.output, false); + } + } + ("kimi-k2.6".into(), 0.16, 0.95, 4.00, true) +} + +fn cost_for_usage(input_other: u64, output: u64, cache_read: u64, cache_create: u64, model: &str) -> (f64, bool) { + let (_price_id, cache_hit, input_price, output_price, est) = match_price(model); + let cost = (input_other as f64 / 1e6) * input_price + + (cache_read as f64 / 1e6) * cache_hit + + (cache_create as f64 / 1e6) * input_price + + (output as f64 / 1e6) * output_price; + (cost, est) +} + +// --------------------------------------------------------------------------- +// Scanner +// --------------------------------------------------------------------------- + +fn scan_usage(home: &Path) -> (Vec, ScanMeta) { + let root = sessions_root(home); + let alias2prov = build_alias_provider_map(home); + let mut records = Vec::new(); + let mut files_scanned = 0; + let mut lines_seen = 0; + let errors = Vec::new(); + + if !root.exists() { + return (records, ScanMeta { + files_scanned: 0, lines_seen: 0, record_count: 0, + home: home.to_string_lossy().to_string(), + sessions_root: root.to_string_lossy().to_string(), + errors: vec!["sessions directory not found".into()], + }); + } + + for entry in WalkDir::new(&root).into_iter().filter_map(|e| e.ok()) { + if entry.file_name() != "wire.jsonl" { continue; } + if !entry.file_type().is_file() { continue; } + // Skip blob/task directories + let p = entry.path(); + if p.to_string_lossy().contains("blobs") || p.to_string_lossy().contains("tasks") { + continue; + } + files_scanned += 1; + let content = match fs::read_to_string(entry.path()) { + Ok(c) => c, + Err(_) => continue, + }; + for line in content.lines() { + lines_seen += 1; + if !line.contains("\"usage.record\"") { continue; } + let obj: serde_json::Value = match serde_json::from_str(line) { + Ok(v) => v, + Err(_) => continue, + }; + if obj.get("type").and_then(|v| v.as_str()) != Some("usage.record") { continue; } + let scope = obj.get("usageScope").and_then(|v| v.as_str()).unwrap_or("turn"); + if scope != "turn" { continue; } + + let model_raw = obj.get("model").and_then(|v| v.as_str()).unwrap_or("unknown").to_string(); + let time = obj.get("time").and_then(|v| v.as_u64()).unwrap_or(0); + let usage = &obj["usage"]; + let input_other = usage.get("inputOther").and_then(|v| v.as_u64()).unwrap_or(0); + let output = usage.get("output").and_then(|v| v.as_u64()).unwrap_or(0); + let cache_read = usage.get("inputCacheRead").and_then(|v| v.as_u64()).unwrap_or(0); + let cache_create = usage.get("inputCacheCreation").and_then(|v| v.as_u64()).unwrap_or(0); + + // Resolve model display + let bare = model_raw.rsplit_once('/').map(|x| x.1).unwrap_or(&model_raw); + let (cost, est) = cost_for_usage(input_other, output, cache_read, cache_create, &model_raw); + let (pid, _ch, _ip, _op, _) = match_price(&model_raw); + + records.push(UsageRecord { + time, + model: model_raw.clone(), + model_resolved: bare.to_string(), + model_display: model_raw.clone(), + provider: resolve_provider(&model_raw, &alias2prov), + from_env: model_raw == "__kimi_env_model__", + input_other, + output, + input_cache_read: cache_read, + input_cache_creation: cache_create, + cost_usd: cost, + cost_estimated: est, + price_id: pid, + }); + } + } + + records.sort_by(|a, b| b.time.cmp(&a.time)); + let count = records.len(); + (records, ScanMeta { + files_scanned, lines_seen, record_count: count, + home: home.to_string_lossy().to_string(), + sessions_root: root.to_string_lossy().to_string(), + errors: errors.into_iter().take(20).collect(), + }) +} + +// --------------------------------------------------------------------------- +// Aggregate +// --------------------------------------------------------------------------- + +fn aggregate(records: &[UsageRecord], range: &str, now_ms: u64) -> RangeStats { + let filtered: Vec<&UsageRecord> = filter_by_range(records, range, now_ms); + let range_label = range.to_string(); + + if filtered.is_empty() { + return RangeStats { + range: range_label, + totals: TotalsRow::default(), + daily: vec![], + models: vec![], + recent: vec![], + recent_total: 0, + recent_limit: 500, + }; + } + + let mut totals = TotalsRow::default(); + let mut by_day: HashMap, HashMap>)> = HashMap::new(); + let mut by_model: HashMap = HashMap::new(); + + for r in &filtered { + totals.add(r); + let dk = day_key(r.time); + let (day_totals, day_models, day_prov_models) = by_day.entry(dk.clone()).or_default(); + day_totals.add(r); + *day_models.entry(r.model.clone()).or_insert(0) += + r.input_other + r.output + r.input_cache_read + r.input_cache_creation; + let provider_key = r.provider.clone().unwrap_or_else(|| "unknown".to_string()); + *day_prov_models + .entry(provider_key) + .or_default() + .entry(r.model.clone()) + .or_insert(0) += r.input_other + r.output + r.input_cache_read + r.input_cache_creation; + + let mk = r.model.clone(); + let entry = by_model.entry(mk.clone()).or_insert_with(|| { + let m = ModelRow { + model: mk.clone(), + model_display: r.model_display.clone(), + model_resolved: r.model_resolved.clone(), + price_id: r.price_id.clone(), + cost_estimated: r.cost_estimated, + requests: 0, input_other: 0, output: 0, + input_cache_read: 0, input_cache_creation: 0, + cost_usd: 0.0, total_tokens: 0, cache_hit_rate: 0.0, + }; + (m, TotalsRow::default()) + }); + entry.1.add(r); + entry.0.cost_estimated = entry.0.cost_estimated || r.cost_estimated; + } + + let total_input = totals.input_other + totals.input_cache_read + totals.input_cache_creation; + totals.cache_hit_rate = if total_input > 0 { totals.input_cache_read as f64 / total_input as f64 } else { 0.0 }; + + let mut daily: Vec = by_day.into_iter() + .map(|(date, (t, by_model, by_provider_model))| { + let ti = t.input_other + t.input_cache_read + t.input_cache_creation; + let ch = if ti > 0 { t.input_cache_read as f64 / ti as f64 } else { 0.0 }; + DailyRow { + date, requests: t.requests, + input_other: t.input_other, output: t.output, + input_cache_read: t.input_cache_read, input_cache_creation: t.input_cache_creation, + cost_usd: t.cost_usd, total_tokens: t.total_tokens, cache_hit_rate: ch, + by_model, + by_provider: by_provider_model + .iter() + .map(|(p, m)| (p.clone(), m.values().sum::())) + .collect(), + by_provider_model, + } + }) + .collect(); + daily.sort_by(|a, b| a.date.cmp(&b.date)); + + let mut models: Vec = by_model.into_iter().map(|(_, (mut m, t))| { + let ti = t.input_other + t.input_cache_read + t.input_cache_creation; + m.cache_hit_rate = if ti > 0 { t.input_cache_read as f64 / ti as f64 } else { 0.0 }; + m.requests = t.requests; + m.input_other = t.input_other; m.output = t.output; + m.input_cache_read = t.input_cache_read; m.input_cache_creation = t.input_cache_creation; + m.cost_usd = t.cost_usd; m.total_tokens = t.total_tokens; + m + }).collect(); + models.sort_by(|a, b| b.total_tokens.cmp(&a.total_tokens)); + + let recent_total = filtered.len(); + let recent_limit = 500; + let recent: Vec = filtered.iter().take(recent_limit).map(|r| RecentRow { + time: r.time, model: r.model.clone(), model_display: r.model_display.clone(), + model_resolved: r.model_resolved.clone(), + input_other: r.input_other, output: r.output, + input_cache_read: r.input_cache_read, input_cache_creation: r.input_cache_creation, + total_tokens: r.input_other + r.output + r.input_cache_read + r.input_cache_creation, + cost_usd: r.cost_usd, cost_estimated: r.cost_estimated, + price_id: r.price_id.clone(), from_env: r.from_env, + }).collect(); + + RangeStats { + range: range_label, + totals, + daily, + models, + recent, + recent_total, + recent_limit, + } +} + +impl TotalsRow { + fn default() -> Self { + TotalsRow { + requests: 0, input_other: 0, output: 0, + input_cache_read: 0, input_cache_creation: 0, + cost_usd: 0.0, total_tokens: 0, cache_hit_rate: 0.0, + } + } + fn add(&mut self, r: &UsageRecord) { + self.requests += 1; + self.input_other += r.input_other; + self.output += r.output; + self.input_cache_read += r.input_cache_read; + self.input_cache_creation += r.input_cache_creation; + self.cost_usd += r.cost_usd; + self.total_tokens = self.input_other + self.output + self.input_cache_read + self.input_cache_creation; + } +} + +fn filter_by_range<'a>(records: &'a [UsageRecord], range: &str, now_ms: u64) -> Vec<&'a UsageRecord> { + if range == "all" { return records.iter().collect(); } + let start = range_start(range, now_ms); + records.iter().filter(|r| r.time >= start).collect() +} + +fn range_start(range: &str, now_ms: u64) -> u64 { + match range { + "today" => { + // LOCAL midnight today — not UTC midnight. Without this, users east of UTC see + // "today" begin at the wrong hour (e.g. UTC+8 users get cutoff at local 08:00). + let now_utc = DateTime::from_timestamp((now_ms / 1000) as i64, 0).unwrap_or_default(); + let now_local = now_utc.with_timezone(&Local); + let today_date = now_local.date_naive(); + let today_start = today_date.and_hms_opt(0, 0, 0).unwrap_or_default(); + Local + .from_local_datetime(&today_start) + .single() + .map(|dt| dt.timestamp() as u64 * 1000) + .unwrap_or_else(|| today_start.and_utc().timestamp() as u64 * 1000) + } + "7d" => now_ms - 7 * 24 * 3600 * 1000, + "30d" => now_ms - 30 * 24 * 3600 * 1000, + _ => now_ms - 30 * 24 * 3600 * 1000, + } +} + +fn build_heatmap(records: &[UsageRecord], now_ms: u64) -> HeatmapData { + let weeks = 53; + // Use LOCAL today for the heatmap's right edge so the current day's cell lights up correctly. + let now_utc = DateTime::from_timestamp((now_ms / 1000) as i64, 0).unwrap_or_default(); + let now_local = now_utc.with_timezone(&Local); + let end_date = now_local.date_naive(); + let start_date = end_date - chrono::Duration::days(weeks * 7 - 1); + let start_date = start_date - chrono::Duration::days(start_date.weekday().num_days_from_sunday() as i64); + + let mut by_day: HashMap = HashMap::new(); + for r in records { + let dk = day_key(r.time); + let t = by_day.entry(dk).or_default(); + t.add(r); + } + + let mut cursor = start_date; + let mut cells = Vec::new(); + let mut max_tokens = 0u64; + + while cursor <= end_date { + let key = format!("{:04}-{:02}-{:02}", cursor.year(), cursor.month(), cursor.day()); + let t = by_day.get(&key).cloned().unwrap_or_else(TotalsRow::default); + let tok = t.total_tokens; + if tok > max_tokens { max_tokens = tok; } + let dow = cursor.weekday().num_days_from_sunday() as usize; + let week_idx = ((cursor - start_date).num_days() / 7) as usize; + let ti = t.input_other + t.input_cache_read + t.input_cache_creation; + let ch = if ti > 0 { t.input_cache_read as f64 / ti as f64 } else { 0.0 }; + cells.push(HeatmapCell { + date: key, dow, week_index: week_idx, + requests: t.requests, total_tokens: tok, cost_usd: t.cost_usd, + cache_hit_rate: ch, level: 0, + }); + cursor += chrono::Duration::days(1); + if cells.len() > (weeks * 7 + 7) as usize { break; } + } + for c in &mut cells { + c.level = if max_tokens == 0 || c.total_tokens == 0 { + 0 + } else { + let r = c.total_tokens as f64 / max_tokens as f64; + if r > 0.75 { 4 } else if r > 0.5 { 3 } else if r > 0.25 { 2 } else { 1 } + }; + } + + let mut month_labels = Vec::new(); + let mut last_month = String::new(); + for c in &cells { + let m = c.date[..7].to_string(); + if m != last_month { + month_labels.push(MonthLabel { week_index: c.week_index, label: c.date[5..7].to_string() }); + last_month = m; + } + } + + HeatmapData { + weeks: weeks as usize, + start: start_date.format("%Y-%m-%d").to_string(), + end: end_date.format("%Y-%m-%d").to_string(), + max_tokens, + cells, + month_labels, + } +} + +// --------------------------------------------------------------------------- +// Sessions +// --------------------------------------------------------------------------- + +fn list_workspace_dirs(home: &Path) -> Vec { + let root = sessions_root(home); + if !root.exists() { return vec![]; } + let mut out = Vec::new(); + let re = workspace_re(); + for entry in safe_read_dir(&root) { + if !entry.file_type().map(|t| t.is_dir()).unwrap_or(false) { continue; } + let name = entry.file_name().to_string_lossy().to_string(); + if name == ".kcd-archive" { continue; } + if !re.is_match(&name) { continue; } + out.push(name); + } + out.sort(); + out +} + +fn read_state_safe(session_dir: &Path) -> (Option, Option, Option, Option) { + let sp = session_dir.join("state.json"); + if !sp.exists() { return (None, None, None, None); } + if let Ok(content) = fs::read_to_string(&sp) { + if let Ok(obj) = serde_json::from_str::(&content) { + let title = obj.get("title").and_then(|v| v.as_str().map(|s| s.to_string())); + let work_dir = obj.get("workDir").and_then(|v| v.as_str().map(|s| s.to_string())); + let created_at = obj.get("createdAt").and_then(|v| v.as_str().map(|s| s.to_string())); + let updated_at = obj.get("updatedAt").and_then(|v| v.as_str().map(|s| s.to_string())); + return (title, work_dir, created_at, updated_at); + } + } + (None, None, None, None) +} + +fn humanize_workspace(id: &str) -> String { + let re = Regex::new(r"^wd_(.+)_[0-9a-fA-F]{8,}$").unwrap(); + if let Some(caps) = re.captures(id) { + caps.get(1).map(|m| m.as_str().to_string()).unwrap_or_else(|| id.to_string()) + } else { + id.to_string() + } +} + +fn list_sessions_in_dir(dir: &Path, workspace_id: &str, status: &str) -> Vec { + let mut sessions = Vec::new(); + if !dir.exists() { return sessions; } + let re = session_re(); + for entry in safe_read_dir(dir) { + if !entry.file_type().map(|t| t.is_dir()).unwrap_or(false) { continue; } + let name = entry.file_name().to_string_lossy().to_string(); + if !re.is_match(&name) { continue; } + let (title, work_dir, created_at, updated_at) = read_state_safe(&entry.path()); + let (bytes, files) = file_size_approx(&entry.path()); + let mtime = entry.path().metadata().ok().and_then(|m| m.modified().ok()) + .map(|t| t.duration_since(std::time::UNIX_EPOCH).ok().map(|d| d.as_millis() as u64)).flatten(); + sessions.push(SessionRow { + id: name, workspace_id: workspace_id.to_string(), status: status.to_string(), + title, work_dir, created_at, + updated_at: updated_at.or_else(|| mtime.map(|m| { + let secs = if m > 1e12 as u64 { m / 1000 } else { m }; + let dt = DateTime::from_timestamp(secs as i64, 0).unwrap_or_default().naive_utc(); + dt.to_string() + })), + bytes, files, + }); + } + sessions +} + +fn list_sessions_cmd(home: &Path, status: &str, workspace_filter: Option) -> SessionsResult { + let root = sessions_root(home); + let archive_root = root.join(".kcd-archive"); + let mut ws_ids: Vec = list_workspace_dirs(home); + // Also include archive-only workspaces + if archive_root.exists() { + for entry in safe_read_dir(&archive_root) { + let name = entry.file_name().to_string_lossy().to_string(); + if workspace_re().is_match(&name) && !ws_ids.contains(&name) { + ws_ids.push(name); + } + } + } + ws_ids.sort(); + + // Load workspaces.json + let wp = home.join("workspaces.json"); + let mut ws_meta: HashMap = HashMap::new(); + if let Ok(content) = fs::read_to_string(&wp) { + if let Ok(obj) = serde_json::from_str::(&content) { + if let Some(ws) = obj.get("workspaces").and_then(|v| v.as_object()) { + for (k, v) in ws { + ws_meta.insert(k.clone(), v.clone()); + } + } + } + } + + let mut workspaces = Vec::new(); + let mut all_sessions = Vec::new(); + + for wid in &ws_ids { + if let Some(ref filter) = workspace_filter { + if wid != filter { continue; } + } + let meta = ws_meta.get(wid); + let name = meta.and_then(|m| m.get("name").and_then(|v| v.as_str())) + .map(|s| s.to_string()).unwrap_or_else(|| humanize_workspace(wid)); + let root_path = meta.and_then(|m| m.get("root").and_then(|v| v.as_str()).map(|s| s.to_string())); + + let active_dir = root.join(wid); + let arch_dir = archive_root.join(wid); + let active_all = list_sessions_in_dir(&active_dir, wid, "active"); + let arch_all = list_sessions_in_dir(&arch_dir, wid, "archived"); + let active_list = if status == "archived" { vec![] } else { active_all.clone() }; + let arch_list = if status == "active" { vec![] } else { arch_all.clone() }; + + let empty = active_all.is_empty() && arch_all.is_empty(); + workspaces.push(WorkspaceRow { + id: wid.clone(), name, root: root_path, + created_at: None, last_opened_at: None, + active_count: active_all.len(), archived_count: arch_all.len(), empty, + }); + all_sessions.extend(active_list); + all_sessions.extend(arch_list); + } + + all_sessions.sort_by(|a, b| { + let ta = a.updated_at.as_deref().or(a.created_at.as_deref()).unwrap_or("").to_string(); + let tb = b.updated_at.as_deref().or(b.created_at.as_deref()).unwrap_or("").to_string(); + tb.cmp(&ta) + }); + + SessionsResult { + home: home.to_string_lossy().to_string(), + archive_root: ".kcd-archive".into(), + workspaces, + sessions: all_sessions, + } +} + +fn assert_safe_path(home: &Path, workspace_id: &str, session_id: &str) -> Result { + if !workspace_re().is_match(workspace_id) { + return Err("invalid workspace id".into()); + } + if !session_re().is_match(session_id) { + return Err("invalid session id".into()); + } + let root = sessions_root(home).canonicalize().unwrap_or_else(|_| sessions_root(home)); + let candidate = root.join(workspace_id).join(session_id).canonicalize().unwrap_or_else(|_| root.join(workspace_id).join(session_id)); + if !candidate.starts_with(&root) { + return Err("path escape blocked".into()); + } + Ok(candidate) +} + +fn archive_session_cmd(home: &Path, workspace_id: &str, session_id: &str) -> Result { + let src = assert_safe_path(home, workspace_id, session_id)?; + let dest = sessions_root(home).join(".kcd-archive").join(workspace_id).join(session_id); + if !src.exists() { return Err("session not found".into()); } + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("mkdir: {}", e))?; + } + fs::rename(&src, &dest).or_else(|_| { + // cross-device fallback + fs_extra::dir::copy(&src, dest.parent().unwrap(), &Default::default()).ok(); + fs::remove_dir_all(&src).ok(); + Ok::<(), String>(()) + }).map_err(|e: String| format!("move: {}", e))?; + scrub_session_index(home, session_id); + Ok(ActionResponse { + ok: true, workspace_id: workspace_id.to_string(), + session_id: session_id.to_string(), status: Some("archived".into()), + path: Some(dest.to_string_lossy().to_string()), deleted: None, + }) +} + +fn unarchive_session_cmd(home: &Path, workspace_id: &str, session_id: &str) -> Result { + let src = sessions_root(home).join(".kcd-archive").join(workspace_id).join(session_id); + let dest = assert_safe_path(home, workspace_id, session_id)?; + if !src.exists() { return Err("archived session not found".into()); } + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("mkdir: {}", e))?; + } + fs::rename(&src, &dest).or_else(|_| { + fs_extra::dir::copy(&src, dest.parent().unwrap(), &Default::default()).ok(); + fs::remove_dir_all(&src).ok(); + Ok::<(), String>(()) + }).map_err(|e: String| format!("move: {}", e))?; + Ok(ActionResponse { + ok: true, workspace_id: workspace_id.to_string(), + session_id: session_id.to_string(), status: Some("active".into()), + path: Some(dest.to_string_lossy().to_string()), deleted: None, + }) +} + +fn delete_session_cmd(home: &Path, workspace_id: &str, session_id: &str, status_hint: Option<&str>) -> Result { + let active = assert_safe_path(home, workspace_id, session_id)?; + let archived = sessions_root(home).join(".kcd-archive").join(workspace_id).join(session_id); + let target = match status_hint { + Some("archived") if archived.exists() => archived, + Some("active") if active.exists() => active, + _ => { + if active.exists() { active } else if archived.exists() { archived } + else { return Err("session not found".into()); } + } + }; + fs::remove_dir_all(&target).map_err(|e| format!("delete: {}", e))?; + scrub_session_index(home, session_id); + Ok(ActionResponse { + ok: true, workspace_id: workspace_id.to_string(), + session_id: session_id.to_string(), status: None, + path: Some(target.to_string_lossy().to_string()), deleted: Some(true), + }) +} + +fn scrub_session_index(home: &Path, session_id: &str) { + let ip = home.join("session_index.jsonl"); + if !ip.exists() { return; } + if let Ok(content) = fs::read_to_string(&ip) { + let lines: Vec<&str> = content.lines().filter(|l| { + let sid = format!("\"sessionId\":\"{}\"", session_id); + let sid2 = format!("\"sessionId\": \"{}\"", session_id); + let path_match = format!("/{}\"", session_id); + !l.contains(&sid) && !l.contains(&sid2) && !l.contains(&path_match) + }).collect(); + if lines.len() < content.lines().count() { + let _ = fs::write(&ip, lines.join("\n") + "\n"); + } + } +} + +fn delete_workspace_cmd(home: &Path, workspace_id: &str, _confirm: bool, _force: bool) -> Result { + if !workspace_re().is_match(workspace_id) { + return Err("invalid workspace id".into()); + } + let root = sessions_root(home); + let active_dir = root.join(workspace_id); + let arch_dir = root.join(".kcd-archive").join(workspace_id); + + if active_dir.exists() { + let active_list = list_sessions_in_dir(&active_dir, workspace_id, "active"); + if !active_list.is_empty() { return Err("workspace is not empty; archive/delete sessions first".into()); } + } + if arch_dir.exists() { + let arch_list = list_sessions_in_dir(&arch_dir, workspace_id, "archived"); + if !arch_list.is_empty() { return Err("workspace is not empty; archive/delete sessions first".into()); } + } + + if active_dir.exists() { fs::remove_dir_all(&active_dir).ok(); } + if arch_dir.exists() { fs::remove_dir_all(&arch_dir).ok(); } + + // Update workspaces.json + let wp = home.join("workspaces.json"); + if let Ok(content) = fs::read_to_string(&wp) { + if let Ok(mut obj) = serde_json::from_str::(&content) { + if let Some(ws) = obj.get_mut("workspaces").and_then(|v| v.as_object_mut()) { + ws.remove(workspace_id); + } + let deleted = obj.get_mut("deleted_workspace_ids") + .and_then(|v| v.as_array_mut()); + if let Some(arr) = deleted { + if !arr.iter().any(|v| v.as_str() == Some(workspace_id)) { + arr.push(serde_json::Value::String(workspace_id.to_string())); + } + } + let _ = fs::write(&wp, serde_json::to_string_pretty(&obj).unwrap() + "\n"); + } + } + + Ok(ActionResponse { + ok: true, workspace_id: workspace_id.to_string(), + session_id: String::new(), status: None, path: None, deleted: Some(true), + }) +} + +// --------------------------------------------------------------------------- +// Preview +// --------------------------------------------------------------------------- + +fn clip_text(s: &str, max: usize) -> String { + // Only walk the first `max` bytes — earlier version filtered the whole string, + // which was fine for short text but blew up when previewing big turns. + let (end, trunc) = if s.len() <= max { + (s.len(), false) + } else { + let mut e = max; + while e < s.len() && !s.is_char_boundary(e) { e += 1; } + (e, true) + }; + let head = &s[..end]; + let cleaned: String = head.chars().filter(|&c| c != '\0').collect(); + if trunc { format!("{}…", cleaned) } else { cleaned } +} + +fn extract_text_parts(content: &serde_json::Value) -> String { + if let Some(s) = content.as_str() { return s.to_string(); } + if let Some(arr) = content.as_array() { + let mut parts = Vec::new(); + for p in arr { + if let Some(obj) = p.as_object() { + if let Some(t) = obj.get("text").and_then(|v| v.as_str()) { + parts.push(t.to_string()); + } + } + } + return parts.join("\n"); + } + String::new() +} + +fn push_user_msg(msgs: &mut Vec, role: &str, text: &str, time: u64) { + let norm: String = text.split_whitespace().collect::>().join(" "); + if norm.is_empty() { return; } + if let Some(last) = msgs.last() { + if last.role == role { + let last_norm: String = last.text.split_whitespace().collect::>().join(" "); + if last_norm == norm { return; } + } + } + let text = if looks_like_secret(text) { "[redacted: possible secret content]".into() } else { clip_text(text, 2500) }; + msgs.push(PreviewMessage { role: role.into(), time: Some(time), text }); +} + +fn flush_assistant_msg(msgs: &mut Vec, bucket: &Option<(Vec, u64)>) { + if let Some((texts, _)) = bucket { + let combined = texts.join(""); + if !combined.trim().is_empty() { + let text = if looks_like_secret(&combined) { "[redacted: possible secret content]".into() } else { clip_text(&combined, 2500) }; + if let Some(last) = msgs.last() { + if last.role == "assistant" { + let last_norm: String = last.text.split_whitespace().collect::>().join(" "); + let this_norm: String = text.split_whitespace().collect::>().join(" "); + if last_norm == this_norm { return; } + } + } + msgs.push(PreviewMessage { role: "assistant".into(), time: None, text }); + } + } +} + +fn get_session_preview_cmd(home: &Path, workspace_id: &str, session_id: &str, status_hint: Option<&str>) -> Result { + let root = sessions_root(home); + let active = assert_safe_path(home, workspace_id, session_id)?; + let archived = root.join(".kcd-archive").join(workspace_id).join(session_id); + let session_dir = match status_hint { + Some("archived") if archived.exists() => archived, + _ => if active.exists() { active } else if archived.exists() { archived } + else { return Err("session not found".into()); } + }; + + let (title, work_dir, created_at, updated_at) = read_state_safe(&session_dir); + let api_dir = session_dir.join("agents").join("main"); + let mut wire_path = api_dir.join("wire.jsonl"); + if !wire_path.exists() { + wire_path = session_dir.join("wire.jsonl"); + } + if !wire_path.exists() { + // try first agent wire + let agents_dir = session_dir.join("agents"); + if agents_dir.exists() { + for entry in safe_read_dir(&agents_dir) { + let w = entry.path().join("wire.jsonl"); + if w.exists() { wire_path = w; break; } + } + } + } + + let mut messages: Vec = Vec::new(); + let mut truncated = false; + let max_msgs = 80; + let _max_chars = 2500usize; + // Hard byte cap: refuse to stream more than this from a single wire.jsonl. + // Typical heavy sessions are 5–30 MB; anything larger risks OOM in the WebView. + const MAX_WIRE_BYTES: usize = 20 * 1024 * 1024; // 20 MB + + if wire_path.exists() { + let file = match fs::File::open(&wire_path) { + Ok(f) => f, + Err(e) => return Err(format!("open wire: {e}")), + }; + let reader = BufReader::new(file); + let mut bytes_read = 0usize; + let mut line_count = 0usize; + let mut current_assistant: Option<(Vec, u64)> = None; + let mut current_step_key: Option = None; + + for line_res in reader.lines() { + let line = match line_res { + Ok(l) => l, + Err(_) => break, + }; + bytes_read += line.len() + 1; // +1 for the stripped newline + line_count += 1; + if bytes_read > MAX_WIRE_BYTES { truncated = true; break; } + if messages.len() >= max_msgs { truncated = true; break; } + if !line.contains("\"context.append_message\"") && !line.contains("\"turn.steer\"") + && !line.contains("\"turn.prompt\"") && !line.contains("\"content.part\"") + && !line.contains("\"step.end\"") { continue; } + let obj: serde_json::Value = match serde_json::from_str(&line) { + Ok(v) => v, Err(_) => continue, + }; + let typ = obj.get("type").and_then(|v| v.as_str()).unwrap_or(""); + + if typ == "context.append_message" { + flush_assistant_msg(&mut messages, ¤t_assistant); + current_assistant = None; + current_step_key = None; + let msg = &obj["message"]; + let role = msg.get("role").and_then(|v| v.as_str()).unwrap_or("unknown"); + if role == "tool" { continue; } + let raw = extract_text_parts(&msg["content"]); + if raw.trim().is_empty() { continue; } + push_user_msg(&mut messages, role, &raw, obj.get("time").and_then(|v| v.as_u64()).unwrap_or(0)); + continue; + } + + if typ == "turn.steer" || typ == "turn.prompt" { + let input = &obj["input"]; + let raw = if let Some(s) = input.as_str() { s.to_string() } + else if let Some(arr) = input.as_array() { + arr.iter().filter_map(|x| x.get("text").and_then(|v| v.as_str())).collect::>().join("\n") + } else { String::new() }; + if raw.trim().is_empty() { continue; } + push_user_msg(&mut messages, "user", &raw, obj.get("time").and_then(|v| v.as_u64()).unwrap_or(0)); + continue; + } + + if typ == "context.append_loop_event" { + let ev = &obj["event"]; + let ev_type = ev.get("type").and_then(|v| v.as_str()).unwrap_or(""); + if ev_type == "content.part" { + let part = &ev["part"]; + if part.get("type").and_then(|v| v.as_str()) == Some("text") { + let text = part.get("text").and_then(|v| v.as_str()).unwrap_or(""); + if !text.is_empty() { + let step_key = ev.get("stepUuid").and_then(|v| v.as_str()) + .map(|s| s.to_string()).unwrap_or_else(|| format!("{}:{}", ev["turnId"], ev["step"])); + // flush if step changed + if current_step_key.as_deref() != Some(&step_key) { + flush_assistant_msg(&mut messages, ¤t_assistant); + current_assistant = Some((Vec::new(), obj.get("time").and_then(|v| v.as_u64()).unwrap_or(0))); + current_step_key = Some(step_key.clone()); + } else if current_assistant.is_none() { + current_assistant = Some((Vec::new(), obj.get("time").and_then(|v| v.as_u64()).unwrap_or(0))); + } + current_assistant.as_mut().unwrap().0.push(text.to_string()); + } + } + continue; + } + if ev_type == "step.end" { + flush_assistant_msg(&mut messages, ¤t_assistant); + current_assistant = None; + current_step_key = None; + } + } + } + flush_assistant_msg(&mut messages, ¤t_assistant); + if line_count > 8000 { truncated = true; } + if messages.len() >= max_msgs { truncated = true; } + if bytes_read > MAX_WIRE_BYTES { truncated = true; } + } + + Ok(PreviewResult { + workspace_id: workspace_id.to_string(), + session_id: session_id.to_string(), + status: if session_dir.to_string_lossy().contains(".kcd-archive") { "archived".into() } else { "active".into() }, + title, work_dir, created_at, updated_at, + message_count: messages.len(), + truncated, + messages, + }) +} + +fn looks_like_secret(s: &str) -> bool { + let re = regex::Regex::new(r"(?i)api[_-]?key|sk-[a-zA-Z0-9]{12,}|BEGIN (RSA |OPENSSH )?PRIVATE KEY").unwrap(); + re.is_match(s) +} + +// --------------------------------------------------------------------------- +// Tauri commands +// --------------------------------------------------------------------------- + +#[tauri::command] +pub fn get_paths() -> PathsResult { + let home = resolve_kimi_home(None); + let valid = is_kimi_home(&home); + let mut candidates = Vec::new(); + if let Ok(env_home) = std::env::var("KIMI_CODE_HOME") { + let p = PathBuf::from(&env_home); + candidates.push(PathCandidate { path: env_home, valid: is_kimi_home(&p) }); + } + if let Some(hd) = dirs::home_dir() { + let p = hd.join(".kimi-code"); + candidates.push(PathCandidate { path: p.to_string_lossy().to_string(), valid: is_kimi_home(&p) }); + if let Ok(up) = std::env::var("USERPROFILE") { + let p2 = PathBuf::from(&up).join(".kimi-code"); + if !candidates.iter().any(|c| c.path == p2.to_string_lossy()) { + candidates.push(PathCandidate { path: p2.to_string_lossy().to_string(), valid: is_kimi_home(&p2) }); + } + } + } + PathsResult { + current: home.to_string_lossy().to_string(), + valid, + candidates, + env: EnvInfo { + kimi_code_home: std::env::var("KIMI_CODE_HOME").ok(), + kimi_model_name: std::env::var("KIMI_MODEL_NAME").ok(), + }, + } +} + +#[tauri::command] +pub fn get_prices() -> PricesResult { + PricesResult { prices: list_prices() } +} + +#[tauri::command] +pub fn get_summary(home_override: Option, range: Option, refresh: Option) -> SummaryResult { + let _refresh = refresh.unwrap_or(false); + let home = resolve_kimi_home(home_override); + let now_ms = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_millis() as u64; + let r = range.unwrap_or_else(|| "30d".into()); + + let (records, meta) = scan_usage(&home); + let stats = aggregate(&records, &r, now_ms); + let all_stats = aggregate(&records, "all", now_ms); + let heatmap = build_heatmap(&records, now_ms); + + let all_models: Vec = all_stats.models.into_iter().map(|m| { + AllModelRow { + model: m.model, model_display: m.model_display, requests: m.requests, + total_tokens: m.total_tokens, cost_usd: m.cost_usd, cost_estimated: m.cost_estimated, + cache_hit_rate: m.cache_hit_rate, + } + }).collect(); + + let all_model_count = all_models.len(); + let mut range_totals = HashMap::new(); + for r_k in ["today", "7d", "30d", "all"] { + let s = aggregate(&records, r_k, now_ms); + range_totals.insert(r_k.to_string(), s.totals); + } + + let default_model = None; + let env_model = std::env::var("KIMI_MODEL_NAME").ok().map(|name| EnvModelInfo { + name, provider: std::env::var("KIMI_MODEL_PROVIDER").ok(), model: std::env::var("KIMI_MODEL_ID").ok(), + }); + + SummaryResult { + home: home.to_string_lossy().to_string(), + valid: is_kimi_home(&home), + scanned_at: now_ms, + meta, + model_map: ModelMapInfo { default_model, env_model, alias_count: 0 }, + range: r, + stats, + heatmap, + all_models, + all_model_count, + range_totals, + } +} + +#[tauri::command] +pub fn list_sessions(home_override: Option, status: Option, workspace: Option) -> SessionsResult { + let home = resolve_kimi_home(home_override); + list_sessions_cmd(&home, &status.unwrap_or_else(|| "active".into()), workspace) +} + +#[tauri::command] +pub fn archive_session(home_override: Option, workspace_id: String, session_id: String) -> Result { + let home = resolve_kimi_home(home_override); + archive_session_cmd(&home, &workspace_id, &session_id) +} + +#[tauri::command] +pub fn unarchive_session(home_override: Option, workspace_id: String, session_id: String) -> Result { + let home = resolve_kimi_home(home_override); + unarchive_session_cmd(&home, &workspace_id, &session_id) +} + +#[tauri::command] +pub fn delete_session(home_override: Option, workspace_id: String, session_id: String, status: Option) -> Result { + let home = resolve_kimi_home(home_override); + delete_session_cmd(&home, &workspace_id, &session_id, status.as_deref()) +} + +#[tauri::command] +pub fn delete_workspace(home_override: Option, workspace_id: String, confirm: bool, force: Option) -> Result { + if !confirm { return Err("confirm_required: Pass confirm:true to delete an empty workspace".into()); } + let home = resolve_kimi_home(home_override); + delete_workspace_cmd(&home, &workspace_id, confirm, force.unwrap_or(false)) +} + +#[tauri::command] +pub fn get_session_preview(home_override: Option, workspace_id: String, session_id: String, status: Option) -> Result { + let home = resolve_kimi_home(home_override); + get_session_preview_cmd(&home, &workspace_id, &session_id, status.as_deref()) +} diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs new file mode 100644 index 0000000..150f27d --- /dev/null +++ b/src-tauri/src/db.rs @@ -0,0 +1,338 @@ +//! Kimi Switch local SQLite storage. +//! +//! This module stores the full Kimi Switch configuration (all providers and models +//! for both Kimi Code and Pi agents) in a local SQLite database. It is separate +//! from the agent-specific config files that are written when the user activates +//! a provider. + +use std::path::PathBuf; + +use anyhow::Context; +use indexmap::IndexMap; +use rusqlite::{params, Connection}; +use serde_json::Value; + +use crate::models::{Agent, Config, Model, Provider, ProviderType}; + +pub type DbResult = anyhow::Result; + +pub fn kimi_switch_data_dir() -> PathBuf { + dirs::home_dir() + .map(|h| h.join(".kimi-switch")) + .expect("failed to resolve home directory") +} + +pub fn db_path() -> PathBuf { + kimi_switch_data_dir().join("kimi-switch.db") +} + +/// One-time migration: if the legacy `~/.pi-switch/` data directory exists and +/// `~/.kimi-switch/` does not, move it so existing users keep their saved +/// configuration. Safe to call on every startup — it is a no-op once the new +/// directory exists. +fn migrate_legacy_data_dir() { + let new_dir = kimi_switch_data_dir(); + if new_dir.exists() { + return; + } + let old_dir = match dirs::home_dir() { + Some(h) => h.join(".pi-switch"), + None => return, + }; + if !old_dir.exists() { + return; + } + // Best-effort move; failures are silently ignored so the app can still start. + if let Some(new_parent) = new_dir.parent() { + if let Err(_) = std::fs::create_dir_all(new_parent) { + return; + } + } + let _ = std::fs::rename(&old_dir, &new_dir); +} + +pub fn init_db() -> DbResult { + migrate_legacy_data_dir(); + let path = db_path(); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent) + .with_context(|| format!("failed to create directory {}", parent.display()))?; + } + let conn = Connection::open(&path) + .with_context(|| format!("failed to open database {}", path.display()))?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS providers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + agent TEXT NOT NULL, + name TEXT NOT NULL, + provider_type TEXT NOT NULL, + base_url TEXT, + api_key TEXT, + env TEXT, + note TEXT, + official_url TEXT, + managed INTEGER NOT NULL DEFAULT 0, + enabled INTEGER NOT NULL DEFAULT 1, + active INTEGER NOT NULL DEFAULT 0, + raw_other TEXT, + UNIQUE(agent, name) + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS models ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + agent TEXT NOT NULL, + alias TEXT NOT NULL, + provider_name TEXT NOT NULL, + model TEXT NOT NULL, + max_context_size INTEGER NOT NULL, + display_name TEXT, + supports_1m INTEGER NOT NULL DEFAULT 0, + capabilities TEXT, + raw_other TEXT, + UNIQUE(agent, alias) + )", + [], + )?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS settings ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + )", + [], + )?; + + // Add icon columns for provider icon picker (introduced in v0.3.1). + // SQLite has no ADD COLUMN IF NOT EXISTS, so ignore duplicate-column errors. + for stmt in [ + "ALTER TABLE providers ADD COLUMN icon TEXT", + "ALTER TABLE providers ADD COLUMN icon_color TEXT", + ] { + if let Err(e) = conn.execute(stmt, []) { + let msg = e.to_string(); + if !msg.contains("duplicate column name") { + return Err(e).with_context(|| format!("failed to run migration: {}", stmt)); + } + } + } + + Ok(conn) +} + +pub fn load_config(agent: &Agent) -> DbResult { + let mut conn = init_db()?; + let tx = conn.transaction()?; + + let default_model = get_setting_tx(&tx, &default_model_key(agent))?; + + let mut providers = IndexMap::new(); + { + let mut stmt = tx.prepare( + "SELECT name, provider_type, base_url, api_key, env, note, official_url, managed, enabled, active, icon, icon_color, raw_other + FROM providers WHERE agent = ?1 ORDER BY id", + )?; + let provider_rows = stmt.query_map(params![agent.as_str()], |row| { + let provider_type: String = row.get(1)?; + let env_json: Option = row.get(4)?; + let raw_json: Option = row.get(12)?; + Ok(Provider { + name: row.get(0)?, + provider_type: provider_type_for_str(&provider_type), + base_url: row.get(2)?, + api_key: row.get(3)?, + env: env_json + .and_then(|s| serde_json::from_str(&s).ok()) + .unwrap_or_default(), + note: row.get(5)?, + official_url: row.get(6)?, + managed: row.get::<_, i32>(7)? != 0, + enabled: row.get::<_, i32>(8)? != 0, + active: row.get::<_, i32>(9)? != 0, + icon: row.get(10)?, + icon_color: row.get(11)?, + raw_other: raw_json + .and_then(|s| serde_json::from_str(&s).ok()) + .unwrap_or(Value::Null), + // Merged from the settings table by load_agent_config_command. + usage_kinds: None, + }) + })?; + + for provider in provider_rows { + let p = provider?; + providers.insert(p.name.clone(), p); + } + } + + let mut models = IndexMap::new(); + { + let mut stmt = tx.prepare( + "SELECT alias, provider_name, model, max_context_size, display_name, supports_1m, capabilities, raw_other + FROM models WHERE agent = ?1 ORDER BY id", + )?; + let model_rows = stmt.query_map(params![agent.as_str()], |row| { + let caps_json: Option = row.get(6)?; + let raw_json: Option = row.get(7)?; + Ok(Model { + alias: row.get(0)?, + provider: row.get(1)?, + model: row.get(2)?, + max_context_size: row.get::<_, i64>(3)? as u64, + display_name: row.get(4)?, + supports_1m: row.get::<_, i32>(5)? != 0, + capabilities: caps_json + .and_then(|s| serde_json::from_str(&s).ok()) + .unwrap_or_default(), + raw_other: raw_json + .and_then(|s| serde_json::from_str(&s).ok()) + .unwrap_or(Value::Null), + }) + })?; + + for model in model_rows { + let m = model?; + models.insert(m.alias.clone(), m); + } + } + + tx.commit()?; + + Ok(Config { + default_model, + providers, + models, + raw_other: Value::Null, + }) +} + +pub fn save_config(agent: &Agent, config: &Config) -> DbResult<()> { + let mut conn = init_db()?; + let tx = conn.transaction()?; + + tx.execute("DELETE FROM providers WHERE agent = ?1", params![agent.as_str()])?; + tx.execute("DELETE FROM models WHERE agent = ?1", params![agent.as_str()])?; + + { + let mut insert_provider = tx.prepare( + "INSERT INTO providers + (agent, name, provider_type, base_url, api_key, env, note, official_url, managed, enabled, active, icon, icon_color, raw_other) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)", + )?; + + for provider in config.providers.values() { + insert_provider.execute(params![ + agent.as_str(), + provider.name, + provider.provider_type.as_str(), + provider.base_url, + provider.api_key, + serde_json::to_string(&provider.env).ok(), + provider.note, + provider.official_url, + provider.managed as i32, + provider.enabled as i32, + provider.active as i32, + provider.icon, + provider.icon_color, + serde_json::to_string(&provider.raw_other).ok(), + ])?; + } + } + + { + let mut insert_model = tx.prepare( + "INSERT INTO models + (agent, alias, provider_name, model, max_context_size, display_name, supports_1m, capabilities, raw_other) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)", + )?; + + for model in config.models.values() { + insert_model.execute(params![ + agent.as_str(), + model.alias, + model.provider, + model.model, + model.max_context_size as i64, + model.display_name, + model.supports_1m as i32, + serde_json::to_string(&model.capabilities).ok(), + serde_json::to_string(&model.raw_other).ok(), + ])?; + } + } + + if let Some(default_model) = &config.default_model { + set_setting_tx(&tx, &default_model_key(agent), default_model)?; + } else { + tx.execute("DELETE FROM settings WHERE key = ?1", params![default_model_key(agent)])?; + } + + tx.commit()?; + Ok(()) +} + +fn default_model_key(agent: &Agent) -> String { + format!("default_model:{}", agent.as_str()) +} + +fn get_setting_tx(tx: &rusqlite::Transaction, key: &str) -> DbResult> { + let mut stmt = tx.prepare("SELECT value FROM settings WHERE key = ?1")?; + let mut rows = stmt.query(params![key])?; + if let Some(row) = rows.next()? { + Ok(Some(row.get(0)?)) + } else { + Ok(None) + } +} + +fn set_setting_tx(tx: &rusqlite::Transaction, key: &str, value: &str) -> DbResult<()> { + tx.execute( + "INSERT INTO settings (key, value) VALUES (?1, ?2) + ON CONFLICT(key) DO UPDATE SET value = excluded.value", + params![key, value], + )?; + Ok(()) +} + +/// Public helper: read a single setting without an explicit transaction. +pub fn get_setting_pub(key: &str) -> DbResult> { + let conn = init_db()?; + let mut stmt = conn.prepare("SELECT value FROM settings WHERE key = ?1")?; + let mut rows = stmt.query(params![key])?; + if let Some(row) = rows.next()? { + Ok(Some(row.get(0)?)) + } else { + Ok(None) + } +} + +/// Public helper: write a single setting in its own transaction. +pub fn set_setting_pub(key: &str, value: &str) -> DbResult<()> { + let mut conn = init_db()?; + let tx = conn.transaction()?; + set_setting_tx(&tx, key, value)?; + tx.commit()?; + Ok(()) +} + +/// Public helper: delete a single setting (no-op if the key does not exist). +pub fn delete_setting_pub(key: &str) -> DbResult<()> { + let conn = init_db()?; + conn.execute("DELETE FROM settings WHERE key = ?1", params![key])?; + Ok(()) +} + +fn provider_type_for_str(s: &str) -> ProviderType { + match s { + "anthropic" => ProviderType::Anthropic, + "openai" => ProviderType::Openai, + "openai_responses" => ProviderType::OpenaiResponses, + "google-genai" => ProviderType::GoogleGenai, + "vertexai" => ProviderType::Vertexai, + _ => ProviderType::Kimi, + } +} diff --git a/src-tauri/src/kimi_code_io.rs b/src-tauri/src/kimi_code_io.rs new file mode 100644 index 0000000..7b75d23 --- /dev/null +++ b/src-tauri/src/kimi_code_io.rs @@ -0,0 +1,758 @@ +//! Kimi Code configuration I/O. +//! +//! Kimi Code stores its configuration in `~/.kimi-code/config.toml`. +//! This module reads/writes that file and converts between Kimi's TOML +//! format and Kimi Switch's internal `Config`/`Provider`/`Model` types. + +use std::path::PathBuf; + +use anyhow::Context; +use indexmap::IndexMap; +use serde_json::Value; +use toml::value::{Table, Value as TomlValue}; + +use crate::config_io::backup_file; +use crate::models::{Agent, Config, Model, Provider, ProviderType}; + +pub type KimiResult = anyhow::Result; + +pub fn kimi_code_config_dir() -> PathBuf { + std::env::var_os("KIMI_CODE_HOME") + .map(PathBuf::from) + .or_else(|| dirs::home_dir().map(|h| h.join(".kimi-code"))) + .expect("failed to resolve Kimi Code config directory") +} + +pub fn kimi_code_config_path() -> PathBuf { + kimi_code_config_dir().join("config.toml") +} + +/// Read the existing Kimi Code `config.toml`, or return an empty table if it +/// does not exist yet. +pub fn load_kimi_code_config() -> KimiResult { + let path = kimi_code_config_path(); + if !path.exists() { + return Ok(TomlValue::Table(Table::new())); + } + let content = std::fs::read_to_string(&path) + .with_context(|| format!("failed to read {}", path.display()))?; + let value: TomlValue = content + .parse() + .with_context(|| format!("failed to parse {}", path.display()))?; + Ok(value) +} + +/// Write the given TOML value to Kimi Code's config file, creating the +/// directory if needed and backing up the previous file. +pub fn save_kimi_code_config(value: &TomlValue) -> KimiResult<()> { + let path = kimi_code_config_path(); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent) + .with_context(|| format!("failed to create directory {}", parent.display()))?; + } + + if path.exists() { + backup_file(&path, 7).with_context(|| { + format!("failed to back up Kimi Code config {}", path.display()) + })?; + } + + let content = toml::to_string_pretty(value) + .with_context(|| "failed to serialize Kimi Code config.toml")?; + std::fs::write(&path, content) + .with_context(|| format!("failed to write {}", path.display()))?; + Ok(()) +} + +/// Import a Kimi Code TOML config into Kimi Switch's internal `Config`. +pub fn kimi_code_to_config(value: &TomlValue) -> Config { + let root = value.as_table().cloned().unwrap_or_default(); + + let default_model = root + .get("default_model") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + let mut providers = IndexMap::new(); + let mut models = IndexMap::new(); + + // Read models first so we can determine which provider the default_model + // belongs to. Only that provider should be marked active in the UI. + if let Some(models_table) = root.get("models").and_then(|v| v.as_table()) { + for (alias, mv) in models_table { + let table = mv.as_table().cloned().unwrap_or_default(); + let provider = table + .get("provider") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + .unwrap_or_default(); + let model_id = table + .get("model") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + .unwrap_or_default(); + let max_context_size = table + .get("max_context_size") + .and_then(|v| v.as_integer()) + .map(|n| n as u64) + .unwrap_or(128_000); + let display_name = table + .get("display_name") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + let capabilities: Vec = table + .get("capabilities") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }) + .unwrap_or_default(); + let supports_1m = max_context_size >= 1_000_000; + + let raw_other = { + let mut rest = table.clone(); + rest.remove("provider"); + rest.remove("model"); + rest.remove("max_context_size"); + rest.remove("display_name"); + rest.remove("capabilities"); + toml_value_to_json(&TomlValue::Table(rest)) + }; + + models.insert( + alias.clone(), + Model { + alias: alias.clone(), + provider, + model: model_id, + max_context_size, + display_name, + supports_1m, + capabilities, + raw_other, + }, + ); + } + } + + let active_provider_name = default_model + .as_ref() + .and_then(|alias| models.get(alias)) + .map(|m| m.provider.as_str()); + + if let Some(providers_table) = root.get("providers").and_then(|v| v.as_table()) { + for (name, pv) in providers_table { + let table = pv.as_table().cloned().unwrap_or_default(); + let provider_type = table + .get("type") + .and_then(|v| v.as_str()) + .map(provider_type_for_kimi_type) + .unwrap_or(ProviderType::Kimi); + + let base_url = table.get("base_url").and_then(|v| v.as_str()).map(|s| s.to_string()); + let api_key = table.get("api_key").and_then(|v| v.as_str()).map(|s| s.to_string()); + let managed = table.contains_key("oauth") + || table.get("managed").and_then(|v| v.as_bool()).unwrap_or(false); + let enabled = table.get("enabled").and_then(|v| v.as_bool()).unwrap_or(true); + + let env: IndexMap = table + .get("env") + .and_then(|v| v.as_table()) + .map(|t| { + t.iter() + .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string()))) + .collect() + }) + .unwrap_or_default(); + + let icon = table + .get("icon") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + let icon_color = table + .get("icon_color") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + let raw_other = { + let mut rest = table.clone(); + rest.remove("type"); + rest.remove("base_url"); + rest.remove("api_key"); + rest.remove("managed"); + rest.remove("enabled"); + rest.remove("env"); + // NOTE: `oauth` is intentionally kept in raw_other so that the + // exact `storage`/`key` block round-trips verbatim on export. + // Previously it was stripped here and regenerated on export + // with a key derived from the provider name, which corrupted + // the managed:kimi-code credential reference (e.g. + // "oauth/kimi-code" became "oauth/managed-kimi-code"). + toml_value_to_json(&TomlValue::Table(rest)) + }; + + providers.insert( + name.clone(), + Provider { + name: name.clone(), + provider_type, + base_url: base_url.filter(|s| !s.is_empty()), + api_key: api_key.filter(|s| !s.is_empty()), + env, + note: None, + official_url: None, + managed, + enabled, + active: active_provider_name == Some(name.as_str()), + icon, + icon_color, + raw_other, + usage_kinds: None, + }, + ); + } + } + + let raw_other = { + let mut rest = root; + rest.remove("default_model"); + rest.remove("providers"); + rest.remove("models"); + toml_value_to_json(&TomlValue::Table(rest)) + }; + + Config { + default_model, + providers, + models, + raw_other, + } +} + +/// Export Kimi Switch's internal `Config` to a Kimi Code TOML config value. +/// +/// If `existing` is provided, unknown top-level sections (e.g. `services`) are +/// preserved; otherwise a fresh TOML table is used. +pub fn config_to_kimi_code(config: &Config, existing: Option<&TomlValue>) -> TomlValue { + let mut root = existing + .and_then(|v| v.as_table().cloned()) + .unwrap_or_default(); + + root.insert( + "default_model".to_string(), + config + .default_model + .clone() + .map(TomlValue::String) + .unwrap_or(TomlValue::String("".to_string())), + ); + + let mut providers_table = Table::new(); + for (name, provider) in &config.providers { + // Write ALL providers to Kimi Code config. The active provider is + // selected via `default_model`, so keeping the full list matches the + // CLI's native multi-provider behavior and prevents data loss when + // switching. + let mut pt = Table::new(); + pt.insert("type".to_string(), TomlValue::String(provider.provider_type.as_str().to_string())); + if let Some(base_url) = provider.base_url.clone().filter(|s| !s.is_empty()) { + pt.insert("base_url".to_string(), TomlValue::String(base_url)); + } + if let Some(api_key) = provider.api_key.clone().filter(|s| !s.is_empty()) { + pt.insert("api_key".to_string(), TomlValue::String(api_key)); + } + pt.insert("enabled".to_string(), TomlValue::Boolean(provider.enabled)); + if let Some(icon) = provider.icon.clone().filter(|s| !s.is_empty()) { + pt.insert("icon".to_string(), TomlValue::String(icon)); + } + if let Some(icon_color) = provider.icon_color.clone().filter(|s| !s.is_empty()) { + pt.insert("icon_color".to_string(), TomlValue::String(icon_color)); + } + if !provider.env.is_empty() { + let mut env_table = Table::new(); + for (k, v) in &provider.env { + env_table.insert(k.clone(), TomlValue::String(v.clone())); + } + pt.insert("env".to_string(), TomlValue::Table(env_table)); + } + if provider.managed { + // Preserve existing oauth config if present, otherwise create a default entry. + let oauth = provider + .raw_other + .get("oauth") + .and_then(json_to_toml) + .unwrap_or_else(|| { + let mut t = Table::new(); + t.insert("storage".to_string(), TomlValue::String("file".to_string())); + t.insert("key".to_string(), TomlValue::String(format!("oauth/{}", name.replace(':', "-")))); + TomlValue::Table(t) + }); + pt.insert("oauth".to_string(), oauth); + } + // Merge remaining raw fields (oauth and env are handled explicitly above). + if let TomlValue::Table(mut extra) = json_to_toml(&provider.raw_other).unwrap_or(TomlValue::Table(Table::new())) { + extra.remove("oauth"); + extra.remove("env"); + // Strip Kimi-Switch-private field: the remembered per-provider + // default model is stored in raw_other.default_model and must NOT + // leak into the agent's config.toml. + extra.remove("default_model"); + for (k, v) in extra { + pt.insert(k, v); + } + } + providers_table.insert(name.clone(), TomlValue::Table(pt)); + } + root.insert("providers".to_string(), TomlValue::Table(providers_table)); + + // Write all models — each provider's models are kept so the CLI's + // /provider command can list and switch between them. + let mut models_table = Table::new(); + for (alias, model) in &config.models { + let mut mt = Table::new(); + mt.insert("provider".to_string(), TomlValue::String(model.provider.clone())); + mt.insert("model".to_string(), TomlValue::String(model.model.clone())); + mt.insert( + "max_context_size".to_string(), + TomlValue::Integer(model.max_context_size as i64), + ); + if let Some(display_name) = model.display_name.clone().filter(|s| !s.is_empty()) { + mt.insert("display_name".to_string(), TomlValue::String(display_name)); + } + let capabilities = model.capabilities.clone(); + if !capabilities.is_empty() { + mt.insert( + "capabilities".to_string(), + TomlValue::Array(capabilities.into_iter().map(TomlValue::String).collect()), + ); + } + if let TomlValue::Table(mut extra) = json_to_toml(&model.raw_other).unwrap_or(TomlValue::Table(Table::new())) { + extra.remove("provider"); + extra.remove("model"); + extra.remove("max_context_size"); + extra.remove("display_name"); + extra.remove("capabilities"); + for (k, v) in extra { + mt.insert(k, v); + } + } + models_table.insert(alias.clone(), TomlValue::Table(mt)); + } + root.insert("models".to_string(), TomlValue::Table(models_table)); + + TomlValue::Table(root) +} + +fn provider_type_for_kimi_type(typ: &str) -> ProviderType { + match typ { + "anthropic" => ProviderType::Anthropic, + "openai" => ProviderType::Openai, + "openai_responses" => ProviderType::OpenaiResponses, + "google-genai" => ProviderType::GoogleGenai, + "vertexai" => ProviderType::Vertexai, + _ => ProviderType::Kimi, + } +} + +fn toml_value_to_json(value: &TomlValue) -> Value { + match value { + TomlValue::String(s) => Value::String(s.clone()), + TomlValue::Integer(n) => Value::Number((*n).into()), + TomlValue::Float(n) => Value::Number(serde_json::Number::from_f64(*n).unwrap_or(Value::Null.as_u64().unwrap_or(0).into())), + TomlValue::Boolean(b) => Value::Bool(*b), + TomlValue::Array(arr) => Value::Array(arr.iter().map(toml_value_to_json).collect()), + TomlValue::Table(t) => { + let mut map = serde_json::Map::new(); + for (k, v) in t { + map.insert(k.clone(), toml_value_to_json(v)); + } + Value::Object(map) + } + TomlValue::Datetime(dt) => Value::String(dt.to_string()), + } +} + +fn json_to_toml(value: &Value) -> Option { + match value { + Value::Null => None, + Value::Bool(b) => Some(TomlValue::Boolean(*b)), + Value::Number(n) => { + if let Some(i) = n.as_i64() { + Some(TomlValue::Integer(i)) + } else if let Some(f) = n.as_f64() { + Some(TomlValue::Float(f)) + } else { + None + } + } + Value::String(s) => Some(TomlValue::String(s.clone())), + Value::Array(arr) => Some(TomlValue::Array( + arr.iter().filter_map(json_to_toml).collect(), + )), + Value::Object(obj) => { + let mut t = Table::new(); + for (k, v) in obj { + if let Some(tv) = json_to_toml(v) { + t.insert(k.clone(), tv); + } + } + Some(TomlValue::Table(t)) + } + } +} + +/// Convenience entry point used by commands: load and convert. +pub fn load_kimi_code_config_as_config() -> KimiResult { + let value = load_kimi_code_config()?; + Ok(kimi_code_to_config(&value)) +} + +/// Convenience entry point used by commands: convert and save. +pub fn save_config_as_kimi_code(config: &Config) -> KimiResult<()> { + let existing = load_kimi_code_config().ok(); + let value = config_to_kimi_code(config, existing.as_ref()); + save_kimi_code_config(&value) +} + +/// Open the Kimi Code config directory in the system file manager. +pub fn open_kimi_code_config_dir() -> KimiResult<()> { + let path = kimi_code_config_dir(); + std::fs::create_dir_all(&path) + .with_context(|| format!("failed to create directory {}", path.display()))?; + Ok(()) +} + +impl Agent { + pub fn config_dir(&self) -> PathBuf { + match self { + Agent::KimiCode => kimi_code_config_dir(), + Agent::Pi => crate::pi_io::pi_agent_dir(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn kimi_code_import_extracts_providers_and_models() { + let toml_str = r#" +default_model = "kimi-code/kimi-for-coding" +default_thinking = true + +[providers."managed:kimi-code"] +type = "kimi" +api_key = "" +base_url = "https://api.kimi.com/coding/v1" + +[providers."managed:kimi-code".oauth] +storage = "file" +key = "oauth/kimi-code" + +[models."kimi-code/kimi-for-coding"] +provider = "managed:kimi-code" +model = "kimi-for-coding" +max_context_size = 262144 +capabilities = ["thinking", "always_thinking", "image_in", "video_in", "tool_use"] +display_name = "K2.7 Code" + +[services.moonshot_search] +base_url = "https://api.kimi.com/coding/v1/search" +api_key = "" +"#; + let value: TomlValue = toml_str.parse().unwrap(); + let config = kimi_code_to_config(&value); + + assert_eq!(config.default_model.as_deref(), Some("kimi-code/kimi-for-coding")); + assert_eq!(config.providers.len(), 1); + assert_eq!(config.models.len(), 1); + + let provider = config.providers.get("managed:kimi-code").unwrap(); + assert_eq!(provider.provider_type, ProviderType::Kimi); + assert!(provider.managed); + assert_eq!(provider.base_url.as_deref(), Some("https://api.kimi.com/coding/v1")); + + let model = config.models.get("kimi-code/kimi-for-coding").unwrap(); + assert_eq!(model.provider, "managed:kimi-code"); + assert_eq!(model.model, "kimi-for-coding"); + assert_eq!(model.max_context_size, 262144); + assert!(model.capabilities.contains(&"thinking".to_string())); + // supports_1m reflects context size only, not thinking capability. + assert!(!model.supports_1m); + + // Unknown top-level sections are preserved. + let services = config.raw_other.get("services"); + assert!(services.is_some()); + } + + #[test] + fn kimi_code_export_roundtrip_preserves_model() { + let mut providers = IndexMap::new(); + providers.insert( + "glmzhongzhuan".to_string(), + Provider { + name: "glmzhongzhuan".to_string(), + provider_type: ProviderType::Anthropic, + base_url: Some("https://fast.cdks.work".to_string()), + api_key: Some("sk-test".to_string()), + env: IndexMap::new(), + note: None, + official_url: None, + managed: false, + enabled: true, + active: true, + icon: None, + icon_color: None, + raw_other: Value::Null, + usage_kinds: None, + }, + ); + let mut models = IndexMap::new(); + models.insert( + "glm-5.2".to_string(), + Model { + alias: "glm-5.2".to_string(), + provider: "glmzhongzhuan".to_string(), + model: "glm-5.2".to_string(), + max_context_size: 900_000, + display_name: None, + supports_1m: true, + capabilities: vec!["thinking".to_string()], + raw_other: Value::Null, + }, + ); + let config = Config { + default_model: Some("glm-5.2".to_string()), + providers, + models, + raw_other: Value::Null, + }; + + let exported = config_to_kimi_code(&config, None); + let root = exported.as_table().unwrap(); + assert_eq!( + root.get("default_model").and_then(|v| v.as_str()), + Some("glm-5.2") + ); + + let providers_table = root.get("providers").unwrap().as_table().unwrap(); + let provider = providers_table.get("glmzhongzhuan").unwrap().as_table().unwrap(); + assert_eq!(provider.get("type").and_then(|v| v.as_str()), Some("anthropic")); + assert_eq!(provider.get("api_key").and_then(|v| v.as_str()), Some("sk-test")); + + let models_table = root.get("models").unwrap().as_table().unwrap(); + let model = models_table.get("glm-5.2").unwrap().as_table().unwrap(); + assert_eq!(model.get("model").and_then(|v| v.as_str()), Some("glm-5.2")); + let caps = model.get("capabilities").unwrap().as_array().unwrap(); + assert!(caps.iter().any(|v| v.as_str() == Some("thinking"))); + } + + #[test] + fn kimi_code_export_does_not_inject_thinking_from_supports_1m() { + let mut providers = IndexMap::new(); + providers.insert( + "test-provider".to_string(), + Provider { + name: "test-provider".to_string(), + provider_type: ProviderType::Anthropic, + base_url: Some("https://example.com".to_string()), + api_key: Some("sk-test".to_string()), + env: IndexMap::new(), + note: None, + official_url: None, + managed: false, + enabled: true, + active: true, + icon: None, + icon_color: None, + raw_other: Value::Null, + usage_kinds: None, + }, + ); + let mut models = IndexMap::new(); + models.insert( + "big-model".to_string(), + Model { + alias: "big-model".to_string(), + provider: "test-provider".to_string(), + model: "big-model".to_string(), + max_context_size: 2_000_000, + display_name: None, + supports_1m: true, + capabilities: vec![], + raw_other: Value::Null, + }, + ); + let config = Config { + default_model: Some("big-model".to_string()), + providers, + models, + raw_other: Value::Null, + }; + + let exported = config_to_kimi_code(&config, None); + let root = exported.as_table().unwrap(); + let models_table = root.get("models").unwrap().as_table().unwrap(); + let model = models_table.get("big-model").unwrap().as_table().unwrap(); + // supports_1m=true but capabilities empty → must NOT inject "thinking". + let caps = model.get("capabilities"); + match caps { + None => {} + Some(v) => { + let arr = v.as_array().unwrap(); + assert!( + !arr.iter().any(|c| c.as_str() == Some("thinking")), + "thinking should not be injected from supports_1m" + ); + } + } + } + + #[test] + fn kimi_code_oauth_key_roundtrip() { + // Regression: importing then exporting managed:kimi-code must preserve + // the exact oauth key "oauth/kimi-code". Previously the oauth block + // was dropped on import and regenerated on export as + // "oauth/managed-kimi-code", breaking the official subscription. + let toml_str = r#" +default_model = "kimi-code/k3" + +[providers."managed:kimi-code"] +type = "kimi" +api_key = "" +base_url = "https://api.kimi.com/coding/v1" + +[providers."managed:kimi-code".oauth] +storage = "file" +key = "oauth/kimi-code" + +[models."kimi-code/k3"] +provider = "managed:kimi-code" +model = "k3" +max_context_size = 1048576 +"#; + let value: TomlValue = toml_str.parse().unwrap(); + let config = kimi_code_to_config(&value); + + // Export back to TOML. + let exported = config_to_kimi_code(&config, None); + let root = exported.as_table().unwrap(); + let providers = root.get("providers").unwrap().as_table().unwrap(); + let managed = providers.get("managed:kimi-code").unwrap().as_table().unwrap(); + let oauth = managed.get("oauth").unwrap().as_table().unwrap(); + assert_eq!( + oauth.get("key").and_then(|v| v.as_str()), + Some("oauth/kimi-code"), + "oauth key must round-trip verbatim, not be regenerated" + ); + assert_eq!( + oauth.get("storage").and_then(|v| v.as_str()), + Some("file") + ); + } + + #[test] + fn kimi_code_export_writes_all_providers() { + // Regression: inactive providers must still be written to config.toml + // so that switching does not wipe the provider list. + let mut providers = IndexMap::new(); + providers.insert( + "active-one".to_string(), + Provider { + name: "active-one".to_string(), + provider_type: ProviderType::Anthropic, + base_url: Some("https://a.example.com".to_string()), + api_key: Some("sk-a".to_string()), + env: IndexMap::new(), + note: None, + official_url: None, + managed: false, + enabled: true, + active: true, + icon: None, + icon_color: None, + raw_other: Value::Null, + usage_kinds: None, + }, + ); + providers.insert( + "inactive-one".to_string(), + Provider { + name: "inactive-one".to_string(), + provider_type: ProviderType::Openai, + base_url: Some("https://b.example.com".to_string()), + api_key: Some("sk-b".to_string()), + env: IndexMap::new(), + note: None, + official_url: None, + managed: false, + enabled: true, + active: false, + icon: None, + icon_color: None, + raw_other: Value::Null, + usage_kinds: None, + }, + ); + let config = Config { + default_model: None, + providers, + models: IndexMap::new(), + raw_other: Value::Null, + }; + + let exported = config_to_kimi_code(&config, None); + let root = exported.as_table().unwrap(); + let providers_table = root.get("providers").unwrap().as_table().unwrap(); + assert_eq!(providers_table.len(), 2, "both providers must be written"); + assert!(providers_table.contains_key("active-one")); + assert!(providers_table.contains_key("inactive-one")); + } + + #[test] + fn kimi_code_export_strips_private_default_model() { + // The remembered per-provider default model (raw_other.default_model) + // is a Kimi-Switch-private field and must NOT leak into config.toml. + let mut providers = IndexMap::new(); + providers.insert( + "p".to_string(), + Provider { + name: "p".to_string(), + provider_type: ProviderType::Anthropic, + base_url: None, + api_key: Some("sk-x".to_string()), + env: IndexMap::new(), + note: None, + official_url: None, + managed: false, + enabled: true, + active: true, + icon: None, + icon_color: None, + raw_other: serde_json::json!({"default_model": "some-alias"}), + usage_kinds: None, + }, + ); + let config = Config { + default_model: None, + providers, + models: IndexMap::new(), + raw_other: Value::Null, + }; + + let exported = config_to_kimi_code(&config, None); + let root = exported.as_table().unwrap(); + let provider = root + .get("providers").unwrap() + .as_table().unwrap() + .get("p").unwrap() + .as_table().unwrap(); + assert!( + !provider.contains_key("default_model"), + "private default_model must not leak into config.toml" + ); + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs new file mode 100644 index 0000000..7149c0e --- /dev/null +++ b/src-tauri/src/lib.rs @@ -0,0 +1,119 @@ +pub mod commands; +pub mod config_io; +pub mod dashboard; +pub mod db; +pub mod kimi_code_io; +pub mod models; +pub mod pi_io; +pub mod services; + +use tauri::menu::{Menu, MenuItem, PredefinedMenuItem}; +use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder}; +use tauri::Manager; + +pub fn run() { + tauri::Builder::default() + // Single instance: must be registered before other plugins. When a + // second process is launched, this callback runs in the existing + // instance and simply brings its window back (including from tray). + .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { + if let Some(window) = app.get_webview_window("main") { + let _ = window.unminimize(); + let _ = window.show(); + let _ = window.set_focus(); + } + })) + .plugin(tauri_plugin_opener::init()) + .setup(|app| { + println!("[Tauri] Setup started"); + let window = app.get_webview_window("main").unwrap(); + println!("[Tauri] Window label: {}", window.label()); + + // Tray menu: show / separator / quit + let show_i = MenuItem::with_id(app, "show", "显示", true, None::<&str>)?; + let quit_i = MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?; + let menu = Menu::with_items( + app, + &[&show_i, &PredefinedMenuItem::separator(app)?, &quit_i], + )?; + + // Tray icon: reuse the window icon + let icon = app.default_window_icon().unwrap().clone(); + TrayIconBuilder::new() + .icon(icon) + .menu(&menu) + .show_menu_on_left_click(false) + .on_menu_event(|app, event| match event.id.as_ref() { + "show" => { + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.unminimize(); + let _ = window.set_focus(); + } + } + "quit" => { + app.exit(0); + } + _ => {} + }) + .on_tray_icon_event(|tray, event| { + if let tauri::tray::TrayIconEvent::Click { + button, + button_state, + .. + } = event + { + if button == MouseButton::Left && button_state == MouseButtonState::Up { + let app = tray.app_handle(); + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.unminimize(); + let _ = window.set_focus(); + } + } + } + }) + .build(app)?; + + // Close button -> hide to tray instead of quitting. Minimize keeps + // the taskbar button (native behaviour); only an explicit close + // (window X) retreats to the tray. + let window_clone = window.clone(); + window.on_window_event(move |event| match event { + tauri::WindowEvent::CloseRequested { api, .. } => { + api.prevent_close(); + let _ = window_clone.hide(); + } + _ => {} + }); + + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + commands::load_agent_config_command, + commands::save_agent_config_command, + commands::activate_agent_config_command, + commands::open_agent_config_dir, + commands::get_app_version, + commands::list_provider_models, + commands::test_connectivity, + commands::query_provider_usage, + commands::debug_log, + commands::get_app_setting, + commands::set_app_setting, + commands::check_for_update, + commands::download_update, + commands::open_installer, + dashboard::get_paths, + dashboard::get_prices, + dashboard::get_summary, + dashboard::list_sessions, + dashboard::archive_session, + dashboard::unarchive_session, + dashboard::delete_session, + dashboard::delete_workspace, + dashboard::get_session_preview, + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs new file mode 100644 index 0000000..f3af8e8 --- /dev/null +++ b/src-tauri/src/main.rs @@ -0,0 +1,5 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + kimiswitch_lib::run(); +} diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs new file mode 100644 index 0000000..a910a9c --- /dev/null +++ b/src-tauri/src/models.rs @@ -0,0 +1,235 @@ +use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// Target agent whose provider/model config is being edited. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Agent { + KimiCode, + Pi, +} + +impl Agent { + pub fn as_str(&self) -> &'static str { + match self { + Agent::KimiCode => "kimi_code", + Agent::Pi => "pi", + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ProviderType { + Anthropic, + Openai, + #[serde(rename = "openai_responses")] + OpenaiResponses, + #[serde(rename = "google-genai")] + GoogleGenai, + Vertexai, + /// Kept for compatibility; mapped to OpenAI-compatible in Pi. + Kimi, +} + +const fn default_true() -> bool { + true +} + +impl ProviderType { + pub fn as_str(&self) -> &'static str { + match self { + ProviderType::Anthropic => "anthropic", + ProviderType::Openai => "openai", + ProviderType::OpenaiResponses => "openai_responses", + ProviderType::GoogleGenai => "google-genai", + ProviderType::Vertexai => "vertexai", + ProviderType::Kimi => "kimi", + } + } + + pub fn default_base_url(&self) -> Option<&'static str> { + match self { + ProviderType::Openai | ProviderType::OpenaiResponses | ProviderType::Kimi => { + Some("https://api.openai.com/v1") + } + ProviderType::GoogleGenai => Some("https://generativelanguage.googleapis.com"), + ProviderType::Anthropic | ProviderType::Vertexai => None, + } + } + + pub fn is_openai_compatible(&self) -> bool { + matches!( + self, + ProviderType::Kimi | ProviderType::Openai | ProviderType::OpenaiResponses + ) + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct Provider { + pub name: String, + pub provider_type: ProviderType, + pub base_url: Option, + pub api_key: Option, + #[serde(default)] + pub env: IndexMap, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub note: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub official_url: Option, + #[serde(default)] + pub managed: bool, + #[serde(default = "default_true")] + pub enabled: bool, + #[serde(default)] + pub active: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub icon: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub icon_color: Option, + #[serde(default, skip_serializing_if = "Value::is_null")] + pub raw_other: Value, + /// Billing/usage query kinds for this provider (e.g. "balance:deepseek", + /// "plan:kimi_coding"). Persisted in the SQLite settings table under + /// `usage_kinds:`, NOT in the agent's config.toml — both + /// export paths (kimi_code_io manual TOML, pi_io PiProvider struct) are + /// explicit and never serialize this field, while the IPC payload to the + /// frontend does carry it. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub usage_kinds: Option>, +} + +impl PartialEq for Provider { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.provider_type == other.provider_type + && self.base_url == other.base_url + && self.api_key == other.api_key + && self.env == other.env + && self.note == other.note + && self.official_url == other.official_url + && self.managed == other.managed + && self.enabled == other.enabled + && self.active == other.active + && self.icon == other.icon + && self.icon_color == other.icon_color + && self.raw_other == other.raw_other + && self.usage_kinds == other.usage_kinds + } +} + +impl Eq for Provider {} + +impl std::fmt::Debug for Provider { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Provider") + .field("name", &self.name) + .field("provider_type", &self.provider_type) + .field("base_url", &self.base_url) + .field("api_key", &"") + .field("env", &"") + .field("managed", &self.managed) + .field("enabled", &self.enabled) + .field("active", &self.active) + .field("icon", &self.icon) + .field("icon_color", &self.icon_color) + .field("raw_other", &"") + .finish() + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct Model { + pub alias: String, + pub provider: String, + pub model: String, + pub max_context_size: u64, + pub display_name: Option, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub supports_1m: bool, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub capabilities: Vec, + #[serde(default, skip_serializing_if = "Value::is_null")] + pub raw_other: Value, +} + +impl std::fmt::Debug for Model { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Model") + .field("alias", &self.alias) + .field("provider", &self.provider) + .field("model", &self.model) + .field("max_context_size", &self.max_context_size) + .field("display_name", &self.display_name) + .field("supports_1m", &self.supports_1m) + .field("capabilities", &self.capabilities) + .field("raw_other", &"") + .finish() + } +} + +impl PartialEq for Model { + fn eq(&self, other: &Self) -> bool { + self.alias == other.alias + && self.provider == other.provider + && self.model == other.model + && self.max_context_size == other.max_context_size + && self.display_name == other.display_name + && self.supports_1m == other.supports_1m + && self.capabilities == other.capabilities + && self.raw_other == other.raw_other + } +} + +impl Eq for Model {} + +#[derive(Clone, Serialize, Deserialize)] +pub struct Config { + pub default_model: Option, + #[serde(default)] + pub providers: IndexMap, + #[serde(default)] + pub models: IndexMap, + #[serde(default, skip_serializing_if = "Value::is_null")] + pub raw_other: Value, +} + +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + self.default_model == other.default_model + && self.providers == other.providers + && self.models == other.models + && self.raw_other == other.raw_other + } +} + +impl Eq for Config {} + +impl std::fmt::Debug for Config { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Config") + .field("default_model", &self.default_model) + .field( + "providers", + &format!( + "{:?} ({} providers)", + self.providers.keys().collect::>(), + self.providers.len() + ), + ) + .field("models", &self.models) + .field("raw_other", &"") + .finish() + } +} + +/// A model discovered from a provider's API endpoint. +/// The frontend uses this to populate a `Model` form entry. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct DiscoveredModel { + pub id: String, + pub display_name: Option, + pub max_context_size: Option, +} diff --git a/src-tauri/src/pi_io.rs b/src-tauri/src/pi_io.rs new file mode 100644 index 0000000..2f75f85 --- /dev/null +++ b/src-tauri/src/pi_io.rs @@ -0,0 +1,626 @@ +//! Pi CLI configuration I/O. +//! +//! Pi stores custom providers and models in `~/.pi/agent/models.json`. +//! This module reads and writes that file and converts between Pi's JSON +//! format and Kimi Switch's internal `Config`/`Provider`/`Model` types. + +use std::path::PathBuf; + +use anyhow::Context; +use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use crate::config_io::backup_file; +use crate::models::{Config, Model, Provider, ProviderType}; + +pub type PiResult = anyhow::Result; + +/// Returns the default Pi agent config directory for the current user. +pub fn pi_agent_dir() -> PathBuf { + std::env::var_os("PI_CODING_AGENT_DIR") + .map(PathBuf::from) + .or_else(|| dirs::home_dir().map(|h| h.join(".pi").join("agent"))) + .expect("failed to resolve Pi agent config directory") +} + +/// Returns the path to Pi's `models.json` file. +pub fn pi_models_path() -> PathBuf { + pi_agent_dir().join("models.json") +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PiCost { + pub input: f64, + pub output: f64, + #[serde(rename = "cacheRead", default)] + pub cache_read: f64, + #[serde(rename = "cacheWrite", default)] + pub cache_write: f64, +} + +/// A single Pi model entry. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PiModel { + pub id: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(default)] + pub reasoning: bool, + #[serde(default = "default_input", skip_serializing_if = "is_default_input")] + pub input: Vec, + #[serde(rename = "contextWindow", default = "default_context_window")] + pub context_window: u64, + #[serde(rename = "maxTokens", default, skip_serializing_if = "Option::is_none")] + pub max_tokens: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cost: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub compat: Option, + #[serde(flatten)] + pub extra: Value, +} + +fn default_input() -> Vec { + vec!["text".to_string()] +} + +fn is_default_input(input: &[String]) -> bool { + input.len() == 1 && input.first().map(String::as_str) == Some("text") +} + +fn default_context_window() -> u64 { + 128_000 +} + +fn default_true() -> bool { + true +} + +/// A single Pi provider entry. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PiProvider { + #[serde(rename = "baseUrl", default, skip_serializing_if = "Option::is_none")] + pub base_url: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub api: Option, + #[serde(rename = "apiKey", default, skip_serializing_if = "Option::is_none")] + pub api_key: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub headers: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub compat: Option, + #[serde(default = "default_true")] + pub enabled: bool, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub models: Vec, + #[serde(flatten)] + pub extra: Value, +} + +/// Root Pi `models.json` structure. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PiModelsFile { + #[serde(default, skip_serializing_if = "Option::is_none")] + pub default_model: Option, + #[serde(default)] + pub providers: IndexMap, + #[serde(flatten)] + pub extra: Value, +} + +/// Read the existing Pi `models.json` file, or return a default empty struct +/// if the file does not exist yet. +pub fn load_pi_models() -> PiResult { + let path = pi_models_path(); + if !path.exists() { + return Ok(PiModelsFile::default()); + } + let content = std::fs::read_to_string(&path) + .with_context(|| format!("failed to read {}", path.display()))?; + let file: PiModelsFile = serde_json::from_str(&content) + .with_context(|| format!("failed to parse {}", path.display()))?; + Ok(file) +} + +/// Write the given Pi models file, creating the parent directory if needed. +/// A backup of the previous file is created when it already exists. +pub fn save_pi_models(file: &PiModelsFile) -> PiResult<()> { + let path = pi_models_path(); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent) + .with_context(|| format!("failed to create directory {}", parent.display()))?; + } + + if path.exists() { + backup_file(&path, 7).with_context(|| { + format!("failed to back up Pi models {}", path.display()) + })?; + } + + let content = serde_json::to_string_pretty(file) + .with_context(|| "failed to serialize Pi models.json")?; + std::fs::write(&path, content) + .with_context(|| format!("failed to write {}", path.display()))?; + Ok(()) +} + +/// Returns the path to Pi's `settings.json` file. +pub fn pi_settings_path() -> PathBuf { + pi_agent_dir().join("settings.json") +} + +/// Pi's `settings.json` file (only the fields Kimi Switch manipulates). +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PiSettingsFile { + #[serde(rename = "defaultProvider", default, skip_serializing_if = "Option::is_none")] + pub default_provider: Option, + #[serde(rename = "defaultModel", default, skip_serializing_if = "Option::is_none")] + pub default_model: Option, + #[serde(flatten)] + pub extra: Value, +} + +/// Read the existing Pi `settings.json` file, or return a default empty struct +/// if the file does not exist yet. +pub fn load_pi_settings() -> PiResult { + let path = pi_settings_path(); + if !path.exists() { + return Ok(PiSettingsFile::default()); + } + let content = std::fs::read_to_string(&path) + .with_context(|| format!("failed to read {}", path.display()))?; + let file: PiSettingsFile = serde_json::from_str(&content) + .with_context(|| format!("failed to parse {}", path.display()))?; + Ok(file) +} + +/// Write the given Pi settings file, creating the parent directory if needed. +/// A backup of the previous file is created when it already exists. +pub fn save_pi_settings(file: &PiSettingsFile) -> PiResult<()> { + let path = pi_settings_path(); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent) + .with_context(|| format!("failed to create directory {}", parent.display()))?; + } + + if path.exists() { + backup_file(&path, 7).with_context(|| { + format!("failed to back up Pi settings {}", path.display()) + })?; + } + + let content = serde_json::to_string_pretty(file) + .with_context(|| "failed to serialize Pi settings.json")?; + std::fs::write(&path, content) + .with_context(|| format!("failed to write {}", path.display()))?; + Ok(()) +} + +/// Convert a Kimi Switch provider type to the Pi `api` field value. +pub fn pi_api_for_provider(provider_type: &ProviderType) -> &'static str { + match provider_type { + ProviderType::Openai => "openai-completions", + ProviderType::OpenaiResponses => "openai-responses", + ProviderType::Anthropic => "anthropic-messages", + ProviderType::GoogleGenai => "google-generative-ai", + ProviderType::Vertexai => "google-vertex", + // Treat Kimi as OpenAI-compatible since it is not a native Pi API. + ProviderType::Kimi => "openai-completions", + } +} + +/// Convert a Pi `api` field value back to a Kimi Switch provider type. +pub fn provider_type_for_pi_api(api: &str) -> ProviderType { + match api { + "openai-responses" => ProviderType::OpenaiResponses, + "anthropic-messages" => ProviderType::Anthropic, + "google-generative-ai" => ProviderType::GoogleGenai, + "google-vertex" => ProviderType::Vertexai, + _ => ProviderType::Openai, + } +} + +/// Merge provider-level fields that have dedicated `PiProvider` fields into the +/// `raw_other` blob so they survive the round-trip through Kimi Switch's internal +/// `Config`. +fn merge_provider_known_into_raw(pi_provider: &PiProvider, raw: &mut Value) { + let has_known = pi_provider.headers.is_some() + || pi_provider.compat.is_some() + || pi_provider.api.is_some(); + if !has_known { + return; + } + + if raw.is_null() { + *raw = Value::Object(serde_json::Map::new()); + } + if let Some(obj) = raw.as_object_mut() { + if let Some(headers) = &pi_provider.headers { + obj.insert("headers".to_string(), headers.clone()); + } + if let Some(compat) = &pi_provider.compat { + obj.insert("compat".to_string(), compat.clone()); + } + if let Some(api) = &pi_provider.api { + obj.insert("api".to_string(), Value::String(api.clone())); + } + } +} + +/// Merge model-level fields that have dedicated `PiModel` fields into the +/// `raw_other` blob so they survive the round-trip through Kimi Switch's internal +/// `Config`. +fn merge_model_known_into_raw(pi_model: &PiModel, raw: &mut Value) { + let has_known = pi_model.cost.is_some() + || pi_model.compat.is_some() + || pi_model.max_tokens.is_some(); + if !has_known { + return; + } + + if raw.is_null() { + *raw = Value::Object(serde_json::Map::new()); + } + if let Some(obj) = raw.as_object_mut() { + if let Some(cost) = &pi_model.cost { + if let Ok(value) = serde_json::to_value(cost) { + obj.insert("cost".to_string(), value); + } + } + if let Some(compat) = &pi_model.compat { + obj.insert("compat".to_string(), compat.clone()); + } + if let Some(max_tokens) = pi_model.max_tokens { + obj.insert( + "maxTokens".to_string(), + Value::Number(serde_json::Number::from(max_tokens)), + ); + } + } +} + +/// Extract provider-level fields that PiProvider serializes explicitly from the +/// `raw_other` blob. Any extracted keys are removed from the returned extra so +/// they are not duplicated by `#[serde(flatten)]`. +fn extract_provider_fields(raw: &Value) -> (Option, Option, Option, Value) { + let mut extra = raw.clone(); + let api = extra + .as_object_mut() + .and_then(|o| o.remove("api")) + .and_then(|v| v.as_str().map(String::from)); + let headers = extra.as_object_mut().and_then(|o| o.remove("headers")); + let compat = extra.as_object_mut().and_then(|o| o.remove("compat")); + (api, headers, compat, extra) +} + +/// Extract model-level fields that PiModel serializes explicitly from the +/// `raw_other` blob. Any extracted keys are removed from the returned extra. +fn extract_model_fields(raw: &Value) -> (Option, Option, Option, Value) { + let mut extra = raw.clone(); + let cost = extra + .as_object_mut() + .and_then(|o| o.remove("cost")) + .and_then(|v| serde_json::from_value(v).ok()); + let compat = extra.as_object_mut().and_then(|o| o.remove("compat")); + let max_tokens = extra + .as_object_mut() + .and_then(|o| o.remove("maxTokens")) + .and_then(|v| v.as_u64()); + (cost, compat, max_tokens, extra) +} + +/// Import a Pi `models.json` into a Kimi Switch `Config`. +pub fn pi_file_to_config(file: &PiModelsFile) -> Config { + let mut providers = IndexMap::new(); + let mut models = IndexMap::new(); + + for (name, pi_provider) in &file.providers { + let provider_type = pi_provider + .api + .as_deref() + .map(provider_type_for_pi_api) + .unwrap_or(ProviderType::Openai); + + let mut provider_raw = pi_provider.extra.clone(); + merge_provider_known_into_raw(pi_provider, &mut provider_raw); + + let provider = Provider { + name: name.clone(), + provider_type, + base_url: pi_provider.base_url.clone().filter(|s| !s.is_empty()), + api_key: pi_provider.api_key.clone().filter(|s| !s.is_empty()), + env: IndexMap::new(), + note: None, + official_url: None, + managed: false, + enabled: pi_provider.enabled, + active: true, + icon: None, + icon_color: None, + raw_other: provider_raw, + usage_kinds: None, + }; + + for (idx, pi_model) in pi_provider.models.iter().enumerate() { + let alias = pi_model + .name + .clone() + .filter(|s| !s.is_empty()) + .unwrap_or_else(|| { + if pi_model.id.trim().is_empty() { + format!("{}-model-{}", name, idx + 1) + } else { + pi_model.id.clone() + } + }); + let display_name = pi_model.name.clone().filter(|s| !s.is_empty()); + + let mut model_raw = pi_model.extra.clone(); + merge_model_known_into_raw(pi_model, &mut model_raw); + + models.insert( + alias.clone(), + Model { + alias, + provider: name.clone(), + model: pi_model.id.clone(), + max_context_size: pi_model.context_window, + display_name, + supports_1m: pi_model.reasoning || pi_model.context_window >= 1_000_000, + capabilities: vec![], + raw_other: model_raw, + }, + ); + } + + providers.insert(name.clone(), provider); + } + + Config { + default_model: file.default_model.clone(), + providers, + models, + raw_other: file.extra.clone(), + } +} + +/// Export a Kimi Switch `Config` to a Pi `models.json`. +pub fn config_to_pi_file(config: &Config) -> PiModelsFile { + let mut providers = IndexMap::new(); + + for (name, provider) in &config.providers { + let (provider_api, provider_headers, provider_compat, provider_extra) = + extract_provider_fields(&provider.raw_other); + let api = provider_api.unwrap_or_else(|| pi_api_for_provider(&provider.provider_type).to_string()); + + let mut pi_models = Vec::new(); + for model in config.models.values() { + if model.provider != *name { + continue; + } + let display_name = model.display_name.clone().filter(|s| !s.is_empty()); + let name_field = display_name.clone().filter(|s| s != &model.model); + let (model_cost, model_compat, model_max_tokens, model_extra) = + extract_model_fields(&model.raw_other); + + pi_models.push(PiModel { + id: model.model.clone(), + name: name_field, + reasoning: model.supports_1m, + input: default_input(), + context_window: model.max_context_size, + max_tokens: model_max_tokens, + cost: model_cost, + compat: model_compat, + extra: model_extra, + }); + } + + providers.insert( + name.clone(), + PiProvider { + base_url: provider.base_url.clone().filter(|s| !s.is_empty()), + api: Some(api), + api_key: provider.api_key.clone().filter(|s| !s.is_empty()), + headers: provider_headers, + compat: provider_compat, + enabled: provider.enabled, + models: pi_models, + extra: provider_extra, + }, + ); + } + + PiModelsFile { + // Pi does not use a top-level default_model field; defaults live in + // ~/.pi/agent/settings.json (defaultProvider / defaultModel). + default_model: None, + providers, + extra: config.raw_other.clone(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn pi_roundtrip_preserves_provider_and_model() { + let mut providers = IndexMap::new(); + providers.insert( + "my-openai".to_string(), + PiProvider { + base_url: Some("https://proxy.example.com/v1".to_string()), + api: Some("openai-completions".to_string()), + api_key: Some("sk-test".to_string()), + headers: None, + compat: None, + enabled: true, + models: vec![PiModel { + id: "gpt-test".to_string(), + name: Some("GPT Test".to_string()), + reasoning: true, + input: vec!["text".to_string()], + context_window: 200_000, + max_tokens: Some(4096), + cost: Some(PiCost { + input: 1.0, + output: 2.0, + cache_read: 0.0, + cache_write: 0.0, + }), + compat: None, + extra: Value::Null, + }], + extra: Value::Null, + }, + ); + let file = PiModelsFile { + default_model: None, + providers, + extra: Value::Null, + }; + + let config = pi_file_to_config(&file); + assert_eq!(config.providers.len(), 1); + assert_eq!(config.models.len(), 1); + + let provider = config.providers.get("my-openai").unwrap(); + assert_eq!(provider.provider_type, ProviderType::Openai); + assert_eq!(provider.base_url.as_deref(), Some("https://proxy.example.com/v1")); + assert_eq!(provider.api_key.as_deref(), Some("sk-test")); + + let model = config.models.get("GPT Test").unwrap(); + assert_eq!(model.model, "gpt-test"); + assert!(model.supports_1m); + assert_eq!(model.max_context_size, 200_000); + + let exported = config_to_pi_file(&config); + let exported_provider = exported.providers.get("my-openai").unwrap(); + assert_eq!(exported_provider.api.as_deref(), Some("openai-completions")); + assert_eq!(exported_provider.models[0].id, "gpt-test"); + assert!(exported_provider.models[0].reasoning); + } + + #[test] + fn pi_roundtrip_preserves_advanced_fields() { + let mut providers = IndexMap::new(); + providers.insert( + "my-proxy".to_string(), + PiProvider { + base_url: Some("https://proxy.example.com/v1".to_string()), + api: Some("anthropic-messages".to_string()), + api_key: Some("sk-test".to_string()), + headers: Some(serde_json::json!({"X-Custom": "value"})), + compat: Some(serde_json::json!({"supportsDeveloperRole": false})), + enabled: true, + models: vec![PiModel { + id: "custom-claude".to_string(), + name: Some("Custom Claude".to_string()), + reasoning: true, + input: vec!["text".to_string(), "image".to_string()], + context_window: 200_000, + max_tokens: Some(4096), + cost: Some(PiCost { + input: 1.0, + output: 2.0, + cache_read: 0.5, + cache_write: 0.75, + }), + compat: Some(serde_json::json!({"forceAdaptiveThinking": true})), + extra: serde_json::json!({ + "thinkingLevelMap": { + "off": null, + "minimal": null, + "low": "low", + "medium": "medium", + "high": "high", + "xhigh": "max" + }, + "headers": {"X-Model-Header": "model-value"}, + "api": "anthropic-messages" + }), + }], + extra: serde_json::json!({ + "name": "My Proxy", + "authHeader": true, + "modelOverrides": { + "claude-sonnet-4": {"name": "Overridden"} + } + }), + }, + ); + let file = PiModelsFile { + default_model: None, + providers, + extra: Value::Null, + }; + + let config = pi_file_to_config(&file); + let exported = config_to_pi_file(&config); + let provider = exported.providers.get("my-proxy").unwrap(); + + // Provider-level fields + assert_eq!( + provider.extra.get("name").and_then(|v| v.as_str()), + Some("My Proxy") + ); + assert_eq!( + provider.extra.get("authHeader").and_then(|v| v.as_bool()), + Some(true) + ); + assert_eq!( + provider + .extra + .get("modelOverrides") + .and_then(|v| v.as_object()) + .and_then(|o| o.get("claude-sonnet-4")) + .and_then(|v| v.get("name")), + Some(&serde_json::json!("Overridden")) + ); + assert_eq!( + provider.headers.as_ref().and_then(|h| h.get("X-Custom")), + Some(&serde_json::json!("value")) + ); + assert_eq!( + provider.compat.as_ref().and_then(|c| c.get("supportsDeveloperRole")), + Some(&serde_json::json!(false)) + ); + + // Model-level fields + let model = &provider.models[0]; + assert_eq!(model.id, "custom-claude"); + assert_eq!(model.max_tokens, Some(4096)); + assert_eq!(model.cost.as_ref().map(|c| c.output), Some(2.0)); + assert_eq!( + model.compat.as_ref().and_then(|c| c.get("forceAdaptiveThinking")), + Some(&serde_json::json!(true)) + ); + assert_eq!( + model.extra.get("thinkingLevelMap").and_then(|v| v.get("xhigh")), + Some(&serde_json::json!("max")) + ); + assert_eq!( + model.extra.get("headers").and_then(|v| v.get("X-Model-Header")), + Some(&serde_json::json!("model-value")) + ); + } + + #[test] + fn pi_settings_roundtrip() { + let file = PiSettingsFile { + default_provider: Some("my-proxy".to_string()), + default_model: Some("glm-5.2".to_string()), + extra: serde_json::json!({"theme": "dark"}), + }; + let serialized = serde_json::to_string_pretty(&file).unwrap(); + assert!(serialized.contains("defaultProvider")); + assert!(serialized.contains("defaultModel")); + + let deserialized: PiSettingsFile = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized.default_provider, file.default_provider); + assert_eq!(deserialized.default_model, file.default_model); + assert_eq!(deserialized.extra.get("theme"), Some(&serde_json::json!("dark"))); + } +} diff --git a/src-tauri/src/profile_manager.rs b/src-tauri/src/profile_manager.rs new file mode 100644 index 0000000..236d135 --- /dev/null +++ b/src-tauri/src/profile_manager.rs @@ -0,0 +1,2 @@ +//! Profile management for KimiSwitch. +//! Loads, saves, and switches between configuration profiles. diff --git a/src-tauri/src/services/balance.rs b/src-tauri/src/services/balance.rs new file mode 100644 index 0000000..61b3c2e --- /dev/null +++ b/src-tauri/src/services/balance.rs @@ -0,0 +1,326 @@ +// Adapted from cc-switch (MIT, © Jason Young) +// https://github.com/farion1231/cc-switch + +//! 供应商余额查询服务 +//! +//! 支持 DeepSeek、StepFun、SiliconFlow、OpenRouter、Novita AI 的账户余额查询。 +//! +//! 错误通道语义(与 cc-switch 一致): +//! - `Err(String)` = 瞬时传输失败(网络不可达/超时/读体中断)。前端 invoke reject, +//! 触发 retry 并保留上一次成功的 data(keep-last-good)。 +//! - `Ok(success:false)` = 确定性失败(空 key/鉴权失败/非 2xx/响应体非法 JSON), +//! 直接透出错误文案。 +//! +//! HTTP 调用与 JSON→UsageData 解析拆成纯函数,便于无 mock 单元测试。 + +use super::usage_types::{UsageData, UsageResult}; +use std::time::Duration; + +const REQUEST_TIMEOUT: Duration = Duration::from_secs(8); + +/// 鉴权头形式:绝大多数供应商用 `Bearer `;智谱套餐接口不加前缀(见 coding_plan)。 +pub(crate) enum AuthStyle { + Bearer, + Raw, +} + +/// GET 请求的归类结果。 +pub(crate) enum Fetched { + /// 2xx 且响应体是合法 JSON。 + Body(serde_json::Value), + /// 确定性失败(401/403/非 2xx/解析失败),调用方原样包成 Ok 返回。 + Failed(UsageResult), +} + +/// 统一的 GET + JSON 读取助手。瞬时失败(网络/超时/读体中断)返回 `Err`; +/// 确定性失败收进 `Fetched::Failed`。 +/// +/// 先 `bytes()` 再解析:读体失败(超时/连接中断)是瞬时 → Err;拿到完整响应体 +/// 后解析失败才是确定性。reqwest 的 `.json()` 把读体错误也包成 decode,无法区分。 +pub(crate) async fn get_json( + url: &str, + api_key: &str, + auth: AuthStyle, +) -> Result { + let client = reqwest::Client::builder() + .timeout(REQUEST_TIMEOUT) + .build() + .map_err(|e| format!("Failed to build HTTP client: {e}"))?; + + // 注意:api_key 只允许进请求头,严禁拼进 URL / 日志 / 错误信息。 + let req = client.get(url).header("Accept", "application/json"); + let req = match auth { + AuthStyle::Bearer => req.header("Authorization", format!("Bearer {api_key}")), + AuthStyle::Raw => req.header("Authorization", api_key), + }; + + let resp = match req.send().await { + Ok(r) => r, + Err(e) => return Err(format!("Network error: {e}")), + }; + + let status = resp.status(); + if status == reqwest::StatusCode::UNAUTHORIZED || status == reqwest::StatusCode::FORBIDDEN { + return Ok(Fetched::Failed(UsageResult::failure(format!( + "Authentication failed (HTTP {status})" + )))); + } + if !status.is_success() { + let body = resp.text().await.unwrap_or_default(); + return Ok(Fetched::Failed(UsageResult::failure(format!( + "API error (HTTP {status}): {body}" + )))); + } + + let raw = match resp.bytes().await { + Ok(b) => b, + Err(e) => return Err(format!("Failed to read response: {e}")), + }; + match serde_json::from_slice(&raw) { + Ok(v) => Ok(Fetched::Body(v)), + Err(e) => Ok(Fetched::Failed(UsageResult::failure(format!( + "Failed to parse response: {e}" + )))), + } +} + +/// 解析 JSON 字段为 f64,兼容数字和字符串格式。 +pub(crate) fn parse_f64_field(obj: &serde_json::Value, field: &str) -> Option { + obj.get(field).and_then(|v| { + v.as_f64() + .or_else(|| v.as_str().and_then(|s| s.parse().ok())) + }) +} + +// ── DeepSeek ──────────────────────────────────────────────── +// GET https://api.deepseek.com/user/balance +// Response: { balance_infos: [{ currency, total_balance, ... }], is_available } + +pub async fn query_deepseek(api_key: &str) -> Result { + match get_json("https://api.deepseek.com/user/balance", api_key, AuthStyle::Bearer).await? { + Fetched::Body(body) => Ok(UsageResult::ok(parse_deepseek(&body))), + Fetched::Failed(err) => Ok(err), + } +} + +fn parse_deepseek(body: &serde_json::Value) -> Vec { + let is_available = body + .get("is_available") + .and_then(|v| v.as_bool()) + .unwrap_or(true); + let mut data = Vec::new(); + + if let Some(infos) = body.get("balance_infos").and_then(|v| v.as_array()) { + for info in infos { + let currency = info + .get("currency") + .and_then(|v| v.as_str()) + .unwrap_or("CNY"); + data.push(UsageData { + plan_name: Some(currency.to_string()), + remaining: parse_f64_field(info, "total_balance"), + is_valid: Some(is_available), + unit: Some(currency.to_string()), + ..Default::default() + }); + } + } + data +} + +// ── StepFun ───────────────────────────────────────────────── +// GET https://api.stepfun.com/v1/accounts +// Response: { object, type, balance, total_cash_balance, total_voucher_balance } + +pub async fn query_stepfun(api_key: &str) -> Result { + match get_json("https://api.stepfun.com/v1/accounts", api_key, AuthStyle::Bearer).await? { + Fetched::Body(body) => Ok(UsageResult::ok(parse_stepfun(&body))), + Fetched::Failed(err) => Ok(err), + } +} + +fn parse_stepfun(body: &serde_json::Value) -> Vec { + vec![UsageData { + plan_name: Some("StepFun".to_string()), + remaining: Some(parse_f64_field(body, "balance").unwrap_or(0.0)), + unit: Some("CNY".to_string()), + is_valid: Some(true), + ..Default::default() + }] +} + +// ── SiliconFlow ───────────────────────────────────────────── +// GET https://api.siliconflow.cn/v1/user/info (.cn;海外站 .com 单位 USD) +// Response: { code, data: { balance, chargeBalance, totalBalance, status } } + +pub async fn query_siliconflow(api_key: &str, is_cn: bool) -> Result { + let domain = if is_cn { + "api.siliconflow.cn" + } else { + "api.siliconflow.com" + }; + let url = format!("https://{domain}/v1/user/info"); + match get_json(&url, api_key, AuthStyle::Bearer).await? { + Fetched::Body(body) => Ok(match parse_siliconflow(&body, is_cn) { + Ok(data) => UsageResult::ok(data), + Err(err) => err, + }), + Fetched::Failed(err) => Ok(err), + } +} + +fn parse_siliconflow(body: &serde_json::Value, is_cn: bool) -> Result, UsageResult> { + let data = match body.get("data") { + Some(d) => d, + None => { + return Err(UsageResult::failure( + "Missing 'data' field in response".to_string(), + )) + } + }; + let (plan_name, unit) = if is_cn { + ("SiliconFlow", "CNY") + } else { + ("SiliconFlow (EN)", "USD") + }; + Ok(vec![UsageData { + plan_name: Some(plan_name.to_string()), + remaining: Some(parse_f64_field(data, "totalBalance").unwrap_or(0.0)), + unit: Some(unit.to_string()), + is_valid: Some(true), + ..Default::default() + }]) +} + +// ── OpenRouter ────────────────────────────────────────────── +// GET https://openrouter.ai/api/v1/credits +// Response: { data: { total_credits, total_usage } } + +pub async fn query_openrouter(api_key: &str) -> Result { + match get_json( + "https://openrouter.ai/api/v1/credits", + api_key, + AuthStyle::Bearer, + ) + .await? + { + Fetched::Body(body) => Ok(UsageResult::ok(parse_openrouter(&body))), + Fetched::Failed(err) => Ok(err), + } +} + +fn parse_openrouter(body: &serde_json::Value) -> Vec { + let data = body.get("data").unwrap_or(body); + let total_credits = parse_f64_field(data, "total_credits").unwrap_or(0.0); + let total_usage = parse_f64_field(data, "total_usage").unwrap_or(0.0); + let remaining = total_credits - total_usage; + + vec![UsageData { + plan_name: Some("OpenRouter".to_string()), + remaining: Some(remaining), + total: Some(total_credits), + used: Some(total_usage), + unit: Some("USD".to_string()), + is_valid: Some(remaining > 0.0), + ..Default::default() + }] +} + +// ── Novita AI ─────────────────────────────────────────────── +// GET https://api.novita.ai/v3/user/balance +// Response: { availableBalance, ... };金额单位 0.0001 USD,需 /10000。 + +pub async fn query_novita(api_key: &str) -> Result { + match get_json( + "https://api.novita.ai/v3/user/balance", + api_key, + AuthStyle::Bearer, + ) + .await? + { + Fetched::Body(body) => Ok(UsageResult::ok(parse_novita(&body))), + Fetched::Failed(err) => Ok(err), + } +} + +fn parse_novita(body: &serde_json::Value) -> Vec { + let available = parse_f64_field(body, "availableBalance").unwrap_or(0.0) / 10000.0; + vec![UsageData { + plan_name: Some("Novita AI".to_string()), + remaining: Some(available), + unit: Some("USD".to_string()), + is_valid: Some(available > 0.0), + ..Default::default() + }] +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn deepseek_maps_balance_infos() { + let body = json!({ + "is_available": true, + "balance_infos": [ + { "currency": "CNY", "total_balance": "12.34" }, + { "currency": "USD", "total_balance": 5.0 } + ] + }); + let data = parse_deepseek(&body); + assert_eq!(data.len(), 2); + assert_eq!(data[0].plan_name.as_deref(), Some("CNY")); + assert_eq!(data[0].remaining, Some(12.34)); + assert_eq!(data[0].unit.as_deref(), Some("CNY")); + assert_eq!(data[0].is_valid, Some(true)); + assert_eq!(data[1].remaining, Some(5.0)); + } + + #[test] + fn stepfun_reads_balance() { + let body = json!({ "balance": 88.5 }); + let data = parse_stepfun(&body); + assert_eq!(data[0].remaining, Some(88.5)); + assert_eq!(data[0].unit.as_deref(), Some("CNY")); + } + + #[test] + fn siliconflow_missing_data_is_deterministic_failure() { + let body = json!({ "code": 500 }); + let err = parse_siliconflow(&body, true).unwrap_err(); + assert!(!err.success); + assert!(err.error.unwrap().contains("Missing 'data'")); + } + + #[test] + fn siliconflow_cn_and_en_units() { + let body = json!({ "data": { "totalBalance": "42.0" } }); + let cn = parse_siliconflow(&body, true).unwrap(); + let en = parse_siliconflow(&body, false).unwrap(); + assert_eq!(cn[0].unit.as_deref(), Some("CNY")); + assert_eq!(en[0].unit.as_deref(), Some("USD")); + assert_eq!(cn[0].remaining, Some(42.0)); + } + + #[test] + fn openrouter_computes_remaining_credits() { + let body = json!({ "data": { "total_credits": 20.0, "total_usage": 7.5 } }); + let data = parse_openrouter(&body); + assert_eq!(data[0].remaining, Some(12.5)); + assert_eq!(data[0].total, Some(20.0)); + assert_eq!(data[0].used, Some(7.5)); + assert_eq!(data[0].is_valid, Some(true)); + } + + #[test] + fn novita_converts_ten_thousandth_usd() { + let body = json!({ "availableBalance": 123400 }); + let data = parse_novita(&body); + assert_eq!(data[0].remaining, Some(12.34)); + assert_eq!(data[0].unit.as_deref(), Some("USD")); + + let zero = parse_novita(&json!({ "availableBalance": 0 })); + assert_eq!(zero[0].is_valid, Some(false)); + } +} diff --git a/src-tauri/src/services/coding_plan.rs b/src-tauri/src/services/coding_plan.rs new file mode 100644 index 0000000..67f6418 --- /dev/null +++ b/src-tauri/src/services/coding_plan.rs @@ -0,0 +1,414 @@ +// Adapted from cc-switch (MIT, © Jason Young) +// https://github.com/farion1231/cc-switch + +//! Token Plan 套餐额度查询服务 +//! +//! 支持 Kimi For Coding、智谱 GLM、MiniMax 的套餐额度查询。 +//! cc-switch 的 SubscriptionQuota/tiers 结构在此展平为 `Vec`: +//! 每个窗口(tier)一条 UsageData,`plan_name` = tier 名("five_hour" / +//! "weekly_limit"),`used` = 已用百分比(0-100),`total` = 100, +//! `remaining` = 剩余百分比,`resets_at` 为 ISO 8601 字符串。 +//! +//! 错误通道语义与 balance.rs 一致(Err = 瞬时,Ok(success:false) = 确定性)。 + +use super::balance::{get_json, AuthStyle, Fetched}; +use super::usage_types::{UsageData, UsageResult}; + +const TIER_FIVE_HOUR: &str = "five_hour"; +const TIER_WEEKLY_LIMIT: &str = "weekly_limit"; + +/// 套餐条目的统一构造:按百分比表示用量。 +fn percent_tier(name: &str, used_percent: f64, resets_at: Option) -> UsageData { + UsageData { + plan_name: Some(name.to_string()), + remaining: Some((100.0 - used_percent).max(0.0)), + total: Some(100.0), + used: Some(used_percent), + unit: Some("%".to_string()), + is_valid: Some(true), + resets_at, + } +} + +fn millis_to_iso8601(ms: i64) -> Option { + let secs = ms / 1000; + let nsecs = ((ms % 1000) * 1_000_000) as u32; + chrono::DateTime::from_timestamp(secs, nsecs).map(|dt| dt.to_rfc3339()) +} + +/// 从 JSON 值提取重置时间,兼容字符串和数字格式: +/// - 字符串:直接返回(视为 ISO 8601) +/// - 数字:自动判断秒/毫秒并转为 ISO 8601;0/负值视为无重置时间 +fn extract_reset_time(value: &serde_json::Value) -> Option { + if let Some(s) = value.as_str() { + return Some(s.to_string()); + } + if let Some(n) = value.as_i64() { + if n <= 0 { + return None; + } + // 秒级时间戳 < 1e12,毫秒 >= 1e12 + let ms = if n < 1_000_000_000_000 { n * 1000 } else { n }; + return millis_to_iso8601(ms); + } + None +} + +/// 解析 JSON 值为 f64,兼容数字和字符串格式(如 `100` 和 `"100"`) +fn parse_f64(value: &serde_json::Value) -> Option { + value + .as_f64() + .or_else(|| value.as_str().and_then(|s| s.parse().ok())) +} + +// ── Kimi For Coding ───────────────────────────────────────── +// GET https://api.kimi.com/coding/v1/usages +// Response: { limits: [{ detail: { limit, remaining, resetTime } }], +// usage: { limit, remaining, resetTime } } + +pub async fn query_kimi_coding(api_key: &str) -> Result { + match get_json( + "https://api.kimi.com/coding/v1/usages", + api_key, + AuthStyle::Bearer, + ) + .await? + { + Fetched::Body(body) => Ok(UsageResult::ok(parse_kimi_coding(&body))), + Fetched::Failed(err) => Ok(err), + } +} + +fn parse_kimi_coding(body: &serde_json::Value) -> Vec { + let mut tiers = Vec::new(); + + // 5 小时窗口限额(优先显示) + if let Some(limits) = body.get("limits").and_then(|v| v.as_array()) { + for limit_item in limits { + if let Some(detail) = limit_item.get("detail") { + tiers.push(kimi_limit_tier(TIER_FIVE_HOUR, detail)); + } + } + } + + // 总体用量(周限额) + if let Some(usage) = body.get("usage") { + tiers.push(kimi_limit_tier(TIER_WEEKLY_LIMIT, usage)); + } + + tiers +} + +fn kimi_limit_tier(name: &str, detail: &serde_json::Value) -> UsageData { + let limit = detail.get("limit").and_then(parse_f64).unwrap_or(1.0); + let remaining = detail.get("remaining").and_then(parse_f64).unwrap_or(0.0); + let resets_at = detail.get("resetTime").and_then(extract_reset_time); + + let used = (limit - remaining).max(0.0); + let utilization = if limit > 0.0 { + (used / limit) * 100.0 + } else { + 0.0 + }; + percent_tier(name, utilization, resets_at) +} + +// ── 智谱 GLM ──────────────────────────────────────────────── +// GET {open.bigmodel.cn | api.z.ai}/api/monitor/usage/quota/limit +// 注意:智谱鉴权不加 Bearer 前缀(cc-switch 实测行为,照搬)。 + +/// 智谱 TOKENS_LIMIT 条目按 `unit` 字段的显式窗口分类。 +/// 实测:`unit: 3` → 5 小时滚动窗口;`unit: 6` → 每周窗口。 +/// 缺失或不识别时走重置时间启发式兜底。 +fn parse_zhipu(body: &serde_json::Value) -> Result, UsageResult> { + // 业务级别错误 + if body.get("success").and_then(|v| v.as_bool()) == Some(false) { + let msg = body + .get("msg") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown error"); + return Err(UsageResult::failure(format!("API error: {msg}"))); + } + + let data = match body.get("data") { + Some(d) => d, + None => { + return Err(UsageResult::failure( + "Missing 'data' field in response".to_string(), + )) + } + }; + + type Entry = (Option, f64, Option); + let mut five_hour: Option = None; + let mut weekly: Option = None; + let mut unclassified: Vec = Vec::new(); + + if let Some(limits) = data.get("limits").and_then(|v| v.as_array()) { + for limit_item in limits { + let limit_type = limit_item + .get("type") + .and_then(|v| v.as_str()) + .unwrap_or(""); + if !limit_type.eq_ignore_ascii_case("TOKENS_LIMIT") { + continue; + } + let percentage = limit_item + .get("percentage") + .and_then(|v| v.as_f64()) + .unwrap_or(0.0); + let reset_ms = limit_item.get("nextResetTime").and_then(|v| v.as_i64()); + let reset_iso = reset_ms.and_then(millis_to_iso8601); + let entry = (reset_ms, percentage, reset_iso); + match limit_item.get("unit").and_then(|v| v.as_i64()) { + Some(3) if five_hour.is_none() => five_hour = Some(entry), + Some(6) if weekly.is_none() => weekly = Some(entry), + _ => unclassified.push(entry), + } + } + } + + // 兜底:无 nextResetTime 的优先归 five_hour,其余按 reset 升序填空槽。 + unclassified.sort_by_key(|(reset, _, _)| (reset.is_some(), reset.unwrap_or(i64::MIN))); + for entry in unclassified { + if five_hour.is_none() { + five_hour = Some(entry); + } else if weekly.is_none() { + weekly = Some(entry); + } + } + + let mut tiers = Vec::new(); + for (name, slot) in [(TIER_FIVE_HOUR, five_hour), (TIER_WEEKLY_LIMIT, weekly)] { + if let Some((_, percentage, resets_at)) = slot { + tiers.push(percent_tier(name, percentage, resets_at)); + } + } + Ok(tiers) +} + +/// 额度接口与推理接口同 host:bigmodel.cn 与 z.ai 共用同一后端与 JSON shape。 +fn zhipu_quota_base(base_url: &str) -> &'static str { + if base_url.to_lowercase().contains("bigmodel.cn") { + "https://open.bigmodel.cn" + } else { + "https://api.z.ai" + } +} + +pub async fn query_zhipu(base_url: &str, api_key: &str) -> Result { + let url = format!( + "{}/api/monitor/usage/quota/limit", + zhipu_quota_base(base_url) + ); + match get_json(&url, api_key, AuthStyle::Raw).await? { + Fetched::Body(body) => Ok(match parse_zhipu(&body) { + Ok(data) => UsageResult::ok(data), + Err(err) => err, + }), + Fetched::Failed(err) => Ok(err), + } +} + +// ── MiniMax ───────────────────────────────────────────────── +// GET https://api.minimaxi.com/v1/api/openplatform/coding_plan/remains +// (海外站 api.minimax.io) +// 接口直接给"剩余百分比",反转为已用百分比;只取 model_name == "general"。 + +pub async fn query_minimax(api_key: &str, is_cn: bool) -> Result { + let domain = if is_cn { + "api.minimaxi.com" + } else { + "api.minimax.io" + }; + let url = format!("https://{domain}/v1/api/openplatform/coding_plan/remains"); + match get_json(&url, api_key, AuthStyle::Bearer).await? { + Fetched::Body(body) => Ok(match parse_minimax(&body) { + Ok(data) => UsageResult::ok(data), + Err(err) => err, + }), + Fetched::Failed(err) => Ok(err), + } +} + +fn parse_minimax(body: &serde_json::Value) -> Result, UsageResult> { + // 业务级别错误 + if let Some(base_resp) = body.get("base_resp") { + let status_code = base_resp + .get("status_code") + .and_then(|v| v.as_i64()) + .unwrap_or(-1); + if status_code != 0 { + let msg = base_resp + .get("status_msg") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown error"); + return Err(UsageResult::failure(format!( + "API error (code {status_code}): {msg}" + ))); + } + } + + let mut tiers = Vec::new(); + + let Some(model_remains) = body.get("model_remains").and_then(|v| v.as_array()) else { + return Ok(tiers); + }; + // 只取 general(编程套餐),跳过 video 等其他模型 + let Some(item) = model_remains.iter().find(|item| { + item.get("model_name") + .and_then(|v| v.as_str()) + .map(|s| s == "general") + .unwrap_or(false) + }) else { + return Ok(tiers); + }; + + // 5h 桶:剩余百分比 → 已用百分比 + if let Some(remain_pct) = item + .get("current_interval_remaining_percent") + .and_then(|v| v.as_f64()) + { + let resets_at = item + .get("end_time") + .and_then(|v| v.as_i64()) + .and_then(millis_to_iso8601); + tiers.push(percent_tier(TIER_FIVE_HOUR, 100.0 - remain_pct, resets_at)); + } + + // 周桶:仅 status=1 时激活;status=3 等表示该套餐无周限额,跳过 + if item.get("current_weekly_status").and_then(|v| v.as_i64()) == Some(1) { + if let Some(remain_pct) = item + .get("current_weekly_remaining_percent") + .and_then(|v| v.as_f64()) + { + let resets_at = item + .get("weekly_end_time") + .and_then(|v| v.as_i64()) + .and_then(millis_to_iso8601); + tiers.push(percent_tier( + TIER_WEEKLY_LIMIT, + 100.0 - remain_pct, + resets_at, + )); + } + } + + Ok(tiers) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn kimi_coding_flattens_limits_and_usage() { + let body = json!({ + "limits": [ + { "detail": { "limit": 100, "remaining": 40, "resetTime": 1_754_000_000_000i64 } } + ], + "usage": { "limit": 1000, "remaining": 900, "resetTime": "2026-08-01T00:00:00Z" } + }); + let tiers = parse_kimi_coding(&body); + assert_eq!(tiers.len(), 2); + assert_eq!(tiers[0].plan_name.as_deref(), Some("five_hour")); + assert_eq!(tiers[0].used, Some(60.0)); + assert_eq!(tiers[0].total, Some(100.0)); + assert_eq!(tiers[0].remaining, Some(40.0)); + assert!(tiers[0].resets_at.is_some()); + assert_eq!(tiers[1].plan_name.as_deref(), Some("weekly_limit")); + assert_eq!(tiers[1].used, Some(10.0)); + assert_eq!( + tiers[1].resets_at.as_deref(), + Some("2026-08-01T00:00:00Z") + ); + } + + #[test] + fn kimi_coding_reset_time_seconds_vs_millis() { + // 秒级时间戳自动 ×1000 + let v = json!(1_754_000_000i64); + assert!(extract_reset_time(&v).is_some()); + // 0 / 负值视为无重置时间 + assert_eq!(extract_reset_time(&json!(0)), None); + assert_eq!(extract_reset_time(&json!(-1)), None); + } + + #[test] + fn zhipu_classifies_by_unit_field() { + let body = json!({ + "success": true, + "data": { + "limits": [ + { "type": "TOKENS_LIMIT", "percentage": 35.0, "unit": 3, "nextResetTime": 1_754_000_000_000i64 }, + { "type": "TOKENS_LIMIT", "percentage": 80.0, "unit": 6, "nextResetTime": 1_754_500_000_000i64 } + ] + } + }); + let tiers = parse_zhipu(&body).unwrap(); + assert_eq!(tiers.len(), 2); + assert_eq!(tiers[0].plan_name.as_deref(), Some("five_hour")); + assert_eq!(tiers[0].used, Some(35.0)); + assert_eq!(tiers[1].plan_name.as_deref(), Some("weekly_limit")); + assert_eq!(tiers[1].used, Some(80.0)); + } + + #[test] + fn zhipu_business_error_is_deterministic_failure() { + let body = json!({ "success": false, "msg": "token invalid" }); + let err = parse_zhipu(&body).unwrap_err(); + assert!(!err.success); + assert!(err.error.unwrap().contains("token invalid")); + } + + #[test] + fn minimax_picks_general_and_inverts_remaining() { + let body = json!({ + "base_resp": { "status_code": 0, "status_msg": "success" }, + "model_remains": [ + { "model_name": "video", "current_interval_remaining_percent": 50.0 }, + { + "model_name": "general", + "current_interval_remaining_percent": 70.0, + "end_time": 1_754_000_000_000i64, + "current_weekly_status": 1, + "current_weekly_remaining_percent": 95.0, + "weekly_end_time": 1_754_500_000_000i64 + } + ] + }); + let tiers = parse_minimax(&body).unwrap(); + assert_eq!(tiers.len(), 2); + assert_eq!(tiers[0].plan_name.as_deref(), Some("five_hour")); + assert_eq!(tiers[0].used, Some(30.0)); + assert_eq!(tiers[0].remaining, Some(70.0)); + assert_eq!(tiers[1].plan_name.as_deref(), Some("weekly_limit")); + assert_eq!(tiers[1].used, Some(5.0)); + } + + #[test] + fn minimax_skips_inactive_weekly_bucket() { + let body = json!({ + "model_remains": [ + { + "model_name": "general", + "current_interval_remaining_percent": 70.0, + "current_weekly_status": 3, + "current_weekly_remaining_percent": 100.0 + } + ] + }); + let tiers = parse_minimax(&body).unwrap(); + assert_eq!(tiers.len(), 1); + assert_eq!(tiers[0].plan_name.as_deref(), Some("five_hour")); + } + + #[test] + fn minimax_business_error_is_deterministic_failure() { + let body = json!({ "base_resp": { "status_code": 1002, "status_msg": "invalid key" } }); + let err = parse_minimax(&body).unwrap_err(); + assert!(!err.success); + assert!(err.error.unwrap().contains("invalid key")); + } +} diff --git a/src-tauri/src/services/mod.rs b/src-tauri/src/services/mod.rs new file mode 100644 index 0000000..9eca9ad --- /dev/null +++ b/src-tauri/src/services/mod.rs @@ -0,0 +1,182 @@ +// Adapted from cc-switch (MIT, © Jason Young) +// https://github.com/farion1231/cc-switch + +//! 供应商账单/用量查询统一入口。 +//! +//! - [`UsageKind`]:8 种查询类型,字符串形式与前端 / SQLite settings 约定一致 +//! (如 `"balance:deepseek"`、`"plan:kimi_coding"`)。 +//! - [`detect_provider`]:按 base_url host 子串匹配,旧用户无显式配置时自动识别。 +//! - [`query_kind`]:按 kind 路由到 balance / coding_plan 的具体实现。 + +pub mod balance; +pub mod coding_plan; +pub mod usage_types; + +pub use usage_types::{UsageData, UsageResult}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum UsageKind { + BalanceDeepseek, + BalanceSiliconflow, + BalanceOpenrouter, + BalanceStepfun, + BalanceNovita, + PlanKimiCoding, + PlanZhipu, + PlanMinimax, +} + +impl UsageKind { + /// 与前端 / SQLite settings(`usage_kinds:`)约定的字符串形式。 + pub fn as_str(&self) -> &'static str { + match self { + UsageKind::BalanceDeepseek => "balance:deepseek", + UsageKind::BalanceSiliconflow => "balance:siliconflow", + UsageKind::BalanceOpenrouter => "balance:openrouter", + UsageKind::BalanceStepfun => "balance:stepfun", + UsageKind::BalanceNovita => "balance:novita", + UsageKind::PlanKimiCoding => "plan:kimi_coding", + UsageKind::PlanZhipu => "plan:zhipu", + UsageKind::PlanMinimax => "plan:minimax", + } + } + + pub const ALL: [UsageKind; 8] = [ + UsageKind::BalanceDeepseek, + UsageKind::BalanceSiliconflow, + UsageKind::BalanceOpenrouter, + UsageKind::BalanceStepfun, + UsageKind::BalanceNovita, + UsageKind::PlanKimiCoding, + UsageKind::PlanZhipu, + UsageKind::PlanMinimax, + ]; +} + +impl std::str::FromStr for UsageKind { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "balance:deepseek" => UsageKind::BalanceDeepseek, + "balance:siliconflow" => UsageKind::BalanceSiliconflow, + "balance:openrouter" => UsageKind::BalanceOpenrouter, + "balance:stepfun" => UsageKind::BalanceStepfun, + "balance:novita" => UsageKind::BalanceNovita, + "plan:kimi_coding" => UsageKind::PlanKimiCoding, + "plan:zhipu" => UsageKind::PlanZhipu, + "plan:minimax" => UsageKind::PlanMinimax, + _ => return Err(()), + }) + } +} + +/// 按 base_url 子串匹配可支持的查询类型;无匹配返回空 vec。 +/// 一个 base_url 理论上可同时命中多种(套餐 + 余额),故返回 Vec。 +pub fn detect_provider(base_url: &str) -> Vec { + let url = base_url.to_lowercase(); + let mut kinds = Vec::new(); + if url.contains("api.deepseek.com") { + kinds.push(UsageKind::BalanceDeepseek); + } + if url.contains("api.siliconflow.cn") { + kinds.push(UsageKind::BalanceSiliconflow); + } + if url.contains("openrouter.ai") { + kinds.push(UsageKind::BalanceOpenrouter); + } + if url.contains("api.stepfun.com") { + kinds.push(UsageKind::BalanceStepfun); + } + if url.contains("api.novita.ai") { + kinds.push(UsageKind::BalanceNovita); + } + if url.contains("api.kimi.com") && url.contains("/coding") { + kinds.push(UsageKind::PlanKimiCoding); + } + if url.contains("open.bigmodel.cn") || url.contains("api.z.ai") { + kinds.push(UsageKind::PlanZhipu); + } + if url.contains("api.minimaxi.com") { + kinds.push(UsageKind::PlanMinimax); + } + kinds +} + +/// 按 kind 路由到对应查询实现。`base_url` 用于消歧同一家供应商的 +/// 国内/海外站(SiliconFlow .cn/.com、MiniMax .com/.io、智谱 bigmodel/z.ai)。 +pub async fn query_kind( + kind: UsageKind, + base_url: &str, + api_key: &str, +) -> Result { + let lower = base_url.to_lowercase(); + match kind { + UsageKind::BalanceDeepseek => balance::query_deepseek(api_key).await, + UsageKind::BalanceSiliconflow => { + balance::query_siliconflow(api_key, !lower.contains("siliconflow.com")).await + } + UsageKind::BalanceOpenrouter => balance::query_openrouter(api_key).await, + UsageKind::BalanceStepfun => balance::query_stepfun(api_key).await, + UsageKind::BalanceNovita => balance::query_novita(api_key).await, + UsageKind::PlanKimiCoding => coding_plan::query_kimi_coding(api_key).await, + UsageKind::PlanZhipu => coding_plan::query_zhipu(base_url, api_key).await, + UsageKind::PlanMinimax => { + coding_plan::query_minimax(api_key, !lower.contains("minimax.io")).await + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn detect_provider_maps_known_hosts() { + let cases: [(&str, UsageKind); 8] = [ + ("https://api.deepseek.com/v1", UsageKind::BalanceDeepseek), + ("https://api.siliconflow.cn/v1", UsageKind::BalanceSiliconflow), + ("https://openrouter.ai/api/v1", UsageKind::BalanceOpenrouter), + ("https://api.stepfun.com/v1", UsageKind::BalanceStepfun), + ("https://api.novita.ai/v3", UsageKind::BalanceNovita), + ("https://api.kimi.com/coding/v1", UsageKind::PlanKimiCoding), + ( + "https://open.bigmodel.cn/api/paas/v4", + UsageKind::PlanZhipu, + ), + ("https://api.minimaxi.com/v1", UsageKind::PlanMinimax), + ]; + for (url, expected) in cases { + assert_eq!( + detect_provider(url), + vec![expected], + "url: {url}" + ); + } + // z.ai 也命中智谱 + assert_eq!( + detect_provider("https://api.z.ai/api/paas/v4"), + vec![UsageKind::PlanZhipu] + ); + } + + #[test] + fn detect_provider_unknown_url_returns_empty() { + assert!(detect_provider("https://api.openai.com/v1").is_empty()); + assert!(detect_provider("https://example.com").is_empty()); + assert!(detect_provider("").is_empty()); + // api.kimi.com 但无 /coding 路径 → 不命中套餐查询 + assert!(detect_provider("https://api.kimi.com/v1").is_empty()); + } + + #[test] + fn usage_kind_string_roundtrip() { + use std::str::FromStr; + for kind in UsageKind::ALL { + let s = kind.as_str(); + assert_eq!(UsageKind::from_str(s), Ok(kind), "kind: {s}"); + } + assert!(UsageKind::from_str("balance:unknown").is_err()); + assert!(UsageKind::from_str("").is_err()); + } +} diff --git a/src-tauri/src/services/usage_types.rs b/src-tauri/src/services/usage_types.rs new file mode 100644 index 0000000..fa21462 --- /dev/null +++ b/src-tauri/src/services/usage_types.rs @@ -0,0 +1,76 @@ +// Adapted from cc-switch (MIT, © Jason Young) +// https://github.com/farion1231/cc-switch + +//! Shared return contract for provider billing/usage queries. +//! +//! MUST stay camelCase: the frontend reads `planName` / `resetsAt` / +//! `isValid` — snake_case serialization would silently misalign every field. + +use serde::Serialize; + +#[derive(Serialize, Clone, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct UsageData { + pub plan_name: Option, + pub remaining: Option, + pub total: Option, + pub used: Option, + pub unit: Option, + pub is_valid: Option, + pub resets_at: Option, +} + +#[derive(Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct UsageResult { + pub success: bool, + pub data: Option>, + pub error: Option, +} + +impl UsageResult { + pub fn ok(data: Vec) -> Self { + UsageResult { + success: true, + data: if data.is_empty() { None } else { Some(data) }, + error: None, + } + } + + pub fn failure(msg: String) -> Self { + UsageResult { + success: false, + data: None, + error: Some(msg), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn usage_result_serializes_camel_case() { + let result = UsageResult { + success: true, + data: Some(vec![UsageData { + plan_name: Some("five_hour".to_string()), + remaining: Some(65.0), + total: Some(100.0), + used: Some(35.0), + unit: Some("%".to_string()), + is_valid: Some(true), + resets_at: Some("2026-07-29T12:00:00+00:00".to_string()), + }]), + error: None, + }; + let json = serde_json::to_string(&result).unwrap(); + assert!(json.contains("\"planName\""), "json: {json}"); + assert!(json.contains("\"resetsAt\""), "json: {json}"); + assert!(json.contains("\"isValid\""), "json: {json}"); + assert!(json.contains("\"plan_name\"") == false, "json: {json}"); + assert!(json.contains("\"resets_at\"") == false, "json: {json}"); + assert!(json.contains("\"is_valid\"") == false, "json: {json}"); + } +} diff --git a/src-tauri/src/validators.rs b/src-tauri/src/validators.rs new file mode 100644 index 0000000..a0b22e4 --- /dev/null +++ b/src-tauri/src/validators.rs @@ -0,0 +1 @@ +//! Validation helpers for KimiSwitch configuration and command inputs. diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json new file mode 100644 index 0000000..39a6aa6 --- /dev/null +++ b/src-tauri/tauri.conf.json @@ -0,0 +1,43 @@ +{ + "productName": "Kimi Switch", + "version": "0.6.0", + "identifier": "com.kimiswitch.app", + "build": { + "beforeDevCommand": "npm run dev", + "beforeBuildCommand": "npm run build", + "devUrl": "http://localhost:1420", + "frontendDist": "../dist" + }, + "app": { + "windows": [ + { + "title": "Kimi Switch", + "width": 1200, + "height": 800, + "minWidth": 1000, + "minHeight": 700, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" + } + }, + "bundle": { + "active": true, + "targets": ["msi"], + "windows": { + "webviewInstallMode": { + "type": "downloadBootstrapper" + }, + "nsis": null + }, + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.ico" + ] + } +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..40f2a38 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,802 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; +import { invoke } from "@tauri-apps/api/core"; +import { getCurrentWindow } from "@tauri-apps/api/window"; +import { useConfig } from "./hooks/useConfig"; +import { useUpdateCheck } from "./hooks/useUpdateCheck"; +import { ProviderList } from "./components/ProviderList"; +import { ProviderEdit } from "./components/ProviderEdit"; +import { DashboardPage } from "./components/dashboard/DashboardPage"; +import { SessionsPage } from "./components/sessions/SessionsPage"; +import { SettingsModal } from "./components/SettingsModal"; +import { PresetPickerModal } from "./components/PresetPickerModal"; +import { useTranslation } from "./i18n"; +import { getDefaultMaxContextSize } from "./lib/model-defaults"; +import { getModelRef } from "./lib/models-dev"; +import { + presetToProviderAndModels, + type ProviderPreset, +} from "./config/providerPresets"; +import { validateProviders } from "./lib/validation"; +import type { Agent, Model, Provider } from "./types"; + +const AGENT_STORAGE_KEY = "kimi-switch-agent"; + +function getProviderDefaultModel(provider: Provider): string | null { + const raw = provider.raw_other as Record | undefined; + const value = raw?.default_model; + return typeof value === "string" ? value : null; +} + +function setProviderDefaultModel(provider: Provider, alias: string | null): Provider { + const raw = (provider.raw_other as Record | undefined) ?? {}; + if (alias) { + return { ...provider, raw_other: { ...raw, default_model: alias } }; + } + const { default_model: _, ...rest } = raw; + return { ...provider, raw_other: rest }; +} + +function findFirstModelForProvider(models: Record, providerName: string): string | null { + for (const [key, m] of Object.entries(models)) { + if (m.provider === providerName) { + return key; + } + } + return null; +} + +function getInitialAgent(): Agent { + try { + const stored = localStorage.getItem(AGENT_STORAGE_KEY) as Agent | null; + if (stored === "kimi_code") return stored; + } catch { + // ignore + } + return "kimi_code"; +} + +export default function App() { + const { t, lang, setLang } = useTranslation(); + const { updateInfo, checking, checkNow, lastChecked } = useUpdateCheck(); + const [agent] = useState(getInitialAgent); + const { + config, + dirty, + error, + loading, + refresh, + save, + updateConfig, + } = useConfig(agent); + + const [view, setView] = useState<"list" | "edit" | "dashboard" | "sessions">("list"); + const [editingProvider, setEditingProvider] = useState(""); + const [loadTimeout, setLoadTimeout] = useState(false); + const [switchMessage, setSwitchMessage] = useState(null); + const [showSettings, setShowSettings] = useState(false); + const [showPresetPicker, setShowPresetPicker] = useState(false); + // Provider names that have been added to the in-memory config but not + // yet committed via save(). Pressing "back" in the edit form for one of + // these drops it silently (no confirm); all other dirty navigation + // keeps the existing unsavedConfirm flow. + const [pendingNewProviders, setPendingNewProviders] = useState>( + () => new Set(), + ); + + + useEffect(() => { + if (!loading) { + setLoadTimeout(false); + return; + } + const timer = setTimeout(() => setLoadTimeout(true), 5000); + return () => clearTimeout(timer); + }, [loading]); + + // Update window title to reflect unsaved changes. + useEffect(() => { + const app = getCurrentWindow(); + const prefix = dirty ? "* " : ""; + app.setTitle(`${prefix}${t("appTitle")}`); + }, [dirty, t]); + + // Warn before closing the window when there are unsaved changes. + useEffect(() => { + const handler = (e: BeforeUnloadEvent) => { + if (dirty) { + e.preventDefault(); + e.returnValue = ""; + } + }; + window.addEventListener("beforeunload", handler); + return () => window.removeEventListener("beforeunload", handler); + }, [dirty]); + + useEffect(() => { + invoke("debug_log", { + message: `App mounted. agent=${agent} loading=${loading} config=${config ? Object.keys(config.providers).length + " providers" : "null"}`, + }).catch(() => {}); + }, [loading, config, agent]); + + const providers = useMemo( + () => (config ? Object.values(config.providers) : []), + [config] + ); + + // trySave calls validateProviders, which takes a library-style + // `(key: string) => string`; useTranslation's `t` is strictly typed to + // the project's i18n key union, so we relax it locally for the call. + const tGeneric = t as unknown as ( + key: string, + vars?: Record, + ) => string; + // Wraps `save` with a completeness check. Three flavours of caller: + // 1. Whole-config save (Ctrl+S, footer button, ProviderEdit onSave): + // no `target` → validate every enabled provider, show a confirm + // dialog listing the incomplete ones. + // 2. Switching a specific provider as active: `target` is the + // provider being switched to — only that one needs to be + // complete; sibling providers being merely listed in the config + // must not block the switch. + // 3. Programmatic auto-saves (duplicate) call `save` directly with + // no validation — duplicates inherit completeness from their + // source. + // Returns `true` when the config was actually persisted, `false` when + // the user cancelled the validation confirm (callers can react to this + // to roll back in-memory mutations made before the save). + const trySave = useCallback( + async (target?: string): Promise => { + if (!config) return false; + if (dirty) { + const issues = validateProviders(config, config.models, tGeneric, target); + if (issues.length > 0) { + const summary = issues + .map((i) => `• ${i.name}: ${i.reasons.join("; ")}`) + .join("\n"); + if (!confirm(t("saveValidationConfirm", { details: summary }))) { + return false; + } + } + } + await save(); + // Successful save: clear the "in-memory only" markers — every + // provider is now on disk. + setPendingNewProviders(new Set()); + return true; + }, + [config, dirty, save, t], + ); + + // Keyboard shortcuts: Ctrl+S save, Ctrl+R reload, Ctrl+O open config dir + useEffect(() => { + const handler = (e: KeyboardEvent) => { + if (!e.ctrlKey || e.metaKey) return; + switch (e.key) { + case "s": + case "S": + e.preventDefault(); + void trySave(); + break; + case "r": + case "R": + e.preventDefault(); + if (dirty && !confirm(t("unsavedConfirm"))) return; + refresh(); + break; + case "o": + case "O": + e.preventDefault(); + invoke("open_agent_config_dir", { agent }).catch((err) => + alert(err instanceof Error ? err.message : String(err)) + ); + break; + } + }; + window.addEventListener("keydown", handler); + return () => window.removeEventListener("keydown", handler); + }, [trySave, refresh, dirty, t, agent]); + + // "Add provider" opens the preset picker; the empty form is reachable via + // the picker's "+ custom config" entry (handleAddCustomProvider). + const handleAddProvider = () => { + if (!config) return; + setShowPresetPicker(true); + }; + + const handleAddCustomProvider = () => { + if (!config) return; + setShowPresetPicker(false); + const name = `provider-${providers.length + 1}`; + const defaultType = agent === "kimi_code" ? "kimi" : "openai"; + updateConfig((cfg) => ({ + ...cfg, + providers: { + ...cfg.providers, + [name]: { + name, + provider_type: defaultType, + base_url: null, + api_key: null, + env: {}, + note: null, + official_url: null, + managed: false, + enabled: true, + }, + }, + })); + // Mark as in-memory only — never persisted until the user explicitly + // saves a complete config. Pressing "back" in the edit form will + // silently drop this entry. + setPendingNewProviders((prev) => new Set([...prev, name])); + setEditingProvider(name); + setView("edit"); + }; + + const handleSelectPreset = async (preset: ProviderPreset) => { + if (!config) return; + setShowPresetPicker(false); + const { provider, models, defaultModel } = presetToProviderAndModels(preset, { + existingProviderNames: new Set(Object.keys(config.providers)), + existingModelAliases: new Set(Object.keys(config.models)), + }); + updateConfig((cfg) => { + const providers = { ...cfg.providers, [provider.name]: provider }; + const updatedModels = { ...cfg.models }; + for (const m of models) { + updatedModels[m.alias] = m; + } + return { + ...cfg, + providers, + models: updatedModels, + default_model: defaultModel || cfg.default_model, + }; + }); + // Do NOT auto-save: a freshly-picked preset is intentionally + // incomplete (no api_key yet). The user lands in the edit form + // next; if they fill the key and save, validation passes and the + // config lands on disk. If they back out without saving, the + // in-memory additions are discarded on the next refresh — config.toml + // never receives a half-configured provider. + setPendingNewProviders((prev) => new Set([...prev, provider.name])); + setEditingProvider(provider.name); + setView("edit"); + }; + + const handleUpdateProvider = (provider: Provider) => { + updateConfig((cfg) => { + const providers = { ...cfg.providers }; + const oldEntry = Object.entries(providers).find( + ([, p]) => p.name === editingProvider + ); + if (oldEntry && oldEntry[0] !== provider.name) { + delete providers[oldEntry[0]]; + const models = { ...cfg.models }; + for (const key of Object.keys(models)) { + if (models[key].provider === editingProvider) { + models[key] = { ...models[key], provider: provider.name }; + } + } + providers[provider.name] = provider; + setEditingProvider(provider.name); + return { ...cfg, providers, models }; + } + providers[provider.name] = provider; + return { ...cfg, providers }; + }); + }; + + const handleDeleteProvider = (name: string) => { + if (!confirm(t("deleteProviderConfirm", { name }))) return; + updateConfig((cfg) => { + const providers = { ...cfg.providers }; + delete providers[name]; + const models = { ...cfg.models }; + for (const key of Object.keys(models)) { + if (models[key].provider === name) { + delete models[key]; + } + } + return { ...cfg, providers, models }; + }); + if (editingProvider === name) { + setEditingProvider(""); + setView("list"); + } + }; + + const handleDuplicateProvider = async (name: string) => { + updateConfig((cfg) => { + const src = cfg.providers[name]; + if (!src) return cfg; + let newName = `${name}-copy`; + let n = 2; + while (cfg.providers[newName]) { + newName = `${name}-copy-${n}`; + n++; + } + // Clone the provider (deactivated, clear its remembered default model + // since the model aliases will be re-keyed to the new name below). + const copied = setProviderDefaultModel( + { ...src, name: newName, active: false }, + null + ); + const providers = { ...cfg.providers, [newName]: copied }; + // Re-key this provider's models to the new provider name so the copy + // has its own independent model set. + const models = { ...cfg.models }; + for (const [alias, m] of Object.entries(cfg.models)) { + if (m.provider === name) { + // The model belongs to this provider by `m.provider === name`. To + // re-key it under the new provider, we want a `newName/...` + // alias. The original code assumed `alias` is exactly + // `${name}/${modelId}` and used `alias.slice(name.length)`; that + // breaks for legacy / non-standard aliases (e.g. `kimi-k3` from + // pre-v0.6 data) which would produce `newName-k3` — missing the + // `/` separator and pointing at the wrong model. Use an explicit + // prefix check and fall back to a full re-prefix. + const prefix = `${name}/`; + const newAlias = alias.startsWith(prefix) + ? newName + alias.slice(name.length) + : `${newName}/${alias}`; + models[newAlias] = { ...m, alias: newAlias, provider: newName }; + } + } + return { ...cfg, providers, models }; + }); + await save(); + setSwitchMessage(t("copiedProvider", { name: `${name}-copy` })); + setTimeout(() => setSwitchMessage(null), 3000); + }; + + const handleSetDefaultModel = (alias: string) => { + updateConfig((cfg) => { + const model = cfg.models[alias]; + if (!model) return cfg; + const provider = cfg.providers[model.provider]; + if (!provider) return cfg; + const providers = { + ...cfg.providers, + [provider.name]: setProviderDefaultModel(provider, alias), + }; + return { ...cfg, providers, default_model: alias }; + }); + }; + + const handleSwitchProvider = async (name: string) => { + updateConfig((cfg) => { + const target = cfg.providers[name]; + if (!target) return cfg; + + // Find the currently active provider so we can remember its default + // model before switching away. + let activeProviderName: string | null = null; + for (const [key, p] of Object.entries(cfg.providers)) { + if (p.active) { + activeProviderName = key; + break; + } + } + + // Rebuild providers with the selected one moved to the front so it is + // visually prioritised. All others are deactivated. + const providers: Record = {}; + providers[name] = { ...target, active: true }; + + // Remember the old active provider's current default model (if it + // belongs to that provider) so switching back later restores the user's + // choice. + if (activeProviderName && activeProviderName !== name && cfg.default_model) { + const oldActive = cfg.providers[activeProviderName]; + if (oldActive && cfg.models[cfg.default_model]?.provider === activeProviderName) { + providers[activeProviderName] = setProviderDefaultModel( + { ...oldActive, active: false }, + cfg.default_model + ); + } + } + + // Add remaining providers (skip selected and old-active if already added). + for (const [key, p] of Object.entries(cfg.providers)) { + if (key === name) continue; + if (providers[key]) continue; + providers[key] = { ...p, active: false }; + } + + // Prefer the target provider's remembered default model; fall back to + // its first model when there is no saved preference or it is invalid. + let default_model = getProviderDefaultModel(target); + if (!default_model || cfg.models[default_model]?.provider !== name) { + default_model = findFirstModelForProvider(cfg.models, name); + } + + return { ...cfg, providers, default_model }; + }); + + // Persist the full config to Kimi Switch's SQLite and activate the selected provider. + const saved = await trySave(name); + if (!saved) { + // Validation was cancelled: undo the in-memory switch by reloading + // the on-disk state, and skip the activation + /reload nudge. + await refresh(); + return; + } + await invoke("activate_agent_config_command", { agent }); + + // /reload is an interactive Kimi Code TUI command with no CLI equivalent, + // so we copy it to the clipboard as a convenience. + try { + await navigator.clipboard.writeText("/reload"); + setSwitchMessage(t("reloadCopiedHint")); + setTimeout(() => setSwitchMessage(null), 4000); + } catch { + // Clipboard may be unavailable; ignore silently. + } + }; + + const handleEditBack = async () => { + const target = editingProvider; + if (target && pendingNewProviders.has(target)) { + // This provider was added in-memory (via preset or "+ custom config") + // but never committed. Drop it silently — no confirm — and reload + // from disk so the list reflects the on-disk truth. + setPendingNewProviders((prev) => { + const next = new Set(prev); + next.delete(target); + return next; + }); + await refresh(); + } else if (dirty) { + // Real edits to a previously-saved provider — keep the existing + // unsaved-changes confirm so the user doesn't lose work by accident. + if (!confirm(t("unsavedConfirm"))) return; + await refresh(); + } + setView("list"); + }; + + const handleApplyProviderJson = (provider: Provider, models: Model[]) => { + updateConfig((cfg) => { + const providers = { ...cfg.providers }; + const oldName = editingProvider; + if (oldName && oldName !== provider.name) { + delete providers[oldName]; + } + providers[provider.name] = provider; + + const updatedModels = { ...cfg.models }; + // Remove existing models for this provider. + for (const key of Object.keys(updatedModels)) { + if (updatedModels[key].provider === oldName) { + delete updatedModels[key]; + } + } + // Add updated models, ensuring aliases are unique. + for (const m of models) { + let alias = m.alias; + let n = 1; + while (alias in updatedModels) { + alias = `${m.alias}-${n}`; + n++; + } + updatedModels[alias] = { + ...m, + alias, + provider: provider.name, + max_context_size: + m.max_context_size ?? + getModelRef(m.model)?.context ?? + getDefaultMaxContextSize(m.model), + }; + } + + let default_model = cfg.default_model; + if (default_model && !(default_model in updatedModels)) { + default_model = null; + } + + // Remember this provider's default model preference so it survives + // provider switches. + const updatedProvider = providers[provider.name]; + if (updatedProvider && default_model && updatedModels[default_model]?.provider === provider.name) { + providers[provider.name] = setProviderDefaultModel(updatedProvider, default_model); + } + + return { ...cfg, providers, models: updatedModels, default_model }; + }); + if (provider.name !== editingProvider) { + setEditingProvider(provider.name); + } + }; + + if (loading || !config) { + return ( +

      +
      {t("loading")}
      + {loadTimeout && ( +
      {t("loadTimeout")}
      + )} + {error && ( +
      +
      {t("loadFailed")}
      +
      {error}
      + +
      + )} +
      + ); + } + + const currentProvider = config.providers[editingProvider]; + + return ( +
      +
      +
      + + + +
      +
      + {/* Language */} + + {/* Settings gear */} + +
      +
      + + {error && ( +
      + {error} +
      + )} + + {switchMessage && ( +
      + {switchMessage} +
      + )} + +
      + {view === "dashboard" ? ( + + ) : view === "sessions" ? ( + + ) : view === "list" ? ( + { + setEditingProvider(name); + setView("edit"); + }} + onDelete={handleDeleteProvider} + onDuplicate={handleDuplicateProvider} + onAdd={handleAddProvider} + onSwitchProvider={handleSwitchProvider} + agent={agent} + /> + ) : currentProvider ? ( + m.provider === currentProvider.name + )} + defaultModel={config.default_model} + rawOther={config.raw_other} + onRawOtherChange={(nextRawOther) => + updateConfig((cfg) => ({ ...cfg, raw_other: nextRawOther })) + } + onBack={handleEditBack} + onChange={handleUpdateProvider} + onDelete={() => handleDeleteProvider(currentProvider.name)} + onModelChange={(model) => { + updateConfig((cfg) => { + const models = { ...cfg.models }; + const existingKeys = Object.keys(models).filter( + (k) => models[k].provider === currentProvider.name + ); + const oldKey = existingKeys.find((k) => + model.alias === k ? true : models[k].alias === model.alias + ); + if (oldKey && oldKey !== model.alias) { + delete models[oldKey]; + } + models[model.alias] = model; + let default_model = cfg.default_model; + if (default_model === oldKey) default_model = model.alias; + return { ...cfg, models, default_model }; + }); + }} + onModelDelete={(alias) => { + updateConfig((cfg) => { + const models = { ...cfg.models }; + delete models[alias]; + return { + ...cfg, + models, + default_model: + cfg.default_model === alias ? null : cfg.default_model, + }; + }); + }} + onModelAdd={() => { + const safeProvider = currentProvider.name.replace(/\//g, "-"); + const alias = `${safeProvider}/新模型`; + updateConfig((cfg) => ({ + ...cfg, + models: { + ...cfg.models, + [alias]: { + alias, + provider: currentProvider.name, + model: "", + max_context_size: getDefaultMaxContextSize(alias), + display_name: null, + supports_1m: false, + capabilities: agent === "kimi_code" ? ["thinking"] : [], + }, + }, + })); + }} + onBulkAdd={(models) => { + updateConfig((cfg) => { + const updated = { ...cfg.models }; + for (const m of models) { + let alias = m.alias; + let n = 1; + while (alias in updated) { + alias = `${m.alias}-${n}`; + n++; + } + updated[alias] = { ...m, alias }; + } + return { ...cfg, models: updated }; + }); + }} + onSetDefault={handleSetDefaultModel} + onApplyJson={handleApplyProviderJson} + onSave={trySave} + /> + ) : ( +
      +
      {t("providerNotFound")}
      + +
      + )} +
      + + {view !== "dashboard" && view !== "sessions" && ( +
      +
      + {dirty && ( + ● {t("unsavedChanges")} + )} +
      +
      + + + +
      +
      + )} + + setShowSettings(false)} + updateInfo={updateInfo} + checking={checking} + onCheckUpdate={checkNow} + lastChecked={lastChecked} + /> + + setShowPresetPicker(false)} + onSelect={handleSelectPreset} + onCustom={handleAddCustomProvider} + /> +
      + ); +} diff --git a/src/components/AgentSettingsPanel.tsx b/src/components/AgentSettingsPanel.tsx new file mode 100644 index 0000000..26acd57 --- /dev/null +++ b/src/components/AgentSettingsPanel.tsx @@ -0,0 +1,376 @@ +import type { ReactNode } from "react"; +import { useTranslation } from "../i18n"; +import type { TranslationKey } from "../i18n/zh"; +import { getAgentSettings, setAgentSettings } from "../lib/agent-settings"; +import type { AgentSettings, Hook, PermissionRule } from "../types"; + +interface AgentSettingsPanelProps { + rawOther: unknown; + onChange: (nextRawOther: unknown) => void; +} + +const THINKING_LEVELS = ["low", "medium", "high", "max"] as const; +const THINKING_LABELS: Record<(typeof THINKING_LEVELS)[number], TranslationKey> = { + low: "thinkingLow", + medium: "thinkingMedium", + high: "thinkingHigh", + max: "thinkingMax", +}; + +const PERMISSION_DECISIONS = ["allow", "deny", "ask"] as const; +const PERMISSION_LABELS: Record<(typeof PERMISSION_DECISIONS)[number], TranslationKey> = { + allow: "permissionAllow", + deny: "permissionDeny", + ask: "permissionAsk", +}; + +const COMMON_EVENTS = ["PreToolUse", "PostToolUse"] as const; + +export function AgentSettingsPanel({ rawOther, onChange }: AgentSettingsPanelProps) { + const { t } = useTranslation(); + const settings = getAgentSettings(rawOther); + + const update = (patch: Partial) => { + onChange(setAgentSettings(rawOther, patch)); + }; + + const updateThinking = (patch: Partial) => { + update({ thinking: { ...settings.thinking, ...patch } }); + }; + + const updateLoopControl = (patch: Partial) => { + update({ loop_control: { ...settings.loop_control, ...patch } }); + }; + + const updateBackground = (patch: Partial) => { + update({ background: { ...settings.background, ...patch } }); + }; + + const setRules = (rules: PermissionRule[]) => { + update({ permission: { rules } }); + }; + + const setHooks = (hooks: Hook[]) => { + update({ hooks }); + }; + + const thinkingEnabled = settings.thinking?.enabled ?? true; + + return ( +
      +

      {t("agentSettings")}

      + + + updateThinking({ enabled: checked })} + /> +
      + {t("thinkingLevel")} + ({ + key: lvl, + label: t(THINKING_LABELS[lvl]), + }))} + value={settings.thinking?.effort ?? "medium"} + onChange={(effort) => + updateThinking({ effort: effort as NonNullable["effort"] }) + } + disabled={!thinkingEnabled} + /> +
      + updateThinking({ keep: checked ? "all" : false })} + /> +

      {t("thinkingContextHint")}

      +
      + + + updateLoopControl({ max_retries_per_step: v })} + /> + updateLoopControl({ reserved_context_size: v })} + /> + + + + updateBackground({ max_running_tasks: v })} + /> + updateBackground({ keep_alive_on_exit: checked })} + /> + + + +
      + {(settings.permission?.rules ?? []).map((rule, idx) => ( +
      + + { + const rules = [...(settings.permission?.rules ?? [])]; + rules[idx] = { ...rule, pattern: e.target.value }; + setRules(rules); + }} + /> + +
      + ))} +
      +
      + + +
      +
      + + +
      + {(settings.hooks ?? []).map((hook, idx) => ( +
      + { + const hooks = [...(settings.hooks ?? [])]; + hooks[idx] = { ...hook, event: e.target.value }; + setHooks(hooks); + }} + /> + + {COMMON_EVENTS.map((e) => ( + + { + const hooks = [...(settings.hooks ?? [])]; + hooks[idx] = { ...hook, matcher: e.target.value }; + setHooks(hooks); + }} + /> + { + const hooks = [...(settings.hooks ?? [])]; + hooks[idx] = { ...hook, command: e.target.value }; + setHooks(hooks); + }} + /> + { + const hooks = [...(settings.hooks ?? [])]; + hooks[idx] = { + ...hook, + timeout: e.target.value === "" ? undefined : Number(e.target.value), + }; + setHooks(hooks); + }} + /> + +
      + ))} +
      + +
      +
      + ); +} + +function Card({ title, children }: { title: string; children: ReactNode }) { + return ( +
      +

      {title}

      + {children} +
      + ); +} + +function Checkbox({ + label, + checked, + disabled, + onChange, +}: { + label: string; + checked: boolean; + disabled?: boolean; + onChange: (checked: boolean) => void; +}) { + return ( + + ); +} + +function NumberField({ + label, + value, + onChange, +}: { + label: string; + value?: number; + onChange: (value: number | undefined) => void; +}) { + return ( + + ); +} + +function Segmented({ + options, + value, + onChange, + disabled, +}: { + options: { key: string; label: string }[]; + value: string; + onChange: (value: string) => void; + disabled?: boolean; +}) { + return ( +
      + {options.map((opt) => ( + + ))} +
      + ); +} diff --git a/src/components/IconPicker.tsx b/src/components/IconPicker.tsx new file mode 100644 index 0000000..c3397a2 --- /dev/null +++ b/src/components/IconPicker.tsx @@ -0,0 +1,70 @@ +import { useMemo, useState } from "react"; +import { useTranslation } from "../i18n"; +import { ProviderIcon } from "./ProviderIcon"; +import { iconList } from "../icons/extracted"; +import { searchIcons, getIconMetadata } from "../icons/extracted/metadata"; + +interface IconPickerProps { + value?: string | null; + onValueChange: (icon: string) => void; +} + +export function IconPicker({ value, onValueChange }: IconPickerProps) { + const { t } = useTranslation(); + const [searchQuery, setSearchQuery] = useState(""); + + const filteredIcons = useMemo(() => { + if (!searchQuery.trim()) return iconList; + return searchIcons(searchQuery); + }, [searchQuery]); + + return ( +
      +
      + + setSearchQuery(e.target.value)} + /> +
      + +
      +
      + {filteredIcons.map((iconName) => { + const meta = getIconMetadata(iconName); + const isSelected = value === iconName; + return ( + + ); + })} +
      + + {filteredIcons.length === 0 && ( +
      + {t("iconPickerNoResults")} +
      + )} +
      +
      + ); +} diff --git a/src/components/PresetPickerModal.tsx b/src/components/PresetPickerModal.tsx new file mode 100644 index 0000000..cbaef09 --- /dev/null +++ b/src/components/PresetPickerModal.tsx @@ -0,0 +1,201 @@ +import { useEffect, useMemo, useState } from "react"; +import { createPortal } from "react-dom"; +import { useTranslation } from "../i18n"; +import type { TranslationKey } from "../i18n/zh"; +import { providerPresets, type PresetCategory, type ProviderPreset } from "../config/providerPresets"; +import { ProviderIcon } from "./ProviderIcon"; + +interface PresetPickerModalProps { + open: boolean; + onClose: () => void; + onSelect: (preset: ProviderPreset) => void; + onCustom: () => void; +} + +const CATEGORY_BADGE: Record, string> = { + official: "bg-blue-100 text-blue-700 dark:bg-blue-500/15 dark:text-blue-400", + cn_official: "bg-green-100 text-green-700 dark:bg-green-500/15 dark:text-green-400", + third_party: "bg-gray-200 text-gray-600 dark:bg-gray-500/15 dark:text-gray-400", + aggregator: "bg-purple-100 text-purple-700 dark:bg-purple-500/15 dark:text-purple-400", +}; + +const CATEGORY_LABEL: Record, TranslationKey> = { + official: "presetCategoryOfficial", + cn_official: "presetCategoryCnOfficial", + third_party: "presetCategoryThirdParty", + aggregator: "presetCategoryAggregator", +}; + +type SortMode = "original" | "alpha"; + +export function PresetPickerModal({ open, onClose, onSelect, onCustom }: PresetPickerModalProps) { + const { t } = useTranslation(); + const [query, setQuery] = useState(""); + const [sort, setSort] = useState("original"); + + // Esc to close + useEffect(() => { + if (!open) return; + const onKey = (e: KeyboardEvent) => { + if (e.key === "Escape") onClose(); + }; + window.addEventListener("keydown", onKey); + return () => window.removeEventListener("keydown", onKey); + }, [open, onClose]); + + // Scroll lock while open + useEffect(() => { + if (!open) return; + const prev = document.body.style.overflow; + document.body.style.overflow = "hidden"; + return () => { + document.body.style.overflow = prev; + }; + }, [open]); + + // Reset transient state each time the modal opens + useEffect(() => { + if (open) { + setQuery(""); + setSort("original"); + } + }, [open]); + + const presetName = (p: ProviderPreset) => + p.nameKey ? t(p.nameKey as TranslationKey) : p.name; + + const visible = useMemo(() => { + const q = query.trim().toLowerCase(); + let list = providerPresets; + if (q) { + list = list.filter( + (p) => p.id.toLowerCase().includes(q) || presetName(p).toLowerCase().includes(q) + ); + } + if (sort === "alpha") { + list = [...list].sort((a, b) => presetName(a).localeCompare(presetName(b))); + } + return list; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [query, sort, t]); + + if (!open) return null; + + return createPortal( +
      +
      e.stopPropagation()} + > + {/* Header */} +
      +
      + {t("presetPickerTitle")} +
      + +
      + + {/* Search + sort */} +
      + setQuery(e.target.value)} + placeholder={t("presetSearchPlaceholder")} + autoFocus + className="h-8 flex-1 rounded border border-border bg-input px-2 text-sm text-content-primary focus:outline-none focus:ring-2 focus:ring-blue-500" + /> +
      + + +
      +
      + + {/* Preset grid */} +
      + {visible.length === 0 ? ( +
      + {t("presetNoResults")} +
      + ) : ( +
      + {visible.map((p) => ( + + ))} +
      + )} + + {/* Custom (empty form) entry */} + +
      + + {/* Footer hint */} +
      + {t("presetFooterHint")} +
      +
      +
      , + document.body + ); +} diff --git a/src/components/ProviderEdit.tsx b/src/components/ProviderEdit.tsx new file mode 100644 index 0000000..42e9ad1 --- /dev/null +++ b/src/components/ProviderEdit.tsx @@ -0,0 +1,812 @@ +import { useEffect, useId, useState } from "react"; +import { createPortal } from "react-dom"; +import { invoke } from "@tauri-apps/api/core"; +import { useTranslation } from "../i18n"; +import type { TranslationKey } from "../i18n/zh"; +import { getDefaultMaxContextSize } from "../lib/model-defaults"; +import { capabilitiesFromRef, getModelRef } from "../lib/models-dev"; +import { getIconMetadata } from "../icons/extracted/metadata"; +import { AgentSettingsPanel } from "./AgentSettingsPanel"; +import { ProviderIcon } from "./ProviderIcon"; +import { IconPicker } from "./IconPicker"; +import type { Agent, DiscoveredModel, Model, Provider, ProviderType } from "../types"; + +const KNOWN_CAPABILITIES = [ + "thinking", + "always_thinking", + "image_in", + "video_in", + "tool_use", +] as const; + +const CAPABILITY_LABELS: Record< + (typeof KNOWN_CAPABILITIES)[number], + TranslationKey +> = { + thinking: "capThinking", + always_thinking: "capAlwaysThinking", + image_in: "capImageIn", + video_in: "capVideoIn", + tool_use: "capToolUse", +}; + +const PROVIDER_TYPES: ProviderType[] = [ + "openai", + "openai_responses", + "anthropic", + "google-genai", + "vertexai", + "kimi", +]; + +function defaultBaseUrl(agent: Agent, type: ProviderType): string { + if (agent === "kimi_code") { + switch (type) { + case "kimi": + return "https://api.kimi.com/coding/v1"; + case "openai": + case "openai_responses": + return "https://api.openai.com/v1"; + case "google-genai": + return "https://generativelanguage.googleapis.com"; + case "anthropic": + case "vertexai": + return ""; + } + } + // Pi defaults + switch (type) { + case "kimi": + return "https://api.moonshot.ai/v1"; + case "openai": + case "openai_responses": + return "https://api.openai.com/v1"; + case "google-genai": + return "https://generativelanguage.googleapis.com"; + case "anthropic": + case "vertexai": + return ""; + } +} + +interface ProviderEditProps { + agent: Agent; + provider: Provider; + models: Model[]; + defaultModel: string | null; + rawOther: unknown; + onRawOtherChange: (nextRawOther: unknown) => void; + onBack: () => void; + onChange: (provider: Provider) => void; + onDelete: () => void; + onModelChange: (model: Model) => void; + onModelDelete: (alias: string) => void; + onModelAdd: () => void; + onBulkAdd: (models: Model[]) => void; + onSetDefault: (alias: string) => void; + onApplyJson: (provider: Provider, models: Model[]) => void; + onSave: () => void; +} + +export function ProviderEdit({ + agent, + provider, + models, + defaultModel, + rawOther, + onRawOtherChange, + onBack, + onChange, + onDelete, + onModelChange, + onModelDelete, + onModelAdd, + onBulkAdd, + onSetDefault, + onApplyJson, + onSave, +}: ProviderEditProps) { + const { t } = useTranslation(); + const nameId = useId(); + const noteId = useId(); + const officialUrlId = useId(); + const apiKeyId = useId(); + const baseUrlId = useId(); + + const [activeTab, setActiveTab] = useState<"basic" | "models" | "json">("basic"); + const [showApiKey, setShowApiKey] = useState(false); + const [showIconPicker, setShowIconPicker] = useState(false); + + useEffect(() => { + const def = defaultBaseUrl(agent, provider.provider_type); + if (!def) return; + if (!provider.base_url) { + onChange({ ...provider, base_url: def }); + } + }, [provider.provider_type, agent]); + + return ( +
      + {/* Header */} +
      + +

      {t("editProvider")}

      +
      + + +
      + + {/* Tabs */} +
      + {[ + { key: "basic", label: t("basicInfo") }, + { key: "models", label: t("modelMapping") }, + { key: "json", label: t("configJson") }, + ].map((tab) => ( + + ))} +
      + + {/* Content */} +
      + {activeTab === "basic" && ( +
      + {/* Basic info */} +
      +

      {t("basicInfo")}

      + + {/* Icon selector */} +
      + + {provider.icon && ( + + )} +
      + +
      +
      + + onChange({ ...provider, name: e.target.value })} + /> +
      +
      + + + onChange({ ...provider, note: e.target.value || null }) + } + /> +
      +
      + + + onChange({ ...provider, official_url: e.target.value || null }) + } + /> +
      +
      + + onChange({ ...provider, managed: e.target.checked }) + } + className="w-4 h-4 rounded border-border bg-input text-blue-600 focus:ring-blue-500" + /> + +
      +
      +
      + + {/* API settings */} +
      +

      {t("apiSettings")}

      +
      +
      +
      + + +
      +
      + + {!provider.managed && ( +
      + +
      + + onChange({ ...provider, api_key: e.target.value || null }) + } + /> + +
      +
      + )} + +
      + + + onChange({ ...provider, base_url: e.target.value || null }) + } + /> +
      + {t("baseUrlHint", { type: provider.provider_type })} +
      +
      +
      +
      +
      + )} + + {activeTab === "models" && ( + <> + + {agent === "kimi_code" && ( + + )} + + )} + + {activeTab === "json" && ( + + )} +
      + + {showIconPicker && + createPortal( +
      setShowIconPicker(false)} + role="dialog" + aria-modal="true" + > +
      e.stopPropagation()} + > +
      +

      + {t("selectIcon")} +

      + +
      +
      + { + const meta = getIconMetadata(iconName); + onChange({ + ...provider, + icon: iconName, + icon_color: meta?.defaultColor ?? null, + }); + setShowIconPicker(false); + }} + /> +
      +
      +
      , + document.body + )} +
      + ); +} + +function ModelMapping({ + agent, + provider, + models, + defaultModel, + onModelChange, + onModelDelete, + onModelAdd, + onBulkAdd, + onSetDefault, +}: { + agent: Agent; + provider: Provider; + models: Model[]; + defaultModel: string | null; + onModelChange: (model: Model) => void; + onModelDelete: (alias: string) => void; + onModelAdd: () => void; + onBulkAdd: (models: Model[]) => void; + onSetDefault: (alias: string) => void; +}) { + const { t } = useTranslation(); + const [discovering, setDiscovering] = useState(false); + const [discovered, setDiscovered] = useState(null); + const [selected, setSelected] = useState>(new Set()); + const [discoverError, setDiscoverError] = useState(null); + const [fetchThinking, setFetchThinking] = useState(true); + + const handleDiscover = async () => { + setDiscovering(true); + setDiscoverError(null); + setDiscovered(null); + setSelected(new Set()); + try { + const result = await invoke("list_provider_models", { + provider, + }); + setDiscovered(result); + } catch (err) { + setDiscoverError(err instanceof Error ? err.message : String(err)); + } finally { + setDiscovering(false); + } + }; + + const toggleSelect = (id: string) => { + setSelected((prev) => { + const next = new Set(prev); + if (next.has(id)) next.delete(id); + else next.add(id); + return next; + }); + }; + + const handleAddSelected = () => { + if (!discovered || selected.size === 0) return; + const toAdd: Model[] = []; + for (const dm of discovered) { + if (!selected.has(dm.id)) continue; + const safeProvider = provider.name.replace(/\//g, "-"); + const safeModelId = dm.id.replace(/\//g, "-"); + const alias = `${safeProvider}/${safeModelId}`; + const ref = getModelRef(dm.id); + // Priority: API-provided value > models.dev reference > regex fallback + const max_context_size = + dm.max_context_size ?? ref?.context ?? getDefaultMaxContextSize(dm.id); + toAdd.push({ + alias, + provider: provider.name, + model: dm.id, + max_context_size, + display_name: dm.display_name ?? ref?.name ?? null, + supports_1m: max_context_size >= 1_000_000, + // Reference data wins when available; otherwise keep the old + // fetchThinking-checkbox behavior as the fallback. + capabilities: ref + ? capabilitiesFromRef(ref) + : fetchThinking + ? ["thinking"] + : [], + }); + } + onBulkAdd(toAdd); + setDiscovered(null); + setSelected(new Set()); + }; + + return ( +
      +
      +
      +

      {t("modelMapping")}

      +

      {t("modelMappingDesc")}

      +
      +
      + + +
      +
      + + {discoverError && ( +
      + {discoverError} +
      + )} + + {discovered && ( +
      +
      + {t("discoveredModels", { count: discovered.length })} +
      + +
      + {discovered.map((m) => ( + + ))} +
      + +
      + )} + +
      + + + + + + + + {agent === "kimi_code" && ( + + )} + + + + + + {models.map((m) => ( + + + + + + {agent === "kimi_code" && ( + + )} + + + + ))} + +
      {t("displayName")}{t("actualModel")}{t("contextSize")}{t("supports1M")}{t("capabilities")}{t("default")}{t("operation")}
      + + {m.model ? `${m.model}[${m.provider}]` : m.alias} + + + + onModelChange({ ...m, model: e.target.value }) + } + /> + + { + const value = parseInt(e.target.value, 10); + onModelChange({ + ...m, + max_context_size: isNaN(value) ? 0 : value, + }); + }} + /> + + + onModelChange({ + ...m, + supports_1m: e.target.checked, + }) + } + className="w-4 h-4 rounded border-border bg-input text-blue-600 focus:ring-blue-500" + /> + + + onModelChange({ ...m, capabilities: next }) + } + /> + + + + +
      + {models.length === 0 && ( +
      + {t("noModelMappings")} +
      + )} +
      + + +
      + ); +} + +function JsonPreview({ + provider, + models, + onApply, +}: { + provider: Provider; + models: Model[]; + onApply: (provider: Provider, models: Model[]) => void; +}) { + const { t } = useTranslation(); + const [text, setText] = useState(() => + JSON.stringify({ provider, models }, null, 2) + ); + const [error, setError] = useState(null); + + useEffect(() => { + setText(JSON.stringify({ provider, models }, null, 2)); + setError(null); + }, [provider, models]); + + const handleApply = () => { + try { + const parsed = JSON.parse(text); + if (!parsed.provider || typeof parsed.provider !== "object") { + throw new Error("missing provider object"); + } + if (!Array.isArray(parsed.models)) { + throw new Error("models must be an array"); + } + onApply(parsed.provider as Provider, parsed.models as Model[]); + setError(null); + } catch (err) { + setError(err instanceof Error ? err.message : String(err)); + } + }; + + return ( +
      +
      +

      {t("configJson")}

      +
      + {t("readOnlyPreview")} + +
      +
      + {error && ( +
      + {t("invalidJson", { message: error })} +
      + )} +