fix(release): stabilize windows npm install

This commit is contained in:
Peter Steinberger
2026-05-02 05:48:30 +01:00
parent a6240b26aa
commit c3b8e5c812
7 changed files with 99 additions and 19 deletions

View File

@@ -154,6 +154,7 @@ Docs: https://docs.openclaw.ai
- Thinking/providers: resolve bundled provider thinking profiles through lightweight provider policy artifacts when startup-lazy providers are not active, so OpenAI Codex GPT-5.x keeps xhigh available in Gateway session validation. Fixes #74796. Thanks @maxschachere.
- Security/Windows: ignore workspace `.env` system-path variables and resolve stale-process `taskkill.exe` from the validated Windows install root, preventing repository-local env files from redirecting cleanup helpers. Thanks @pgondhi987.
- CLI/plugins: refresh persisted plugin registry policy in place for `plugins enable` and `plugins disable`, so routine toggles no longer rebuild and hash every plugin source when the target is already indexed. Thanks @vincentkoc.
- Windows/install: run npm from a writable installer temp directory and pin the Bedrock runtime dependency below a Windows ARM Node 24 npm resolver failure, so global OpenClaw installs no longer fail before onboarding. Thanks @mariozechner.
- CLI/plugins: scope install and enable slot selection to the selected plugin manifest/runtime fallback, so plugin installs no longer load every plugin runtime or broad status snapshot just to update memory/context slots. Thanks @vincentkoc.
- Plugins/TTS: keep bundled speech-provider discovery available on cold package Gateway paths and add bundled plugin matrix runtime probes for health, readiness, RPC, TTS discovery, and post-ready runtime-deps watchdog coverage. Refs #75283. Thanks @vincentkoc.
- Google Meet/Twilio: show delegated voice call ID, DTMF, and intro-greeting state in `googlemeet doctor`, and avoid claiming DTMF was sent when no Meet PIN sequence was configured. Refs #72478. Thanks @DougButdorf.

View File

