From c034a178b965c3ba8794be000accfb9a3f7db0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E4=B8=AD=E6=B4=8B?= Date: Fri, 5 Jun 2026 18:06:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Windows=20=E4=B8=8B=20zmo=20upgrade=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - installation/index.ts 新增 Windows 升级路径:下载 release zip → PowerShell 解压 → 写 .cmd 在进程退出后替换 exe(绕过运行中文件锁) - method() 在 Windows 兜底返回 curl,让手动下载的 exe 也能走自动更新 - 修 cmd/upgrade.ts 残留的 "opencode upgrade skipped" 文案 Co-Authored-By: Claude Opus 4.7 --- packages/opencode/src/cli/cmd/upgrade.ts | 2 +- packages/opencode/src/installation/index.ts | 55 +++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/upgrade.ts b/packages/opencode/src/cli/cmd/upgrade.ts index 8e53521f1..d5217efda 100644 --- a/packages/opencode/src/cli/cmd/upgrade.ts +++ b/packages/opencode/src/cli/cmd/upgrade.ts @@ -46,7 +46,7 @@ export const UpgradeCommand = { const target = args.target ? args.target.replace(/^v/, "") : await Installation.latest() if (InstallationVersion === target) { - prompts.log.warn(`opencode upgrade skipped: ${target} is already installed`) + prompts.log.warn(`zmo upgrade skipped: ${target} is already installed`) prompts.outro("Done") return } diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index fa6324885..459341ddb 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -6,6 +6,8 @@ import { errorMessage } from "@/util/error" import { ChildProcess } from "effect/unstable/process" import { AppProcess } from "@opencode-ai/core/process" import path from "path" +import os from "os" +import fs from "fs" import { EventV2 } from "@opencode-ai/core/event" import * as Log from "@opencode-ai/core/util/log" import { makeRuntime } from "@opencode-ai/core/effect/runtime" @@ -155,8 +157,58 @@ export const layer: Layer.Layernul", + `:retry`, + `move /Y "${newExe}" "${exePath}" >nul 2>&1`, + `if errorlevel 1 (`, + ` ping 127.0.0.1 -n 2 >nul`, + ` goto retry`, + `)`, + `rmdir /S /Q "${tmpDir}" >nul 2>&1`, + ].join("\r\n") + fs.writeFileSync(cmdPath, script) + + // 4. detached 启动 cmd,本进程随后正常退出,让 cmd 完成替换 + Bun.spawn(["cmd", "/c", cmdPath], { stdio: ["ignore", "ignore", "ignore"] }).unref() + + return { code: 0, stdout: `zmo will finish updating to v${target} after exit. Please restart zmo.`, stderr: "" } + }, Effect.catch((err) => Effect.succeed({ code: 1, stdout: "", stderr: errorMessage(err) }))) + const upgradeCurl = Effect.fnUntraced( function* (target: string) { + if (process.platform === "win32") { + return yield* upgradeWindows(target) + } const response = yield* httpOk.execute(HttpClientRequest.get("https://raw.githubusercontent.com/helpLogin/zmo-cli/main/install")) const body = yield* response.text const bodyBytes = new TextEncoder().encode(body) @@ -216,6 +268,9 @@ export const layer: Layer.Layer