diff --git a/scripts/e2e/parallels/npm-update-scripts.ts b/scripts/e2e/parallels/npm-update-scripts.ts index 0be413f9ca3..751f194be2d 100644 --- a/scripts/e2e/parallels/npm-update-scripts.ts +++ b/scripts/e2e/parallels/npm-update-scripts.ts @@ -11,6 +11,7 @@ export interface NpmUpdateScriptInput { export function macosUpdateScript(input: NpmUpdateScriptInput): string { return String.raw`set -euo pipefail +export PATH=/opt/homebrew/bin:/opt/homebrew/opt/node/bin:/opt/homebrew/sbin:/usr/bin:/bin:/usr/sbin:/sbin scrub_future_plugin_entries() { python3 - <<'PY' import json @@ -63,7 +64,7 @@ wait_for_gateway() { } scrub_future_plugin_entries stop_openclaw_gateway_processes -OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 /opt/homebrew/bin/openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json +OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 /opt/homebrew/bin/openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart ${posixVersionCheck("/opt/homebrew/bin/openclaw", input.expectedNeedle)} start_openclaw_gateway wait_for_gateway @@ -100,11 +101,15 @@ function Stop-OpenClawGatewayProcesses { Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -match 'openclaw.*gateway' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } + Get-NetTCPConnection -LocalPort 18789 -State Listen -ErrorAction SilentlyContinue | + Select-Object -ExpandProperty OwningProcess -Unique | + ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue } + Start-Sleep -Seconds 2 } Remove-FuturePluginEntries Stop-OpenClawGatewayProcesses $env:OPENCLAW_DISABLE_BUNDLED_PLUGINS = '1' -Invoke-OpenClaw update --tag ${psSingleQuote(input.updateTarget)} --yes --json +Invoke-OpenClaw update --tag ${psSingleQuote(input.updateTarget)} --yes --json --no-restart if ($LASTEXITCODE -ne 0) { throw "openclaw update failed with exit code $LASTEXITCODE" } $version = Invoke-OpenClaw --version $version @@ -120,6 +125,7 @@ Invoke-OpenClaw agent --local --agent main --session-id parallels-npm-update-win export function linuxUpdateScript(input: NpmUpdateScriptInput): string { return String.raw`set -euo pipefail +export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/snap/bin scrub_future_plugin_entries() { node - <<'JS' const fs = require("node:fs"); @@ -167,7 +173,7 @@ wait_for_gateway() { } scrub_future_plugin_entries stop_openclaw_gateway_processes -OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json +OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart ${posixVersionCheck("openclaw", input.expectedNeedle)} start_openclaw_gateway wait_for_gateway diff --git a/scripts/e2e/parallels/npm-update-smoke.ts b/scripts/e2e/parallels/npm-update-smoke.ts index c49c81a8159..497e3646370 100755 --- a/scripts/e2e/parallels/npm-update-smoke.ts +++ b/scripts/e2e/parallels/npm-update-smoke.ts @@ -442,14 +442,23 @@ class NpmUpdateSmoke { ctx: UpdateJobContext, ): Promise { const macosExecArgs = this.resolveMacosUpdateExecArgs(ctx); - const status = await this.runStreamingToJobLog( - "prlctl", - ["exec", macosVm, ...macosExecArgs, "/bin/bash", "-lc", script], - timeoutMs, - ctx, + const scriptPath = this.writeGuestScript( + macosVm, + script, + "openclaw-parallels-npm-update-macos", ); - if (status !== 0) { - throw new Error(`macOS update command failed with exit code ${status}`); + try { + const status = await this.runStreamingToJobLog( + "prlctl", + ["exec", macosVm, ...macosExecArgs, "/bin/bash", scriptPath], + timeoutMs, + ctx, + ); + if (status !== 0) { + throw new Error(`macOS update command failed with exit code ${status}`); + } + } finally { + this.removeGuestScript(macosVm, scriptPath); } } @@ -688,17 +697,64 @@ Remove-Item -Path $scriptPath, $logPath, $donePath, $exitPath -Force -ErrorActio timeoutMs: number, ctx: UpdateJobContext, ): Promise { - const status = await this.runStreamingToJobLog( - "prlctl", - ["exec", this.linuxVm, "/usr/bin/env", "HOME=/root", "bash", "-lc", script], - timeoutMs, - ctx, + const scriptPath = this.writeGuestScript( + this.linuxVm, + script, + "openclaw-parallels-npm-update-linux", ); - if (status !== 0) { - throw new Error(`Linux update command failed with exit code ${status}`); + try { + const status = await this.runStreamingToJobLog( + "prlctl", + [ + "exec", + this.linuxVm, + "/usr/bin/env", + "HOME=/root", + "PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/snap/bin", + "bash", + scriptPath, + ], + timeoutMs, + ctx, + ); + if (status !== 0) { + throw new Error(`Linux update command failed with exit code ${status}`); + } + } finally { + this.removeGuestScript(this.linuxVm, scriptPath); } } + private writeGuestScript(vm: string, script: string, prefix: string): string { + const scriptPath = `/tmp/${prefix}-${process.pid}-${Date.now()}.sh`; + const write = run("prlctl", ["exec", vm, "/usr/bin/tee", scriptPath], { + check: false, + input: script, + quiet: true, + timeoutMs: 120_000, + }); + if (write.status !== 0) { + throw new Error(`failed to write guest script ${scriptPath}: ${write.stderr.trim()}`); + } + const chmod = run("prlctl", ["exec", vm, "/bin/chmod", "700", scriptPath], { + check: false, + quiet: true, + timeoutMs: 30_000, + }); + if (chmod.status !== 0) { + throw new Error(`failed to chmod guest script ${scriptPath}: ${chmod.stderr.trim()}`); + } + return scriptPath; + } + + private removeGuestScript(vm: string, scriptPath: string): void { + run("prlctl", ["exec", vm, "/bin/rm", "-f", scriptPath], { + check: false, + quiet: true, + timeoutMs: 30_000, + }); + } + private async runStreamingToJobLog( command: string, args: string[],