@@ -287,7 +287,7 @@ by default, plus git-checkout installs under the same prefix flow.
If missing, attempts install via winget, then Chocolatey, then Scoop. Node 22 LTS, currently `22.14+`, remains supported for compatibility.
</Step>
<Step title="Install OpenClaw">
- `npm` method (default): global npm install using selected `-Tag`
- `npm` method (default): global npm install using selected `-Tag`, launched from a writable installer temp directory so shells opened in protected folders such as `C:\` still work
- `git` method: clone/update repo, install/build with pnpm, and install wrapper at `%USERPROFILE%\.local\bin\openclaw.cmd`
</Step>

View File

@@ -1674,6 +1674,7 @@
"vitest": "^4.1.5"
},
"overrides": {
"@aws-sdk/client-bedrock-runtime": "3.1024.0",
"axios": "1.15.0",
"follow-redirects": "1.16.0",
"node-domexception": "npm:@nolyfill/domexception@1.0.28",
@@ -1688,6 +1689,7 @@
"@anthropic-ai/sdk": "0.92.0",
"hono": "4.12.14",
"@hono/node-server": "1.19.14",
"@aws-sdk/client-bedrock-runtime": "3.1024.0",
"axios": "1.15.0",
"follow-redirects": "1.16.0",
"defu": "6.1.5",

31
pnpm-lock.yaml generated
View File

@@ -8,6 +8,7 @@ overrides:
'@anthropic-ai/sdk': 0.92.0
hono: 4.12.14
'@hono/node-server': 1.19.14
'@aws-sdk/client-bedrock-runtime': 3.1024.0
axios: 1.15.0
follow-redirects: 1.16.0
defu: 6.1.5
@@ -243,8 +244,8 @@ importers:
specifier: 3.1041.0
version: 3.1041.0
'@aws-sdk/client-bedrock-runtime':
specifier: 3.1041.0
version: 3.1041.0
specifier: 3.1024.0
version: 3.1024.0
'@aws-sdk/credential-provider-node':
specifier: 3.972.39
version: 3.972.39
@@ -1699,8 +1700,8 @@ packages:
'@aws-crypto/util@5.2.0':
resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==}
'@aws-sdk/client-bedrock-runtime@3.1041.0':
resolution: {integrity: sha512-1QehYO3jhdvNQ5mOKtwIiNV04y4aywaNZw9HzCp7SSYCX4yy+AGXc2hhYjCiMDUvQPIELuvbR8MXw81NGAj8ZQ==}
'@aws-sdk/client-bedrock-runtime@3.1024.0':
resolution: {integrity: sha512-nIhsn0/eYrL2fTh4kMO7Hpfmhv+AkkXl0KGNpD6+fdmotGvRBWcDv9/PmP/+sT6gvrKTYyzH3vu4efpTPzzP0Q==}
engines: {node: '>=20.0.0'}
'@aws-sdk/client-bedrock@3.1041.0':
@@ -1831,6 +1832,10 @@ packages:
resolution: {integrity: sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw==}
engines: {node: '>=20.0.0'}
'@aws-sdk/token-providers@3.1024.0':
resolution: {integrity: sha512-eoyTMgd6OzoE1dq50um5Y53NrosEkWsjH0W6pswi7vrv1W9hY/7hR43jDcPevqqj+OQksf/5lc++FTqRlb8Y1Q==}
engines: {node: '>=20.0.0'}
'@aws-sdk/token-providers@3.1041.0':
resolution: {integrity: sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw==}
engines: {node: '>=20.0.0'}
@@ -7896,7 +7901,7 @@ snapshots:
'@smithy/util-utf8': 2.3.0
tslib: 2.8.1
'@aws-sdk/client-bedrock-runtime@3.1041.0':
'@aws-sdk/client-bedrock-runtime@3.1024.0':
dependencies:
'@aws-crypto/sha256-browser': 5.2.0
'@aws-crypto/sha256-js': 5.2.0
@@ -7910,7 +7915,7 @@ snapshots:
'@aws-sdk/middleware-user-agent': 3.972.38
'@aws-sdk/middleware-websocket': 3.972.16
'@aws-sdk/region-config-resolver': 3.972.13
'@aws-sdk/token-providers': 3.1041.0
'@aws-sdk/token-providers': 3.1024.0
'@aws-sdk/types': 3.973.8
'@aws-sdk/util-endpoints': 3.996.8
'@aws-sdk/util-user-agent-browser': 3.972.10
@@ -8454,6 +8459,18 @@ snapshots:
'@smithy/types': 4.14.1
tslib: 2.8.1
'@aws-sdk/token-providers@3.1024.0':
dependencies:
'@aws-sdk/core': 3.974.8
'@aws-sdk/nested-clients': 3.997.6
'@aws-sdk/types': 3.973.8
'@smithy/property-provider': 4.2.14
'@smithy/shared-ini-file-loader': 4.4.9
'@smithy/types': 4.14.1
tslib: 2.8.1
transitivePeerDependencies:
- aws-crt
'@aws-sdk/token-providers@3.1041.0':
dependencies:
'@aws-sdk/core': 3.974.8
@@ -9529,7 +9546,7 @@ snapshots:
'@mariozechner/pi-ai@0.71.1(@modelcontextprotocol/sdk@1.29.0(zod@4.4.1))(ws@8.20.0)(zod@4.4.1)':
dependencies:
'@anthropic-ai/sdk': 0.92.0(zod@4.4.1)
'@aws-sdk/client-bedrock-runtime': 3.1041.0
'@aws-sdk/client-bedrock-runtime': 3.1024.0
'@google/genai': 1.51.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.1))
'@mistralai/mistralai': 2.2.1
chalk: 5.6.2

View File

@@ -220,7 +220,8 @@ function Invoke-NativeCommandCapture {
param(
[Parameter(Mandatory = $true)]
[string]$FilePath,
[string[]]$Arguments = @()
[string[]]$Arguments = @(),
[string]$WorkingDirectory = ""
)
$stdoutPath = [System.IO.Path]::GetTempFileName()
@@ -253,12 +254,19 @@ function Invoke-NativeCommandCapture {
)
}
$process = Start-Process -FilePath $startFilePath `
-ArgumentList $startArguments `
-Wait `
-PassThru `
-RedirectStandardOutput $stdoutPath `
-RedirectStandardError $stderrPath
$startProcessArgs = @{
FilePath = $startFilePath
ArgumentList = $startArguments
Wait = $true
PassThru = $true
RedirectStandardOutput = $stdoutPath
RedirectStandardError = $stderrPath
}
if (![string]::IsNullOrWhiteSpace($WorkingDirectory)) {
$startProcessArgs.WorkingDirectory = $WorkingDirectory
}
$process = Start-Process @startProcessArgs
return @{
ExitCode = $process.ExitCode
@@ -270,6 +278,12 @@ function Invoke-NativeCommandCapture {
}
}
function Get-NpmWorkingDirectory {
$workingDirectory = Join-Path ([System.IO.Path]::GetTempPath()) "openclaw-installer"
New-Item -ItemType Directory -Path $workingDirectory -Force | Out-Null
return $workingDirectory
}
function Install-OpenClawNpm {
param([string]$Target = "latest")
@@ -286,7 +300,7 @@ function Install-OpenClawNpm {
$installSpec,
"--no-fund",
"--no-audit"
)
) -WorkingDirectory (Get-NpmWorkingDirectory)
if ($installResult.Stdout) {
Microsoft.PowerShell.Utility\Write-Host $installResult.Stdout
}
@@ -468,7 +482,7 @@ function Main {
"config",
"get",
"prefix"
)
) -WorkingDirectory (Get-NpmWorkingDirectory)
$npmPrefix = $prefixResult.Stdout
if ($prefixResult.ExitCode -eq 0 -and $npmPrefix) {
Add-ToPath -Path "$npmPrefix"

View File

@@ -73,6 +73,44 @@ describe("install.ps1 failure handling", () => {
expect(completeInstallBody).toMatch(/\bthrow "OpenClaw installation failed with exit code/);
});
it("runs npm capture commands from a writable installer temp directory", () => {
const nativeCaptureBody = extractFunctionBody(source, "Invoke-NativeCommandCapture");
const npmInstallBody = extractFunctionBody(source, "Install-OpenClawNpm");
const mainBody = extractFunctionBody(source, "Main");
expect(source).toContain("function Get-NpmWorkingDirectory {");
expect(nativeCaptureBody).toContain('[string]$WorkingDirectory = ""');
expect(nativeCaptureBody).toContain("$startProcessArgs.WorkingDirectory = $WorkingDirectory");
expect(npmInstallBody).toContain("-WorkingDirectory (Get-NpmWorkingDirectory)");
expect(mainBody).toContain("-WorkingDirectory (Get-NpmWorkingDirectory)");
});
runIfPowerShell("creates a temp npm working directory", () => {
const tempDir = harness.createTempDir("openclaw-install-ps1-");
const scriptPath = join(tempDir, "install.ps1");
const scriptWithoutEntryPoint = source.replace(ENTRYPOINT_RE, "");
writeFileSync(
scriptPath,
[
scriptWithoutEntryPoint,
"",
"$result = Get-NpmWorkingDirectory",
'if (!(Test-Path -LiteralPath $result)) { throw "missing $result" }',
'if ($result -notmatch "openclaw-installer") { throw "unexpected $result" }',
"",
].join("\n"),
);
chmodSync(scriptPath, 0o755);
const result = spawnSync(
powershell!,
["-NoLogo", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", scriptPath],
{ encoding: "utf8" },
);
expect(result.status).toBe(0);
expect(result.stderr).toBe("");
});
runIfPowerShell("exits non-zero when run as a script file", () => {
const tempDir = harness.createTempDir("openclaw-install-ps1-");
const scriptPath = join(tempDir, "install.ps1");
@@ -125,7 +163,7 @@ describe("install.ps1 failure handling", () => {
"function Ensure-Node { return $true }",
"function Add-ToPath { param([string]$Path) }",
"function Invoke-NativeCommandCapture {",
" param([string]$FilePath, [string[]]$Arguments)",
" param([string]$FilePath, [string[]]$Arguments, [string]$WorkingDirectory = '')",
" return @{ ExitCode = 0; Stdout = 'npm stdout'; Stderr = 'npm stderr' }",
"}",
"$NoOnboard = $true",
@@ -167,7 +205,7 @@ describe("install.ps1 failure handling", () => {
" return $true",
"}",
"function Invoke-NativeCommandCapture {",
" param([string]$FilePath, [string[]]$Arguments)",
" param([string]$FilePath, [string[]]$Arguments, [string]$WorkingDirectory = '')",
" return @{ ExitCode = 0; Stdout = 'npm prefix'; Stderr = '' }",
"}",
"$NoOnboard = $true",

View File

@@ -15,6 +15,14 @@ function readRootManifest(): RootPackageManifest {
}
describe("root package override guardrails", () => {
it("pins the Bedrock runtime below the Windows ARM Node 24 npm resolver failure", () => {
const manifest = readRootManifest();
const pnpmOverride = manifest.pnpm?.overrides?.["@aws-sdk/client-bedrock-runtime"];
expect(pnpmOverride).toBe("3.1024.0");
expect(manifest.overrides?.["@aws-sdk/client-bedrock-runtime"]).toBe(pnpmOverride);
});
it("pins the node-domexception alias exactly in npm and pnpm overrides", () => {
const manifest = readRootManifest();
const pnpmOverride = manifest.pnpm?.overrides?.["node-domexception"];