

























@@ -54,7 +54,6 @@ import { defaultRuntime } from "../../runtime.js";
5454import { normalizeOptionalString } from "../../shared/string-coerce.js";
5555import { stylePromptMessage } from "../../terminal/prompt-style.js";
5656import { theme } from "../../terminal/theme.js";
57-import { pathExists } from "../../utils.js";
5857import { replaceCliName, resolveCliName } from "../cli-name.js";
5958import { formatCliCommand } from "../command-format.js";
6059import { installCompletion } from "../completion-runtime.js";
@@ -93,6 +92,7 @@ const SERVICE_REFRESH_TIMEOUT_MS = 60_000;
9392const DEFAULT_UPDATE_STEP_TIMEOUT_MS = 30 * 60_000;
9493const POST_CORE_UPDATE_ENV = "OPENCLAW_UPDATE_POST_CORE";
9594const POST_CORE_UPDATE_CHANNEL_ENV = "OPENCLAW_UPDATE_POST_CORE_CHANNEL";
95+const POST_CORE_UPDATE_REQUESTED_CHANNEL_ENV = "OPENCLAW_UPDATE_POST_CORE_REQUESTED_CHANNEL";
9696const POST_CORE_UPDATE_RESULT_PATH_ENV = "OPENCLAW_UPDATE_POST_CORE_RESULT_PATH";
9797const SERVICE_REFRESH_PATH_ENV_KEYS = [
9898"OPENCLAW_HOME",
@@ -1093,6 +1093,40 @@ async function runPostCorePluginUpdate(params: {
10931093});
10941094}
109510951096+async function persistRequestedUpdateChannel(params: {
1097+configSnapshot: Awaited<ReturnType<typeof readConfigFileSnapshot>>;
1098+requestedChannel: "stable" | "beta" | "dev" | null;
1099+}): Promise<Awaited<ReturnType<typeof readConfigFileSnapshot>>> {
1100+if (!params.requestedChannel || !params.configSnapshot.valid) {
1101+return params.configSnapshot;
1102+}
1103+const storedChannel = normalizeUpdateChannel(params.configSnapshot.config.update?.channel);
1104+if (params.requestedChannel === storedChannel) {
1105+return params.configSnapshot;
1106+}
1107+1108+const next = {
1109+ ...params.configSnapshot.sourceConfig,
1110+update: {
1111+ ...params.configSnapshot.sourceConfig.update,
1112+channel: params.requestedChannel,
1113+},
1114+};
1115+await replaceConfigFile({
1116+nextConfig: next,
1117+baseHash: params.configSnapshot.hash,
1118+});
1119+return {
1120+ ...params.configSnapshot,
1121+hash: undefined,
1122+parsed: next,
1123+sourceConfig: asResolvedSourceConfig(next),
1124+resolved: asResolvedSourceConfig(next),
1125+runtimeConfig: asRuntimeConfig(next),
1126+config: asRuntimeConfig(next),
1127+};
1128+}
1129+10961130async function writePostCorePluginUpdateResultFile(
10971131filePath: string | undefined,
10981132result: PostCorePluginUpdateResult,
@@ -1125,10 +1159,11 @@ async function readPostCorePluginUpdateResultFile(
11251159async function continuePostCoreUpdateInFreshProcess(params: {
11261160root: string;
11271161channel: "stable" | "beta" | "dev";
1162+requestedChannel: "stable" | "beta" | "dev" | null;
11281163opts: UpdateCommandOptions;
11291164}): Promise<{ resumed: boolean; pluginUpdate?: PostCorePluginUpdateResult }> {
1130-const entryPath = path.join(params.root, "dist", "entry.js");
1131-if (!(await pathExists(entryPath))) {
1165+const entryPath = await resolveGatewayInstallEntrypoint(params.root);
1166+if (!entryPath) {
11321167return { resumed: false };
11331168}
11341169@@ -1158,6 +1193,9 @@ async function continuePostCoreUpdateInFreshProcess(params: {
11581193 ...disableUpdatedPackageCompileCacheEnv(process.env),
11591194[POST_CORE_UPDATE_ENV]: "1",
11601195[POST_CORE_UPDATE_CHANNEL_ENV]: params.channel,
1196+ ...(params.requestedChannel
1197+ ? { [POST_CORE_UPDATE_REQUESTED_CHANNEL_ENV]: params.requestedChannel }
1198+ : {}),
11611199 ...(resultPath ? { [POST_CORE_UPDATE_RESULT_PATH_ENV]: resultPath } : {}),
11621200},
11631201});
@@ -1195,14 +1233,32 @@ function shouldResumePostCoreUpdateInFreshProcess(params: {
11951233result: UpdateRunResult;
11961234downgradeRisk: boolean;
11971235}): boolean {
1198-return isPackageManagerUpdateMode(params.result.mode) && !params.downgradeRisk;
1236+if (params.downgradeRisk) {
1237+return false;
1238+}
1239+if (isPackageManagerUpdateMode(params.result.mode)) {
1240+return true;
1241+}
1242+if (params.result.mode !== "git") {
1243+return false;
1244+}
1245+const beforeSha = normalizeOptionalString(params.result.before?.sha);
1246+const afterSha = normalizeOptionalString(params.result.after?.sha);
1247+if (beforeSha && afterSha && beforeSha !== afterSha) {
1248+return true;
1249+}
1250+const beforeVersion = normalizeOptionalString(params.result.before?.version);
1251+const afterVersion = normalizeOptionalString(params.result.after?.version);
1252+return Boolean(beforeVersion && afterVersion && beforeVersion !== afterVersion);
11991253}
1200125412011255export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
12021256suppressDeprecations();
12031257const invocationCwd = tryResolveInvocationCwd();
12041258const postCoreUpdateResume = process.env[POST_CORE_UPDATE_ENV] === "1";
12051259const postCoreUpdateChannel = process.env[POST_CORE_UPDATE_CHANNEL_ENV]?.trim();
1260+const postCoreRequestedChannelInput =
1261+process.env[POST_CORE_UPDATE_REQUESTED_CHANNEL_ENV]?.trim() ?? "";
1206126212071263const timeoutMs = parseTimeoutMsOrExit(opts.timeout);
12081264const shouldRestart = opts.restart !== false;
@@ -1223,10 +1279,24 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
12231279return;
12241280}
122512811282+const postCoreRequestedChannel = postCoreRequestedChannelInput
1283+ ? normalizeUpdateChannel(postCoreRequestedChannelInput)
1284+ : null;
1285+if (postCoreRequestedChannelInput && !postCoreRequestedChannel) {
1286+defaultRuntime.error("Invalid post-core requested update channel context.");
1287+defaultRuntime.exit(1);
1288+return;
1289+}
1290+1291+const postCoreConfigSnapshot = await persistRequestedUpdateChannel({
1292+configSnapshot: await readConfigFileSnapshot(),
1293+requestedChannel: postCoreRequestedChannel,
1294+});
1295+12261296const pluginUpdate = await runPostCorePluginUpdate({
12271297 root,
12281298channel: postCoreUpdateChannel,
1229-configSnapshot: await readConfigFileSnapshot(),
1299+configSnapshot: postCoreConfigSnapshot,
12301300 opts,
12311301timeoutMs: updateStepTimeoutMs,
12321302});
@@ -1567,53 +1637,58 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
15671637return;
15681638}
156916391640+const shouldResumePostCoreInFreshProcess = shouldResumePostCoreUpdateInFreshProcess({
1641+ result,
1642+ downgradeRisk,
1643+});
1644+15701645let postUpdateConfigSnapshot = configSnapshot;
1571-if (requestedChannel && configSnapshot.valid && requestedChannel !== storedChannel) {
1572-const next = {
1573- ...configSnapshot.sourceConfig,
1574-update: {
1575- ...configSnapshot.sourceConfig.update,
1576-channel: requestedChannel,
1577-},
1578-};
1579-await replaceConfigFile({
1580-nextConfig: next,
1581-baseHash: configSnapshot.hash,
1646+if (!shouldResumePostCoreInFreshProcess) {
1647+postUpdateConfigSnapshot = await persistRequestedUpdateChannel({
1648+ configSnapshot,
1649+ requestedChannel,
15821650});
1583-postUpdateConfigSnapshot = {
1584- ...configSnapshot,
1585-hash: undefined,
1586-parsed: next,
1587-sourceConfig: asResolvedSourceConfig(next),
1588-resolved: asResolvedSourceConfig(next),
1589-runtimeConfig: asRuntimeConfig(next),
1590-config: asRuntimeConfig(next),
1591-};
1592-if (!opts.json) {
1593-defaultRuntime.log(theme.muted(`Update channel set to ${requestedChannel}.`));
1594-}
1651+}
1652+if (
1653+requestedChannel &&
1654+configSnapshot.valid &&
1655+requestedChannel !== storedChannel &&
1656+!shouldResumePostCoreInFreshProcess &&
1657+!opts.json
1658+) {
1659+defaultRuntime.log(theme.muted(`Update channel set to ${requestedChannel}.`));
1660+} else if (
1661+requestedChannel &&
1662+configSnapshot.valid &&
1663+requestedChannel !== storedChannel &&
1664+shouldResumePostCoreInFreshProcess &&
1665+!opts.json
1666+) {
1667+defaultRuntime.log(theme.muted(`Update channel will be set to ${requestedChannel}.`));
15951668}
1596166915971670const postUpdateRoot = result.root ?? root;
1598167115991672let postCorePluginUpdate: PostCorePluginUpdateResult | undefined;
16001673let pluginsUpdatedInFreshProcess = false;
1601-if (
1602-shouldResumePostCoreUpdateInFreshProcess({
1603- result,
1604- downgradeRisk,
1605-})
1606-) {
1674+if (shouldResumePostCoreInFreshProcess) {
16071675const freshProcessResult = await continuePostCoreUpdateInFreshProcess({
16081676root: postUpdateRoot,
16091677 channel,
1678+ requestedChannel,
16101679 opts,
16111680});
16121681pluginsUpdatedInFreshProcess = freshProcessResult.resumed;
16131682postCorePluginUpdate = freshProcessResult.pluginUpdate;
16141683}
1615168416161685if (!pluginsUpdatedInFreshProcess) {
1686+if (shouldResumePostCoreInFreshProcess) {
1687+postUpdateConfigSnapshot = await persistRequestedUpdateChannel({
1688+ configSnapshot,
1689+ requestedChannel,
1690+});
1691+}
16171692postCorePluginUpdate = await runPostCorePluginUpdate({
16181693root: postUpdateRoot,
16191694 channel,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。