diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eea2f2e..037d19d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -190,8 +190,8 @@ jobs: throw new Error(`cpa-core must contain exactly one archive; found: ${entries.map((entry) => entry.name).join(', ')}`); } NODE - - name: Prepare Windows portable updater payload - if: matrix.os == 'windows' + - name: Prepare v0.2.10 legacy updater bridge + if: matrix.os == 'windows' && steps.package.outputs.version == '0.2.10' shell: pwsh run: | $updateDir = "release/update-${{ matrix.arch }}" @@ -201,11 +201,11 @@ jobs: $marker = Get-Content -Raw -LiteralPath "$updateDir/portable-app.json" | ConvertFrom-Json if ($marker.schemaVersion -ne 1 -or $marker.application -ne "EasyCLIProxyAPI" -or - $marker.version -ne "${{ steps.package.outputs.version }}" -or + $marker.version -ne "0.2.10" -or $marker.platform -ne "windows" -or $marker.arch -ne "${{ matrix.arch }}" -or $marker.autoUpdate -ne $true) { - throw "portable-app.json does not match the Windows updater target" + throw "v0.2.10 legacy updater bridge does not match the Windows target" } - name: Build signed macOS DMG if: matrix.os == 'darwin' @@ -341,22 +341,40 @@ jobs: - name: Archive Windows release if: matrix.os == 'windows' shell: pwsh + env: + LEGACY_UPDATE_BRIDGE: ${{ steps.package.outputs.version == '0.2.10' }} run: | Compress-Archive -Path "release/${{ steps.package.outputs.stem }}" -DestinationPath "${{ steps.package.outputs.stem }}.zip" - $updateArchive = "EasyCLIProxyAPI-update-v${{ steps.package.outputs.version }}-Windows-${{ matrix.arch }}.zip" - Compress-Archive -Path "release/update-${{ matrix.arch }}/*" -DestinationPath $updateArchive Add-Type -AssemblyName System.IO.Compression.FileSystem - $zip = [System.IO.Compression.ZipFile]::OpenRead((Resolve-Path $updateArchive)) + $releaseArchive = "${{ steps.package.outputs.stem }}.zip" + $zip = [System.IO.Compression.ZipFile]::OpenRead((Resolve-Path $releaseArchive)) try { $entries = @($zip.Entries | ForEach-Object { $_.FullName.Replace('\', '/') }) - if ($entries.Count -ne 2 -or - $entries -notcontains "EasyCLIProxyAPI.exe" -or - $entries -notcontains "portable-app.json") { - throw "Portable updater ZIP contains unexpected entries: $($entries -join ', ')" + $root = "${{ steps.package.outputs.stem }}" + if ($entries -notcontains "$root/EasyCLIProxyAPI.exe" -or + $entries -notcontains "$root/portable-app.json" -or + $entries -notcontains "$root/core-version.txt" -or + -not ($entries | Where-Object { $_ -match "^$([regex]::Escape($root))/cpa-core/CLIProxyAPI_.+_windows_${{ matrix.arch }}\.zip$" })) { + throw "Full Windows release ZIP is incomplete: $($entries -join ', ')" } } finally { $zip.Dispose() } + if ($env:LEGACY_UPDATE_BRIDGE -eq "true") { + $updateArchive = "EasyCLIProxyAPI-update-v0.2.10-Windows-${{ matrix.arch }}.zip" + Compress-Archive -Path "release/update-${{ matrix.arch }}/*" -DestinationPath $updateArchive + $updateZip = [System.IO.Compression.ZipFile]::OpenRead((Resolve-Path $updateArchive)) + try { + $updateEntries = @($updateZip.Entries | ForEach-Object { $_.FullName.Replace('\', '/') }) + if ($updateEntries.Count -ne 2 -or + $updateEntries -notcontains "EasyCLIProxyAPI.exe" -or + $updateEntries -notcontains "portable-app.json") { + throw "v0.2.10 legacy updater bridge contains unexpected entries: $($updateEntries -join ', ')" + } + } finally { + $updateZip.Dispose() + } + } - uses: actions/upload-artifact@v7 with: name: ${{ steps.package.outputs.stem }} @@ -364,13 +382,12 @@ jobs: if-no-files-found: error retention-days: 14 - uses: actions/upload-artifact@v7 - if: matrix.os == 'windows' + if: matrix.os == 'windows' && steps.package.outputs.version == '0.2.10' with: - name: portable-updater-windows-${{ matrix.arch }} - path: EasyCLIProxyAPI-update-v${{ steps.package.outputs.version }}-Windows-${{ matrix.arch }}.zip + name: legacy-updater-bridge-windows-${{ matrix.arch }} + path: EasyCLIProxyAPI-update-v0.2.10-Windows-${{ matrix.arch }}.zip if-no-files-found: error retention-days: 14 - publish: name: Publish GitHub release if: >- diff --git a/.gitignore b/.gitignore index 394af76..e425e99 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ cpa-core/ *.log *.tmp +misc/ diff --git a/README.ja.md b/README.ja.md index c2869d2..1c6119f 100644 --- a/README.ja.md +++ b/README.ja.md @@ -90,7 +90,7 @@ OpenAI、Claude、Gemini、およびその他の互換形式の間で変換で ## その他の機能 -- コア設定、API Key、リモート管理用認証情報、プラグイン、ルーティング戦略の管理。 +- コア設定、API Key、リモート管理用認証情報、ルーティング戦略の管理。 - クライアント向けモデルエイリアスを作成し、プロバイダーモデルや推論レベルへマッピング。 - 認証ファイルのアップロード、ダウンロード、確認、管理。 - プロバイダーのクォータとアカウント利用状態を確認。 @@ -106,6 +106,12 @@ OpenAI、Claude、Gemini、およびその他の互換形式の間で変換で 4. **コア** 画面を開き、同梱版または最新版の CLIProxyAPI コアをインストールします。 5. コアを起動し、必要なローカル API エンドポイントをコピーするか、OAuth/API プロバイダーを設定します。 +## アップグレード + +v0.2.10 は一度限りの移行用リリースです。完全版 Windows ZIP と旧クライアント互換の `update` ZIP を同時に公開し、v0.2.6~v0.2.9 からアプリ内で v0.2.10 へ更新できます。v0.2.11 以降は完全版 ZIP のみを公開し、v0.2.10 へ移行済みのクライアントは途中のバージョンを個別に導入せず直接アップグレードできます。 + +v0.2.5 以前を使用している場合は、一度だけ手動で移行してください。EasyCLIProxyAPI を終了し、使用中のアーキテクチャに対応する最新版の完全版 Windows ZIP をダウンロードして、その最上位ディレクトリの内容を既存のインストール先へコピーし、同名ファイルを上書きします。既存のディレクトリを先に削除しないでください。`config.toml`、`oauth`、`cpa-core/config.yaml` などのユーザーデータは保持されます。新しいバージョンを起動した後は、以降のリリースでアプリ内自動更新を利用できます。 + ## 対応プラットフォーム GitHub Actions では、次のリリースパッケージをビルドします。 diff --git a/README.md b/README.md index 534205e..ce89c9e 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ previous configuration, and launch an available desktop or CLI entry point. ## Additional Capabilities -- Manage core settings, API keys, remote management credentials, plugins, and routing strategy. +- Manage core settings, API keys, remote management credentials, and routing strategy. - Create client-visible model aliases and map them to provider models and reasoning levels. - Upload, download, inspect, and manage authentication files. - Review provider quotas and account availability. @@ -107,6 +107,12 @@ previous configuration, and launch an available desktop or CLI entry point. 4. Open the **Core** page and install the bundled or latest CLIProxyAPI core. 5. Start the core, then copy the required local endpoint or configure an OAuth/API provider. +## Upgrading + +v0.2.10 is a one-time bridge release. It publishes both the complete Windows ZIP and the legacy `update` ZIP so v0.2.6–v0.2.9 can upgrade to v0.2.10 in the app. Starting with v0.2.11, only the complete ZIP is published; clients already on v0.2.10 can consume it and jump directly across intermediate releases. + +If you are running v0.2.5 or earlier, perform one manual migration: exit EasyCLIProxyAPI, download the latest complete Windows ZIP for your architecture, then copy the contents of its top-level directory over the existing installation directory. Do not delete the existing directory first; user data such as `config.toml`, `oauth`, and `cpa-core/config.yaml` will remain in place. After launching the new version, later releases can use in-app automatic updates. + ## Supported Platforms GitHub Actions builds the following release packages: diff --git a/README.zh-CN.md b/README.zh-CN.md index af10392..6f431f4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -86,7 +86,7 @@ API 接入页面按照协议或 Provider 管理上游 API 凭证和服务地址 ## 其他功能 -- 管理内核配置、API Key、远程管理凭证、插件和路由策略。 +- 管理内核配置、API Key、远程管理凭证和路由策略。 - 创建客户端可见的模型别名,并映射到 Provider 模型和推理等级。 - 上传、下载、检查和管理认证文件。 - 查看 Provider 配额和账号可用状态。 @@ -102,6 +102,12 @@ API 接入页面按照协议或 Provider 管理上游 API 凭证和服务地址 4. 打开 **内核** 页面,安装内置版本或最新版本的 CLIProxyAPI 内核。 5. 启动内核,然后复制所需的本地 API 地址,或配置 OAuth/API Provider。 +## 升级 + +v0.2.10 是一次性桥接版本:它会同时发布完整 Windows ZIP 和兼容旧客户端的 `update` ZIP,使 v0.2.6–v0.2.9 可以通过应用内更新升级到 v0.2.10。v0.2.11 起只发布完整 ZIP;已升级到 v0.2.10 的客户端可以识别完整包并跨过多个中间版本直接升级。 + +如果当前版本是 v0.2.5 或更早版本,请执行一次手动迁移:退出 EasyCLIProxyAPI,下载最新版对应架构的完整 Windows ZIP,将 ZIP 顶层目录内的内容复制到现有安装目录并覆盖同名文件。不要先删除现有安装目录;`config.toml`、`oauth` 和 `cpa-core/config.yaml` 等用户数据会被保留。启动新版后,后续版本即可继续使用应用内自动升级。 + ## 支持的平台 GitHub Actions 会构建以下发行包: diff --git a/build.ps1 b/build.ps1 index 5b2e281..a958702 100644 --- a/build.ps1 +++ b/build.ps1 @@ -58,7 +58,7 @@ if (-not (Test-Path -LiteralPath $AppBin -PathType Leaf)) { throw "Build finished, but executable not found: $AppBin" } -& bun $PreparePortable --binary $AppBin --output $BinDir --download true +& bun $PreparePortable --binary $AppBin --output $BinDir --download true --preserve-runtime-config true if ($LASTEXITCODE -ne 0) { throw "Portable preparation failed with exit code $LASTEXITCODE." } @@ -68,15 +68,14 @@ if (-not (Test-Path -LiteralPath $BinOut -PathType Leaf)) { } $CoreOut = Join-Path $BinDir 'cpa-core' -$CoreEntries = @(Get-ChildItem -LiteralPath $CoreOut -Force) -if ( - $CoreEntries.Count -ne 1 -or - $CoreEntries[0].PSIsContainer -or - $CoreEntries[0].Name -notmatch '^CLIProxyAPI_.+_windows_.+\.zip$' -) { +$CoreArchives = @( + Get-ChildItem -LiteralPath $CoreOut -File | + Where-Object { $_.Name -match '^CLIProxyAPI_.+_windows_.+\.zip$' } +) +if ($CoreArchives.Count -ne 1) { throw "Portable core output must contain exactly one Windows core archive: $CoreOut" } Write-Host "Built: $AppBin" Write-Host "Copied: $BinOut" -Write-Host "Bundled core archive: $($CoreEntries[0].FullName)" +Write-Host "Bundled core archive: $($CoreArchives[0].FullName)" diff --git a/bun.lock b/bun.lock index abf4563..086e187 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "name": "cpa-gui", "dependencies": { "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-dialog": "^2.7.1", "lucide-react": "^1.24.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -199,6 +200,8 @@ "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.11.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw=="], + "@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.7.2", "", { "dependencies": { "@tauri-apps/api": "^2.11.0" } }, "sha512-pX0IGm1I3I6wc+zeKYcq1GSqogK6okCNX5fOdaNU5ab1AjGS6l1E5wFNjEb7meg7ZFSp0JUs+0jQGQNyOvLrsg=="], + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], diff --git a/core-version.txt b/core-version.txt index 3d296eb..ee4117d 100644 --- a/core-version.txt +++ b/core-version.txt @@ -1 +1 @@ -7.2.101 +7.2.112 diff --git a/index.html b/index.html index 0030da6..b35e535 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,7 @@ : matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; document.documentElement.dataset.theme = theme; document.documentElement.style.colorScheme = theme; - document.documentElement.style.backgroundColor = theme === 'dark' ? '#101419' : '#faf9f5'; + document.documentElement.style.backgroundColor = theme === 'dark' ? '#111412' : '#f6f7f5'; } catch { // The app applies the theme again during initialization. } diff --git a/package.json b/package.json index 0558eb7..c55a8ac 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cpa-gui", "private": true, - "version": "0.2.9", + "version": "0.2.10", "type": "module", "packageManager": "bun@1.3.14", "scripts": { @@ -13,6 +13,7 @@ }, "dependencies": { "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-dialog": "^2.7.1", "lucide-react": "^1.24.0", "react": "^19.0.0", "react-dom": "^19.0.0" diff --git a/scripts/generate-portable-update-manifest.d.mts b/scripts/generate-portable-update-manifest.d.mts index 88b6dce..2daf8d5 100644 --- a/scripts/generate-portable-update-manifest.d.mts +++ b/scripts/generate-portable-update-manifest.d.mts @@ -4,6 +4,8 @@ export type PortableUpdateManifestAsset = { sizeBytes: number; }; +export const LEGACY_UPDATE_BRIDGE_VERSION: string; + export type PortableUpdateManifest = { schemaVersion: number; version: string; diff --git a/scripts/generate-portable-update-manifest.mjs b/scripts/generate-portable-update-manifest.mjs index 82cfab9..0a62cb5 100644 --- a/scripts/generate-portable-update-manifest.mjs +++ b/scripts/generate-portable-update-manifest.mjs @@ -3,6 +3,8 @@ import { readFile, stat, writeFile } from 'node:fs/promises'; import { basename, join, resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; +export const LEGACY_UPDATE_BRIDGE_VERSION = '0.2.10'; + export async function generatePortableUpdateManifest({ directory, output, @@ -29,12 +31,15 @@ export async function generatePortableUpdateManifest({ } const assets = {}; + const useLegacyBridgeAssets = version === LEGACY_UPDATE_BRIDGE_VERSION; for (const arch of ['amd64', 'aarch64']) { - const filename = `EasyCLIProxyAPI-update-${tag}-Windows-${arch}.zip`; + const filename = useLegacyBridgeAssets + ? `EasyCLIProxyAPI-update-${tag}-Windows-${arch}.zip` + : `EasyCLIProxyAPI-${tag}-Windows-${arch}.zip`; const path = join(resolvedDirectory, filename); const [contents, metadata] = await Promise.all([readFile(path), stat(path)]); if (!metadata.isFile() || metadata.size === 0) { - throw new Error(`Portable updater asset is empty or not a file: ${filename}`); + throw new Error(`Portable release asset is empty or not a file: ${filename}`); } assets[`windows-${arch}`] = { url: `https://github.com/${resolvedRepository}/releases/download/${tag}/${filename}`, diff --git a/scripts/prepare-portable.mjs b/scripts/prepare-portable.mjs index 1615c06..37b7fd8 100644 --- a/scripts/prepare-portable.mjs +++ b/scripts/prepare-portable.mjs @@ -14,6 +14,7 @@ const binary = resolve(args.get('--binary') ?? join(root, 'src-tauri', 'target', const targetOS = args.get('--os') ?? ({ linux: 'linux', darwin: 'darwin', win32: 'windows' })[process.platform]; const targetArch = args.get('--arch') ?? ({ x64: 'amd64', arm64: 'aarch64' })[process.arch]; const shouldDownload = args.get('--download') === 'true'; +const preserveRuntimeConfig = args.get('--preserve-runtime-config') === 'true'; if (!targetOS || !targetArch) throw new Error(`Unsupported target: ${process.platform}/${process.arch}`); if (!existsSync(binary)) throw new Error(`GUI binary not found: ${binary}`); @@ -75,17 +76,25 @@ await writeFile(join(output, 'portable-app.json'), `${JSON.stringify({ }, null, 2)}\n`); const coreOutput = join(output, 'cpa-core'); -await rm(coreOutput, { recursive: true, force: true }); +if (preserveRuntimeConfig) { + await mkdir(coreOutput, { recursive: true }); + const entries = await readdir(coreOutput, { withFileTypes: true }); + await Promise.all(entries + .filter((entry) => entry.name !== 'config.yaml') + .map((entry) => rm(join(coreOutput, entry.name), { recursive: true, force: true }))); +} else { + await rm(coreOutput, { recursive: true, force: true }); +} await mkdir(coreOutput, { recursive: true }); await copyFile(sourceArchive, join(coreOutput, assetName)); const coreEntries = await readdir(coreOutput, { withFileTypes: true }); -if ( - coreEntries.length !== 1 - || !coreEntries[0].isFile() - || coreEntries[0].name !== assetName -) { +const bundledArchive = coreEntries.find((entry) => entry.isFile() && entry.name === assetName); +if (!bundledArchive) { + throw new Error(`Core output must contain ${assetName}`); +} +if (!preserveRuntimeConfig && coreEntries.length !== 1) { throw new Error(`Core output must contain only ${assetName}`); } console.log(`Prepared portable directory: ${output}`); -console.log(`Bundled core: ${basename(sourceArchive)} (archive only)`); +console.log(`Bundled core: ${basename(sourceArchive)}${preserveRuntimeConfig ? ' (preserved cpa-core/config.yaml)' : ' (archive only)'}`); diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index edd4b58..c0e8718 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -582,12 +582,13 @@ checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" [[package]] name = "cpa-gui" -version = "0.2.9" +version = "0.2.10" dependencies = [ "base64 0.22.1", "chrono", "flate2", "futures-util", + "getrandom 0.3.4", "json5", "libc", "notify", @@ -604,6 +605,7 @@ dependencies = [ "tar", "tauri", "tauri-build", + "tauri-plugin-dialog", "tauri-plugin-opener", "tokio", "tokio-util", @@ -2486,6 +2488,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.13.0", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -3167,6 +3170,30 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + [[package]] name = "ring" version = "0.17.14" @@ -4003,6 +4030,48 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371" +dependencies = [ + "anyhow", + "dunce", + "glob", + "log", + "objc2-foundation", + "percent-encoding", + "schemars 0.8.22", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.18", + "toml 1.1.3+spec-1.1.0", + "url", +] + [[package]] name = "tauri-plugin-opener" version = "2.5.4" @@ -5150,6 +5219,15 @@ 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" @@ -5183,13 +5261,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "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" @@ -5220,6 +5315,12 @@ 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" @@ -5232,6 +5333,12 @@ 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" @@ -5244,12 +5351,24 @@ 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" @@ -5262,6 +5381,12 @@ 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" @@ -5274,6 +5399,12 @@ 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" @@ -5286,6 +5417,12 @@ 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" @@ -5298,6 +5435,12 @@ 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" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 69d8a1d..1bf22d8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cpa-gui" -version = "0.2.9" +version = "0.2.10" description = "CPA desktop management shell" authors = ["lzt404"] edition = "2021" @@ -13,6 +13,7 @@ base64 = "0.22" chrono = { version = "0.4", features = ["serde"] } flate2 = "1" futures-util = "0.3" +getrandom = "0.3" json5 = "0.4" notify = "7" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] } @@ -25,6 +26,7 @@ serde_yaml = "0.9" sha2 = "0.10" tar = "0.4" tauri = { version = "~2.11", features = ["tray-icon"] } +tauri-plugin-dialog = "2.7.1" tauri-plugin-opener = "2" tokio = { version = "1", features = ["macros", "sync", "time"] } tokio-util = "0.7" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 0a29d28..e06f87d 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -8,6 +8,7 @@ "core:event:allow-unlisten", "core:window:allow-set-theme", "core:window:allow-set-background-color", - "core:webview:allow-set-webview-background-color" + "core:webview:allow-set-webview-background-color", + "dialog:allow-open" ] } diff --git a/src-tauri/src/codex_catalog.rs b/src-tauri/src/codex_catalog.rs index 4b1829e..1bfa837 100644 --- a/src-tauri/src/codex_catalog.rs +++ b/src-tauri/src/codex_catalog.rs @@ -99,11 +99,14 @@ pub(crate) fn parse_runtime_models(payload: &Value) -> Result Result