Browse Source

构建和发布脚本

黄中银 2 weeks ago
parent
commit
9d5f7eda56

+ 53 - 88
.github/workflows/release.yml

@@ -32,14 +32,22 @@ jobs:
         id: version
         run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
 
-      - name: Update package.json version
-        run: npm pkg set version=${{ steps.version.outputs.VERSION }}
+      - name: Update version in all config files
+        run: |
+          # Update package.json
+          npm pkg set version=${{ steps.version.outputs.VERSION }}
+
+          # Update Cargo.toml
+          sed -i 's/^version = ".*"/version = "${{ steps.version.outputs.VERSION }}"/' src-tauri/Cargo.toml
+
+          # Update tauri.conf.json
+          sed -i 's/"version": ".*"/"version": "${{ steps.version.outputs.VERSION }}"/' src-tauri/tauri.conf.json
 
       - name: Commit version update
         run: |
           git config user.name "github-actions[bot]"
           git config user.email "github-actions[bot]@users.noreply.github.com"
-          git add package.json
+          git add package.json src-tauri/Cargo.toml src-tauri/tauri.conf.json
           git commit -m "chore: bump version to ${{ steps.version.outputs.VERSION }}" || echo "No changes to commit"
           git push origin HEAD:main
 
@@ -52,10 +60,16 @@ jobs:
         include:
           - os: windows-latest
             platform: win
+            target: x86_64-pc-windows-msvc
           - os: macos-latest
             platform: mac
-          - os: ubuntu-latest
+            target: aarch64-apple-darwin
+          - os: macos-latest
+            platform: mac-intel
+            target: x86_64-apple-darwin
+          - os: ubuntu-22.04
             platform: linux
+            target: x86_64-unknown-linux-gnu
 
     runs-on: ${{ matrix.os }}
 
@@ -71,98 +85,49 @@ jobs:
           node-version: '20'
           cache: 'npm'
 
-      - name: Cache Electron
-        uses: actions/cache@v4
+      - name: Install Rust toolchain
+        uses: dtolnay/rust-toolchain@stable
         with:
-          path: |
-            ~/AppData/Local/electron/Cache
-            ~/.cache/electron
-            ~/Library/Caches/electron
-          key: electron-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
+          targets: ${{ matrix.target }}
 
-      - name: Cache pkg (Windows only)
-        if: matrix.platform == 'win'
+      - name: Cache Cargo
         uses: actions/cache@v4
         with:
-          path: ~/.pkg-cache
-          key: pkg-cache-node18-win-x64
+          path: |
+            ~/.cargo/bin/
+            ~/.cargo/registry/index/
+            ~/.cargo/registry/cache/
+            ~/.cargo/git/db/
+            src-tauri/target/
+          key: cargo-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('src-tauri/Cargo.lock') }}
+          restore-keys: |
+            cargo-${{ runner.os }}-${{ matrix.target }}-
+
+      - name: Install Linux dependencies
+        if: matrix.platform == 'linux'
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y \
+            libwebkit2gtk-4.1-dev \
+            libappindicator3-dev \
+            librsvg2-dev \
+            patchelf \
+            libgtk-3-dev \
+            libayatana-appindicator3-dev
 
       - name: Install dependencies
         run: npm ci
 
-      - name: Build frontend
-        run: npx vite build
-
-      - name: Package application
-        run: npx electron-builder --${{ matrix.platform }}
+      - name: Build Tauri application
+        uses: tauri-apps/tauri-action@v0
         env:
