mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix(plugin-sdk): restore channel compatibility facades
This commit is contained in:
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Plugin SDK: add tracked Discord component-message helpers and a Telegram account-resolution compatibility facade, so existing plugins using those subpaths resolve while new plugins stay on generic channel SDK contracts. Thanks @vincentkoc.
|
||||
- Docs/Hetzner: clarify that SSH tunnel access requires `AllowTcpForwarding local` before running `ssh -L`, so hardened VPS sshd configs do not block loopback Gateway access. Fixes #54557; carries forward #54564; refs #54954. Thanks @satishkc7, @blackstrype, and @Aftabbs.
|
||||
- Gateway/shutdown: report structured shutdown warnings and HTTP close timeout warnings through `ShutdownResult` while preserving lifecycle hook hardening. Carries forward #41296. Thanks @edenfunf.
|
||||
- Plugins/QA: prebuild the private QA channel runtime before plugin gauntlet source runs so wrapper CPU/RSS measurements are not polluted by private QA dist rebuild work. Thanks @vincentkoc.
|
||||
|
||||
@@ -51,9 +51,10 @@ map when they have tracked owner usage. They exist for bundled-plugin
|
||||
maintenance only and are not recommended import paths for new third-party
|
||||
plugins.
|
||||
|
||||
`openclaw/plugin-sdk/discord` is also kept as a deprecated compatibility facade
|
||||
for the published `@openclaw/discord@2026.3.13` package. Do not copy that import
|
||||
path into new plugins; use the generic channel SDK subpaths instead.
|
||||
`openclaw/plugin-sdk/discord` and `openclaw/plugin-sdk/telegram-account` are
|
||||
also kept as deprecated compatibility facades for tracked owner usage. Do not
|
||||
copy those import paths into new plugins; use injected runtime helpers and
|
||||
generic channel SDK subpaths instead.
|
||||
</Warning>
|
||||
|
||||
## Subpath reference
|
||||
|
||||
@@ -84,7 +84,8 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
|
||||
| `plugin-sdk/allowlist-config-edit` | Allowlist config edit/read helpers |
|
||||
| `plugin-sdk/group-access` | Shared group-access decision helpers |
|
||||
| `plugin-sdk/direct-dm` | Shared direct-DM auth/guard helpers |
|
||||
| `plugin-sdk/discord` | Deprecated Discord compatibility facade for published `@openclaw/discord@2026.3.13`; new plugins should use generic channel SDK subpaths |
|
||||
| `plugin-sdk/discord` | Deprecated Discord compatibility facade for published `@openclaw/discord@2026.3.13` and tracked owner compatibility; new plugins should use generic channel SDK subpaths |
|
||||
| `plugin-sdk/telegram-account` | Deprecated Telegram account-resolution compatibility facade for tracked owner compatibility; new plugins should use injected runtime helpers or generic channel SDK subpaths |
|
||||
| `plugin-sdk/interactive-runtime` | Semantic message presentation, delivery, and legacy interactive reply helpers. See [Message Presentation](/plugins/message-presentation) |
|
||||
| `plugin-sdk/channel-inbound` | Compatibility barrel for inbound debounce, mention matching, mention-policy helpers, and envelope helpers |
|
||||
| `plugin-sdk/channel-inbound-debounce` | Narrow inbound debounce helpers |
|
||||
|
||||
@@ -1193,6 +1193,10 @@
|
||||
"types": "./dist/plugin-sdk/target-resolver-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/target-resolver-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/telegram-account": {
|
||||
"types": "./dist/plugin-sdk/telegram-account.d.ts",
|
||||
"default": "./dist/plugin-sdk/telegram-account.js"
|
||||
},
|
||||
"./plugin-sdk/telegram-command-config": {
|
||||
"types": "./dist/plugin-sdk/telegram-command-config.d.ts",
|
||||
"default": "./dist/plugin-sdk/telegram-command-config.js"
|
||||
|
||||
@@ -281,6 +281,7 @@
|
||||
"string-normalization-runtime",
|
||||
"state-paths",
|
||||
"target-resolver-runtime",
|
||||
"telegram-account",
|
||||
"telegram-command-config",
|
||||
"text-autolink-runtime",
|
||||
"tool-payload",
|
||||
|
||||
@@ -3,6 +3,10 @@ import { describe, expect, it, vi } from "vitest";
|
||||
const mocks = vi.hoisted(() => {
|
||||
const runtimeConfig = { channels: { discord: { token: "token" } } };
|
||||
const apiModule = {
|
||||
buildDiscordComponentMessage: vi.fn((params: { spec: { text?: string } }) => ({
|
||||
components: [],
|
||||
text: params.spec.text ?? "",
|
||||
})),
|
||||
collectDiscordStatusIssues: vi.fn(() => []),
|
||||
discordOnboardingAdapter: { kind: "legacy-onboarding" },
|
||||
inspectDiscordAccount: vi.fn(() => ({ accountId: "default" })),
|
||||
@@ -33,7 +37,9 @@ const mocks = vi.hoisted(() => {
|
||||
cfg: params.cfg,
|
||||
})),
|
||||
collectDiscordAuditChannelIds: vi.fn(() => ({ channelIds: [], unresolvedChannels: [] })),
|
||||
editDiscordComponentMessage: vi.fn(async () => ({ id: "message" })),
|
||||
listThreadBindingsBySessionKey: vi.fn(() => []),
|
||||
registerBuiltDiscordComponentMessage: vi.fn(),
|
||||
unbindThreadBindingsBySessionKey: vi.fn(() => []),
|
||||
};
|
||||
|
||||
@@ -78,6 +84,7 @@ describe("discord plugin-sdk compatibility facade", () => {
|
||||
"PAIRING_APPROVED_MESSAGE",
|
||||
"applyAccountNameToChannelSection",
|
||||
"autoBindSpawnedDiscordSubagent",
|
||||
"buildDiscordComponentMessage",
|
||||
"buildChannelConfigSchema",
|
||||
"buildComputedAccountStatusSnapshot",
|
||||
"buildTokenChannelStatusSummary",
|
||||
@@ -97,6 +104,8 @@ describe("discord plugin-sdk compatibility facade", () => {
|
||||
"normalizeDiscordMessagingTarget",
|
||||
"normalizeDiscordOutboundTarget",
|
||||
"projectCredentialSnapshotFields",
|
||||
"editDiscordComponentMessage",
|
||||
"registerBuiltDiscordComponentMessage",
|
||||
"resolveConfiguredFromCredentialStatuses",
|
||||
"resolveDefaultDiscordAccountId",
|
||||
"resolveDiscordAccount",
|
||||
@@ -108,6 +117,40 @@ describe("discord plugin-sdk compatibility facade", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("forwards Discord component helpers through the compatibility facade", async () => {
|
||||
const {
|
||||
buildDiscordComponentMessage,
|
||||
editDiscordComponentMessage,
|
||||
registerBuiltDiscordComponentMessage,
|
||||
} = await import("./discord.js");
|
||||
|
||||
const built = buildDiscordComponentMessage({ spec: { text: "hello" } });
|
||||
await editDiscordComponentMessage(
|
||||
"channel",
|
||||
"message",
|
||||
{ text: "edited" },
|
||||
{ cfg: mocks.runtimeConfig },
|
||||
);
|
||||
registerBuiltDiscordComponentMessage({
|
||||
buildResult: built,
|
||||
messageId: "message",
|
||||
});
|
||||
|
||||
expect(mocks.apiModule.buildDiscordComponentMessage).toHaveBeenCalledWith({
|
||||
spec: { text: "hello" },
|
||||
});
|
||||
expect(mocks.runtimeModule.editDiscordComponentMessage).toHaveBeenCalledWith(
|
||||
"channel",
|
||||
"message",
|
||||
{ text: "edited" },
|
||||
{ cfg: mocks.runtimeConfig },
|
||||
);
|
||||
expect(mocks.runtimeModule.registerBuiltDiscordComponentMessage).toHaveBeenCalledWith({
|
||||
buildResult: built,
|
||||
messageId: "message",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps legacy Discord subagent auto-bind calls working without cfg", async () => {
|
||||
const { autoBindSpawnedDiscordSubagent } = await import("./discord.js");
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ import {
|
||||
} from "./facade-loader.js";
|
||||
import { getRuntimeConfig, getRuntimeConfigSnapshot } from "./runtime-config-snapshot.js";
|
||||
|
||||
export type {
|
||||
DiscordComponentBuildResult,
|
||||
DiscordComponentMessageSpec,
|
||||
} from "../../extensions/discord/api.js";
|
||||
export type { ChannelMessageActionAdapter, ChannelMessageActionName } from "./channel-contract.js";
|
||||
export type { ChannelPlugin } from "./channel-core.js";
|
||||
export type { OpenClawConfig } from "./config-types.js";
|
||||
@@ -68,6 +72,7 @@ type DirectoryConfigParams = {
|
||||
|
||||
type DiscordApiFacadeModule = {
|
||||
collectDiscordStatusIssues: (accounts: ChannelAccountSnapshot[]) => ChannelStatusIssue[];
|
||||
buildDiscordComponentMessage: typeof import("../../extensions/discord/api.js").buildDiscordComponentMessage;
|
||||
discordOnboardingAdapter?: NonNullable<ChannelPlugin<ResolvedDiscordAccount>["setup"]>;
|
||||
inspectDiscordAccount: (params: { cfg: OpenClawConfig; accountId?: string | null }) => unknown;
|
||||
listDiscordAccountIds: (cfg: OpenClawConfig) => string[];
|
||||
@@ -90,6 +95,8 @@ type DiscordApiFacadeModule = {
|
||||
};
|
||||
|
||||
type DiscordRuntimeFacadeModule = {
|
||||
editDiscordComponentMessage: typeof import("../../extensions/discord/runtime-api.js").editDiscordComponentMessage;
|
||||
registerBuiltDiscordComponentMessage: typeof import("../../extensions/discord/runtime-api.js").registerBuiltDiscordComponentMessage;
|
||||
autoBindSpawnedDiscordSubagent: (params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string;
|
||||
@@ -148,6 +155,12 @@ export function collectDiscordStatusIssues(
|
||||
return loadDiscordApiFacadeModule().collectDiscordStatusIssues(accounts);
|
||||
}
|
||||
|
||||
export const buildDiscordComponentMessage: DiscordApiFacadeModule["buildDiscordComponentMessage"] =
|
||||
((...args) =>
|
||||
loadDiscordApiFacadeModule().buildDiscordComponentMessage(
|
||||
...args,
|
||||
)) as DiscordApiFacadeModule["buildDiscordComponentMessage"];
|
||||
|
||||
export function inspectDiscordAccount(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
@@ -211,6 +224,18 @@ export function collectDiscordAuditChannelIds(params: {
|
||||
return loadDiscordRuntimeFacadeModule().collectDiscordAuditChannelIds(params);
|
||||
}
|
||||
|
||||
export const editDiscordComponentMessage: DiscordRuntimeFacadeModule["editDiscordComponentMessage"] =
|
||||
((...args) =>
|
||||
loadDiscordRuntimeFacadeModule().editDiscordComponentMessage(
|
||||
...args,
|
||||
)) as DiscordRuntimeFacadeModule["editDiscordComponentMessage"];
|
||||
|
||||
export const registerBuiltDiscordComponentMessage: DiscordRuntimeFacadeModule["registerBuiltDiscordComponentMessage"] =
|
||||
((...args) =>
|
||||
loadDiscordRuntimeFacadeModule().registerBuiltDiscordComponentMessage(
|
||||
...args,
|
||||
)) as DiscordRuntimeFacadeModule["registerBuiltDiscordComponentMessage"];
|
||||
|
||||
export async function autoBindSpawnedDiscordSubagent(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
accountId?: string;
|
||||
|
||||
@@ -16,6 +16,7 @@ export const supportedBundledFacadeSdkEntrypoints = [
|
||||
"lmstudio-runtime",
|
||||
"memory-core-engine-runtime",
|
||||
"qa-runner-runtime",
|
||||
"telegram-account",
|
||||
"tts-runtime",
|
||||
] as const;
|
||||
|
||||
|
||||
46
src/plugin-sdk/telegram-account.test.ts
Normal file
46
src/plugin-sdk/telegram-account.test.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const apiModule = {
|
||||
resolveTelegramAccount: vi.fn(() => ({
|
||||
accountId: "default",
|
||||
config: {},
|
||||
enabled: true,
|
||||
token: "token",
|
||||
tokenSource: "config",
|
||||
})),
|
||||
};
|
||||
|
||||
return {
|
||||
apiModule,
|
||||
loadBundledPluginPublicSurfaceModuleSync: vi.fn(() => apiModule),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./facade-loader.js", () => ({
|
||||
loadBundledPluginPublicSurfaceModuleSync: mocks.loadBundledPluginPublicSurfaceModuleSync,
|
||||
}));
|
||||
|
||||
describe("telegram account plugin-sdk compatibility facade", () => {
|
||||
it("forwards account resolution through Telegram's public surface", async () => {
|
||||
const { resolveTelegramAccount } = await import("./telegram-account.js");
|
||||
const cfg = { channels: { telegram: { botToken: "token" } } };
|
||||
|
||||
const account = resolveTelegramAccount({ cfg, accountId: "default" });
|
||||
|
||||
expect(mocks.loadBundledPluginPublicSurfaceModuleSync).toHaveBeenCalledWith({
|
||||
dirName: "telegram",
|
||||
artifactBasename: "api.js",
|
||||
});
|
||||
expect(mocks.apiModule.resolveTelegramAccount).toHaveBeenCalledWith({
|
||||
cfg,
|
||||
accountId: "default",
|
||||
});
|
||||
expect(account).toEqual(
|
||||
expect.objectContaining({
|
||||
accountId: "default",
|
||||
token: "token",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
26
src/plugin-sdk/telegram-account.ts
Normal file
26
src/plugin-sdk/telegram-account.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { OpenClawConfig } from "./config-types.js";
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-loader.js";
|
||||
|
||||
export type { ResolvedTelegramAccount } from "../../extensions/telegram/api.js";
|
||||
|
||||
type TelegramAccountFacadeModule = {
|
||||
resolveTelegramAccount: typeof import("../../extensions/telegram/api.js").resolveTelegramAccount;
|
||||
};
|
||||
|
||||
function loadTelegramAccountFacadeModule(): TelegramAccountFacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<TelegramAccountFacadeModule>({
|
||||
dirName: "telegram",
|
||||
artifactBasename: "api.js",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Compatibility facade for plugin code that needs Telegram account resolution.
|
||||
* New channel plugins should prefer injected runtime helpers and generic SDK subpaths.
|
||||
*/
|
||||
export function resolveTelegramAccount(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId?: string | null;
|
||||
}): ReturnType<TelegramAccountFacadeModule["resolveTelegramAccount"]> {
|
||||
return loadTelegramAccountFacadeModule().resolveTelegramAccount(params);
|
||||
}
|
||||
@@ -101,6 +101,25 @@ export const PLUGIN_COMPAT_RECORDS = [
|
||||
"src/plugins/captured-registration.test.ts",
|
||||
],
|
||||
},
|
||||
{
|
||||
code: "bundled-channel-sdk-compat-facades",
|
||||
status: "active",
|
||||
owner: "sdk",
|
||||
introduced: "2026-04-28",
|
||||
replacement:
|
||||
"generic channel SDK subpaths or plugin-local `api.ts` / `runtime-api.ts` barrels for new plugins",
|
||||
docsPath: "/plugins/sdk-overview",
|
||||
surfaces: [
|
||||
"openclaw/plugin-sdk/discord component message helpers",
|
||||
"openclaw/plugin-sdk/telegram-account resolveTelegramAccount",
|
||||
],
|
||||
diagnostics: ["plugin SDK compatibility registry"],
|
||||
tests: [
|
||||
"src/plugin-sdk/discord.test.ts",
|
||||
"src/plugin-sdk/telegram-account.test.ts",
|
||||
"src/plugins/contracts/plugin-sdk-package-contract-guardrails.test.ts",
|
||||
],
|
||||
},
|
||||
{
|
||||
code: "bundled-channel-config-schema-legacy",
|
||||
status: "deprecated",
|
||||
|
||||
Reference in New Issue
Block a user