refactor: untangle bundled channel sdk bridges

This commit is contained in:
Peter Steinberger 2026-03-16 18:49:04 -07:00
parent 3aa4199ef0
commit 7c2c20a62f
No known key found for this signature in database
49 changed files with 439 additions and 456 deletions

View File

@ -1,13 +1,13 @@
import {
hasConfiguredSecretInput,
normalizeSecretInputString,
} from "../../../src/config/types.secrets.js";
import {
DEFAULT_ACCOUNT_ID,
normalizeAccountId,
type OpenClawConfig,
type DiscordAccountConfig,
} from "openclaw/plugin-sdk/discord";
import {
hasConfiguredSecretInput,
normalizeSecretInputString,
} from "../../../src/config/types.secrets.js";
} from "../../../src/plugin-sdk-internal/discord.js";
import {
mergeDiscordAccountConfig,
resolveDefaultDiscordAccountId,

View File

@ -1,14 +1,14 @@
import type {
OpenClawConfig,
DiscordAccountConfig,
DiscordActionConfig,
} from "openclaw/plugin-sdk/discord";
import {
createAccountActionGate,
createAccountListHelpers,
normalizeAccountId,
resolveAccountEntry,
} from "../../../src/plugin-sdk-internal/accounts.js";
import type {
OpenClawConfig,
DiscordAccountConfig,
DiscordActionConfig,
} from "../../../src/plugin-sdk-internal/discord.js";
import { resolveDiscordToken } from "./token.js";
export type ResolvedDiscordAccount = {

View File

@ -1,46 +1,12 @@
import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
import {
createScopedAccountConfigAccessors,
formatAllowFromLowercase,
} from "openclaw/plugin-sdk/compat";
import {
buildChannelConfigSchema,
DiscordConfigSchema,
getChatChannelMeta,
type ChannelPlugin,
} from "openclaw/plugin-sdk/discord";
import { inspectDiscordAccount } from "./account-inspect.js";
import {
listDiscordAccountIds,
resolveDefaultDiscordAccountId,
resolveDiscordAccount,
type ResolvedDiscordAccount,
} from "./accounts.js";
import { createDiscordSetupWizardProxy, discordSetupAdapter } from "./setup-core.js";
async function loadDiscordChannelRuntime() {
return await import("./channel.runtime.js");
}
const discordConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveDiscordAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedDiscordAccount) => account.config.dm?.allowFrom,
formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
resolveDefaultTo: (account: ResolvedDiscordAccount) => account.config.defaultTo,
});
const discordConfigBase = createScopedChannelConfigBase({
sectionKey: "discord",
listAccountIds: listDiscordAccountIds,
resolveAccount: (cfg, accountId) => resolveDiscordAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectDiscordAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultDiscordAccountId,
clearBaseFields: ["token", "name"],
});
const discordSetupWizard = createDiscordSetupWizardProxy(async () => ({
discordSetupWizard: (await loadDiscordChannelRuntime()).discordSetupWizard,
}));
} from "../../../src/plugin-sdk-internal/discord.js";
import { type ResolvedDiscordAccount } from "./accounts.js";
import { discordConfigAccessors, discordConfigBase, discordSetupWizard } from "./plugin-shared.js";
import { discordSetupAdapter } from "./setup-core.js";
export const discordSetupPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
id: "discord",

View File

@ -1,18 +1,16 @@
import { Separator, TextDisplay } from "@buape/carbon";
import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
import {
buildAccountScopedAllowlistConfigEditor,
buildAccountScopedDmSecurityPolicy,
collectOpenProviderGroupPolicyWarnings,
collectOpenGroupPolicyConfiguredRouteWarnings,
createScopedAccountConfigAccessors,
formatAllowFromLowercase,
} from "openclaw/plugin-sdk/compat";
collectOpenProviderGroupPolicyWarnings,
} from "../../../src/plugin-sdk-internal/channel-config.js";
import {
buildAgentSessionKey,
resolveThreadSessionKeys,
type RoutePeer,
} from "openclaw/plugin-sdk/core";
} from "../../../src/plugin-sdk-internal/core.js";
import {
buildComputedAccountStatusSnapshot,
buildChannelConfigSchema,
@ -30,14 +28,11 @@ import {
type ChannelMessageActionAdapter,
type ChannelPlugin,
type OpenClawConfig,
} from "openclaw/plugin-sdk/discord";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
} from "../../../src/plugin-sdk-internal/discord.js";
import { normalizeMessageChannel } from "../../../src/utils/message-channel.js";
import { inspectDiscordAccount } from "./account-inspect.js";
import {
listDiscordAccountIds,
resolveDiscordAccount,
resolveDefaultDiscordAccountId,
type ResolvedDiscordAccount,
} from "./accounts.js";
import { collectDiscordAuditChannelIds } from "./audit.js";
@ -50,11 +45,12 @@ import {
normalizeDiscordMessagingTarget,
normalizeDiscordOutboundTarget,
} from "./normalize.js";
import { discordConfigAccessors, discordConfigBase, discordSetupWizard } from "./plugin-shared.js";
import type { DiscordProbe } from "./probe.js";
import { resolveDiscordUserAllowlist } from "./resolve-users.js";
import { getDiscordRuntime } from "./runtime.js";
import { fetchChannelPermissionsDiscord } from "./send.js";
import { createDiscordSetupWizardProxy, discordSetupAdapter } from "./setup-core.js";
import { discordSetupAdapter } from "./setup-core.js";
import { collectDiscordStatusIssues } from "./status-issues.js";
import { parseDiscordTarget } from "./targets.js";
import { DiscordUiContainer } from "./ui.js";
@ -66,10 +62,6 @@ type DiscordSendFn = ReturnType<
const meta = getChatChannelMeta("discord");
const REQUIRED_DISCORD_PERMISSIONS = ["ViewChannel", "SendMessages"] as const;
async function loadDiscordChannelRuntime() {
return await import("./channel.runtime.js");
}
function formatDiscordIntents(intents?: {
messageContent?: string;
guildMembers?: string;
@ -304,26 +296,6 @@ function resolveDiscordOutboundSessionRoute(params: {
};
}
const discordConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveDiscordAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedDiscordAccount) => account.config.dm?.allowFrom,
formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
resolveDefaultTo: (account: ResolvedDiscordAccount) => account.config.defaultTo,
});
const discordConfigBase = createScopedChannelConfigBase({
sectionKey: "discord",
listAccountIds: listDiscordAccountIds,
resolveAccount: (cfg, accountId) => resolveDiscordAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectDiscordAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultDiscordAccountId,
clearBaseFields: ["token", "name"],
});
const discordSetupWizard = createDiscordSetupWizardProxy(async () => ({
discordSetupWizard: (await loadDiscordChannelRuntime()).discordSetupWizard,
}));
export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
id: "discord",
meta: {

View File

@ -0,0 +1,39 @@
import {
createScopedAccountConfigAccessors,
createScopedChannelConfigBase,
formatAllowFromLowercase,
} from "../../../src/plugin-sdk-internal/channel-config.js";
import { type OpenClawConfig } from "../../../src/plugin-sdk-internal/discord.js";
import { inspectDiscordAccount } from "./account-inspect.js";
import {
listDiscordAccountIds,
resolveDefaultDiscordAccountId,
resolveDiscordAccount,
type ResolvedDiscordAccount,
} from "./accounts.js";
import { createDiscordSetupWizardProxy } from "./setup-core.js";
async function loadDiscordChannelRuntime() {
return await import("./channel.runtime.js");
}
export const discordConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId?: string | null }) =>
resolveDiscordAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedDiscordAccount) => account.config.dm?.allowFrom,
formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
resolveDefaultTo: (account: ResolvedDiscordAccount) => account.config.defaultTo,
});
export const discordConfigBase = createScopedChannelConfigBase({
sectionKey: "discord",
listAccountIds: listDiscordAccountIds,
resolveAccount: (cfg, accountId) => resolveDiscordAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectDiscordAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultDiscordAccountId,
clearBaseFields: ["token", "name"],
});
export const discordSetupWizard = createDiscordSetupWizardProxy(async () => ({
discordSetupWizard: (await loadDiscordChannelRuntime()).discordSetupWizard,
}));

