Skip to content

fix: keep whatsapp and acpx bundled, show install hint for missing channel plugins [AI-assisted]#52846

Closed
armanddp wants to merge 1 commit intoopenclaw:mainfrom
armanddp:fix/doctor-detect-missing-optional-plugins
Closed

fix: keep whatsapp and acpx bundled, show install hint for missing channel plugins [AI-assisted]#52846
armanddp wants to merge 1 commit intoopenclaw:mainfrom
armanddp:fix/doctor-detect-missing-optional-plugins

Conversation

@armanddp
Copy link
Copy Markdown
Contributor

@armanddp armanddp commented Mar 23, 2026

Problem

Upgrading from 2026.3.13 to 2026.3.22 silently breaks WhatsApp and ACPX. Both were added to optionalBundledClusters but:

  • Neither has a published npm package (@openclaw/whatsapp, @openclaw/acpx return 404)
  • The ClawHub [email protected] package is broken (missing openclaw.extensions metadata)
  • The validation warning says "stale config entry ignored; remove it from plugins config" — the opposite of what users should do

6 of 13 optional bundled plugins are completely unavailable on 2026.3.22 (not bundled, not on npm): whatsapp, acpx, googlechat, diffs, memory-lancedb, ui.

Fix

Single commit with three targeted changes to ease the transition to channels-as-plugins:

1. Keep whatsapp and acpx in default builds (scripts/lib/optional-bundled-clusters.mjs)

Remove whatsapp and acpx from the optional list. Both are core functionality — WhatsApp is a primary messaging channel (bundled since day one) and ACPX is the ACP/Codex runtime. Once their npm packages are published and stable, they can move back to optional with proper migration guidance.

2. Include WhatsApp runtime API entries in the extension build (extensions/whatsapp/package.json)

The WhatsApp plugin uses a lazy boundary pattern that resolves light-runtime-api, runtime-api, and other modules at runtime. These were not listed in openclaw.extensions, so tsdown never compiled them into dist/extensions/whatsapp/. Without this, tarball installs crash with:

WhatsApp plugin runtime is unavailable: missing light-runtime-api for plugin 'whatsapp'

3. Show install hint for configured-but-missing channel plugins (src/config/validation.ts)

When a missing plugin matches a known channel ID with active configuration, show an actionable install command. This covers both plugins.entries and plugins.allow paths.

Before:

plugin not found: whatsapp (stale config entry ignored; remove it from plugins config)

After:

plugin not installed: whatsapp — channel is configured but the plugin is not bundled
in this build. Install it with: openclaw plugins install whatsapp

Changes

File Change
scripts/lib/optional-bundled-clusters.mjs Remove whatsapp and acpx from optional list
extensions/whatsapp/package.json Add runtime API entries to openclaw.extensions
src/plugins/bundled-plugin-metadata.generated.ts Regenerated (reflects new extension entries)
src/config/validation.ts Install hint for configured-but-missing channel plugins
src/config/config.plugin-validation.test.ts Test for install hint behavior

Testing

  • Unit tests: pnpm vitest run src/config/config.plugin-validation.test.ts — 16/16 pass
  • Extension tests: pnpm test:extension whatsapp — 297/305 pass (8 pre-existing failures in login.test.ts timer mocks, unrelated to this change)
  • Build from source: pnpm build → verified dist/extensions/whatsapp/ includes light-runtime-api.js, runtime-api.js, etc.
  • Tarball install: npm packnpm install -g openclaw-2026.3.23.tgz → gateway restart → WhatsApp connected and processing messages (not a symlink — real tarball install)
  • Fully tested end-to-end on macOS arm64

Review feedback addressed

  • Hoisted KNOWN_CHANNEL_ID_SET to module scope (greptile P2)
  • Added expect(res.ok).toBe(true) assertion (greptile P2)
  • Install hint fires for plugins.allow entries too, not just plugins.entries (codex P1)
  • Extracted isConfiguredChannel() helper (codex P1)

AI-assisted

Fixes #52838

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 23, 2026

Greptile Summary

This PR improves the UX for users upgrading from builds that included WhatsApp/ACPX as bundled channels: instead of the misleading "stale config entry" message, they now receive an actionable install hint (openclaw plugins install whatsapp) when the channel is actively configured but the plugin is not present in the registry.

The implementation is tightly scoped — the new branch is guarded by both warnOnly (so only the plugins.entries code path is affected, not plugins.allow/plugins.deny/plugins.slots.memory) and an active channels.* configuration check, making false positives very unlikely.

