fix(onboarding): default dual-source installs to npm

This commit is contained in:
Vincent Koc
2026-05-02 18:53:36 -07:00
parent ba3c0fc78e
commit 82e7accf53
2 changed files with 45 additions and 12 deletions

View File

@@ -317,7 +317,7 @@ describe("ensureOnboardingPluginInstalled", () => {
expect(installPluginFromNpmSpec).not.toHaveBeenCalled();
});
it("offers ClawHub as the default remote source when package metadata provides it", async () => {
it("defaults dual-source remote installs to npm unless ClawHub is explicit", async () => {
let captured:
| {
options: Array<{
@@ -353,11 +353,41 @@ describe("ensureOnboardingPluginInstalled", () => {
{ value: "npm", label: "Download from npm (@openclaw/demo-plugin@2026.5.2)" },
{ value: "skip", label: "Skip for now" },
]);
expect(captured?.initialValue).toBe("clawhub");
expect(captured?.initialValue).toBe("npm");
expect(installPluginFromClawHub).not.toHaveBeenCalled();
expect(installPluginFromNpmSpec).not.toHaveBeenCalled();
});
it("honors explicit ClawHub defaults for dual-source remote installs", async () => {
let captured:
| {
initialValue: "clawhub" | "npm" | "local" | "skip";
}
| undefined;
await ensureOnboardingPluginInstalled({
cfg: { update: { channel: "stable" } },
entry: {
pluginId: "demo-plugin",
label: "Demo Plugin",
install: {
clawhubSpec: "clawhub:demo-plugin@2026.5.2",
npmSpec: "@openclaw/demo-plugin@2026.5.2",
defaultChoice: "clawhub",
},
},
prompter: {
select: vi.fn(async (input) => {
captured = input;
return "skip";
}),
} as never,
runtime: {} as never,
});
expect(captured?.initialValue).toBe("clawhub");
});
it("does not offer local installs when the workspace only has a spoofed .git marker", async () => {
await withTempDir({ prefix: "openclaw-onboarding-install-spoofed-git-" }, async (temp) => {
const workspaceDir = path.join(temp, "workspace");

View File

@@ -273,11 +273,21 @@ function resolveInstallDefaultChoice(params: {
}): InstallChoice {
const { cfg, entry, localPath, bundledLocalPath, hasClawHubSpec, hasNpmSpec } = params;
const hasRemoteSpec = hasClawHubSpec || hasNpmSpec;
const entryDefault = entry.install.defaultChoice;
const remoteDefault = (): InstallChoice => {
if (entryDefault === "clawhub" && hasClawHubSpec) {
return "clawhub";
}
if (entryDefault === "npm" && hasNpmSpec) {
return "npm";
}
return hasNpmSpec ? "npm" : "clawhub";
};
if (!hasRemoteSpec) {
return localPath ? "local" : "skip";
}
if (!localPath) {
return hasClawHubSpec ? "clawhub" : "npm";
return remoteDefault();
}
if (bundledLocalPath) {
return "local";
@@ -287,19 +297,12 @@ function resolveInstallDefaultChoice(params: {
return "local";
}
if (updateChannel === "stable" || updateChannel === "beta") {
return hasClawHubSpec ? "clawhub" : "npm";
}
const entryDefault = entry.install.defaultChoice;
if (entryDefault === "clawhub" && hasClawHubSpec) {
return "clawhub";
return remoteDefault();
}
if (entryDefault === "local") {
return "local";
}
if (entryDefault === "npm") {
return "npm";
}
return hasClawHubSpec ? "clawhub" : "local";
return remoteDefault();
}
async function promptInstallChoice(params: {