View File

@ -1,5 +1,7 @@
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
import {
createPluginRuntimeStore,
type PluginRuntime,
} from "../../../src/plugin-sdk-internal/core.js";
const { setRuntime: setDiscordRuntime, getRuntime: getDiscordRuntime } =
createPluginRuntimeStore<PluginRuntime>("Discord runtime not initialized");

View File

@ -1,4 +1,4 @@
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
import type { OpenClawPluginApi } from "../../../src/plugin-sdk-internal/core.js";
import { resolveDiscordAccount } from "./accounts.js";
import {
autoBindSpawnedDiscordSubagent,

View File

@ -1,10 +1,10 @@
import type { IMessageAccountConfig } from "openclaw/plugin-sdk/imessage";
import {
type OpenClawConfig,
createAccountListHelpers,
normalizeAccountId,
resolveAccountEntry,
} from "../../../src/plugin-sdk-internal/accounts.js";
import type { IMessageAccountConfig } from "../../../src/plugin-sdk-internal/imessage.js";
export type ResolvedIMessageAccount = {
accountId: string;

View File

@ -1,7 +1,7 @@
import {
buildAccountScopedDmSecurityPolicy,
collectAllowlistProviderRestrictSendersWarnings,
} from "openclaw/plugin-sdk/compat";
} from "../../../src/plugin-sdk-internal/channel-config.js";
import {
buildChannelConfigSchema,
DEFAULT_ACCOUNT_ID,
@ -13,22 +13,15 @@ import {
resolveIMessageConfigDefaultTo,
setAccountEnabledInConfigSection,
type ChannelPlugin,
} from "openclaw/plugin-sdk/imessage";
} from "../../../src/plugin-sdk-internal/imessage.js";
import {
listIMessageAccountIds,
resolveDefaultIMessageAccountId,
resolveIMessageAccount,
type ResolvedIMessageAccount,
} from "./accounts.js";
import { createIMessageSetupWizardProxy, imessageSetupAdapter } from "./setup-core.js";
async function loadIMessageChannelRuntime() {
return await import("./channel.runtime.js");
}
const imessageSetupWizard = createIMessageSetupWizardProxy(async () => ({
imessageSetupWizard: (await loadIMessageChannelRuntime()).imessageSetupWizard,
}));
import { imessageSetupWizard } from "./plugin-shared.js";
import { imessageSetupAdapter } from "./setup-core.js";
export const imessageSetupPlugin: ChannelPlugin<ResolvedIMessageAccount> = {
id: "imessage",

View File

@ -1,9 +1,10 @@
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
import {
buildAccountScopedAllowlistConfigEditor,
buildAccountScopedDmSecurityPolicy,
collectAllowlistProviderRestrictSendersWarnings,
} from "openclaw/plugin-sdk/compat";
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/core";
} from "../../../src/plugin-sdk-internal/channel-config.js";
import { buildAgentSessionKey, type RoutePeer } from "../../../src/plugin-sdk-internal/core.js";
import {
buildChannelConfigSchema,
collectStatusIssuesFromLastError,
@ -22,8 +23,7 @@ import {
resolveIMessageGroupToolPolicy,
setAccountEnabledInConfigSection,
type ChannelPlugin,
} from "openclaw/plugin-sdk/imessage";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
} from "../../../src/plugin-sdk-internal/imessage.js";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import {
listIMessageAccountIds,
@ -31,20 +31,13 @@ import {
resolveIMessageAccount,
type ResolvedIMessageAccount,
} from "./accounts.js";
import { imessageSetupWizard } from "./plugin-shared.js";
import { getIMessageRuntime } from "./runtime.js";
import { createIMessageSetupWizardProxy, imessageSetupAdapter } from "./setup-core.js";
import { imessageSetupAdapter } from "./setup-core.js";
import { normalizeIMessageHandle, parseIMessageTarget } from "./targets.js";
const meta = getChatChannelMeta("imessage");
async function loadIMessageChannelRuntime() {
return await import("./channel.runtime.js");
}
const imessageSetupWizard = createIMessageSetupWizardProxy(async () => ({
imessageSetupWizard: (await loadIMessageChannelRuntime()).imessageSetupWizard,
}));
type IMessageSendFn = ReturnType<
typeof getIMessageRuntime
>["channel"]["imessage"]["sendMessageIMessage"];

View File

@ -0,0 +1,11 @@
import { type ChannelPlugin } from "../../../src/plugin-sdk-internal/imessage.js";
import { type ResolvedIMessageAccount } from "./accounts.js";
import { createIMessageSetupWizardProxy } from "./setup-core.js";
async function loadIMessageChannelRuntime() {
return await import("./channel.runtime.js");
}
export const imessageSetupWizard = createIMessageSetupWizardProxy(async () => ({
imessageSetupWizard: (await loadIMessageChannelRuntime()).imessageSetupWizard,
})) satisfies NonNullable<ChannelPlugin<ResolvedIMessageAccount>["setupWizard"]>;

View File

@ -1,5 +1,7 @@
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
import {
createPluginRuntimeStore,
type PluginRuntime,
} from "../../../src/plugin-sdk-internal/core.js";
const { setRuntime: setIMessageRuntime, getRuntime: getIMessageRuntime } =
createPluginRuntimeStore<PluginRuntime>("iMessage runtime not initialized");

View File

@ -1,4 +1,4 @@
import { isAllowedParsedChatSender } from "../../../src/plugin-sdk/allow-from.js";
import { isAllowedParsedChatSender } from "../../../src/plugin-sdk-internal/imessage.js";
export type ServicePrefix<TService extends string> = { prefix: string; service: TService };

View File

@ -1,10 +1,10 @@
import type { SignalAccountConfig } from "openclaw/plugin-sdk/signal";
import {
type OpenClawConfig,
createAccountListHelpers,
normalizeAccountId,
resolveAccountEntry,
} from "../../../src/plugin-sdk-internal/accounts.js";
import type { SignalAccountConfig } from "../../../src/plugin-sdk-internal/signal.js";
export type ResolvedSignalAccount = {
accountId: string;

View File

@ -1,8 +1,7 @@
import {
createScopedAccountConfigAccessors,
buildAccountScopedDmSecurityPolicy,
collectAllowlistProviderRestrictSendersWarnings,
} from "openclaw/plugin-sdk/compat";
} from "../../../src/plugin-sdk-internal/channel-config.js";
import {
buildChannelConfigSchema,
DEFAULT_ACCOUNT_ID,
@ -12,34 +11,15 @@ import {
setAccountEnabledInConfigSection,
SignalConfigSchema,
type ChannelPlugin,
} from "openclaw/plugin-sdk/signal";
} from "../../../src/plugin-sdk-internal/signal.js";
import {
listSignalAccountIds,
resolveDefaultSignalAccountId,
resolveSignalAccount,
type ResolvedSignalAccount,
} from "./accounts.js";
import { createSignalSetupWizardProxy, signalSetupAdapter } from "./setup-core.js";
async function loadSignalChannelRuntime() {
return await import("./channel.runtime.js");
}
const signalSetupWizard = createSignalSetupWizardProxy(async () => ({
signalSetupWizard: (await loadSignalChannelRuntime()).signalSetupWizard,
}));
const signalConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveSignalAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedSignalAccount) => account.config.allowFrom,
formatAllowFrom: (allowFrom) =>
allowFrom
.map((entry) => String(entry).trim())
.filter(Boolean)
.map((entry) => (entry === "*" ? "*" : normalizeE164(entry.replace(/^signal:/i, ""))))
.filter(Boolean),
resolveDefaultTo: (account: ResolvedSignalAccount) => account.config.defaultTo,
});
import { signalConfigAccessors, signalSetupWizard } from "./plugin-shared.js";
import { signalSetupAdapter } from "./setup-core.js";
export const signalSetupPlugin: ChannelPlugin<ResolvedSignalAccount> = {
id: "signal",

View File

@ -1,10 +1,12 @@
import { resolveTextChunkLimit } from "../../../src/auto-reply/chunk.js";
import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
import {
buildAccountScopedAllowlistConfigEditor,
buildAccountScopedDmSecurityPolicy,
createScopedAccountConfigAccessors,
collectAllowlistProviderRestrictSendersWarnings,
} from "openclaw/plugin-sdk/compat";
import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/core";
} from "../../../src/plugin-sdk-internal/channel-config.js";
import { buildAgentSessionKey, type RoutePeer } from "../../../src/plugin-sdk-internal/core.js";
import {
buildBaseAccountStatusSnapshot,
buildBaseChannelStatusSummary,
@ -23,10 +25,7 @@ import {
SignalConfigSchema,
type ChannelMessageActionAdapter,
type ChannelPlugin,
} from "openclaw/plugin-sdk/signal";
import { resolveTextChunkLimit } from "../../../src/auto-reply/chunk.js";
import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
} from "../../../src/plugin-sdk-internal/signal.js";
import {
listSignalAccountIds,
resolveDefaultSignalAccountId,
@ -40,17 +39,10 @@ import {
resolveSignalRecipient,
resolveSignalSender,
} from "./identity.js";
import { signalConfigAccessors, signalSetupWizard } from "./plugin-shared.js";
import type { SignalProbe } from "./probe.js";
import { getSignalRuntime } from "./runtime.js";
import { createSignalSetupWizardProxy, signalSetupAdapter } from "./setup-core.js";
async function loadSignalChannelRuntime() {
return await import("./channel.runtime.js");
}
const signalSetupWizard = createSignalSetupWizardProxy(async () => ({
signalSetupWizard: (await loadSignalChannelRuntime()).signalSetupWizard,
}));
import { signalSetupAdapter } from "./setup-core.js";
const signalMessageActions: ChannelMessageActionAdapter = {
listActions: (ctx) => getSignalRuntime().channel.signal.messageActions?.listActions?.(ctx) ?? [],
@ -65,18 +57,6 @@ const signalMessageActions: ChannelMessageActionAdapter = {
},
};
const signalConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveSignalAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedSignalAccount) => account.config.allowFrom,
formatAllowFrom: (allowFrom) =>
allowFrom
.map((entry) => String(entry).trim())
.filter(Boolean)
.map((entry) => (entry === "*" ? "*" : normalizeE164(entry.replace(/^signal:/i, ""))))
.filter(Boolean),
resolveDefaultTo: (account: ResolvedSignalAccount) => account.config.defaultTo,
});
type SignalSendFn = ReturnType<typeof getSignalRuntime>["channel"]["signal"]["sendMessageSignal"];
function resolveSignalSendContext(params: {

View File

@ -1,4 +1,4 @@
import { evaluateSenderGroupAccessForPolicy } from "../../../src/plugin-sdk/group-access.js";
import { evaluateSenderGroupAccessForPolicy } from "../../../src/plugin-sdk-internal/signal.js";
import { normalizeE164 } from "../../../src/utils.js";
export type SignalSender =

View File

@ -0,0 +1,25 @@
import { createScopedAccountConfigAccessors } from "../../../src/plugin-sdk-internal/channel-config.js";
import { normalizeE164, type OpenClawConfig } from "../../../src/plugin-sdk-internal/signal.js";
import { resolveSignalAccount, type ResolvedSignalAccount } from "./accounts.js";
import { createSignalSetupWizardProxy } from "./setup-core.js";
async function loadSignalChannelRuntime() {
return await import("./channel.runtime.js");
}
export const signalSetupWizard = createSignalSetupWizardProxy(async () => ({
signalSetupWizard: (await loadSignalChannelRuntime()).signalSetupWizard,
}));
export const signalConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId?: string | null }) =>
resolveSignalAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedSignalAccount) => account.config.allowFrom,
formatAllowFrom: (allowFrom) =>
allowFrom
.map((entry) => String(entry).trim())
.filter(Boolean)
.map((entry) => (entry === "*" ? "*" : normalizeE164(entry.replace(/^signal:/i, ""))))
.filter(Boolean),
resolveDefaultTo: (account: ResolvedSignalAccount) => account.config.defaultTo,
});