Key changes:

  • src/config/validation.ts: A new guard inside pushMissingPluginIssue intercepts missing-plugin events for known channel IDs (CHANNEL_IDS) when the channel is actively configured, emitting a targeted install hint warning instead of the stale-entry warning.
  • src/config/config.plugin-validation.test.ts: A focused test verifies the install hint appears and the stale-entry message does not.

Confidence Score: 5/5

  • Safe to merge — changes are additive, well-guarded, and only affect the warning message path.
  • The fix is narrow (only warnOnly + known channel ID + active channel config), CHANNEL_IDS statically includes whatsapp so the new branch triggers correctly, existing error paths are untouched, and the test validates both positive and negative assertions. The two remaining notes (module-level constant, missing res.ok assertion) are non-blocking style improvements.
  • No files require special attention.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/config/validation.ts
Line: 527

Comment:
**Module-level constant preferred**

`KNOWN_CHANNEL_ID_SET` is derived entirely from `CHANNEL_IDS`, which is a compile-time constant. Rebuilding the `Set` inside the function on every call to `validateConfigObjectWithPluginsBase` is harmless (it's a tiny array), but hoisting it to module scope makes the intent clearer and avoids unnecessary allocations:

```suggestion
  const CHANNEL_IDS_SET: ReadonlySet<string> = new Set(CHANNEL_IDS);
```

…or better yet, declare it at module scope alongside `LEGACY_REMOVED_PLUGIN_IDS`:

```ts
const KNOWN_CHANNEL_ID_SET: ReadonlySet<string> = new Set(CHANNEL_IDS as readonly string[]);
```

Then remove the local declaration and reference the module-level constant inside the function.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/config/config.plugin-validation.test.ts
Line: 538

Comment:
**Test doesn't assert `res.ok === true`**

The comment says "Config should still be valid (warnOnly path)" but the assertion is never made. If a future change accidentally starts emitting issues instead of warnings (making `res.ok === false`), this test would still pass because `res.warnings` is present on both result shapes. Adding an explicit `ok` assertion closes that gap:

```suggestion
    expect(res.ok).toBe(true);
    // Config should still be valid (warnOnly path) but with an install hint.
    expect(res.warnings).toContainEqual({
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: show install hint when channel plug..." | Re-trigger Greptile

const { registry } = ensureRegistry();
const knownIds = ensureKnownIds();
const normalizedPlugins = ensureNormalizedPlugins();
const KNOWN_CHANNEL_ID_SET: ReadonlySet<string> = new Set(CHANNEL_IDS as readonly string[]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Module-level constant preferred

KNOWN_CHANNEL_ID_SET is derived entirely from CHANNEL_IDS, which is a compile-time constant. Rebuilding the Set inside the function on every call to validateConfigObjectWithPluginsBase is harmless (it's a tiny array), but hoisting it to module scope makes the intent clearer and avoids unnecessary allocations:

Suggested change
const KNOWN_CHANNEL_ID_SET: ReadonlySet<string> = new Set(CHANNEL_IDS as readonly string[]);
const CHANNEL_IDS_SET: ReadonlySet<string> = new Set(CHANNEL_IDS);

…or better yet, declare it at module scope alongside LEGACY_REMOVED_PLUGIN_IDS:

const KNOWN_CHANNEL_ID_SET: ReadonlySet<string> = new Set(CHANNEL_IDS as readonly string[]);

Then remove the local declaration and reference the module-level constant inside the function.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/config/validation.ts
Line: 527

Comment:
**Module-level constant preferred**

`KNOWN_CHANNEL_ID_SET` is derived entirely from `CHANNEL_IDS`, which is a compile-time constant. Rebuilding the `Set` inside the function on every call to `validateConfigObjectWithPluginsBase` is harmless (it's a tiny array), but hoisting it to module scope makes the intent clearer and avoids unnecessary allocations:

```suggestion
  const CHANNEL_IDS_SET: ReadonlySet<string> = new Set(CHANNEL_IDS);
```

…or better yet, declare it at module scope alongside `LEGACY_REMOVED_PLUGIN_IDS`:

```ts
const KNOWN_CHANNEL_ID_SET: ReadonlySet<string> = new Set(CHANNEL_IDS as readonly string[]);
```

Then remove the local declaration and reference the module-level constant inside the function.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

entries: { whatsapp: { enabled: true } },
},
});
// Config should still be valid (warnOnly path) but with an install hint.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Test doesn't assert res.ok === true

The comment says "Config should still be valid (warnOnly path)" but the assertion is never made. If a future change accidentally starts emitting issues instead of warnings (making res.ok === false), this test would still pass because res.warnings is present on both result shapes. Adding an explicit ok assertion closes that gap:

Suggested change
// Config should still be valid (warnOnly path) but with an install hint.
expect(res.ok).toBe(true);
// Config should still be valid (warnOnly path) but with an install hint.
expect(res.warnings).toContainEqual({
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/config/config.plugin-validation.test.ts
Line: 538

Comment:
**Test doesn't assert `res.ok === true`**

The comment says "Config should still be valid (warnOnly path)" but the assertion is never made. If a future change accidentally starts emitting issues instead of warnings (making `res.ok === false`), this test would still pass because `res.warnings` is present on both result shapes. Adding an explicit `ok` assertion closes that gap:

```suggestion
    expect(res.ok).toBe(true);
    // Config should still be valid (warnOnly path) but with an install hint.
    expect(res.warnings).toContainEqual({
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8a426f8d5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +537 to +543
});
return;
}
// When a missing plugin corresponds to a known channel that is configured,
// it is almost certainly an optional bundled plugin that needs to be
// installed separately rather than a stale leftover.
if (opts?.warnOnly && KNOWN_CHANNEL_ID_SET.has(pluginId)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include extension-backed optional channels in this install-hint check

Because KNOWN_CHANNEL_ID_SET is built only from CHANNEL_IDS, this branch only recognizes the built-in chat IDs from src/channels/ids.ts:4-14. Most optional bundled channel plugins that were moved out of the default build (matrix, msteams, nostr, tlon, twitch, zalouser) are extension channels listed in scripts/lib/optional-bundled-clusters.mjs:1-14, and their config still lives under channels.* (src/config/zod-schema.providers.ts:25-46). Those upgrades will continue to fall through to the old unknown channel id/stale-entry behavior instead of getting the new install guidance, so this fix only covers a small subset of the affected channels.

Useful? React with 👍 / 👎.

Comment on lines +550 to +553
warnings.push({
path,
message: `plugin not installed: ${pluginId} — channel is configured but the plugin is not bundled in this build. Install it with: openclaw plugins install ${pluginId}`,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use the declared npm install spec in the warning

This message hard-codes openclaw plugins install ${pluginId}, but the official install surface for repo-owned channel plugins is the package's declared install.npmSpec (for example @openclaw/whatsapp in extensions/whatsapp/package.json:36-40), and ensureChannelSetupPluginInstalled installs that exact spec in src/commands/channel-setup/plugin-install.ts:185-199. For channels whose package name is scoped, users following this new warning on stable/beta builds can still fail to install the plugin or resolve a different package than the one OpenClaw expects.

Useful? React with 👍 / 👎.

@armanddp
Copy link
Copy Markdown
Contributor Author

Updated the parent issue (#52838) with a full audit of all 13 optional bundled clusters. 6 of 13 are completely unavailable on 2026.3.22 (not bundled, not on npm) — including whatsapp and acpx which are core functionality.

This PR handles the UX side (better error message → install hint), but the root issue is that the npm release workflow doesn't set OPENCLAW_INCLUDE_OPTIONAL_BUNDLED=1 and the plugin-npm-release workflow hasn't been run for the 6 missing packages.

See the full breakdown and workaround in the issue comment: #52838 (comment)

@openclaw-barnacle openclaw-barnacle bot added scripts Repository scripts size: S and removed size: XS labels Mar 23, 2026
@armanddp armanddp force-pushed the fix/doctor-detect-missing-optional-plugins branch from 81bb97c to 80b0ca6 Compare March 23, 2026 13:09
@armanddp armanddp changed the title fix: show install hint when channel plugin is configured but not bundled fix: keep whatsapp and acpx bundled, show install hint for missing channel plugins Mar 23, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80b0ca6e7b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// When a missing plugin corresponds to a known channel that is configured,
// it is almost certainly an optional bundled plugin that needs to be
// installed separately rather than a stale leftover.
if (opts?.warnOnly && KNOWN_CHANNEL_ID_SET.has(pluginId)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Downgrade missing allowlisted optional channels to install hints

When a built-in channel becomes optional-bundled (for example googlechat in scripts/lib/optional-bundled-clusters.mjs:8-19), upgrades with a non-empty plugins.allow still fail validation. enablePluginInConfig appends built-in channel IDs to plugins.allow whenever an allowlist exists (src/plugins/enable.ts:21-22, src/plugins/enable.test.ts:43-52), but this new branch only runs on the warnOnly path used for plugins.entries.*; the later plugins.allow check still emits a hard plugin not found error. That leaves existing allowlisted channel installs unable to start instead of getting the migration guidance this patch is supposed to add.

Useful? React with 👍 / 👎.

Comment on lines +550 to +553
warnings.push({
path,
message: `plugin not installed: ${pluginId} — channel is configured but the plugin is not bundled in this build. Install it with: openclaw plugins install ${pluginId}`,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit the install hint for channel-only configs as well

This hint is only reached after an unknown plugin ID is found under plugins.entries, but bundled chat channels can be enabled from channels.<id>.enabled=true alone (src/plugins/config-state.test.ts:171-176, src/plugins/loader.test.ts:753-766). For optional-bundled built-ins like googlechat (scripts/lib/optional-bundled-clusters.mjs:8-19), a config that only sets channels.googlechat.enabled=true never creates plugins.entries.googlechat, so validation now succeeds with no warning at all even though the channel plugin is absent and will not load.

Useful? React with 👍 / 👎.

@GodsBoy
Copy link
Copy Markdown
Contributor

GodsBoy commented Mar 23, 2026

Can confirm the root cause analysis here is spot on. I filed #52857 independently with the same findings (npm 404 for @openclaw/whatsapp, missing dist/extensions/whatsapp/ in the published tarball, runtime files orphaned in dist/).

The two-part fix makes sense: keeping whatsapp and acpx bundled until proper npm packages exist is the right call, and the install hint for missing channel plugins is a solid UX improvement over the misleading "stale config entry" message.

Tested the regression on a live VPS upgrade from v2026.3.13 to v2026.3.22 — WhatsApp silently disappeared, Telegram recovered fine. Rolling back restored WhatsApp. This PR addresses the packaging root cause correctly.

@Henryy417
Copy link
Copy Markdown

Henryy417 commented Mar 23, 2026

Agree on kepping whatsapp in default builds. Whatsapp is a rather common channel used, it should not be marked as optional as it does not appear to be only of regional minor usage, despite its bulkiness.

@armanddp armanddp force-pushed the fix/doctor-detect-missing-optional-plugins branch from 80b0ca6 to bdd5ddb Compare March 23, 2026 14:06
@openclaw-barnacle openclaw-barnacle bot added the channel: whatsapp-web Channel integration: whatsapp-web label Mar 23, 2026
@armanddp armanddp force-pushed the fix/doctor-detect-missing-optional-plugins branch from bdd5ddb to 274029f Compare March 23, 2026 14:13
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 274029ffea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +23 to +27
"./index.ts",
"./light-runtime-api.ts",
"./runtime-api.ts",
"./api.ts",
"./auth-presence.ts",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep WhatsApp helper barrels out of openclaw.extensions

openclaw.extensions is consumed as the set of loadable plugin entrypoints in src/plugins/discovery.ts:584-603 and src/plugins/discovery.ts:715-730, not as a generic “files to publish” list. Once this array has more than one entry, deriveIdHint() switches the primary candidate to whatsapp/index (src/plugins/discovery.ts:339-365), which src/plugins/manifest-registry.ts:388-394 immediately reports as a plugin id mismatch for manifest id whatsapp. That warning is then surfaced during config validation and normal gateway startup (src/config/validation.ts:411-418, src/gateway/server-plugins.ts:429-444), so this change makes every bundled/workspace WhatsApp load look broken even when the plugin is fine.

Useful? React with 👍 / 👎.

Comment on lines +554 to +557
if (isConfiguredChannel(pluginId)) {
warnings.push({
path,
message: `plugin not installed: ${pluginId} — channel is configured but the plugin is not bundled in this build. Install it with: openclaw plugins install ${pluginId}`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Extend the install hint to plugin-entry-enabled channel configs

This new branch only looks at channels.<id> before deciding to show the install guidance. An explicit plugins.entries.<id>.enabled = true is also a supported way to enable a channel plugin — resolveEnableState() treats entry.enabled === true as enabled even without any channels.<id> section (src/plugins/config-state.ts:286-301) — so those plugin-centric configs still fall through to the old stale config entry ignored warning. In practice, upgrades that enable a channel through plugins.entries.whatsapp will still get told to remove the config instead of being shown how to install the missing plugin.

Useful? React with 👍 / 👎.

@armanddp armanddp force-pushed the fix/doctor-detect-missing-optional-plugins branch from 274029f to 8b8ae88 Compare March 23, 2026 14:27
@armanddp armanddp changed the title fix: keep whatsapp and acpx bundled, show install hint for missing channel plugins fix: keep whatsapp and acpx bundled, show install hint for missing channel plugins [AI-assisted] Mar 23, 2026
…annel plugins

Two changes to ease the transition to channels-as-plugins:

1. Remove whatsapp and acpx from optionalBundledClusters so they ship
   in npm and Docker releases. Both are core functionality with no
   published npm package yet, so excluding them leaves users with no
   install path. Once @openclaw/whatsapp and @openclaw/acpx are
   published and stable, they can move back to optional with proper
   migration guidance.

2. When a missing plugin matches a known channel with active config,
   show an actionable install hint instead of the misleading 'stale
   config entry' message. This covers both plugins.entries and
   plugins.allow paths, helping users of remaining optional channels
   (googlechat, matrix, msteams, etc.) find the right fix.

Also adds the WhatsApp runtime API entries (light-runtime-api,
runtime-api, etc.) to openclaw.extensions so they are compiled into
dist/extensions/whatsapp/ — without these, tarball installs crash
with 'missing light-runtime-api for plugin whatsapp'.

Fixes openclaw#52838
@armanddp armanddp force-pushed the fix/doctor-detect-missing-optional-plugins branch from 8b8ae88 to 160c0c0 Compare March 23, 2026 14:33
@aipwp-claw
Copy link
Copy Markdown

Cmon @steipete fix it man <3

@openclaw-barnacle openclaw-barnacle bot removed the channel: whatsapp-web Channel integration: whatsapp-web label Mar 23, 2026
@armanddp
Copy link
Copy Markdown
Contributor Author

Addressed Codex review feedback (latest push)

P2: Keep WhatsApp helper barrels out of openclaw.extensions

Reverted — runtime .ts shim files (light-runtime-api.ts, runtime-api.ts, etc.) are now copied during copy-bundled-plugin-metadata.mjs postbuild instead of being declared as extension entries. This avoids the deriveIdHint multi-extension plugin id mismatch issue while ensuring tarball installs have the files the WhatsApp boundary resolves via jiti.

P2: Extend the install hint to plugin-entry-enabled channel configs

Noted. The current implementation covers the most common upgrade path (channels.<id> + plugins.entries.<id> both present). Extending to pure plugins.entries.<id>.enabled = true without a channels.<id> section is valid but a less common pattern. Happy to add if a maintainer considers it in scope.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 160c0c0c0a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +254 to +265
for (const file of fs.readdirSync(pluginDir)) {
if (!file.endsWith(".ts") || file.endsWith(".test.ts") || file.endsWith(".runtime.ts")) {
continue;
}
const baseName = file.replace(/\.[^.]+$/u, "");
if (declaredEntries.has(baseName)) {
continue;
}
const sourceFile = path.join(pluginDir, file);
const distFile = path.join(distPluginDir, file);
if (fs.statSync(sourceFile).isFile()) {
fs.copyFileSync(sourceFile, distFile);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Build the runtime shims instead of copying raw .ts files

This postbuild only copies top-level shim sources into dist/extensions/<plugin>, but the shims it is trying to rescue still immediately re-export ./src/*.js (for example extensions/whatsapp/runtime-api.ts and light-runtime-api.ts). tsdown.config.ts only emits declared openclaw.extensions/setupEntry entrypoints, so no dist/extensions/whatsapp/src/* tree is generated alongside these copied files. In packaged installs, src/plugins/runtime/runtime-whatsapp-boundary.ts resolves dist/extensions/whatsapp/runtime-api.ts, Jiti has no sibling sources to rewrite against, and the WhatsApp runtime still fails to load.

Useful? React with 👍 / 👎.

Comment on lines +4 to 8
// WhatsApp and ACPX were removed from this list to ease the transition to
// channels-as-plugins. Both are core functionality (primary messaging channel
// and ACP/Codex runtime) and have no published npm package yet, so excluding
// them from the default build leaves users with no install path.
export const optionalBundledClusters = [
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep ACPX optional until its bundled dependency is staged

Removing acpx from optionalBundledClusters makes every default build claim ACPX is bundled, but scripts/stage-bundled-plugin-runtime-deps.mjs only installs bundled plugin dependencies when openclaw.bundle.stageRuntimeDependencies === true, and extensions/acpx/package.json does not opt in. That means the default package still ships without dist/extensions/acpx/node_modules/.bin/acpx, so resolveAcpxPluginConfig() falls back to a runtime npm install [email protected]; on offline or registry-restricted hosts the newly bundled ACP backend still comes up broken.

Useful? React with 👍 / 👎.

@vincentkoc
Copy link
Copy Markdown
Member

Thanks but we are working on a fix ourselves and will be released very shortly.

@vincentkoc vincentkoc closed this Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scripts Repository scripts size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: WhatsApp (and other optional bundled plugins) silently broken after upgrade to 2026.3.22

5 participants