


























@@ -1,3 +1,4 @@
1+// Shared update command primitives for channel resolution, install roots, and subprocess steps.
12import { spawnSync } from "node:child_process";
23import fs from "node:fs/promises";
34import os from "node:os";
@@ -56,6 +57,7 @@ export type UpdateWizardOptions = {
5657const INVALID_TIMEOUT_ERROR = "--timeout must be a positive integer (seconds)";
5758const MAX_SAFE_TIMEOUT_SECONDS = Math.floor(Number.MAX_SAFE_INTEGER / 1000);
585960+/** Parse a CLI timeout in seconds, exiting through the runtime on invalid input. */
5961export function parseTimeoutMsOrExit(timeout?: string): number | undefined | null {
6062if (timeout === undefined) {
6163return undefined;
@@ -76,6 +78,7 @@ const MAX_LOG_CHARS = 8000;
7678export const DEFAULT_PACKAGE_NAME = "openclaw";
7779const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME]);
788081+/** Normalize a CLI tag/version/spec into the npm target form accepted by update flows. */
7982export function normalizeTag(value?: string | null): string | null {
8083return normalizePackageTagInput(value, ["openclaw", DEFAULT_PACKAGE_NAME]);
8184}
@@ -91,6 +94,7 @@ function normalizeVersionTag(tag: string): string | null {
91949295export { readPackageName, readPackageVersion };
939697+/** Resolve an npm dist-tag or explicit version into a concrete package version. */
9498export async function resolveTargetVersion(
9599tag: string,
96100timeoutMs?: number,
@@ -106,6 +110,7 @@ export async function resolveTargetVersion(
106110return res.version ?? null;
107111}
108112113+/** Return true when `root` is a local git checkout directory. */
109114export async function isGitCheckout(root: string): Promise<boolean> {
110115try {
111116await fs.stat(path.join(root, ".git"));
@@ -120,6 +125,7 @@ async function isCorePackage(root: string): Promise<boolean> {
120125return Boolean(name && CORE_PACKAGE_NAMES.has(name));
121126}
122127128+/** Return true only for existing directories with no entries. */
123129export async function isEmptyDir(targetPath: string): Promise<boolean> {
124130try {
125131const entries = await fs.readdir(targetPath);
@@ -129,6 +135,7 @@ export async function isEmptyDir(targetPath: string): Promise<boolean> {
129135}
130136}
131137138+/** Resolve the checkout path used by source-based self-update. */
132139export function resolveGitInstallDir(): string {
133140const override = process.env.OPENCLAW_GIT_DIR?.trim();
134141if (override) {
@@ -145,6 +152,7 @@ function resolveDefaultGitDir(): string {
145152return path.join(home, "openclaw");
146153}
147154155+/** Prefer the current Node executable, falling back to `node` when run through another shim. */
148156export function resolveNodeRunner(): string {
149157const base = normalizeLowercaseStringOrEmpty(path.basename(process.execPath));
150158if (base === "node" || base === "node.exe") {
@@ -153,6 +161,7 @@ export function resolveNodeRunner(): string {
153161return "node";
154162}
155163164+/** Locate the installed OpenClaw package root that should receive update operations. */
156165export async function resolveUpdateRoot(): Promise<string> {
157166return (
158167(await resolveOpenClawPackageRoot({
@@ -163,6 +172,7 @@ export async function resolveUpdateRoot(): Promise<string> {
163172);
164173}
165174175+/** Run one update subprocess and report bounded stdout/stderr tails to progress listeners. */
166176export async function runUpdateStep(params: {
167177name: string;
168178argv: string[];
@@ -209,6 +219,7 @@ export async function runUpdateStep(params: {
209219};
210220}
211221222+/** Ensure the configured source-update directory exists and points at an OpenClaw checkout. */
212223export async function ensureGitCheckout(params: {
213224dir: string;
214225timeoutMs: number;
@@ -253,6 +264,7 @@ export async function ensureGitCheckout(params: {
253264return null;
254265}
255266267+/** Detect the package manager that owns a global/package OpenClaw install. */
256268export async function resolveGlobalManager(params: {
257269root: string;
258270installKind: "git" | "package" | "unknown";
@@ -279,6 +291,7 @@ const COMPLETION_CACHE_WRITE_TIMEOUT_MS = 30_000;
279291const COMPLETION_CACHE_MANUAL_REFRESH_HINT =
280292"Shell tab-completion may be stale; refresh manually with: openclaw completion --write-state";
281293294+/** Best-effort refresh of shell completion state after a successful update. */
282295export async function tryWriteCompletionCache(root: string, jsonMode: boolean): Promise<void> {
283296const binPath = path.join(root, "openclaw.mjs");
284297if (!(await pathExists(binPath))) {
@@ -322,6 +335,7 @@ export async function tryWriteCompletionCache(root: string, jsonMode: boolean):
322335}
323336}
324337338+/** Adapter used by global-install detection helpers to execute bounded subprocess probes. */
325339export function createGlobalCommandRunner(): CommandRunner {
326340return async (argv, options) => {
327341const res = await runCommandWithTimeout(argv, options);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。