View File

@ -1,5 +1,7 @@
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
import {
createPluginRuntimeStore,
type PluginRuntime,
} from "../../../src/plugin-sdk-internal/core.js";
const { setRuntime: setSignalRuntime, getRuntime: getSignalRuntime } =
createPluginRuntimeStore<PluginRuntime>("Signal runtime not initialized");

View File

@ -1,13 +1,13 @@
import {
hasConfiguredSecretInput,
normalizeSecretInputString,
} from "../../../src/config/types.secrets.js";
import {
DEFAULT_ACCOUNT_ID,
normalizeAccountId,
type OpenClawConfig,
type SlackAccountConfig,
} from "openclaw/plugin-sdk/slack";
import {
hasConfiguredSecretInput,
normalizeSecretInputString,
} from "../../../src/config/types.secrets.js";
} from "../../../src/plugin-sdk-internal/slack.js";
import type { SlackAccountSurfaceFields } from "./account-surface-fields.js";
import {
mergeSlackAccountConfig,

View File

@ -1,4 +1,3 @@
import type { SlackAccountConfig } from "openclaw/plugin-sdk/slack";
import {
type OpenClawConfig,
createAccountListHelpers,
@ -7,6 +6,7 @@ import {
normalizeChatType,
resolveAccountEntry,
} from "../../../src/plugin-sdk-internal/accounts.js";
import type { SlackAccountConfig } from "../../../src/plugin-sdk-internal/slack.js";
import type { SlackAccountSurfaceFields } from "./account-surface-fields.js";
import { resolveSlackAppToken, resolveSlackBotToken, resolveSlackUserToken } from "./token.js";

View File

@ -3,19 +3,16 @@ import {
getChatChannelMeta,
SlackConfigSchema,
type ChannelPlugin,
} from "openclaw/plugin-sdk/slack";
} from "../../../src/plugin-sdk-internal/slack.js";
import { type ResolvedSlackAccount } from "./accounts.js";
import { isSlackInteractiveRepliesEnabled } from "./interactive-replies.js";
import { createSlackSetupWizardProxy, slackSetupAdapter } from "./setup-core.js";
import { isSlackPluginAccountConfigured, slackConfigAccessors, slackConfigBase } from "./shared.js";
async function loadSlackChannelRuntime() {
return await import("./channel.runtime.js");
}
const slackSetupWizard = createSlackSetupWizardProxy(async () => ({
slackSetupWizard: (await loadSlackChannelRuntime()).slackSetupWizard,
}));
import {
isSlackPluginAccountConfigured,
slackConfigAccessors,
slackConfigBase,
slackSetupWizard,
} from "./plugin-shared.js";
import { slackSetupAdapter } from "./setup-core.js";
export const slackSetupPlugin: ChannelPlugin<ResolvedSlackAccount> = {
id: "slack",

View File

@ -1,14 +1,15 @@
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
import {
buildAccountScopedAllowlistConfigEditor,
buildAccountScopedDmSecurityPolicy,
collectOpenProviderGroupPolicyWarnings,
collectOpenGroupPolicyConfiguredRouteWarnings,
} from "openclaw/plugin-sdk/compat";
collectOpenProviderGroupPolicyWarnings,
} from "../../../src/plugin-sdk-internal/channel-config.js";
import {
buildAgentSessionKey,
resolveThreadSessionKeys,
type RoutePeer,
} from "openclaw/plugin-sdk/core";
} from "../../../src/plugin-sdk-internal/core.js";
import {
buildComputedAccountStatusSnapshot,
buildChannelConfigSchema,
@ -26,8 +27,7 @@ import {
SlackConfigSchema,
type ChannelPlugin,
type OpenClawConfig,
} from "openclaw/plugin-sdk/slack";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
} from "../../../src/plugin-sdk-internal/slack.js";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import {
listEnabledSlackAccounts,
@ -41,22 +41,23 @@ import { isSlackInteractiveRepliesEnabled } from "./interactive-replies.js";
import { handleSlackMessageAction } from "./message-action-dispatch.js";
import { extractSlackToolSend, listSlackMessageActions } from "./message-actions.js";
import { normalizeAllowListLower } from "./monitor/allow-list.js";
import {
isSlackPluginAccountConfigured,
slackConfigAccessors,
slackConfigBase,
slackSetupWizard,
} from "./plugin-shared.js";
import type { SlackProbe } from "./probe.js";
import { resolveSlackUserAllowlist } from "./resolve-users.js";
import { getSlackRuntime } from "./runtime.js";
import { fetchSlackScopes } from "./scopes.js";
import { createSlackSetupWizardProxy, slackSetupAdapter } from "./setup-core.js";
import { isSlackPluginAccountConfigured, slackConfigAccessors, slackConfigBase } from "./shared.js";
import { slackSetupAdapter } from "./setup-core.js";
import { parseSlackTarget } from "./targets.js";
import { buildSlackThreadingToolContext } from "./threading-tool-context.js";
const meta = getChatChannelMeta("slack");
const SLACK_CHANNEL_TYPE_CACHE = new Map<string, "channel" | "group" | "dm" | "unknown">();
async function loadSlackChannelRuntime() {
return await import("./channel.runtime.js");
}
// Select the appropriate Slack token for read/write operations.
function getTokenForOperation(
account: ResolvedSlackAccount,
@ -328,10 +329,6 @@ async function resolveSlackAllowlistNames(params: {
return await resolveSlackUserAllowlist({ token, entries: params.entries });
}
const slackSetupWizard = createSlackSetupWizardProxy(async () => ({
slackSetupWizard: (await loadSlackChannelRuntime()).slackSetupWizard,
}));
export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
id: "slack",
meta: {

View File

@ -1 +1 @@
export { handleSlackMessageAction } from "../../../src/plugin-sdk/slack-message-actions.js";
export { handleSlackMessageAction } from "../../../src/plugin-sdk-internal/slack.js";

View File

@ -0,0 +1,53 @@
import {
createScopedAccountConfigAccessors,
createScopedChannelConfigBase,
formatAllowFromLowercase,
} from "../../../src/plugin-sdk-internal/channel-config.js";
import { type OpenClawConfig } from "../../../src/plugin-sdk-internal/slack.js";
import { inspectSlackAccount } from "./account-inspect.js";
import {
listSlackAccountIds,
resolveDefaultSlackAccountId,
resolveSlackAccount,
type ResolvedSlackAccount,
} from "./accounts.js";
import { createSlackSetupWizardProxy } from "./setup-core.js";
async function loadSlackChannelRuntime() {
return await import("./channel.runtime.js");
}
export function isSlackAccountConfigured(account: ResolvedSlackAccount): boolean {
const mode = account.config.mode ?? "socket";
const hasBotToken = Boolean(account.botToken?.trim());
if (!hasBotToken) {
return false;
}
if (mode === "http") {
return Boolean(account.config.signingSecret?.trim());
}
return Boolean(account.appToken?.trim());
}
export const isSlackPluginAccountConfigured = isSlackAccountConfigured;
export const slackConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId?: string | null }) =>
resolveSlackAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedSlackAccount) => account.dm?.allowFrom,
formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
resolveDefaultTo: (account: ResolvedSlackAccount) => account.config.defaultTo,
});
export const slackConfigBase = createScopedChannelConfigBase({
sectionKey: "slack",
listAccountIds: listSlackAccountIds,
resolveAccount: (cfg, accountId) => resolveSlackAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectSlackAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultSlackAccountId,
clearBaseFields: ["botToken", "appToken", "name"],
});
export const slackSetupWizard = createSlackSetupWizardProxy(async () => ({
slackSetupWizard: (await loadSlackChannelRuntime()).slackSetupWizard,
}));

