diff --git a/src/i18n/ja.ts b/src/i18n/ja.ts index d0d9054..50c2a6f 100644 --- a/src/i18n/ja.ts +++ b/src/i18n/ja.ts @@ -1639,8 +1639,8 @@ export const jaOverrides = { 'kernel.versions.confirmUpdateTitle': 'コアを停止して更新', 'kernel.versions.stopAndConfirmDescription': 'コアを更新すると実行中のコアプロセスが停止し、バージョン {version} がインストールされます。更新後にコアを再起動できます。続行しますか?', 'kernel.versions.stopAndUpdateVersion': '{version} に停止して更新', - 'kernel.versions.reinstallTitle': '現在のバージョンを再インストール', - 'kernel.versions.reinstall': '再インストール', + 'kernel.versions.installBundledTitle': 'ダウンロードせずに同梱コア {version} をインストール', + 'kernel.versions.installBundled': '同梱コアをインストール', 'kernel.versions.noBundled': 'このリリースには組み込みコアが含まれていません', 'kernel.versions.offlineInstall': 'オフラインインストール', 'kernel.versions.downloadSource': 'ダウンロード元を切り替える', diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 4c87605..2c1629e 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -1639,8 +1639,8 @@ export const en: Record = { 'kernel.versions.confirmUpdateTitle': 'Stop and Update Core', 'kernel.versions.stopAndConfirmDescription': 'Updating the core will stop the currently running core process and install version {version}. You can restart the core after the update. Do you want to continue?', 'kernel.versions.stopAndUpdateVersion': 'Stop and update to {version}', - 'kernel.versions.reinstallTitle': 'Reinstall the current version', - 'kernel.versions.reinstall': 'Reinstall', + 'kernel.versions.installBundledTitle': 'Install bundled core {version} without downloading', + 'kernel.versions.installBundled': 'Install Bundled Core', 'kernel.versions.noBundled': 'This release does not include a bundled core', 'kernel.versions.offlineInstall': 'Offline Install', 'kernel.versions.downloadSource': 'Switch Download Source', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 41a067a..d6fcde5 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -1638,8 +1638,8 @@ export const zhCN = { 'kernel.versions.confirmUpdateTitle': '停止并更新内核', 'kernel.versions.stopAndConfirmDescription': '更新内核将停止正在运行的内核进程,并下载安装版本 {version}。更新完成后需重新启动内核,是否继续?', 'kernel.versions.stopAndUpdateVersion': '停止并更新至 {version}', - 'kernel.versions.reinstallTitle': '重新安装当前版本', - 'kernel.versions.reinstall': '重新安装', + 'kernel.versions.installBundledTitle': '安装随应用附带的内核 {version},无需下载', + 'kernel.versions.installBundled': '安装内置内核', 'kernel.versions.noBundled': '当前发行包未包含内置内核', 'kernel.versions.offlineInstall': '离线安装', 'kernel.versions.downloadSource': '切换下载源', diff --git a/src/mocks/browserMockRuntime.ts b/src/mocks/browserMockRuntime.ts index 52a4633..37df148 100644 --- a/src/mocks/browserMockRuntime.ts +++ b/src/mocks/browserMockRuntime.ts @@ -15,6 +15,7 @@ export type BrowserMockRuntime = { }; const SCENARIOS = new Set(['running', 'stopped', 'empty', 'error']); +const BUNDLED_CORE = { version: '7.3.15', assetName: 'CLIProxyAPI_7.3.15_windows_amd64.zip' }; const PROVIDER_SECTIONS = [ 'gemini-api-key', 'codex-api-key', @@ -931,9 +932,10 @@ export function createBrowserMockRuntime( case 'get_core_install_task': return clone(state.coreInstallTask); case 'install_core_version': case 'install_bundled_core': { + const source = command === 'install_bundled_core' ? BUNDLED_CORE : state.coreLatest; const result = { - version: readString(payload.version) || state.coreLatest.version, - assetName: state.coreLatest.assetName, + version: command === 'install_bundled_core' ? source.version : readString(payload.version) || source.version, + assetName: source.assetName, installDir: state.coreStatus.installDir, binaryPath: 'C:\\EasyCLIProxyAPI\\cpa-core\\cli-proxy-api.exe', }; @@ -944,7 +946,7 @@ export function createBrowserMockRuntime( return clone(result); } case 'cancel_core_install': return null; - case 'detect_bundled_core': return { version: '7.3.15', assetName: 'CLIProxyAPI_7.3.15_windows_amd64.zip' }; + case 'detect_bundled_core': return clone(BUNDLED_CORE); case 'get_version_source_settings': return clone(state.versionSource); case 'set_download_source': { state.versionSource.source = readString(payload.source) || 'github'; diff --git a/src/pages/VersionManagementPage.tsx b/src/pages/VersionManagementPage.tsx index 66c17bf..9685f1c 100644 --- a/src/pages/VersionManagementPage.tsx +++ b/src/pages/VersionManagementPage.tsx @@ -7,7 +7,7 @@ import { ExternalLink, Info, RefreshCw, - RotateCcw, + Package, Trash2, X, } from 'lucide-react'; @@ -27,6 +27,11 @@ export type CoreInstallResult = { binaryPath: string | null; }; +type BundledCoreInfo = { + version: string; + assetName: string; +}; + export type CoreInstallTask = { running: boolean; cancellable: boolean; @@ -99,6 +104,8 @@ export function VersionManagementPage() { } = useCoreUpdate(); const [installedAppVersion, setInstalledAppVersion] = useState(''); + const [bundledCore, setBundledCore] = useState(null); + const [bundledCoreError, setBundledCoreError] = useState(''); const [installing, setInstalling] = useState(false); const [progress, setProgress] = useState(null); @@ -244,7 +251,7 @@ export function VersionManagementPage() { } }; - const installVersion = async (version: string) => { + const installCore = async (target: { kind: 'bundled' } | { kind: 'release'; version: string }) => { completedInstallKeyRef.current = ''; manualInstallInProgressRef.current = true; setInstalling(true); @@ -252,8 +259,8 @@ export function VersionManagementPage() { setInstallDialogOpen(true); setProgress({ running: true, - cancellable: true, - phase: 'Preparing download', + cancellable: target.kind === 'release', + phase: target.kind === 'bundled' ? 'Preparing bundled kernel' : 'Preparing download', downloaded: 0, total: null, percent: null, @@ -262,8 +269,11 @@ export function VersionManagementPage() { }); try { - const result = await invoke('install_core_version', { version }); - showInstallCompletedNotice(result, t('kernel.install.completed', { version: result.version })); + const result = target.kind === 'bundled' + ? await invoke('install_bundled_core') + : await invoke('install_core_version', { version: target.version }); + const message = t(target.kind === 'bundled' ? 'kernel.install.bundledCompleted' : 'kernel.install.completed', { version: result.version }); + showInstallCompletedNotice(result, message); manualInstallInProgressRef.current = false; setProgress({ running: false, @@ -272,13 +282,12 @@ export function VersionManagementPage() { downloaded: 1, total: 1, percent: 100, - message: t('kernel.install.completed', { version: result.version }), + message, result, }); setInstallDialogOpen(false); setProgress(null); setCancellingInstall(false); - await refreshStatus(); } catch (error) { manualInstallInProgressRef.current = false; const errorMessage = String(error); @@ -296,6 +305,7 @@ export function VersionManagementPage() { })); } finally { setInstalling(false); + await refreshStatus(); } }; @@ -382,6 +392,13 @@ export function VersionManagementPage() { loadInstallTask(); void loadVersionSourceSettings(); + void invoke('detect_bundled_core') + .then((info) => { + if (!disposed) setBundledCore(info); + }) + .catch((error) => { + if (!disposed) setBundledCoreError(String(error)); + }); void getVersion() .then((version) => { @@ -402,7 +419,7 @@ export function VersionManagementPage() { const coreInstalled = Boolean(coreStatus?.installed); const coreProcessBusy = Boolean(coreStatus?.starting); const busy = checkingLatest || installing || coreProcessBusy; - const installDisabled = busy || installing; + const installDisabled = installing || coreProcessBusy; const resolvedAppVersion = appUpdate?.currentVersion || installedAppVersion; const currentAppVersion = resolvedAppVersion ? displayAppVersion(resolvedAppVersion) : t('common.detecting'); @@ -511,7 +528,7 @@ export function VersionManagementPage() { return (
setVersionSourceError('')} /> -
+
{t('kernel.versions.downloadSource')} @@ -686,12 +703,12 @@ export function VersionManagementPage() {
@@ -820,7 +837,7 @@ export function VersionManagementPage() { className="primary-button" onClick={() => { setConfirmUpdateOpen(false); - void installVersion(latestVersion); + void installCore({ kind: 'release', version: latestVersion }); }} >