


















@@ -1,4 +1,4 @@
1-import { spawn } from "node:child_process";
1+import { spawn, type ChildProcess } from "node:child_process";
22import fs from "node:fs/promises";
33import os from "node:os";
44import path from "node:path";
@@ -110,6 +110,7 @@ const POST_CORE_UPDATE_ENV = "OPENCLAW_UPDATE_POST_CORE";
110110const POST_CORE_UPDATE_CHANNEL_ENV = "OPENCLAW_UPDATE_POST_CORE_CHANNEL";
111111const POST_CORE_UPDATE_REQUESTED_CHANNEL_ENV = "OPENCLAW_UPDATE_POST_CORE_REQUESTED_CHANNEL";
112112const POST_CORE_UPDATE_RESULT_PATH_ENV = "OPENCLAW_UPDATE_POST_CORE_RESULT_PATH";
113+const POST_CORE_UPDATE_RESULT_POLL_MS = 100;
113114const UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE_ENV =
114115"OPENCLAW_UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE";
115116const SERVICE_REFRESH_PATH_ENV_KEYS = [
@@ -1608,6 +1609,25 @@ async function readPostCorePluginUpdateResultFile(
16081609return undefined;
16091610}
161016111612+function stopPostCoreUpdateChild(child: ChildProcess): void {
1613+if (process.platform === "win32" && child.pid) {
1614+try {
1615+const killer = spawn("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
1616+stdio: "ignore",
1617+windowsHide: true,
1618+});
1619+killer.once("error", () => {
1620+child.kill();
1621+});
1622+return;
1623+} catch {
1624+child.kill();
1625+return;
1626+}
1627+}
1628+child.kill();
1629+}
1630+16111631async function continuePostCoreUpdateInFreshProcess(params: {
16121632root: string;
16131633channel: "stable" | "beta" | "dev";
@@ -1632,11 +1652,8 @@ async function continuePostCoreUpdateInFreshProcess(params: {
16321652if (params.opts.timeout) {
16331653argv.push("--timeout", params.opts.timeout);
16341654}
1635-const resultDir =
1636-params.opts.json === true
1637- ? await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-post-core-"))
1638- : null;
1639-const resultPath = resultDir ? path.join(resultDir, "plugins.json") : null;
1655+const resultDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-post-core-"));
1656+const resultPath = path.join(resultDir, "plugins.json");
1640165716411658try {
16421659const child = spawn(resolveNodeRunner(), argv, {
@@ -1648,24 +1665,65 @@ async function continuePostCoreUpdateInFreshProcess(params: {
16481665 ...(params.requestedChannel
16491666 ? { [POST_CORE_UPDATE_REQUESTED_CHANNEL_ENV]: params.requestedChannel }
16501667 : {}),
1651-...(resultPath ? { [POST_CORE_UPDATE_RESULT_PATH_ENV]: resultPath } : {}),
1668+[POST_CORE_UPDATE_RESULT_PATH_ENV]: resultPath,
16521669},
16531670});
165416711655-const exitCode = await new Promise<number>((resolve, reject) => {
1656-child.once("error", reject);
1672+const childResult = await new Promise<
1673+| { kind: "exit"; exitCode: number }
1674+| { kind: "plugin-update"; pluginUpdate: PostCorePluginUpdateResult }
1675+>((resolve, reject) => {
1676+let settled = false;
1677+const finish = (
1678+result:
1679+| { kind: "exit"; exitCode: number }
1680+| { kind: "plugin-update"; pluginUpdate: PostCorePluginUpdateResult },
1681+) => {
1682+if (settled) {
1683+return;
1684+}
1685+settled = true;
1686+clearInterval(resultPoll);
1687+resolve(result);
1688+};
1689+const resultPoll = setInterval(() => {
1690+void readPostCorePluginUpdateResultFile(resultPath)
1691+.then((pluginUpdate) => {
1692+if (!pluginUpdate) {
1693+return;
1694+}
1695+stopPostCoreUpdateChild(child);
1696+finish({ kind: "plugin-update", pluginUpdate });
1697+})
1698+.catch(() => undefined);
1699+}, POST_CORE_UPDATE_RESULT_POLL_MS);
1700+child.once("error", (error) => {
1701+if (settled) {
1702+return;
1703+}
1704+settled = true;
1705+clearInterval(resultPoll);
1706+reject(error);
1707+});
16571708child.once("exit", (code, signal) => {
1709+if (settled) {
1710+return;
1711+}
16581712if (signal) {
1713+settled = true;
1714+clearInterval(resultPoll);
16591715reject(new Error(`post-update process terminated by signal ${signal}`));
16601716return;
16611717}
1662-resolve(code ?? 1);
1718+finish({ kind: "exit", exitCode: code ?? 1 });
16631719});
16641720});
166517211666-const pluginUpdate = resultPath
1667- ? await readPostCorePluginUpdateResultFile(resultPath)
1668- : undefined;
1722+const pluginUpdate =
1723+childResult.kind === "plugin-update"
1724+ ? childResult.pluginUpdate
1725+ : await readPostCorePluginUpdateResultFile(resultPath);
1726+const exitCode = childResult.kind === "exit" ? childResult.exitCode : 0;
16691727if (exitCode !== 0) {
16701728if (pluginUpdate) {
16711729return { resumed: true, pluginUpdate };
@@ -1675,9 +1733,7 @@ async function continuePostCoreUpdateInFreshProcess(params: {
16751733}
16761734return { resumed: true, ...(pluginUpdate ? { pluginUpdate } : {}) };
16771735} finally {
1678-if (resultDir) {
1679-await fs.rm(resultDir, { recursive: true, force: true }).catch(() => undefined);
1680-}
1736+await fs.rm(resultDir, { recursive: true, force: true }).catch(() => undefined);
16811737}
16821738}
16831739@@ -1752,11 +1808,13 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
17521808 opts,
17531809timeoutMs: updateStepTimeoutMs,
17541810});
1755-if (opts.json) {
1811+if (process.env[POST_CORE_UPDATE_RESULT_PATH_ENV]) {
17561812await writePostCorePluginUpdateResultFile(
17571813process.env[POST_CORE_UPDATE_RESULT_PATH_ENV],
17581814pluginUpdate,
17591815);
1816+}
1817+if (opts.json) {
17601818if (!process.env[POST_CORE_UPDATE_RESULT_PATH_ENV]) {
17611819const result: UpdateRunResult = {
17621820status: pluginUpdate.status === "error" ? "error" : "ok",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。