#!/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()