fix(channels): load third-party official channel packages · openclaw/openclaw@4781b46
vincentkoc
·
2026-05-03
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -22,6 +22,8 @@ Docs: https://docs.openclaw.ai
|
22 | 22 | - Plugins/onboarding: trust optional official plugin and web-search installs selected from the official catalog so npm security scanning treats them like other source-linked official install paths. Thanks @vincentkoc. |
23 | 23 | - Microsoft Teams: persist sent-message markers across Gateway restarts so follow-up replies to recent bot messages keep resolving the original conversation instead of dropping out after restart, with marker TTLs preserved on best-effort recovery. (#75585) Thanks @amknight. |
24 | 24 | - Matrix: persist pending approval reaction targets across Gateway restarts so room approvers can still approve or deny outstanding prompts after OpenClaw comes back online. (#75586) Thanks @amknight. |
| 25 | +- Channels/onboarding: map third-party official WeCom and Yuanbao catalog entries to their published plugin ids so npm installs pass expected-plugin validation. Thanks @vincentkoc. |
| 26 | +- Plugin SDK: restore the Mattermost and Matrix compatibility subpaths used by the pinned Yuanbao channel package so external installs can module-load after npm install. Thanks @vincentkoc. |
25 | 27 | - CLI/plugins: keep `plugins enable` and `plugins disable` from creating unconfigured channel config sections, so channel plugins with required setup fields no longer fail validation during lifecycle probes. Thanks @vincentkoc. |
26 | 28 | - Agents/sessions: keep delayed `sessions_send` A2A replies alive after soft wait-window timeouts, while preserving terminal run timeouts and avoiding stale target replies in requester sessions. Fixes #76443. Thanks @ryswork1993 and @vincentkoc. |
27 | 29 | - CLI/sessions: keep intentional empty agent replies silent after tool-delivered channel output, instead of surfacing a misleading "No reply from agent." fallback. Thanks @vincentkoc. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -695,6 +695,14 @@
|
695 | 695 | "types": "./dist/plugin-sdk/discord.d.ts", |
696 | 696 | "default": "./dist/plugin-sdk/discord.js" |
697 | 697 | }, |
| 698 | +"./plugin-sdk/mattermost": { |
| 699 | +"types": "./dist/plugin-sdk/mattermost.d.ts", |
| 700 | +"default": "./dist/plugin-sdk/mattermost.js" |
| 701 | + }, |
| 702 | +"./plugin-sdk/matrix": { |
| 703 | +"types": "./dist/plugin-sdk/matrix.d.ts", |
| 704 | +"default": "./dist/plugin-sdk/matrix.js" |
| 705 | + }, |
698 | 706 | "./plugin-sdk/device-bootstrap": { |
699 | 707 | "types": "./dist/plugin-sdk/device-bootstrap.d.ts", |
700 | 708 | "default": "./dist/plugin-sdk/device-bootstrap.js" |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -6,6 +6,10 @@
|
6 | 6 | "source": "external", |
7 | 7 | "kind": "channel", |
8 | 8 | "openclaw": { |
| 9 | +"plugin": { |
| 10 | +"id": "wecom-openclaw-plugin", |
| 11 | +"label": "WeCom" |
| 12 | + }, |
9 | 13 | "channel": { |
10 | 14 | "id": "wecom", |
11 | 15 | "label": "WeCom", |
@@ -30,6 +34,10 @@
|
30 | 34 | "source": "external", |
31 | 35 | "kind": "channel", |
32 | 36 | "openclaw": { |
| 37 | +"plugin": { |
| 38 | +"id": "openclaw-plugin-yuanbao", |
| 39 | +"label": "Yuanbao" |
| 40 | + }, |
33 | 41 | "channel": { |
34 | 42 | "id": "yuanbao", |
35 | 43 | "label": "Yuanbao", |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -150,6 +150,8 @@
|
150 | 150 | "direct-dm-access", |
151 | 151 | "direct-dm-guard-policy", |
152 | 152 | "discord", |
| 153 | +"mattermost", |
| 154 | +"matrix", |
153 | 155 | "device-bootstrap", |
154 | 156 | "diagnostic-runtime", |
155 | 157 | "error-runtime", |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import { describe, expect, it } from "vitest"; |
| 2 | +import { getChannelPluginCatalogEntry } from "./catalog.js"; |
| 3 | + |
| 4 | +describe("channel plugin catalog", () => { |
| 5 | +it("keeps third-party official channel ids mapped to their published plugin ids", () => { |
| 6 | +const options = { |
| 7 | +workspaceDir: "/tmp/openclaw-channel-catalog-empty-workspace", |
| 8 | +env: {}, |
| 9 | +}; |
| 10 | + |
| 11 | +expect(getChannelPluginCatalogEntry("wecom", options)).toEqual( |
| 12 | +expect.objectContaining({ |
| 13 | +id: "wecom", |
| 14 | +pluginId: "wecom-openclaw-plugin", |
| 15 | +trustedSourceLinkedOfficialInstall: true, |
| 16 | +install: expect.objectContaining({ |
| 17 | +npmSpec: "@wecom/wecom-openclaw-plugin@2026.4.23", |
| 18 | +}), |
| 19 | +}), |
| 20 | +); |
| 21 | +expect(getChannelPluginCatalogEntry("yuanbao", options)).toEqual( |
| 22 | +expect.objectContaining({ |
| 23 | +id: "yuanbao", |
| 24 | +pluginId: "openclaw-plugin-yuanbao", |
| 25 | +trustedSourceLinkedOfficialInstall: true, |
| 26 | +install: expect.objectContaining({ |
| 27 | +npmSpec: "openclaw-plugin-yuanbao@2.11.0", |
| 28 | +}), |
| 29 | +}), |
| 30 | +); |
| 31 | +}); |
| 32 | +}); |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -347,6 +347,7 @@ function buildExternalCatalogEntry(
|
347 | 347 | ): ChannelPluginCatalogEntry | null { |
348 | 348 | const manifest = entry[MANIFEST_KEY]; |
349 | 349 | return buildCatalogEntryFromManifest({ |
| 350 | +pluginId: manifest?.plugin?.id, |
350 | 351 | packageName: entry.name, |
351 | 352 | trustedSourceLinkedOfficialInstall: options?.trustedSourceLinkedOfficialInstall, |
352 | 353 | channel: manifest?.channel, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -709,10 +709,12 @@ describe("plugins cli install", () => {
|
709 | 709 | |
710 | 710 | it("passes official external catalog integrity to npm installs", async () => { |
711 | 711 | const cfg = createEmptyPluginConfig(); |
712 | | -const enabledCfg = createEnabledPluginConfig("wecom"); |
| 712 | +const enabledCfg = createEnabledPluginConfig("wecom-openclaw-plugin"); |
713 | 713 | loadConfig.mockReturnValue(cfg); |
714 | 714 | findBundledPluginSourceMock.mockReturnValue(undefined); |
715 | | -installPluginFromNpmSpec.mockResolvedValue(createNpmPluginInstallResult("wecom")); |
| 715 | +installPluginFromNpmSpec.mockResolvedValue( |
| 716 | +createNpmPluginInstallResult("wecom-openclaw-plugin"), |
| 717 | +); |
716 | 718 | enablePluginInConfig.mockReturnValue({ config: enabledCfg }); |
717 | 719 | applyExclusiveSlotSelection.mockReturnValue({ |
718 | 720 | config: enabledCfg, |
@@ -724,7 +726,7 @@ describe("plugins cli install", () => {
|
724 | 726 | expect(installPluginFromNpmSpec).toHaveBeenCalledWith( |
725 | 727 | expect.objectContaining({ |
726 | 728 | spec: "@wecom/wecom-openclaw-plugin@2026.4.23", |
727 | | -expectedPluginId: "wecom", |
| 729 | +expectedPluginId: "wecom-openclaw-plugin", |
728 | 730 | expectedIntegrity: |
729 | 731 | "sha512-bnzfdIEEu1/LFvcdyjaTkyxt27w6c7dqhkPezU62OWaqmcdFsUGR3T55USK/O9pIKsNcnL1Tnu1pqKYCWHFgWQ==", |
730 | 732 | trustedSourceLinkedOfficialInstall: true, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -607,7 +607,7 @@ describe("ensureChannelSetupPluginInstalled", () => {
|
607 | 607 | // npm-only entry (no local path) |
608 | 608 | const npmOnlyEntry: ChannelPluginCatalogEntry = { |
609 | 609 | id: "wecom", |
610 | | -pluginId: "wecom", |
| 610 | +pluginId: "wecom-openclaw-plugin", |
611 | 611 | meta: { |
612 | 612 | id: "wecom", |
613 | 613 | label: "WeCom", |
@@ -621,8 +621,8 @@ describe("ensureChannelSetupPluginInstalled", () => {
|
621 | 621 | }; |
622 | 622 | installPluginFromNpmSpec.mockResolvedValue({ |
623 | 623 | ok: true, |
624 | | -pluginId: "wecom", |
625 | | -installPath: "/tmp/wecom", |
| 624 | +pluginId: "wecom-openclaw-plugin", |
| 625 | +installPath: "/tmp/wecom-openclaw-plugin", |
626 | 626 | }); |
627 | 627 | vi.mocked(fs.existsSync).mockReturnValue(false); |
628 | 628 | resolveBundledPluginSources.mockReturnValue(new Map()); |
@@ -637,7 +637,7 @@ describe("ensureChannelSetupPluginInstalled", () => {
|
637 | 637 | |
638 | 638 | expect(select).not.toHaveBeenCalled(); |
639 | 639 | expect(result.installed).toBe(true); |
640 | | -expect(result.pluginId).toBe("wecom"); |
| 640 | +expect(result.pluginId).toBe("wecom-openclaw-plugin"); |
641 | 641 | }); |
642 | 642 | |
643 | 643 | it("reloads the setup plugin registry without using plugin registry cache", () => { |
|
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +/** |
| 2 | + * @deprecated Compatibility facade for older third-party channel packages that |
| 3 | + * imported the previous Matrix-shaped helper bundle. New plugins should import |
| 4 | + * `openclaw/plugin-sdk/run-command` directly. |
| 5 | + */ |
| 6 | +export { runPluginCommandWithTimeout } from "./run-command.js"; |
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +/** |
| 2 | + * @deprecated Compatibility facade for older third-party channel packages that |
| 3 | + * imported the previous Mattermost-shaped helper bundle. New plugins should |
| 4 | + * import the generic SDK subpaths directly. |
| 5 | + */ |
| 6 | +export { resolveControlCommandGate } from "./command-auth.js"; |
| 7 | +export { formatPairingApproveHint } from "./channel-plugin-common.js"; |
| 8 | +export type { HistoryEntry } from "./reply-history.js"; |
| 9 | +export { |
| 10 | +buildPendingHistoryContextFromMap, |
| 11 | +clearHistoryEntriesIfEnabled, |
| 12 | +recordPendingHistoryEntryIfEnabled, |
| 13 | +} from "./reply-history.js"; |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。