View File

@ -1,5 +1,7 @@
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
import {
createPluginRuntimeStore,
type PluginRuntime,
} from "../../../src/plugin-sdk-internal/core.js";
const { setRuntime: setSlackRuntime, getRuntime: getSlackRuntime } =
createPluginRuntimeStore<PluginRuntime>("Slack runtime not initialized");

View File

@ -1,4 +1,3 @@
import type { TelegramAccountConfig } from "openclaw/plugin-sdk/telegram";
import type { OpenClawConfig } from "../../../src/config/config.js";
import {
coerceSecretRef,
@ -6,7 +5,8 @@ import {
normalizeSecretInputString,
} from "../../../src/config/types.secrets.js";
import { tryReadSecretFileSync } from "../../../src/infra/secret-file.js";
import { resolveAccountWithDefaultFallback } from "../../../src/plugin-sdk/account-resolution.js";
import { resolveAccountWithDefaultFallback } from "../../../src/plugin-sdk-internal/accounts.js";
import type { TelegramAccountConfig } from "../../../src/plugin-sdk-internal/telegram.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js";
import { resolveDefaultSecretProviderAlias } from "../../../src/secrets/ref-contract.js";
import {

View File

@ -1,5 +1,4 @@
import util from "node:util";
import type { TelegramAccountConfig, TelegramActionConfig } from "openclaw/plugin-sdk/telegram";
import { createAccountActionGate } from "../../../src/channels/plugins/account-action-gate.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import { isTruthyEnvValue } from "../../../src/infra/env.js";
@ -7,7 +6,11 @@ import { createSubsystemLogger } from "../../../src/logging/subsystem.js";
import {
listConfiguredAccountIds as listConfiguredAccountIdsFromSection,
resolveAccountWithDefaultFallback,
} from "../../../src/plugin-sdk/account-resolution.js";
} from "../../../src/plugin-sdk-internal/accounts.js";
import type {
TelegramAccountConfig,
TelegramActionConfig,
} from "../../../src/plugin-sdk-internal/telegram.js";
import { resolveAccountEntry } from "../../../src/routing/account-lookup.js";
import {
listBoundAccountIds,

View File

@ -15,8 +15,7 @@ import type {
ChannelMessageActionName,
} from "../../../src/channels/plugins/types.js";
import type { TelegramActionConfig } from "../../../src/config/types.telegram.js";
import { readBooleanParam } from "../../../src/plugin-sdk/boolean-param.js";
import { extractToolSend } from "../../../src/plugin-sdk/tool-send.js";
import { extractToolSend, readBooleanParam } from "../../../src/plugin-sdk-internal/telegram.js";
import { resolveTelegramPollVisibility } from "../../../src/poll-params.js";
import {
createTelegramActionGate,

View File

@ -1,78 +1,20 @@
import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
import {
createScopedAccountConfigAccessors,
formatAllowFromLowercase,
} from "openclaw/plugin-sdk/compat";
import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
import {
buildChannelConfigSchema,
getChatChannelMeta,
normalizeAccountId,
TelegramConfigSchema,
type OpenClawConfig,
} from "openclaw/plugin-sdk/telegram";
import { inspectTelegramAccount } from "./account-inspect.js";
type ChannelPlugin,
} from "../../../src/plugin-sdk-internal/telegram.js";
import { type ResolvedTelegramAccount } from "./accounts.js";
import {
listTelegramAccountIds,
resolveDefaultTelegramAccountId,
resolveTelegramAccount,
type ResolvedTelegramAccount,
} from "./accounts.js";
findTelegramTokenOwnerAccountId,
formatDuplicateTelegramTokenReason,
telegramConfigAccessors,
telegramConfigBase,
} from "./plugin-shared.js";
import type { TelegramProbe } from "./probe.js";
import { telegramSetupAdapter } from "./setup-core.js";
import { telegramSetupWizard } from "./setup-surface.js";
function findTelegramTokenOwnerAccountId(params: {
cfg: OpenClawConfig;
accountId: string;
}): string | null {
const normalizedAccountId = normalizeAccountId(params.accountId);
const tokenOwners = new Map<string, string>();
for (const id of listTelegramAccountIds(params.cfg)) {
const account = inspectTelegramAccount({ cfg: params.cfg, accountId: id });
const token = (account.token ?? "").trim();
if (!token) {
continue;
}
const ownerAccountId = tokenOwners.get(token);
if (!ownerAccountId) {
tokenOwners.set(token, account.accountId);
continue;
}
if (account.accountId === normalizedAccountId) {
return ownerAccountId;
}
}
return null;
}
function formatDuplicateTelegramTokenReason(params: {
accountId: string;
ownerAccountId: string;
}): string {
return (
`Duplicate Telegram bot token: account "${params.accountId}" shares a token with ` +
`account "${params.ownerAccountId}". Keep one owner account per bot token.`
);
}
const telegramConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveTelegramAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedTelegramAccount) => account.config.allowFrom,
formatAllowFrom: (allowFrom) =>
formatAllowFromLowercase({ allowFrom, stripPrefixRe: /^(telegram|tg):/i }),
resolveDefaultTo: (account: ResolvedTelegramAccount) => account.config.defaultTo,
});
const telegramConfigBase = createScopedChannelConfigBase<ResolvedTelegramAccount>({
sectionKey: "telegram",
listAccountIds: listTelegramAccountIds,
resolveAccount: (cfg, accountId) => resolveTelegramAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectTelegramAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultTelegramAccountId,
clearBaseFields: ["botToken", "tokenFile", "name"],
});
export const telegramSetupPlugin: ChannelPlugin<ResolvedTelegramAccount, TelegramProbe> = {
id: "telegram",
meta: {

View File

@ -1,18 +1,22 @@
import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
import { parseTelegramTopicConversation } from "../../../src/acp/conversation-id.js";
import { resolveExecApprovalCommandDisplay } from "../../../src/infra/exec-approval-command-display.js";
import { buildExecApprovalPendingReplyPayload } from "../../../src/infra/exec-approval-reply.js";
import {
type OutboundSendDeps,
resolveOutboundSendDep,
} from "../../../src/infra/outbound/send-deps.js";
import {
buildAccountScopedAllowlistConfigEditor,
collectAllowlistProviderGroupPolicyWarnings,
collectOpenGroupPolicyRouteAllowlistWarnings,
createScopedAccountConfigAccessors,
createScopedDmSecurityResolver,
formatAllowFromLowercase,
} from "openclaw/plugin-sdk/compat";
} from "../../../src/plugin-sdk-internal/channel-config.js";
import {
buildAgentSessionKey,
resolveThreadSessionKeys,
type ChannelPlugin,
type RoutePeer,
} from "openclaw/plugin-sdk/core";
import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
} from "../../../src/plugin-sdk-internal/core.js";
import {
buildChannelConfigSchema,
buildTokenChannelStatusSummary,
@ -21,7 +25,6 @@ import {
getChatChannelMeta,
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
normalizeAccountId,
PAIRING_APPROVED_MESSAGE,
projectCredentialSnapshotFields,
resolveConfiguredFromCredentialStatuses,
@ -30,19 +33,10 @@ import {
TelegramConfigSchema,
type ChannelMessageActionAdapter,
type OpenClawConfig,
} from "openclaw/plugin-sdk/telegram";
import { parseTelegramTopicConversation } from "../../../src/acp/conversation-id.js";
import { resolveExecApprovalCommandDisplay } from "../../../src/infra/exec-approval-command-display.js";
import { buildExecApprovalPendingReplyPayload } from "../../../src/infra/exec-approval-reply.js";
import {
type OutboundSendDeps,
resolveOutboundSendDep,
} from "../../../src/infra/outbound/send-deps.js";
} from "../../../src/plugin-sdk-internal/telegram.js";
import { normalizeMessageChannel } from "../../../src/utils/message-channel.js";
import { inspectTelegramAccount } from "./account-inspect.js";
import {
listTelegramAccountIds,
resolveDefaultTelegramAccountId,
resolveTelegramAccount,
type ResolvedTelegramAccount,
} from "./accounts.js";
@ -57,6 +51,12 @@ import { monitorTelegramProvider } from "./monitor.js";
import { looksLikeTelegramTargetId, normalizeTelegramMessagingTarget } from "./normalize.js";
import { sendTelegramPayloadMessages } from "./outbound-adapter.js";
import { parseTelegramReplyToMessageId, parseTelegramThreadId } from "./outbound-params.js";
import {
findTelegramTokenOwnerAccountId,
formatDuplicateTelegramTokenReason,
telegramConfigAccessors,
telegramConfigBase,
} from "./plugin-shared.js";
import { probeTelegram, type TelegramProbe } from "./probe.js";
import { getTelegramRuntime } from "./runtime.js";
import { sendTypingTelegram } from "./send.js";
@ -71,40 +71,6 @@ type TelegramSendFn = ReturnType<
const meta = getChatChannelMeta("telegram");
function findTelegramTokenOwnerAccountId(params: {
cfg: OpenClawConfig;
accountId: string;
}): string | null {
const normalizedAccountId = normalizeAccountId(params.accountId);
const tokenOwners = new Map<string, string>();
for (const id of listTelegramAccountIds(params.cfg)) {
const account = inspectTelegramAccount({ cfg: params.cfg, accountId: id });
const token = (account.token ?? "").trim();
if (!token) {
continue;
}
const ownerAccountId = tokenOwners.get(token);
if (!ownerAccountId) {
tokenOwners.set(token, account.accountId);
continue;
}
if (account.accountId === normalizedAccountId) {
return ownerAccountId;
}
}
return null;
}
function formatDuplicateTelegramTokenReason(params: {
accountId: string;
ownerAccountId: string;
}): string {
return (
`Duplicate Telegram bot token: account "${params.accountId}" shares a token with ` +
`account "${params.ownerAccountId}". Keep one owner account per bot token.`
);
}
type TelegramSendOptions = NonNullable<Parameters<TelegramSendFn>[2]>;
function buildTelegramSendOptions(params: {
@ -329,23 +295,6 @@ const telegramMessageActions: ChannelMessageActionAdapter = {
},
};
const telegramConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveTelegramAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedTelegramAccount) => account.config.allowFrom,
formatAllowFrom: (allowFrom) =>
formatAllowFromLowercase({ allowFrom, stripPrefixRe: /^(telegram|tg):/i }),
resolveDefaultTo: (account: ResolvedTelegramAccount) => account.config.defaultTo,
});
const telegramConfigBase = createScopedChannelConfigBase<ResolvedTelegramAccount>({
sectionKey: "telegram",
listAccountIds: listTelegramAccountIds,
resolveAccount: (cfg, accountId) => resolveTelegramAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectTelegramAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultTelegramAccountId,
clearBaseFields: ["botToken", "tokenFile", "name"],
});
const resolveTelegramDmPolicy = createScopedDmSecurityResolver<ResolvedTelegramAccount>({
channelKey: "telegram",
resolvePolicy: (account) => account.config.dmPolicy,

View File

@ -7,7 +7,7 @@ import type {
TelegramGroupConfig,
TelegramTopicConfig,
} from "../../../src/config/types.js";
import { evaluateMatchedGroupAccessForPolicy } from "../../../src/plugin-sdk/group-access.js";
import { evaluateMatchedGroupAccessForPolicy } from "../../../src/plugin-sdk-internal/telegram.js";
import { isSenderAllowed, type NormalizedAllowFrom } from "./bot-access.js";
import { firstDefined } from "./bot-access.js";

View File

@ -0,0 +1,68 @@
import {
createScopedAccountConfigAccessors,
createScopedChannelConfigBase,
formatAllowFromLowercase,
} from "../../../src/plugin-sdk-internal/channel-config.js";
import {
normalizeAccountId,
type OpenClawConfig,
} from "../../../src/plugin-sdk-internal/telegram.js";
import { inspectTelegramAccount } from "./account-inspect.js";
import {
listTelegramAccountIds,
resolveDefaultTelegramAccountId,
resolveTelegramAccount,
type ResolvedTelegramAccount,
} from "./accounts.js";
export function findTelegramTokenOwnerAccountId(params: {
cfg: OpenClawConfig;
accountId: string;
}): string | null {
const normalizedAccountId = normalizeAccountId(params.accountId);
const tokenOwners = new Map<string, string>();
for (const id of listTelegramAccountIds(params.cfg)) {
const account = inspectTelegramAccount({ cfg: params.cfg, accountId: id });
const token = (account.token ?? "").trim();
if (!token) {
continue;
}
const ownerAccountId = tokenOwners.get(token);
if (!ownerAccountId) {
tokenOwners.set(token, account.accountId);
continue;
}
if (account.accountId === normalizedAccountId) {
return ownerAccountId;
}
}
return null;
}
export function formatDuplicateTelegramTokenReason(params: {
accountId: string;
ownerAccountId: string;
}): string {
return (
`Duplicate Telegram bot token: account "${params.accountId}" shares a token with ` +
`account "${params.ownerAccountId}". Keep one owner account per bot token.`
);
}
export const telegramConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId?: string | null }) =>
resolveTelegramAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedTelegramAccount) => account.config.allowFrom,
formatAllowFrom: (allowFrom) =>
formatAllowFromLowercase({ allowFrom, stripPrefixRe: /^(telegram|tg):/i }),
resolveDefaultTo: (account: ResolvedTelegramAccount) => account.config.defaultTo,
});
export const telegramConfigBase = createScopedChannelConfigBase<ResolvedTelegramAccount>({
sectionKey: "telegram",
listAccountIds: listTelegramAccountIds,
resolveAccount: (cfg, accountId) => resolveTelegramAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectTelegramAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultTelegramAccountId,
clearBaseFields: ["botToken", "tokenFile", "name"],
});

