fix(parallels): preserve plugin inventory during updates (#122912)

* fix(parallels): preserve plugin inventory during updates

* fix(parallels): preserve dev update plugin inventory
This commit is contained in:
Vincent Koc
2026-08-13 10:26:02 +08:00
committed by GitHub
parent dabf55727b
commit 3eef8ebfd5
5 changed files with 44 additions and 17 deletions
+1 -1
View File
@@ -970,7 +970,7 @@ config.update = { ...(config.update || {}), channel: "dev" };
fs.mkdirSync(path.dirname(configPath), { recursive: true });
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\\n");
JS
/usr/bin/env NODE_OPTIONS=--max-old-space-size=8192 OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS=1 OPENCLAW_DISABLE_BUNDLED_PLUGINS=1${devTargetEnv} ${guestOpenClawEntryRunner} update --channel dev --yes --json --no-restart --timeout ${this.updateDevTimeoutSeconds}
/usr/bin/env NODE_OPTIONS=--max-old-space-size=8192 OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS=1${devTargetEnv} ${guestOpenClawEntryRunner} update --channel dev --yes --json --no-restart --timeout ${this.updateDevTimeoutSeconds}
${guestOpenClawEntryRunner} --version
${guestOpenClawEntryRunner} update status --json`,
{},
+5 -5
View File
@@ -142,12 +142,12 @@ if [ "$agent_ok" != true ]; then
fi`;
}
function windowsUpdateWithBundledPluginsDisabled(input: NpmUpdateScriptInput): string {
function windowsUpdateWithScopedEnv(input: NpmUpdateScriptInput): string {
const registryEntry = input.npmRegistry
? `; NPM_CONFIG_REGISTRY = ${psSingleQuote(input.npmRegistry)}`
: "";
return `$script:OpenClawUpdateExit = 0
$updateOutput = Invoke-WithScopedEnv @{ OPENCLAW_DISABLE_BUNDLED_PLUGINS = '1'; OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS = '1'${registryEntry} } {
$updateOutput = Invoke-WithScopedEnv @{ OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS = '1'${registryEntry} } {
Invoke-OpenClaw update --tag ${psSingleQuote(input.updateTarget)} --yes --json --no-restart 2>&1
$script:OpenClawUpdateExit = $LASTEXITCODE
}
@@ -285,7 +285,7 @@ wait_for_gateway() {
}
scrub_future_plugin_entries
stop_openclaw_gateway_processes
${posixNpmRegistryEnv(input.npmRegistry)}OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS=1 OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 "$OPENCLAW_BIN" update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart
${posixNpmRegistryEnv(input.npmRegistry)}OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS=1 "$OPENCLAW_BIN" update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart
${posixVersionCheck(macosOpenClawCommand, input.expectedNeedle)}
start_openclaw_gateway
wait_for_gateway
@@ -360,7 +360,7 @@ function Stop-OpenClawGatewayProcesses {
}
Remove-FuturePluginEntries
Stop-OpenClawGatewayProcesses
${windowsUpdateWithBundledPluginsDisabled(input)}
${windowsUpdateWithScopedEnv(input)}
if ($updateExit -ne 0) {
$updateText = $updateOutput | Out-String
$stalePostSwapImport = $updateText -match 'ERR_MODULE_NOT_FOUND' -and $updateText -match ${psSingleQuote(windowsStalePostSwapImportRegex)}
@@ -429,7 +429,7 @@ wait_for_gateway() {
}
scrub_future_plugin_entries
stop_openclaw_gateway_processes
${posixNpmRegistryEnv(input.npmRegistry)}OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS=1 OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart
${posixNpmRegistryEnv(input.npmRegistry)}OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS=1 openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart
${posixVersionCheck("openclaw", input.expectedNeedle)}
start_openclaw_gateway
wait_for_gateway
+1 -1
View File
@@ -687,7 +687,7 @@ $config.update | Add-Member -Force -MemberType NoteProperty -Name channel -Value
$config | ConvertTo-Json -Depth 100 | Set-Content -Path $configPath -Encoding utf8
${windowsScopedEnvFunction}
$script:OpenClawUpdateExit = 0
Invoke-WithScopedEnv @{ OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS = '1'; OPENCLAW_DISABLE_BUNDLED_PLUGINS = '1'${devTargetEntry} } {
Invoke-WithScopedEnv @{ OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS = '1'${devTargetEntry} } {
Invoke-OpenClaw update --channel dev --yes --json --no-restart --timeout ${this.updateTimeoutSeconds}
$script:OpenClawUpdateExit = $LASTEXITCODE
}
@@ -1177,23 +1177,40 @@ exit 7
);
expect(windowsScript).toContain("Remove-FuturePluginEntries\nStop-OpenClawGatewayProcesses");
expect(script).toContain("scrub_future_plugin_entries\nstop_openclaw_gateway_processes");
expect(script).toContain("Invoke-WithScopedEnv @{ OPENCLAW_DISABLE_BUNDLED_PLUGINS = '1'");
expect(macosScript).toContain('OPENCLAW_BIN="$(resolve_required_command openclaw)"');
expect(macosScript).toContain("/usr/local/bin:/usr/local/sbin");
expect(macosScript).toContain(
'OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 "$OPENCLAW_BIN" update --tag',
);
expect(macosScript).not.toContain("/opt/homebrew/bin/openclaw");
expect(script).toContain("OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 openclaw update --tag");
});
it("preserves bundled plugin inventory during updates while isolating POSIX gateway stops", () => {
const input = {
auth: TEST_AUTH,
expectedNeedle: "2026.5.3-beta.2",
updateTarget: "2026.5.3-beta.2",
};
const windowsScript = windowsUpdateScript(input);
const macosScript = macosUpdateScript(input);
const linuxScript = linuxUpdateScript(input);
const updateLines = [windowsScript, macosScript, linuxScript].map((generatedScript) =>
generatedScript.split("\n").find((line) => line.includes(" update --tag ")),
);
expect(updateLines).not.toContain(undefined);
for (const updateLine of updateLines) {
expect(updateLine).not.toContain("OPENCLAW_DISABLE_BUNDLED_PLUGINS");
}
expect(windowsScript).toContain(
"Invoke-WithScopedEnv @{ OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS = '1'",
);
expect(macosScript).toContain(
'OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 "$OPENCLAW_BIN" gateway stop',
);
expect(script).toContain(
expect(linuxScript).toContain(
"OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 OPENCLAW_ALLOW_ROOT=1 openclaw gateway stop",
);
});
it("reenables bundled plugins before Windows post-update verification", () => {
it("limits the Windows update environment to the update invocation", () => {
const script = windowsUpdateScript({
auth: TEST_AUTH,
expectedNeedle: "2026.5.3-beta.2",
@@ -1201,7 +1218,9 @@ exit 7
});
const updateIndex = script.indexOf("Invoke-OpenClaw update --tag");
const scopedIndex = script.indexOf("Invoke-WithScopedEnv @{ OPENCLAW_DISABLE_BUNDLED_PLUGINS");
const scopedIndex = script.indexOf(
"Invoke-WithScopedEnv @{ OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS",
);
const versionIndex = script.indexOf("Invoke-OpenClaw --version", scopedIndex);
const restartIndex = script.indexOf("Invoke-OpenClaw gateway restart");
const agentIndex = script.indexOf("Invoke-OpenClaw agent --local");
@@ -1212,7 +1231,7 @@ exit 7
expect(versionIndex).toBeGreaterThan(updateIndex);
expect(restartIndex).toBeGreaterThan(updateIndex);
expect(agentIndex).toBeGreaterThan(updateIndex);
expect(script).not.toContain("$env:OPENCLAW_DISABLE_BUNDLED_PLUGINS = '1'");
expect(script).not.toContain("OPENCLAW_DISABLE_BUNDLED_PLUGINS");
});
it("generates a .NET-safe Windows stale import regex in the update-failure guard", () => {
+9 -1
View File
@@ -2153,7 +2153,15 @@ kill -TERM "$$"`,
expect(transports).toContain("launch retry");
});
it("keeps Windows update-only env flags scoped before verification", () => {
it("preserves bundled plugin inventory during dev updates", () => {
const devUpdateLines = [macos, windows].map((script) =>
script.split("\n").find((line) => line.includes("update --channel dev")),
);
expect(devUpdateLines).not.toContain(undefined);
for (const updateLine of devUpdateLines) {
expect(updateLine).not.toContain("OPENCLAW_DISABLE_BUNDLED_PLUGINS");
}
expect(powershell).toContain("windowsScopedEnvFunction");
expect(windows).toContain(
"Invoke-WithScopedEnv @{ OPENCLAW_ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS",