Implementation:Openclaw Openclaw UpdateCommand
UpdateCommand
This page documents the implementation of Version Update in the OpenClaw gateway. It covers the CLI-facing updateCommand function and the lower-level runGatewayUpdate engine that executes the actual update steps.
Source Locations
| Function | File | Lines |
|---|---|---|
updateCommand |
src/cli/update-cli.ts |
L689-1118 |
runGatewayUpdate |
src/infra/update-runner.ts |
L367-912 |
updateCommand
Signature
export async function updateCommand(opts: UpdateCommandOptions): Promise<void>
Purpose
updateCommand is the CLI entry point for the openclaw update command. It orchestrates the entire update lifecycle: channel resolution, version comparison, downgrade protection, the core update, plugin synchronization, shell completion, gateway restart, and post-update doctor checks.
Parameters
export type UpdateCommandOptions = {
json?: boolean;
restart?: boolean;
channel?: string;
tag?: string;
timeout?: string;
yes?: boolean;
};
| Option | Type | Description |
|---|---|---|
json |
boolean |
Output results as JSON (suppresses interactive UI). |
restart |
boolean |
Whether to restart the gateway after update. Default: true; --no-restart disables.
|
channel |
string |
Persist and switch to this update channel ("stable", "beta", or "dev").
|
tag |
string |
Override npm dist-tag or specific version for this update only. |
timeout |
string |
Timeout per step in seconds (default: 1200, i.e., 20 minutes). |
yes |
boolean |
Skip confirmation prompts (non-interactive mode). |
Behavior
Phase 1: Resolution
- Suppresses Node.js deprecation warnings for clean output.
- Resolves the package root via
resolveOpenClawPackageRoot. - Calls
checkUpdateStatusto determine the current install kind, version, and git state. - Reads the stored update channel from configuration and resolves the effective channel.
- Validates the
--channelargument if provided.
Phase 2: Channel and version negotiation
- Determines whether the update involves switching installation kinds (e.g., npm to git for
--channel dev, or git to npm for--channel stable). - For package installs:
- Resolves the target version from the npm registry via
resolveNpmChannelTagorresolveTargetVersion. - Compares current version against the target using
compareSemverStrings. - If the target is older (downgrade), prompts for confirmation unless
--yesis set.
- Resolves the target version from the npm registry via
- For git installs: notes that
--tagis ignored. - If a channel switch was requested, persists the new channel to configuration.
Phase 3: Core update
- Creates a progress controller with spinner UI (disabled in JSON mode).
- Delegates to the appropriate update path:
Switch to package (git -> npm):
- Detects the global package manager via
resolveGlobalManager. - Runs
globalInstallArgsto install the package at the target tag. - Optionally runs doctor via the new package's entry point.
Switch to git (npm -> git) or git update:
- For switching to git: ensures a git checkout exists at
~/.openclaw(orOPENCLAW_GIT_DIR) viaensureGitCheckout. - Calls
runGatewayUpdate(documented below) for the core git update. - For git-to-npm switches, additionally runs
globalInstallArgsto install from the updated checkout.
Phase 4: Post-update
- Prints the update result (status, before/after versions, step details).
- If the update failed or was skipped, exits with appropriate code and messaging.
- Plugin sync: Calls
syncPluginsForUpdateChannelto switch bundled/npm plugins as appropriate for the channel, thenupdateNpmInstalledPluginsto update remaining npm-installed plugins. - Shell completion: Calls
tryWriteCompletionCacheandtryInstallShellCompletion. - Gateway restart: If
restartistrue, callsrunDaemonRestart. On success, runs a non-interactivedoctorCommandpass. On failure, suggests manual restart. - Prints a random update quip for personality.
runGatewayUpdate
Signature
export async function runGatewayUpdate(opts: UpdateRunnerOptions = {}): Promise<UpdateRunResult>
Purpose
runGatewayUpdate is the core update engine that handles both git-based and package-manager-based updates. It detects the installation type, runs the appropriate steps, and returns a structured result.
Parameters
type UpdateRunnerOptions = {
cwd?: string;
argv1?: string;
tag?: string;
channel?: UpdateChannel;
timeoutMs?: number;
runCommand?: CommandRunner;
progress?: UpdateStepProgress;
};
| Option | Description |
|---|---|
cwd |
Working directory hint for locating the package root. |
argv1 |
Path to the CLI entry script (process.argv[1]) for resolving the install location.
|
tag |
npm dist-tag or version to install (for package updates). |
channel |
Update channel ("stable", "beta", or "dev"). Defaults to "dev" for git installs.
|
timeoutMs |
Timeout per step. Defaults to 20 minutes (1,200,000ms). |
runCommand |
Command runner function (injectable for testing). Defaults to runCommandWithTimeout.
|
progress |
Progress callback with onStepStart and onStepComplete hooks.
|
Behavior: Git Update (Dev Channel)
- Clean check -- Runs
git status --porcelain(excludingdist/control-ui/). Returnsstatus: "skipped"withreason: "dirty"if uncommitted changes exist. - Checkout main -- If not already on the
mainbranch, checks it out. - Upstream check -- Verifies an upstream tracking branch exists.
- Fetch -- Runs
git fetch --all --prune --tags. - Resolve upstream SHA -- Gets the upstream commit hash.
- Enumerate candidates -- Lists the most recent upstream commits (up to 10).
- Preflight testing -- Creates a temporary git worktree and for each candidate commit:
- Checks out the commit.
- Runs
pnpm install(or bun/npm based on lockfile detection). - Runs the build script.
- Runs the lint script.
- Selects the first commit where all steps pass.
- Preflight cleanup -- Removes the temporary worktree.
- Rebase -- Rebases onto the selected commit. If the rebase fails, runs
git rebase --abort.
Behavior: Git Update (Stable/Beta Channel)
- Fetch -- Runs
git fetch --all --prune --tags. - Resolve tag -- Finds the latest git tag matching the channel (stable tags for stable, beta-or-newer for beta).
- Checkout -- Detached checkout of the resolved tag.
Behavior: Common Post-Steps (Git)
- Install deps -- Runs the detected package manager's install command.
- Build -- Runs the
buildscript. - UI build -- Runs the
ui:buildscript. - Doctor entry check -- Verifies
openclaw.mjsexists in the root. - Doctor run -- Executes
openclaw doctor --non-interactivevia the updated entry point. - UI asset verification -- If control UI assets are missing after doctor, re-runs
ui:build. - Version capture -- Records the after SHA and version.
Behavior: Package Manager Update
If no git root is found but a package root exists, detects the global package manager and runs the appropriate install command (e.g., npm install -g openclaw@latest).
Return Value: UpdateRunResult
export type UpdateRunResult = {
status: "ok" | "error" | "skipped";
mode: "git" | "pnpm" | "bun" | "npm" | "unknown";
root?: string;
reason?: string;
before?: { sha?: string | null; version?: string | null };
after?: { sha?: string | null; version?: string | null };
steps: UpdateStepResult[];
durationMs: number;
};
export type UpdateStepResult = {
name: string;
command: string;
cwd: string;
durationMs: number;
exitCode: number | null;
stdoutTail?: string | null;
stderrTail?: string | null;
};
Dependencies
| Module | Purpose |
|---|---|
src/infra/update-channels.ts |
Channel normalization, npm tag mapping, and channel label formatting. |
src/infra/update-check.ts |
checkUpdateStatus, compareSemverStrings, fetchNpmTagVersion.
|
src/infra/update-global.ts |
Global package manager detection and install argument generation. |
src/process/exec.ts |
runCommandWithTimeout for spawning subprocesses.
|
src/plugins/update.ts |
syncPluginsForUpdateChannel and updateNpmInstalledPlugins.
|
src/cli/daemon-cli.ts |
runDaemonRestart for post-update gateway restart.
|
src/commands/doctor.ts |
doctorCommand for post-update diagnostic checks.
|
src/infra/control-ui-assets.ts |
UI asset health verification. |