From 85f9276624fcd5367deab854b095e4ac0300bb94 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 13 May 2026 10:58:24 +0100 Subject: [PATCH] build(whatsapp): externalize whatsapp plugin --- CHANGELOG.md | 2 +- docs/channels/index.md | 4 +- docs/channels/whatsapp.md | 22 ++++------- docs/plugins/plugin-inventory.md | 2 +- docs/plugins/reference.md | 2 +- docs/plugins/reference/whatsapp.md | 12 +----- extensions/whatsapp/package.json | 5 ++- ....0-rc10.patch => baileys@7.0.0-rc11.patch} | 0 pnpm-lock.yaml | 39 +++++++++---------- pnpm-workspace.yaml | 5 ++- scripts/generate-plugin-inventory-doc.mjs | 15 +------ scripts/lib/bundled-plugin-build-entries.mjs | 2 +- .../official-external-channel-catalog.json | 3 +- .../copy-bundled-plugin-metadata.test.ts | 4 +- ...icial-external-plugin-repair-hints.test.ts | 25 ++++++++++++ test/official-channel-catalog.test.ts | 9 +++-- .../bundled-plugin-build-entries.test.ts | 6 ++- .../postinstall-bundled-plugins.test.ts | 4 +- 18 files changed, 81 insertions(+), 80 deletions(-) rename patches/{baileys@7.0.0-rc10.patch => baileys@7.0.0-rc11.patch} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34eee6c6588..988595ec037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,7 @@ Docs: https://docs.openclaw.ai - Scrub streamable MCP redirect headers [AI]. (#80906) Thanks @pgondhi987. - fix(memory-wiki): require admin scope for ingest [AI]. (#80897) Thanks @pgondhi987. - memory-wiki: require write scope for Obsidian search [AI]. (#80904) Thanks @pgondhi987. -- WhatsApp/install: allow Baileys' pinned libsignal git subdependency under pnpm 11 so source installs and local checks can complete. +- WhatsApp: externalize the channel as a ClawHub/npm plugin outside the core npm runtime bundle, and bump Baileys to `7.0.0-rc11` so libsignal resolves from the registry instead of a GitHub tarball. - Build: skip copied metadata for bundled plugins that are excluded from build entries, preventing update/status rebuilds from advertising missing QQ Bot runtime files. (#80925) - Control UI/sessions: nest subagent sessions under their parent session in the session picker dropdown using a visual `└─ ` prefix, making the parent-child relationship clear. Fixes #77628. (#78623) Thanks @chinar-amrutkar. - fix(config): reject auto-managed meta.lastTouched\* paths in config set/unset (#80856). Thanks @ai-hpc diff --git a/docs/channels/index.md b/docs/channels/index.md index 786ffa2454a..14908431f1c 100644 --- a/docs/channels/index.md +++ b/docs/channels/index.md @@ -16,8 +16,8 @@ Text is supported everywhere; media and reactions vary by channel. - Slack multi-person DMs route as group chats, so group policy, mention behavior, and group-session rules apply to MPIM conversations. - WhatsApp setup is install-on-demand: onboarding can show the setup flow before - the plugin package is installed, and the Gateway loads the WhatsApp runtime - only when the channel is actually active. + the plugin package is installed, and the Gateway loads the external + ClawHub/npm plugin only when the channel is actually active. ## Supported channels diff --git a/docs/channels/whatsapp.md b/docs/channels/whatsapp.md index 6e99c417589..4302083907d 100644 --- a/docs/channels/whatsapp.md +++ b/docs/channels/whatsapp.md @@ -14,27 +14,19 @@ Status: production-ready via WhatsApp Web (Baileys). Gateway owns linked session - `openclaw channels login --channel whatsapp` also offers the install flow when the plugin is not present yet. - Dev channel + git checkout: defaults to the local plugin path. -- Stable/Beta: uses the npm package `@openclaw/whatsapp` on the current official - release tag. +- Stable/Beta: installs the official `@openclaw/whatsapp` plugin from ClawHub + first, with npm as the fallback. +- The WhatsApp runtime is distributed outside the core OpenClaw npm package + because its Baileys dependency chain uses GPL-licensed `libsignal`. Manual install stays available: ```bash -openclaw plugins install @openclaw/whatsapp +openclaw plugins install clawhub:@openclaw/whatsapp ``` -Use the bare package to follow the current official release tag. Pin an exact -version only when you need a reproducible install. - -On Windows, the WhatsApp plugin needs Git on `PATH` during npm install because -one of its Baileys/libsignal dependencies is fetched from a git URL. Install -Git for Windows, then restart the shell and rerun the install: - -```powershell -winget install --id Git.Git -e -``` - -Portable Git also works if its `bin` directory is on `PATH`. +Use the bare npm package (`@openclaw/whatsapp`) only when you need the registry +fallback. Pin an exact version only when you need a reproducible install. diff --git a/docs/plugins/plugin-inventory.md b/docs/plugins/plugin-inventory.md index 1e9f3d92235..48761e981b3 100644 --- a/docs/plugins/plugin-inventory.md +++ b/docs/plugins/plugin-inventory.md @@ -166,7 +166,7 @@ uninstall, and publishing commands. | [tlon](/plugins/reference/tlon) | Adds the Tlon channel surface for sending and receiving OpenClaw messages. | `@openclaw/tlon`
npm; ClawHub | channels: tlon; contracts: tools; skills | | [twitch](/plugins/reference/twitch) | Adds the Twitch channel surface for sending and receiving OpenClaw messages. | `@openclaw/twitch`
npm; ClawHub | channels: twitch | | [voice-call](/plugins/reference/voice-call) | Adds agent-callable tools. | `@openclaw/voice-call`
npm; ClawHub | contracts: tools | -| [whatsapp](/plugins/reference/whatsapp) | Adds the WhatsApp channel surface for sending and receiving OpenClaw messages. | `@openclaw/whatsapp`
npm; ClawHub | channels: whatsapp | +| [whatsapp](/plugins/reference/whatsapp) | Adds the WhatsApp channel surface for sending and receiving OpenClaw messages. | `@openclaw/whatsapp`
ClawHub: `clawhub:@openclaw/whatsapp`; npm | channels: whatsapp | | [zalo](/plugins/reference/zalo) | Adds the Zalo channel surface for sending and receiving OpenClaw messages. | `@openclaw/zalo`
npm; ClawHub | channels: zalo | | [zalouser](/plugins/reference/zalouser) | Adds the Zalo Personal channel surface for sending and receiving OpenClaw messages. | `@openclaw/zalouser`
npm; ClawHub | channels: zalouser; contracts: tools | diff --git a/docs/plugins/reference.md b/docs/plugins/reference.md index 34af64754f8..48de08e251b 100644 --- a/docs/plugins/reference.md +++ b/docs/plugins/reference.md @@ -128,7 +128,7 @@ pnpm plugins:inventory:gen | [vydra](/plugins/reference/vydra) | Adds Vydra model provider support to OpenClaw. | `@openclaw/vydra-provider`
included in OpenClaw | providers: vydra; contracts: imageGenerationProviders, speechProviders, videoGenerationProviders | | [web-readability](/plugins/reference/web-readability) | Extract readable article content from local HTML web fetch responses. | `@openclaw/web-readability-plugin`
included in OpenClaw | contracts: webContentExtractors | | [webhooks](/plugins/reference/webhooks) | Authenticated inbound webhooks that bind external automation to OpenClaw TaskFlows. | `@openclaw/webhooks`
included in OpenClaw | plugin | -| [whatsapp](/plugins/reference/whatsapp) | Adds the WhatsApp channel surface for sending and receiving OpenClaw messages. | `@openclaw/whatsapp`
npm; ClawHub | channels: whatsapp | +| [whatsapp](/plugins/reference/whatsapp) | Adds the WhatsApp channel surface for sending and receiving OpenClaw messages. | `@openclaw/whatsapp`
ClawHub: `clawhub:@openclaw/whatsapp`; npm | channels: whatsapp | | [xai](/plugins/reference/xai) | Adds xAI model provider support to OpenClaw. | `@openclaw/xai-plugin`
included in OpenClaw | providers: xai; contracts: imageGenerationProviders, mediaUnderstandingProviders, realtimeTranscriptionProviders, speechProviders, tools, videoGenerationProviders, webSearchProviders | | [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi model provider support to OpenClaw. | `@openclaw/xiaomi-provider`
included in OpenClaw | providers: xiaomi; contracts: speechProviders | | [zai](/plugins/reference/zai) | Adds Z.AI model provider support to OpenClaw. | `@openclaw/zai-provider`
included in OpenClaw | providers: zai; contracts: mediaUnderstandingProviders | diff --git a/docs/plugins/reference/whatsapp.md b/docs/plugins/reference/whatsapp.md index b2bf8a43a62..46518f0f268 100644 --- a/docs/plugins/reference/whatsapp.md +++ b/docs/plugins/reference/whatsapp.md @@ -12,22 +12,12 @@ Adds the WhatsApp channel surface for sending and receiving OpenClaw messages. ## Distribution - Package: `@openclaw/whatsapp` -- Install route: npm; ClawHub +- Install route: ClawHub: `clawhub:@openclaw/whatsapp`; npm ## Surface channels: whatsapp -## Windows install note - -On Windows, the WhatsApp plugin needs Git on `PATH` during npm install because one of its Baileys/libsignal dependencies is fetched from a git URL. Install Git for Windows, then restart the shell and rerun the install: - -```powershell -winget install --id Git.Git -e -``` - -Portable Git also works if its `bin` directory is on `PATH`. - ## Related docs - [whatsapp](/channels/whatsapp) diff --git a/extensions/whatsapp/package.json b/extensions/whatsapp/package.json index bb42060e4bf..d0029f328cc 100644 --- a/extensions/whatsapp/package.json +++ b/extensions/whatsapp/package.json @@ -8,7 +8,7 @@ }, "type": "module", "dependencies": { - "baileys": "7.0.0-rc10", + "baileys": "7.0.0-rc11", "https-proxy-agent": "9.0.0", "jimp": "1.6.1", "typebox": "1.1.38", @@ -56,8 +56,9 @@ ] }, "install": { + "clawhubSpec": "clawhub:@openclaw/whatsapp", "npmSpec": "@openclaw/whatsapp", - "defaultChoice": "npm", + "defaultChoice": "clawhub", "minHostVersion": ">=2026.4.25" }, "compat": { diff --git a/patches/baileys@7.0.0-rc10.patch b/patches/baileys@7.0.0-rc11.patch similarity index 100% rename from patches/baileys@7.0.0-rc10.patch rename to patches/baileys@7.0.0-rc11.patch diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 421f3c1c642..20393eb4df5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,7 +35,7 @@ packageExtensionsChecksum: sha256-oc/FAHkBR844HBfph1RZWyRMHHBpIFya25tyv5SGf6s= patchedDependencies: '@agentclientprotocol/claude-agent-acp@0.33.1': 3995624bb834cc60fea1461c7ef33f1fcdd8fb58b8f43f2f1490bc689f6e1be2 - baileys@7.0.0-rc10: a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2 + baileys@7.0.0-rc11: a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2 importers: @@ -1656,8 +1656,8 @@ importers: extensions/whatsapp: dependencies: baileys: - specifier: 7.0.0-rc10 - version: 7.0.0-rc10(patch_hash=a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2)(audio-decode@2.2.3)(jimp@1.6.1)(sharp@0.34.5) + specifier: 7.0.0-rc11 + version: 7.0.0-rc11(patch_hash=a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2)(audio-decode@2.2.3)(jimp@1.6.1)(sharp@0.34.5) https-proxy-agent: specifier: 9.0.0 version: 9.0.0 @@ -4602,10 +4602,6 @@ packages: '@wasm-audio-decoders/opus-ml@0.0.2': resolution: {integrity: sha512-58rWEqDGg+CKCyEeKm2KoxxSwTWtHh/NLTW9ObR4K8CGF6VwuuGudEI1CtniS/oSRmL1nJq/eh8MKARiluw4DQ==} - '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': - resolution: {gitHosted: true, tarball: https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67} - version: 2.0.1 - '@zed-industries/codex-acp-darwin-arm64@0.14.0': resolution: {integrity: sha512-FWjHKlNJTZmXWM/2/GAQAg0WJEjPlfxEQJgvfxuzK1xZh81CDg9U6uSgZ1ggBkkN2bOoCnOupvGAPOmBoL5m2Q==} cpu: [arm64] @@ -4811,8 +4807,8 @@ packages: bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - baileys@7.0.0-rc10: - resolution: {integrity: sha512-B1ShVyha4iZP7aNyz4QsXFceExzkvLFgISQGaDGHQaYFxIdNqoen+xKmlo1iWEsaexvQORAvUK44VicRi1T94g==} + baileys@7.0.0-rc11: + resolution: {integrity: sha512-yi7An4f5DmShjb75L8eSttrA6HLy7PYoP3XIQBmvQ5yH8vVZWBXZDogDxfGQQL6N98ELRwznG7puhjyLEa5CQg==} engines: {node: '>=20.0.0'} peerDependencies: audio-decode: ^2.1.3 @@ -6022,6 +6018,9 @@ packages: resolution: {integrity: sha512-LrQfPUeTW7MXbMvT62moEMnpMTuj9TO3lqjCeLKjM975PJ4Alrl/43f2tlDX7xOsNptKgH4LSNGwIbXwEkLg4g==} engines: {node: '>=22.0.0'} + libsignal@6.0.0: + resolution: {integrity: sha512-d/5V3YFtDljbFMufz4ncyUYGYhJl+vzAe+c2EFFBQ6bz1h8Q3IOMEGXYMzlibU60I+e8GagMMpji18iez3P1hA==} + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -7757,8 +7756,8 @@ packages: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} - whatsapp-rust-bridge@0.5.3: - resolution: {integrity: sha512-Xb3GAgtWQQJ30oI4a4pjM4+YUeli9CMLTwTIewUrb+AJMFElIkiT5uo+j1Zhc+amiV0Jj+LfX76c/EEZirJbGA==} + whatsapp-rust-bridge@0.5.4: + resolution: {integrity: sha512-yYO1qSs0Fe7tGtnxOFHomocUD6IZtoAgmA4oDFyGIRZ67D3QZk3w7swA6XXFXNQngiyrg2k7tul6IrM3eUFh7A==} whatwg-mimetype@5.0.0: resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} @@ -11297,11 +11296,6 @@ snapshots: dependencies: '@wasm-audio-decoders/common': 9.0.7 - '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': - dependencies: - curve25519-js: 0.0.4 - protobufjs: 7.5.6 - '@zed-industries/codex-acp-darwin-arm64@0.14.0': optional: true @@ -11485,19 +11479,19 @@ snapshots: bail@2.0.2: {} - baileys@7.0.0-rc10(patch_hash=a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2)(audio-decode@2.2.3)(jimp@1.6.1)(sharp@0.34.5): + baileys@7.0.0-rc11(patch_hash=a9aea1790d2c65b1ae543c77faca4119bbfb91ee3b6ca6c38d1cad4f5702ada2)(audio-decode@2.2.3)(jimp@1.6.1)(sharp@0.34.5): dependencies: '@cacheable/node-cache': 1.7.6 '@hapi/boom': 9.1.4 async-mutex: 0.5.0 - libsignal: '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67' + libsignal: 6.0.0 lru-cache: 11.3.6 music-metadata: 11.12.3 p-queue: 9.2.0 pino: 9.14.0 protobufjs: 7.5.6 sharp: 0.34.5 - whatsapp-rust-bridge: 0.5.3 + whatsapp-rust-bridge: 0.5.4 ws: 8.20.0 optionalDependencies: audio-decode: 2.2.3 @@ -12881,6 +12875,11 @@ snapshots: kysely@0.29.0: {} + libsignal@6.0.0: + dependencies: + curve25519-js: 0.0.4 + protobufjs: 7.5.6 + lie@3.3.0: dependencies: immediate: 3.0.6 @@ -14867,7 +14866,7 @@ snapshots: webidl-conversions@8.0.1: {} - whatsapp-rust-bridge@0.5.3: {} + whatsapp-rust-bridge@0.5.4: {} whatwg-mimetype@5.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 96a53913044..e04545b8ae8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,7 +12,9 @@ minimumReleaseAgeExclude: - "@agentclientprotocol/sdk" - "axios" - "basic-ftp" + - "baileys@7.0.0-rc11" - "hono" + - "libsignal@6.0.0" - "openclaw" - "protobufjs" - "vite" @@ -71,7 +73,6 @@ allowBuilds: "@tloncorp/api": true "@tloncorp/tlon-skill": true baileys: true - "@whiskeysockets/libsignal-node": true authenticate-pam: true "@discordjs/opus": false esbuild: true @@ -92,5 +93,5 @@ peerDependencyRules: "prism-media>opusscript": "^0.0.8 || ^0.1.1" patchedDependencies: - "baileys@7.0.0-rc10": "patches/baileys@7.0.0-rc10.patch" + "baileys@7.0.0-rc11": "patches/baileys@7.0.0-rc11.patch" "@agentclientprotocol/claude-agent-acp@0.33.1": "patches/@agentclientprotocol__claude-agent-acp@0.33.1.patch" diff --git a/scripts/generate-plugin-inventory-doc.mjs b/scripts/generate-plugin-inventory-doc.mjs index 2fb8b166356..93bbbfe6102 100644 --- a/scripts/generate-plugin-inventory-doc.mjs +++ b/scripts/generate-plugin-inventory-doc.mjs @@ -28,20 +28,7 @@ const PLUGIN_DOC_ALIASES = new Map([ ["tavily", "/tools/tavily"], ["tokenjuice", "/tools/tokenjuice"], ]); -const PLUGIN_REFERENCE_EXTRA_SECTIONS = new Map([ - [ - "whatsapp", - `## Windows install note - -On Windows, the WhatsApp plugin needs Git on \`PATH\` during npm install because one of its Baileys/libsignal dependencies is fetched from a git URL. Install Git for Windows, then restart the shell and rerun the install: - -\`\`\`powershell -winget install --id Git.Git -e -\`\`\` - -Portable Git also works if its \`bin\` directory is on \`PATH\`.`, - ], -]); +const PLUGIN_REFERENCE_EXTRA_SECTIONS = new Map([]); function readJson(relativePath) { return JSON.parse(fs.readFileSync(path.join(ROOT, relativePath), "utf8")); diff --git a/scripts/lib/bundled-plugin-build-entries.mjs b/scripts/lib/bundled-plugin-build-entries.mjs index c08446ead8e..b8dc8dd0215 100644 --- a/scripts/lib/bundled-plugin-build-entries.mjs +++ b/scripts/lib/bundled-plugin-build-entries.mjs @@ -9,7 +9,7 @@ import { shouldBuildBundledCluster } from "./optional-bundled-clusters.mjs"; const TOP_LEVEL_PUBLIC_SURFACE_EXTENSIONS = new Set([".ts", ".js", ".mts", ".cts", ".mjs", ".cjs"]); export const NON_PACKAGED_BUNDLED_PLUGIN_DIRS = new Set(["qa-channel", "qa-lab", "qa-matrix"]); -const EXCLUDED_CORE_BUNDLED_PLUGIN_DIRS = new Set(["qqbot"]); +const EXCLUDED_CORE_BUNDLED_PLUGIN_DIRS = new Set(["qqbot", "whatsapp"]); const toPosixPath = (value) => value.replaceAll("\\", "/"); function readBundledPluginPackageJson(packageJsonPath) { diff --git a/scripts/lib/official-external-channel-catalog.json b/scripts/lib/official-external-channel-catalog.json index b854f44c77a..d53e14d943c 100644 --- a/scripts/lib/official-external-channel-catalog.json +++ b/scripts/lib/official-external-channel-catalog.json @@ -475,8 +475,9 @@ "systemImage": "message" }, "install": { + "clawhubSpec": "clawhub:@openclaw/whatsapp", "npmSpec": "@openclaw/whatsapp", - "defaultChoice": "npm", + "defaultChoice": "clawhub", "minHostVersion": ">=2026.4.25" } } diff --git a/src/plugins/copy-bundled-plugin-metadata.test.ts b/src/plugins/copy-bundled-plugin-metadata.test.ts index 8644f1af895..b0e15332af2 100644 --- a/src/plugins/copy-bundled-plugin-metadata.test.ts +++ b/src/plugins/copy-bundled-plugin-metadata.test.ts @@ -414,7 +414,7 @@ describe("copyBundledPluginMetadata", () => { expectedExists: false, }, { - name: "still bundles previously released optional plugins without the opt-in env", + name: "removes externalized optional plugin metadata from the core dist", pluginId: "whatsapp", packageName: "@openclaw/whatsapp", packageOpenClaw: { @@ -422,7 +422,7 @@ describe("copyBundledPluginMetadata", () => { install: { npmSpec: "@openclaw/whatsapp" }, }, env: {}, - expectedExists: true, + expectedExists: false, }, ] as const)("$name", ({ pluginId, packageName, packageOpenClaw, env, expectedExists }) => { const repoRoot = makeRepoRoot(`openclaw-bundled-plugin-${pluginId}-`); diff --git a/src/plugins/official-external-plugin-repair-hints.test.ts b/src/plugins/official-external-plugin-repair-hints.test.ts index 60e2b4acf5a..c8c5c646a91 100644 --- a/src/plugins/official-external-plugin-repair-hints.test.ts +++ b/src/plugins/official-external-plugin-repair-hints.test.ts @@ -43,6 +43,31 @@ describe("resolveMissingOfficialExternalChannelPluginRepairHint", () => { }); }); + it("prefers the ClawHub install hint for externalized WhatsApp", () => { + mocks.resolveConfiguredChannelPresencePolicy.mockReturnValue([ + { + channelId: "whatsapp", + sources: ["explicit-config"], + effective: false, + pluginIds: [], + blockedReasons: ["no-channel-owner"], + }, + ]); + + expect( + resolveMissingOfficialExternalChannelPluginRepairHint({ + config: { channels: { whatsapp: { enabled: true } } }, + channelId: "whatsapp", + }), + ).toMatchObject({ + pluginId: "whatsapp", + channelId: "whatsapp", + label: "WhatsApp", + installSpec: "clawhub:@openclaw/whatsapp", + installCommand: "openclaw plugins install clawhub:@openclaw/whatsapp", + }); + }); + it("does not return install hints for policy-blocked official external channel owners", () => { mocks.resolveConfiguredChannelPresencePolicy.mockReturnValue([ { diff --git a/test/official-channel-catalog.test.ts b/test/official-channel-catalog.test.ts index 8dd7c187a9b..44c7559bb04 100644 --- a/test/official-channel-catalog.test.ts +++ b/test/official-channel-catalog.test.ts @@ -85,9 +85,10 @@ describe("buildOfficialChannelCatalog", () => { blurb: "works with your own number; recommend a separate phone + eSIM.", }, install: { + clawhubSpec: "clawhub:@openclaw/whatsapp", npmSpec: "@openclaw/whatsapp", localPath: bundledPluginRoot("whatsapp"), - defaultChoice: "npm", + defaultChoice: "clawhub", }, release: { publishToNpm: true, @@ -195,8 +196,9 @@ describe("buildOfficialChannelCatalog", () => { systemImage: "message", }, install: { + clawhubSpec: "clawhub:@openclaw/whatsapp", npmSpec: "@openclaw/whatsapp", - defaultChoice: "npm", + defaultChoice: "clawhub", minHostVersion: ">=2026.4.25", }, }); @@ -325,8 +327,9 @@ describe("buildOfficialChannelCatalog", () => { systemImage: "message", }, install: { + clawhubSpec: "clawhub:@openclaw/whatsapp", npmSpec: "@openclaw/whatsapp", - defaultChoice: "npm", + defaultChoice: "clawhub", minHostVersion: ">=2026.4.25", }, }); diff --git a/test/scripts/bundled-plugin-build-entries.test.ts b/test/scripts/bundled-plugin-build-entries.test.ts index dc5866c9e74..5450426ffca 100644 --- a/test/scripts/bundled-plugin-build-entries.test.ts +++ b/test/scripts/bundled-plugin-build-entries.test.ts @@ -104,8 +104,10 @@ describe("bundled plugin build entries", () => { expectSomePrefixMatch(Object.keys(entries), `extensions/${pluginId}/`); expectNoPrefixMatches(artifacts, `dist/extensions/${pluginId}/`); } - expectNoPrefixMatches(Object.keys(entries), "extensions/qqbot/"); - expectNoPrefixMatches(artifacts, "dist/extensions/qqbot/"); + for (const pluginId of ["qqbot", "whatsapp"]) { + expectNoPrefixMatches(Object.keys(entries), `extensions/${pluginId}/`); + expectNoPrefixMatches(artifacts, `dist/extensions/${pluginId}/`); + } }); it("keeps bundled channel secret contracts on packed top-level sidecars", () => { diff --git a/test/scripts/postinstall-bundled-plugins.test.ts b/test/scripts/postinstall-bundled-plugins.test.ts index ada42a223e1..ded782721c9 100644 --- a/test/scripts/postinstall-bundled-plugins.test.ts +++ b/test/scripts/postinstall-bundled-plugins.test.ts @@ -221,7 +221,7 @@ describe("bundled plugin postinstall", () => { expect(warn).not.toHaveBeenCalled(); }); - it("patches the Baileys rc10 upload helper dispatcher guard", async () => { + it("patches the Baileys upload helper dispatcher guard", async () => { const packageRoot = await createTempDirAsync("openclaw-baileys-postinstall-"); const mediaFile = await writeBaileysMediaFile( packageRoot, @@ -266,7 +266,7 @@ describe("bundled plugin postinstall", () => { expect(patchedText).not.toContain(" dispatcher: agent,"); }); - it("recognizes already patched Baileys rc10 upload helpers", async () => { + it("recognizes already patched Baileys upload helpers", async () => { const packageRoot = await createTempDirAsync("openclaw-baileys-postinstall-"); await writeBaileysMediaFile( packageRoot,