fix(channels): preserve external catalog overrides#52988
Conversation
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🔵 Untrusted search path for official plugin catalog via process.execPath directory
Description
Vulnerable code: if (process.execPath) {
const execDir = path.dirname(process.execPath);
candidates.push(path.join(execDir, OFFICIAL_CHANNEL_CATALOG_RELATIVE_PATH));
candidates.push(path.join(execDir, "channel-catalog.json"));
}RecommendationDo not treat the executable directory as a trusted source for the official catalog unless you can guarantee it is non-user-writable. Recommended fixes (choose one):
Example (opt-in via env var and path allowlist): function resolveOfficialCatalogPaths(options: CatalogOptions): string[] {
// ...packageRoot candidates...
const allowExecDir = options.env?.OPENCLAW_ALLOW_EXECDIR_CATALOG === "1";
if (allowExecDir && process.execPath) {
const execDir = path.dirname(process.execPath);
// optionally: ensure execDir is within an expected installation prefix
candidates.push(path.join(execDir, OFFICIAL_CHANNEL_CATALOG_RELATIVE_PATH));
}
return dedupe(candidates);
}If the catalog can influence install behavior, consider signing the catalog and verifying the signature before parsing/using it. Analyzed PR: #52988 at commit Last updated on: 2026-03-23T16:28:48Z |
Greptile SummaryThis PR fixes a catalog merge precedence bug introduced in #52913 where shipped fallback metadata (bundled
Confidence Score: 5/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/channels/plugins/catalog.ts
Line: 55-56
Comment:
**Dead `?? 99` fallback on a typed Record key**
`ORIGIN_PRIORITY` is declared as `Record<PluginOrigin, number>`, and `bundled` is a concrete key in that record, so `ORIGIN_PRIORITY.bundled` is always typed as `number` — never `undefined`. The `?? 99` branch is unreachable dead code and may trigger a TypeScript "unnecessary nullish coalescing" lint warning in strict mode.
```suggestion
const EXTERNAL_CATALOG_PRIORITY = ORIGIN_PRIORITY.bundled;
const FALLBACK_CATALOG_PRIORITY = EXTERNAL_CATALOG_PRIORITY + 1;
```
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/channels/plugins/catalog.ts
Line: 55
Comment:
**Tie between `EXTERNAL_CATALOG_PRIORITY` and `ORIGIN_PRIORITY.bundled` relies on loop ordering**
`EXTERNAL_CATALOG_PRIORITY` (3) equals `ORIGIN_PRIORITY.bundled` (3), so the "discovered bundled beats external catalog" invariant is enforced only because the discovered-plugin loop runs before the external-catalog loop, and the comparison is a strict `<` rather than `<=`. This is correct today, but the intent is obscured and is one loop-reorder away from breaking silently.
A slightly lower number (e.g., `ORIGIN_PRIORITY.bundled + 1`) would make external catalogs numerically weaker than all discovered sources without relying on insertion order, while still beating `FALLBACK_CATALOG_PRIORITY`:
```suggestion
const EXTERNAL_CATALOG_PRIORITY = ORIGIN_PRIORITY.bundled + 1;
const FALLBACK_CATALOG_PRIORITY = EXTERNAL_CATALOG_PRIORITY + 1;
```
The regression tests do guard this invariant, so the current state is safe — this is a readability/maintainability note only.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(channels): preserve external catalog..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8dc07b87c5
ℹ️ 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".
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟠 Untrusted external plugin catalogs can override official/bundled channel metadata, enabling supply-chain RCE via arbitrary npm package install
Description
Why this is dangerous:
Vulnerable code (priority override): // External catalogs ... supported override seam for shipped fallback metadata
const priority = EXTERNAL_CATALOG_PRIORITY;
const existing = resolved.get(entry.id);
if (!existing || priority < existing.priority) {
resolved.set(entry.id, { entry, priority });
}Note: RecommendationTreat external catalogs as untrusted by default and prevent silent substitution of official/bundled channel ids. Recommended options (pick one or combine):
Example: disallow overriding known ids unless explicitly allowed: const isKnownFallback = existing && existing.priority >= FALLBACK_CATALOG_PRIORITY;
const allowOverride = options.env?.OPENCLAW_ALLOW_CATALOG_OVERRIDE === "1";
if (!existing || (!isKnownFallback) || allowOverride) {
resolved.set(entry.id, { entry, priority });
}Additionally, log a warning whenever an external catalog overrides a shipped entry, and consider requiring an exact version pin ( Analyzed PR: #52988 at commit Last updated on: 2026-03-23T16:17:48Z |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13ca9a362d
ℹ️ 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".
| const priority = EXTERNAL_CATALOG_PRIORITY; | ||
| const existing = resolved.get(entry.id); | ||
| if (!existing || priority < existing.priority) { | ||
| resolved.set(entry.id, { entry, priority }); |
There was a problem hiding this comment.
Preserve shipped aliases on external channel overrides
When an external catalog reuses a built-in channel ID just to change install.npmSpec, this now replaces the entire shipped catalog entry instead of overlaying it. resolveCatalogChannelEntry() only matches entry.id and entry.meta.aliases (src/commands/channel-setup/channel-plugin-resolution.ts:49-59), and the built-in catalog already relies on shipped aliases such as Microsoft Teams' teams alias (src/channels/plugins/plugins-core.test.ts:119-123). In the private-fork override scenario this patch targets, any external entry that omits aliases/order/other metadata will silently drop those behaviors, so alias-based channel selection and similar metadata-driven flows stop working unless operators duplicate every shipped field in the override file.
Useful? React with 👍 / 👎.
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs (cherry picked from commit 041c474)
* Slack: fix review regressions (cherry picked from commit 0277aa0) * fix(channels): preserve external catalog overrides (openclaw#52988) * fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs (cherry picked from commit 041c474) * Channels: ignore enabled-only disabled plugin config (cherry picked from commit 2c3c48f) * fix(onboarding): use scoped plugin snapshots to prevent OOM on low-memory hosts (openclaw#46763) * fix(onboarding): use scoped plugin snapshots to prevent OOM on low-memory hosts Onboarding and channel-add flows previously loaded the full plugin registry, which caused OOM crashes on memory-constrained hosts. This patch introduces scoped, non-activating plugin registry snapshots that load only the selected channel plugin without replacing the running gateway's global state. Key changes: - Add onlyPluginIds and activate options to loadOpenClawPlugins for scoped loads - Add suppressGlobalCommands to plugin registry to avoid leaking commands - Replace full registry reloads in onboarding with per-channel scoped snapshots - Validate command definitions in snapshot loads without writing global registry - Preload configured external plugins via scoped discovery during onboarding Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(test): add return type annotation to hoisted mock to resolve TS2322 * fix(plugins): enforce cache:false invariant for non-activating snapshot loads * Channels: preserve lazy scoped snapshot import after rebase * Onboarding: scope channel snapshots by plugin id * Catalog: trust manifest ids for channel plugin mapping * Onboarding: preserve scoped setup channel loading * Onboarding: restore built-in adapter fallback --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org> (cherry picked from commit f4cc93d) * Status: lazy-load read-only account inspectors (cherry picked from commit f71f445) * Tests: add plugin contract suites (cherry picked from commit 3105a12) * refactor: share outbound media payload sequencing (cherry picked from commit 5018370) * refactor: share directory config helpers (cherry picked from commit 592dd35) * Tests: add plugin contract registry (cherry picked from commit 6043e73) * refactor: share plugin directory helpers (cherry picked from commit 614844c) * perf(status): defer heavy startup loading (cherry picked from commit 83ee5c0) * refactor: reuse shared core account lookups (cherry picked from commit 8aca2fd) * Slack: fail oversized merged block payloads (cherry picked from commit 98877dc) * fix(whatsapp): trim leading whitespace in direct outbound sends (openclaw#43539) Trim leading whitespace from direct WhatsApp text and media caption sends. Also guard empty text-only web sends after trimming. (cherry picked from commit a5ceb62) * fix: adapt cherry-picks for fork TS strictness * fix: remove upstream-only case-insensitive iMessage account test * fix: revert upstream-only test expectations and source changes --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org> Co-authored-by: Nimrod Gutman <nimrod.gutman@gmail.com> Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com> Co-authored-by: Mason <bwjava@163.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: Luke <92253590+ImLukeF@users.noreply.github.com>
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
…claw#105) * fix(web-search): mark DuckDuckGo experimental * docs(tools): update DuckDuckGo Search for landed plugin code - Mark as experimental (not just unofficial) - Add region and safeSearch tool parameters (from DDG schema) - Add plugin config example for region/safeSearch defaults - Document auto-detection order (100 = last) - Note SafeSearch defaults to moderate - Verified against extensions/duckduckgo/src/ * fix(agents): deny local MEDIA paths for MCP results * Usage: include reset and deleted session archives (openclaw#43215) Merged via squash. Prepared head SHA: 49ed6c2 Co-authored-by: rcrick <23069968+rcrick@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com> Reviewed-by: @frankekn * docs(tools): soften DDG wording (scrapes -> pulls/gathers) * fix(build): add stable memory-cli dist entry (openclaw#51759) Co-authored-by: oliviareid-svg <269669958+oliviareid-svg@users.noreply.github.com> Co-authored-by: Frank <vibespecs@gmail.com> * refactor!: drop legacy CLAWDBOT env compatibility * refactor!: remove moltbot state-dir migration fallback * fix(gateway): preserve async hook ingress provenance * fix(ci): write dist build stamp after builds * perf: trim vitest hot imports and refresh manifests * fix(security): unwrap time dispatch wrappers * fix(plugin-sdk): fall back to src root alias files * fix(ci): skip docs-only preflight pnpm audit * docs(changelog): note time exec approval fix * docs: refresh plugin-sdk api baseline * fix(runtime): make dist-runtime staging idempotent * fix(media): bound remote error-body snippet reads * fix(gateway): gate internal command persistence mutations * fix: restrict remote marketplace plugin sources * fix(runtime): skip peer resolution for bundled plugin deps * docs(agents): prefer current test model examples * fix(exec): escape invisible approval filler chars * test(models): refresh example model fixtures * fix(security): unify dispatch wrapper approval hardening * fix(security): harden explicit-proxy SSRF pinning * fix: gate synology chat reply name matching * docs: clarify sessions_spawn ACP vs subagent policies * refactor(exec): split wrapper resolution modules * refactor(exec): make dispatch wrapper semantics spec-driven * refactor(exec): share wrapper trust planning * refactor(exec): rename wrapper plans for trust semantics * fix: include .npmrc in onboard docker build * test: trim docker live auth mounts * Docs: refresh config baseline for Synology Chat * refactor: clarify synology delivery identity names * refactor: centralize synology dangerous name matching * refactor: narrow synology legacy name lookup * refactor: audit synology dangerous name matching * refactor: dedupe synology config schema * fix: normalize scoped vitest filter paths * fix(voice-call): harden webhook pre-auth guards * fix(synology-chat): fail closed shared webhook paths * docs: credit nexrin in synology changelog * test: fix base vitest thread regressions * test: finish base vitest thread fixture fixes * test(voice-call): accept oversize webhook socket resets * test: honor env auth in gateway live probes * fix: harden plugin docker e2e * Docs: align MiniMax examples with M2.7 * fix(ci): restore stale guardrails and baselines * Test: isolate qr dashboard integration suite * Gateway: resolve fallback plugin context lazily * fix: bind bootstrap setup codes to node profile * fix(tlon): unify settings reconciliation semantics * refactor(synology-chat): type startup webhook path policy * docs(synology-chat): clarify multi-account webhook paths * refactor: unify minimax model and failover live policies * docs: sync minimax m2.7 references * fix: harden Windows Parallels smoke installs * docs: reorder unreleased changelog by user impact * refactor: remove embedded runner cwd mutation * Infra: support shell carrier allow-always approvals * refactor: centralize bootstrap profile handling * refactor: reuse canonical setup bootstrap profile * fix(plugin-sdk): resolve hashed diagnostic events chunks * fix(plugin-sdk): normalize hashed diagnostic event exports * test: fix ci env-sensitive assertions * fix(gateway): fail closed on unresolved discovery endpoints * feat: add slash plugin installs * fix(media): block remote-host file URLs in loaders * fix(media): harden secondary local path seams * test: harden no-isolate reply teardown * docs(changelog): add Windows media security fix * refactor(gateway): centralize discovery target handling * test: narrow live transcript scaffolding strip * test: fix ci docs drift and bun qr exit handling * fix(browser): enforce node browser proxy allowProfiles * refactor(media): share local file access guards * test: stabilize ci test harnesses * test: harden no-isolate test module resets * fix(plugins): preserve live hook registry during gateway runs * test: fix channel summary registry setup * test: harden isolated test mocks * chore(plugins): remove opik investigation checkpoints * ACPX: align pinned runtime version (openclaw#52730) * ACPX: align pinned runtime version * ACPX: drop version example from help text * test: stop leaking image workspace temp dirs * fix(android): gate canvas bridge to trusted pages (openclaw#52722) * fix(android): gate canvas bridge to trusted pages * fix(changelog): note android canvas bridge gating * Update apps/android/app/src/main/java/ai/openclaw/app/node/CanvasActionTrust.kt Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix(android): snapshot canvas URL on UI thread --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * test: isolate base vitest thread blockers * fix: sync agent and autoreply e2e updates * test: harden no-isolate mocked module resets * docs: reorder unreleased changelog * fix(changelog): note windows media path guardrails (openclaw#52738) * fix: alphabetize web search provider listings * docs: clarify unreleased breaking changes * test: harden ci isolated mocks * fix: align websocket stream fallback types * test: finish no-isolate suite hardening * style: format image-generation runtime tests * fix(memory-core): register memory tools independently to prevent coupled failure (openclaw#52668) Merged via admin squash because current required CI failures are inherited from base and match latest `main` failures outside this PR's `memory-core` surface. Prepared head SHA: df7f968 Co-authored-by: artwalker <44759507+artwalker@users.noreply.github.com> Reviewed-by: @frankekn * fix(status): recompute fallback context window (openclaw#51795) * fix(status): recompute fallback context window * fix(status): keep live context token caps on fallback * fix(status): preserve fallback runtime context windows * fix(status): preserve configured fallback context caps * fix(status): keep provider-aware transcript context lookups * fix(status): preserve explicit fallback context caps * fix(status): clamp fallback configured context caps * fix(status): keep raw runtime slash ids * fix(status): refresh plugin-sdk api baseline * fix(status): preserve fallback context lookup * test(status): refresh plugin-sdk api baseline * fix(status): keep runtime slash-id context lookup --------- Co-authored-by: create <create@createdeMacBook-Pro.local> Co-authored-by: Frank Yang <frank.ekn@gmail.com> Co-authored-by: RichardCao <RichardCao@users.noreply.github.com> * fix(telegram): make buttons schema optional in message tool The Telegram plugin injects a `buttons` property into the message tool schema via `createMessageToolButtonsSchema()`, but without wrapping it in `Type.Optional()`. This causes TypeBox to include `buttons` in the JSON Schema `required` array. In isolated sessions (e.g. cron jobs) where no `currentChannel` is set, all plugin schemas are merged into the message tool. When the LLM calls the message tool without a `buttons` parameter, AJV validation fails with: `buttons: must have required property 'buttons'`. Wrap the buttons schema in `Type.Optional()` so it is not required. * fix: keep message-tool buttons optional for Telegram and Mattermost (openclaw#52589) (thanks @tylerliu612) * test: update codex test fixtures to gpt-5.4 * fix: repair runtime seams after rebase * fix: restore Telegram topic announce delivery (openclaw#51688) (thanks @mvanhorn) When `replyLike.text` or `replyLike.caption` is an unexpected non-string value (edge case from some Telegram API responses), the reply body was coerced to "[object Object]" via string concatenation. Add a `typeof === "string"` guard to gracefully fall back to empty string, matching the existing pattern used for `quoteText` in the same function. Co-authored-by: Penchan <penchan@penchan.co> * docs: sync generated release baselines * test: isolate pi embedded model thread fixtures * fix: restore provider runtime lazy boundary * fix: preserve Telegram reply context text (openclaw#50500) (thanks @p3nchan) * fix: guard Telegram reply context text (openclaw#50500) (thanks @p3nchan) * fix: preserve Telegram reply caption fallback (openclaw#50500) (thanks @p3nchan) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us> * fix: harden gateway SIGTERM shutdown (openclaw#51242) (thanks @juliabush) * fix: increase shutdown timeout to avoid SIGTERM hang * fix(telegram): abort polling fetch on shutdown to prevent SIGTERM hang * fix(gateway): enforce hard exit on shutdown timeout for SIGTERM * fix: tighten gateway shutdown watchdog * fix: harden gateway SIGTERM shutdown (openclaw#51242) (thanks @juliabush) --------- Co-authored-by: Ayaan Zaidi <hi@obviy.us> * build: prepare 2026.3.22-beta.1 * fix: restore provider runtime lazy boundary * test: add parallels npm update smoke * test: split pi embedded model thread fixtures * fix: stop browser server tests from launching real chrome * test: stabilize live provider docker probes * fix: restart windows gateway after npm update * test: isolate server-context browser harness imports * test: inject model runtime hooks for thread-safe tests * test: snapshot ci timeout investigation * test: target gemini 3.1 flash alias * test: stabilize trigger handling and hook e2e tests * build: prepare 2026.3.22 * test: harden channel suite isolation * test: inject thread-safe deps for agent tools * test: raise timeout for slow provider auth normalization * ci: stabilize windows and bun unit lanes * test: inject thread-safe gateway and ACP seams * test: isolate pi model and reset-model thread fixtures * build: prepare 2026.3.23 * test: inject image-tool provider deps for raw threads * test: stabilize e2e module isolation * test: decouple vitest config checks from ambient env * fix: harden parallels smoke agent invocation * test: avoid repo-root perf profile artifacts * test: inject thread-safe base seams * fix: document Telegram asDocument alias (openclaw#52461) (thanks @bakhtiersizhaev) * feat(telegram): add asDocument param to message tool Adds `asDocument` as a user-facing alias for the existing `forceDocument` parameter in the message tool. When set to `true`, media files (images, videos, GIFs) are sent via `sendDocument` instead of `sendPhoto`/ `sendVideo`/`sendAnimation`, preserving the original file quality without Telegram compression. This is useful when agents need to deliver high-resolution images or uncompressed files to users via Telegram. `asDocument` is intentionally an alias rather than a replacement — the existing `forceDocument` continues to work unchanged. Changes: - src/agents/tools/message-tool.ts: add asDocument to send schema - src/agents/tools/telegram-actions.ts: OR asDocument into forceDocument - src/infra/outbound/message-action-runner.ts: same OR logic for outbound path - extensions/telegram/src/channel-actions.ts: read and forward asDocument - src/channels/plugins/actions/actions.test.ts: add test case * fix: restore channel-actions.ts to main version (rebase conflict fix) * fix(test): match asDocument test payload to actual params structure * fix(telegram): preserve forceDocument alias semantics * fix: document Telegram asDocument alias (openclaw#52461) (thanks @bakhtiersizhaev) --------- Co-authored-by: Бахтиер Сижаев <bkh@MacBook-Air.local> Co-authored-by: Ayaan Zaidi <hi@obviy.us> * fix: refactor deepseek bundled plugin (openclaw#48762) (thanks @07akioni) * fix: declare typebox runtime dep for mattermost plugin * test: reset line webhook mocks between cases * test: split attempt spawn-workspace thread fixtures * test: remove replaced spawn-workspace monolith * refactor: isolate attempt context engine thread helpers * CI: remove npm release preview workflow (openclaw#52825) * CI: remove npm release preview workflow * Docs: align release maintainer skill with manual publish * Docs: expand release maintainer skill flow * test: stabilize gateway thread harness * test: fix status plugin pagination expectation * test: harden channel suite isolation * build: sync lockfile for mattermost plugin * fix: ensure env proxy dispatcher before MiniMax and OpenAI Codex OAuth flows (openclaw#52228) Verified: - pnpm install --frozen-lockfile - NPM_CONFIG_CACHE=/tmp/openclaw-npm-cache-52228 pnpm build - pnpm check - pnpm test:macmini (failed on inherited pre-existing plugin contract test: src/plugins/contracts/registry.contract.test.ts missing deepseek in bundled provider contract registry outside this PR surface) Co-authored-by: openperf <80630709+openperf@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> * fix: restore ci gates * test: stabilize channel ci gate * docs: refresh generated config baseline * release: verify control-ui assets are included in npm tarball * release-check: include stderr/stdout when npm pack fails * release: add changelog for control UI tarball check * fix: keep session transcript pointers fresh after compaction (openclaw#50688) Co-authored-by: Frank Yang <frank.ekn@gmail.com> * fix(msteams): isolate probe test env credentials * release: automate macOS publishing (openclaw#52853) * release: automate macOS publishing * release: keep mac appcast in openclaw repo * release: add preflight-only release workflow runs * release: keep appcast updates manual * release: generate signed appcast as workflow artifact * release: require preflight before publish * release: require mac app for every release * docs: clarify every release ships mac app * release: document Sparkle feed and SHA rules * release: keep publish flow tag-based * release: stabilize mac appcast flow * release: document local mac fallback * Update CHANGELOG.md * Improve PR template regression prompts * fix(agents): preserve anthropic thinking block order (openclaw#52961) * fix(release): ship bundled plugins in pack artifacts * fix(config): keep built-in channels out of plugin allowlists (openclaw#52964) * fix(config): keep built-in channels out of plugin allowlists * docs(changelog): note doctor whatsapp allowlist fix * docs(changelog): move doctor whatsapp fix to top * Update CHANGELOG.md * fix(config): keep built-in auto-enable idempotent * fix(release): preserve shipped channel surfaces in npm tar (openclaw#52913) * fix(channels): ship official channel catalog (openclaw#52838) * fix(release): keep shipped bundles in npm tar (openclaw#52838) * build(release): fix rebased release-check helpers (openclaw#52838) * fix(gateway): harden supervised lock and browser attach readiness * fix(matrix): avoid duplicate runtime api exports * fix(gateway): avoid probe false negatives after connect * docs(changelog): note release and matrix fixes * fix(plugins): unblock Discord/Slack message tool sends and Feishu media (openclaw#52991) * fix(plugins): unblock Discord and Slack message tool payloads * docs(changelog): note Discord Slack and Feishu message fixes * fix(channels): preserve external catalog overrides (openclaw#52988) * fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs * fix(gateway): require admin for agent session reset * fix(voice-call): stabilize plivo v2 replay keys * fix(gateway): require auth for canvas routes * fix(clawhub): resolve auth token for skill browsing (openclaw#53017) * fix(clawhub): resolve auth token for skill browsing * docs(changelog): note clawhub skill auth fix * fix(release): raise npm pack size budget * Tests: fix fresh-main regressions (openclaw#53011) * Tests: fix fresh-main regressions * Tests: avoid chat notice cache priming --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * fix(config): ignore stale plugin allow entries * fix(browser): reuse running loopback browser after probe miss * fix(clawhub): honor macOS auth config path (openclaw#53034) * docs: fix nav ordering, missing pages, and stale model references - Sort providers alphabetically in docs.json nav - Sort channels alphabetically in docs.json nav (slack before synology-chat) - Add install/migrating-matrix to Maintenance nav section (was orphaned) - Remove zh-CN/plugins/architecture from nav (file does not exist) - Add Voice Call to channels index page - Add missing providers to providers index (DeepSeek, GitHub Copilot, OpenCode Go, Synthetic) - Sort providers index alphabetically - Update stale claude-3-5-sonnet model reference to claude-sonnet-4-6 in webhook docs * fix(clawhub): preserve XDG auth path on macOS * Agents: fix runtime web_search provider selection (openclaw#53020) Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * docs: fix CLI command tree, SDK import path, and tool group listing - Remove non-existent 'secrets migrate' from CLI command tree - Add actual secrets subcommands: audit, configure, apply - Add missing plugin subcommands: inspect, uninstall, update, marketplace list - Fix plugins info -> inspect (actual command name) - Add message send and broadcast subcommands to command tree - Remove misleading deprecated import from sdk-overview - Add sessions_yield and subagents to group:sessions tool group docs - Fix formatting * fix(gateway): guard openrouter auto pricing recursion (openclaw#53055) * test: refresh thread-safe agent fixtures * Release: fix npm release preflight under pnpm (openclaw#52985) Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * docs(changelog): add channel catalog override note (openclaw#52988) (openclaw#53059) * fix: harden update dev switch and refresh changelog * fix(mistral): repair max-token defaults and doctor migration (openclaw#53054) * fix(mistral): repair max-token defaults and doctor migration * fix(mistral): add missing small-model repair cap * fix(plugins): enable bundled Brave web search plugin by default (openclaw#52072) Brave is a bundled web search plugin but was missing from BUNDLED_ENABLED_BY_DEFAULT, causing it to be filtered out during provider resolution. This made web_search unavailable even when plugins.entries.brave.enabled was configured. Fixes openclaw#51937 Co-authored-by: Ubuntu <ubuntu@ip-172-26-10-234.us-west-2.compute.internal> Co-authored-by: Vincent Koc <vincentkoc@ieee.org> * fix(release): fail empty control ui tarballs * Revert "fix(plugins): enable bundled Brave web search plugin by default (openclaw#52072)" This reverts commit 0ea3c4d. * Telegram: preserve inbound debounce order * Telegram: fix fire-and-forget debounce order * fix(reply): refresh followup drain callbacks * Update CHANGELOG.md * fix(reply): preserve no-debounce inbound concurrency * fix(reply): clear idle followup callbacks * fix(inbound): bound tracked debounce keys * fix: preserve debounce and followup ordering (openclaw#52998) (thanks @osolmaz) * fix(discord): reply on native command auth failures (openclaw#53072) * docs(changelog): add missing recent fixes * fix: bound tracked debounce key accounting * fix packaged control ui asset lookup (openclaw#53081) * fix(cli): preserve posix default git dir * build: prepare 2026.3.23-beta.1 * test: harden canvas host undici isolation * docs(changelog): credit web search runtime fix * fix(openai-codex): bootstrap proxy on oauth refresh (openclaw#53078) Verified: - pnpm install --frozen-lockfile - pnpm exec vitest run extensions/openai/openai-codex-provider.runtime.test.ts extensions/openai/openai-provider.test.ts * release: harden preflight workflows (openclaw#53087) * release: harden preflight-only workflows * release: require main for publish runs * release: select xcode for macos workflow * release: retry flaky macos preflight steps * ci: shard bun test lane * Fix Control UI operator.read scope handling (openclaw#53110) Preserve Control UI scopes through the device-auth bypass path, normalize implied operator device-auth scopes, ignore cached under-scoped operator tokens, and degrade read-backed main pages gracefully when a connection truly lacks operator.read. Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com> * build: prepare 2026.3.23 * fix(agents): prefer runtime snapshot for skill secrets * docs(changelog): note skill secretref runtime fix * fix(memory): bootstrap lancedb runtime on demand (openclaw#53111) Bootstrap LanceDB into plugin runtime state on first use for packaged/global installs, keep @lancedb/lancedb plugin-local, and add regression coverage for bundled, cached, retry, and Nix fail-fast runtime paths. Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com> * build: finalize 2026.3.23 release * release: upload macos preflight artifacts (openclaw#53105) * release: upload macos preflight artifacts * release: speed up macos preflight * release: use xlarge macos runner * release: skip dmg path in macos preflight * fix(subagents): recheck timed-out announce waits (openclaw#53127) Recheck timed-out subagent announce waits against the latest runtime snapshot before announcing timeout, and keep that recheck best-effort so transient gateway failures do not suppress the announcement. Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com> * docs(feishu): replace botName with name in config examples (openclaw#52753) Merged via squash. Prepared head SHA: 5237726 Co-authored-by: haroldfabla2-hue <229189334+haroldfabla2-hue@users.noreply.github.com> Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com> Reviewed-by: @altaywtf * fix(plugins): accept clawhub uninstall specs * test(auth): align device scope expectations (openclaw#53151) * fix: prevent delivery-mirror re-delivery and raise Slack chunk limit (openclaw#45489) Merged via squash. Prepared head SHA: c7664c7 Co-authored-by: theo674 <261068216+theo674@users.noreply.github.com> Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com> Reviewed-by: @altaywtf * Infra: tighten shell-wrapper positional-argv allowlist matching (openclaw#53133) * Infra: tighten shell carrier allowlist matching * fix(security): tighten shell carrier allowlist matcher * fix: generalize api_error detection for fallback model triggering (openclaw#49611) Co-authored-by: Ayush Ojha <7945279+ayushozha@users.noreply.github.com> Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com> * feat(modelstudio): add standard (pay-as-you-go) DashScope endpoints for Qwen (openclaw#43878) Add Standard API Key auth methods for China (dashscope.aliyuncs.com) and Global/Intl (dashscope-intl.aliyuncs.com) pay-as-you-go endpoints alongside the existing Coding Plan (subscription) endpoints. Also updates group label to 'Qwen (Alibaba Cloud Model Studio)' and fixes glm-4.7 -> glm-5 in Coding Plan note messages. Co-authored-by: wenmeng zhou <wenmengzhou@users.noreply.github.com> * Release: privatize macOS publish flow (openclaw#53166) * fix(diagnostics): redact credentials from cache-trace diagnostic output Refs openclaw#53103 * Release: document manual macOS asset upload (openclaw#53178) * Release: document manual macOS asset upload * Release: document macOS smoke-test mode * docs(changelog): reorder release highlights * test(whatsapp): stabilize login coverage in shared workers * test(whatsapp): preserve session exports in login coverage * test(whatsapp): preserve media test module exports * test(whatsapp): preserve harness session exports * fix(ci): stabilize whatsapp extension checks * test: make update-cli checkout path assertion platform-safe * fix(auth): prevent stale auth store reverts (openclaw#53211) * Doctor: prune stale plugin allowlist and entry refs (openclaw#53187) Signed-off-by: sallyom <somalley@redhat.com> * test: stabilize test isolation * test: update command coverage * test: expand gemini live transcript stripping * test: fix update-cli default path assertion * chore(sre:PLA-920): adopt upstream sync changes * fix(sre:PLA-920): align branch with adopted upstream tree * build(sre:PLA-920): refresh dist artifacts * test(sre:PLA-920): align incident-format expectations --------- Signed-off-by: sallyom <somalley@redhat.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org> Co-authored-by: Peter Steinberger <steipete@gmail.com> Co-authored-by: Rick_Xu <rick_xu@asus.com> Co-authored-by: rcrick <23069968+rcrick@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com> Co-authored-by: oliviareid-svg <oliviareid@visionclaw.dev> Co-authored-by: oliviareid-svg <269669958+oliviareid-svg@users.noreply.github.com> Co-authored-by: Frank <vibespecs@gmail.com> Co-authored-by: scoootscooob <zhentongfan@gmail.com> Co-authored-by: ruochen <wangrui@ruochen.email> Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Frank Yang <frank.ekn@gmail.com> Co-authored-by: artwalker <44759507+artwalker@users.noreply.github.com> Co-authored-by: RichardCao <create0818@163.com> Co-authored-by: create <create@createdeMacBook-Pro.local> Co-authored-by: RichardCao <RichardCao@users.noreply.github.com> Co-authored-by: liuyang <liuyang@hkgai.org> Co-authored-by: Ayaan Zaidi <hi@obviy.us> Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com> Co-authored-by: Penchan <penchan@penchan.co> Co-authored-by: Penchan <5032148+p3nchan@users.noreply.github.com> Co-authored-by: Julia Bush <j.elizabethbush@gmail.com> Co-authored-by: Bakhtier Sizhaev <108124494+bakhtiersizhaev@users.noreply.github.com> Co-authored-by: Бахтиер Сижаев <bkh@MacBook-Air.local> Co-authored-by: wangchunyue <80630709+openperf@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Co-authored-by: evann <newmanevanv@myyahoo.com> Co-authored-by: Robin Waslander <r.waslander@gmail.com> Co-authored-by: Sathvik Veerapaneni <98241593+Sathvik-Chowdary-Veerapaneni@users.noreply.github.com> Co-authored-by: Nimrod Gutman <nimrod.gutman@gmail.com> Co-authored-by: Luke <92253590+ImLukeF@users.noreply.github.com> Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com> Co-authored-by: Jamil Zakirov <jamil@zakirov.com> Co-authored-by: TheRipper <144421782+DavidNitZ@users.noreply.github.com> Co-authored-by: Quinn H. <quinnhou@foxmail.com> Co-authored-by: Ubuntu <ubuntu@ip-172-26-10-234.us-west-2.compute.internal> Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com> Co-authored-by: betoblair <alberto.farah.b@gmail.com> Co-authored-by: haroldfabla2-hue <229189334+haroldfabla2-hue@users.noreply.github.com> Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com> Co-authored-by: Altay <altay@uinaf.dev> Co-authored-by: theo674 <theo@takethesis.com> Co-authored-by: theo674 <261068216+theo674@users.noreply.github.com> Co-authored-by: Ayush Ojha <ayushojzha@gmail.com> Co-authored-by: Ayush Ojha <7945279+ayushozha@users.noreply.github.com> Co-authored-by: George Zhang <georgezhangtj97@gmail.com> Co-authored-by: wenmeng zhou <wenmengzhou@users.noreply.github.com> Co-authored-by: Onur <onur@textcortex.com> Co-authored-by: Sally O'Malley <somalley@redhat.com>
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
* fix(channels): preserve external catalog overrides * fix(channels): clarify catalog precedence * fix(channels): respect overridden install specs
Summary
Describe the problem and fix in 2–5 bullets:
dist/channel-catalog.jsoncould take over a channel ID before external catalogs were merged.whatsappfork and install the hard-coded shippednpmSpecinstead.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause / Regression History (if applicable)
For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write
N/A. If the cause is unclear, writeUnknown.git blame, prior PR, issue, or refactor if known): this behavior came in during the fallback catalog work in fix(release): preserve shipped channel surfaces in npm tar #52913.Regression Test Plan (if applicable)
For bug fixes or regressions, name the smallest reliable test coverage that should have caught this. Otherwise write
N/A.src/channels/plugins/plugins-core.test.tsUser-visible / Behavior Changes
Catalog-driven channel overrides work again for channels that are also present in shipped fallback metadata.
Security Impact (required)
Yes/No): NoYes/No): NoYes/No): NoYes/No): NoYes/No): NoYes, explain risk + mitigation:Repro + Verification
Environment
Darwin 25.3.0OPENCLAW_BUNDLED_PLUGINS_DIR,OPENCLAW_PLUGIN_CATALOG_PATHS, andofficialCatalogPathsSteps
whatsapp.install.npmSpec.listChannelPluginCatalogEntries()and inspect the selected entry.Expected
Actual
Evidence
Attach at least one:
Human Verification (required)
What you personally verified (not just CI), and how:
pnpm check;pnpm test -- src/channels/plugins/plugins-core.test.tsafter the fix.Review Conversations
If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.
Compatibility / Migration
Yes/No): YesYes/No): NoYes/No): NoFailure Recovery (if this breaks)
8dc07b87c5.src/channels/plugins/catalog.tsandsrc/channels/plugins/plugins-core.test.ts.Risks and Mitigations
List only real risks for this PR. Add/remove entries as needed. If none, write
None.