Skip to content

Commit 3ba2ce6

Browse files
authored
fix(plugins): avoid managed npm prefix on Windows
Fixes #78514.
1 parent becfeb4 commit 3ba2ce6

8 files changed

Lines changed: 5 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Docs: https://docs.openclaw.ai
3333
- Discord/voice: include a bounded one-line STT transcript preview in verbose voice logs so live voice debugging shows what speakers said before the agent reply.
3434
- Codex app-server: pin the managed Codex harness and Codex CLI smoke package to `@openai/codex@0.129.0`, defer OpenClaw integration dynamic tools behind Codex tool search by default, and accept current Codex service-tier values so legacy `fast` settings survive the stable harness upgrade as `priority`.
3535
- Codex app-server: default implicit local stdio app-server permissions to guardian when Codex system requirements disallow the YOLO approval, reviewer, or sandbox value, including hostname-scoped remote sandbox entries, avoiding turn-start failures on managed hosts that permit only reviewed approval or narrower sandboxes.
36+
- Plugins/install: run managed npm-root install, uninstall, prune, and repair commands from the managed root without a redundant `--prefix .`, avoiding npm 10.9.3 Arborist crashes on native Windows WhatsApp plugin installs. Fixes #78514. (#78902) Thanks @melihselamett-stack.
3637
- Discord/voice: stream ElevenLabs TTS directly into Discord playback and send ElevenLabs latency optimization as the documented query parameter so spoken replies can start sooner.
3738
- Discord/voice: keep TTS playback running when another user starts speaking, ignore new capture during playback to avoid feedback loops, and downgrade expected receive-stream aborts to verbose diagnostics.
3839
- iMessage: expose native private-API message actions through `imsg rpc` for reactions, edits, unsends, replies, rich sends, attachments, and group management when `imsg status --json` reports the required bridge capabilities.

docs/plugins/dependency-resolution.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ OpenClaw uses stable per-source roots:
4141
npm installs run in the npm root with:
4242

4343
```bash
44-
npm install --prefix ~/.openclaw/npm <spec> --omit=dev --omit=peer --legacy-peer-deps --ignore-scripts --no-audit --no-fund
44+
cd ~/.openclaw/npm
45+
npm install --omit=dev --omit=peer --legacy-peer-deps --ignore-scripts --no-audit --no-fund
4546
```
4647

4748
`openclaw plugins install npm-pack:<path.tgz>` uses that same managed npm root

src/infra/npm-managed-root.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,6 @@ describe("managed npm root", () => {
398398
"--ignore-scripts",
399399
"--no-audit",
400400
"--no-fund",
401-
"--prefix",
402-
".",
403401
"openclaw",
404402
],
405403
expect.objectContaining({

src/infra/npm-managed-root.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,6 @@ export async function repairManagedNpmRootOpenClawPeer(params: {
245245
"--ignore-scripts",
246246
"--no-audit",
247247
"--no-fund",
248-
"--prefix",
249-
".",
250248
"openclaw",
251249
]
252250
: [
@@ -257,8 +255,6 @@ export async function repairManagedNpmRootOpenClawPeer(params: {
257255
"--ignore-scripts",
258256
"--no-audit",
259257
"--no-fund",
260-
"--prefix",
261-
".",
262258
];
263259
try {
264260
const result = await command(npmArgs, {

src/plugins/install.npm-spec.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ function expectNpmInstallIntoRoot(params: { calls: unknown[][]; npmRoot: string
6969
"--ignore-scripts",
7070
"--no-audit",
7171
"--no-fund",
72-
"--prefix",
73-
".",
7472
]);
7573
}
7674

@@ -290,9 +288,7 @@ function mockNpmViewAndInstallMany(packages: MockNpmPackage[]) {
290288
);
291289
}
292290
if (argv[0] === "npm" && argv[1] === "install") {
293-
const prefixIndex = argv.indexOf("--prefix");
294-
const prefixValue = prefixIndex >= 0 ? argv[prefixIndex + 1] : undefined;
295-
const npmRoot = prefixValue === "." ? options?.cwd : prefixValue;
291+
const npmRoot = options?.cwd;
296292
if (!npmRoot) {
297293
throw new Error(`unexpected npm install command: ${argv.join(" ")}`);
298294
}
@@ -345,9 +341,7 @@ function mockNpmViewAndInstallMany(packages: MockNpmPackage[]) {
345341
if (argv[0] === "npm" && argv[1] === "uninstall") {
346342
const packageName = argv.at(-1);
347343
if (packageName === "openclaw") {
348-
const prefixIndex = argv.indexOf("--prefix");
349-
const prefixValue = prefixIndex >= 0 ? argv[prefixIndex + 1] : undefined;
350-
const npmRoot = prefixValue === "." ? options?.cwd : prefixValue;
344+
const npmRoot = options?.cwd;
351345
if (!npmRoot) {
352346
throw new Error(`unexpected npm uninstall command: ${argv.join(" ")}`);
353347
}

src/plugins/install.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,6 @@ async function rollbackManagedNpmPluginInstall(params: {
328328
"--ignore-scripts",
329329
"--no-audit",
330330
"--no-fund",
331-
"--prefix",
332-
".",
333331
params.packageName,
334332
],
335333
{
@@ -499,8 +497,6 @@ async function installPluginFromManagedNpmRoot(
499497
noAudit: true,
500498
noFund: true,
501499
}),
502-
"--prefix",
503-
".",
504500
],
505501
{
506502
cwd: npmRoot,

src/plugins/uninstall.test.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -992,8 +992,6 @@ describe("uninstallPlugin", () => {
992992
"--ignore-scripts",
993993
"--no-audit",
994994
"--no-fund",
995-
"--prefix",
996-
".",
997995
"@openclaw/kitchen-sink",
998996
],
999997
expect.objectContaining({
@@ -1128,8 +1126,6 @@ describe("uninstallPlugin", () => {
11281126
"--ignore-scripts",
11291127
"--no-audit",
11301128
"--no-fund",
1131-
"--prefix",
1132-
".",
11331129
"missing-plugin",
11341130
],
11351131
expect.objectContaining({

src/plugins/uninstall.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,8 +611,6 @@ export async function applyPluginUninstallDirectoryRemoval(
611611
"--ignore-scripts",
612612
"--no-audit",
613613
"--no-fund",
614-
"--prefix",
615-
".",
616614
removal.cleanup.packageName,
617615
],
618616
{

0 commit comments

Comments
 (0)