Skip to content

Commit 93d00f3

Browse files
author
pingu
committed
fix(plugins): suppress misleading hook-pack fallback on npm-root recovery failure
Address review: the managed-npm-root recovery rebuild-failure error ("managed npm root recovery failed after quarantining…") did not match the hook-pack-fallback skip predicate, so the misleading "Also not a valid hook pack" message could still print on that path. Add the recovery-failure prefix to shouldSkipHookPackFallbackAfterPluginInstallError, add a CLI regression test for the rebuild-failure path, and document the managed-root no-lock quarantine assumption.
1 parent ca303d0 commit 93d00f3

3 files changed

Lines changed: 24 additions & 0 deletions

File tree

src/cli/plugins-cli.install.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,28 @@ describe("plugins cli install", () => {
11591159
expect(runtimeErrors.at(-1)).not.toContain("Also not a valid hook pack");
11601160
});
11611161

1162+
it("does not fall back to hook pack when managed npm root recovery rebuild fails", async () => {
1163+
loadConfig.mockReturnValue({} as OpenClawConfig);
1164+
installPluginFromNpmSpec.mockResolvedValue({
1165+
ok: false,
1166+
error:
1167+
"managed npm root recovery failed after quarantining package-lock.json at /tmp/openclaw-state/extensions/.openclaw-managed-node_modules/_openclaw-quarantined-npm-roots/corrupt-demo: npm install failed during rebuild",
1168+
});
1169+
installHooksFromNpmSpec.mockResolvedValue({
1170+
ok: false,
1171+
error: "package.json missing openclaw.hooks",
1172+
});
1173+
1174+
await expect(runPluginsCommand(["plugins", "install", "npm:demo"])).rejects.toThrow(
1175+
"__exit__:1",
1176+
);
1177+
1178+
expect(installPluginFromClawHub).not.toHaveBeenCalled();
1179+
expect(installHooksFromNpmSpec).not.toHaveBeenCalled();
1180+
expect(runtimeErrors.at(-1)).toContain("managed npm root recovery failed");
1181+
expect(runtimeErrors.at(-1)).not.toContain("Also not a valid hook pack");
1182+
});
1183+
11621184
it("adds a Git PATH hint when npm plugin dependency install cannot spawn git", async () => {
11631185
loadConfig.mockReturnValue({} as OpenClawConfig);
11641186
installPluginFromNpmSpec.mockResolvedValue({

src/cli/plugins-command-helpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ export function shouldSkipHookPackFallbackAfterPluginInstallError(pluginError: s
201201
return (
202202
pluginError.startsWith("npm install failed") ||
203203
pluginError.startsWith("npm peer dependency planning failed") ||
204+
pluginError.startsWith("managed npm root recovery failed") ||
204205
pluginError.startsWith("Failed to stage npm pack archive in managed npm root")
205206
);
206207
}

src/infra/npm-managed-root.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ export async function quarantineManagedNpmRootForRebuild(params: {
569569
await fs.mkdir(params.npmRoot, { recursive: true });
570570
const quarantineParent = path.join(params.npmRoot, MANAGED_NPM_ROOT_QUARANTINE_DIR);
571571
await fs.mkdir(quarantineParent, { recursive: true });
572+
// No process lock on the managed root; safe-by-construction: mkdtemp unique dir + rename ENOENT swallowed on re-quarantine.
572573
const quarantineDir = await fs.mkdtemp(path.join(quarantineParent, "corrupt-"));
573574
const movedArtifactNames: string[] = [];
574575
for (const artifactName of MANAGED_NPM_ROOT_REBUILD_ARTIFACT_NAMES) {

0 commit comments

Comments
 (0)