View File

@ -1,5 +1,5 @@
import type { TelegramNetworkConfig } from "openclaw/plugin-sdk/telegram";
import type { BaseProbeResult } from "../../../src/channels/plugins/types.js";
import type { TelegramNetworkConfig } from "../../../src/plugin-sdk-internal/telegram.js";
import { fetchWithTimeout } from "../../../src/utils/fetch-timeout.js";
import { resolveTelegramFetch } from "./fetch.js";
import { makeProxyFetch } from "./proxy.js";

View File

@ -1,5 +1,7 @@
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
import {
createPluginRuntimeStore,
type PluginRuntime,
} from "../../../src/plugin-sdk-internal/core.js";
const { setRuntime: setTelegramRuntime, getRuntime: getTelegramRuntime } =
createPluginRuntimeStore<PluginRuntime>("Telegram runtime not initialized");

View File

@ -1,8 +1,8 @@
import type { TelegramAccountConfig } from "openclaw/plugin-sdk/telegram";
import type { BaseTokenResolution } from "../../../src/channels/plugins/types.core.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import { normalizeResolvedSecretInputString } from "../../../src/config/types.secrets.js";
import { tryReadSecretFileSync } from "../../../src/infra/secret-file.js";
import type { TelegramAccountConfig } from "../../../src/plugin-sdk-internal/telegram.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js";
export type TelegramTokenSource = "env" | "tokenFile" | "config" | "none";

