mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-29 13:23:38 +00:00
* fix(respawn): rewrite pnpm versioned entry paths to stable wrapper During self-update the pnpm versioned directory (node_modules/.pnpm/openclaw@<ver>/) may be removed. If process.argv contains the versioned path, the respawned child fails to start because the entrypoint no longer exists. Detect pnpm versioned realpaths in spawnDetachedGatewayProcess and rewrite them to the stable node_modules/<pkg>/openclaw.mjs wrapper before spawning. Fixes #52313 * fix(respawn): scope pnpm entry rewrite to openclaw --------- Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
This commit is contained in:
@@ -298,7 +298,7 @@ describe("respawnGatewayProcessForUpdate", () => {
|
||||
process.execArgv = [];
|
||||
process.argv = [
|
||||
"C:\\Program Files\\node.exe",
|
||||
"C:\\openclaw\\dist\\index.js",
|
||||
"C:\\openclaw\\node_modules\\.pnpm\\openclaw@2026.6.5\\node_modules\\openclaw\\dist\\index.js",
|
||||
"gateway",
|
||||
"run",
|
||||
];
|
||||
@@ -310,7 +310,7 @@ describe("respawnGatewayProcessForUpdate", () => {
|
||||
expect(result.pid).toBe(5151);
|
||||
expect(spawnMock).toHaveBeenCalledWith(
|
||||
process.execPath,
|
||||
["C:\\openclaw\\dist\\index.js", "gateway", "run"],
|
||||
["C:\\openclaw\\node_modules\\openclaw\\openclaw.mjs", "gateway", "run"],
|
||||
{
|
||||
detached: true,
|
||||
env: process.env,
|
||||
@@ -319,6 +319,50 @@ describe("respawnGatewayProcessForUpdate", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("rewrites a pnpm-versioned OpenClaw entry before detached update respawn", () => {
|
||||
clearSupervisorHints();
|
||||
setPlatform("linux");
|
||||
process.execArgv = [];
|
||||
process.argv = [
|
||||
"/usr/local/bin/node",
|
||||
"/app/node_modules/.pnpm/openclaw@2026.6.5/node_modules/openclaw/dist/entry.js",
|
||||
"gateway",
|
||||
"run",
|
||||
];
|
||||
spawnMock.mockReturnValue({ pid: 7171, unref: vi.fn(), kill: vi.fn() });
|
||||
|
||||
const result = respawnGatewayProcessForUpdate();
|
||||
|
||||
expect(result.mode).toBe("spawned");
|
||||
expect(spawnMock).toHaveBeenCalledWith(
|
||||
process.execPath,
|
||||
["/app/node_modules/openclaw/openclaw.mjs", "gateway", "run"],
|
||||
{
|
||||
detached: true,
|
||||
env: process.env,
|
||||
stdio: "inherit",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not rewrite another package's pnpm-versioned entry", () => {
|
||||
clearSupervisorHints();
|
||||
setPlatform("linux");
|
||||
process.execArgv = [];
|
||||
const entry =
|
||||
"/app/node_modules/.pnpm/@anthropic+sdk@1.0.0/node_modules/@anthropic/sdk/dist/index.js";
|
||||
process.argv = ["/usr/local/bin/node", entry, "gateway", "run"];
|
||||
spawnMock.mockReturnValue({ pid: 8181, unref: vi.fn(), kill: vi.fn() });
|
||||
|
||||
respawnGatewayProcessForUpdate();
|
||||
|
||||
expect(spawnMock).toHaveBeenCalledWith(process.execPath, [entry, "gateway", "run"], {
|
||||
detached: true,
|
||||
env: process.env,
|
||||
stdio: "inherit",
|
||||
});
|
||||
});
|
||||
|
||||
it("spawns a detached update process when macOS only has inherited XPC state", () => {
|
||||
clearSupervisorHints();
|
||||
setPlatform("darwin");
|
||||
|
||||
@@ -26,11 +26,28 @@ function isTruthy(value: string | undefined): boolean {
|
||||
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
||||
}
|
||||
|
||||
const PNPM_VERSIONED_OPENCLAW_ENTRY_PATTERN =
|
||||
/^(.*?)([\\/])node_modules\2\.pnpm\2openclaw@[^\\/]+\2node_modules\2openclaw\2.+$/;
|
||||
|
||||
function rewritePnpmVersionedOpenClawEntryPath(entryPath: string): string {
|
||||
// pnpm can expose argv[1] as a versioned realpath that self-update removes.
|
||||
// Respawn through the stable OpenClaw package wrapper instead.
|
||||
return entryPath.replace(
|
||||
PNPM_VERSIONED_OPENCLAW_ENTRY_PATTERN,
|
||||
"$1$2node_modules$2openclaw$2openclaw.mjs",
|
||||
);
|
||||
}
|
||||
|
||||
function spawnDetachedGatewayProcess(opts: GatewayRespawnOptions = {}): {
|
||||
child: ChildProcess;
|
||||
pid?: number;
|
||||
} {
|
||||
const args = [...process.execArgv, ...process.argv.slice(1)];
|
||||
const [entryArg, ...entryArgs] = process.argv.slice(1);
|
||||
const args = [
|
||||
...process.execArgv,
|
||||
...(entryArg ? [rewritePnpmVersionedOpenClawEntryPath(entryArg)] : []),
|
||||
...entryArgs,
|
||||
];
|
||||
const child = spawn(process.execPath, args, {
|
||||
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
||||
detached: true,
|
||||
|
||||
Reference in New Issue
Block a user