-          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
-      - name: Build portable version with launcher (Windows only)
-        if: matrix.platform == 'win'
-        shell: pwsh
-        run: |
-          # Build launcher
-          npx pkg launcher/launcher.js --target node18-win-x64 --output release/launcher.exe
-
-          # Find portable exe
-          $portableExe = Get-ChildItem -Path release -Filter "*portable*.exe" | Select-Object -First 1
-          if (-not $portableExe) {
-            Write-Error "Portable exe not found"
-            exit 1
-          }
-
-          $version = "${{ needs.update-version.outputs.version }}"
-          $portableDirName = "Claude-AI-Installer-$version-portable"
-          $portableDir = "release/$portableDirName"
-
-          # Create directory structure
-          New-Item -ItemType Directory -Force -Path "$portableDir/app"
-          New-Item -ItemType Directory -Force -Path "$portableDir/update"
-
-          # Copy files
-          Copy-Item "release/launcher.exe" "$portableDir/Claude-AI-Installer.exe"
-          Copy-Item $portableExe.FullName "$portableDir/app/Claude-AI-Installer-$version.exe"
-
-          # Create README
-          @"
-          Claude AI Installer - Portable 版本
-
-          使用方法:
-          1. 双击 Claude-AI-Installer.exe 启动程序
-          2. 程序会自动检查更新
-          3. 更新下载后,重启程序即可完成更新
-
-          目录说明:
-          - Claude-AI-Installer.exe: 启动器
-          - app/: 主程序目录
-          - update/: 更新文件临时目录
-
-          版本: $version
-          "@ | Out-File -FilePath "$portableDir/README.txt" -Encoding UTF8
-
-          # Create ZIP
-          Compress-Archive -Path "$portableDir/*" -DestinationPath "release/$portableDirName.zip" -Force
-
-      - name: Clean up unnecessary files
-        shell: bash
-        run: |
-          rm -f release/launcher.exe 2>/dev/null || true
-          rm -f release/*.blockmap 2>/dev/null || true
-          rm -f release/builder-debug.yml 2>/dev/null || true
-
-      - name: Upload release assets
-        uses: softprops/action-gh-release@v2
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
+          TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ""
         with:
-          files: |
-            release/*.exe
-            release/*.dmg
-            release/*.zip
-            release/*.AppImage
-            release/*.deb
-            release/*.rpm
-            release/latest*.yml
-          draft: false
+          tagName: v${{ needs.update-version.outputs.version }}
+          releaseName: 'Claude AI Installer v${{ needs.update-version.outputs.version }}'
+          releaseBody: 'See the assets to download this version and install.'
+          releaseDraft: false
           prerelease: false
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          args: --target ${{ matrix.target }}

+ 3 - 0
.gitignore

@@ -43,3 +43,6 @@ nul
 
 # Rust
 Cargo.lock
+
+# Signing keys (private key - DO NOT COMMIT!)
+.keys/tauri-signing.key

+ 1 - 0
.keys/tauri-signing.key

@@ -0,0 +1 @@
+dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5TVh4REs0RktFcXp4eFBDVHZKNnJVWGtVOW5hS3ZIbHBmODBscFhpVWNoa0FBQkFBQUFBQUFBQUFBQUlBQUFBQXZscEJOWS93WjNueTlmMmVvbGtaZGEraERTN3JHV25rdHNCTU1EZHZ4c1RUZHdJTFViQ3V4QTlSQzRXSSt2RE4vMXR3WW1jKzIyai9McFR4d2FFVTlPb3kwTDhIdFdSQnFEL0ZlN0xKa3hjMzB4WDJaejIybFVjWHo3em9sS0ZMNDk3dnpqYjhIdmc9Cg==

+ 1 - 0
.keys/tauri-signing.key.pub

@@ -0,0 +1 @@
+dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDc5NjdGMDhGMzU0MTVBQkUKUldTK1drRTFqL0JuZVE5UkM0V0krdkROLzF0d1ltYysyMmovTHBUeHdhRVU5T295MEw4SHRXUkIK

+ 17 - 5
build-win.bat

@@ -44,6 +44,16 @@ if errorlevel 1 (
 :: 显示 Node.js 版本
 for /f "tokens=*" %%i in ('node --version') do echo   [92m√[0m Node.js: %%i
 
+:: 设置 Tauri 签名密钥环境变量
+if exist ".keys\tauri-signing.key" (
+    echo   [92m√[0m 找到签名密钥
+    for /f "usebackq delims=" %%i in (".keys\tauri-signing.key") do set "TAURI_SIGNING_PRIVATE_KEY=%%i"
+    set "TAURI_SIGNING_PRIVATE_KEY_PASSWORD="
+) else (
+    echo   [93m![0m 未找到签名密钥 (.keys\tauri-signing.key)
+    echo   [94mi[0m 更新功能将不可用,构建将继续...
+)
+
 :: 检查 node_modules
 if not exist "node_modules" (
     echo.
@@ -107,11 +117,13 @@ echo     build-win.bat                    完整发布构建
 echo     build-win.bat --debug            调试构建
 echo     build-win.bat -s                 跳过前端,仅构建 Tauri
 echo.
-echo   输出:
-echo     release\*-nsis.exe                              (NSIS 安装程序)
-echo     release\*-portable.exe                          (便携版)
-echo     release\Claude-AI-Installer-x.x.x-portable\     (带启动器的便携版)
-echo     release\Claude-AI-Installer-x.x.x-portable.zip  (便携版压缩包)
+echo   输出 (发布模式):
+echo     src-tauri\target\release\bundle\nsis\*.exe      (NSIS 安装程序)
+echo     src-tauri\target\release\bundle\msi\*.msi       (MSI 安装程序)
+echo     src-tauri\target\release\claude-ai-installer.exe (可执行文件)
+echo.
+echo   输出 (调试模式):
+echo     src-tauri\target\debug\claude-ai-installer.exe  (调试版可执行文件)
 echo.
 echo   前置要求:
 echo     - Rust (https://rustup.rs/)

+ 0 - 164
launcher/launcher.js

@@ -1,164 +0,0 @@
-#!/usr/bin/env node
-/**
- * Claude AI Installer - Portable 启动器
- *
- * 功能:
- * 1. 检查 update 目录是否有新版本
- * 2. 如果有,替换 app 目录中的旧版本
- * 3. 启动主程序
- */
-
-const fs = require('fs')
-const path = require('path')
-const { spawn } = require('child_process')
-
-// 获取启动器所在目录
-const launcherDir = path.dirname(process.execPath)
-const appDir = path.join(launcherDir, 'app')
-const updateDir = path.join(launcherDir, 'update')
-const logFile = path.join(launcherDir, 'launcher.log')
-
-/**
- * 写入日志
- */
-function log(message) {
-  const timestamp = new Date().toISOString()
-  const logMessage = `[${timestamp}] ${message}\n`
-  console.log(message)
-  try {
-    fs.appendFileSync(logFile, logMessage)
-  } catch (e) {
-    // 忽略日志写入错误
-  }
-}
-
-/**
- * 查找目录中的 exe 文件
- */
-function findExeFile(dir) {
-  try {
-    const files = fs.readdirSync(dir)
-    const exeFile = files.find(f => f.endsWith('.exe') && f.includes('Claude-AI-Installer'))
-    return exeFile ? path.join(dir, exeFile) : null
-  } catch (e) {
-    return null
-  }
-}
-
-/**
- * 删除目录及其内容
- */
-function removeDir(dir) {
-  if (fs.existsSync(dir)) {
-    fs.rmSync(dir, { recursive: true, force: true })
-  }
-}
-
-/**
- * 复制文件
- */
-function copyFile(src, dest) {
-  fs.copyFileSync(src, dest)
-}
-
-/**
- * 应用更新
- */
-function applyUpdate() {
-  const updateExe = findExeFile(updateDir)
-
-  if (!updateExe) {
-    log('没有找到更新文件')
-    return false
-  }
-
-  log(`发现更新文件: ${updateExe}`)
-
-  try {
-    // 确保 app 目录存在
-    if (!fs.existsSync(appDir)) {
-      fs.mkdirSync(appDir, { recursive: true })
-    }
-
-    // 删除旧版本
-    const oldExe = findExeFile(appDir)
-    if (oldExe) {
-      log(`删除旧版本: ${oldExe}`)
-      fs.unlinkSync(oldExe)
-    }
-
-    // 移动新版本到 app 目录
-    const newExeName = path.basename(updateExe)
-    const destPath = path.join(appDir, newExeName)
-    log(`安装新版本: ${destPath}`)
-
-    // 复制文件(而不是移动,以便保留更新目录结构)
-    copyFile(updateExe, destPath)
-
-    // 清理更新目录
-    removeDir(updateDir)
-    log('更新完成')
-
-    return true
-  } catch (error) {
-    log(`更新失败: ${error.message}`)
-    return false
-  }
-}
-
-/**
- * 启动主程序
- */
-function launchApp() {
-  const appExe = findExeFile(appDir)
-
-  if (!appExe) {
-    log('错误: 找不到主程序')
-
-    // 尝试在启动器目录查找
-    const fallbackExe = findExeFile(launcherDir)
-    if (fallbackExe && !fallbackExe.includes('launcher')) {
-      log(`使用备用程序: ${fallbackExe}`)
-      spawn(fallbackExe, [], { detached: true, stdio: 'ignore' }).unref()
-      return
-    }
-
-    process.exit(1)
-  }
-
-  log(`启动主程序: ${appExe}`)
-
-  // 启动主程序并退出启动器
-  const child = spawn(appExe, [], {
-    detached: true,
-    stdio: 'ignore',
-    cwd: appDir
-  })
-
-  child.unref()
-}
-
-/**
- * 主函数
- */
-function main() {
-  log('========== 启动器开始 ==========')
-  log(`启动器目录: ${launcherDir}`)
-  log(`应用目录: ${appDir}`)
-  log(`更新目录: ${updateDir}`)
-
-  // 检查并应用更新
-  if (fs.existsSync(updateDir)) {
-    log('检测到更新目录,尝试应用更新...')
-    applyUpdate()
-  }
-
-  // 启动主程序
-  launchApp()
-
-  log('启动器退出')
-  process.exit(0)
-}
-
-// 运行
-main()