View File

@ -1,6 +1,5 @@
import fs from "node:fs";
import path from "node:path";
import type { DmPolicy, GroupPolicy, WhatsAppAccountConfig } from "openclaw/plugin-sdk/whatsapp";
import { resolveOAuthDir } from "../../../src/config/paths.js";
import {
type OpenClawConfig,
@ -10,6 +9,11 @@ import {
resolveAccountEntry,
resolveUserPath,
} from "../../../src/plugin-sdk-internal/accounts.js";
import type {
DmPolicy,
GroupPolicy,
WhatsAppAccountConfig,
} from "../../../src/plugin-sdk-internal/whatsapp.js";
import { hasWebCredsSync } from "./auth-store.js";
export type ResolvedWhatsAppAccount = {

View File

@ -14,7 +14,7 @@ import {
resolveWhatsAppGroupToolPolicy,
WhatsAppConfigSchema,
type ChannelPlugin,
} from "openclaw/plugin-sdk/whatsapp";
} from "../../../src/plugin-sdk-internal/whatsapp.js";
import {
listWhatsAppAccountIds,
resolveDefaultWhatsAppAccountId,
@ -22,57 +22,9 @@ import {
type ResolvedWhatsAppAccount,
} from "./accounts.js";
import { webAuthExists } from "./auth-store.js";
import { whatsappSetupWizardProxy } from "./plugin-shared.js";
import { whatsappSetupAdapter } from "./setup-core.js";
async function loadWhatsAppChannelRuntime() {
return await import("./channel.runtime.js");
}
const whatsappSetupWizardProxy = {
channel: "whatsapp",
status: {
configuredLabel: "linked",
unconfiguredLabel: "not linked",
configuredHint: "linked",
unconfiguredHint: "not linked",
configuredScore: 5,
unconfiguredScore: 4,
resolveConfigured: async ({ cfg }) =>
await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.status.resolveConfigured({
cfg,
}),
resolveStatusLines: async ({ cfg, configured }) =>
(await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.status.resolveStatusLines?.({
cfg,
configured,
})) ?? [],
},
resolveShouldPromptAccountIds: (params) =>
(params.shouldPromptAccountIds || params.options?.promptWhatsAppAccountId) ?? false,
credentials: [],
finalize: async (params) =>
await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.finalize!(params),
disable: (cfg) => ({
...cfg,
channels: {
...cfg.channels,
whatsapp: {
...cfg.channels?.whatsapp,
enabled: false,
},
},
}),
onAccountRecorded: (accountId, options) => {
options?.onWhatsAppAccountId?.(accountId);
},
} satisfies NonNullable<ChannelPlugin<ResolvedWhatsAppAccount>["setupWizard"]>;
export const whatsappSetupPlugin: ChannelPlugin<ResolvedWhatsAppAccount> = {
id: "whatsapp",
meta: {

View File

@ -1,4 +1,4 @@
import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/compat";
import { buildAccountScopedAllowlistConfigEditor } from "../../../src/plugin-sdk-internal/channel-config.js";
import {
buildChannelConfigSchema,
buildAccountScopedDmSecurityPolicy,
@ -24,7 +24,7 @@ import {
WhatsAppConfigSchema,
type ChannelMessageActionName,
type ChannelPlugin,
} from "openclaw/plugin-sdk/whatsapp";
} from "../../../src/plugin-sdk-internal/whatsapp.js";
import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../../../src/whatsapp/normalize.js";
// WhatsApp-specific imports from local extension code (moved from src/web/ and src/channels/plugins/)
import {
@ -34,16 +34,13 @@ import {
type ResolvedWhatsAppAccount,
} from "./accounts.js";
import { looksLikeWhatsAppTargetId, normalizeWhatsAppMessagingTarget } from "./normalize.js";
import { whatsappSetupWizardProxy } from "./plugin-shared.js";
import { getWhatsAppRuntime } from "./runtime.js";
import { whatsappSetupAdapter } from "./setup-core.js";
import { collectWhatsAppStatusIssues } from "./status-issues.js";
const meta = getChatChannelMeta("whatsapp");
async function loadWhatsAppChannelRuntime() {
return await import("./channel.runtime.js");
}
function normalizeWhatsAppPayloadText(text: string | undefined): string {
return (text ?? "").replace(/^(?:[ \t]*\r?\n)+/, "");
}
@ -59,51 +56,6 @@ function parseWhatsAppExplicitTarget(raw: string) {
};
}
const whatsappSetupWizardProxy = {
channel: "whatsapp",
status: {
configuredLabel: "linked",
unconfiguredLabel: "not linked",
configuredHint: "linked",
unconfiguredHint: "not linked",
configuredScore: 5,
unconfiguredScore: 4,
resolveConfigured: async ({ cfg }) =>
await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.status.resolveConfigured({
cfg,
}),
resolveStatusLines: async ({ cfg, configured }) =>
(await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.status.resolveStatusLines?.({
cfg,
configured,
})) ?? [],
},
resolveShouldPromptAccountIds: (params) =>
(params.shouldPromptAccountIds || params.options?.promptWhatsAppAccountId) ?? false,
credentials: [],
finalize: async (params) =>
await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.finalize!(params),
disable: (cfg) => ({
...cfg,
channels: {
...cfg.channels,
whatsapp: {
...cfg.channels?.whatsapp,
enabled: false,
},
},
}),
onAccountRecorded: (accountId, options) => {
options?.onWhatsAppAccountId?.(accountId);
},
} satisfies NonNullable<ChannelPlugin<ResolvedWhatsAppAccount>["setupWizard"]>;
export const whatsappPlugin: ChannelPlugin<ResolvedWhatsAppAccount> = {
id: "whatsapp",
meta: {

View File

@ -0,0 +1,51 @@
import { type ChannelPlugin } from "../../../src/plugin-sdk-internal/whatsapp.js";
import { type ResolvedWhatsAppAccount } from "./accounts.js";
async function loadWhatsAppChannelRuntime() {
return await import("./channel.runtime.js");
}
export const whatsappSetupWizardProxy = {
channel: "whatsapp",
status: {
configuredLabel: "linked",
unconfiguredLabel: "not linked",
configuredHint: "linked",
unconfiguredHint: "not linked",
configuredScore: 5,
unconfiguredScore: 4,
resolveConfigured: async ({ cfg }) =>
await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.status.resolveConfigured({
cfg,
}),
resolveStatusLines: async ({ cfg, configured }) =>
(await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.status.resolveStatusLines?.({
cfg,
configured,
})) ?? [],
},
resolveShouldPromptAccountIds: (params) =>
(params.shouldPromptAccountIds || params.options?.promptWhatsAppAccountId) ?? false,
credentials: [],
finalize: async (params) =>
await (
await loadWhatsAppChannelRuntime()
).whatsappSetupWizard.finalize!(params),
disable: (cfg) => ({
...cfg,
channels: {
...cfg.channels,
whatsapp: {
...cfg.channels?.whatsapp,
enabled: false,
},
},
}),
onAccountRecorded: (accountId, options) => {
options?.onWhatsAppAccountId?.(accountId);
},
} satisfies NonNullable<ChannelPlugin<ResolvedWhatsAppAccount>["setupWizard"]>;

View File

@ -1,5 +1,7 @@
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/compat";
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
import {
createPluginRuntimeStore,
type PluginRuntime,
} from "../../../src/plugin-sdk-internal/core.js";
const { setRuntime: setWhatsAppRuntime, getRuntime: getWhatsAppRuntime } =
createPluginRuntimeStore<PluginRuntime>("WhatsApp runtime not initialized");

View File

@ -13,6 +13,7 @@ import {
type OpenClawConfig,
} from "../../../src/plugin-sdk-internal/setup.js";
import type { ChannelSetupWizard } from "../../../src/plugin-sdk-internal/setup.js";
import { type DmPolicy } from "../../../src/plugin-sdk-internal/whatsapp.js";
import { listWhatsAppAccountIds, resolveWhatsAppAuthDir } from "./accounts.js";
import { loginWeb } from "./login.js";
import { whatsappSetupAdapter } from "./setup-core.js";

View File

@ -402,7 +402,6 @@ export function installChannelDirectoryContractSuite(params: {
if (params.invokeLookups === false) {
return;
}
const self = await directory?.self?.({
cfg: {} as OpenClawConfig,
accountId: "default",

View File

@ -3,6 +3,10 @@ export type { OpenClawConfig } from "../config/config.js";
export { createAccountActionGate } from "../channels/plugins/account-action-gate.js";
export { createAccountListHelpers } from "../channels/plugins/account-helpers.js";
export { normalizeChatType } from "../channels/chat-type.js";
export {
listConfiguredAccountIds,
resolveAccountWithDefaultFallback,
} from "../plugin-sdk/account-resolution.js";
export { resolveAccountEntry } from "../routing/account-lookup.js";
export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
export { normalizeE164, pathExists, resolveUserPath } from "../utils.js";

View File

@ -0,0 +1,17 @@
// Private bridge for bundled channel plugins. These config helpers are shared
// internally, but do not belong on the public compat surface.
export { buildAccountScopedAllowlistConfigEditor } from "../plugin-sdk/allowlist-config-edit.js";
export { formatAllowFromLowercase } from "../plugin-sdk/allow-from.js";
export {
createScopedAccountConfigAccessors,
createScopedChannelConfigBase,
createScopedDmSecurityResolver,
} from "../plugin-sdk/channel-config-helpers.js";
export {
collectAllowlistProviderGroupPolicyWarnings,
collectAllowlistProviderRestrictSendersWarnings,
collectOpenGroupPolicyConfiguredRouteWarnings,
collectOpenGroupPolicyRouteAllowlistWarnings,
collectOpenProviderGroupPolicyWarnings,
} from "../channels/plugins/group-policy-warnings.js";
export { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js";

View File

@ -0,0 +1,14 @@
// Private bridge for bundled channel plugins. Keep public sdk/core slim for
// third-party plugins; bundled channels can reach shared runtime helpers here.
export type {
ChannelMessageActionContext,
OpenClawPluginApi,
PluginRuntime,
} from "../plugin-sdk/channel-plugin-common.js";
export { createPluginRuntimeStore } from "../plugin-sdk/runtime-store.js";
export {
buildAgentSessionKey,
type RoutePeer,
type RoutePeerKind,
} from "../routing/resolve-route.js";
export { resolveThreadSessionKeys } from "../routing/session-key.js";

View File

@ -11,6 +11,7 @@ export {
resolveIMessageConfigAllowFrom,
resolveIMessageConfigDefaultTo,
} from "../plugin-sdk/channel-config-helpers.js";
export { isAllowedParsedChatSender } from "../plugin-sdk/allow-from.js";
export {
looksLikeIMessageTargetId,
normalizeIMessageMessagingTarget,

View File

@ -1,4 +1,5 @@
export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js";
export type { OpenClawConfig } from "../config/config.js";
export type { ResolvedSignalAccount } from "../../extensions/signal/src/accounts.js";
export type { SignalAccountConfig } from "../config/types.js";
export * from "../plugin-sdk/channel-plugin-common.js";
@ -23,6 +24,7 @@ export {
resolveAllowlistProviderRuntimeGroupPolicy,
resolveDefaultGroupPolicy,
} from "../config/runtime-group-policy.js";
export { evaluateSenderGroupAccessForPolicy } from "../plugin-sdk/group-access.js";
export { signalSetupWizard } from "../../extensions/signal/src/setup-surface.js";
export { signalSetupAdapter } from "../../extensions/signal/src/setup-core.js";
export { SignalConfigSchema } from "../config/zod-schema.providers-core.js";

View File

@ -7,7 +7,11 @@ export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
export type { OpenClawConfig } from "../config/config.js";
export type { PluginRuntime } from "../plugins/runtime/types.js";
export type { OpenClawPluginApi } from "../plugins/types.js";
export type { TelegramAccountConfig, TelegramActionConfig } from "../config/types.js";
export type {
TelegramAccountConfig,
TelegramActionConfig,
TelegramNetworkConfig,
} from "../config/types.js";
export type { InspectedTelegramAccount } from "../../extensions/telegram/src/account-inspect.js";
export type { ResolvedTelegramAccount } from "../../extensions/telegram/src/accounts.js";
export type { TelegramProbe } from "../../extensions/telegram/src/probe.js";
@ -102,6 +106,9 @@ export {
resolveAllowlistProviderRuntimeGroupPolicy,
resolveDefaultGroupPolicy,
} from "../config/runtime-group-policy.js";
export { readBooleanParam } from "../plugin-sdk/boolean-param.js";
export { evaluateMatchedGroupAccessForPolicy } from "../plugin-sdk/group-access.js";
export { extractToolSend } from "../plugin-sdk/tool-send.js";
export {
resolveTelegramGroupRequireMention,
resolveTelegramGroupToolPolicy,