mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:10:44 +00:00
fix: stage WhatsApp runtime deps before setup login
This commit is contained in:
@@ -12,4 +12,10 @@ describe("whatsapp setup entry", () => {
|
||||
expect(setupEntry.kind).toBe("bundled-channel-setup-entry");
|
||||
expect(whatsappSetupPlugin.id).toBe("whatsapp");
|
||||
});
|
||||
|
||||
it("loads the delegated setup wizard without importing runtime dependencies", async () => {
|
||||
const { whatsappSetupWizard } = await import("./src/setup-surface.js");
|
||||
|
||||
expect(whatsappSetupWizard.channel).toBe("whatsapp");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
resolveWhatsAppAccount,
|
||||
resolveWhatsAppAuthDir,
|
||||
} from "./accounts.js";
|
||||
import { loginWeb } from "./login.js";
|
||||
import { whatsappSetupAdapter } from "./setup-core.js";
|
||||
|
||||
type SetupPrompter = Parameters<NonNullable<ChannelSetupWizard["finalize"]>>[0]["prompter"];
|
||||
@@ -424,6 +423,7 @@ export async function finalizeWhatsAppSetup(params: {
|
||||
});
|
||||
if (wantsLink) {
|
||||
try {
|
||||
const { loginWeb } = await import("./login.js");
|
||||
await loginWeb(false, undefined, params.runtime, accountId);
|
||||
} catch (error) {
|
||||
params.runtime.error(`WhatsApp login failed: ${String(error)}`);
|
||||
|
||||
@@ -94,8 +94,12 @@ export async function loadWhatsAppChannelRuntime() {
|
||||
return await import("./channel.runtime.js");
|
||||
}
|
||||
|
||||
async function loadWhatsAppSetupSurface() {
|
||||
return await import("./setup-surface.js");
|
||||
}
|
||||
|
||||
export const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(
|
||||
async () => (await loadWhatsAppChannelRuntime()).whatsappSetupWizard,
|
||||
async () => (await loadWhatsAppSetupSurface()).whatsappSetupWizard,
|
||||
);
|
||||
|
||||
const whatsappConfigAdapter = createScopedChannelConfigAdapter<ResolvedWhatsAppAccount>({
|
||||
|
||||
@@ -709,6 +709,102 @@ for channel in "${!SETUP_ENTRY_DEP_SENTINELS[@]}"; do
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Running packaged guided WhatsApp setup; runtime deps should be staged before finalize..."
|
||||
OPENCLAW_PACKAGE_ROOT="$root" node --input-type=module - <<'NODE'
|
||||
import path from "node:path";
|
||||
import { readdir } from "node:fs/promises";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
const root = process.env.OPENCLAW_PACKAGE_ROOT;
|
||||
if (!root) {
|
||||
throw new Error("missing OPENCLAW_PACKAGE_ROOT");
|
||||
}
|
||||
const distDir = path.join(root, "dist");
|
||||
const onboardChannelFiles = (await readdir(distDir))
|
||||
.filter((entry) => /^onboard-channels-.*\.js$/.test(entry))
|
||||
.sort();
|
||||
let setupChannels;
|
||||
for (const entry of onboardChannelFiles) {
|
||||
const module = await import(pathToFileURL(path.join(distDir, entry)));
|
||||
if (typeof module.setupChannels === "function") {
|
||||
setupChannels = module.setupChannels;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!setupChannels) {
|
||||
throw new Error(
|
||||
`could not find packaged setupChannels export in ${JSON.stringify(onboardChannelFiles)}`,
|
||||
);
|
||||
}
|
||||
|
||||
let channelSelectCount = 0;
|
||||
const notes = [];
|
||||
const prompter = {
|
||||
intro: async () => {},
|
||||
outro: async () => {},
|
||||
note: async (body, title) => {
|
||||
notes.push({ title, body });
|
||||
},
|
||||
confirm: async ({ message, initialValue }) => {
|
||||
if (message === "Link WhatsApp now (QR)?") {
|
||||
return false;
|
||||
}
|
||||
return initialValue ?? true;
|
||||
},
|
||||
select: async ({ message }) => {
|
||||
if (message === "Select a channel") {
|
||||
channelSelectCount += 1;
|
||||
return channelSelectCount === 1 ? "whatsapp" : "__done__";
|
||||
}
|
||||
if (message === "WhatsApp phone setup") {
|
||||
return "separate";
|
||||
}
|
||||
if (message === "WhatsApp DM policy") {
|
||||
return "disabled";
|
||||
}
|
||||
throw new Error(`unexpected select prompt: ${message}`);
|
||||
},
|
||||
multiselect: async ({ message }) => {
|
||||
throw new Error(`unexpected multiselect prompt: ${message}`);
|
||||
},
|
||||
text: async ({ message }) => {
|
||||
throw new Error(`unexpected text prompt: ${message}`);
|
||||
},
|
||||
};
|
||||
const runtime = {
|
||||
log: (message) => console.log(message),
|
||||
error: (message) => console.error(message),
|
||||
};
|
||||
|
||||
const result = await setupChannels(
|
||||
{ plugins: { enabled: true } },
|
||||
runtime,
|
||||
prompter,
|
||||
{
|
||||
deferStatusUntilSelection: true,
|
||||
skipConfirm: true,
|
||||
skipStatusNote: true,
|
||||
skipDmPolicyPrompt: true,
|
||||
initialSelection: ["whatsapp"],
|
||||
},
|
||||
);
|
||||
|
||||
if (!result.channels?.whatsapp) {
|
||||
throw new Error(`WhatsApp setup did not write channel config: ${JSON.stringify(result)}`);
|
||||
}
|
||||
console.log("packaged guided WhatsApp setup completed");
|
||||
NODE
|
||||
|
||||
if [ -e "$root/dist/extensions/whatsapp/node_modules/@whiskeysockets/baileys/package.json" ]; then
|
||||
echo "expected guided WhatsApp setup deps to be installed externally, not into bundled plugin tree" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -path "*/node_modules/@whiskeysockets/baileys/package.json" -type f | grep -q .; then
|
||||
echo "guided WhatsApp setup did not stage @whiskeysockets/baileys before finalize" >&2
|
||||
find "$OPENCLAW_PLUGIN_STAGE_DIR" -maxdepth 12 -type f | sort | head -160 >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Configuring setup-entry channels; doctor should now install bundled runtime deps externally..."
|
||||
node - <<'NODE'
|
||||
const fs = require("node:fs");
|
||||
|
||||
@@ -72,6 +72,7 @@ function loadChannelSetupPluginRegistry(params: {
|
||||
onlyPluginIds?: string[];
|
||||
activate?: boolean;
|
||||
installRuntimeDeps?: boolean;
|
||||
forceSetupOnlyChannelPlugins?: boolean;
|
||||
}): PluginRegistry {
|
||||
clearPluginDiscoveryCache();
|
||||
const autoEnabled = applyPluginAutoEnable({ config: params.cfg, env: process.env });
|
||||
@@ -89,7 +90,8 @@ function loadChannelSetupPluginRegistry(params: {
|
||||
logger: createPluginLoaderLogger(log),
|
||||
onlyPluginIds: params.onlyPluginIds,
|
||||
includeSetupOnlyChannelPlugins: true,
|
||||
forceSetupOnlyChannelPlugins: params.installRuntimeDeps === false,
|
||||
forceSetupOnlyChannelPlugins:
|
||||
params.forceSetupOnlyChannelPlugins ?? params.installRuntimeDeps === false,
|
||||
activate: params.activate,
|
||||
installBundledRuntimeDeps: params.installRuntimeDeps !== false,
|
||||
});
|
||||
@@ -160,6 +162,7 @@ export function loadChannelSetupPluginRegistrySnapshotForChannel(params: {
|
||||
pluginId?: string;
|
||||
workspaceDir?: string;
|
||||
installRuntimeDeps?: boolean;
|
||||
forceSetupOnlyChannelPlugins?: boolean;
|
||||
}): PluginRegistry {
|
||||
const scopedPluginId = resolveScopedChannelPluginId({
|
||||
cfg: params.cfg,
|
||||
|
||||
@@ -461,12 +461,23 @@ describe("setupChannels workspace shadow exclusion", () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledTimes(1);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith(
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledTimes(2);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({
|
||||
channel: "external-chat",
|
||||
pluginId: "external-chat",
|
||||
workspaceDir: "/tmp/openclaw-workspace",
|
||||
installRuntimeDeps: false,
|
||||
}),
|
||||
);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({
|
||||
channel: "external-chat",
|
||||
workspaceDir: "/tmp/openclaw-workspace",
|
||||
forceSetupOnlyChannelPlugins: true,
|
||||
installRuntimeDeps: true,
|
||||
}),
|
||||
);
|
||||
expect(getChannelSetupPlugin).not.toHaveBeenCalled();
|
||||
|
||||
@@ -163,9 +163,14 @@ export async function setupChannels(
|
||||
const loadScopedChannelPlugin = async (
|
||||
channel: ChannelChoice,
|
||||
pluginId?: string,
|
||||
setup?: {
|
||||
installRuntimeDeps?: boolean;
|
||||
forceReload?: boolean;
|
||||
forceSetupOnlyChannelPlugins?: boolean;
|
||||
},
|
||||
): Promise<ChannelSetupPlugin | undefined> => {
|
||||
const existing = getVisibleChannelPlugin(channel);
|
||||
if (existing) {
|
||||
if (existing && setup?.forceReload !== true) {
|
||||
return existing;
|
||||
}
|
||||
const snapshot = loadChannelSetupPluginRegistrySnapshotForChannel({
|
||||
@@ -174,7 +179,8 @@ export async function setupChannels(
|
||||
channel,
|
||||
...(pluginId ? { pluginId } : {}),
|
||||
workspaceDir: resolveWorkspaceDir(),
|
||||
installRuntimeDeps: false,
|
||||
installRuntimeDeps: setup?.installRuntimeDeps ?? false,
|
||||
forceSetupOnlyChannelPlugins: setup?.forceSetupOnlyChannelPlugins,
|
||||
});
|
||||
const plugin =
|
||||
snapshot.channelSetups.find((entry) => entry.plugin.id === channel)?.plugin ??
|
||||
@@ -401,6 +407,13 @@ export async function setupChannels(
|
||||
};
|
||||
|
||||
const configureChannel = async (channel: ChannelChoice) => {
|
||||
if (scopedPluginsById.has(channel)) {
|
||||
await loadScopedChannelPlugin(channel, undefined, {
|
||||
forceReload: true,
|
||||
forceSetupOnlyChannelPlugins: true,
|
||||
installRuntimeDeps: true,
|
||||
});
|
||||
}
|
||||
const adapter = getVisibleSetupFlowAdapter(channel);
|
||||
if (!adapter) {
|
||||
await prompter.note(`${channel} does not support guided setup yet.`, "Channel setup");
|
||||
|
||||
@@ -2441,7 +2441,9 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
||||
manifestRecord.setupSource
|
||||
) {
|
||||
const setupRegistration = resolveSetupChannelRegistration(mod, {
|
||||
installRuntimeDeps: shouldInstallBundledRuntimeDeps && enableState.enabled,
|
||||
installRuntimeDeps:
|
||||
shouldInstallBundledRuntimeDeps &&
|
||||
(enableState.enabled || forceSetupOnlyChannelPlugins),
|
||||
});
|
||||
if (setupRegistration.loadError) {
|
||||
recordPluginError({
|
||||
|
||||
Reference in New Issue
Block a user