+ 3 - 3
release-win.bat

@@ -55,10 +55,10 @@ goto :parse_args
 :run_release
 echo.
 echo   [96m^> 调用 Node.js 发布脚本...[0m
-echo   [94mi[0m 执行: node scripts/release.js %NODE_ARGS%
+echo   [94mi[0m 执行: node scripts/release.cjs %NODE_ARGS%
 echo.
 
-call node scripts/release.js %NODE_ARGS%
+call node scripts/release.cjs %NODE_ARGS%
 if errorlevel 1 (
     echo.
     echo   [91mx[0m 发布失败!
@@ -104,7 +104,7 @@ echo   输出:
 echo     release\Claude-AI-Installer-x.x.x-win-x64-setup.exe     (NSIS 安装程序)
 echo     release\Claude-AI-Installer-x.x.x-win-x64.exe           (便携版)
 echo.
-echo   注意: 此脚本调用 scripts/release.js 执行实际发布
+echo   注意: 此脚本调用 scripts/release.cjs 执行实际发布
 echo         Windows 上默认只构建 win 平台
 echo.
 goto :eof

+ 50 - 242
scripts/build.js

@@ -43,8 +43,6 @@ const log = {
 // 项目路径
 const PROJECT_ROOT = path.resolve(__dirname, '..');
 const TAURI_DIR = path.join(PROJECT_ROOT, 'src-tauri');
-const RELEASE_DIR = path.join(PROJECT_ROOT, 'release');
-const LAUNCHER_DIR = path.join(PROJECT_ROOT, 'launcher');
 
 // 解析命令行参数
 function parseArgs() {
@@ -94,12 +92,16 @@ ${colors.cyan}示例:${colors.reset}
   node scripts/build.js --debug        # 调试构建
   node scripts/build.js -s             # 跳过前端,仅构建 Tauri
 
-${colors.cyan}输出:${colors.reset}
-  release/                                          # 最终发布目录
-    ├── *-nsis.exe                                  # NSIS 安装程序
-    ├── *-portable.exe                              # 便携版
-    └── Claude-AI-Installer-x.x.x-portable/         # 带启动器的便携版
-        └── Claude-AI-Installer-x.x.x-portable.zip  # 便携版压缩包
+${colors.cyan}输出 (发布模式):${colors.reset}
+  src-tauri/target/release/bundle/
+    ├── nsis/*.exe                     # NSIS 安装程序
+    └── msi/*.msi                      # MSI 安装程序
+  src-tauri/target/release/
+    └── claude-ai-installer.exe        # 可执行文件
+
+${colors.cyan}输出 (调试模式):${colors.reset}
+  src-tauri/target/debug/
+    └── claude-ai-installer.exe        # 调试版可执行文件
 `);
 }
 
@@ -133,19 +135,6 @@ function getProductName() {
   return tauriConf.productName || 'Claude AI Installer';
 }
 
-// 清理旧的构建文件
-function cleanBuild() {
-  log.step('清理旧的构建文件...');
-
-  // 清空 release 目录
-  if (fs.existsSync(RELEASE_DIR)) {
-    fs.rmSync(RELEASE_DIR, { recursive: true, force: true });
-  }
-  fs.mkdirSync(RELEASE_DIR, { recursive: true });
-
-  log.success('清理完成');
-}
-
 // 构建 Tauri 应用
 function buildTauri(options) {
   log.step(`构建 Tauri 应用 (${options.debug ? '调试' : '发布'}模式)...`);
@@ -162,228 +151,55 @@ function buildTauri(options) {
   log.success('Tauri 构建完成');
 }
 
-// 获取 Tauri 生成的 exe 文件名(小写,空格转连字符)
-function getTauriExeName() {
-  const productName = getProductName();
-  // Tauri 将产品名称转换为小写并用连字符替换空格
-  return productName.toLowerCase().replace(/\s+/g, '-') + '.exe';
-}
-
-// 复制构建产物到 release 目录
-function copyArtifacts(options) {
-  log.step('复制构建产物到 release 目录...');
+// 显示构建结果
+function showResults(options) {
+  log.step('构建结果:');
 
   const mode = options.debug ? 'debug' : 'release';
-  const bundleDir = path.join(TAURI_DIR, 'target', mode, 'bundle');
-  const nsisDir = path.join(bundleDir, 'nsis');
-
-  // 复制 NSIS 安装程序
-  if (fs.existsSync(nsisDir)) {
-    const files = fs.readdirSync(nsisDir);
-    for (const file of files) {
-      if (file.endsWith('.exe')) {
-        const src = path.join(nsisDir, file);
-        const dest = path.join(RELEASE_DIR, file);
-        fs.copyFileSync(src, dest);
-        log.info(`复制: ${file}`);
-      }
-    }
-  }
-
-  // 复制独立 exe (portable)
-  const exeName = getTauriExeName();
-  const portableExe = path.join(TAURI_DIR, 'target', mode, exeName);
-  if (fs.existsSync(portableExe)) {
-    const version = getVersion();
-    const portableName = `Claude-AI-Installer_${version}_x64-portable.exe`;
-    const dest = path.join(RELEASE_DIR, portableName);
-    fs.copyFileSync(portableExe, dest);
-    log.info(`复制便携版: ${portableName}`);
-  } else {
-    log.warn(`未找到便携版 exe: ${portableExe}`);
-  }
-
-  log.success('构建产物复制完成');
-}
-
-// ==================== Portable 版本构建(带启动器)====================
-
-/**
- * 查找 portable exe 文件
- */
-function findPortableExe() {
-  const files = fs.readdirSync(RELEASE_DIR);
-  return files.find(f => f.includes('portable') && f.endsWith('.exe'));
-}
-
-/**
- * 使用 pkg 打包启动器
- */
-function buildLauncher() {
-  log.step('构建启动器...');
-
-  // 检查 launcher.js 是否存在
-  const launcherScript = path.join(LAUNCHER_DIR, 'launcher.js');
-  if (!fs.existsSync(launcherScript)) {
-    log.warn('launcher.js 不存在,跳过启动器构建');
-    return null;
-  }
-
-  // 检查是否安装了 pkg
-  try {
-    execSync('npx pkg --version', { stdio: 'ignore' });
-  } catch {
-    log.info('安装 pkg...');
-    execSync('npm install -g pkg', { stdio: 'inherit' });
-  }
-
-  const outputPath = path.join(RELEASE_DIR, 'launcher.exe');
-
-  // 使用 pkg 打包
-  execSync(`npx pkg "${launcherScript}" --target node18-win-x64 --output "${outputPath}"`, {
-    stdio: 'inherit',
-    cwd: PROJECT_ROOT,
-  });
-
-  log.success(`启动器构建完成: ${outputPath}`);
-  return outputPath;
-}
-
-/**
- * 创建 Portable 目录结构
- */
-function createPortableStructure(portableExe, launcherExe) {
-  const version = getVersion();
-  const portableDirName = `Claude-AI-Installer-${version}-portable`;
-  const portableDir = path.join(RELEASE_DIR, portableDirName);
-  const appDir = path.join(portableDir, 'app');
-  const updateDir = path.join(portableDir, 'update');
-
-  log.step('创建 Portable 目录结构...');
-
-  // 清理旧目录
-  if (fs.existsSync(portableDir)) {
-    fs.rmSync(portableDir, { recursive: true });
-  }
-
-  // 创建目录
-  fs.mkdirSync(appDir, { recursive: true });
-  fs.mkdirSync(updateDir, { recursive: true });
-
-  // 复制启动器
-  const launcherDest = path.join(portableDir, 'Claude-AI-Installer.exe');
-  fs.copyFileSync(launcherExe, launcherDest);
-  log.info(`复制启动器: ${launcherDest}`);
+  const targetDir = path.join(TAURI_DIR, 'target', mode);
+  const bundleDir = path.join(targetDir, 'bundle');
 
-  // 复制主程序到 app 目录
-  const portableExePath = path.join(RELEASE_DIR, portableExe);
-  const appExeName = `Claude-AI-Installer-${version}.exe`;
-  const appExeDest = path.join(appDir, appExeName);
-  fs.copyFileSync(portableExePath, appExeDest);
-  log.info(`复制主程序: ${appExeDest}`);
-
-  // 创建 .gitkeep 文件保持 update 目录
-  fs.writeFileSync(path.join(updateDir, '.gitkeep'), '');
-
-  // 创建 README
-  const readme = `Claude AI Installer - Portable 版本
-
-使用方法:
-1. 双击 Claude-AI-Installer.exe 启动程序
-2. 程序会自动检查更新
-3. 更新下载后,重启程序即可完成更新
-
-目录说明:
-- Claude-AI-Installer.exe: 启动器
-- app/: 主程序目录
-- update/: 更新文件临时目录
-
-版本: ${version}
-`;
-  fs.writeFileSync(path.join(portableDir, 'README.txt'), readme, 'utf8');
-
-  log.success(`Portable 目录创建完成: ${portableDir}`);
-
-  // 创建 zip 包
-  createPortableZip(portableDir, portableDirName);
-
-  return portableDir;
-}
-
-/**
- * 创建 ZIP 压缩包
- */
-function createPortableZip(sourceDir, name) {
-  const zipPath = path.join(RELEASE_DIR, `${name}.zip`);
-
-  log.step('创建 ZIP 压缩包...');
-
-  // 使用 PowerShell 创建 zip
-  const psCommand = `Compress-Archive -Path "${sourceDir}\\*" -DestinationPath "${zipPath}" -Force`;
-  execSync(`powershell -Command "${psCommand}"`, { stdio: 'inherit' });
-
-  log.success(`ZIP 压缩包创建完成: ${zipPath}`);
-}
-
-/**
- * 构建 Portable 版本(带启动器)
- */
-function buildPortableVersion() {
-  log.step('构建 Portable 版本(带启动器)...');
-
-  // 查找 portable exe
-  const portableExe = findPortableExe();
-  if (!portableExe) {
-    log.warn('未找到 portable exe 文件,跳过带启动器的 Portable 版本构建');
-    return;
-  }
-  log.info(`找到 Portable 文件: ${portableExe}`);
+  console.log('');
 
-  // 构建启动器
-  const launcherExe = buildLauncher();
-  if (!launcherExe) {
-    log.warn('启动器构建失败,跳过带启动器的 Portable 版本构建');
-    return;
+  // 显示可执行文件
+  const exeName = 'claude-ai-installer.exe';
+  const exePath = path.join(targetDir, exeName);
+  if (fs.existsSync(exePath)) {
+    const stats = fs.statSync(exePath);
+    const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
+    console.log(`  ${colors.green}•${colors.reset} ${exeName} (${sizeMB} MB)`);
+    log.info(`  路径: ${exePath}`);
   }
 
-  // 创建 Portable 目录结构
-  createPortableStructure(portableExe, launcherExe);
-
-  // 清理临时的 launcher.exe
-  fs.unlinkSync(launcherExe);
-
-  log.success('Portable 版本构建完成');
-}
-
-// 显示构建结果
-function showResults() {
-  log.step('构建结果:');
-
-  if (!fs.existsSync(RELEASE_DIR)) {
-    log.warn('release 目录不存在');
-    return;
+  // 显示 NSIS 安装程序
+  const nsisDir = path.join(bundleDir, 'nsis');
+  if (fs.existsSync(nsisDir)) {
+    const files = fs.readdirSync(nsisDir).filter(f => f.endsWith('.exe'));
+    for (const file of files) {
+      const filePath = path.join(nsisDir, file);
+      const stats = fs.statSync(filePath);
+      const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
+      console.log(`  ${colors.green}•${colors.reset} nsis/${file} (${sizeMB} MB)`);
+    }
   }
 
-  const files = fs.readdirSync(RELEASE_DIR);
-  const packages = files.filter(f => {
-    const ext = path.extname(f).toLowerCase();
-    return ['.exe', '.zip'].includes(ext);
-  });
-
-  if (packages.length === 0) {
-    log.warn('未找到打包文件');
-    return;
+  // 显示 MSI 安装程序
+  const msiDir = path.join(bundleDir, 'msi');
+  if (fs.existsSync(msiDir)) {
+    const files = fs.readdirSync(msiDir).filter(f => f.endsWith('.msi'));
+    for (const file of files) {
+      const filePath = path.join(msiDir, file);
+      const stats = fs.statSync(filePath);
+      const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
+      console.log(`  ${colors.green}•${colors.reset} msi/${file} (${sizeMB} MB)`);
+    }
   }
 
   console.log('');
-  for (const pkg of packages) {
-    const filePath = path.join(RELEASE_DIR, pkg);
-    const stats = fs.statSync(filePath);
-    const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
-    console.log(`  ${colors.green}•${colors.reset} ${pkg} (${sizeMB} MB)`);
+  log.info(`输出目录: ${targetDir}`);
+  if (fs.existsSync(bundleDir)) {
+    log.info(`安装包目录: ${bundleDir}`);
   }
-  console.log('');
-  log.info(`输出目录: ${RELEASE_DIR}`);
 }
 
 // 主函数
@@ -403,25 +219,17 @@ ${colors.bright}╔════════════════════
 `);
 
   log.info(`构建模式: ${options.debug ? '调试' : '发布'}`);
-  log.info(`跳过前端: ${options.skipFrontend}`);
+  log.info(`版本: ${getVersion()}`);
+  log.info(`产品名称: ${getProductName()}`);
 
   const startTime = Date.now();
 
   try {
-    // 清理旧的构建文件
-    cleanBuild();
-
     // 构建 Tauri 应用
     buildTauri(options);
 
-    // 复制构建产物
-    copyArtifacts(options);
-
-    // 构建带启动器的 Portable 版本
-    buildPortableVersion();
-
     // 显示结果
-    showResults();
+    showResults(options);
 
     const duration = ((Date.now() - startTime) / 1000).toFixed(1);
     log.success(`构建完成! 耗时: ${duration}s`);

+ 0 - 0
scripts/release.js → scripts/release.cjs


+ 4 - 2
src-tauri/tauri.conf.json

@@ -67,8 +67,10 @@
       "open": true
     },
     "updater": {
-      "pubkey": "",
-      "endpoints": []
+      "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDc5NjdGMDhGMzU0MTVBQkUKUldTK1drRTFqL0JuZVE5UkM0V0krdkROLzF0d1ltYysyMmovTHBUeHdhRVU5T295MEw4SHRXUkIK",
+      "endpoints": [
+        "https://github.com/Apq/ClaudeCodeInstaller/releases/latest/download/latest.json"
+      ]
     }
   }
 }