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