diff --git a/extensions/acpx/src/test-utils/runtime-fixtures.ts b/extensions/acpx/src/test-utils/runtime-fixtures.ts index c5cbef83877..ebf5052f450 100644 --- a/extensions/acpx/src/test-utils/runtime-fixtures.ts +++ b/extensions/acpx/src/test-utils/runtime-fixtures.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import { chmod, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import path from "node:path"; -import { resolvePreferredOpenClawTmpDir } from "../../../../src/infra/tmp-openclaw-dir.js"; +import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/infra-runtime"; import type { ResolvedAcpxPluginConfig } from "../config.js"; import { ACPX_PINNED_VERSION } from "../config.js"; import { AcpxRuntime } from "../runtime.js"; diff --git a/extensions/anthropic/index.ts b/extensions/anthropic/index.ts index cf63e876354..25cb604dbcb 100644 --- a/extensions/anthropic/index.ts +++ b/extensions/anthropic/index.ts @@ -1,3 +1,5 @@ +import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; +import { parseDurationMs } from "openclaw/plugin-sdk/cli-runtime"; import { emptyPluginConfigSchema, type OpenClawPluginApi, @@ -7,26 +9,25 @@ import { } from "openclaw/plugin-sdk/core"; import { CLAUDE_CLI_PROFILE_ID, + applyAuthProfileConfig, + buildTokenProfileId, + createProviderApiKeyAuthMethod, + ensureApiKeyFromOptionEnvOrPrompt, listProfilesForProvider, - upsertAuthProfile, -} from "../../src/agents/auth-profiles.js"; -import { suggestOAuthProfileIdForLegacyDefault } from "../../src/agents/auth-profiles/repair.js"; -import type { AuthProfileStore } from "../../src/agents/auth-profiles/types.js"; -import { normalizeModelCompat } from "../../src/agents/model-compat.js"; -import { formatCliCommand } from "../../src/cli/command-format.js"; -import { parseDurationMs } from "../../src/cli/parse-duration.js"; -import { + normalizeApiKeyInput, + suggestOAuthProfileIdForLegacyDefault, + type AuthProfileStore, + type ProviderAuthResult, + normalizeSecretInput, normalizeSecretInputModeInput, promptSecretRefForSetup, resolveSecretInputModeForEnvSelection, -} from "../../src/commands/auth-choice.apply-helpers.js"; -import { buildTokenProfileId, validateAnthropicSetupToken } from "../../src/commands/auth-token.js"; -import { applyAuthProfileConfig } from "../../src/commands/onboard-auth.js"; -import { fetchClaudeUsage } from "../../src/infra/provider-usage.fetch.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import type { ProviderAuthResult } from "../../src/plugins/types.js"; -import { normalizeSecretInput } from "../../src/utils/normalize-secret-input.js"; -import { anthropicMediaUnderstandingProvider } from "./media-understanding-provider.js"; + upsertAuthProfile, + validateAnthropicSetupToken, + validateApiKeyInput, +} from "openclaw/plugin-sdk/provider-auth"; +import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-models"; +import { fetchClaudeUsage } from "openclaw/plugin-sdk/provider-usage"; const PROVIDER_ID = "anthropic"; const DEFAULT_ANTHROPIC_MODEL = "anthropic/claude-sonnet-4-6"; @@ -395,7 +396,6 @@ const anthropicPlugin = { profileId: ctx.profileId, }), }); - api.registerMediaUnderstandingProvider(anthropicMediaUnderstandingProvider); }, }; diff --git a/extensions/brave/index.ts b/extensions/brave/index.ts index 1150dec5d80..f23c5d4d485 100644 --- a/extensions/brave/index.ts +++ b/extensions/brave/index.ts @@ -1,10 +1,9 @@ +import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; import { createPluginBackedWebSearchProvider, getTopLevelCredentialValue, setTopLevelCredentialValue, -} from "../../src/agents/tools/web-search-plugin-factory.js"; -import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js"; -import type { OpenClawPluginApi } from "../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/provider-web-search"; const bravePlugin = { id: "brave", diff --git a/extensions/byteplus/index.ts b/extensions/byteplus/index.ts index 7c6cf2f08fe..215ac1a1705 100644 --- a/extensions/byteplus/index.ts +++ b/extensions/byteplus/index.ts @@ -1,7 +1,6 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { ensureModelAllowlistEntry } from "../../src/commands/model-allowlist.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import { buildPairedProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { ensureModelAllowlistEntry } from "openclaw/plugin-sdk/provider-onboard"; import { buildBytePlusCodingProvider, buildBytePlusProvider } from "./provider-catalog.js"; const PROVIDER_ID = "byteplus"; @@ -46,15 +45,18 @@ const byteplusPlugin = { ], catalog: { order: "paired", - run: (ctx) => - buildPairedProviderApiKeyCatalog({ - ctx, - providerId: PROVIDER_ID, - buildProviders: () => ({ - byteplus: buildBytePlusProvider(), - "byteplus-plan": buildBytePlusCodingProvider(), - }), - }), + run: async (ctx) => { + const apiKey = ctx.resolveProviderApiKey(PROVIDER_ID).apiKey; + if (!apiKey) { + return null; + } + return { + providers: { + byteplus: { ...buildBytePlusProvider(), apiKey }, + "byteplus-plan": { ...buildBytePlusCodingProvider(), apiKey }, + }, + }; + }, }, }); }, diff --git a/extensions/byteplus/provider-catalog.ts b/extensions/byteplus/provider-catalog.ts index 77cca06a2db..bcb5b153d20 100644 --- a/extensions/byteplus/provider-catalog.ts +++ b/extensions/byteplus/provider-catalog.ts @@ -4,8 +4,8 @@ import { BYTEPLUS_CODING_BASE_URL, BYTEPLUS_CODING_MODEL_CATALOG, BYTEPLUS_MODEL_CATALOG, -} from "../../src/agents/byteplus-models.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; + type ModelProviderConfig, +} from "openclaw/plugin-sdk/provider-models"; export function buildBytePlusProvider(): ModelProviderConfig { return { diff --git a/extensions/cloudflare-ai-gateway/index.ts b/extensions/cloudflare-ai-gateway/index.ts index aa584af8208..6c3cda9d0d2 100644 --- a/extensions/cloudflare-ai-gateway/index.ts +++ b/extensions/cloudflare-ai-gateway/index.ts @@ -1,21 +1,22 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { upsertAuthProfile } from "../../src/agents/auth-profiles.js"; -import { ensureAuthProfileStore, listProfilesForProvider } from "../../src/agents/auth-profiles.js"; +import { + applyAuthProfileConfig, + buildApiKeyCredential, + coerceSecretRef, + ensureApiKeyFromOptionEnvOrPrompt, + ensureAuthProfileStore, + listProfilesForProvider, + normalizeApiKeyInput, + normalizeOptionalSecretInput, + resolveNonEnvSecretRefApiKeyMarker, + type SecretInput, + upsertAuthProfile, + validateApiKeyInput, +} from "openclaw/plugin-sdk/provider-auth"; import { buildCloudflareAiGatewayModelDefinition, resolveCloudflareAiGatewayBaseUrl, -} from "../../src/agents/cloudflare-ai-gateway.js"; -import { resolveNonEnvSecretRefApiKeyMarker } from "../../src/agents/model-auth-markers.js"; -import { - normalizeApiKeyInput, - validateApiKeyInput, -} from "../../src/commands/auth-choice.api-key.js"; -import { ensureApiKeyFromOptionEnvOrPrompt } from "../../src/commands/auth-choice.apply-helpers.js"; -import { buildApiKeyCredential } from "../../src/commands/auth-credentials.js"; -import { applyAuthProfileConfig } from "../../src/commands/onboard-auth.js"; -import type { SecretInput } from "../../src/config/types.secrets.js"; -import { coerceSecretRef } from "../../src/config/types.secrets.js"; -import { normalizeOptionalSecretInput } from "../../src/utils/normalize-secret-input.js"; +} from "openclaw/plugin-sdk/provider-models"; import { applyCloudflareAiGatewayConfig, buildCloudflareAiGatewayConfigPatch, diff --git a/extensions/cloudflare-ai-gateway/onboard.ts b/extensions/cloudflare-ai-gateway/onboard.ts index 267c2f806f1..5260e1495a8 100644 --- a/extensions/cloudflare-ai-gateway/onboard.ts +++ b/extensions/cloudflare-ai-gateway/onboard.ts @@ -2,12 +2,12 @@ import { buildCloudflareAiGatewayModelDefinition, CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF, resolveCloudflareAiGatewayBaseUrl, -} from "../../src/agents/cloudflare-ai-gateway.js"; +} from "openclaw/plugin-sdk/provider-models"; import { applyAgentDefaultModelPrimary, applyProviderConfigWithDefaultModel, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export { CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF }; diff --git a/extensions/discord/src/account-inspect.ts b/extensions/discord/src/account-inspect.ts index a998c5ba874..c74c630cee4 100644 --- a/extensions/discord/src/account-inspect.ts +++ b/extensions/discord/src/account-inspect.ts @@ -1,13 +1,13 @@ import { hasConfiguredSecretInput, normalizeSecretInputString, -} from "../../../src/config/types.secrets.js"; +} from "openclaw/plugin-sdk/config-runtime"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId, type OpenClawConfig, type DiscordAccountConfig, -} from "../../../src/plugin-sdk-internal/discord.js"; +} from "openclaw/plugin-sdk/discord"; import { mergeDiscordAccountConfig, resolveDefaultDiscordAccountId, diff --git a/extensions/discord/src/accounts.ts b/extensions/discord/src/accounts.ts index 39903077aaf..b9b8ede5fe1 100644 --- a/extensions/discord/src/accounts.ts +++ b/extensions/discord/src/accounts.ts @@ -3,12 +3,12 @@ import { createAccountListHelpers, normalizeAccountId, resolveAccountEntry, -} from "../../../src/plugin-sdk-internal/accounts.js"; +} from "openclaw/plugin-sdk/account-resolution"; import type { - OpenClawConfig, DiscordAccountConfig, DiscordActionConfig, -} from "../../../src/plugin-sdk-internal/discord.js"; + OpenClawConfig, +} from "openclaw/plugin-sdk/discord"; import { resolveDiscordToken } from "./token.js"; export type ResolvedDiscordAccount = { diff --git a/extensions/discord/src/actions/handle-action.guild-admin.ts b/extensions/discord/src/actions/handle-action.guild-admin.ts index 80cd97217ae..0f6075384a5 100644 --- a/extensions/discord/src/actions/handle-action.guild-admin.ts +++ b/extensions/discord/src/actions/handle-action.guild-admin.ts @@ -4,13 +4,13 @@ import { readNumberParam, readStringArrayParam, readStringParam, -} from "../../../../src/agents/tools/common.js"; +} from "openclaw/plugin-sdk/agent-runtime"; import { isDiscordModerationAction, readDiscordModerationCommand, -} from "../../../../src/agents/tools/discord-actions-moderation-shared.js"; -import { handleDiscordAction } from "../../../../src/agents/tools/discord-actions.js"; -import type { ChannelMessageActionContext } from "../../../../src/channels/plugins/types.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { handleDiscordAction } from "openclaw/plugin-sdk/agent-runtime"; +import type { ChannelMessageActionContext } from "openclaw/plugin-sdk/channel-runtime"; type Ctx = Pick< ChannelMessageActionContext, diff --git a/extensions/discord/src/actions/handle-action.ts b/extensions/discord/src/actions/handle-action.ts index c938d675955..d23b078292a 100644 --- a/extensions/discord/src/actions/handle-action.ts +++ b/extensions/discord/src/actions/handle-action.ts @@ -1,15 +1,15 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; -import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param"; import { readNumberParam, readStringArrayParam, readStringParam, -} from "../../../../src/agents/tools/common.js"; -import { readDiscordParentIdParam } from "../../../../src/agents/tools/discord-actions-shared.js"; -import { handleDiscordAction } from "../../../../src/agents/tools/discord-actions.js"; -import { resolveReactionMessageId } from "../../../../src/channels/plugins/actions/reaction-message-id.js"; -import type { ChannelMessageActionContext } from "../../../../src/channels/plugins/types.js"; -import { normalizeInteractiveReply } from "../../../../src/interactive/payload.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { readDiscordParentIdParam } from "openclaw/plugin-sdk/agent-runtime"; +import { handleDiscordAction } from "openclaw/plugin-sdk/agent-runtime"; +import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param"; +import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelMessageActionContext } from "openclaw/plugin-sdk/channel-runtime"; +import { normalizeInteractiveReply } from "openclaw/plugin-sdk/channel-runtime"; import { buildDiscordInteractiveComponents } from "../shared-interactive.js"; import { resolveDiscordChannelId } from "../targets.js"; import { tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin.js"; diff --git a/extensions/discord/src/api.ts b/extensions/discord/src/api.ts index cead5eb8cea..0352656d21b 100644 --- a/extensions/discord/src/api.ts +++ b/extensions/discord/src/api.ts @@ -1,5 +1,9 @@ -import { resolveFetch } from "../../../src/infra/fetch.js"; -import { resolveRetryConfig, retryAsync, type RetryConfig } from "../../../src/infra/retry.js"; +import { resolveFetch } from "openclaw/plugin-sdk/infra-runtime"; +import { + resolveRetryConfig, + retryAsync, + type RetryConfig, +} from "openclaw/plugin-sdk/infra-runtime"; const DISCORD_API_BASE = "https://discord.com/api/v10"; const DISCORD_API_RETRY_DEFAULTS = { diff --git a/extensions/discord/src/audit.ts b/extensions/discord/src/audit.ts index a5a226c5550..79bc9b5b5fc 100644 --- a/extensions/discord/src/audit.ts +++ b/extensions/discord/src/audit.ts @@ -1,6 +1,9 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { DiscordGuildChannelConfig, DiscordGuildEntry } from "../../../src/config/types.js"; -import { isRecord } from "../../../src/utils.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { + DiscordGuildChannelConfig, + DiscordGuildEntry, +} from "openclaw/plugin-sdk/config-runtime"; +import { isRecord } from "openclaw/plugin-sdk/text-runtime"; import { inspectDiscordAccount } from "./account-inspect.js"; import { fetchChannelPermissionsDiscord } from "./send.js"; diff --git a/extensions/discord/src/channel-actions.ts b/extensions/discord/src/channel-actions.ts index 049eb4a320c..21f24fd9553 100644 --- a/extensions/discord/src/channel-actions.ts +++ b/extensions/discord/src/channel-actions.ts @@ -1,12 +1,12 @@ import { createUnionActionGate, listTokenSourcedAccounts, -} from "../../../src/channels/plugins/actions/shared.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelMessageActionAdapter, ChannelMessageActionName, -} from "../../../src/channels/plugins/types.js"; -import type { DiscordActionConfig } from "../../../src/config/types.discord.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { DiscordActionConfig } from "openclaw/plugin-sdk/config-runtime"; import { createDiscordActionGate, listEnabledDiscordAccounts } from "./accounts.js"; import { handleDiscordMessageAction } from "./actions/handle-action.js"; diff --git a/extensions/discord/src/channel.setup.ts b/extensions/discord/src/channel.setup.ts index 5c7bfe6e659..1988c03ca26 100644 --- a/extensions/discord/src/channel.setup.ts +++ b/extensions/discord/src/channel.setup.ts @@ -1,8 +1,43 @@ -import type { ChannelPlugin } from "openclaw/plugin-sdk/discord"; -import type { ResolvedDiscordAccount } from "./accounts.js"; +import { + buildChannelConfigSchema, + DiscordConfigSchema, + getChatChannelMeta, + type ChannelPlugin, +} from "openclaw/plugin-sdk/discord"; +import { type ResolvedDiscordAccount } from "./accounts.js"; +import { discordConfigAccessors, discordConfigBase, discordSetupWizard } from "./plugin-shared.js"; import { discordSetupAdapter } from "./setup-core.js"; -import { createDiscordPluginBase } from "./shared.js"; -export const discordSetupPlugin: ChannelPlugin = createDiscordPluginBase({ +export const discordSetupPlugin: ChannelPlugin = { + id: "discord", + meta: { + ...getChatChannelMeta("discord"), + }, + setupWizard: discordSetupWizard, + capabilities: { + chatTypes: ["direct", "channel", "thread"], + polls: true, + reactions: true, + threads: true, + media: true, + nativeCommands: true, + }, + streaming: { + blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 }, + }, + reload: { configPrefixes: ["channels.discord"] }, + configSchema: buildChannelConfigSchema(DiscordConfigSchema), + config: { + ...discordConfigBase, + isConfigured: (account) => Boolean(account.token?.trim()), + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: Boolean(account.token?.trim()), + tokenSource: account.tokenSource, + }), + ...discordConfigAccessors, + }, setup: discordSetupAdapter, -}); +}; diff --git a/extensions/discord/src/channel.ts b/extensions/discord/src/channel.ts index b598f004cf7..d12813e66a6 100644 --- a/extensions/discord/src/channel.ts +++ b/extensions/discord/src/channel.ts @@ -1,10 +1,12 @@ import { Separator, TextDisplay } from "@buape/carbon"; +import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/allowlist-config-edit"; import { - buildAccountScopedAllowlistConfigEditor, buildAccountScopedDmSecurityPolicy, - collectOpenProviderGroupPolicyWarnings, collectOpenGroupPolicyConfiguredRouteWarnings, -} from "openclaw/plugin-sdk/compat"; + collectOpenProviderGroupPolicyWarnings, +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; +import { normalizeMessageChannel } from "openclaw/plugin-sdk/channel-runtime"; import { buildAgentSessionKey, resolveThreadSessionKeys, @@ -12,8 +14,11 @@ import { } from "openclaw/plugin-sdk/core"; import { buildComputedAccountStatusSnapshot, + buildChannelConfigSchema, buildTokenChannelStatusSummary, DEFAULT_ACCOUNT_ID, + DiscordConfigSchema, + getChatChannelMeta, listDiscordDirectoryGroupsFromConfig, listDiscordDirectoryPeersFromConfig, PAIRING_APPROVED_MESSAGE, @@ -25,9 +30,6 @@ import { type ChannelPlugin, type OpenClawConfig, } from "openclaw/plugin-sdk/discord"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; -import { normalizeOutboundThreadId } from "../../../src/infra/outbound/thread-id.js"; -import { normalizeMessageChannel } from "../../../src/utils/message-channel.js"; import { listDiscordAccountIds, resolveDiscordAccount, @@ -43,12 +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 { discordSetupAdapter } from "./setup-core.js"; -import { createDiscordPluginBase, discordConfigAccessors } from "./shared.js"; import { collectDiscordStatusIssues } from "./status-issues.js"; import { parseDiscordTarget } from "./targets.js"; import { DiscordUiContainer } from "./ui.js"; @@ -57,6 +59,7 @@ type DiscordSendFn = ReturnType< typeof getDiscordRuntime >["channel"]["discord"]["sendMessageDiscord"]; +const meta = getChatChannelMeta("discord"); const REQUIRED_DISCORD_PERMISSIONS = ["ViewChannel", "SendMessages"] as const; function formatDiscordIntents(intents?: { @@ -197,6 +200,20 @@ function parseDiscordExplicitTarget(raw: string) { } } +function normalizeOutboundThreadId(value?: string | number | null): string | undefined { + if (value == null) { + return undefined; + } + if (typeof value === "number") { + if (!Number.isFinite(value)) { + return undefined; + } + return String(Math.trunc(value)); + } + const trimmed = value.trim(); + return trimmed ? trimmed : undefined; +} + function buildDiscordBaseSessionKey(params: { cfg: OpenClawConfig; agentId: string; @@ -280,9 +297,11 @@ function resolveDiscordOutboundSessionRoute(params: { } export const discordPlugin: ChannelPlugin = { - ...createDiscordPluginBase({ - setup: discordSetupAdapter, - }), + id: "discord", + meta: { + ...meta, + }, + setupWizard: discordSetupWizard, pairing: { idLabel: "discordUserId", normalizeAllowEntry: (entry) => entry.replace(/^(discord|user):/i, ""), @@ -293,6 +312,31 @@ export const discordPlugin: ChannelPlugin = { ); }, }, + capabilities: { + chatTypes: ["direct", "channel", "thread"], + polls: true, + reactions: true, + threads: true, + media: true, + nativeCommands: true, + }, + streaming: { + blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 }, + }, + reload: { configPrefixes: ["channels.discord"] }, + configSchema: buildChannelConfigSchema(DiscordConfigSchema), + config: { + ...discordConfigBase, + isConfigured: (account) => Boolean(account.token?.trim()), + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: Boolean(account.token?.trim()), + tokenSource: account.tokenSource, + }), + ...discordConfigAccessors, + }, allowlist: { supportsScope: ({ scope }) => scope === "dm", readConfig: ({ cfg, accountId }) => diff --git a/extensions/discord/src/chunk.ts b/extensions/discord/src/chunk.ts index a814c10d2c8..5efff023152 100644 --- a/extensions/discord/src/chunk.ts +++ b/extensions/discord/src/chunk.ts @@ -1,4 +1,4 @@ -import { chunkMarkdownTextWithMode, type ChunkMode } from "../../../src/auto-reply/chunk.js"; +import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; export type ChunkDiscordTextOpts = { /** Max characters per Discord message. Default: 2000. */ diff --git a/extensions/discord/src/client.ts b/extensions/discord/src/client.ts index 2e8d53799a6..2688add72cd 100644 --- a/extensions/discord/src/client.ts +++ b/extensions/discord/src/client.ts @@ -1,8 +1,8 @@ import { RequestClient } from "@buape/carbon"; -import { loadConfig } from "../../../src/config/config.js"; -import { createDiscordRetryRunner, type RetryRunner } from "../../../src/infra/retry-policy.js"; -import type { RetryConfig } from "../../../src/infra/retry.js"; -import { normalizeAccountId } from "../../../src/routing/session-key.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { createDiscordRetryRunner, type RetryRunner } from "openclaw/plugin-sdk/infra-runtime"; +import type { RetryConfig } from "openclaw/plugin-sdk/infra-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { mergeDiscordAccountConfig, resolveDiscordAccount, diff --git a/extensions/discord/src/directory-cache.ts b/extensions/discord/src/directory-cache.ts index d1a85767216..cc8c9d7c546 100644 --- a/extensions/discord/src/directory-cache.ts +++ b/extensions/discord/src/directory-cache.ts @@ -1,4 +1,4 @@ -import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/account-id.js"; +import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing"; const DISCORD_DIRECTORY_CACHE_MAX_ENTRIES = 4000; const DISCORD_DISCRIMINATOR_SUFFIX = /#\d{4}$/; diff --git a/extensions/discord/src/directory-live.ts b/extensions/discord/src/directory-live.ts index af55475a43e..6bd38204a0a 100644 --- a/extensions/discord/src/directory-live.ts +++ b/extensions/discord/src/directory-live.ts @@ -1,5 +1,5 @@ -import type { DirectoryConfigParams } from "../../../src/channels/plugins/directory-config.js"; -import type { ChannelDirectoryEntry } from "../../../src/channels/plugins/types.js"; +import type { DirectoryConfigParams } from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelDirectoryEntry } from "openclaw/plugin-sdk/channel-runtime"; import { resolveDiscordAccount } from "./accounts.js"; import { fetchDiscord } from "./api.js"; import { rememberDiscordDirectoryUser } from "./directory-cache.js"; diff --git a/extensions/discord/src/draft-chunking.ts b/extensions/discord/src/draft-chunking.ts index a6461412ae7..98cc48a2f9f 100644 --- a/extensions/discord/src/draft-chunking.ts +++ b/extensions/discord/src/draft-chunking.ts @@ -1,7 +1,7 @@ -import { resolveTextChunkLimit } from "../../../src/auto-reply/chunk.js"; -import { type OpenClawConfig } from "../../../src/config/config.js"; -import { resolveAccountEntry } from "../../../src/routing/account-lookup.js"; -import { normalizeAccountId } from "../../../src/routing/session-key.js"; +import { type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAccountEntry } from "openclaw/plugin-sdk/routing"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter.js"; const DEFAULT_DISCORD_DRAFT_STREAM_MIN = 200; diff --git a/extensions/discord/src/draft-stream.ts b/extensions/discord/src/draft-stream.ts index db9089f6176..a12348334bc 100644 --- a/extensions/discord/src/draft-stream.ts +++ b/extensions/discord/src/draft-stream.ts @@ -1,6 +1,6 @@ import type { RequestClient } from "@buape/carbon"; import { Routes } from "discord-api-types/v10"; -import { createFinalizableDraftLifecycle } from "../../../src/channels/draft-stream-controls.js"; +import { createFinalizableDraftLifecycle } from "openclaw/plugin-sdk/channel-runtime"; /** Discord messages cap at 2000 characters. */ const DISCORD_STREAM_MAX_CHARS = 2000; diff --git a/extensions/discord/src/exec-approvals.ts b/extensions/discord/src/exec-approvals.ts index 5640805705a..bdafce36713 100644 --- a/extensions/discord/src/exec-approvals.ts +++ b/extensions/discord/src/exec-approvals.ts @@ -1,6 +1,6 @@ -import type { ReplyPayload } from "../../../src/auto-reply/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { getExecApprovalReplyMetadata } from "../../../src/infra/exec-approval-reply.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/infra-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { resolveDiscordAccount } from "./accounts.js"; export function isDiscordExecApprovalClientEnabled(params: { diff --git a/extensions/discord/src/gateway-logging.ts b/extensions/discord/src/gateway-logging.ts index 18ce32909ef..3a6802ccaef 100644 --- a/extensions/discord/src/gateway-logging.ts +++ b/extensions/discord/src/gateway-logging.ts @@ -1,6 +1,6 @@ import type { EventEmitter } from "node:events"; -import { logVerbose } from "../../../src/globals.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; type GatewayEmitter = Pick; diff --git a/extensions/discord/src/monitor.tool-result.test-harness.ts b/extensions/discord/src/monitor.tool-result.test-harness.ts index 700e9a63df3..fd4f67b0890 100644 --- a/extensions/discord/src/monitor.tool-result.test-harness.ts +++ b/extensions/discord/src/monitor.tool-result.test-harness.ts @@ -1,5 +1,5 @@ +import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { vi } from "vitest"; -import type { MockFn } from "../../../src/test-utils/vitest-mock-fn.js"; export const sendMock: MockFn = vi.fn(); export const reactMock: MockFn = vi.fn(); @@ -15,8 +15,8 @@ vi.mock("./send.js", () => ({ }, })); -vi.mock("../../../src/auto-reply/dispatch.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/reply-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, dispatchInboundMessage: (...args: unknown[]) => dispatchMock(...args), @@ -36,10 +36,10 @@ function createPairingStoreMocks() { }; } -vi.mock("../../../src/pairing/pairing-store.js", () => createPairingStoreMocks()); +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => createPairingStoreMocks()); -vi.mock("../../../src/config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), diff --git a/extensions/discord/src/monitor/agent-components.ts b/extensions/discord/src/monitor/agent-components.ts index e28bd17b70e..5ac63e76d51 100644 --- a/extensions/discord/src/monitor/agent-components.ts +++ b/extensions/discord/src/monitor/agent-components.ts @@ -18,41 +18,41 @@ import { } from "@buape/carbon"; import type { APIStringSelectComponent } from "discord-api-types/v10"; import { ButtonStyle, ChannelType } from "discord-api-types/v10"; -import { resolveHumanDelayConfig } from "../../../../src/agents/identity.js"; -import { resolveChunkMode, resolveTextChunkLimit } from "../../../../src/auto-reply/chunk.js"; -import { - formatInboundEnvelope, - resolveEnvelopeFormatOptions, -} from "../../../../src/auto-reply/envelope.js"; -import { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js"; -import { dispatchReplyWithBufferedBlockDispatcher } from "../../../../src/auto-reply/reply/provider-dispatcher.js"; -import { createReplyReferencePlanner } from "../../../../src/auto-reply/reply/reply-reference.js"; -import { resolveCommandAuthorizedFromAuthorizers } from "../../../../src/channels/command-gating.js"; -import { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js"; -import { recordInboundSession } from "../../../../src/channels/session.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; -import { resolveMarkdownTableMode } from "../../../../src/config/markdown-tables.js"; -import { readSessionUpdatedAt, resolveStorePath } from "../../../../src/config/sessions.js"; -import type { DiscordAccountConfig } from "../../../../src/config/types.discord.js"; -import { logVerbose } from "../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../src/infra/system-events.js"; -import { logDebug, logError } from "../../../../src/logger.js"; -import { getAgentScopedMediaLocalRoots } from "../../../../src/media/local-roots.js"; -import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js"; -import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js"; +import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime"; +import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import type { DiscordAccountConfig } from "openclaw/plugin-sdk/config-runtime"; +import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime"; +import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime"; import { buildPluginBindingResolvedText, parsePluginBindingApprovalCustomId, resolvePluginConversationBindingApproval, -} from "../../../../src/plugins/conversation-binding.js"; -import { dispatchPluginInteractiveHandler } from "../../../../src/plugins/interactive.js"; -import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; -import { createNonExitingRuntime, type RuntimeEnv } from "../../../../src/runtime.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +import { dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime"; +import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import { + formatInboundEnvelope, + resolveEnvelopeFormatOptions, +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchReplyWithBufferedBlockDispatcher } from "openclaw/plugin-sdk/reply-runtime"; +import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { readStoreAllowFromForDmPolicy, resolvePinnedMainDmOwnerFromAllowlist, -} from "../../../../src/security/dm-policy-shared.js"; +} from "openclaw/plugin-sdk/security-runtime"; +import { logDebug, logError } from "openclaw/plugin-sdk/text-runtime"; import { resolveDiscordMaxLinesPerMessage } from "../accounts.js"; import { resolveDiscordComponentEntry, resolveDiscordModalEntry } from "../components-registry.js"; import { diff --git a/extensions/discord/src/monitor/allow-list.ts b/extensions/discord/src/monitor/allow-list.ts index a6208eaf63a..31d95f2f45b 100644 --- a/extensions/discord/src/monitor/allow-list.ts +++ b/extensions/discord/src/monitor/allow-list.ts @@ -1,12 +1,12 @@ import type { Guild, User } from "@buape/carbon"; -import { evaluateGroupRouteAccessForPolicy } from "openclaw/plugin-sdk/group-access"; -import type { AllowlistMatch } from "../../../../src/channels/allowlist-match.js"; +import type { AllowlistMatch } from "openclaw/plugin-sdk/channel-runtime"; import { buildChannelKeyCandidates, resolveChannelEntryMatchWithFallback, resolveChannelMatchConfig, type ChannelMatchSource, -} from "../../../../src/channels/channel-config.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { evaluateGroupRouteAccessForPolicy } from "openclaw/plugin-sdk/group-access"; import { formatDiscordUserTag } from "./format.js"; export type DiscordAllowList = { diff --git a/extensions/discord/src/monitor/auto-presence.ts b/extensions/discord/src/monitor/auto-presence.ts index 60e5619e348..b76ea6f6d5c 100644 --- a/extensions/discord/src/monitor/auto-presence.ts +++ b/extensions/discord/src/monitor/auto-presence.ts @@ -6,12 +6,12 @@ import { resolveProfilesUnavailableReason, type AuthProfileFailureReason, type AuthProfileStore, -} from "../../../../src/agents/auth-profiles.js"; +} from "openclaw/plugin-sdk/agent-runtime"; import type { DiscordAccountConfig, DiscordAutoPresenceConfig, -} from "../../../../src/config/config.js"; -import { warn } from "../../../../src/globals.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { warn } from "openclaw/plugin-sdk/runtime-env"; import { resolveDiscordPresenceUpdate } from "./presence.js"; const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4; diff --git a/extensions/discord/src/monitor/commands.ts b/extensions/discord/src/monitor/commands.ts index a9bb9c1548e..43e92ea9122 100644 --- a/extensions/discord/src/monitor/commands.ts +++ b/extensions/discord/src/monitor/commands.ts @@ -1,4 +1,4 @@ -import type { DiscordSlashCommandConfig } from "../../../../src/config/types.discord.js"; +import type { DiscordSlashCommandConfig } from "openclaw/plugin-sdk/config-runtime"; export function resolveDiscordSlashCommandConfig( raw?: DiscordSlashCommandConfig, diff --git a/extensions/discord/src/monitor/dm-command-auth.ts b/extensions/discord/src/monitor/dm-command-auth.ts index 2fa02d9d605..1e8f1afbb4b 100644 --- a/extensions/discord/src/monitor/dm-command-auth.ts +++ b/extensions/discord/src/monitor/dm-command-auth.ts @@ -1,9 +1,9 @@ -import { resolveCommandAuthorizedFromAuthorizers } from "../../../../src/channels/command-gating.js"; +import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime"; import { readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithLists, type DmGroupAccessDecision, -} from "../../../../src/security/dm-policy-shared.js"; +} from "openclaw/plugin-sdk/security-runtime"; import { normalizeDiscordAllowList, resolveDiscordAllowListMatch } from "./allow-list.js"; const DISCORD_ALLOW_LIST_PREFIXES = ["discord:", "user:", "pk:"]; diff --git a/extensions/discord/src/monitor/dm-command-decision.ts b/extensions/discord/src/monitor/dm-command-decision.ts index 8c15e7cac11..ec5cb6330e0 100644 --- a/extensions/discord/src/monitor/dm-command-decision.ts +++ b/extensions/discord/src/monitor/dm-command-decision.ts @@ -1,5 +1,5 @@ -import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js"; -import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js"; +import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime"; +import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime"; import type { DiscordDmCommandAccess } from "./dm-command-auth.js"; export async function handleDiscordDmCommandDecision(params: { diff --git a/extensions/discord/src/monitor/exec-approvals.ts b/extensions/discord/src/monitor/exec-approvals.ts index e5fda7682a9..607d5088ad1 100644 --- a/extensions/discord/src/monitor/exec-approvals.ts +++ b/extensions/discord/src/monitor/exec-approvals.ts @@ -10,30 +10,24 @@ import { type TopLevelComponents, } from "@buape/carbon"; import { ButtonStyle, Routes } from "discord-api-types/v10"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { loadSessionStore, resolveStorePath } from "../../../../src/config/sessions.js"; -import type { DiscordExecApprovalConfig } from "../../../../src/config/types.discord.js"; -import { GatewayClient } from "../../../../src/gateway/client.js"; -import { createOperatorApprovalsGatewayClient } from "../../../../src/gateway/operator-approvals-client.js"; -import type { EventFrame } from "../../../../src/gateway/protocol/index.js"; -import { resolveExecApprovalCommandDisplay } from "../../../../src/infra/exec-approval-command-display.js"; -import { getExecApprovalApproverDmNoticeText } from "../../../../src/infra/exec-approval-reply.js"; +import { normalizeMessageChannel } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { loadSessionStore, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import type { DiscordExecApprovalConfig } from "openclaw/plugin-sdk/config-runtime"; +import { GatewayClient } from "openclaw/plugin-sdk/gateway-runtime"; +import { createOperatorApprovalsGatewayClient } from "openclaw/plugin-sdk/gateway-runtime"; +import type { EventFrame } from "openclaw/plugin-sdk/gateway-runtime"; +import { resolveExecApprovalCommandDisplay } from "openclaw/plugin-sdk/infra-runtime"; +import { getExecApprovalApproverDmNoticeText } from "openclaw/plugin-sdk/infra-runtime"; import type { ExecApprovalDecision, ExecApprovalRequest, ExecApprovalResolved, -} from "../../../../src/infra/exec-approvals.js"; -import { logDebug, logError } from "../../../../src/logger.js"; -import { - normalizeAccountId, - resolveAgentIdFromSessionKey, -} from "../../../../src/routing/session-key.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; -import { - compileSafeRegex, - testRegexWithBoundedInput, -} from "../../../../src/security/safe-regex.js"; -import { normalizeMessageChannel } from "../../../../src/utils/message-channel.js"; +} from "openclaw/plugin-sdk/infra-runtime"; +import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { compileSafeRegex, testRegexWithBoundedInput } from "openclaw/plugin-sdk/security-runtime"; +import { logDebug, logError } from "openclaw/plugin-sdk/text-runtime"; import { createDiscordClient, stripUndefinedFields } from "../send.shared.js"; import { DiscordUiContainer } from "../ui.js"; diff --git a/extensions/discord/src/monitor/gateway-plugin.ts b/extensions/discord/src/monitor/gateway-plugin.ts index 1799c16d79e..109135a3684 100644 --- a/extensions/discord/src/monitor/gateway-plugin.ts +++ b/extensions/discord/src/monitor/gateway-plugin.ts @@ -1,11 +1,11 @@ import { GatewayIntents, GatewayPlugin } from "@buape/carbon/gateway"; import type { APIGatewayBotInfo } from "discord-api-types/v10"; import { HttpsProxyAgent } from "https-proxy-agent"; +import type { DiscordAccountConfig } from "openclaw/plugin-sdk/config-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { ProxyAgent, fetch as undiciFetch } from "undici"; import WebSocket from "ws"; -import type { DiscordAccountConfig } from "../../../../src/config/types.js"; -import { danger } from "../../../../src/globals.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; const DISCORD_GATEWAY_BOT_URL = "https://discord.com/api/v10/gateway/bot"; const DEFAULT_DISCORD_GATEWAY_URL = "wss://gateway.discord.gg/"; @@ -20,7 +20,7 @@ type DiscordGatewayFetch = ( ) => Promise; export function resolveDiscordGatewayIntents( - intentsConfig?: import("../../../../src/config/types.discord.js").DiscordIntentsConfig, + intentsConfig?: import("openclaw/plugin-sdk/config-runtime").DiscordIntentsConfig, ): number { let intents = GatewayIntents.Guilds | diff --git a/extensions/discord/src/monitor/inbound-context.ts b/extensions/discord/src/monitor/inbound-context.ts index 26b2a07f03e..1f0608d3529 100644 --- a/extensions/discord/src/monitor/inbound-context.ts +++ b/extensions/discord/src/monitor/inbound-context.ts @@ -1,4 +1,4 @@ -import { buildUntrustedChannelMetadata } from "../../../../src/security/channel-metadata.js"; +import { buildUntrustedChannelMetadata } from "openclaw/plugin-sdk/security-runtime"; import { resolveDiscordOwnerAllowFrom, type DiscordChannelConfigResolved, diff --git a/extensions/discord/src/monitor/inbound-worker.ts b/extensions/discord/src/monitor/inbound-worker.ts index cbc8e246704..33986e458a3 100644 --- a/extensions/discord/src/monitor/inbound-worker.ts +++ b/extensions/discord/src/monitor/inbound-worker.ts @@ -1,7 +1,7 @@ +import { createRunStateMachine } from "openclaw/plugin-sdk/channel-runtime"; +import { formatDurationSeconds } from "openclaw/plugin-sdk/infra-runtime"; import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue"; -import { createRunStateMachine } from "../../../../src/channels/run-state-machine.js"; -import { danger } from "../../../../src/globals.js"; -import { formatDurationSeconds } from "../../../../src/infra/format-time/format-duration.ts"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; import { materializeDiscordInboundJob, type DiscordInboundJob } from "./inbound-job.js"; import type { RuntimeEnv } from "./message-handler.preflight.types.js"; import { processDiscordMessage } from "./message-handler.process.js"; diff --git a/extensions/discord/src/monitor/listeners.ts b/extensions/discord/src/monitor/listeners.ts index 318435d5318..9ed94d0a52f 100644 --- a/extensions/discord/src/monitor/listeners.ts +++ b/extensions/discord/src/monitor/listeners.ts @@ -8,16 +8,16 @@ import { ThreadUpdateListener, type User, } from "@buape/carbon"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { danger, logVerbose } from "../../../../src/globals.js"; -import { formatDurationSeconds } from "../../../../src/infra/format-time/format-duration.ts"; -import { enqueueSystemEvent } from "../../../../src/infra/system-events.js"; -import { createSubsystemLogger } from "../../../../src/logging/subsystem.js"; -import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { formatDurationSeconds } from "openclaw/plugin-sdk/infra-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; import { readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithLists, -} from "../../../../src/security/dm-policy-shared.js"; +} from "openclaw/plugin-sdk/security-runtime"; import { isDiscordGroupAllowedByPolicy, normalizeDiscordAllowList, @@ -36,11 +36,9 @@ import { isThreadArchived } from "./thread-bindings.discord-api.js"; import { closeDiscordThreadSessions } from "./thread-session-close.js"; import { normalizeDiscordListenerTimeoutMs, runDiscordTaskWithTimeout } from "./timeouts.js"; -type LoadedConfig = ReturnType; -type RuntimeEnv = import("../../../../src/runtime.js").RuntimeEnv; -type Logger = ReturnType< - typeof import("../../../../src/logging/subsystem.js").createSubsystemLogger ->; +type LoadedConfig = ReturnType; +type RuntimeEnv = import("openclaw/plugin-sdk/runtime-env").RuntimeEnv; +type Logger = ReturnType; export type DiscordMessageEvent = Parameters[0]; diff --git a/extensions/discord/src/monitor/message-handler.module-test-helpers.ts b/extensions/discord/src/monitor/message-handler.module-test-helpers.ts index 83174ad5621..adeaf7953e7 100644 --- a/extensions/discord/src/monitor/message-handler.module-test-helpers.ts +++ b/extensions/discord/src/monitor/message-handler.module-test-helpers.ts @@ -1,5 +1,5 @@ +import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { vi } from "vitest"; -import type { MockFn } from "../../../../src/test-utils/vitest-mock-fn.js"; export const preflightDiscordMessageMock: MockFn = vi.fn(); export const processDiscordMessageMock: MockFn = vi.fn(); diff --git a/extensions/discord/src/monitor/message-handler.preflight.test-helpers.ts b/extensions/discord/src/monitor/message-handler.preflight.test-helpers.ts index 24895d287f7..8c6aa5f3cc1 100644 --- a/extensions/discord/src/monitor/message-handler.preflight.test-helpers.ts +++ b/extensions/discord/src/monitor/message-handler.preflight.test-helpers.ts @@ -1,5 +1,5 @@ import { ChannelType } from "@buape/carbon"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { preflightDiscordMessage } from "./message-handler.preflight.js"; import { createNoopThreadBindingManager } from "./thread-bindings.js"; @@ -90,7 +90,7 @@ export function createDiscordPreflightArgs(params: { discordConfig: params.discordConfig, accountId: "default", token: "token", - runtime: {} as import("../../../../src/runtime.js").RuntimeEnv, + runtime: {} as import("openclaw/plugin-sdk/runtime-env").RuntimeEnv, botUserId: params.botUserId ?? "openclaw-bot", guildHistories: new Map(), historyLimit: 0, diff --git a/extensions/discord/src/monitor/message-handler.preflight.ts b/extensions/discord/src/monitor/message-handler.preflight.ts index 77640784063..0a402518927 100644 --- a/extensions/discord/src/monitor/message-handler.preflight.ts +++ b/extensions/discord/src/monitor/message-handler.preflight.ts @@ -1,36 +1,33 @@ import { ChannelType, MessageType, type User } from "@buape/carbon"; +import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveControlCommandGate } from "openclaw/plugin-sdk/channel-runtime"; +import { logInboundDrop } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; import { ensureConfiguredAcpRouteReady, resolveConfiguredAcpRoute, -} from "../../../../src/acp/persistent-bindings.route.js"; -import { hasControlCommand } from "../../../../src/auto-reply/command-detection.js"; -import { shouldHandleTextCommands } from "../../../../src/auto-reply/commands-registry.js"; -import { - recordPendingHistoryEntryIfEnabled, - type HistoryEntry, -} from "../../../../src/auto-reply/reply/history.js"; -import { - buildMentionRegexes, - matchesMentionWithExplicit, -} from "../../../../src/auto-reply/reply/mentions.js"; -import { formatAllowlistMatchMeta } from "../../../../src/channels/allowlist-match.js"; -import { resolveControlCommandGate } from "../../../../src/channels/command-gating.js"; -import { logInboundDrop } from "../../../../src/channels/logging.js"; -import { resolveMentionGatingWithBypass } from "../../../../src/channels/mention-gating.js"; -import { loadConfig } from "../../../../src/config/config.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; -import { logVerbose, shouldLogVerbose } from "../../../../src/globals.js"; -import { recordChannelActivity } from "../../../../src/infra/channel-activity.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; import { getSessionBindingService, type SessionBindingRecord, -} from "../../../../src/infra/outbound/session-binding-service.js"; -import { enqueueSystemEvent } from "../../../../src/infra/system-events.js"; -import { logDebug } from "../../../../src/logger.js"; -import { getChildLogger } from "../../../../src/logging.js"; -import { buildPairingReply } from "../../../../src/pairing/pairing-messages.js"; -import { isPluginOwnedSessionBindingRecord } from "../../../../src/plugins/conversation-binding.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { buildPairingReply } from "openclaw/plugin-sdk/conversation-runtime"; +import { isPluginOwnedSessionBindingRecord } from "openclaw/plugin-sdk/conversation-runtime"; +import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime"; +import { shouldHandleTextCommands } from "openclaw/plugin-sdk/reply-runtime"; +import { + recordPendingHistoryEntryIfEnabled, + type HistoryEntry, +} from "openclaw/plugin-sdk/reply-runtime"; +import { buildMentionRegexes, matchesMentionWithExplicit } from "openclaw/plugin-sdk/reply-runtime"; +import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; +import { logDebug } from "openclaw/plugin-sdk/text-runtime"; import { fetchPluralKitMessageInfo } from "../pluralkit.js"; import { sendMessageDiscord } from "../send.js"; import { diff --git a/extensions/discord/src/monitor/message-handler.preflight.types.ts b/extensions/discord/src/monitor/message-handler.preflight.types.ts index a123a22dcaa..368352e1551 100644 --- a/extensions/discord/src/monitor/message-handler.preflight.types.ts +++ b/extensions/discord/src/monitor/message-handler.preflight.types.ts @@ -1,8 +1,8 @@ import type { ChannelType, Client, User } from "@buape/carbon"; -import type { HistoryEntry } from "../../../../src/auto-reply/reply/history.js"; -import type { ReplyToMode } from "../../../../src/config/config.js"; -import type { SessionBindingRecord } from "../../../../src/infra/outbound/session-binding-service.js"; -import type { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; +import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; +import type { SessionBindingRecord } from "openclaw/plugin-sdk/conversation-runtime"; +import type { HistoryEntry } from "openclaw/plugin-sdk/reply-runtime"; +import type { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; import type { DiscordChannelConfigResolved, DiscordGuildEntryResolved } from "./allow-list.js"; import type { DiscordChannelInfo } from "./message-utils.js"; import type { DiscordThreadBindingLookup } from "./reply-delivery.js"; @@ -11,15 +11,17 @@ import type { DiscordSenderIdentity } from "./sender-identity.js"; export type { DiscordSenderIdentity } from "./sender-identity.js"; import type { DiscordThreadChannel } from "./threading.js"; -export type LoadedConfig = ReturnType; -export type RuntimeEnv = import("../../../../src/runtime.js").RuntimeEnv; +export type LoadedConfig = ReturnType< + typeof import("openclaw/plugin-sdk/config-runtime").loadConfig +>; +export type RuntimeEnv = import("openclaw/plugin-sdk/runtime-env").RuntimeEnv; export type DiscordMessageEvent = import("./listeners.js").DiscordMessageEvent; type DiscordMessagePreflightSharedFields = { cfg: LoadedConfig; discordConfig: NonNullable< - import("../../../../src/config/config.js").OpenClawConfig["channels"] + import("openclaw/plugin-sdk/config-runtime").OpenClawConfig["channels"] >["discord"]; accountId: string; token: string; diff --git a/extensions/discord/src/monitor/message-handler.process.ts b/extensions/discord/src/monitor/message-handler.process.ts index dc86c3720ef..526ca4ecb71 100644 --- a/extensions/discord/src/monitor/message-handler.process.ts +++ b/extensions/discord/src/monitor/message-handler.process.ts @@ -1,40 +1,40 @@ import { ChannelType, type RequestClient } from "@buape/carbon"; -import { resolveAckReaction, resolveHumanDelayConfig } from "../../../../src/agents/identity.js"; -import { EmbeddedBlockChunker } from "../../../../src/agents/pi-embedded-block-chunker.js"; -import { resolveChunkMode } from "../../../../src/auto-reply/chunk.js"; -import { dispatchInboundMessage } from "../../../../src/auto-reply/dispatch.js"; -import { - formatInboundEnvelope, - resolveEnvelopeFormatOptions, -} from "../../../../src/auto-reply/envelope.js"; -import { - buildPendingHistoryContextFromMap, - clearHistoryEntriesIfEnabled, -} from "../../../../src/auto-reply/reply/history.js"; -import { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js"; -import { createReplyDispatcherWithTyping } from "../../../../src/auto-reply/reply/reply-dispatcher.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import { shouldAckReaction as shouldAckReactionGate } from "../../../../src/channels/ack-reactions.js"; -import { logTypingFailure, logAckFailure } from "../../../../src/channels/logging.js"; -import { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js"; -import { recordInboundSession } from "../../../../src/channels/session.js"; +import { resolveAckReaction, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime"; +import { EmbeddedBlockChunker } from "openclaw/plugin-sdk/agent-runtime"; +import { shouldAckReaction as shouldAckReactionGate } from "openclaw/plugin-sdk/channel-runtime"; +import { logTypingFailure, logAckFailure } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime"; import { createStatusReactionController, DEFAULT_TIMING, type StatusReactionAdapter, -} from "../../../../src/channels/status-reactions.js"; -import { createTypingCallbacks } from "../../../../src/channels/typing.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; -import { resolveDiscordPreviewStreamMode } from "../../../../src/config/discord-preview-streaming.js"; -import { resolveMarkdownTableMode } from "../../../../src/config/markdown-tables.js"; -import { readSessionUpdatedAt, resolveStorePath } from "../../../../src/config/sessions.js"; -import { danger, logVerbose, shouldLogVerbose } from "../../../../src/globals.js"; -import { convertMarkdownTables } from "../../../../src/markdown/tables.js"; -import { getAgentScopedMediaLocalRoots } from "../../../../src/media/local-roots.js"; -import { buildAgentSessionKey } from "../../../../src/routing/resolve-route.js"; -import { resolveThreadSessionKeys } from "../../../../src/routing/session-key.js"; -import { stripReasoningTagsFromText } from "../../../../src/shared/text/reasoning-tags.js"; -import { truncateUtf16Safe } from "../../../../src/utils.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; +import { resolveDiscordPreviewStreamMode } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +import { resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchInboundMessage } from "openclaw/plugin-sdk/reply-runtime"; +import { + formatInboundEnvelope, + resolveEnvelopeFormatOptions, +} from "openclaw/plugin-sdk/reply-runtime"; +import { + buildPendingHistoryContextFromMap, + clearHistoryEntriesIfEnabled, +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import { createReplyDispatcherWithTyping } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing"; +import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; +import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; +import { stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-runtime"; +import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-runtime"; import { resolveDiscordMaxLinesPerMessage } from "../accounts.js"; import { chunkDiscordTextWithMode } from "../chunk.js"; import { resolveDiscordDraftStreamingChunking } from "../draft-chunking.js"; diff --git a/extensions/discord/src/monitor/message-handler.test-helpers.ts b/extensions/discord/src/monitor/message-handler.test-helpers.ts index 04bfb9b603c..ed232ae43fb 100644 --- a/extensions/discord/src/monitor/message-handler.test-helpers.ts +++ b/extensions/discord/src/monitor/message-handler.test-helpers.ts @@ -1,5 +1,5 @@ +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { vi } from "vitest"; -import type { OpenClawConfig } from "../../../../src/config/types.js"; import type { createDiscordMessageHandler } from "./message-handler.js"; import { createNoopThreadBindingManager } from "./thread-bindings.js"; diff --git a/extensions/discord/src/monitor/message-handler.ts b/extensions/discord/src/monitor/message-handler.ts index 2c9745a8bf0..400f35a2529 100644 --- a/extensions/discord/src/monitor/message-handler.ts +++ b/extensions/discord/src/monitor/message-handler.ts @@ -2,9 +2,9 @@ import type { Client } from "@buape/carbon"; import { createChannelInboundDebouncer, shouldDebounceTextInbound, -} from "../../../../src/channels/inbound-debounce-policy.js"; -import { resolveOpenProviderRuntimeGroupPolicy } from "../../../../src/config/runtime-group-policy.js"; -import { danger } from "../../../../src/globals.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; import { buildDiscordInboundJob } from "./inbound-job.js"; import { createDiscordInboundWorker } from "./inbound-worker.js"; import type { DiscordMessageEvent, DiscordMessageHandler } from "./listeners.js"; diff --git a/extensions/discord/src/monitor/message-utils.ts b/extensions/discord/src/monitor/message-utils.ts index ae37d6615fd..4e84f4b3827 100644 --- a/extensions/discord/src/monitor/message-utils.ts +++ b/extensions/discord/src/monitor/message-utils.ts @@ -1,10 +1,10 @@ import type { ChannelType, Client, Message } from "@buape/carbon"; import { StickerFormatType, type APIAttachment, type APIStickerItem } from "discord-api-types/v10"; -import { buildMediaPayload } from "../../../../src/channels/plugins/media-payload.js"; -import { logVerbose } from "../../../../src/globals.js"; -import type { SsrFPolicy } from "../../../../src/infra/net/ssrf.js"; -import { fetchRemoteMedia, type FetchLike } from "../../../../src/media/fetch.js"; -import { saveMediaBuffer } from "../../../../src/media/store.js"; +import { buildMediaPayload } from "openclaw/plugin-sdk/channel-runtime"; +import type { SsrFPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import { fetchRemoteMedia, type FetchLike } from "openclaw/plugin-sdk/media-runtime"; +import { saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; const DISCORD_CDN_HOSTNAMES = [ "cdn.discordapp.com", diff --git a/extensions/discord/src/monitor/model-picker-preferences.ts b/extensions/discord/src/monitor/model-picker-preferences.ts index 8657ed66436..ca3483678af 100644 --- a/extensions/discord/src/monitor/model-picker-preferences.ts +++ b/extensions/discord/src/monitor/model-picker-preferences.ts @@ -1,11 +1,11 @@ import os from "node:os"; import path from "node:path"; import { normalizeAccountId as normalizeSharedAccountId } from "openclaw/plugin-sdk/account-id"; +import { normalizeProviderId } from "openclaw/plugin-sdk/agent-runtime"; +import { withFileLock } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveRequiredHomeDir } from "openclaw/plugin-sdk/infra-runtime"; import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store"; -import { normalizeProviderId } from "../../../../src/agents/model-selection.js"; -import { resolveStateDir } from "../../../../src/config/paths.js"; -import { withFileLock } from "../../../../src/infra/file-lock.js"; -import { resolveRequiredHomeDir } from "../../../../src/infra/home-dir.js"; +import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; const MODEL_PICKER_PREFERENCES_LOCK_OPTIONS = { retries: { diff --git a/extensions/discord/src/monitor/model-picker.test-utils.ts b/extensions/discord/src/monitor/model-picker.test-utils.ts index 8d9a9dd3197..56dcd7480c1 100644 --- a/extensions/discord/src/monitor/model-picker.test-utils.ts +++ b/extensions/discord/src/monitor/model-picker.test-utils.ts @@ -1,4 +1,4 @@ -import type { ModelsProviderData } from "../../../../src/auto-reply/reply/commands-models.js"; +import type { ModelsProviderData } from "openclaw/plugin-sdk/reply-runtime"; export function createModelsProviderData( entries: Record, diff --git a/extensions/discord/src/monitor/model-picker.ts b/extensions/discord/src/monitor/model-picker.ts index fb9226ac899..ec067ede2dd 100644 --- a/extensions/discord/src/monitor/model-picker.ts +++ b/extensions/discord/src/monitor/model-picker.ts @@ -11,12 +11,12 @@ import { } from "@buape/carbon"; import type { APISelectMenuOption } from "discord-api-types/v10"; import { ButtonStyle } from "discord-api-types/v10"; -import { normalizeProviderId } from "../../../../src/agents/model-selection.js"; +import { normalizeProviderId } from "openclaw/plugin-sdk/agent-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { buildModelsProviderData, type ModelsProviderData, -} from "../../../../src/auto-reply/reply/commands-models.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; +} from "openclaw/plugin-sdk/reply-runtime"; export const DISCORD_MODEL_PICKER_CUSTOM_ID_KEY = "mdlpk"; export const DISCORD_CUSTOM_ID_MAX_CHARS = 100; diff --git a/extensions/discord/src/monitor/native-command-context.ts b/extensions/discord/src/monitor/native-command-context.ts index fc650827d45..07dc0bf0a76 100644 --- a/extensions/discord/src/monitor/native-command-context.ts +++ b/extensions/discord/src/monitor/native-command-context.ts @@ -1,5 +1,5 @@ -import type { CommandArgs } from "../../../../src/auto-reply/commands-registry.js"; -import { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js"; +import type { CommandArgs } from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; import { type DiscordChannelConfigResolved, type DiscordGuildEntryResolved } from "./allow-list.js"; import { buildDiscordInboundAccessContext } from "./inbound-context.js"; diff --git a/extensions/discord/src/monitor/native-command.ts b/extensions/discord/src/monitor/native-command.ts index e745063d8d0..ed50aff52a3 100644 --- a/extensions/discord/src/monitor/native-command.ts +++ b/extensions/discord/src/monitor/native-command.ts @@ -15,19 +15,29 @@ import { type StringSelectMenuInteraction, } from "@buape/carbon"; import { ApplicationCommandOptionType, ButtonStyle } from "discord-api-types/v10"; +import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime"; +import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveNativeCommandSessionTargets } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig, loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; +import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { loadSessionStore, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; import { ensureConfiguredAcpRouteReady, resolveConfiguredAcpRoute, -} from "../../../../src/acp/persistent-bindings.route.js"; -import { resolveHumanDelayConfig } from "../../../../src/agents/identity.js"; -import { resolveChunkMode, resolveTextChunkLimit } from "../../../../src/auto-reply/chunk.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { buildPairingReply } from "openclaw/plugin-sdk/conversation-runtime"; +import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +import { executePluginCommand, matchPluginCommand } from "openclaw/plugin-sdk/plugin-runtime"; +import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; import type { ChatCommandDefinition, CommandArgDefinition, CommandArgValues, CommandArgs, NativeCommandSpec, -} from "../../../../src/auto-reply/commands-registry.js"; +} from "openclaw/plugin-sdk/reply-runtime"; import { buildCommandTextFromArgs, findCommandByNativeName, @@ -36,25 +46,15 @@ import { resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs, -} from "../../../../src/auto-reply/commands-registry.js"; -import { resolveStoredModelOverride } from "../../../../src/auto-reply/reply/model-selection.js"; -import { dispatchReplyWithDispatcher } from "../../../../src/auto-reply/reply/provider-dispatcher.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import { resolveCommandAuthorizedFromAuthorizers } from "../../../../src/channels/command-gating.js"; -import { resolveNativeCommandSessionTargets } from "../../../../src/channels/native-command-session-targets.js"; -import { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js"; -import type { OpenClawConfig, loadConfig } from "../../../../src/config/config.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; -import { resolveOpenProviderRuntimeGroupPolicy } from "../../../../src/config/runtime-group-policy.js"; -import { loadSessionStore, resolveStorePath } from "../../../../src/config/sessions.js"; -import { logVerbose } from "../../../../src/globals.js"; -import { createSubsystemLogger } from "../../../../src/logging/subsystem.js"; -import { getAgentScopedMediaLocalRoots } from "../../../../src/media/local-roots.js"; -import { buildPairingReply } from "../../../../src/pairing/pairing-messages.js"; -import { executePluginCommand, matchPluginCommand } from "../../../../src/plugins/commands.js"; -import type { ResolvedAgentRoute } from "../../../../src/routing/resolve-route.js"; -import { chunkItems } from "../../../../src/utils/chunk-items.js"; -import { withTimeout } from "../../../../src/utils/with-timeout.js"; +} from "openclaw/plugin-sdk/reply-runtime"; +import { resolveStoredModelOverride } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchReplyWithDispatcher } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import type { ResolvedAgentRoute } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { chunkItems } from "openclaw/plugin-sdk/text-runtime"; +import { withTimeout } from "openclaw/plugin-sdk/text-runtime"; import { loadWebMedia } from "../../../whatsapp/src/media.js"; import { resolveDiscordMaxLinesPerMessage } from "../accounts.js"; import { chunkDiscordTextWithMode } from "../chunk.js"; diff --git a/extensions/discord/src/monitor/preflight-audio.ts b/extensions/discord/src/monitor/preflight-audio.ts index f52e2b0df93..f26fe5de9a9 100644 --- a/extensions/discord/src/monitor/preflight-audio.ts +++ b/extensions/discord/src/monitor/preflight-audio.ts @@ -1,5 +1,5 @@ -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { logVerbose } from "../../../../src/globals.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; type DiscordAudioAttachment = { content_type?: string; @@ -50,8 +50,7 @@ export async function resolveDiscordPreflightAudioMentionContext(params: { }; } try { - const { transcribeFirstAudio } = - await import("../../../../src/media-understanding/audio-preflight.js"); + const { transcribeFirstAudio } = await import("openclaw/plugin-sdk/media-runtime"); if (params.abortSignal?.aborted) { return { hasAudioAttachment, diff --git a/extensions/discord/src/monitor/presence.ts b/extensions/discord/src/monitor/presence.ts index b13a21dc2f1..cfe8125e50e 100644 --- a/extensions/discord/src/monitor/presence.ts +++ b/extensions/discord/src/monitor/presence.ts @@ -1,5 +1,5 @@ import type { Activity, UpdatePresenceData } from "@buape/carbon/gateway"; -import type { DiscordAccountConfig } from "../../../../src/config/config.js"; +import type { DiscordAccountConfig } from "openclaw/plugin-sdk/config-runtime"; const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4; const CUSTOM_STATUS_NAME = "Custom Status"; diff --git a/extensions/discord/src/monitor/provider.allowlist.ts b/extensions/discord/src/monitor/provider.allowlist.ts index 3f108e443ea..ac6c89dd9f8 100644 --- a/extensions/discord/src/monitor/provider.allowlist.ts +++ b/extensions/discord/src/monitor/provider.allowlist.ts @@ -4,11 +4,11 @@ import { canonicalizeAllowlistWithResolvedIds, patchAllowlistUsersInConfigEntries, summarizeMapping, -} from "../../../../src/channels/allowlists/resolve-utils.js"; -import type { DiscordGuildEntry } from "../../../../src/config/types.discord.js"; -import { formatErrorMessage } from "../../../../src/infra/errors.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; -import { normalizeStringEntries } from "../../../../src/shared/string-normalization.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { DiscordGuildEntry } from "openclaw/plugin-sdk/config-runtime"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { normalizeStringEntries } from "openclaw/plugin-sdk/text-runtime"; import { resolveDiscordChannelAllowlist } from "../resolve-channels.js"; import { resolveDiscordUserAllowlist } from "../resolve-users.js"; diff --git a/extensions/discord/src/monitor/provider.lifecycle.ts b/extensions/discord/src/monitor/provider.lifecycle.ts index 4d2130c3a5d..0d5fbd66b25 100644 --- a/extensions/discord/src/monitor/provider.lifecycle.ts +++ b/extensions/discord/src/monitor/provider.lifecycle.ts @@ -1,9 +1,9 @@ import type { Client } from "@buape/carbon"; import type { GatewayPlugin } from "@buape/carbon/gateway"; -import { createArmableStallWatchdog } from "../../../../src/channels/transport/stall-watchdog.js"; -import { createConnectedChannelStatusPatch } from "../../../../src/gateway/channel-status-patches.js"; -import { danger } from "../../../../src/globals.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +import { createArmableStallWatchdog } from "openclaw/plugin-sdk/channel-runtime"; +import { createConnectedChannelStatusPatch } from "openclaw/plugin-sdk/gateway-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { attachDiscordGatewayLogging } from "../gateway-logging.js"; import { getDiscordGatewayEmitter, waitForDiscordGatewayStop } from "../monitor.gateway.js"; import type { DiscordVoiceManager } from "../voice/manager.js"; diff --git a/extensions/discord/src/monitor/provider.ts b/extensions/discord/src/monitor/provider.ts index d4ef01ab0d8..9c766334964 100644 --- a/extensions/discord/src/monitor/provider.ts +++ b/extensions/discord/src/monitor/provider.ts @@ -11,39 +11,45 @@ import { import { GatewayCloseCodes, type GatewayPlugin } from "@buape/carbon/gateway"; import { VoicePlugin } from "@buape/carbon/voice"; import { Routes } from "discord-api-types/v10"; -import { getAcpSessionManager } from "../../../../src/acp/control-plane/manager.js"; -import { isAcpRuntimeError } from "../../../../src/acp/runtime/errors.js"; -import { resolveTextChunkLimit } from "../../../../src/auto-reply/chunk.js"; -import type { NativeCommandSpec } from "../../../../src/auto-reply/commands-registry.js"; -import { listNativeCommandSpecsForConfig } from "../../../../src/auto-reply/commands-registry.js"; -import type { HistoryEntry } from "../../../../src/auto-reply/reply/history.js"; -import { listSkillCommandsForAgents } from "../../../../src/auto-reply/skill-commands.js"; +import { getAcpSessionManager } from "openclaw/plugin-sdk/acp-runtime"; +import { isAcpRuntimeError } from "openclaw/plugin-sdk/acp-runtime"; import { resolveThreadBindingIdleTimeoutMs, resolveThreadBindingMaxAgeMs, resolveThreadBindingsEnabled, -} from "../../../../src/channels/thread-bindings-policy.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import { isNativeCommandsExplicitlyDisabled, resolveNativeCommandsEnabled, resolveNativeSkillsEnabled, -} from "../../../../src/config/commands.js"; -import type { OpenClawConfig, ReplyToMode } from "../../../../src/config/config.js"; -import { loadConfig } from "../../../../src/config/config.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import type { OpenClawConfig, ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; import { GROUP_POLICY_BLOCKED_LABEL, resolveOpenProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce, -} from "../../../../src/config/runtime-group-policy.js"; -import { createConnectedChannelStatusPatch } from "../../../../src/gateway/channel-status-patches.js"; -import { danger, isVerbose, logVerbose, shouldLogVerbose, warn } from "../../../../src/globals.js"; -import { formatErrorMessage } from "../../../../src/infra/errors.js"; -import { createSubsystemLogger } from "../../../../src/logging/subsystem.js"; -import { getPluginCommandSpecs } from "../../../../src/plugins/commands.js"; -import { createNonExitingRuntime, type RuntimeEnv } from "../../../../src/runtime.js"; -import { summarizeStringEntries } from "../../../../src/shared/string-sample.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { createConnectedChannelStatusPatch } from "openclaw/plugin-sdk/gateway-runtime"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { getPluginCommandSpecs } from "openclaw/plugin-sdk/plugin-runtime"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import type { NativeCommandSpec } from "openclaw/plugin-sdk/reply-runtime"; +import { listNativeCommandSpecsForConfig } from "openclaw/plugin-sdk/reply-runtime"; +import type { HistoryEntry } from "openclaw/plugin-sdk/reply-runtime"; +import { listSkillCommandsForAgents } from "openclaw/plugin-sdk/reply-runtime"; +import { + danger, + isVerbose, + logVerbose, + shouldLogVerbose, + warn, +} from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { summarizeStringEntries } from "openclaw/plugin-sdk/text-runtime"; import { resolveDiscordAccount } from "../accounts.js"; import { getDiscordGatewayEmitter } from "../monitor.gateway.js"; import { fetchDiscordApplicationId } from "../probe.js"; diff --git a/extensions/discord/src/monitor/reply-delivery.ts b/extensions/discord/src/monitor/reply-delivery.ts index 07e5c9e06c5..6e495d420ce 100644 --- a/extensions/discord/src/monitor/reply-delivery.ts +++ b/extensions/discord/src/monitor/reply-delivery.ts @@ -1,13 +1,17 @@ import type { RequestClient } from "@buape/carbon"; -import { resolveAgentAvatar } from "../../../../src/agents/identity-avatar.js"; -import type { ChunkMode } from "../../../../src/auto-reply/chunk.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import type { MarkdownTableMode, ReplyToMode } from "../../../../src/config/types.base.js"; -import { createDiscordRetryRunner, type RetryRunner } from "../../../../src/infra/retry-policy.js"; -import { resolveRetryConfig, retryAsync, type RetryConfig } from "../../../../src/infra/retry.js"; -import { convertMarkdownTables } from "../../../../src/markdown/tables.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +import { resolveAgentAvatar } from "openclaw/plugin-sdk/agent-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { MarkdownTableMode, ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; +import { createDiscordRetryRunner, type RetryRunner } from "openclaw/plugin-sdk/infra-runtime"; +import { + resolveRetryConfig, + retryAsync, + type RetryConfig, +} from "openclaw/plugin-sdk/infra-runtime"; +import type { ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; import { resolveDiscordAccount } from "../accounts.js"; import { chunkDiscordTextWithMode } from "../chunk.js"; import { sendMessageDiscord, sendVoiceMessageDiscord, sendWebhookMessageDiscord } from "../send.js"; diff --git a/extensions/discord/src/monitor/rest-fetch.ts b/extensions/discord/src/monitor/rest-fetch.ts index 83be5a98325..43b4c768381 100644 --- a/extensions/discord/src/monitor/rest-fetch.ts +++ b/extensions/discord/src/monitor/rest-fetch.ts @@ -1,7 +1,7 @@ +import { wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/infra-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { ProxyAgent, fetch as undiciFetch } from "undici"; -import { danger } from "../../../../src/globals.js"; -import { wrapFetchWithAbortSignal } from "../../../../src/infra/fetch.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; export function resolveDiscordRestFetch( proxyUrl: string | undefined, diff --git a/extensions/discord/src/monitor/route-resolution.ts b/extensions/discord/src/monitor/route-resolution.ts index aacbebbd51e..f76c9b49f65 100644 --- a/extensions/discord/src/monitor/route-resolution.ts +++ b/extensions/discord/src/monitor/route-resolution.ts @@ -1,11 +1,11 @@ -import type { OpenClawConfig } from "../../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { deriveLastRoutePolicy, resolveAgentRoute, type ResolvedAgentRoute, type RoutePeer, -} from "../../../../src/routing/resolve-route.js"; -import { resolveAgentIdFromSessionKey } from "../../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/routing"; +import { resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; export function buildDiscordRoutePeer(params: { isDirectMessage: boolean; diff --git a/extensions/discord/src/monitor/thread-bindings.config.ts b/extensions/discord/src/monitor/thread-bindings.config.ts index 830d54d0d1b..701defcfbe1 100644 --- a/extensions/discord/src/monitor/thread-bindings.config.ts +++ b/extensions/discord/src/monitor/thread-bindings.config.ts @@ -2,9 +2,9 @@ import { resolveThreadBindingIdleTimeoutMs, resolveThreadBindingMaxAgeMs, resolveThreadBindingsEnabled, -} from "../../../../src/channels/thread-bindings-policy.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { normalizeAccountId } from "../../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; export { resolveThreadBindingIdleTimeoutMs, diff --git a/extensions/discord/src/monitor/thread-bindings.discord-api.ts b/extensions/discord/src/monitor/thread-bindings.discord-api.ts index 134eda0f109..d144bb22b72 100644 --- a/extensions/discord/src/monitor/thread-bindings.discord-api.ts +++ b/extensions/discord/src/monitor/thread-bindings.discord-api.ts @@ -1,6 +1,6 @@ import { ChannelType, Routes } from "discord-api-types/v10"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { logVerbose } from "../../../../src/globals.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { createDiscordRestClient } from "../client.js"; import { sendMessageDiscord, sendWebhookMessageDiscord } from "../send.js"; import { createThreadDiscord } from "../send.messages.js"; diff --git a/extensions/discord/src/monitor/thread-bindings.lifecycle.ts b/extensions/discord/src/monitor/thread-bindings.lifecycle.ts index d7d96857250..230a9cd7273 100644 --- a/extensions/discord/src/monitor/thread-bindings.lifecycle.ts +++ b/extensions/discord/src/monitor/thread-bindings.lifecycle.ts @@ -1,9 +1,6 @@ -import { - readAcpSessionEntry, - type AcpSessionStoreEntry, -} from "../../../../src/acp/runtime/session-meta.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { normalizeAccountId } from "../../../../src/routing/session-key.js"; +import { readAcpSessionEntry, type AcpSessionStoreEntry } from "openclaw/plugin-sdk/acp-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { parseDiscordTarget } from "../targets.js"; import { resolveChannelIdForBinding } from "./thread-bindings.discord-api.js"; import { getThreadBindingManager } from "./thread-bindings.manager.js"; diff --git a/extensions/discord/src/monitor/thread-bindings.manager.ts b/extensions/discord/src/monitor/thread-bindings.manager.ts index efa599cadc2..f6d5f7d3d90 100644 --- a/extensions/discord/src/monitor/thread-bindings.manager.ts +++ b/extensions/discord/src/monitor/thread-bindings.manager.ts @@ -1,17 +1,14 @@ import { Routes } from "discord-api-types/v10"; -import { resolveThreadBindingConversationIdFromBindingId } from "../../../../src/channels/thread-binding-id.js"; -import { getRuntimeConfigSnapshot, type OpenClawConfig } from "../../../../src/config/config.js"; -import { logVerbose } from "../../../../src/globals.js"; +import { resolveThreadBindingConversationIdFromBindingId } from "openclaw/plugin-sdk/channel-runtime"; +import { getRuntimeConfigSnapshot, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { registerSessionBindingAdapter, unregisterSessionBindingAdapter, type BindingTargetKind, type SessionBindingRecord, -} from "../../../../src/infra/outbound/session-binding-service.js"; -import { - normalizeAccountId, - resolveAgentIdFromSessionKey, -} from "../../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { createDiscordRestClient } from "../client.js"; import { createThreadForBinding, diff --git a/extensions/discord/src/monitor/thread-bindings.messages.ts b/extensions/discord/src/monitor/thread-bindings.messages.ts index 3fc122cbe71..043e888b7fc 100644 --- a/extensions/discord/src/monitor/thread-bindings.messages.ts +++ b/extensions/discord/src/monitor/thread-bindings.messages.ts @@ -3,4 +3,4 @@ export { resolveThreadBindingFarewellText, resolveThreadBindingIntroText, resolveThreadBindingThreadName, -} from "../../../../src/channels/thread-bindings-messages.js"; +} from "openclaw/plugin-sdk/channel-runtime"; diff --git a/extensions/discord/src/monitor/thread-bindings.persona.ts b/extensions/discord/src/monitor/thread-bindings.persona.ts index 6798df009e0..2ee38c5f49d 100644 --- a/extensions/discord/src/monitor/thread-bindings.persona.ts +++ b/extensions/discord/src/monitor/thread-bindings.persona.ts @@ -1,4 +1,4 @@ -import { SYSTEM_MARK } from "../../../../src/infra/system-message.js"; +import { SYSTEM_MARK } from "openclaw/plugin-sdk/infra-runtime"; import type { ThreadBindingRecord } from "./thread-bindings.types.js"; const THREAD_BINDING_PERSONA_MAX_CHARS = 80; diff --git a/extensions/discord/src/monitor/thread-bindings.state.ts b/extensions/discord/src/monitor/thread-bindings.state.ts index cfcbc65f3f5..97de19c1dd5 100644 --- a/extensions/discord/src/monitor/thread-bindings.state.ts +++ b/extensions/discord/src/monitor/thread-bindings.state.ts @@ -1,11 +1,8 @@ import fs from "node:fs"; import path from "node:path"; -import { resolveStateDir } from "../../../../src/config/paths.js"; -import { loadJsonFile, saveJsonFile } from "../../../../src/infra/json-file.js"; -import { - normalizeAccountId, - resolveAgentIdFromSessionKey, -} from "../../../../src/routing/session-key.js"; +import { loadJsonFile, saveJsonFile } from "openclaw/plugin-sdk/json-store"; +import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; +import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; import { DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS, DEFAULT_THREAD_BINDING_MAX_AGE_MS, diff --git a/extensions/discord/src/monitor/thread-session-close.ts b/extensions/discord/src/monitor/thread-session-close.ts index ca73f623bd0..6a5d6c88c8b 100644 --- a/extensions/discord/src/monitor/thread-session-close.ts +++ b/extensions/discord/src/monitor/thread-session-close.ts @@ -1,5 +1,5 @@ -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { resolveStorePath, updateSessionStore } from "../../../../src/config/sessions.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveStorePath, updateSessionStore } from "openclaw/plugin-sdk/config-runtime"; /** * Marks every session entry in the store whose key contains {@link threadId} diff --git a/extensions/discord/src/monitor/threading.ts b/extensions/discord/src/monitor/threading.ts index 035354b98af..c3bf70d659c 100644 --- a/extensions/discord/src/monitor/threading.ts +++ b/extensions/discord/src/monitor/threading.ts @@ -1,10 +1,10 @@ import { ChannelType, type Client } from "@buape/carbon"; import { Routes } from "discord-api-types/v10"; -import { createReplyReferencePlanner } from "../../../../src/auto-reply/reply/reply-reference.js"; -import type { ReplyToMode } from "../../../../src/config/config.js"; -import { logVerbose } from "../../../../src/globals.js"; -import { buildAgentSessionKey } from "../../../../src/routing/resolve-route.js"; -import { truncateUtf16Safe } from "../../../../src/utils.js"; +import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; +import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-runtime"; +import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-runtime"; import type { DiscordChannelConfigResolved } from "./allow-list.js"; import type { DiscordMessageEvent } from "./listeners.js"; import { diff --git a/extensions/discord/src/outbound-adapter.ts b/extensions/discord/src/outbound-adapter.ts index bc2f5f8c2d1..93fd1cb8bfb 100644 --- a/extensions/discord/src/outbound-adapter.ts +++ b/extensions/discord/src/outbound-adapter.ts @@ -2,11 +2,11 @@ import { resolvePayloadMediaUrls, sendPayloadMediaSequence, sendTextMediaPayload, -} from "../../../src/channels/plugins/outbound/direct-text-media.js"; -import type { ChannelOutboundAdapter } from "../../../src/channels/plugins/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { OutboundIdentity } from "../../../src/infra/outbound/identity.js"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { OutboundIdentity } from "openclaw/plugin-sdk/infra-runtime"; import type { DiscordComponentMessageSpec } from "./components.js"; import { getThreadBindingManager, type ThreadBindingRecord } from "./monitor/thread-bindings.js"; import { normalizeDiscordOutboundTarget } from "./normalize.js"; diff --git a/extensions/discord/src/plugin-shared.ts b/extensions/discord/src/plugin-shared.ts index 9b5aec43b9e..f67e04d1a51 100644 --- a/extensions/discord/src/plugin-shared.ts +++ b/extensions/discord/src/plugin-shared.ts @@ -1,9 +1,9 @@ +import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from"; import { createScopedAccountConfigAccessors, createScopedChannelConfigBase, - formatAllowFromLowercase, -} from "../../../src/plugin-sdk-internal/channel-config.js"; -import { type OpenClawConfig } from "../../../src/plugin-sdk-internal/discord.js"; +} from "openclaw/plugin-sdk/channel-config-helpers"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/discord"; import { inspectDiscordAccount } from "./account-inspect.js"; import { listDiscordAccountIds, diff --git a/extensions/discord/src/pluralkit.ts b/extensions/discord/src/pluralkit.ts index e328fb27eff..b8e6b30609a 100644 --- a/extensions/discord/src/pluralkit.ts +++ b/extensions/discord/src/pluralkit.ts @@ -1,4 +1,4 @@ -import { resolveFetch } from "../../../src/infra/fetch.js"; +import { resolveFetch } from "openclaw/plugin-sdk/infra-runtime"; const PLURALKIT_API_BASE = "https://api.pluralkit.me/v2"; diff --git a/extensions/discord/src/probe.ts b/extensions/discord/src/probe.ts index b434cd8c78d..f84b4aad10a 100644 --- a/extensions/discord/src/probe.ts +++ b/extensions/discord/src/probe.ts @@ -1,6 +1,6 @@ -import type { BaseProbeResult } from "../../../src/channels/plugins/types.js"; -import { resolveFetch } from "../../../src/infra/fetch.js"; -import { fetchWithTimeout } from "../../../src/utils/fetch-timeout.js"; +import type { BaseProbeResult } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveFetch } from "openclaw/plugin-sdk/infra-runtime"; +import { fetchWithTimeout } from "openclaw/plugin-sdk/text-runtime"; import { normalizeDiscordToken } from "./token.js"; const DISCORD_API_BASE = "https://discord.com/api/v10"; diff --git a/extensions/discord/src/runtime.ts b/extensions/discord/src/runtime.ts index b73ec43a065..4a07abdc1f7 100644 --- a/extensions/discord/src/runtime.ts +++ b/extensions/discord/src/runtime.ts @@ -1,7 +1,5 @@ -import { - createPluginRuntimeStore, - type PluginRuntime, -} from "../../../src/plugin-sdk-internal/core.js"; +import type { PluginRuntime } from "openclaw/plugin-sdk/core"; +import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; const { setRuntime: setDiscordRuntime, getRuntime: getDiscordRuntime } = createPluginRuntimeStore("Discord runtime not initialized"); diff --git a/extensions/discord/src/send.components.ts b/extensions/discord/src/send.components.ts index 9212e383ed7..9c641ba596d 100644 --- a/extensions/discord/src/send.components.ts +++ b/extensions/discord/src/send.components.ts @@ -5,8 +5,8 @@ import { type RequestClient, } from "@buape/carbon"; import { ChannelType, Routes } from "discord-api-types/v10"; -import { loadConfig, type OpenClawConfig } from "../../../src/config/config.js"; -import { recordChannelActivity } from "../../../src/infra/channel-activity.js"; +import { loadConfig, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime"; import { loadWebMedia } from "../../whatsapp/src/media.js"; import { resolveDiscordAccount } from "./accounts.js"; import { registerDiscordComponentEntries } from "./components-registry.js"; diff --git a/extensions/discord/src/send.outbound.ts b/extensions/discord/src/send.outbound.ts index 8f7b743e0d0..cc71330b192 100644 --- a/extensions/discord/src/send.outbound.ts +++ b/extensions/discord/src/send.outbound.ts @@ -3,17 +3,17 @@ import fs from "node:fs/promises"; import path from "node:path"; import { serializePayload, type MessagePayloadObject, type RequestClient } from "@buape/carbon"; import { ChannelType, Routes } from "discord-api-types/v10"; -import { resolveChunkMode } from "../../../src/auto-reply/chunk.js"; -import { loadConfig, type OpenClawConfig } from "../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { recordChannelActivity } from "../../../src/infra/channel-activity.js"; -import type { RetryConfig } from "../../../src/infra/retry.js"; -import { resolvePreferredOpenClawTmpDir } from "../../../src/infra/tmp-openclaw-dir.js"; -import { convertMarkdownTables } from "../../../src/markdown/tables.js"; -import { maxBytesForKind } from "../../../src/media/constants.js"; -import { extensionForMime } from "../../../src/media/mime.js"; -import { unlinkIfExists } from "../../../src/media/temp-files.js"; -import type { PollInput } from "../../../src/polls.js"; +import { loadConfig, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime"; +import type { RetryConfig } from "openclaw/plugin-sdk/infra-runtime"; +import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/infra-runtime"; +import { maxBytesForKind } from "openclaw/plugin-sdk/media-runtime"; +import { extensionForMime } from "openclaw/plugin-sdk/media-runtime"; +import { unlinkIfExists } from "openclaw/plugin-sdk/media-runtime"; +import type { PollInput } from "openclaw/plugin-sdk/media-runtime"; +import { resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; import { loadWebMediaRaw } from "../../whatsapp/src/media.js"; import { resolveDiscordAccount } from "./accounts.js"; import { rewriteDiscordKnownMentions } from "./mentions.js"; diff --git a/extensions/discord/src/send.reactions.ts b/extensions/discord/src/send.reactions.ts index 26353a7acb5..be48c85771d 100644 --- a/extensions/discord/src/send.reactions.ts +++ b/extensions/discord/src/send.reactions.ts @@ -1,5 +1,5 @@ import { Routes } from "discord-api-types/v10"; -import { loadConfig } from "../../../src/config/config.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { buildReactionIdentifier, createDiscordClient, diff --git a/extensions/discord/src/send.shared.ts b/extensions/discord/src/send.shared.ts index f1a7fd4c28e..115356510d2 100644 --- a/extensions/discord/src/send.shared.ts +++ b/extensions/discord/src/send.shared.ts @@ -9,15 +9,15 @@ import { import { PollLayoutType } from "discord-api-types/payloads/v10"; import type { RESTAPIPoll } from "discord-api-types/rest/v10"; import { Routes, type APIChannel, type APIEmbed } from "discord-api-types/v10"; -import type { ChunkMode } from "../../../src/auto-reply/chunk.js"; -import { loadConfig, type OpenClawConfig } from "../../../src/config/config.js"; -import type { RetryRunner } from "../../../src/infra/retry-policy.js"; -import { buildOutboundMediaLoadOptions } from "../../../src/media/load-options.js"; +import { loadConfig, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { RetryRunner } from "openclaw/plugin-sdk/infra-runtime"; +import { buildOutboundMediaLoadOptions } from "openclaw/plugin-sdk/media-runtime"; import { normalizePollDurationHours, normalizePollInput, type PollInput, -} from "../../../src/polls.js"; +} from "openclaw/plugin-sdk/media-runtime"; +import type { ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; import { loadWebMedia } from "../../whatsapp/src/media.js"; import { resolveDiscordAccount } from "./accounts.js"; import { chunkDiscordTextWithMode } from "./chunk.js"; diff --git a/extensions/discord/src/send.test-harness.ts b/extensions/discord/src/send.test-harness.ts index f3c5ae36842..8a2058772fc 100644 --- a/extensions/discord/src/send.test-harness.ts +++ b/extensions/discord/src/send.test-harness.ts @@ -1,5 +1,5 @@ +import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { vi } from "vitest"; -import type { MockFn } from "../../../src/test-utils/vitest-mock-fn.js"; type DiscordWebMediaMockFactoryResult = { loadWebMedia: MockFn; diff --git a/extensions/discord/src/send.types.ts b/extensions/discord/src/send.types.ts index 189c9434d1e..781cb84a435 100644 --- a/extensions/discord/src/send.types.ts +++ b/extensions/discord/src/send.types.ts @@ -1,6 +1,6 @@ import type { RequestClient } from "@buape/carbon"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { RetryConfig } from "../../../src/infra/retry.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { RetryConfig } from "openclaw/plugin-sdk/infra-runtime"; export class DiscordSendError extends Error { kind?: "missing-permissions" | "dm-blocked"; diff --git a/extensions/discord/src/session-key-normalization.ts b/extensions/discord/src/session-key-normalization.ts index 7e47fe012dd..06164d6aba5 100644 --- a/extensions/discord/src/session-key-normalization.ts +++ b/extensions/discord/src/session-key-normalization.ts @@ -1,5 +1,5 @@ -import type { MsgContext } from "../../../src/auto-reply/templating.js"; -import { normalizeChatType } from "../../../src/channels/chat-type.js"; +import { normalizeChatType } from "openclaw/plugin-sdk/channel-runtime"; +import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime"; export function normalizeExplicitDiscordSessionKey( sessionKey: string, diff --git a/extensions/discord/src/setup-core.ts b/extensions/discord/src/setup-core.ts index fe2b559a975..a362824a0f3 100644 --- a/extensions/discord/src/setup-core.ts +++ b/extensions/discord/src/setup-core.ts @@ -1,7 +1,10 @@ -import { createPatchedAccountSetupAdapter } from "../../../src/channels/plugins/setup-helpers.js"; -import type { DiscordGuildEntry } from "../../../src/config/types.discord.js"; +import type { DiscordGuildEntry } from "openclaw/plugin-sdk/config-runtime"; import { + applyAccountNameToChannelSection, DEFAULT_ACCOUNT_ID, + formatDocsLink, + migrateBaseNameToDefaultAccount, + normalizeAccountId, noteChannelLookupFailure, noteChannelLookupSummary, parseMentionOrPrefixedId, @@ -9,13 +12,12 @@ import { setLegacyChannelDmPolicyWithAllowFrom, setSetupChannelEnabled, type OpenClawConfig, -} from "../../../src/plugin-sdk-internal/setup.js"; +} from "openclaw/plugin-sdk/setup"; import { type ChannelSetupAdapter, type ChannelSetupDmPolicy, type ChannelSetupWizard, -} from "../../../src/plugin-sdk-internal/setup.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; +} from "openclaw/plugin-sdk/setup"; import { inspectDiscordAccount } from "./account-inspect.js"; import { listDiscordAccountIds, resolveDiscordAccount } from "./accounts.js"; @@ -70,8 +72,15 @@ export function parseDiscordAllowFromId(value: string): string | null { }); } -export const discordSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupAdapter({ - channelKey: channel, +export const discordSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + }), validateInput: ({ accountId, input }) => { if (input.useEnv && accountId !== DEFAULT_ACCOUNT_ID) { return "DISCORD_BOT_TOKEN can only be used for the default account."; @@ -81,46 +90,57 @@ export const discordSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetu } return null; }, - buildPatch: (input) => (input.useEnv ? {} : input.token ? { token: input.token } : {}), -}); - -type DiscordAllowFromResolverParams = { - cfg: OpenClawConfig; - accountId: string; - credentialValues: { token?: string }; - entries: string[]; + applyAccountConfig: ({ cfg, accountId, input }) => { + const namedConfig = applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name: input.name, + }); + const next = + accountId !== DEFAULT_ACCOUNT_ID + ? migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + }) + : namedConfig; + if (accountId === DEFAULT_ACCOUNT_ID) { + return { + ...next, + channels: { + ...next.channels, + discord: { + ...next.channels?.discord, + enabled: true, + ...(input.useEnv ? {} : input.token ? { token: input.token } : {}), + }, + }, + }; + } + return { + ...next, + channels: { + ...next.channels, + discord: { + ...next.channels?.discord, + enabled: true, + accounts: { + ...next.channels?.discord?.accounts, + [accountId]: { + ...next.channels?.discord?.accounts?.[accountId], + enabled: true, + ...(input.token ? { token: input.token } : {}), + }, + }, + }, + }, + }; + }, }; -type DiscordGroupAllowlistResolverParams = DiscordAllowFromResolverParams & { - prompter: { note: (message: string, title?: string) => Promise }; -}; - -type DiscordGroupAllowlistResolution = Array<{ - input: string; - resolved: boolean; -}>; - -type DiscordSetupWizardHandlers = { - promptAllowFrom: (params: { - cfg: OpenClawConfig; - prompter: import("../../../src/plugin-sdk-internal/setup.js").WizardPrompter; - accountId?: string; - }) => Promise; - resolveAllowFromEntries: (params: DiscordAllowFromResolverParams) => Promise< - Array<{ - input: string; - resolved: boolean; - id: string | null; - }> - >; - resolveGroupAllowlist: ( - params: DiscordGroupAllowlistResolverParams, - ) => Promise; -}; - -export function createDiscordSetupWizardBase( - handlers: DiscordSetupWizardHandlers, -): ChannelSetupWizard { +export function createDiscordSetupWizardProxy( + loadWizard: () => Promise<{ discordSetupWizard: ChannelSetupWizard }>, +) { const discordDmPolicy: ChannelSetupDmPolicy = { label: "Discord", channel, @@ -134,7 +154,13 @@ export function createDiscordSetupWizardBase( channel, dmPolicy: policy, }), - promptAllowFrom: handlers.promptAllowFrom, + promptAllowFrom: async ({ cfg, prompter, accountId }) => { + const wizard = (await loadWizard()).discordSetupWizard; + if (!wizard.dmPolicy?.promptAllowFrom) { + return cfg; + } + return await wizard.dmPolicy.promptAllowFrom({ cfg, prompter, accountId }); + }, }; return { @@ -212,22 +238,44 @@ export function createDiscordSetupWizardBase( accountId, patch: { groupPolicy: policy }, }), - resolveAllowlist: async (params: DiscordGroupAllowlistResolverParams) => { + resolveAllowlist: async ({ + cfg, + accountId, + credentialValues, + entries, + prompter, + }: { + cfg: OpenClawConfig; + accountId: string; + credentialValues: { token?: string }; + entries: string[]; + prompter: { note: (message: string, title?: string) => Promise }; + }) => { + const wizard = (await loadWizard()).discordSetupWizard; + if (!wizard.groupAccess?.resolveAllowlist) { + return entries.map((input) => ({ input, resolved: false })); + } try { - return await handlers.resolveGroupAllowlist(params); + return await wizard.groupAccess.resolveAllowlist({ + cfg, + accountId, + credentialValues, + entries, + prompter, + }); } catch (error) { await noteChannelLookupFailure({ - prompter: params.prompter, + prompter, label: "Discord channels", error, }); await noteChannelLookupSummary({ - prompter: params.prompter, + prompter, label: "Discord channels", resolvedSections: [], - unresolved: params.entries, + unresolved: entries, }); - return params.entries.map((input) => ({ input, resolved: false })); + return entries.map((input) => ({ input, resolved: false })); } }, applyAllowlist: ({ @@ -257,7 +305,28 @@ export function createDiscordSetupWizardBase( invalidWithoutCredentialNote: "Bot token missing; use numeric user ids (or mention form) only.", parseId: parseDiscordAllowFromId, - resolveEntries: handlers.resolveAllowFromEntries, + resolveEntries: async ({ + cfg, + accountId, + credentialValues, + entries, + }: { + cfg: OpenClawConfig; + accountId: string; + credentialValues: { token?: string }; + entries: string[]; + }) => { + const wizard = (await loadWizard()).discordSetupWizard; + if (!wizard.allowFrom) { + return entries.map((input) => ({ input, resolved: false, id: null })); + } + return await wizard.allowFrom.resolveEntries({ + cfg, + accountId, + credentialValues, + entries, + }); + }, apply: async ({ cfg, accountId, @@ -278,42 +347,3 @@ export function createDiscordSetupWizardBase( disable: (cfg: OpenClawConfig) => setSetupChannelEnabled(cfg, channel, false), } satisfies ChannelSetupWizard; } - -export function createDiscordSetupWizardProxy( - loadWizard: () => Promise<{ discordSetupWizard: ChannelSetupWizard }>, -) { - return createDiscordSetupWizardBase({ - promptAllowFrom: async ({ cfg, prompter, accountId }) => { - const wizard = (await loadWizard()).discordSetupWizard; - if (!wizard.dmPolicy?.promptAllowFrom) { - return cfg; - } - return await wizard.dmPolicy.promptAllowFrom({ cfg, prompter, accountId }); - }, - resolveAllowFromEntries: async ({ cfg, accountId, credentialValues, entries }) => { - const wizard = (await loadWizard()).discordSetupWizard; - if (!wizard.allowFrom) { - return entries.map((input) => ({ input, resolved: false, id: null })); - } - return await wizard.allowFrom.resolveEntries({ - cfg, - accountId, - credentialValues, - entries, - }); - }, - resolveGroupAllowlist: async ({ cfg, accountId, credentialValues, entries, prompter }) => { - const wizard = (await loadWizard()).discordSetupWizard; - if (!wizard.groupAccess?.resolveAllowlist) { - return entries.map((input) => ({ input, resolved: false })); - } - return (await wizard.groupAccess.resolveAllowlist({ - cfg, - accountId, - credentialValues, - entries, - prompter, - })) as DiscordGroupAllowlistResolution; - }, - }); -} diff --git a/extensions/discord/src/setup-surface.ts b/extensions/discord/src/setup-surface.ts index 5f785db6f01..da87bfd77d0 100644 --- a/extensions/discord/src/setup-surface.ts +++ b/extensions/discord/src/setup-surface.ts @@ -1,14 +1,24 @@ import { + DEFAULT_ACCOUNT_ID, + formatDocsLink, noteChannelLookupFailure, noteChannelLookupSummary, type OpenClawConfig, + parseMentionOrPrefixedId, + patchChannelConfigForAccount, promptLegacyChannelAllowFrom, resolveSetupAccountId, + setLegacyChannelDmPolicyWithAllowFrom, + setSetupChannelEnabled, type WizardPrompter, -} from "../../../src/plugin-sdk-internal/setup.js"; -import { type ChannelSetupWizard } from "../../../src/plugin-sdk-internal/setup.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; -import { resolveDefaultDiscordAccountId, resolveDiscordAccount } from "./accounts.js"; +} from "openclaw/plugin-sdk/setup"; +import { type ChannelSetupDmPolicy, type ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { inspectDiscordAccount } from "./account-inspect.js"; +import { + listDiscordAccountIds, + resolveDefaultDiscordAccountId, + resolveDiscordAccount, +} from "./accounts.js"; import { normalizeDiscordSlug } from "./monitor/allow-list.js"; import { resolveDiscordChannelAllowlist, @@ -16,7 +26,6 @@ import { } from "./resolve-channels.js"; import { resolveDiscordUserAllowlist } from "./resolve-users.js"; import { - createDiscordSetupWizardBase, discordSetupAdapter, DISCORD_TOKEN_HELP_LINES, parseDiscordAllowFromId, @@ -82,62 +91,186 @@ async function promptDiscordAllowFrom(params: { }); } -export const discordSetupWizard: ChannelSetupWizard = createDiscordSetupWizardBase({ - promptAllowFrom: promptDiscordAllowFrom, - resolveAllowFromEntries: async ({ cfg, accountId, credentialValues, entries }) => - await resolveDiscordAllowFromEntries({ - token: - resolveDiscordAccount({ cfg, accountId }).token || - (typeof credentialValues.token === "string" ? credentialValues.token : ""), - entries, +const discordDmPolicy: ChannelSetupDmPolicy = { + label: "Discord", + channel, + policyKey: "channels.discord.dmPolicy", + allowFromKey: "channels.discord.allowFrom", + getCurrent: (cfg) => + cfg.channels?.discord?.dmPolicy ?? cfg.channels?.discord?.dm?.policy ?? "pairing", + setPolicy: (cfg, policy) => + setLegacyChannelDmPolicyWithAllowFrom({ + cfg, + channel, + dmPolicy: policy, }), - resolveGroupAllowlist: async ({ cfg, accountId, credentialValues, entries, prompter }) => { - const token = - resolveDiscordAccount({ cfg, accountId }).token || - (typeof credentialValues.token === "string" ? credentialValues.token : ""); - let resolved: DiscordChannelResolution[] = entries.map((input) => ({ - input, - resolved: false, - })); - if (!token || entries.length === 0) { - return resolved; - } - try { - resolved = await resolveDiscordChannelAllowlist({ - token, - entries, - }); - const resolvedChannels = resolved.filter((entry) => entry.resolved && entry.channelId); - const resolvedGuilds = resolved.filter( - (entry) => entry.resolved && entry.guildId && !entry.channelId, - ); - const unresolved = resolved.filter((entry) => !entry.resolved).map((entry) => entry.input); - await noteChannelLookupSummary({ - prompter, - label: "Discord channels", - resolvedSections: [ - { - title: "Resolved channels", - values: resolvedChannels - .map((entry) => entry.channelId) - .filter((value): value is string => Boolean(value)), - }, - { - title: "Resolved guilds", - values: resolvedGuilds - .map((entry) => entry.guildId) - .filter((value): value is string => Boolean(value)), - }, - ], - unresolved, - }); - } catch (error) { - await noteChannelLookupFailure({ - prompter, - label: "Discord channels", - error, - }); - } - return resolved; + promptAllowFrom: promptDiscordAllowFrom, +}; + +export const discordSetupWizard: ChannelSetupWizard = { + channel, + status: { + configuredLabel: "configured", + unconfiguredLabel: "needs token", + configuredHint: "configured", + unconfiguredHint: "needs token", + configuredScore: 2, + unconfiguredScore: 1, + resolveConfigured: ({ cfg }) => + listDiscordAccountIds(cfg).some( + (accountId) => inspectDiscordAccount({ cfg, accountId }).configured, + ), }, -}); + credentials: [ + { + inputKey: "token", + providerHint: channel, + credentialLabel: "Discord bot token", + preferredEnvVar: "DISCORD_BOT_TOKEN", + helpTitle: "Discord bot token", + helpLines: DISCORD_TOKEN_HELP_LINES, + envPrompt: "DISCORD_BOT_TOKEN detected. Use env var?", + keepPrompt: "Discord token already configured. Keep it?", + inputPrompt: "Enter Discord bot token", + allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID, + inspect: ({ cfg, accountId }) => { + const account = inspectDiscordAccount({ cfg, accountId }); + return { + accountConfigured: account.configured, + hasConfiguredValue: account.tokenStatus !== "missing", + resolvedValue: account.token?.trim() || undefined, + envValue: + accountId === DEFAULT_ACCOUNT_ID + ? process.env.DISCORD_BOT_TOKEN?.trim() || undefined + : undefined, + }; + }, + }, + ], + groupAccess: { + label: "Discord channels", + placeholder: "My Server/#general, guildId/channelId, #support", + currentPolicy: ({ cfg, accountId }) => + resolveDiscordAccount({ cfg, accountId }).config.groupPolicy ?? "allowlist", + currentEntries: ({ cfg, accountId }) => + Object.entries(resolveDiscordAccount({ cfg, accountId }).config.guilds ?? {}).flatMap( + ([guildKey, value]) => { + const channels = value?.channels ?? {}; + const channelKeys = Object.keys(channels); + if (channelKeys.length === 0) { + const input = /^\d+$/.test(guildKey) ? `guild:${guildKey}` : guildKey; + return [input]; + } + return channelKeys.map((channelKey) => `${guildKey}/${channelKey}`); + }, + ), + updatePrompt: ({ cfg, accountId }) => + Boolean(resolveDiscordAccount({ cfg, accountId }).config.guilds), + setPolicy: ({ cfg, accountId, policy }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { groupPolicy: policy }, + }), + resolveAllowlist: async ({ cfg, accountId, credentialValues, entries, prompter }) => { + const token = + resolveDiscordAccount({ cfg, accountId }).token || + (typeof credentialValues.token === "string" ? credentialValues.token : ""); + let resolved: DiscordChannelResolution[] = entries.map((input) => ({ + input, + resolved: false, + })); + if (!token || entries.length === 0) { + return resolved; + } + try { + resolved = await resolveDiscordChannelAllowlist({ + token, + entries, + }); + const resolvedChannels = resolved.filter((entry) => entry.resolved && entry.channelId); + const resolvedGuilds = resolved.filter( + (entry) => entry.resolved && entry.guildId && !entry.channelId, + ); + const unresolved = resolved.filter((entry) => !entry.resolved).map((entry) => entry.input); + await noteChannelLookupSummary({ + prompter, + label: "Discord channels", + resolvedSections: [ + { + title: "Resolved channels", + values: resolvedChannels + .map((entry) => entry.channelId) + .filter((value): value is string => Boolean(value)), + }, + { + title: "Resolved guilds", + values: resolvedGuilds + .map((entry) => entry.guildId) + .filter((value): value is string => Boolean(value)), + }, + ], + unresolved, + }); + } catch (error) { + await noteChannelLookupFailure({ + prompter, + label: "Discord channels", + error, + }); + } + return resolved; + }, + applyAllowlist: ({ cfg, accountId, resolved }) => { + const allowlistEntries: Array<{ guildKey: string; channelKey?: string }> = []; + for (const entry of resolved as DiscordChannelResolution[]) { + const guildKey = + entry.guildId ?? + (entry.guildName ? normalizeDiscordSlug(entry.guildName) : undefined) ?? + "*"; + const channelKey = + entry.channelId ?? + (entry.channelName ? normalizeDiscordSlug(entry.channelName) : undefined); + if (!channelKey && guildKey === "*") { + continue; + } + allowlistEntries.push({ guildKey, ...(channelKey ? { channelKey } : {}) }); + } + return setDiscordGuildChannelAllowlist(cfg, accountId, allowlistEntries); + }, + }, + allowFrom: { + credentialInputKey: "token", + helpTitle: "Discord allowlist", + helpLines: [ + "Allowlist Discord DMs by username (we resolve to user ids).", + "Examples:", + "- 123456789012345678", + "- @alice", + "- alice#1234", + "Multiple entries: comma-separated.", + `Docs: ${formatDocsLink("/discord", "discord")}`, + ], + message: "Discord allowFrom (usernames or ids)", + placeholder: "@alice, 123456789012345678", + invalidWithoutCredentialNote: "Bot token missing; use numeric user ids (or mention form) only.", + parseId: parseDiscordAllowFromId, + resolveEntries: async ({ cfg, accountId, credentialValues, entries }) => + await resolveDiscordAllowFromEntries({ + token: + resolveDiscordAccount({ cfg, accountId }).token || + (typeof credentialValues.token === "string" ? credentialValues.token : ""), + entries, + }), + apply: async ({ cfg, accountId, allowFrom }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { dmPolicy: "allowlist", allowFrom }, + }), + }, + dmPolicy: discordDmPolicy, + disable: (cfg) => setSetupChannelEnabled(cfg, channel, false), +}; diff --git a/extensions/discord/src/shared-interactive.ts b/extensions/discord/src/shared-interactive.ts index d99f964f5c9..bb8bf1dac70 100644 --- a/extensions/discord/src/shared-interactive.ts +++ b/extensions/discord/src/shared-interactive.ts @@ -1,5 +1,5 @@ -import { reduceInteractiveReply } from "../../../src/channels/plugins/outbound/interactive.js"; -import type { InteractiveButtonStyle, InteractiveReply } from "../../../src/interactive/payload.js"; +import { reduceInteractiveReply } from "openclaw/plugin-sdk/channel-runtime"; +import type { InteractiveButtonStyle, InteractiveReply } from "openclaw/plugin-sdk/channel-runtime"; import type { DiscordComponentButtonStyle, DiscordComponentMessageSpec } from "./components.js"; function resolveDiscordInteractiveButtonStyle( diff --git a/extensions/discord/src/status-issues.ts b/extensions/discord/src/status-issues.ts index baf2551c0f8..4fa26fd011b 100644 --- a/extensions/discord/src/status-issues.ts +++ b/extensions/discord/src/status-issues.ts @@ -3,11 +3,11 @@ import { asString, isRecord, resolveEnabledConfiguredAccountId, -} from "../../../src/channels/plugins/status-issues/shared.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelAccountSnapshot, ChannelStatusIssue, -} from "../../../src/channels/plugins/types.js"; +} from "openclaw/plugin-sdk/channel-runtime"; type DiscordIntentSummary = { messageContent?: "enabled" | "limited" | "disabled"; diff --git a/extensions/discord/src/subagent-hooks.ts b/extensions/discord/src/subagent-hooks.ts index fa45eadd7c2..c9ba7b97984 100644 --- a/extensions/discord/src/subagent-hooks.ts +++ b/extensions/discord/src/subagent-hooks.ts @@ -1,4 +1,4 @@ -import type { OpenClawPluginApi } from "../../../src/plugin-sdk-internal/core.js"; +import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core"; import { resolveDiscordAccount } from "./accounts.js"; import { autoBindSpawnedDiscordSubagent, diff --git a/extensions/discord/src/targets.ts b/extensions/discord/src/targets.ts index 198660dceff..3660f75921e 100644 --- a/extensions/discord/src/targets.ts +++ b/extensions/discord/src/targets.ts @@ -1,4 +1,4 @@ -import type { DirectoryConfigParams } from "../../../src/channels/plugins/directory-config.js"; +import type { DirectoryConfigParams } from "openclaw/plugin-sdk/channel-runtime"; import { buildMessagingTarget, parseMentionPrefixOrAtUserTarget, @@ -6,7 +6,7 @@ import { type MessagingTarget, type MessagingTargetKind, type MessagingTargetParseOptions, -} from "../../../src/channels/targets.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import { rememberDiscordDirectoryUser } from "./directory-cache.js"; import { listDiscordDirectoryPeersLive } from "./directory-live.js"; diff --git a/extensions/discord/src/token.ts b/extensions/discord/src/token.ts index aff802f3ded..2a979ca4b3b 100644 --- a/extensions/discord/src/token.ts +++ b/extensions/discord/src/token.ts @@ -1,7 +1,7 @@ -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 { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js"; +import type { BaseTokenResolution } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/config-runtime"; +import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing"; export type DiscordTokenSource = "env" | "config" | "none"; diff --git a/extensions/discord/src/ui.ts b/extensions/discord/src/ui.ts index ed4cc9d4fa6..50f818f1471 100644 --- a/extensions/discord/src/ui.ts +++ b/extensions/discord/src/ui.ts @@ -1,5 +1,5 @@ import { Container } from "@buape/carbon"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { inspectDiscordAccount } from "./account-inspect.js"; const DEFAULT_DISCORD_ACCENT_COLOR = "#5865F2"; diff --git a/extensions/discord/src/voice-message.ts b/extensions/discord/src/voice-message.ts index 6f77ebc7bd9..ea014f5f59e 100644 --- a/extensions/discord/src/voice-message.ts +++ b/extensions/discord/src/voice-message.ts @@ -14,15 +14,15 @@ import crypto from "node:crypto"; import fs from "node:fs/promises"; import path from "node:path"; import { RateLimitError, type RequestClient } from "@buape/carbon"; -import type { RetryRunner } from "../../../src/infra/retry-policy.js"; -import { resolvePreferredOpenClawTmpDir } from "../../../src/infra/tmp-openclaw-dir.js"; +import type { RetryRunner } from "openclaw/plugin-sdk/infra-runtime"; +import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/infra-runtime"; import { parseFfprobeCodecAndSampleRate, runFfmpeg, runFfprobe, -} from "../../../src/media/ffmpeg-exec.js"; -import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS } from "../../../src/media/ffmpeg-limits.js"; -import { unlinkIfExists } from "../../../src/media/temp-files.js"; +} from "openclaw/plugin-sdk/media-runtime"; +import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS } from "openclaw/plugin-sdk/media-runtime"; +import { unlinkIfExists } from "openclaw/plugin-sdk/media-runtime"; const DISCORD_VOICE_MESSAGE_FLAG = 1 << 13; const SUPPRESS_NOTIFICATIONS_FLAG = 1 << 12; diff --git a/extensions/discord/src/voice/command.ts b/extensions/discord/src/voice/command.ts index 26ef7b9bbe5..3ed7aa2ccdb 100644 --- a/extensions/discord/src/voice/command.ts +++ b/extensions/discord/src/voice/command.ts @@ -10,10 +10,10 @@ import { ChannelType as DiscordChannelType, type APIApplicationCommandChannelOption, } from "discord-api-types/v10"; -import { resolveCommandAuthorizedFromAuthorizers } from "../../../../src/channels/command-gating.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; -import type { DiscordAccountConfig } from "../../../../src/config/types.js"; +import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; +import type { DiscordAccountConfig } from "openclaw/plugin-sdk/config-runtime"; import { formatMention } from "../mentions.js"; import { isDiscordGroupAllowedByPolicy, diff --git a/extensions/discord/src/voice/manager.ts b/extensions/discord/src/voice/manager.ts index a9f8d0fd721..c2fbcbfc686 100644 --- a/extensions/discord/src/voice/manager.ts +++ b/extensions/discord/src/voice/manager.ts @@ -16,20 +16,30 @@ import { type AudioPlayer, type VoiceConnection, } from "@discordjs/voice"; -import { resolveAgentDir } from "../../../../src/agents/agent-scope.js"; -import { agentCommandFromIngress } from "../../../../src/commands/agent.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; -import type { DiscordAccountConfig, TtsConfig } from "../../../../src/config/types.js"; -import { logVerbose, shouldLogVerbose } from "../../../../src/globals.js"; -import { formatErrorMessage } from "../../../../src/infra/errors.js"; -import { resolvePreferredOpenClawTmpDir } from "../../../../src/infra/tmp-openclaw-dir.js"; -import { createSubsystemLogger } from "../../../../src/logging/subsystem.js"; -import { transcribeAudioFile } from "../../../../src/media-understanding/runtime.js"; -import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; -import { parseTtsDirectives } from "../../../../src/tts/tts-core.js"; -import { resolveTtsConfig, textToSpeech, type ResolvedTtsConfig } from "../../../../src/tts/tts.js"; +import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime"; +import { agentCommandFromIngress } from "openclaw/plugin-sdk/agent-runtime"; +import { + resolveTtsConfig, + textToSpeech, + type ResolvedTtsConfig, +} from "openclaw/plugin-sdk/agent-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; +import type { DiscordAccountConfig, TtsConfig } from "openclaw/plugin-sdk/config-runtime"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/infra-runtime"; +import { + buildProviderRegistry, + createMediaAttachmentCache, + normalizeMediaAttachments, + runCapability, +} from "openclaw/plugin-sdk/media-runtime"; +import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { parseTtsDirectives } from "openclaw/plugin-sdk/speech"; import { formatMention } from "../mentions.js"; import { resolveDiscordOwnerAccess } from "../monitor/allow-list.js"; import { formatDiscordUserTag } from "../monitor/format.js"; @@ -230,13 +240,33 @@ async function transcribeAudio(params: { agentId: string; filePath: string; }): Promise { - const result = await transcribeAudioFile({ - cfg: params.cfg, - filePath: params.filePath, - mime: "audio/wav", - agentDir: resolveAgentDir(params.cfg, params.agentId), - }); - return result.text?.trim() || undefined; + const ctx: MsgContext = { + MediaPath: params.filePath, + MediaType: "audio/wav", + }; + const attachments = normalizeMediaAttachments(ctx); + if (attachments.length === 0) { + return undefined; + } + const cache = createMediaAttachmentCache(attachments); + const providerRegistry = buildProviderRegistry(); + try { + const result = await runCapability({ + capability: "audio", + cfg: params.cfg, + ctx, + attachments: cache, + media: attachments, + agentDir: resolveAgentDir(params.cfg, params.agentId), + providerRegistry, + config: params.cfg.tools?.media?.audio, + }); + const output = result.outputs.find((entry) => entry.kind === "audio.transcription"); + const text = output?.text?.trim(); + return text || undefined; + } finally { + await cache.cleanup(); + } } export class DiscordVoiceManager { diff --git a/extensions/elevenlabs/index.ts b/extensions/elevenlabs/index.ts index 49d792df20f..034c56815c3 100644 --- a/extensions/elevenlabs/index.ts +++ b/extensions/elevenlabs/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { buildElevenLabsSpeechProvider } from "../../src/tts/providers/elevenlabs.js"; +import { buildElevenLabsSpeechProvider } from "openclaw/plugin-sdk/speech"; const elevenLabsPlugin = { id: "elevenlabs", diff --git a/extensions/feishu/src/bot.ts b/extensions/feishu/src/bot.ts index 728bb9a8ffc..6181d32f4af 100644 --- a/extensions/feishu/src/bot.ts +++ b/extensions/feishu/src/bot.ts @@ -1,3 +1,8 @@ +import { + ensureConfiguredAcpRouteReady, + resolveConfiguredAcpRoute, +} from "openclaw/plugin-sdk/conversation-runtime"; +import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime"; import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk/feishu"; import { buildAgentMediaPayload, @@ -14,13 +19,8 @@ import { resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce, } from "openclaw/plugin-sdk/feishu"; -import { - ensureConfiguredAcpRouteReady, - resolveConfiguredAcpRoute, -} from "../../../src/acp/persistent-bindings.route.js"; -import { getSessionBindingService } from "../../../src/infra/outbound/session-binding-service.js"; -import { deriveLastRoutePolicy } from "../../../src/routing/resolve-route.js"; -import { resolveAgentIdFromSessionKey } from "../../../src/routing/session-key.js"; +import { deriveLastRoutePolicy } from "openclaw/plugin-sdk/routing"; +import { resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; import { resolveFeishuAccount } from "./accounts.js"; import { createFeishuClient } from "./client.js"; import { buildFeishuConversationId } from "./conversation-id.js"; diff --git a/extensions/feishu/src/media.ts b/extensions/feishu/src/media.ts index b7888b7069e..617bc504756 100644 --- a/extensions/feishu/src/media.ts +++ b/extensions/feishu/src/media.ts @@ -2,7 +2,7 @@ import fs from "fs"; import path from "path"; import { Readable } from "stream"; import { withTempDownloadPath, type ClawdbotConfig } from "openclaw/plugin-sdk/feishu"; -import { mediaKindFromMime } from "../../../src/media/constants.js"; +import { mediaKindFromMime } from "openclaw/plugin-sdk/media-runtime"; import { resolveFeishuAccount } from "./accounts.js"; import { createFeishuClient } from "./client.js"; import { normalizeFeishuExternalKey } from "./external-keys.js"; diff --git a/extensions/feishu/src/thread-bindings.ts b/extensions/feishu/src/thread-bindings.ts index b2ab72467c3..cfae8fb2058 100644 --- a/extensions/feishu/src/thread-bindings.ts +++ b/extensions/feishu/src/thread-bindings.ts @@ -1,20 +1,17 @@ -import { resolveThreadBindingConversationIdFromBindingId } from "../../../src/channels/thread-binding-id.js"; +import { resolveThreadBindingConversationIdFromBindingId } from "openclaw/plugin-sdk/channel-runtime"; import { resolveThreadBindingIdleTimeoutMsForChannel, resolveThreadBindingMaxAgeMsForChannel, -} from "../../../src/channels/thread-bindings-policy.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { registerSessionBindingAdapter, unregisterSessionBindingAdapter, type BindingTargetKind, type SessionBindingRecord, -} from "../../../src/infra/outbound/session-binding-service.js"; -import { - normalizeAccountId, - resolveAgentIdFromSessionKey, -} from "../../../src/routing/session-key.js"; -import { resolveGlobalSingleton } from "../../../src/shared/global-singleton.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing"; +import { resolveGlobalSingleton } from "openclaw/plugin-sdk/text-runtime"; type FeishuBindingTargetKind = "subagent" | "acp"; diff --git a/extensions/firecrawl/index.ts b/extensions/firecrawl/index.ts index 42bd1a3252f..6b38ac6dc75 100644 --- a/extensions/firecrawl/index.ts +++ b/extensions/firecrawl/index.ts @@ -1,6 +1,8 @@ -import type { AnyAgentTool } from "../../src/agents/tools/common.js"; -import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js"; -import type { OpenClawPluginApi } from "../../src/plugins/types.js"; +import { + emptyPluginConfigSchema, + type AnyAgentTool, + type OpenClawPluginApi, +} from "openclaw/plugin-sdk/core"; import { createFirecrawlScrapeTool } from "./src/firecrawl-scrape-tool.js"; import { createFirecrawlWebSearchProvider } from "./src/firecrawl-search-provider.js"; import { createFirecrawlSearchTool } from "./src/firecrawl-search-tool.js"; diff --git a/extensions/firecrawl/src/config.ts b/extensions/firecrawl/src/config.ts index 808b81891f1..5558c0dce0a 100644 --- a/extensions/firecrawl/src/config.ts +++ b/extensions/firecrawl/src/config.ts @@ -1,6 +1,6 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { normalizeResolvedSecretInputString } from "../../../src/config/types.secrets.js"; -import { normalizeSecretInput } from "../../../src/utils/normalize-secret-input.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeSecretInput } from "openclaw/plugin-sdk/provider-auth"; export const DEFAULT_FIRECRAWL_BASE_URL = "https://api.firecrawl.dev"; export const DEFAULT_FIRECRAWL_SEARCH_TIMEOUT_SECONDS = 30; diff --git a/extensions/firecrawl/src/firecrawl-client.ts b/extensions/firecrawl/src/firecrawl-client.ts index 2929f2f9dde..18500d81c14 100644 --- a/extensions/firecrawl/src/firecrawl-client.ts +++ b/extensions/firecrawl/src/firecrawl-client.ts @@ -1,5 +1,6 @@ -import { markdownToText, truncateText } from "../../../src/agents/tools/web-fetch-utils.js"; -import { withTrustedWebToolsEndpoint } from "../../../src/agents/tools/web-guarded-fetch.js"; +import { markdownToText, truncateText } from "openclaw/plugin-sdk/agent-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { withTrustedWebToolsEndpoint } from "openclaw/plugin-sdk/provider-web-search"; import { DEFAULT_CACHE_TTL_MINUTES, normalizeCacheKey, @@ -7,9 +8,8 @@ import { readResponseText, resolveCacheTtlMs, writeCache, -} from "../../../src/agents/tools/web-shared.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { wrapExternalContent, wrapWebContent } from "../../../src/security/external-content.js"; +} from "openclaw/plugin-sdk/provider-web-search"; +import { wrapExternalContent, wrapWebContent } from "openclaw/plugin-sdk/security-runtime"; import { resolveFirecrawlApiKey, resolveFirecrawlBaseUrl, diff --git a/extensions/firecrawl/src/firecrawl-scrape-tool.ts b/extensions/firecrawl/src/firecrawl-scrape-tool.ts index 509b3d5fbd6..70f0691d3d7 100644 --- a/extensions/firecrawl/src/firecrawl-scrape-tool.ts +++ b/extensions/firecrawl/src/firecrawl-scrape-tool.ts @@ -1,7 +1,7 @@ import { Type } from "@sinclair/typebox"; -import { optionalStringEnum } from "../../../src/agents/schema/typebox.js"; -import { jsonResult, readNumberParam, readStringParam } from "../../../src/agents/tools/common.js"; -import type { OpenClawPluginApi } from "../../../src/plugins/types.js"; +import { optionalStringEnum } from "openclaw/plugin-sdk/agent-runtime"; +import { jsonResult, readNumberParam, readStringParam } from "openclaw/plugin-sdk/agent-runtime"; +import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime"; import { runFirecrawlScrape } from "./firecrawl-client.js"; const FirecrawlScrapeToolSchema = Type.Object( diff --git a/extensions/firecrawl/src/firecrawl-search-provider.ts b/extensions/firecrawl/src/firecrawl-search-provider.ts index 60489e9618e..0940aedb74d 100644 --- a/extensions/firecrawl/src/firecrawl-search-provider.ts +++ b/extensions/firecrawl/src/firecrawl-search-provider.ts @@ -1,5 +1,5 @@ import { Type } from "@sinclair/typebox"; -import type { WebSearchProviderPlugin } from "../../../src/plugins/types.js"; +import type { WebSearchProviderPlugin } from "openclaw/plugin-sdk/plugin-runtime"; import { runFirecrawlSearch } from "./firecrawl-client.js"; const GenericFirecrawlSearchSchema = Type.Object( diff --git a/extensions/firecrawl/src/firecrawl-search-tool.ts b/extensions/firecrawl/src/firecrawl-search-tool.ts index f2f133fd7ec..9a1201ec6e0 100644 --- a/extensions/firecrawl/src/firecrawl-search-tool.ts +++ b/extensions/firecrawl/src/firecrawl-search-tool.ts @@ -4,8 +4,8 @@ import { readNumberParam, readStringArrayParam, readStringParam, -} from "../../../src/agents/tools/common.js"; -import type { OpenClawPluginApi } from "../../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime"; import { runFirecrawlSearch } from "./firecrawl-client.js"; const FirecrawlSearchToolSchema = Type.Object( diff --git a/extensions/github-copilot/index.ts b/extensions/github-copilot/index.ts index 8dadad31903..45f964c60f0 100644 --- a/extensions/github-copilot/index.ts +++ b/extensions/github-copilot/index.ts @@ -5,11 +5,13 @@ import { type ProviderResolveDynamicModelContext, type ProviderRuntimeModel, } from "openclaw/plugin-sdk/core"; -import { listProfilesForProvider } from "../../src/agents/auth-profiles/profiles.js"; -import { ensureAuthProfileStore } from "../../src/agents/auth-profiles/store.js"; -import { normalizeModelCompat } from "../../src/agents/model-compat.js"; -import { coerceSecretRef } from "../../src/config/types.secrets.js"; -import { githubCopilotLoginCommand } from "../../src/providers/github-copilot-auth.js"; +import { + coerceSecretRef, + ensureAuthProfileStore, + githubCopilotLoginCommand, + listProfilesForProvider, +} from "openclaw/plugin-sdk/provider-auth"; +import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-models"; import { DEFAULT_COPILOT_API_BASE_URL, resolveCopilotApiToken } from "./token.js"; import { fetchCopilotUsage } from "./usage.js"; diff --git a/extensions/github-copilot/token.ts b/extensions/github-copilot/token.ts index afb1eb03b61..f743cf8bb88 100644 --- a/extensions/github-copilot/token.ts +++ b/extensions/github-copilot/token.ts @@ -1,6 +1,6 @@ import path from "node:path"; -import { resolveStateDir } from "../../src/config/paths.js"; -import { loadJsonFile, saveJsonFile } from "../../src/infra/json-file.js"; +import { loadJsonFile, saveJsonFile } from "openclaw/plugin-sdk/json-store"; +import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; const COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token"; diff --git a/extensions/github-copilot/usage.ts b/extensions/github-copilot/usage.ts index 9035027890c..1e13717c9ea 100644 --- a/extensions/github-copilot/usage.ts +++ b/extensions/github-copilot/usage.ts @@ -1,9 +1,11 @@ import { buildUsageHttpErrorSnapshot, fetchJson, -} from "../../src/infra/provider-usage.fetch.shared.js"; -import { clampPercent, PROVIDER_LABELS } from "../../src/infra/provider-usage.shared.js"; -import type { ProviderUsageSnapshot, UsageWindow } from "../../src/infra/provider-usage.types.js"; + clampPercent, + PROVIDER_LABELS, + type ProviderUsageSnapshot, + type UsageWindow, +} from "openclaw/plugin-sdk/provider-usage"; type CopilotUsageResponse = { quota_snapshots?: { diff --git a/extensions/google/gemini-cli-provider.ts b/extensions/google/gemini-cli-provider.ts index e235a0dfebc..6db7561a10b 100644 --- a/extensions/google/gemini-cli-provider.ts +++ b/extensions/google/gemini-cli-provider.ts @@ -1,10 +1,10 @@ import { buildOauthProviderAuthResult } from "openclaw/plugin-sdk/core"; -import { fetchGeminiUsage } from "../../src/infra/provider-usage.fetch.js"; import type { OpenClawPluginApi, ProviderAuthContext, ProviderFetchUsageSnapshotContext, -} from "../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/core"; +import { fetchGeminiUsage } from "openclaw/plugin-sdk/provider-usage"; import { loginGeminiCliOAuth } from "./oauth.js"; import { isModernGoogleModel, resolveGoogle31ForwardCompatModel } from "./provider-models.js"; diff --git a/extensions/google/index.ts b/extensions/google/index.ts index 6389dd25e48..d310d8183a9 100644 --- a/extensions/google/index.ts +++ b/extensions/google/index.ts @@ -1,15 +1,14 @@ +import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { + GOOGLE_GEMINI_DEFAULT_MODEL, + applyGoogleGeminiModelDefault, +} from "openclaw/plugin-sdk/provider-models"; import { createPluginBackedWebSearchProvider, getScopedCredentialValue, setScopedCredentialValue, -} from "../../src/agents/tools/web-search-plugin-factory.js"; -import { - GOOGLE_GEMINI_DEFAULT_MODEL, - applyGoogleGeminiModelDefault, -} from "../../src/commands/google-gemini-model-default.js"; -import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import type { OpenClawPluginApi } from "../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/provider-web-search"; import { registerGoogleGeminiCliProvider } from "./gemini-cli-provider.js"; import { googleMediaUnderstandingProvider } from "./media-understanding-provider.js"; import { isModernGoogleModel, resolveGoogle31ForwardCompatModel } from "./provider-models.js"; diff --git a/extensions/google/oauth.flow.ts b/extensions/google/oauth.flow.ts index 00cab07dc68..1ac7f260723 100644 --- a/extensions/google/oauth.flow.ts +++ b/extensions/google/oauth.flow.ts @@ -1,6 +1,6 @@ import { createHash, randomBytes } from "node:crypto"; import { createServer } from "node:http"; -import { isWSL2Sync } from "../../src/infra/wsl.js"; +import { isWSL2Sync } from "openclaw/plugin-sdk/infra-runtime"; import { resolveOAuthClientConfig } from "./oauth.credentials.js"; import { AUTH_URL, REDIRECT_URI, SCOPES } from "./oauth.shared.js"; diff --git a/extensions/google/oauth.http.ts b/extensions/google/oauth.http.ts index 6c07c447143..3dcbd086b1c 100644 --- a/extensions/google/oauth.http.ts +++ b/extensions/google/oauth.http.ts @@ -1,4 +1,4 @@ -import { fetchWithSsrFGuard } from "../../src/infra/net/fetch-guard.js"; +import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/infra-runtime"; import { DEFAULT_FETCH_TIMEOUT_MS } from "./oauth.shared.js"; export async function fetchWithTimeout( diff --git a/extensions/google/provider-models.ts b/extensions/google/provider-models.ts index 0a086780b1a..eddda4a9f9a 100644 --- a/extensions/google/provider-models.ts +++ b/extensions/google/provider-models.ts @@ -1,8 +1,8 @@ -import { normalizeModelCompat } from "../../src/agents/model-compat.js"; import type { ProviderResolveDynamicModelContext, ProviderRuntimeModel, -} from "../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/core"; +import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-models"; const GEMINI_3_1_PRO_PREFIX = "gemini-3.1-pro"; const GEMINI_3_1_FLASH_PREFIX = "gemini-3.1-flash"; diff --git a/extensions/huggingface/index.ts b/extensions/huggingface/index.ts index 433223bf268..c0c65f0051b 100644 --- a/extensions/huggingface/index.ts +++ b/extensions/huggingface/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyHuggingfaceConfig, HUGGINGFACE_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildHuggingfaceProvider } from "./provider-catalog.js"; diff --git a/extensions/huggingface/onboard.ts b/extensions/huggingface/onboard.ts index 22493f87f0b..40df946abe3 100644 --- a/extensions/huggingface/onboard.ts +++ b/extensions/huggingface/onboard.ts @@ -2,12 +2,12 @@ import { buildHuggingfaceModelDefinition, HUGGINGFACE_BASE_URL, HUGGINGFACE_MODEL_CATALOG, -} from "../../src/agents/huggingface-models.js"; +} from "openclaw/plugin-sdk/provider-models"; import { applyAgentDefaultModelPrimary, applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export const HUGGINGFACE_DEFAULT_MODEL_REF = "huggingface/deepseek-ai/DeepSeek-R1"; diff --git a/extensions/huggingface/provider-catalog.ts b/extensions/huggingface/provider-catalog.ts index 5dc87b751df..502a94f2a9e 100644 --- a/extensions/huggingface/provider-catalog.ts +++ b/extensions/huggingface/provider-catalog.ts @@ -1,10 +1,10 @@ import { buildHuggingfaceModelDefinition, discoverHuggingfaceModels, + type ModelProviderConfig, HUGGINGFACE_BASE_URL, HUGGINGFACE_MODEL_CATALOG, -} from "../../src/agents/huggingface-models.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +} from "openclaw/plugin-sdk/provider-models"; export async function buildHuggingfaceProvider( discoveryApiKey?: string, diff --git a/extensions/imessage/src/accounts.ts b/extensions/imessage/src/accounts.ts index 67ffb5e6865..5ee90339aa8 100644 --- a/extensions/imessage/src/accounts.ts +++ b/extensions/imessage/src/accounts.ts @@ -1,10 +1,10 @@ import { - type OpenClawConfig, createAccountListHelpers, normalizeAccountId, resolveAccountEntry, -} from "../../../src/plugin-sdk-internal/accounts.js"; -import type { IMessageAccountConfig } from "../../../src/plugin-sdk-internal/imessage.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/account-resolution"; +import type { IMessageAccountConfig } from "openclaw/plugin-sdk/imessage"; export type ResolvedIMessageAccount = { accountId: string; diff --git a/extensions/imessage/src/channel.setup.ts b/extensions/imessage/src/channel.setup.ts index 5587914a0ce..0590eba9356 100644 --- a/extensions/imessage/src/channel.setup.ts +++ b/extensions/imessage/src/channel.setup.ts @@ -1,11 +1,94 @@ -import { type ChannelPlugin } from "openclaw/plugin-sdk/imessage"; -import { type ResolvedIMessageAccount } from "./accounts.js"; +import { + buildAccountScopedDmSecurityPolicy, + collectAllowlistProviderRestrictSendersWarnings, +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { + buildChannelConfigSchema, + DEFAULT_ACCOUNT_ID, + deleteAccountFromConfigSection, + formatTrimmedAllowFromEntries, + getChatChannelMeta, + IMessageConfigSchema, + resolveIMessageConfigAllowFrom, + resolveIMessageConfigDefaultTo, + setAccountEnabledInConfigSection, + type ChannelPlugin, +} from "openclaw/plugin-sdk/imessage"; +import { + listIMessageAccountIds, + resolveDefaultIMessageAccountId, + resolveIMessageAccount, + type ResolvedIMessageAccount, +} from "./accounts.js"; +import { imessageSetupWizard } from "./plugin-shared.js"; import { imessageSetupAdapter } from "./setup-core.js"; -import { createIMessagePluginBase, imessageSetupWizard } from "./shared.js"; -export const imessageSetupPlugin: ChannelPlugin = createIMessagePluginBase( - { - setupWizard: imessageSetupWizard, - setup: imessageSetupAdapter, +export const imessageSetupPlugin: ChannelPlugin = { + id: "imessage", + meta: { + ...getChatChannelMeta("imessage"), + aliases: ["imsg"], + showConfigured: false, }, -); + setupWizard: imessageSetupWizard, + capabilities: { + chatTypes: ["direct", "group"], + media: true, + }, + reload: { configPrefixes: ["channels.imessage"] }, + configSchema: buildChannelConfigSchema(IMessageConfigSchema), + config: { + listAccountIds: (cfg) => listIMessageAccountIds(cfg), + resolveAccount: (cfg, accountId) => resolveIMessageAccount({ cfg, accountId }), + defaultAccountId: (cfg) => resolveDefaultIMessageAccountId(cfg), + setAccountEnabled: ({ cfg, accountId, enabled }) => + setAccountEnabledInConfigSection({ + cfg, + sectionKey: "imessage", + accountId, + enabled, + allowTopLevel: true, + }), + deleteAccount: ({ cfg, accountId }) => + deleteAccountFromConfigSection({ + cfg, + sectionKey: "imessage", + accountId, + clearBaseFields: ["cliPath", "dbPath", "service", "region", "name"], + }), + isConfigured: (account) => account.configured, + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: account.configured, + }), + resolveAllowFrom: ({ cfg, accountId }) => resolveIMessageConfigAllowFrom({ cfg, accountId }), + formatAllowFrom: ({ allowFrom }) => formatTrimmedAllowFromEntries(allowFrom), + resolveDefaultTo: ({ cfg, accountId }) => resolveIMessageConfigDefaultTo({ cfg, accountId }), + }, + security: { + resolveDmPolicy: ({ cfg, accountId, account }) => + buildAccountScopedDmSecurityPolicy({ + cfg, + channelKey: "imessage", + accountId, + fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID, + policy: account.config.dmPolicy, + allowFrom: account.config.allowFrom ?? [], + policyPathSuffix: "dmPolicy", + }), + collectWarnings: ({ account, cfg }) => + collectAllowlistProviderRestrictSendersWarnings({ + cfg, + providerConfigPresent: cfg.channels?.imessage !== undefined, + configuredGroupPolicy: account.config.groupPolicy, + surface: "iMessage groups", + openScope: "any member", + groupPolicyPath: "channels.imessage.groupPolicy", + groupAllowFromPath: "channels.imessage.groupAllowFrom", + mentionGated: false, + }), + }, + setup: imessageSetupAdapter, +}; diff --git a/extensions/imessage/src/channel.ts b/extensions/imessage/src/channel.ts index 95cac7d1123..5e3d48817a0 100644 --- a/extensions/imessage/src/channel.ts +++ b/extensions/imessage/src/channel.ts @@ -1,25 +1,43 @@ -import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/compat"; +import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/allowlist-config-edit"; +import { + buildAccountScopedDmSecurityPolicy, + collectAllowlistProviderRestrictSendersWarnings, +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/core"; import { + buildChannelConfigSchema, collectStatusIssuesFromLastError, DEFAULT_ACCOUNT_ID, + deleteAccountFromConfigSection, formatTrimmedAllowFromEntries, + getChatChannelMeta, + IMessageConfigSchema, looksLikeIMessageTargetId, normalizeIMessageMessagingTarget, PAIRING_APPROVED_MESSAGE, resolveChannelMediaMaxBytes, + resolveIMessageConfigAllowFrom, + resolveIMessageConfigDefaultTo, resolveIMessageGroupRequireMention, resolveIMessageGroupToolPolicy, + setAccountEnabledInConfigSection, type ChannelPlugin, } from "openclaw/plugin-sdk/imessage"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js"; -import { resolveIMessageAccount, type ResolvedIMessageAccount } from "./accounts.js"; +import { + listIMessageAccountIds, + resolveDefaultIMessageAccountId, + resolveIMessageAccount, + type ResolvedIMessageAccount, +} from "./accounts.js"; +import { imessageSetupWizard } from "./plugin-shared.js"; import { getIMessageRuntime } from "./runtime.js"; import { imessageSetupAdapter } from "./setup-core.js"; -import { createIMessagePluginBase, imessageSetupWizard } from "./shared.js"; import { normalizeIMessageHandle, parseIMessageTarget } from "./targets.js"; +const meta = getChatChannelMeta("imessage"); + type IMessageSendFn = ReturnType< typeof getIMessageRuntime >["channel"]["imessage"]["sendMessageIMessage"]; @@ -132,16 +150,55 @@ function resolveIMessageOutboundSessionRoute(params: { } export const imessagePlugin: ChannelPlugin = { - ...createIMessagePluginBase({ - setupWizard: imessageSetupWizard, - setup: imessageSetupAdapter, - }), + id: "imessage", + meta: { + ...meta, + aliases: ["imsg"], + showConfigured: false, + }, + setupWizard: imessageSetupWizard, pairing: { idLabel: "imessageSenderId", notifyApproval: async ({ id }) => { await getIMessageRuntime().channel.imessage.sendMessageIMessage(id, PAIRING_APPROVED_MESSAGE); }, }, + capabilities: { + chatTypes: ["direct", "group"], + media: true, + }, + reload: { configPrefixes: ["channels.imessage"] }, + configSchema: buildChannelConfigSchema(IMessageConfigSchema), + config: { + listAccountIds: (cfg) => listIMessageAccountIds(cfg), + resolveAccount: (cfg, accountId) => resolveIMessageAccount({ cfg, accountId }), + defaultAccountId: (cfg) => resolveDefaultIMessageAccountId(cfg), + setAccountEnabled: ({ cfg, accountId, enabled }) => + setAccountEnabledInConfigSection({ + cfg, + sectionKey: "imessage", + accountId, + enabled, + allowTopLevel: true, + }), + deleteAccount: ({ cfg, accountId }) => + deleteAccountFromConfigSection({ + cfg, + sectionKey: "imessage", + accountId, + clearBaseFields: ["cliPath", "dbPath", "service", "region", "name"], + }), + isConfigured: (account) => account.configured, + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: account.configured, + }), + resolveAllowFrom: ({ cfg, accountId }) => resolveIMessageConfigAllowFrom({ cfg, accountId }), + formatAllowFrom: ({ allowFrom }) => formatTrimmedAllowFromEntries(allowFrom), + resolveDefaultTo: ({ cfg, accountId }) => resolveIMessageConfigDefaultTo({ cfg, accountId }), + }, allowlist: { supportsScope: ({ scope }) => scope === "dm" || scope === "group" || scope === "all", readConfig: ({ cfg, accountId }) => { @@ -162,6 +219,31 @@ export const imessagePlugin: ChannelPlugin = { }), }), }, + security: { + resolveDmPolicy: ({ cfg, accountId, account }) => { + return buildAccountScopedDmSecurityPolicy({ + cfg, + channelKey: "imessage", + accountId, + fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID, + policy: account.config.dmPolicy, + allowFrom: account.config.allowFrom ?? [], + policyPathSuffix: "dmPolicy", + }); + }, + collectWarnings: ({ account, cfg }) => { + return collectAllowlistProviderRestrictSendersWarnings({ + cfg, + providerConfigPresent: cfg.channels?.imessage !== undefined, + configuredGroupPolicy: account.config.groupPolicy, + surface: "iMessage groups", + openScope: "any member", + groupPolicyPath: "channels.imessage.groupPolicy", + groupAllowFromPath: "channels.imessage.groupAllowFrom", + mentionGated: false, + }); + }, + }, groups: { resolveRequireMention: resolveIMessageGroupRequireMention, resolveToolPolicy: resolveIMessageGroupToolPolicy, @@ -174,6 +256,7 @@ export const imessagePlugin: ChannelPlugin = { hint: "", }, }, + setup: imessageSetupAdapter, outbound: { deliveryMode: "direct", chunker: (text, limit) => getIMessageRuntime().channel.text.chunkText(text, limit), diff --git a/extensions/imessage/src/client.ts b/extensions/imessage/src/client.ts index efe9e5deb3b..4c9dea59c2c 100644 --- a/extensions/imessage/src/client.ts +++ b/extensions/imessage/src/client.ts @@ -1,7 +1,7 @@ import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process"; import { createInterface, type Interface } from "node:readline"; -import type { RuntimeEnv } from "../../../src/runtime.js"; -import { resolveUserPath } from "../../../src/utils.js"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { resolveUserPath } from "openclaw/plugin-sdk/text-runtime"; import { DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./constants.js"; export type IMessageRpcError = { diff --git a/extensions/imessage/src/monitor/deliver.ts b/extensions/imessage/src/monitor/deliver.ts index e8db8c0cac9..65dc125be68 100644 --- a/extensions/imessage/src/monitor/deliver.ts +++ b/extensions/imessage/src/monitor/deliver.ts @@ -1,9 +1,9 @@ -import { chunkTextWithMode, resolveChunkMode } from "../../../../src/auto-reply/chunk.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import { loadConfig } from "../../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../../src/config/markdown-tables.js"; -import { convertMarkdownTables } from "../../../../src/markdown/tables.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { chunkTextWithMode, resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; import type { createIMessageRpcClient } from "../client.js"; import { sendMessageIMessage } from "../send.js"; import type { SentMessageCache } from "./echo-cache.js"; diff --git a/extensions/imessage/src/monitor/inbound-processing.ts b/extensions/imessage/src/monitor/inbound-processing.ts index af900e21b40..531a8324dfd 100644 --- a/extensions/imessage/src/monitor/inbound-processing.ts +++ b/extensions/imessage/src/monitor/inbound-processing.ts @@ -1,34 +1,31 @@ -import { hasControlCommand } from "../../../../src/auto-reply/command-detection.js"; +import { resolveDualTextControlCommandGate } from "openclaw/plugin-sdk/channel-runtime"; +import { logInboundDrop } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { + resolveChannelGroupPolicy, + resolveChannelGroupRequireMention, +} from "openclaw/plugin-sdk/config-runtime"; +import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime"; import { formatInboundEnvelope, formatInboundFromLabel, resolveEnvelopeFormatOptions, type EnvelopeFormatOptions, -} from "../../../../src/auto-reply/envelope.js"; +} from "openclaw/plugin-sdk/reply-runtime"; import { buildPendingHistoryContextFromMap, recordPendingHistoryEntryIfEnabled, type HistoryEntry, -} from "../../../../src/auto-reply/reply/history.js"; -import { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js"; -import { - buildMentionRegexes, - matchesMentionPatterns, -} from "../../../../src/auto-reply/reply/mentions.js"; -import { resolveDualTextControlCommandGate } from "../../../../src/channels/command-gating.js"; -import { logInboundDrop } from "../../../../src/channels/logging.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import { - resolveChannelGroupPolicy, - resolveChannelGroupRequireMention, -} from "../../../../src/config/group-policy.js"; -import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import { buildMentionRegexes, matchesMentionPatterns } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; import { DM_GROUP_ACCESS_REASON, resolveDmGroupAccessWithLists, -} from "../../../../src/security/dm-policy-shared.js"; -import { sanitizeTerminalText } from "../../../../src/terminal/safe-text.js"; -import { truncateUtf16Safe } from "../../../../src/utils.js"; +} from "openclaw/plugin-sdk/security-runtime"; +import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-runtime"; +import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-runtime"; import { formatIMessageChatTarget, isAllowedIMessageSender, diff --git a/extensions/imessage/src/monitor/monitor-provider.ts b/extensions/imessage/src/monitor/monitor-provider.ts index e3c062cd814..dc15715d652 100644 --- a/extensions/imessage/src/monitor/monitor-provider.ts +++ b/extensions/imessage/src/monitor/monitor-provider.ts @@ -1,42 +1,42 @@ import fs from "node:fs/promises"; -import { resolveHumanDelayConfig } from "../../../../src/agents/identity.js"; -import { resolveTextChunkLimit } from "../../../../src/auto-reply/chunk.js"; -import { dispatchInboundMessage } from "../../../../src/auto-reply/dispatch.js"; -import { - clearHistoryEntriesIfEnabled, - DEFAULT_GROUP_HISTORY_LIMIT, - type HistoryEntry, -} from "../../../../src/auto-reply/reply/history.js"; -import { createReplyDispatcher } from "../../../../src/auto-reply/reply/reply-dispatcher.js"; +import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime"; import { createChannelInboundDebouncer, shouldDebounceTextInbound, -} from "../../../../src/channels/inbound-debounce-policy.js"; -import { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js"; -import { recordInboundSession } from "../../../../src/channels/session.js"; -import { loadConfig } from "../../../../src/config/config.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveOpenProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce, -} from "../../../../src/config/runtime-group-policy.js"; -import { readSessionUpdatedAt, resolveStorePath } from "../../../../src/config/sessions.js"; -import { danger, logVerbose, shouldLogVerbose, warn } from "../../../../src/globals.js"; -import { normalizeScpRemoteHost } from "../../../../src/infra/scp-host.js"; -import { waitForTransportReady } from "../../../../src/infra/transport-ready.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime"; +import { + readChannelAllowFromStore, + upsertChannelPairingRequest, +} from "openclaw/plugin-sdk/conversation-runtime"; +import { normalizeScpRemoteHost } from "openclaw/plugin-sdk/infra-runtime"; +import { waitForTransportReady } from "openclaw/plugin-sdk/infra-runtime"; import { isInboundPathAllowed, resolveIMessageAttachmentRoots, resolveIMessageRemoteAttachmentRoots, -} from "../../../../src/media/inbound-path-policy.js"; -import { kindFromMime } from "../../../../src/media/mime.js"; -import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js"; +} from "openclaw/plugin-sdk/media-runtime"; +import { kindFromMime } from "openclaw/plugin-sdk/media-runtime"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchInboundMessage } from "openclaw/plugin-sdk/reply-runtime"; import { - readChannelAllowFromStore, - upsertChannelPairingRequest, -} from "../../../../src/pairing/pairing-store.js"; -import { resolvePinnedMainDmOwnerFromAllowlist } from "../../../../src/security/dm-policy-shared.js"; -import { truncateUtf16Safe } from "../../../../src/utils.js"; + clearHistoryEntriesIfEnabled, + DEFAULT_GROUP_HISTORY_LIMIT, + type HistoryEntry, +} from "openclaw/plugin-sdk/reply-runtime"; +import { createReplyDispatcher } from "openclaw/plugin-sdk/reply-runtime"; +import { danger, logVerbose, shouldLogVerbose, warn } from "openclaw/plugin-sdk/runtime-env"; +import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime"; +import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-runtime"; import { resolveIMessageAccount } from "../accounts.js"; import { createIMessageRpcClient } from "../client.js"; import { DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "../constants.js"; diff --git a/extensions/imessage/src/monitor/reflection-guard.ts b/extensions/imessage/src/monitor/reflection-guard.ts index 0af95d957cc..9ed38d2a175 100644 --- a/extensions/imessage/src/monitor/reflection-guard.ts +++ b/extensions/imessage/src/monitor/reflection-guard.ts @@ -4,7 +4,7 @@ * bounced back as a new inbound message — creating an echo loop. */ -import { findCodeRegions, isInsideCode } from "../../../../src/shared/text/code-regions.js"; +import { findCodeRegions, isInsideCode } from "openclaw/plugin-sdk/text-runtime"; const INTERNAL_SEPARATOR_RE = /(?:#\+){2,}#?/; const ASSISTANT_ROLE_MARKER_RE = /\bassistant\s+to\s*=\s*\w+/i; diff --git a/extensions/imessage/src/monitor/runtime.ts b/extensions/imessage/src/monitor/runtime.ts index e4fe6ae4336..437224013d4 100644 --- a/extensions/imessage/src/monitor/runtime.ts +++ b/extensions/imessage/src/monitor/runtime.ts @@ -1,5 +1,5 @@ -import { createNonExitingRuntime, type RuntimeEnv } from "../../../../src/runtime.js"; -import { normalizeStringEntries } from "../../../../src/shared/string-normalization.js"; +import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { normalizeStringEntries } from "openclaw/plugin-sdk/text-runtime"; import type { MonitorIMessageOpts } from "./types.js"; export function resolveRuntime(opts: MonitorIMessageOpts): RuntimeEnv { diff --git a/extensions/imessage/src/monitor/sanitize-outbound.ts b/extensions/imessage/src/monitor/sanitize-outbound.ts index 83eb75a8da2..533eb7f2176 100644 --- a/extensions/imessage/src/monitor/sanitize-outbound.ts +++ b/extensions/imessage/src/monitor/sanitize-outbound.ts @@ -1,4 +1,4 @@ -import { stripAssistantInternalScaffolding } from "../../../../src/shared/text/assistant-visible-text.js"; +import { stripAssistantInternalScaffolding } from "openclaw/plugin-sdk/text-runtime"; /** * Patterns that indicate assistant-internal metadata leaked into text. diff --git a/extensions/imessage/src/monitor/types.ts b/extensions/imessage/src/monitor/types.ts index 074c7c34c9f..a03ed5faea8 100644 --- a/extensions/imessage/src/monitor/types.ts +++ b/extensions/imessage/src/monitor/types.ts @@ -1,5 +1,5 @@ -import type { OpenClawConfig } from "../../../../src/config/config.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; export type IMessageAttachment = { original_path?: string | null; diff --git a/extensions/imessage/src/outbound-adapter.ts b/extensions/imessage/src/outbound-adapter.ts index ae5e7c2836a..cd961c30bfa 100644 --- a/extensions/imessage/src/outbound-adapter.ts +++ b/extensions/imessage/src/outbound-adapter.ts @@ -1,11 +1,8 @@ import { createScopedChannelMediaMaxBytesResolver, createDirectTextMediaOutbound, -} from "../../../src/channels/plugins/outbound/direct-text-media.js"; -import { - resolveOutboundSendDep, - type OutboundSendDeps, -} from "../../../src/infra/outbound/send-deps.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { resolveOutboundSendDep, type OutboundSendDeps } from "openclaw/plugin-sdk/channel-runtime"; import { sendMessageIMessage } from "./send.js"; function resolveIMessageSender(deps: OutboundSendDeps | undefined) { diff --git a/extensions/imessage/src/plugin-shared.ts b/extensions/imessage/src/plugin-shared.ts index c7ed39cd21a..415a152f56a 100644 --- a/extensions/imessage/src/plugin-shared.ts +++ b/extensions/imessage/src/plugin-shared.ts @@ -1,4 +1,4 @@ -import { type ChannelPlugin } from "../../../src/plugin-sdk-internal/imessage.js"; +import type { ChannelPlugin } from "openclaw/plugin-sdk/imessage"; import { type ResolvedIMessageAccount } from "./accounts.js"; import { createIMessageSetupWizardProxy } from "./setup-core.js"; diff --git a/extensions/imessage/src/probe.ts b/extensions/imessage/src/probe.ts index 1b6ab665d09..7ae049f02eb 100644 --- a/extensions/imessage/src/probe.ts +++ b/extensions/imessage/src/probe.ts @@ -1,8 +1,8 @@ -import type { BaseProbeResult } from "../../../src/channels/plugins/types.js"; -import { detectBinary } from "../../../src/commands/onboard-helpers.js"; -import { loadConfig } from "../../../src/config/config.js"; -import { runCommandWithTimeout } from "../../../src/process/exec.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +import type { BaseProbeResult } from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { runCommandWithTimeout } from "openclaw/plugin-sdk/process-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { detectBinary } from "openclaw/plugin-sdk/setup"; import { createIMessageRpcClient } from "./client.js"; import { DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS } from "./constants.js"; diff --git a/extensions/imessage/src/runtime.ts b/extensions/imessage/src/runtime.ts index 3a49020348f..a7ed927b9ab 100644 --- a/extensions/imessage/src/runtime.ts +++ b/extensions/imessage/src/runtime.ts @@ -1,7 +1,5 @@ -import { - createPluginRuntimeStore, - type PluginRuntime, -} from "../../../src/plugin-sdk-internal/core.js"; +import type { PluginRuntime } from "openclaw/plugin-sdk/core"; +import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; const { setRuntime: setIMessageRuntime, getRuntime: getIMessageRuntime } = createPluginRuntimeStore("iMessage runtime not initialized"); diff --git a/extensions/imessage/src/send.ts b/extensions/imessage/src/send.ts index 5bc02b6bb7f..70c996329e1 100644 --- a/extensions/imessage/src/send.ts +++ b/extensions/imessage/src/send.ts @@ -1,8 +1,8 @@ -import { loadConfig } from "../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { convertMarkdownTables } from "../../../src/markdown/tables.js"; -import { kindFromMime } from "../../../src/media/mime.js"; -import { resolveOutboundAttachmentFromUrl } from "../../../src/media/outbound-attachment.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { kindFromMime } from "openclaw/plugin-sdk/media-runtime"; +import { resolveOutboundAttachmentFromUrl } from "openclaw/plugin-sdk/media-runtime"; +import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; import { resolveIMessageAccount, type ResolvedIMessageAccount } from "./accounts.js"; import { createIMessageRpcClient, type IMessageRpcClient } from "./client.js"; import { formatIMessageChatTarget, type IMessageService, parseIMessageTarget } from "./targets.js"; diff --git a/extensions/imessage/src/setup-core.ts b/extensions/imessage/src/setup-core.ts index 45f385e0691..eed33e64192 100644 --- a/extensions/imessage/src/setup-core.ts +++ b/extensions/imessage/src/setup-core.ts @@ -1,18 +1,21 @@ -import { createPatchedAccountSetupAdapter } from "../../../src/channels/plugins/setup-helpers.js"; import { + applyAccountNameToChannelSection, + DEFAULT_ACCOUNT_ID, + formatDocsLink, + migrateBaseNameToDefaultAccount, + normalizeAccountId, parseSetupEntriesAllowingWildcard, promptParsedAllowFromForScopedChannel, setChannelDmPolicyWithAllowFrom, setSetupChannelEnabled, type OpenClawConfig, type WizardPrompter, -} from "../../../src/plugin-sdk-internal/setup.js"; +} from "openclaw/plugin-sdk/setup"; import type { ChannelSetupAdapter, ChannelSetupDmPolicy, ChannelSetupWizard, -} from "../../../src/plugin-sdk-internal/setup.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; +} from "openclaw/plugin-sdk/setup"; import { listIMessageAccountIds, resolveDefaultIMessageAccountId, @@ -95,23 +98,66 @@ async function promptIMessageAllowFrom(params: { }); } -export const imessageSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupAdapter({ - channelKey: channel, - buildPatch: (input) => buildIMessageSetupPatch(input), -}); - -type IMessageSetupWizardHandlers = { - resolveStatusLines: NonNullable["resolveStatusLines"]; - resolveSelectionHint: NonNullable["resolveSelectionHint"]; - resolveQuickstartScore: NonNullable["resolveQuickstartScore"]; - shouldPromptCliPath: NonNullable< - NonNullable[number]["shouldPrompt"] - >; +export const imessageSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + }), + applyAccountConfig: ({ cfg, accountId, input }) => { + const namedConfig = applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name: input.name, + }); + const next = + accountId !== DEFAULT_ACCOUNT_ID + ? migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + }) + : namedConfig; + if (accountId === DEFAULT_ACCOUNT_ID) { + return { + ...next, + channels: { + ...next.channels, + imessage: { + ...next.channels?.imessage, + enabled: true, + ...buildIMessageSetupPatch(input), + }, + }, + }; + } + return { + ...next, + channels: { + ...next.channels, + imessage: { + ...next.channels?.imessage, + enabled: true, + accounts: { + ...next.channels?.imessage?.accounts, + [accountId]: { + ...next.channels?.imessage?.accounts?.[accountId], + enabled: true, + ...buildIMessageSetupPatch(input), + }, + }, + }, + }, + }; + }, }; -export function createIMessageSetupWizardBase( - handlers: IMessageSetupWizardHandlers, -): ChannelSetupWizard { +export function createIMessageSetupWizardProxy( + loadWizard: () => Promise<{ imessageSetupWizard: ChannelSetupWizard }>, +) { const imessageDmPolicy: ChannelSetupDmPolicy = { label: "iMessage", channel, @@ -147,9 +193,12 @@ export function createIMessageSetupWizardBase( account.config.region, ); }), - resolveStatusLines: handlers.resolveStatusLines, - resolveSelectionHint: handlers.resolveSelectionHint, - resolveQuickstartScore: handlers.resolveQuickstartScore, + resolveStatusLines: async (params) => + (await loadWizard()).imessageSetupWizard.status.resolveStatusLines?.(params) ?? [], + resolveSelectionHint: async (params) => + await (await loadWizard()).imessageSetupWizard.status.resolveSelectionHint?.(params), + resolveQuickstartScore: async (params) => + await (await loadWizard()).imessageSetupWizard.status.resolveQuickstartScore?.(params), }, credentials: [], textInputs: [ @@ -160,7 +209,12 @@ export function createIMessageSetupWizardBase( resolveIMessageAccount({ cfg, accountId }).config.cliPath ?? "imsg", currentValue: ({ cfg, accountId }) => resolveIMessageAccount({ cfg, accountId }).config.cliPath ?? "imsg", - shouldPrompt: handlers.shouldPromptCliPath, + shouldPrompt: async (params) => { + const input = (await loadWizard()).imessageSetupWizard.textInputs?.find( + (entry) => entry.inputKey === "cliPath", + ); + return (await input?.shouldPrompt?.(params)) ?? false; + }, confirmCurrentValue: false, applyCurrentValue: true, helpTitle: "iMessage", @@ -181,22 +235,3 @@ export function createIMessageSetupWizardBase( disable: (cfg: OpenClawConfig) => setSetupChannelEnabled(cfg, channel, false), } satisfies ChannelSetupWizard; } - -export function createIMessageSetupWizardProxy( - loadWizard: () => Promise<{ imessageSetupWizard: ChannelSetupWizard }>, -) { - return createIMessageSetupWizardBase({ - resolveStatusLines: async (params) => - (await loadWizard()).imessageSetupWizard.status.resolveStatusLines?.(params) ?? [], - resolveSelectionHint: async (params) => - await (await loadWizard()).imessageSetupWizard.status.resolveSelectionHint?.(params), - resolveQuickstartScore: async (params) => - await (await loadWizard()).imessageSetupWizard.status.resolveQuickstartScore?.(params), - shouldPromptCliPath: async (params) => { - const input = (await loadWizard()).imessageSetupWizard.textInputs?.find( - (entry) => entry.inputKey === "cliPath", - ); - return (await input?.shouldPrompt?.(params)) ?? false; - }, - }); -} diff --git a/extensions/imessage/src/setup-surface.ts b/extensions/imessage/src/setup-surface.ts index c1158960cec..48c9f130355 100644 --- a/extensions/imessage/src/setup-surface.ts +++ b/extensions/imessage/src/setup-surface.ts @@ -1,23 +1,134 @@ -import { detectBinary } from "../../../src/plugin-sdk-internal/setup.js"; -import { createIMessageSetupWizardBase, imessageSetupAdapter } from "./setup-core.js"; +import { + DEFAULT_ACCOUNT_ID, + detectBinary, + formatDocsLink, + type OpenClawConfig, + parseSetupEntriesAllowingWildcard, + promptParsedAllowFromForScopedChannel, + setChannelDmPolicyWithAllowFrom, + setSetupChannelEnabled, + type WizardPrompter, +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupDmPolicy, ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { + listIMessageAccountIds, + resolveDefaultIMessageAccountId, + resolveIMessageAccount, +} from "./accounts.js"; +import { imessageSetupAdapter, parseIMessageAllowFromEntries } from "./setup-core.js"; -export const imessageSetupWizard = createIMessageSetupWizardBase({ - resolveStatusLines: async ({ cfg, configured }) => { - const cliPath = cfg.channels?.imessage?.cliPath ?? "imsg"; - const cliDetected = await detectBinary(cliPath); - return [ - `iMessage: ${configured ? "configured" : "needs setup"}`, - `imsg: ${cliDetected ? "found" : "missing"} (${cliPath})`, - ]; +const channel = "imessage" as const; + +async function promptIMessageAllowFrom(params: { + cfg: OpenClawConfig; + prompter: WizardPrompter; + accountId?: string; +}): Promise { + return promptParsedAllowFromForScopedChannel({ + cfg: params.cfg, + channel, + accountId: params.accountId, + defaultAccountId: resolveDefaultIMessageAccountId(params.cfg), + prompter: params.prompter, + noteTitle: "iMessage allowlist", + noteLines: [ + "Allowlist iMessage DMs by handle or chat target.", + "Examples:", + "- +15555550123", + "- user@example.com", + "- chat_id:123", + "- chat_guid:... or chat_identifier:...", + "Multiple entries: comma-separated.", + `Docs: ${formatDocsLink("/imessage", "imessage")}`, + ], + message: "iMessage allowFrom (handle or chat_id)", + placeholder: "+15555550123, user@example.com, chat_id:123", + parseEntries: parseIMessageAllowFromEntries, + getExistingAllowFrom: ({ cfg, accountId }) => + resolveIMessageAccount({ cfg, accountId }).config.allowFrom ?? [], + }); +} + +const imessageDmPolicy: ChannelSetupDmPolicy = { + label: "iMessage", + channel, + policyKey: "channels.imessage.dmPolicy", + allowFromKey: "channels.imessage.allowFrom", + getCurrent: (cfg) => cfg.channels?.imessage?.dmPolicy ?? "pairing", + setPolicy: (cfg, policy) => + setChannelDmPolicyWithAllowFrom({ + cfg, + channel, + dmPolicy: policy, + }), + promptAllowFrom: promptIMessageAllowFrom, +}; + +export const imessageSetupWizard: ChannelSetupWizard = { + channel, + status: { + configuredLabel: "configured", + unconfiguredLabel: "needs setup", + configuredHint: "imsg found", + unconfiguredHint: "imsg missing", + configuredScore: 1, + unconfiguredScore: 0, + resolveConfigured: ({ cfg }) => + listIMessageAccountIds(cfg).some((accountId) => { + const account = resolveIMessageAccount({ cfg, accountId }); + return Boolean( + account.config.cliPath || + account.config.dbPath || + account.config.allowFrom || + account.config.service || + account.config.region, + ); + }), + resolveStatusLines: async ({ cfg, configured }) => { + const cliPath = cfg.channels?.imessage?.cliPath ?? "imsg"; + const cliDetected = await detectBinary(cliPath); + return [ + `iMessage: ${configured ? "configured" : "needs setup"}`, + `imsg: ${cliDetected ? "found" : "missing"} (${cliPath})`, + ]; + }, + resolveSelectionHint: async ({ cfg }) => { + const cliPath = cfg.channels?.imessage?.cliPath ?? "imsg"; + return (await detectBinary(cliPath)) ? "imsg found" : "imsg missing"; + }, + resolveQuickstartScore: async ({ cfg }) => { + const cliPath = cfg.channels?.imessage?.cliPath ?? "imsg"; + return (await detectBinary(cliPath)) ? 1 : 0; + }, }, - resolveSelectionHint: async ({ cfg }) => { - const cliPath = cfg.channels?.imessage?.cliPath ?? "imsg"; - return (await detectBinary(cliPath)) ? "imsg found" : "imsg missing"; + credentials: [], + textInputs: [ + { + inputKey: "cliPath", + message: "imsg CLI path", + initialValue: ({ cfg, accountId }) => + resolveIMessageAccount({ cfg, accountId }).config.cliPath ?? "imsg", + currentValue: ({ cfg, accountId }) => + resolveIMessageAccount({ cfg, accountId }).config.cliPath ?? "imsg", + shouldPrompt: async ({ currentValue }) => !(await detectBinary(currentValue ?? "imsg")), + confirmCurrentValue: false, + applyCurrentValue: true, + helpTitle: "iMessage", + helpLines: ["imsg CLI path required to enable iMessage."], + }, + ], + completionNote: { + title: "iMessage next steps", + lines: [ + "This is still a work in progress.", + "Ensure OpenClaw has Full Disk Access to Messages DB.", + "Grant Automation permission for Messages when prompted.", + "List chats with: imsg chats --limit 20", + `Docs: ${formatDocsLink("/imessage", "imessage")}`, + ], }, - resolveQuickstartScore: async ({ cfg }) => { - const cliPath = cfg.channels?.imessage?.cliPath ?? "imsg"; - return (await detectBinary(cliPath)) ? 1 : 0; - }, - shouldPromptCliPath: async ({ currentValue }) => !(await detectBinary(currentValue ?? "imsg")), -}); -export { imessageSetupAdapter, parseIMessageAllowFromEntries } from "./setup-core.js"; + dmPolicy: imessageDmPolicy, + disable: (cfg) => setSetupChannelEnabled(cfg, channel, false), +}; + +export { imessageSetupAdapter, parseIMessageAllowFromEntries }; diff --git a/extensions/imessage/src/target-parsing-helpers.ts b/extensions/imessage/src/target-parsing-helpers.ts index 7995b271fe4..04881fa2131 100644 --- a/extensions/imessage/src/target-parsing-helpers.ts +++ b/extensions/imessage/src/target-parsing-helpers.ts @@ -1,4 +1,4 @@ -import { isAllowedParsedChatSender } from "../../../src/plugin-sdk-internal/imessage.js"; +import { isAllowedParsedChatSender } from "openclaw/plugin-sdk/allow-from"; export type ServicePrefix = { prefix: string; service: TService }; diff --git a/extensions/imessage/src/targets.ts b/extensions/imessage/src/targets.ts index a376a6e7f45..d6cd6a11f38 100644 --- a/extensions/imessage/src/targets.ts +++ b/extensions/imessage/src/targets.ts @@ -1,4 +1,4 @@ -import { normalizeE164 } from "../../../src/utils.js"; +import { normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import { createAllowedChatSenderMatcher, type ChatSenderAllowParams, diff --git a/extensions/irc/src/setup-core.ts b/extensions/irc/src/setup-core.ts index 3c28017e1e9..23422e30ba0 100644 --- a/extensions/irc/src/setup-core.ts +++ b/extensions/irc/src/setup-core.ts @@ -1,15 +1,15 @@ +import type { ChannelSetupAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelSetupInput } from "openclaw/plugin-sdk/channel-runtime"; +import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { + applyAccountNameToChannelSection, patchScopedAccountConfig, - prepareScopedSetupConfig, -} from "../../../src/channels/plugins/setup-helpers.js"; +} from "openclaw/plugin-sdk/setup"; import { setTopLevelChannelAllowFrom, setTopLevelChannelDmPolicyWithAllowFrom, -} from "../../../src/channels/plugins/setup-wizard-helpers.js"; -import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js"; -import type { ChannelSetupInput } from "../../../src/channels/plugins/types.core.js"; -import type { DmPolicy } from "../../../src/config/types.js"; -import { normalizeAccountId } from "../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/setup"; import type { CoreConfig, IrcAccountConfig, IrcNickServConfig } from "./types.js"; const channel = "irc" as const; @@ -100,7 +100,7 @@ export function setIrcGroupAccess( export const ircSetupAdapter: ChannelSetupAdapter = { resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), applyAccountName: ({ cfg, accountId, name }) => - prepareScopedSetupConfig({ + applyAccountNameToChannelSection({ cfg, channelKey: channel, accountId, @@ -118,7 +118,7 @@ export const ircSetupAdapter: ChannelSetupAdapter = { }, applyAccountConfig: ({ cfg, accountId, input }) => { const setupInput = input as IrcSetupInput; - const namedConfig = prepareScopedSetupConfig({ + const namedConfig = applyAccountNameToChannelSection({ cfg, channelKey: channel, accountId, diff --git a/extensions/irc/src/setup-surface.ts b/extensions/irc/src/setup-surface.ts index 1607a9bdd54..cdadcffbaec 100644 --- a/extensions/irc/src/setup-surface.ts +++ b/extensions/irc/src/setup-surface.ts @@ -1,13 +1,10 @@ -import { - resolveSetupAccountId, - setSetupChannelEnabled, -} from "../../../src/channels/plugins/setup-wizard-helpers.js"; -import type { ChannelSetupDmPolicy } from "../../../src/channels/plugins/setup-wizard-types.js"; -import type { ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js"; -import type { DmPolicy } from "../../../src/config/types.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; -import type { WizardPrompter } from "../../../src/wizard/prompts.js"; +import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing"; +import { resolveSetupAccountId, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { formatDocsLink } from "openclaw/plugin-sdk/setup"; +import type { WizardPrompter } from "openclaw/plugin-sdk/setup"; import { listIrcAccountIds, resolveDefaultIrcAccountId, resolveIrcAccount } from "./accounts.js"; import { isChannelTarget, diff --git a/extensions/kilocode/index.ts b/extensions/kilocode/index.ts index 7089d212628..33dc9718021 100644 --- a/extensions/kilocode/index.ts +++ b/extensions/kilocode/index.ts @@ -1,9 +1,9 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { createKilocodeWrapper, isProxyReasoningUnsupported, -} from "../../src/agents/pi-embedded-runner/proxy-stream-wrappers.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +} from "openclaw/plugin-sdk/provider-stream"; import { applyKilocodeConfig, KILOCODE_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; import { buildKilocodeProviderWithDiscovery } from "./provider-catalog.js"; diff --git a/extensions/kilocode/onboard.ts b/extensions/kilocode/onboard.ts index 260233c3d34..fd285341f52 100644 --- a/extensions/kilocode/onboard.ts +++ b/extensions/kilocode/onboard.ts @@ -1,12 +1,9 @@ +import { KILOCODE_BASE_URL, KILOCODE_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models"; import { applyAgentDefaultModelPrimary, applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; -import { - KILOCODE_BASE_URL, - KILOCODE_DEFAULT_MODEL_REF, -} from "../../src/providers/kilocode-shared.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; import { buildKilocodeProvider } from "./provider-catalog.js"; export { KILOCODE_BASE_URL, KILOCODE_DEFAULT_MODEL_REF }; diff --git a/extensions/kilocode/provider-catalog.ts b/extensions/kilocode/provider-catalog.ts index 696b351c530..98e324f4784 100644 --- a/extensions/kilocode/provider-catalog.ts +++ b/extensions/kilocode/provider-catalog.ts @@ -1,12 +1,12 @@ -import { discoverKilocodeModels } from "../../src/agents/kilocode-models.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; import { + discoverKilocodeModels, + type ModelProviderConfig, KILOCODE_BASE_URL, KILOCODE_DEFAULT_CONTEXT_WINDOW, KILOCODE_DEFAULT_COST, KILOCODE_DEFAULT_MAX_TOKENS, KILOCODE_MODEL_CATALOG, -} from "../../src/providers/kilocode-shared.js"; +} from "openclaw/plugin-sdk/provider-models"; export function buildKilocodeProvider(): ModelProviderConfig { return { diff --git a/extensions/kimi-coding/index.ts b/extensions/kimi-coding/index.ts index 709e5a8de4c..3803a0af951 100644 --- a/extensions/kimi-coding/index.ts +++ b/extensions/kimi-coding/index.ts @@ -1,69 +1,47 @@ -import { - emptyPluginConfigSchema, - type OpenClawPluginApi, - type ProviderRuntimeModel, -} from "openclaw/plugin-sdk/core"; -import { findNormalizedProviderValue, normalizeProviderId } from "../../src/agents/provider-id.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import { isRecord } from "../../src/utils.js"; -import { applyKimiCodeConfig, KIMI_DEFAULT_MODEL_REF } from "./onboard.js"; -import { - buildKimiProvider, - KIMI_DEFAULT_MODEL_ID, - KIMI_LEGACY_MODEL_ID, - KIMI_UPSTREAM_MODEL_ID, -} from "./provider-catalog.js"; +import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { isRecord } from "openclaw/plugin-sdk/text-runtime"; +import { applyKimiCodeConfig, KIMI_CODING_MODEL_REF } from "./onboard.js"; +import { buildKimiCodingProvider } from "./provider-catalog.js"; -const PROVIDER_ID = "kimi"; -const KIMI_TRANSPORT_MODEL_IDS = new Set([KIMI_DEFAULT_MODEL_ID, KIMI_LEGACY_MODEL_ID]); - -function normalizeKimiTransportModel(model: ProviderRuntimeModel): ProviderRuntimeModel { - if (!KIMI_TRANSPORT_MODEL_IDS.has(model.id)) { - return model; - } - return { - ...model, - id: KIMI_UPSTREAM_MODEL_ID, - name: "Kimi Code", - }; -} +const PROVIDER_ID = "kimi-coding"; const kimiCodingPlugin = { id: PROVIDER_ID, - name: "Kimi Code Provider", - description: "Bundled Kimi Code provider plugin", + name: "Kimi Provider", + description: "Bundled Kimi provider plugin", configSchema: emptyPluginConfigSchema(), register(api: OpenClawPluginApi) { api.registerProvider({ id: PROVIDER_ID, - label: "Kimi Code", - aliases: ["kimi-code", "kimi-coding"], + label: "Kimi", + aliases: ["kimi", "kimi-code"], docsPath: "/providers/moonshot", envVars: ["KIMI_API_KEY", "KIMICODE_API_KEY"], auth: [ createProviderApiKeyAuthMethod({ providerId: PROVIDER_ID, methodId: "api-key", - label: "Kimi Code API key", - hint: "Dedicated coding endpoint", + label: "Kimi API key (subscription)", + hint: "Kimi K2.5 + Kimi", optionKey: "kimiCodeApiKey", flagName: "--kimi-code-api-key", envVar: "KIMI_API_KEY", - promptMessage: "Enter Kimi Code API key", - defaultModel: KIMI_DEFAULT_MODEL_REF, + promptMessage: "Enter Kimi API key", + defaultModel: KIMI_CODING_MODEL_REF, expectedProviders: ["kimi", "kimi-code", "kimi-coding"], applyConfig: (cfg) => applyKimiCodeConfig(cfg), noteMessage: [ - "Kimi Code uses a dedicated coding endpoint and API key.", + "Kimi uses a dedicated coding endpoint and API key.", "Get your API key at: https://www.kimi.com/code/en", ].join("\n"), - noteTitle: "Kimi Code", + noteTitle: "Kimi", wizard: { choiceId: "kimi-code-api-key", - choiceLabel: "Kimi Code API key", - groupId: "kimi-code", - groupLabel: "Kimi Code", - groupHint: "Dedicated coding endpoint", + choiceLabel: "Kimi API key (subscription)", + groupId: "moonshot", + groupLabel: "Moonshot AI (Kimi K2.5)", + groupHint: "Kimi K2.5 + Kimi", }, }), ], @@ -74,11 +52,8 @@ const kimiCodingPlugin = { if (!apiKey) { return null; } - const explicitProvider = findNormalizedProviderValue( - ctx.config.models?.providers, - PROVIDER_ID, - ); - const builtInProvider = buildKimiProvider(); + const explicitProvider = ctx.config.models?.providers?.[PROVIDER_ID]; + const builtInProvider = buildKimiCodingProvider(); const explicitBaseUrl = typeof explicitProvider?.baseUrl === "string" ? explicitProvider.baseUrl.trim() : ""; const explicitHeaders = isRecord(explicitProvider?.headers) @@ -104,12 +79,6 @@ const kimiCodingPlugin = { capabilities: { preserveAnthropicThinkingSignatures: false, }, - normalizeResolvedModel: (ctx) => { - if (normalizeProviderId(ctx.provider) !== PROVIDER_ID) { - return undefined; - } - return normalizeKimiTransportModel(ctx.model); - }, }); }, }; diff --git a/extensions/kimi-coding/onboard.ts b/extensions/kimi-coding/onboard.ts index 07feea91327..c97738f1e72 100644 --- a/extensions/kimi-coding/onboard.ts +++ b/extensions/kimi-coding/onboard.ts @@ -1,44 +1,38 @@ import { applyAgentDefaultModelPrimary, - applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + applyProviderConfigWithDefaultModel, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; import { buildKimiCodingProvider, - KIMI_BASE_URL, - KIMI_DEFAULT_MODEL_ID, - KIMI_LEGACY_MODEL_ID, + KIMI_CODING_BASE_URL, + KIMI_CODING_DEFAULT_MODEL_ID, } from "./provider-catalog.js"; -export const KIMI_DEFAULT_MODEL_REF = `kimi/${KIMI_DEFAULT_MODEL_ID}`; -export const KIMI_LEGACY_MODEL_REF = `kimi/${KIMI_LEGACY_MODEL_ID}`; -export const KIMI_CODING_MODEL_REF = KIMI_DEFAULT_MODEL_REF; +export const KIMI_CODING_MODEL_REF = `kimi-coding/${KIMI_CODING_DEFAULT_MODEL_ID}`; export function applyKimiCodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig { const models = { ...cfg.agents?.defaults?.models }; - models[KIMI_DEFAULT_MODEL_REF] = { - ...models[KIMI_DEFAULT_MODEL_REF], - alias: models[KIMI_DEFAULT_MODEL_REF]?.alias ?? "Kimi Code", - }; - models[KIMI_LEGACY_MODEL_REF] = { - ...models[KIMI_LEGACY_MODEL_REF], - alias: models[KIMI_LEGACY_MODEL_REF]?.alias ?? "Kimi Code", + models[KIMI_CODING_MODEL_REF] = { + ...models[KIMI_CODING_MODEL_REF], + alias: models[KIMI_CODING_MODEL_REF]?.alias ?? "Kimi", }; - const catalog = buildKimiCodingProvider().models ?? []; - if (catalog.length === 0) { + const defaultModel = buildKimiCodingProvider().models[0]; + if (!defaultModel) { return cfg; } - return applyProviderConfigWithModelCatalog(cfg, { + return applyProviderConfigWithDefaultModel(cfg, { agentModels: models, - providerId: "kimi", + providerId: "kimi-coding", api: "anthropic-messages", - baseUrl: KIMI_BASE_URL, - catalogModels: catalog, + baseUrl: KIMI_CODING_BASE_URL, + defaultModel, + defaultModelId: KIMI_CODING_DEFAULT_MODEL_ID, }); } export function applyKimiCodeConfig(cfg: OpenClawConfig): OpenClawConfig { - return applyAgentDefaultModelPrimary(applyKimiCodeProviderConfig(cfg), KIMI_DEFAULT_MODEL_REF); + return applyAgentDefaultModelPrimary(applyKimiCodeProviderConfig(cfg), KIMI_CODING_MODEL_REF); } diff --git a/extensions/kimi-coding/provider-catalog.ts b/extensions/kimi-coding/provider-catalog.ts index 439c86fdff0..5fc27495c76 100644 --- a/extensions/kimi-coding/provider-catalog.ts +++ b/extensions/kimi-coding/provider-catalog.ts @@ -1,4 +1,4 @@ -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-models"; export const KIMI_BASE_URL = "https://api.kimi.com/coding/"; const KIMI_CODING_USER_AGENT = "claude-code/0.1.0"; diff --git a/extensions/line/src/channel.setup.ts b/extensions/line/src/channel.setup.ts index 71a1d87c45d..771107dff58 100644 --- a/extensions/line/src/channel.setup.ts +++ b/extensions/line/src/channel.setup.ts @@ -9,7 +9,7 @@ import { listLineAccountIds, resolveDefaultLineAccountId, resolveLineAccount, -} from "../../../src/line/accounts.js"; +} from "openclaw/plugin-sdk/line"; import { lineSetupAdapter } from "./setup-core.js"; import { lineSetupWizard } from "./setup-surface.js"; diff --git a/extensions/line/src/setup-core.ts b/extensions/line/src/setup-core.ts index 67c9c674df5..737ba1cc856 100644 --- a/extensions/line/src/setup-core.ts +++ b/extensions/line/src/setup-core.ts @@ -1,12 +1,11 @@ -import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; import { listLineAccountIds, normalizeAccountId, resolveLineAccount, -} from "../../../src/line/accounts.js"; -import type { LineConfig } from "../../../src/line/types.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js"; + type LineConfig, +} from "openclaw/plugin-sdk/line"; +import type { ChannelSetupAdapter, OpenClawConfig } from "openclaw/plugin-sdk/setup"; +import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup"; const channel = "line" as const; diff --git a/extensions/line/src/setup-surface.ts b/extensions/line/src/setup-surface.ts index 9ea7dd4ce68..d548b096434 100644 --- a/extensions/line/src/setup-surface.ts +++ b/extensions/line/src/setup-surface.ts @@ -1,13 +1,13 @@ +import { resolveLineAccount } from "openclaw/plugin-sdk/line"; import { + DEFAULT_ACCOUNT_ID, + formatDocsLink, setSetupChannelEnabled, setTopLevelChannelDmPolicyWithAllowFrom, splitSetupEntries, -} from "../../../src/channels/plugins/setup-wizard-helpers.js"; -import type { ChannelSetupDmPolicy } from "../../../src/channels/plugins/setup-wizard-types.js"; -import type { ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js"; -import { resolveLineAccount } from "../../../src/line/accounts.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; + type ChannelSetupDmPolicy, + type ChannelSetupWizard, +} from "openclaw/plugin-sdk/setup"; import { isLineConfigured, listLineAccountIds, diff --git a/extensions/matrix/src/outbound.ts b/extensions/matrix/src/outbound.ts index 072ab2fb8c1..09374b7746e 100644 --- a/extensions/matrix/src/outbound.ts +++ b/extensions/matrix/src/outbound.ts @@ -1,5 +1,5 @@ +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/matrix"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; import { sendMessageMatrix, sendPollMatrix } from "./matrix/send.js"; import { getMatrixRuntime } from "./runtime.js"; diff --git a/extensions/mattermost/src/setup-core.ts b/extensions/mattermost/src/setup-core.ts index 45bfbc5ac82..781967c70a6 100644 --- a/extensions/mattermost/src/setup-core.ts +++ b/extensions/mattermost/src/setup-core.ts @@ -1,10 +1,13 @@ +import type { ChannelSetupAdapter } from "openclaw/plugin-sdk/channel-runtime"; import { + applyAccountNameToChannelSection, + applySetupAccountConfigPatch, DEFAULT_ACCOUNT_ID, hasConfiguredSecretInput, + migrateBaseNameToDefaultAccount, + normalizeAccountId, type OpenClawConfig, } from "openclaw/plugin-sdk/mattermost"; -import { createPatchedAccountSetupAdapter } from "../../../src/channels/plugins/setup-helpers.js"; -import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js"; import { resolveMattermostAccount, type ResolvedMattermostAccount } from "./mattermost/accounts.js"; import { normalizeMattermostBaseUrl } from "./mattermost/client.js"; @@ -24,8 +27,15 @@ export function resolveMattermostAccountWithSecrets(cfg: OpenClawConfig, account }); } -export const mattermostSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupAdapter({ - channelKey: channel, +export const mattermostSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + }), validateInput: ({ accountId, input }) => { const token = input.botToken ?? input.token; const baseUrl = normalizeMattermostBaseUrl(input.httpUrl); @@ -40,14 +50,32 @@ export const mattermostSetupAdapter: ChannelSetupAdapter = createPatchedAccountS } return null; }, - buildPatch: (input) => { + applyAccountConfig: ({ cfg, accountId, input }) => { const token = input.botToken ?? input.token; const baseUrl = normalizeMattermostBaseUrl(input.httpUrl); - return input.useEnv - ? {} - : { - ...(token ? { botToken: token } : {}), - ...(baseUrl ? { baseUrl } : {}), - }; + const namedConfig = applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name: input.name, + }); + const next = + accountId !== DEFAULT_ACCOUNT_ID + ? migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + }) + : namedConfig; + return applySetupAccountConfigPatch({ + cfg: next, + channelKey: channel, + accountId, + patch: input.useEnv + ? {} + : { + ...(token ? { botToken: token } : {}), + ...(baseUrl ? { baseUrl } : {}), + }, + }); }, -}); +}; diff --git a/extensions/mattermost/src/setup-surface.ts b/extensions/mattermost/src/setup-surface.ts index 13b69542d02..d3b0a66b4c8 100644 --- a/extensions/mattermost/src/setup-surface.ts +++ b/extensions/mattermost/src/setup-surface.ts @@ -4,8 +4,8 @@ import { hasConfiguredSecretInput, type OpenClawConfig, } from "openclaw/plugin-sdk/mattermost"; -import { type ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; +import { type ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { formatDocsLink } from "openclaw/plugin-sdk/setup"; import { listMattermostAccountIds } from "./mattermost/accounts.js"; import { normalizeMattermostBaseUrl } from "./mattermost/client.js"; import { diff --git a/extensions/microsoft/index.ts b/extensions/microsoft/index.ts index 358ea2057a0..db0bebbcc0b 100644 --- a/extensions/microsoft/index.ts +++ b/extensions/microsoft/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { buildMicrosoftSpeechProvider } from "../../src/tts/providers/microsoft.js"; +import { buildMicrosoftSpeechProvider } from "openclaw/plugin-sdk/speech"; const microsoftPlugin = { id: "microsoft", diff --git a/extensions/minimax/index.ts b/extensions/minimax/index.ts index 8dbe47f466c..30894be556d 100644 --- a/extensions/minimax/index.ts +++ b/extensions/minimax/index.ts @@ -6,14 +6,13 @@ import { type ProviderAuthResult, type ProviderCatalogContext, } from "openclaw/plugin-sdk/minimax-portal-auth"; -import { ensureAuthProfileStore, listProfilesForProvider } from "../../src/agents/auth-profiles.js"; -import { MINIMAX_OAUTH_MARKER } from "../../src/agents/model-auth-markers.js"; -import { fetchMinimaxUsage } from "../../src/infra/provider-usage.fetch.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; import { - minimaxMediaUnderstandingProvider, - minimaxPortalMediaUnderstandingProvider, -} from "./media-understanding-provider.js"; + MINIMAX_OAUTH_MARKER, + createProviderApiKeyAuthMethod, + ensureAuthProfileStore, + listProfilesForProvider, +} from "openclaw/plugin-sdk/provider-auth"; +import { fetchMinimaxUsage } from "openclaw/plugin-sdk/provider-usage"; import { loginMiniMaxPortalOAuth, type MiniMaxRegion } from "./oauth.js"; import { applyMinimaxApiConfig, applyMinimaxApiConfigCn } from "./onboard.js"; import { buildMinimaxPortalProvider, buildMinimaxProvider } from "./provider-catalog.js"; @@ -274,8 +273,6 @@ const minimaxPlugin = { ], isModernModelRef: ({ modelId }) => isModernMiniMaxModel(modelId), }); - api.registerMediaUnderstandingProvider(minimaxMediaUnderstandingProvider); - api.registerMediaUnderstandingProvider(minimaxPortalMediaUnderstandingProvider); }, }; diff --git a/extensions/minimax/onboard.ts b/extensions/minimax/onboard.ts index 6a2ff47e1f0..2edcf9637e4 100644 --- a/extensions/minimax/onboard.ts +++ b/extensions/minimax/onboard.ts @@ -1,14 +1,14 @@ -import { - applyAgentDefaultModelPrimary, - applyOnboardAuthAgentModelsAndProviders, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; import { buildMinimaxApiModelDefinition, MINIMAX_API_BASE_URL, MINIMAX_CN_API_BASE_URL, -} from "./model-definitions.js"; +} from "openclaw/plugin-sdk/provider-models"; +import { + applyAgentDefaultModelPrimary, + applyOnboardAuthAgentModelsAndProviders, + type ModelProviderConfig, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; type MinimaxApiProviderConfigParams = { providerId: string; diff --git a/extensions/minimax/provider-catalog.ts b/extensions/minimax/provider-catalog.ts index 83c1c46df13..ab8cceb9c53 100644 --- a/extensions/minimax/provider-catalog.ts +++ b/extensions/minimax/provider-catalog.ts @@ -1,4 +1,7 @@ -import type { ModelDefinitionConfig, ModelProviderConfig } from "../../src/config/types.models.js"; +import type { + ModelDefinitionConfig, + ModelProviderConfig, +} from "openclaw/plugin-sdk/provider-models"; const MINIMAX_PORTAL_BASE_URL = "https://api.minimax.io/anthropic"; export const MINIMAX_DEFAULT_MODEL_ID = "MiniMax-M2.5"; diff --git a/extensions/mistral/index.ts b/extensions/mistral/index.ts index 6da8e431759..72b3b6a60ac 100644 --- a/extensions/mistral/index.ts +++ b/extensions/mistral/index.ts @@ -1,6 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import { mistralMediaUnderstandingProvider } from "./media-understanding-provider.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyMistralConfig, MISTRAL_DEFAULT_MODEL_REF } from "./onboard.js"; const PROVIDER_ID = "mistral"; @@ -51,7 +50,6 @@ const mistralPlugin = { ], }, }); - api.registerMediaUnderstandingProvider(mistralMediaUnderstandingProvider); }, }; diff --git a/extensions/mistral/onboard.ts b/extensions/mistral/onboard.ts index 9a60e3f7c72..cefdeda2d01 100644 --- a/extensions/mistral/onboard.ts +++ b/extensions/mistral/onboard.ts @@ -1,16 +1,15 @@ -import { - applyAgentDefaultModelPrimary, - applyProviderConfigWithDefaultModel, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; import { buildMistralModelDefinition, MISTRAL_BASE_URL, MISTRAL_DEFAULT_MODEL_ID, - MISTRAL_DEFAULT_MODEL_REF, -} from "./model-definitions.js"; +} from "openclaw/plugin-sdk/provider-models"; +import { + applyAgentDefaultModelPrimary, + applyProviderConfigWithDefaultModel, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; -export { MISTRAL_DEFAULT_MODEL_REF }; +export const MISTRAL_DEFAULT_MODEL_REF = `mistral/${MISTRAL_DEFAULT_MODEL_ID}`; export function applyMistralProviderConfig(cfg: OpenClawConfig): OpenClawConfig { const models = { ...cfg.agents?.defaults?.models }; diff --git a/extensions/modelstudio/index.ts b/extensions/modelstudio/index.ts index e4dc27ee6df..ad5c1852b59 100644 --- a/extensions/modelstudio/index.ts +++ b/extensions/modelstudio/index.ts @@ -1,6 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyModelStudioConfig, applyModelStudioConfigCn, @@ -79,13 +78,22 @@ const modelStudioPlugin = { ], catalog: { order: "simple", - run: (ctx) => - buildSingleProviderApiKeyCatalog({ - ctx, - providerId: PROVIDER_ID, - buildProvider: buildModelStudioProvider, - allowExplicitBaseUrl: true, - }), + run: async (ctx) => { + const apiKey = ctx.resolveProviderApiKey(PROVIDER_ID).apiKey; + if (!apiKey) { + return null; + } + const explicitProvider = ctx.config.models?.providers?.[PROVIDER_ID]; + const explicitBaseUrl = + typeof explicitProvider?.baseUrl === "string" ? explicitProvider.baseUrl.trim() : ""; + return { + provider: { + ...buildModelStudioProvider(), + ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}), + apiKey, + }, + }; + }, }, }); }, diff --git a/extensions/modelstudio/onboard.ts b/extensions/modelstudio/onboard.ts index 9a8760b8550..881b742dde4 100644 --- a/extensions/modelstudio/onboard.ts +++ b/extensions/modelstudio/onboard.ts @@ -1,13 +1,13 @@ -import { - applyAgentDefaultModelPrimary, - applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; import { MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL, -} from "./model-definitions.js"; +} from "openclaw/plugin-sdk/provider-models"; +import { + applyAgentDefaultModelPrimary, + applyProviderConfigWithModelCatalog, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; import { buildModelStudioProvider } from "./provider-catalog.js"; export { MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL }; diff --git a/extensions/modelstudio/provider-catalog.ts b/extensions/modelstudio/provider-catalog.ts index ea9f2b2ae72..0908155a5f8 100644 --- a/extensions/modelstudio/provider-catalog.ts +++ b/extensions/modelstudio/provider-catalog.ts @@ -1,4 +1,7 @@ -import type { ModelDefinitionConfig, ModelProviderConfig } from "../../src/config/types.models.js"; +import type { + ModelDefinitionConfig, + ModelProviderConfig, +} from "openclaw/plugin-sdk/provider-models"; export const MODELSTUDIO_BASE_URL = "https://coding-intl.dashscope.aliyuncs.com/v1"; export const MODELSTUDIO_DEFAULT_MODEL_ID = "qwen3.5-plus"; diff --git a/extensions/moonshot/index.ts b/extensions/moonshot/index.ts index 5ef777edcc4..e8d7ecedb0c 100644 --- a/extensions/moonshot/index.ts +++ b/extensions/moonshot/index.ts @@ -1,17 +1,14 @@ +import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { createMoonshotThinkingWrapper, resolveMoonshotThinkingType, -} from "../../src/agents/pi-embedded-runner/moonshot-stream-wrappers.js"; +} from "openclaw/plugin-sdk/provider-stream"; import { createPluginBackedWebSearchProvider, getScopedCredentialValue, setScopedCredentialValue, -} from "../../src/agents/tools/web-search-plugin-factory.js"; -import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; -import type { OpenClawPluginApi } from "../../src/plugins/types.js"; -import { moonshotMediaUnderstandingProvider } from "./media-understanding-provider.js"; +} from "openclaw/plugin-sdk/provider-web-search"; import { applyMoonshotConfig, applyMoonshotConfigCn, @@ -36,8 +33,8 @@ const moonshotPlugin = { createProviderApiKeyAuthMethod({ providerId: PROVIDER_ID, methodId: "api-key", - label: "Moonshot API key (.ai)", - hint: "Kimi K2.5", + label: "Kimi API key (.ai)", + hint: "Kimi K2.5 + Kimi", optionKey: "moonshotApiKey", flagName: "--moonshot-api-key", envVar: "MOONSHOT_API_KEY", @@ -47,17 +44,17 @@ const moonshotPlugin = { applyConfig: (cfg) => applyMoonshotConfig(cfg), wizard: { choiceId: "moonshot-api-key", - choiceLabel: "Moonshot API key (.ai)", + choiceLabel: "Kimi API key (.ai)", groupId: "moonshot", groupLabel: "Moonshot AI (Kimi K2.5)", - groupHint: "Kimi K2.5", + groupHint: "Kimi K2.5 + Kimi", }, }), createProviderApiKeyAuthMethod({ providerId: PROVIDER_ID, methodId: "api-key-cn", - label: "Moonshot API key (.cn)", - hint: "Kimi K2.5", + label: "Kimi API key (.cn)", + hint: "Kimi K2.5 + Kimi", optionKey: "moonshotApiKey", flagName: "--moonshot-api-key", envVar: "MOONSHOT_API_KEY", @@ -67,22 +64,31 @@ const moonshotPlugin = { applyConfig: (cfg) => applyMoonshotConfigCn(cfg), wizard: { choiceId: "moonshot-api-key-cn", - choiceLabel: "Moonshot API key (.cn)", + choiceLabel: "Kimi API key (.cn)", groupId: "moonshot", groupLabel: "Moonshot AI (Kimi K2.5)", - groupHint: "Kimi K2.5", + groupHint: "Kimi K2.5 + Kimi", }, }), ], catalog: { order: "simple", - run: (ctx) => - buildSingleProviderApiKeyCatalog({ - ctx, - providerId: PROVIDER_ID, - buildProvider: buildMoonshotProvider, - allowExplicitBaseUrl: true, - }), + run: async (ctx) => { + const apiKey = ctx.resolveProviderApiKey(PROVIDER_ID).apiKey; + if (!apiKey) { + return null; + } + const explicitProvider = ctx.config.models?.providers?.[PROVIDER_ID]; + const explicitBaseUrl = + typeof explicitProvider?.baseUrl === "string" ? explicitProvider.baseUrl.trim() : ""; + return { + provider: { + ...buildMoonshotProvider(), + ...(explicitBaseUrl ? { baseUrl: explicitBaseUrl } : {}), + apiKey, + }, + }; + }, }, wrapStreamFn: (ctx) => { const thinkingType = resolveMoonshotThinkingType({ @@ -92,7 +98,6 @@ const moonshotPlugin = { return createMoonshotThinkingWrapper(ctx.streamFn, thinkingType); }, }); - api.registerMediaUnderstandingProvider(moonshotMediaUnderstandingProvider); api.registerWebSearchProvider( createPluginBackedWebSearchProvider({ id: "kimi", diff --git a/extensions/moonshot/onboard.ts b/extensions/moonshot/onboard.ts index 57459b724ce..61cc537a622 100644 --- a/extensions/moonshot/onboard.ts +++ b/extensions/moonshot/onboard.ts @@ -1,8 +1,8 @@ import { applyAgentDefaultModelPrimary, applyProviderConfigWithDefaultModel, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; import { buildMoonshotProvider, MOONSHOT_BASE_URL, diff --git a/extensions/moonshot/provider-catalog.ts b/extensions/moonshot/provider-catalog.ts index 86ab93e6e05..37f7213701e 100644 --- a/extensions/moonshot/provider-catalog.ts +++ b/extensions/moonshot/provider-catalog.ts @@ -1,4 +1,4 @@ -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-models"; export const MOONSHOT_BASE_URL = "https://api.moonshot.ai/v1"; export const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2.5"; diff --git a/extensions/msteams/src/outbound.ts b/extensions/msteams/src/outbound.ts index 60d78a2dac5..8f56ab2ce4c 100644 --- a/extensions/msteams/src/outbound.ts +++ b/extensions/msteams/src/outbound.ts @@ -1,5 +1,5 @@ +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/msteams"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; import { createMSTeamsPollStoreFs } from "./polls.js"; import { getMSTeamsRuntime } from "./runtime.js"; import { sendMessageMSTeams, sendPollMSTeams } from "./send.js"; diff --git a/extensions/nextcloud-talk/src/setup-core.ts b/extensions/nextcloud-talk/src/setup-core.ts index a94482b8d43..0b74753dcb6 100644 --- a/extensions/nextcloud-talk/src/setup-core.ts +++ b/extensions/nextcloud-talk/src/setup-core.ts @@ -1,21 +1,21 @@ +import type { ChannelSetupAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelSetupInput } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { + applyAccountNameToChannelSection, patchScopedAccountConfig, - prepareScopedSetupConfig, -} from "../../../src/channels/plugins/setup-helpers.js"; +} from "openclaw/plugin-sdk/setup"; import { mergeAllowFromEntries, resolveSetupAccountId, setSetupChannelEnabled, setTopLevelChannelDmPolicyWithAllowFrom, -} from "../../../src/channels/plugins/setup-wizard-helpers.js"; -import type { ChannelSetupDmPolicy } from "../../../src/channels/plugins/setup-wizard-types.js"; -import { type ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js"; -import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js"; -import type { ChannelSetupInput } from "../../../src/channels/plugins/types.core.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; -import type { WizardPrompter } from "../../../src/wizard/prompts.js"; +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup"; +import { type ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { formatDocsLink } from "openclaw/plugin-sdk/setup"; +import type { WizardPrompter } from "openclaw/plugin-sdk/setup"; import { listNextcloudTalkAccountIds, resolveDefaultNextcloudTalkAccountId, @@ -115,7 +115,7 @@ export function clearNextcloudTalkAccountFields( } as CoreConfig; } -export async function promptNextcloudTalkAllowFrom(params: { +async function promptNextcloudTalkAllowFrom(params: { cfg: CoreConfig; prompter: WizardPrompter; accountId: string; @@ -127,7 +127,7 @@ export async function promptNextcloudTalkAllowFrom(params: { "1) Check the Nextcloud admin panel for user IDs", "2) Or look at the webhook payload logs when someone messages", "3) User IDs are typically lowercase usernames in Nextcloud", - `Docs: ${formatDocsLink("/channels/nextcloud-talk", "channels/nextcloud-talk")}`, + `Docs: ${formatDocsLink("/channels/nextcloud-talk", "nextcloud-talk")}`, ].join("\n"), "Nextcloud Talk user id", ); @@ -158,7 +158,7 @@ export async function promptNextcloudTalkAllowFrom(params: { }); } -export async function promptNextcloudTalkAllowFromForAccount(params: { +async function promptNextcloudTalkAllowFromForAccount(params: { cfg: OpenClawConfig; prompter: WizardPrompter; accountId?: string; @@ -174,7 +174,7 @@ export async function promptNextcloudTalkAllowFromForAccount(params: { }); } -export const nextcloudTalkDmPolicy: ChannelSetupDmPolicy = { +const nextcloudTalkDmPolicy: ChannelSetupDmPolicy = { label: "Nextcloud Talk", channel, policyKey: "channels.nextcloud-talk.dmPolicy", @@ -187,7 +187,7 @@ export const nextcloudTalkDmPolicy: ChannelSetupDmPolicy = { export const nextcloudTalkSetupAdapter: ChannelSetupAdapter = { resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), applyAccountName: ({ cfg, accountId, name }) => - prepareScopedSetupConfig({ + applyAccountNameToChannelSection({ cfg, channelKey: channel, accountId, @@ -208,7 +208,7 @@ export const nextcloudTalkSetupAdapter: ChannelSetupAdapter = { }, applyAccountConfig: ({ cfg, accountId, input }) => { const setupInput = input as NextcloudSetupInput; - const namedConfig = prepareScopedSetupConfig({ + const namedConfig = applyAccountNameToChannelSection({ cfg, channelKey: channel, accountId, diff --git a/extensions/nextcloud-talk/src/setup-surface.ts b/extensions/nextcloud-talk/src/setup-surface.ts index 46561f5b274..ecb7b29084d 100644 --- a/extensions/nextcloud-talk/src/setup-surface.ts +++ b/extensions/nextcloud-talk/src/setup-surface.ts @@ -1,22 +1,111 @@ -import { setSetupChannelEnabled } from "../../../src/channels/plugins/setup-wizard-helpers.js"; -import { type ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js"; -import { hasConfiguredSecretInput } from "../../../src/config/types.secrets.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; -import { listNextcloudTalkAccountIds, resolveNextcloudTalkAccount } from "./accounts.js"; +import type { ChannelSetupInput } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { hasConfiguredSecretInput } from "openclaw/plugin-sdk/config-runtime"; +import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing"; +import { + mergeAllowFromEntries, + resolveSetupAccountId, + setSetupChannelEnabled, + setTopLevelChannelDmPolicyWithAllowFrom, +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup"; +import { type ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { formatDocsLink } from "openclaw/plugin-sdk/setup"; +import type { WizardPrompter } from "openclaw/plugin-sdk/setup"; +import { + listNextcloudTalkAccountIds, + resolveDefaultNextcloudTalkAccountId, + resolveNextcloudTalkAccount, +} from "./accounts.js"; import { clearNextcloudTalkAccountFields, - nextcloudTalkDmPolicy, nextcloudTalkSetupAdapter, normalizeNextcloudTalkBaseUrl, setNextcloudTalkAccountConfig, validateNextcloudTalkBaseUrl, } from "./setup-core.js"; -import type { CoreConfig } from "./types.js"; +import type { CoreConfig, DmPolicy } from "./types.js"; const channel = "nextcloud-talk" as const; const CONFIGURE_API_FLAG = "__nextcloudTalkConfigureApiCredentials"; +function setNextcloudTalkDmPolicy(cfg: CoreConfig, dmPolicy: DmPolicy): CoreConfig { + return setTopLevelChannelDmPolicyWithAllowFrom({ + cfg, + channel, + dmPolicy, + }) as CoreConfig; +} + +async function promptNextcloudTalkAllowFrom(params: { + cfg: CoreConfig; + prompter: WizardPrompter; + accountId: string; +}): Promise { + const resolved = resolveNextcloudTalkAccount({ cfg: params.cfg, accountId: params.accountId }); + const existingAllowFrom = resolved.config.allowFrom ?? []; + await params.prompter.note( + [ + "1) Check the Nextcloud admin panel for user IDs", + "2) Or look at the webhook payload logs when someone messages", + "3) User IDs are typically lowercase usernames in Nextcloud", + `Docs: ${formatDocsLink("/channels/nextcloud-talk", "channels/nextcloud-talk")}`, + ].join("\n"), + "Nextcloud Talk user id", + ); + + let resolvedIds: string[] = []; + while (resolvedIds.length === 0) { + const entry = await params.prompter.text({ + message: "Nextcloud Talk allowFrom (user id)", + placeholder: "username", + initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined, + validate: (value) => (String(value ?? "").trim() ? undefined : "Required"), + }); + resolvedIds = String(entry) + .split(/[\n,;]+/g) + .map((value) => value.trim().toLowerCase()) + .filter(Boolean); + if (resolvedIds.length === 0) { + await params.prompter.note("Please enter at least one valid user ID.", "Nextcloud Talk"); + } + } + + return setNextcloudTalkAccountConfig(params.cfg, params.accountId, { + dmPolicy: "allowlist", + allowFrom: mergeAllowFromEntries( + existingAllowFrom.map((value) => String(value).trim().toLowerCase()), + resolvedIds, + ), + }); +} + +async function promptNextcloudTalkAllowFromForAccount(params: { + cfg: OpenClawConfig; + prompter: WizardPrompter; + accountId?: string; +}): Promise { + const accountId = resolveSetupAccountId({ + accountId: params.accountId, + defaultAccountId: resolveDefaultNextcloudTalkAccountId(params.cfg as CoreConfig), + }); + return await promptNextcloudTalkAllowFrom({ + cfg: params.cfg as CoreConfig, + prompter: params.prompter, + accountId, + }); +} + +const nextcloudTalkDmPolicy: ChannelSetupDmPolicy = { + label: "Nextcloud Talk", + channel, + policyKey: "channels.nextcloud-talk.dmPolicy", + allowFromKey: "channels.nextcloud-talk.allowFrom", + getCurrent: (cfg) => cfg.channels?.["nextcloud-talk"]?.dmPolicy ?? "pairing", + setPolicy: (cfg, policy) => setNextcloudTalkDmPolicy(cfg as CoreConfig, policy as DmPolicy), + promptAllowFrom: promptNextcloudTalkAllowFromForAccount, +}; + export const nextcloudTalkSetupWizard: ChannelSetupWizard = { channel, stepOrder: "text-first", diff --git a/extensions/nostr/src/setup-surface.ts b/extensions/nostr/src/setup-surface.ts index e284d7b68a6..fca302e75fb 100644 --- a/extensions/nostr/src/setup-surface.ts +++ b/extensions/nostr/src/setup-surface.ts @@ -1,18 +1,18 @@ +import type { ChannelSetupAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing"; import { mergeAllowFromEntries, parseSetupEntriesWithParser, setTopLevelChannelAllowFrom, setTopLevelChannelDmPolicyWithAllowFrom, splitSetupEntries, -} from "../../../src/channels/plugins/setup-wizard-helpers.js"; -import type { ChannelSetupDmPolicy } from "../../../src/channels/plugins/setup-wizard-types.js"; -import type { ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js"; -import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { DmPolicy } from "../../../src/config/types.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; -import type { WizardPrompter } from "../../../src/wizard/prompts.js"; +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { formatDocsLink } from "openclaw/plugin-sdk/setup"; +import type { WizardPrompter } from "openclaw/plugin-sdk/setup"; import { DEFAULT_RELAYS } from "./default-relays.js"; import { getPublicKeyFromPrivate, normalizePubkey } from "./nostr-bus.js"; import { resolveNostrAccount } from "./types.js"; diff --git a/extensions/nvidia/provider-catalog.ts b/extensions/nvidia/provider-catalog.ts index f506839fa33..ce66986e20a 100644 --- a/extensions/nvidia/provider-catalog.ts +++ b/extensions/nvidia/provider-catalog.ts @@ -1,4 +1,4 @@ -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-models"; const NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1"; const NVIDIA_DEFAULT_MODEL_ID = "nvidia/llama-3.1-nemotron-70b-instruct"; diff --git a/extensions/ollama/index.ts b/extensions/ollama/index.ts index 5386a37d270..6f75f9b08a5 100644 --- a/extensions/ollama/index.ts +++ b/extensions/ollama/index.ts @@ -6,8 +6,7 @@ import { type ProviderAuthResult, type ProviderDiscoveryContext, } from "openclaw/plugin-sdk/core"; -import { OLLAMA_DEFAULT_BASE_URL } from "../../src/agents/ollama-defaults.js"; -import { resolveOllamaApiBase } from "../../src/agents/ollama-models.js"; +import { OLLAMA_DEFAULT_BASE_URL, resolveOllamaApiBase } from "openclaw/plugin-sdk/provider-models"; const PROVIDER_ID = "ollama"; const DEFAULT_API_KEY = "ollama-local"; diff --git a/extensions/openai/index.ts b/extensions/openai/index.ts index e45c9718087..831e49acdd8 100644 --- a/extensions/openai/index.ts +++ b/extensions/openai/index.ts @@ -1,6 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { buildOpenAISpeechProvider } from "../../src/tts/providers/openai.js"; -import { openaiMediaUnderstandingProvider } from "./media-understanding-provider.js"; +import { buildOpenAISpeechProvider } from "openclaw/plugin-sdk/speech"; import { buildOpenAICodexProviderPlugin } from "./openai-codex-provider.js"; import { buildOpenAIProvider } from "./openai-provider.js"; @@ -13,7 +12,6 @@ const openAIPlugin = { api.registerProvider(buildOpenAIProvider()); api.registerProvider(buildOpenAICodexProviderPlugin()); api.registerSpeechProvider(buildOpenAISpeechProvider()); - api.registerMediaUnderstandingProvider(openaiMediaUnderstandingProvider); }, }; diff --git a/extensions/openai/openai-codex-catalog.ts b/extensions/openai/openai-codex-catalog.ts index ecea655547b..11c1d564986 100644 --- a/extensions/openai/openai-codex-catalog.ts +++ b/extensions/openai/openai-codex-catalog.ts @@ -1,4 +1,4 @@ -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-models"; export const OPENAI_CODEX_BASE_URL = "https://chatgpt.com/backend-api"; diff --git a/extensions/openai/openai-codex-provider.ts b/extensions/openai/openai-codex-provider.ts index e8be8bd4eb1..6ea59a2e7a7 100644 --- a/extensions/openai/openai-codex-provider.ts +++ b/extensions/openai/openai-codex-provider.ts @@ -5,16 +5,20 @@ import type { ProviderRuntimeModel, } from "openclaw/plugin-sdk/core"; import { buildOauthProviderAuthResult } from "openclaw/plugin-sdk/core"; -import { CODEX_CLI_PROFILE_ID } from "../../src/agents/auth-profiles.js"; -import { listProfilesForProvider } from "../../src/agents/auth-profiles/profiles.js"; -import { ensureAuthProfileStore } from "../../src/agents/auth-profiles/store.js"; -import type { OAuthCredential } from "../../src/agents/auth-profiles/types.js"; -import { DEFAULT_CONTEXT_TOKENS } from "../../src/agents/defaults.js"; -import { normalizeModelCompat } from "../../src/agents/model-compat.js"; -import { normalizeProviderId } from "../../src/agents/provider-id.js"; -import { loginOpenAICodexOAuth } from "../../src/commands/openai-codex-oauth.js"; -import { fetchCodexUsage } from "../../src/infra/provider-usage.fetch.js"; -import type { ProviderPlugin } from "../../src/plugins/types.js"; +import { + CODEX_CLI_PROFILE_ID, + ensureAuthProfileStore, + listProfilesForProvider, + loginOpenAICodexOAuth, + type OAuthCredential, +} from "openclaw/plugin-sdk/provider-auth"; +import { + DEFAULT_CONTEXT_TOKENS, + normalizeModelCompat, + normalizeProviderId, + type ProviderPlugin, +} from "openclaw/plugin-sdk/provider-models"; +import { fetchCodexUsage } from "openclaw/plugin-sdk/provider-usage"; import { buildOpenAICodexProvider } from "./openai-codex-catalog.js"; import { cloneFirstTemplateModel, diff --git a/extensions/openai/openai-provider.ts b/extensions/openai/openai-provider.ts index 9c93ec1bd27..8e97b56573f 100644 --- a/extensions/openai/openai-provider.ts +++ b/extensions/openai/openai-provider.ts @@ -2,14 +2,14 @@ import { type ProviderResolveDynamicModelContext, type ProviderRuntimeModel, } from "openclaw/plugin-sdk/core"; -import { normalizeModelCompat } from "../../src/agents/model-compat.js"; -import { normalizeProviderId } from "../../src/agents/provider-id.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyOpenAIConfig, + normalizeModelCompat, + normalizeProviderId, OPENAI_DEFAULT_MODEL, -} from "../../src/commands/openai-model-default.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import type { ProviderPlugin } from "../../src/plugins/types.js"; + type ProviderPlugin, +} from "openclaw/plugin-sdk/provider-models"; import { cloneFirstTemplateModel, findCatalogTemplate, diff --git a/extensions/openai/shared.ts b/extensions/openai/shared.ts index ad469a2f136..2b67454fc07 100644 --- a/extensions/openai/shared.ts +++ b/extensions/openai/shared.ts @@ -1,9 +1,8 @@ -import { normalizeModelCompat } from "../../src/agents/model-compat.js"; -import { findCatalogTemplate } from "../../src/plugins/provider-catalog.js"; import type { ProviderResolveDynamicModelContext, ProviderRuntimeModel, -} from "../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/core"; +import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-models"; export const OPENAI_API_BASE_URL = "https://api.openai.com/v1"; @@ -49,4 +48,18 @@ export function cloneFirstTemplateModel(params: { return undefined; } -export { findCatalogTemplate }; +export function findCatalogTemplate(params: { + entries: ReadonlyArray<{ provider: string; id: string }>; + providerId: string; + templateIds: readonly string[]; +}) { + return params.templateIds + .map((templateId) => + params.entries.find( + (entry) => + entry.provider.toLowerCase() === params.providerId.toLowerCase() && + entry.id.toLowerCase() === templateId.toLowerCase(), + ), + ) + .find((entry) => entry !== undefined); +} diff --git a/extensions/opencode-go/index.ts b/extensions/opencode-go/index.ts index ddfd9a5858c..09319628684 100644 --- a/extensions/opencode-go/index.ts +++ b/extensions/opencode-go/index.ts @@ -1,6 +1,6 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { OPENCODE_GO_DEFAULT_MODEL_REF } from "../../src/commands/opencode-go-model-default.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { OPENCODE_GO_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models"; import { applyOpencodeGoConfig } from "./onboard.js"; const PROVIDER_ID = "opencode-go"; diff --git a/extensions/opencode-go/onboard.ts b/extensions/opencode-go/onboard.ts index 8ca47a0f9d0..ec5727f9525 100644 --- a/extensions/opencode-go/onboard.ts +++ b/extensions/opencode-go/onboard.ts @@ -1,6 +1,8 @@ -import { applyAgentDefaultModelPrimary } from "../../src/commands/onboard-auth.config-shared.js"; -import { OPENCODE_GO_DEFAULT_MODEL_REF } from "../../src/commands/opencode-go-model-default.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; +import { OPENCODE_GO_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models"; +import { + applyAgentDefaultModelPrimary, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export { OPENCODE_GO_DEFAULT_MODEL_REF }; diff --git a/extensions/opencode/index.ts b/extensions/opencode/index.ts index 01ccea24656..4f9bbb1384a 100644 --- a/extensions/opencode/index.ts +++ b/extensions/opencode/index.ts @@ -1,6 +1,6 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { OPENCODE_ZEN_DEFAULT_MODEL } from "../../src/commands/opencode-zen-model-default.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { OPENCODE_ZEN_DEFAULT_MODEL } from "openclaw/plugin-sdk/provider-models"; import { applyOpencodeZenConfig } from "./onboard.js"; const PROVIDER_ID = "opencode"; diff --git a/extensions/opencode/onboard.ts b/extensions/opencode/onboard.ts index a308129b688..5bccbb34d8a 100644 --- a/extensions/opencode/onboard.ts +++ b/extensions/opencode/onboard.ts @@ -1,6 +1,8 @@ -import { OPENCODE_ZEN_DEFAULT_MODEL_REF } from "../../src/agents/opencode-zen-models.js"; -import { applyAgentDefaultModelPrimary } from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; +import { OPENCODE_ZEN_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models"; +import { + applyAgentDefaultModelPrimary, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export { OPENCODE_ZEN_DEFAULT_MODEL_REF }; diff --git a/extensions/openrouter/index.ts b/extensions/openrouter/index.ts index 2246424787a..b4c1d908c4f 100644 --- a/extensions/openrouter/index.ts +++ b/extensions/openrouter/index.ts @@ -5,17 +5,15 @@ import { type ProviderResolveDynamicModelContext, type ProviderRuntimeModel, } from "openclaw/plugin-sdk/core"; -import { DEFAULT_CONTEXT_TOKENS } from "../../src/agents/defaults.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { DEFAULT_CONTEXT_TOKENS } from "openclaw/plugin-sdk/provider-models"; import { getOpenRouterModelCapabilities, loadOpenRouterModelCapabilities, -} from "../../src/agents/pi-embedded-runner/openrouter-model-capabilities.js"; -import { createOpenRouterSystemCacheWrapper, createOpenRouterWrapper, isProxyReasoningUnsupported, -} from "../../src/agents/pi-embedded-runner/proxy-stream-wrappers.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +} from "openclaw/plugin-sdk/provider-stream"; import { applyOpenrouterConfig, OPENROUTER_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildOpenrouterProvider } from "./provider-catalog.js"; diff --git a/extensions/openrouter/onboard.ts b/extensions/openrouter/onboard.ts index 03ec7bf86bc..f5662399192 100644 --- a/extensions/openrouter/onboard.ts +++ b/extensions/openrouter/onboard.ts @@ -1,5 +1,7 @@ -import { applyAgentDefaultModelPrimary } from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; +import { + applyAgentDefaultModelPrimary, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export const OPENROUTER_DEFAULT_MODEL_REF = "openrouter/auto"; diff --git a/extensions/openrouter/provider-catalog.ts b/extensions/openrouter/provider-catalog.ts index cfb5fecf8bf..52be862e34d 100644 --- a/extensions/openrouter/provider-catalog.ts +++ b/extensions/openrouter/provider-catalog.ts @@ -1,4 +1,4 @@ -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-models"; const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"; const OPENROUTER_DEFAULT_MODEL_ID = "auto"; diff --git a/extensions/perplexity/index.ts b/extensions/perplexity/index.ts index 513c70d131d..0fe3034a000 100644 --- a/extensions/perplexity/index.ts +++ b/extensions/perplexity/index.ts @@ -1,10 +1,9 @@ +import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; import { createPluginBackedWebSearchProvider, getScopedCredentialValue, setScopedCredentialValue, -} from "../../src/agents/tools/web-search-plugin-factory.js"; -import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js"; -import type { OpenClawPluginApi } from "../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/provider-web-search"; const perplexityPlugin = { id: "perplexity", diff --git a/extensions/qianfan/index.ts b/extensions/qianfan/index.ts index 04bd8429755..e8f2f2cc59d 100644 --- a/extensions/qianfan/index.ts +++ b/extensions/qianfan/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyQianfanConfig, QIANFAN_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; import { buildQianfanProvider } from "./provider-catalog.js"; diff --git a/extensions/qianfan/onboard.ts b/extensions/qianfan/onboard.ts index 6df59e49a40..c389868c7d8 100644 --- a/extensions/qianfan/onboard.ts +++ b/extensions/qianfan/onboard.ts @@ -1,9 +1,9 @@ import { applyAgentDefaultModelPrimary, applyProviderConfigWithDefaultModels, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; -import type { ModelApi } from "../../src/config/types.models.js"; + type ModelApi, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; import { buildQianfanProvider, QIANFAN_BASE_URL, diff --git a/extensions/qianfan/provider-catalog.ts b/extensions/qianfan/provider-catalog.ts index f96fca8e14c..c8aee208a8e 100644 --- a/extensions/qianfan/provider-catalog.ts +++ b/extensions/qianfan/provider-catalog.ts @@ -1,4 +1,4 @@ -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-models"; export const QIANFAN_BASE_URL = "https://qianfan.baidubce.com/v2"; export const QIANFAN_DEFAULT_MODEL_ID = "deepseek-v3.2"; diff --git a/extensions/qwen-portal-auth/index.ts b/extensions/qwen-portal-auth/index.ts index 7c64c9b7683..2a9538a33ab 100644 --- a/extensions/qwen-portal-auth/index.ts +++ b/extensions/qwen-portal-auth/index.ts @@ -1,3 +1,5 @@ +import { ensureAuthProfileStore, listProfilesForProvider } from "openclaw/plugin-sdk/agent-runtime"; +import { QWEN_OAUTH_MARKER } from "openclaw/plugin-sdk/agent-runtime"; import { buildOauthProviderAuthResult, emptyPluginConfigSchema, @@ -5,9 +7,7 @@ import { type ProviderAuthContext, type ProviderCatalogContext, } from "openclaw/plugin-sdk/qwen-portal-auth"; -import { ensureAuthProfileStore, listProfilesForProvider } from "../../src/agents/auth-profiles.js"; -import { QWEN_OAUTH_MARKER } from "../../src/agents/model-auth-markers.js"; -import { refreshQwenPortalCredentials } from "../../src/providers/qwen-portal-oauth.js"; +import { refreshQwenPortalCredentials } from "openclaw/plugin-sdk/qwen-portal-auth"; import { loginQwenPortalOAuth } from "./oauth.js"; import { buildQwenPortalProvider, QWEN_PORTAL_BASE_URL } from "./provider-catalog.js"; diff --git a/extensions/qwen-portal-auth/provider-catalog.ts b/extensions/qwen-portal-auth/provider-catalog.ts index aa038c0810e..f8d350fc2da 100644 --- a/extensions/qwen-portal-auth/provider-catalog.ts +++ b/extensions/qwen-portal-auth/provider-catalog.ts @@ -1,4 +1,7 @@ -import type { ModelDefinitionConfig, ModelProviderConfig } from "../../src/config/types.models.js"; +import type { + ModelDefinitionConfig, + ModelProviderConfig, +} from "openclaw/plugin-sdk/provider-models"; export const QWEN_PORTAL_BASE_URL = "https://portal.qwen.ai/v1"; const QWEN_PORTAL_DEFAULT_CONTEXT_WINDOW = 128000; diff --git a/extensions/sglang/index.ts b/extensions/sglang/index.ts index fc7522ef15b..9918c7ee98b 100644 --- a/extensions/sglang/index.ts +++ b/extensions/sglang/index.ts @@ -1,14 +1,14 @@ -import { - emptyPluginConfigSchema, - type OpenClawPluginApi, - type ProviderAuthMethodNonInteractiveContext, -} from "openclaw/plugin-sdk/core"; import { SGLANG_DEFAULT_API_KEY_ENV_VAR, SGLANG_DEFAULT_BASE_URL, SGLANG_MODEL_PLACEHOLDER, SGLANG_PROVIDER_LABEL, -} from "../../src/agents/sglang-defaults.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { + emptyPluginConfigSchema, + type OpenClawPluginApi, + type ProviderAuthMethodNonInteractiveContext, +} from "openclaw/plugin-sdk/core"; const PROVIDER_ID = "sglang"; diff --git a/extensions/signal/src/accounts.ts b/extensions/signal/src/accounts.ts index 30a3b56189c..456db907685 100644 --- a/extensions/signal/src/accounts.ts +++ b/extensions/signal/src/accounts.ts @@ -1,10 +1,10 @@ import { - type OpenClawConfig, createAccountListHelpers, normalizeAccountId, resolveAccountEntry, -} from "../../../src/plugin-sdk-internal/accounts.js"; -import type { SignalAccountConfig } from "../../../src/plugin-sdk-internal/signal.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/account-resolution"; +import type { SignalAccountConfig } from "openclaw/plugin-sdk/signal"; export type ResolvedSignalAccount = { accountId: string; diff --git a/extensions/signal/src/channel.setup.ts b/extensions/signal/src/channel.setup.ts index d633ff6a251..b81d10cc99d 100644 --- a/extensions/signal/src/channel.setup.ts +++ b/extensions/signal/src/channel.setup.ts @@ -1,9 +1,94 @@ -import { type ChannelPlugin } from "openclaw/plugin-sdk/signal"; -import { type ResolvedSignalAccount } from "./accounts.js"; +import { + buildAccountScopedDmSecurityPolicy, + collectAllowlistProviderRestrictSendersWarnings, +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { + buildChannelConfigSchema, + DEFAULT_ACCOUNT_ID, + deleteAccountFromConfigSection, + getChatChannelMeta, + normalizeE164, + setAccountEnabledInConfigSection, + SignalConfigSchema, + type ChannelPlugin, +} from "openclaw/plugin-sdk/signal"; +import { + listSignalAccountIds, + resolveDefaultSignalAccountId, + resolveSignalAccount, + type ResolvedSignalAccount, +} from "./accounts.js"; +import { signalConfigAccessors, signalSetupWizard } from "./plugin-shared.js"; import { signalSetupAdapter } from "./setup-core.js"; -import { createSignalPluginBase, signalSetupWizard } from "./shared.js"; -export const signalSetupPlugin: ChannelPlugin = createSignalPluginBase({ +export const signalSetupPlugin: ChannelPlugin = { + id: "signal", + meta: { + ...getChatChannelMeta("signal"), + }, setupWizard: signalSetupWizard, + capabilities: { + chatTypes: ["direct", "group"], + media: true, + reactions: true, + }, + streaming: { + blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 }, + }, + reload: { configPrefixes: ["channels.signal"] }, + configSchema: buildChannelConfigSchema(SignalConfigSchema), + config: { + listAccountIds: (cfg) => listSignalAccountIds(cfg), + resolveAccount: (cfg, accountId) => resolveSignalAccount({ cfg, accountId }), + defaultAccountId: (cfg) => resolveDefaultSignalAccountId(cfg), + setAccountEnabled: ({ cfg, accountId, enabled }) => + setAccountEnabledInConfigSection({ + cfg, + sectionKey: "signal", + accountId, + enabled, + allowTopLevel: true, + }), + deleteAccount: ({ cfg, accountId }) => + deleteAccountFromConfigSection({ + cfg, + sectionKey: "signal", + accountId, + clearBaseFields: ["account", "httpUrl", "httpHost", "httpPort", "cliPath", "name"], + }), + isConfigured: (account) => account.configured, + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: account.configured, + baseUrl: account.baseUrl, + }), + ...signalConfigAccessors, + }, + security: { + resolveDmPolicy: ({ cfg, accountId, account }) => + buildAccountScopedDmSecurityPolicy({ + cfg, + channelKey: "signal", + accountId, + fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID, + policy: account.config.dmPolicy, + allowFrom: account.config.allowFrom ?? [], + policyPathSuffix: "dmPolicy", + normalizeEntry: (raw) => normalizeE164(raw.replace(/^signal:/i, "").trim()), + }), + collectWarnings: ({ account, cfg }) => + collectAllowlistProviderRestrictSendersWarnings({ + cfg, + providerConfigPresent: cfg.channels?.signal !== undefined, + configuredGroupPolicy: account.config.groupPolicy, + surface: "Signal groups", + openScope: "any member", + groupPolicyPath: "channels.signal.groupPolicy", + groupAllowFromPath: "channels.signal.groupAllowFrom", + mentionGated: false, + }), + }, setup: signalSetupAdapter, -}); +}; diff --git a/extensions/signal/src/channel.ts b/extensions/signal/src/channel.ts index 2b392bbacf2..aba60d3e29a 100644 --- a/extensions/signal/src/channel.ts +++ b/extensions/signal/src/channel.ts @@ -1,21 +1,31 @@ -import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/compat"; +import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/allowlist-config-edit"; +import { + buildAccountScopedDmSecurityPolicy, + collectAllowlistProviderRestrictSendersWarnings, +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; import { buildAgentSessionKey, type RoutePeer } from "openclaw/plugin-sdk/core"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; import { buildBaseAccountStatusSnapshot, buildBaseChannelStatusSummary, + buildChannelConfigSchema, collectStatusIssuesFromLastError, createDefaultChannelRuntimeState, DEFAULT_ACCOUNT_ID, + deleteAccountFromConfigSection, + getChatChannelMeta, looksLikeSignalTargetId, + normalizeE164, normalizeSignalMessagingTarget, PAIRING_APPROVED_MESSAGE, resolveChannelMediaMaxBytes, + setAccountEnabledInConfigSection, + 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"; import { listSignalAccountIds, resolveDefaultSignalAccountId, @@ -29,10 +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 { signalSetupAdapter } from "./setup-core.js"; -import { createSignalPluginBase, signalConfigAccessors, signalSetupWizard } from "./shared.js"; const signalMessageActions: ChannelMessageActionAdapter = { listActions: (ctx) => getSignalRuntime().channel.signal.messageActions?.listActions?.(ctx) ?? [], @@ -282,10 +292,11 @@ async function sendFormattedSignalMedia(ctx: { } export const signalPlugin: ChannelPlugin = { - ...createSignalPluginBase({ - setupWizard: signalSetupWizard, - setup: signalSetupAdapter, - }), + id: "signal", + meta: { + ...getChatChannelMeta("signal"), + }, + setupWizard: signalSetupWizard, pairing: { idLabel: "signalNumber", normalizeAllowEntry: (entry) => entry.replace(/^signal:/i, ""), @@ -293,7 +304,46 @@ export const signalPlugin: ChannelPlugin = { await getSignalRuntime().channel.signal.sendMessageSignal(id, PAIRING_APPROVED_MESSAGE); }, }, + capabilities: { + chatTypes: ["direct", "group"], + media: true, + reactions: true, + }, actions: signalMessageActions, + streaming: { + blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 }, + }, + reload: { configPrefixes: ["channels.signal"] }, + configSchema: buildChannelConfigSchema(SignalConfigSchema), + config: { + listAccountIds: (cfg) => listSignalAccountIds(cfg), + resolveAccount: (cfg, accountId) => resolveSignalAccount({ cfg, accountId }), + defaultAccountId: (cfg) => resolveDefaultSignalAccountId(cfg), + setAccountEnabled: ({ cfg, accountId, enabled }) => + setAccountEnabledInConfigSection({ + cfg, + sectionKey: "signal", + accountId, + enabled, + allowTopLevel: true, + }), + deleteAccount: ({ cfg, accountId }) => + deleteAccountFromConfigSection({ + cfg, + sectionKey: "signal", + accountId, + clearBaseFields: ["account", "httpUrl", "httpHost", "httpPort", "cliPath", "name"], + }), + isConfigured: (account) => account.configured, + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: account.configured, + baseUrl: account.baseUrl, + }), + ...signalConfigAccessors, + }, allowlist: { supportsScope: ({ scope }) => scope === "dm" || scope === "group" || scope === "all", readConfig: ({ cfg, accountId }) => { @@ -315,6 +365,32 @@ export const signalPlugin: ChannelPlugin = { }), }), }, + security: { + resolveDmPolicy: ({ cfg, accountId, account }) => { + return buildAccountScopedDmSecurityPolicy({ + cfg, + channelKey: "signal", + accountId, + fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID, + policy: account.config.dmPolicy, + allowFrom: account.config.allowFrom ?? [], + policyPathSuffix: "dmPolicy", + normalizeEntry: (raw) => normalizeE164(raw.replace(/^signal:/i, "").trim()), + }); + }, + collectWarnings: ({ account, cfg }) => { + return collectAllowlistProviderRestrictSendersWarnings({ + cfg, + providerConfigPresent: cfg.channels?.signal !== undefined, + configuredGroupPolicy: account.config.groupPolicy, + surface: "Signal groups", + openScope: "any member", + groupPolicyPath: "channels.signal.groupPolicy", + groupAllowFromPath: "channels.signal.groupAllowFrom", + mentionGated: false, + }); + }, + }, messaging: { normalizeTarget: normalizeSignalMessagingTarget, parseExplicitTarget: ({ raw }) => parseSignalExplicitTarget(raw), @@ -325,6 +401,7 @@ export const signalPlugin: ChannelPlugin = { hint: "", }, }, + setup: signalSetupAdapter, outbound: { deliveryMode: "direct", chunker: (text, limit) => getSignalRuntime().channel.text.chunkText(text, limit), diff --git a/extensions/signal/src/client.ts b/extensions/signal/src/client.ts index 394aec4e297..4a6d63bd685 100644 --- a/extensions/signal/src/client.ts +++ b/extensions/signal/src/client.ts @@ -1,6 +1,6 @@ -import { resolveFetch } from "../../../src/infra/fetch.js"; -import { generateSecureUuid } from "../../../src/infra/secure-random.js"; -import { fetchWithTimeout } from "../../../src/utils/fetch-timeout.js"; +import { resolveFetch } from "openclaw/plugin-sdk/infra-runtime"; +import { generateSecureUuid } from "openclaw/plugin-sdk/infra-runtime"; +import { fetchWithTimeout } from "openclaw/plugin-sdk/text-runtime"; export type SignalRpcOptions = { baseUrl: string; diff --git a/extensions/signal/src/daemon.ts b/extensions/signal/src/daemon.ts index d53597a296b..028b9fbe964 100644 --- a/extensions/signal/src/daemon.ts +++ b/extensions/signal/src/daemon.ts @@ -1,5 +1,5 @@ import { spawn } from "node:child_process"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; export type SignalDaemonOpts = { cliPath: string; diff --git a/extensions/signal/src/format.ts b/extensions/signal/src/format.ts index 2180693293e..73574832df8 100644 --- a/extensions/signal/src/format.ts +++ b/extensions/signal/src/format.ts @@ -1,10 +1,10 @@ -import type { MarkdownTableMode } from "../../../src/config/types.base.js"; +import type { MarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; import { chunkMarkdownIR, markdownToIR, type MarkdownIR, type MarkdownStyle, -} from "../../../src/markdown/ir.js"; +} from "openclaw/plugin-sdk/text-runtime"; type SignalTextStyle = "BOLD" | "ITALIC" | "STRIKETHROUGH" | "MONOSPACE" | "SPOILER"; diff --git a/extensions/signal/src/identity.ts b/extensions/signal/src/identity.ts index 464713559c3..dbd86ca1584 100644 --- a/extensions/signal/src/identity.ts +++ b/extensions/signal/src/identity.ts @@ -1,5 +1,5 @@ -import { evaluateSenderGroupAccessForPolicy } from "../../../src/plugin-sdk-internal/signal.js"; -import { normalizeE164 } from "../../../src/utils.js"; +import { evaluateSenderGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access"; +import { normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; export type SignalSender = | { kind: "phone"; raw: string; e164: string } diff --git a/extensions/signal/src/monitor.tool-result.test-harness.ts b/extensions/signal/src/monitor.tool-result.test-harness.ts index 252e039b0fb..10cf32b383a 100644 --- a/extensions/signal/src/monitor.tool-result.test-harness.ts +++ b/extensions/signal/src/monitor.tool-result.test-harness.ts @@ -1,7 +1,7 @@ +import { resetSystemEventsForTest } from "openclaw/plugin-sdk/infra-runtime"; +import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-runtime"; +import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { beforeEach, vi } from "vitest"; -import { resetInboundDedupe } from "../../../src/auto-reply/reply/inbound-dedupe.js"; -import { resetSystemEventsForTest } from "../../../src/infra/system-events.js"; -import type { MockFn } from "../../../src/test-utils/vitest-mock-fn.js"; import type { SignalDaemonExitEvent, SignalDaemonHandle } from "./daemon.js"; type SignalToolResultTestMocks = { @@ -68,15 +68,15 @@ export function createMockSignalDaemonHandle( }; } -vi.mock("../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig: () => config, }; }); -vi.mock("../../../src/auto-reply/reply.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ getReplyFromConfig: (...args: unknown[]) => replyMock(...args), })); @@ -86,13 +86,13 @@ vi.mock("./send.js", () => ({ sendReadReceiptSignal: vi.fn().mockResolvedValue(true), })); -vi.mock("../../../src/pairing/pairing-store.js", () => ({ +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args), upsertChannelPairingRequest: (...args: unknown[]) => upsertPairingRequestMock(...args), })); -vi.mock("../../../src/config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), @@ -116,7 +116,7 @@ vi.mock("./daemon.js", async (importOriginal) => { }; }); -vi.mock("../../../src/infra/transport-ready.js", () => ({ +vi.mock("openclaw/plugin-sdk/infra-runtime", () => ({ waitForTransportReady: (...args: unknown[]) => waitForTransportReadyMock(...args), })); diff --git a/extensions/signal/src/monitor.ts b/extensions/signal/src/monitor.ts index 3febfe740d4..02fd94ff8b8 100644 --- a/extensions/signal/src/monitor.ts +++ b/extensions/signal/src/monitor.ts @@ -1,27 +1,24 @@ -import { - chunkTextWithMode, - resolveChunkMode, - resolveTextChunkLimit, -} from "../../../src/auto-reply/chunk.js"; -import { - DEFAULT_GROUP_HISTORY_LIMIT, - type HistoryEntry, -} from "../../../src/auto-reply/reply/history.js"; -import type { ReplyPayload } from "../../../src/auto-reply/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { loadConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce, -} from "../../../src/config/runtime-group-policy.js"; -import type { SignalReactionNotificationMode } from "../../../src/config/types.js"; -import type { BackoffPolicy } from "../../../src/infra/backoff.js"; -import { waitForTransportReady } from "../../../src/infra/transport-ready.js"; -import { saveMediaBuffer } from "../../../src/media/store.js"; -import { createNonExitingRuntime, type RuntimeEnv } from "../../../src/runtime.js"; -import { normalizeStringEntries } from "../../../src/shared/string-normalization.js"; -import { normalizeE164 } from "../../../src/utils.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import type { SignalReactionNotificationMode } from "openclaw/plugin-sdk/config-runtime"; +import type { BackoffPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import { waitForTransportReady } from "openclaw/plugin-sdk/infra-runtime"; +import { saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime"; +import { + chunkTextWithMode, + resolveChunkMode, + resolveTextChunkLimit, +} from "openclaw/plugin-sdk/reply-runtime"; +import { DEFAULT_GROUP_HISTORY_LIMIT, type HistoryEntry } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { normalizeStringEntries } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import { resolveSignalAccount } from "./accounts.js"; import { signalCheck, signalRpcRequest } from "./client.js"; import { formatSignalDaemonExit, spawnSignalDaemon, type SignalDaemonHandle } from "./daemon.js"; diff --git a/extensions/signal/src/monitor/access-policy.ts b/extensions/signal/src/monitor/access-policy.ts index 72555186031..de083efd9fd 100644 --- a/extensions/signal/src/monitor/access-policy.ts +++ b/extensions/signal/src/monitor/access-policy.ts @@ -1,9 +1,9 @@ -import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js"; -import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js"; +import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime"; +import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime"; import { readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithLists, -} from "../../../../src/security/dm-policy-shared.js"; +} from "openclaw/plugin-sdk/security-runtime"; import { isSignalSenderAllowed, type SignalSender } from "../identity.js"; type SignalDmPolicy = "open" | "pairing" | "allowlist" | "disabled"; diff --git a/extensions/signal/src/monitor/event-handler.ts b/extensions/signal/src/monitor/event-handler.ts index 36eb0e8d276..c8f9da661a0 100644 --- a/extensions/signal/src/monitor/event-handler.ts +++ b/extensions/signal/src/monitor/event-handler.ts @@ -1,44 +1,41 @@ -import { resolveHumanDelayConfig } from "../../../../src/agents/identity.js"; -import { hasControlCommand } from "../../../../src/auto-reply/command-detection.js"; -import { dispatchInboundMessage } from "../../../../src/auto-reply/dispatch.js"; +import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime"; +import { resolveControlCommandGate } from "openclaw/plugin-sdk/channel-runtime"; +import { + createChannelInboundDebouncer, + shouldDebounceTextInbound, +} from "openclaw/plugin-sdk/channel-runtime"; +import { logInboundDrop, logTypingFailure } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk/channel-runtime"; +import { normalizeSignalMessagingTarget } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime"; +import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/config-runtime"; +import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { kindFromMime } from "openclaw/plugin-sdk/media-runtime"; +import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchInboundMessage } from "openclaw/plugin-sdk/reply-runtime"; import { formatInboundEnvelope, formatInboundFromLabel, resolveEnvelopeFormatOptions, -} from "../../../../src/auto-reply/envelope.js"; +} from "openclaw/plugin-sdk/reply-runtime"; import { buildPendingHistoryContextFromMap, clearHistoryEntriesIfEnabled, recordPendingHistoryEntryIfEnabled, -} from "../../../../src/auto-reply/reply/history.js"; -import { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js"; -import { - buildMentionRegexes, - matchesMentionPatterns, -} from "../../../../src/auto-reply/reply/mentions.js"; -import { createReplyDispatcherWithTyping } from "../../../../src/auto-reply/reply/reply-dispatcher.js"; -import { resolveControlCommandGate } from "../../../../src/channels/command-gating.js"; -import { - createChannelInboundDebouncer, - shouldDebounceTextInbound, -} from "../../../../src/channels/inbound-debounce-policy.js"; -import { logInboundDrop, logTypingFailure } from "../../../../src/channels/logging.js"; -import { resolveMentionGatingWithBypass } from "../../../../src/channels/mention-gating.js"; -import { normalizeSignalMessagingTarget } from "../../../../src/channels/plugins/normalize/signal.js"; -import { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js"; -import { recordInboundSession } from "../../../../src/channels/session.js"; -import { createTypingCallbacks } from "../../../../src/channels/typing.js"; -import { resolveChannelGroupRequireMention } from "../../../../src/config/group-policy.js"; -import { readSessionUpdatedAt, resolveStorePath } from "../../../../src/config/sessions.js"; -import { danger, logVerbose, shouldLogVerbose } from "../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../src/infra/system-events.js"; -import { kindFromMime } from "../../../../src/media/mime.js"; -import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import { buildMentionRegexes, matchesMentionPatterns } from "openclaw/plugin-sdk/reply-runtime"; +import { createReplyDispatcherWithTyping } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; import { DM_GROUP_ACCESS_REASON, resolvePinnedMainDmOwnerFromAllowlist, -} from "../../../../src/security/dm-policy-shared.js"; -import { normalizeE164 } from "../../../../src/utils.js"; +} from "openclaw/plugin-sdk/security-runtime"; +import { normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import { formatSignalPairingIdLine, formatSignalSenderDisplay, diff --git a/extensions/signal/src/monitor/event-handler.types.ts b/extensions/signal/src/monitor/event-handler.types.ts index c1d0b0b3881..82a96af73cc 100644 --- a/extensions/signal/src/monitor/event-handler.types.ts +++ b/extensions/signal/src/monitor/event-handler.types.ts @@ -1,12 +1,12 @@ -import type { HistoryEntry } from "../../../../src/auto-reply/reply/history.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import type { OpenClawConfig } from "../../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { DmPolicy, GroupPolicy, SignalReactionNotificationMode, -} from "../../../../src/config/types.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import type { HistoryEntry } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import type { SignalSender } from "../identity.js"; export type SignalEnvelope = { diff --git a/extensions/signal/src/outbound-adapter.ts b/extensions/signal/src/outbound-adapter.ts index b0d77c12bd0..cd61b825981 100644 --- a/extensions/signal/src/outbound-adapter.ts +++ b/extensions/signal/src/outbound-adapter.ts @@ -1,11 +1,8 @@ -import { resolveTextChunkLimit } from "../../../src/auto-reply/chunk.js"; -import { createScopedChannelMediaMaxBytesResolver } from "../../../src/channels/plugins/outbound/direct-text-media.js"; -import type { ChannelOutboundAdapter } from "../../../src/channels/plugins/types.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { - resolveOutboundSendDep, - type OutboundSendDeps, -} from "../../../src/infra/outbound/send-deps.js"; +import { createScopedChannelMediaMaxBytesResolver } from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveOutboundSendDep, type OutboundSendDeps } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; import { markdownToSignalTextChunks } from "./format.js"; import { sendMessageSignal } from "./send.js"; diff --git a/extensions/signal/src/plugin-shared.ts b/extensions/signal/src/plugin-shared.ts index 60559f09dcb..a5713e4c361 100644 --- a/extensions/signal/src/plugin-shared.ts +++ b/extensions/signal/src/plugin-shared.ts @@ -1,5 +1,5 @@ -import { createScopedAccountConfigAccessors } from "../../../src/plugin-sdk-internal/channel-config.js"; -import { normalizeE164, type OpenClawConfig } from "../../../src/plugin-sdk-internal/signal.js"; +import { createScopedAccountConfigAccessors } from "openclaw/plugin-sdk/channel-config-helpers"; +import { normalizeE164, type OpenClawConfig } from "openclaw/plugin-sdk/signal"; import { resolveSignalAccount, type ResolvedSignalAccount } from "./accounts.js"; import { createSignalSetupWizardProxy } from "./setup-core.js"; diff --git a/extensions/signal/src/probe.ts b/extensions/signal/src/probe.ts index bf200effd6d..ac7dce428e8 100644 --- a/extensions/signal/src/probe.ts +++ b/extensions/signal/src/probe.ts @@ -1,4 +1,4 @@ -import type { BaseProbeResult } from "../../../src/channels/plugins/types.js"; +import type { BaseProbeResult } from "openclaw/plugin-sdk/channel-runtime"; import { signalCheck, signalRpcRequest } from "./client.js"; export type SignalProbe = BaseProbeResult & { diff --git a/extensions/signal/src/reaction-level.ts b/extensions/signal/src/reaction-level.ts index 884bccec58e..2211b9f261a 100644 --- a/extensions/signal/src/reaction-level.ts +++ b/extensions/signal/src/reaction-level.ts @@ -1,9 +1,9 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveReactionLevel, type ReactionLevel, type ResolvedReactionLevel, -} from "../../../src/utils/reaction-level.js"; +} from "openclaw/plugin-sdk/text-runtime"; import { resolveSignalAccount } from "./accounts.js"; export type SignalReactionLevel = ReactionLevel; diff --git a/extensions/signal/src/rpc-context.ts b/extensions/signal/src/rpc-context.ts index 54c123cc6be..255338379d4 100644 --- a/extensions/signal/src/rpc-context.ts +++ b/extensions/signal/src/rpc-context.ts @@ -1,4 +1,4 @@ -import { loadConfig } from "../../../src/config/config.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveSignalAccount } from "./accounts.js"; export function resolveSignalRpcContext( diff --git a/extensions/signal/src/runtime.ts b/extensions/signal/src/runtime.ts index 99bdf04a447..9790195f0e8 100644 --- a/extensions/signal/src/runtime.ts +++ b/extensions/signal/src/runtime.ts @@ -1,7 +1,5 @@ -import { - createPluginRuntimeStore, - type PluginRuntime, -} from "../../../src/plugin-sdk-internal/core.js"; +import type { PluginRuntime } from "openclaw/plugin-sdk/core"; +import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; const { setRuntime: setSignalRuntime, getRuntime: getSignalRuntime } = createPluginRuntimeStore("Signal runtime not initialized"); diff --git a/extensions/signal/src/send-reactions.ts b/extensions/signal/src/send-reactions.ts index a5000ca9e8f..6b8c3791b2d 100644 --- a/extensions/signal/src/send-reactions.ts +++ b/extensions/signal/src/send-reactions.ts @@ -2,8 +2,8 @@ * Signal reactions via signal-cli JSON-RPC API */ -import { loadConfig } from "../../../src/config/config.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveSignalAccount } from "./accounts.js"; import { signalRpcRequest } from "./client.js"; import { resolveSignalRpcContext } from "./rpc-context.js"; diff --git a/extensions/signal/src/send.ts b/extensions/signal/src/send.ts index bb953680290..c102624836e 100644 --- a/extensions/signal/src/send.ts +++ b/extensions/signal/src/send.ts @@ -1,7 +1,7 @@ -import { loadConfig, type OpenClawConfig } from "../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { kindFromMime } from "../../../src/media/mime.js"; -import { resolveOutboundAttachmentFromUrl } from "../../../src/media/outbound-attachment.js"; +import { loadConfig, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { kindFromMime } from "openclaw/plugin-sdk/media-runtime"; +import { resolveOutboundAttachmentFromUrl } from "openclaw/plugin-sdk/media-runtime"; import { resolveSignalAccount } from "./accounts.js"; import { signalRpcRequest } from "./client.js"; import { markdownToSignalText, type SignalTextStyleRange } from "./format.js"; diff --git a/extensions/signal/src/setup-core.ts b/extensions/signal/src/setup-core.ts index 5e3901f0fae..1e479c38dc6 100644 --- a/extensions/signal/src/setup-core.ts +++ b/extensions/signal/src/setup-core.ts @@ -1,5 +1,10 @@ -import { createPatchedAccountSetupAdapter } from "../../../src/channels/plugins/setup-helpers.js"; import { + applyAccountNameToChannelSection, + DEFAULT_ACCOUNT_ID, + formatCliCommand, + formatDocsLink, + migrateBaseNameToDefaultAccount, + normalizeAccountId, normalizeE164, parseSetupEntriesAllowingWildcard, promptParsedAllowFromForScopedChannel, @@ -7,13 +12,12 @@ import { setSetupChannelEnabled, type OpenClawConfig, type WizardPrompter, -} from "../../../src/plugin-sdk-internal/setup.js"; +} from "openclaw/plugin-sdk/setup"; import type { ChannelSetupAdapter, ChannelSetupDmPolicy, ChannelSetupWizard, -} from "../../../src/plugin-sdk-internal/setup.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; +} from "openclaw/plugin-sdk/setup"; import { listSignalAccountIds, resolveDefaultSignalAccountId, @@ -24,7 +28,7 @@ const channel = "signal" as const; const MIN_E164_DIGITS = 5; const MAX_E164_DIGITS = 15; const DIGITS_ONLY = /^\d+$/; -export const INVALID_SIGNAL_ACCOUNT_ERROR = +const INVALID_SIGNAL_ACCOUNT_ERROR = "Invalid E.164 phone number (must start with + and country code, e.g. +15555550123)"; export function normalizeSignalAccountInput(value: string | null | undefined): string | null { @@ -83,7 +87,7 @@ function buildSignalSetupPatch(input: { }; } -export async function promptSignalAllowFrom(params: { +async function promptSignalAllowFrom(params: { cfg: OpenClawConfig; prompter: WizardPrompter; accountId?: string; @@ -111,8 +115,15 @@ export async function promptSignalAllowFrom(params: { }); } -export const signalSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupAdapter({ - channelKey: channel, +export const signalSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + }), validateInput: ({ input }) => { if ( !input.signalNumber && @@ -125,40 +136,74 @@ export const signalSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetup } return null; }, - buildPatch: (input) => buildSignalSetupPatch(input), -}); - -type SignalSetupWizardHandlers = { - resolveStatusLines: NonNullable["resolveStatusLines"]; - resolveSelectionHint: NonNullable["resolveSelectionHint"]; - resolveQuickstartScore: NonNullable["resolveQuickstartScore"]; - prepare?: ChannelSetupWizard["prepare"]; - shouldPromptCliPath: NonNullable< - NonNullable[number]["shouldPrompt"] - >; + applyAccountConfig: ({ cfg, accountId, input }) => { + const namedConfig = applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name: input.name, + }); + const next = + accountId !== DEFAULT_ACCOUNT_ID + ? migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + }) + : namedConfig; + if (accountId === DEFAULT_ACCOUNT_ID) { + return { + ...next, + channels: { + ...next.channels, + signal: { + ...next.channels?.signal, + enabled: true, + ...buildSignalSetupPatch(input), + }, + }, + }; + } + return { + ...next, + channels: { + ...next.channels, + signal: { + ...next.channels?.signal, + enabled: true, + accounts: { + ...next.channels?.signal?.accounts, + [accountId]: { + ...next.channels?.signal?.accounts?.[accountId], + enabled: true, + ...buildSignalSetupPatch(input), + }, + }, + }, + }, + }; + }, }; -export function createSignalSetupWizardBase( - handlers: SignalSetupWizardHandlers, -): ChannelSetupWizard { - const setupChannel = "signal" as const; +export function createSignalSetupWizardProxy( + loadWizard: () => Promise<{ signalSetupWizard: ChannelSetupWizard }>, +) { const signalDmPolicy: ChannelSetupDmPolicy = { label: "Signal", - channel: setupChannel, + channel, policyKey: "channels.signal.dmPolicy", allowFromKey: "channels.signal.allowFrom", getCurrent: (cfg: OpenClawConfig) => cfg.channels?.signal?.dmPolicy ?? "pairing", setPolicy: (cfg: OpenClawConfig, policy) => setChannelDmPolicyWithAllowFrom({ cfg, - channel: setupChannel, + channel, dmPolicy: policy, }), promptAllowFrom: promptSignalAllowFrom, }; return { - channel: setupChannel, + channel, status: { configuredLabel: "configured", unconfiguredLabel: "needs setup", @@ -170,11 +215,14 @@ export function createSignalSetupWizardBase( listSignalAccountIds(cfg).some( (accountId) => resolveSignalAccount({ cfg, accountId }).configured, ), - resolveStatusLines: handlers.resolveStatusLines, - resolveSelectionHint: handlers.resolveSelectionHint, - resolveQuickstartScore: handlers.resolveQuickstartScore, + resolveStatusLines: async (params) => + (await loadWizard()).signalSetupWizard.status.resolveStatusLines?.(params) ?? [], + resolveSelectionHint: async (params) => + await (await loadWizard()).signalSetupWizard.status.resolveSelectionHint?.(params), + resolveQuickstartScore: async (params) => + await (await loadWizard()).signalSetupWizard.status.resolveQuickstartScore?.(params), }, - prepare: handlers.prepare, + prepare: async (params) => await (await loadWizard()).signalSetupWizard.prepare?.(params), credentials: [], textInputs: [ { @@ -188,7 +236,12 @@ export function createSignalSetupWizardBase( (typeof credentialValues.cliPath === "string" ? credentialValues.cliPath : undefined) ?? resolveSignalAccount({ cfg, accountId }).config.cliPath ?? "signal-cli", - shouldPrompt: handlers.shouldPromptCliPath, + shouldPrompt: async (params) => { + const input = (await loadWizard()).signalSetupWizard.textInputs?.find( + (entry) => entry.inputKey === "cliPath", + ); + return (await input?.shouldPrompt?.(params)) ?? false; + }, confirmCurrentValue: false, applyCurrentValue: true, helpTitle: "Signal", @@ -213,31 +266,11 @@ export function createSignalSetupWizardBase( lines: [ 'Link device with: signal-cli link -n "OpenClaw"', "Scan QR in Signal -> Linked Devices", - `Then run: openclaw gateway call channels.status --params '{"probe":true}'`, - "Docs: https://docs.openclaw.ai/signal", + `Then run: ${formatCliCommand("openclaw gateway call channels.status --params '{\"probe\":true}'")}`, + `Docs: ${formatDocsLink("/signal", "signal")}`, ], }, dmPolicy: signalDmPolicy, - disable: (cfg: OpenClawConfig) => setSetupChannelEnabled(cfg, setupChannel, false), + disable: (cfg: OpenClawConfig) => setSetupChannelEnabled(cfg, channel, false), } satisfies ChannelSetupWizard; } - -export function createSignalSetupWizardProxy( - loadWizard: () => Promise<{ signalSetupWizard: ChannelSetupWizard }>, -) { - return createSignalSetupWizardBase({ - resolveStatusLines: async (params) => - (await loadWizard()).signalSetupWizard.status.resolveStatusLines?.(params) ?? [], - resolveSelectionHint: async (params) => - await (await loadWizard()).signalSetupWizard.status.resolveSelectionHint?.(params), - resolveQuickstartScore: async (params) => - await (await loadWizard()).signalSetupWizard.status.resolveQuickstartScore?.(params), - prepare: async (params) => await (await loadWizard()).signalSetupWizard.prepare?.(params), - shouldPromptCliPath: async (params) => { - const input = (await loadWizard()).signalSetupWizard.textInputs?.find( - (entry) => entry.inputKey === "cliPath", - ); - return (await input?.shouldPrompt?.(params)) ?? false; - }, - }); -} diff --git a/extensions/signal/src/setup-surface.ts b/extensions/signal/src/setup-surface.ts index e3ac6f7e42a..32270cde952 100644 --- a/extensions/signal/src/setup-surface.ts +++ b/extensions/signal/src/setup-surface.ts @@ -1,34 +1,104 @@ import { + DEFAULT_ACCOUNT_ID, detectBinary, + formatCliCommand, + formatDocsLink, installSignalCli, type OpenClawConfig, -} from "../../../src/plugin-sdk-internal/setup.js"; -import type { ChannelSetupWizard } from "../../../src/plugin-sdk-internal/setup.js"; -import { resolveSignalAccount } from "./accounts.js"; + parseSetupEntriesAllowingWildcard, + promptParsedAllowFromForScopedChannel, + setChannelDmPolicyWithAllowFrom, + setSetupChannelEnabled, + type WizardPrompter, +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupDmPolicy, ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { + listSignalAccountIds, + resolveDefaultSignalAccountId, + resolveSignalAccount, +} from "./accounts.js"; import { - createSignalSetupWizardBase, - INVALID_SIGNAL_ACCOUNT_ERROR, normalizeSignalAccountInput, - promptSignalAllowFrom, + parseSignalAllowFromEntries, signalSetupAdapter, } from "./setup-core.js"; -export const signalSetupWizard: ChannelSetupWizard = createSignalSetupWizardBase({ - resolveStatusLines: async ({ cfg, configured }) => { - const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli"; - const signalCliDetected = await detectBinary(signalCliPath); - return [ - `Signal: ${configured ? "configured" : "needs setup"}`, - `signal-cli: ${signalCliDetected ? "found" : "missing"} (${signalCliPath})`, - ]; - }, - resolveSelectionHint: async ({ cfg }) => { - const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli"; - return (await detectBinary(signalCliPath)) ? "signal-cli found" : "signal-cli missing"; - }, - resolveQuickstartScore: async ({ cfg }) => { - const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli"; - return (await detectBinary(signalCliPath)) ? 1 : 0; +const channel = "signal" as const; +const INVALID_SIGNAL_ACCOUNT_ERROR = + "Invalid E.164 phone number (must start with + and country code, e.g. +15555550123)"; + +async function promptSignalAllowFrom(params: { + cfg: OpenClawConfig; + prompter: WizardPrompter; + accountId?: string; +}): Promise { + return promptParsedAllowFromForScopedChannel({ + cfg: params.cfg, + channel, + accountId: params.accountId, + defaultAccountId: resolveDefaultSignalAccountId(params.cfg), + prompter: params.prompter, + noteTitle: "Signal allowlist", + noteLines: [ + "Allowlist Signal DMs by sender id.", + "Examples:", + "- +15555550123", + "- uuid:123e4567-e89b-12d3-a456-426614174000", + "Multiple entries: comma-separated.", + `Docs: ${formatDocsLink("/signal", "signal")}`, + ], + message: "Signal allowFrom (E.164 or uuid)", + placeholder: "+15555550123, uuid:123e4567-e89b-12d3-a456-426614174000", + parseEntries: parseSignalAllowFromEntries, + getExistingAllowFrom: ({ cfg, accountId }) => + resolveSignalAccount({ cfg, accountId }).config.allowFrom ?? [], + }); +} + +const signalDmPolicy: ChannelSetupDmPolicy = { + label: "Signal", + channel, + policyKey: "channels.signal.dmPolicy", + allowFromKey: "channels.signal.allowFrom", + getCurrent: (cfg) => cfg.channels?.signal?.dmPolicy ?? "pairing", + setPolicy: (cfg, policy) => + setChannelDmPolicyWithAllowFrom({ + cfg, + channel, + dmPolicy: policy, + }), + promptAllowFrom: promptSignalAllowFrom, +}; + +export const signalSetupWizard: ChannelSetupWizard = { + channel, + status: { + configuredLabel: "configured", + unconfiguredLabel: "needs setup", + configuredHint: "signal-cli found", + unconfiguredHint: "signal-cli missing", + configuredScore: 1, + unconfiguredScore: 0, + resolveConfigured: ({ cfg }) => + listSignalAccountIds(cfg).some( + (accountId) => resolveSignalAccount({ cfg, accountId }).configured, + ), + resolveStatusLines: async ({ cfg, configured }) => { + const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli"; + const signalCliDetected = await detectBinary(signalCliPath); + return [ + `Signal: ${configured ? "configured" : "needs setup"}`, + `signal-cli: ${signalCliDetected ? "found" : "missing"} (${signalCliPath})`, + ]; + }, + resolveSelectionHint: async ({ cfg }) => { + const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli"; + return (await detectBinary(signalCliPath)) ? "signal-cli found" : "signal-cli missing"; + }, + resolveQuickstartScore: async ({ cfg }) => { + const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli"; + return (await detectBinary(signalCliPath)) ? 1 : 0; + }, }, prepare: async ({ cfg, accountId, credentialValues, runtime, prompter, options }) => { if (!options?.allowSignalInstall) { @@ -65,13 +135,50 @@ export const signalSetupWizard: ChannelSetupWizard = createSignalSetupWizardBase await prompter.note(`signal-cli install failed: ${String(error)}`, "Signal"); } }, - shouldPromptCliPath: async ({ currentValue }) => - !(await detectBinary(currentValue ?? "signal-cli")), -}); - -export { - INVALID_SIGNAL_ACCOUNT_ERROR, - normalizeSignalAccountInput, - promptSignalAllowFrom, - signalSetupAdapter, + credentials: [], + textInputs: [ + { + inputKey: "cliPath", + message: "signal-cli path", + currentValue: ({ cfg, accountId, credentialValues }) => + (typeof credentialValues.cliPath === "string" ? credentialValues.cliPath : undefined) ?? + resolveSignalAccount({ cfg, accountId }).config.cliPath ?? + "signal-cli", + initialValue: ({ cfg, accountId, credentialValues }) => + (typeof credentialValues.cliPath === "string" ? credentialValues.cliPath : undefined) ?? + resolveSignalAccount({ cfg, accountId }).config.cliPath ?? + "signal-cli", + shouldPrompt: async ({ currentValue }) => !(await detectBinary(currentValue ?? "signal-cli")), + confirmCurrentValue: false, + applyCurrentValue: true, + helpTitle: "Signal", + helpLines: [ + "signal-cli not found. Install it, then rerun this step or set channels.signal.cliPath.", + ], + }, + { + inputKey: "signalNumber", + message: "Signal bot number (E.164)", + currentValue: ({ cfg, accountId }) => + normalizeSignalAccountInput(resolveSignalAccount({ cfg, accountId }).config.account) ?? + undefined, + keepPrompt: (value) => `Signal account set (${value}). Keep it?`, + validate: ({ value }) => + normalizeSignalAccountInput(value) ? undefined : INVALID_SIGNAL_ACCOUNT_ERROR, + normalizeValue: ({ value }) => normalizeSignalAccountInput(value) ?? value, + }, + ], + completionNote: { + title: "Signal next steps", + lines: [ + 'Link device with: signal-cli link -n "OpenClaw"', + "Scan QR in Signal -> Linked Devices", + `Then run: ${formatCliCommand("openclaw gateway call channels.status --params '{\"probe\":true}'")}`, + `Docs: ${formatDocsLink("/signal", "signal")}`, + ], + }, + dmPolicy: signalDmPolicy, + disable: (cfg) => setSetupChannelEnabled(cfg, channel, false), }; + +export { normalizeSignalAccountInput, parseSignalAllowFromEntries, signalSetupAdapter }; diff --git a/extensions/signal/src/sse-reconnect.ts b/extensions/signal/src/sse-reconnect.ts index 240ec7a4beb..f825a211afb 100644 --- a/extensions/signal/src/sse-reconnect.ts +++ b/extensions/signal/src/sse-reconnect.ts @@ -1,7 +1,7 @@ -import { logVerbose, shouldLogVerbose } from "../../../src/globals.js"; -import type { BackoffPolicy } from "../../../src/infra/backoff.js"; -import { computeBackoff, sleepWithAbort } from "../../../src/infra/backoff.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +import type { BackoffPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import { computeBackoff, sleepWithAbort } from "openclaw/plugin-sdk/infra-runtime"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { type SignalSseEvent, streamSignalEvents } from "./client.js"; const DEFAULT_RECONNECT_POLICY: BackoffPolicy = { diff --git a/extensions/slack/src/account-inspect.ts b/extensions/slack/src/account-inspect.ts index 1cc3f2b8509..7ea7ef042c2 100644 --- a/extensions/slack/src/account-inspect.ts +++ b/extensions/slack/src/account-inspect.ts @@ -1,13 +1,13 @@ import { hasConfiguredSecretInput, normalizeSecretInputString, -} from "../../../src/config/types.secrets.js"; +} from "openclaw/plugin-sdk/config-runtime"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId, type OpenClawConfig, type SlackAccountConfig, -} from "../../../src/plugin-sdk-internal/slack.js"; +} from "openclaw/plugin-sdk/slack"; import type { SlackAccountSurfaceFields } from "./account-surface-fields.js"; import { mergeSlackAccountConfig, diff --git a/extensions/slack/src/account-surface-fields.ts b/extensions/slack/src/account-surface-fields.ts index 8913a9859fe..be264d9d369 100644 --- a/extensions/slack/src/account-surface-fields.ts +++ b/extensions/slack/src/account-surface-fields.ts @@ -1,4 +1,4 @@ -import type { SlackAccountConfig } from "../../../src/config/types.js"; +import type { SlackAccountConfig } from "openclaw/plugin-sdk/config-runtime"; export type SlackAccountSurfaceFields = { groupPolicy?: SlackAccountConfig["groupPolicy"]; diff --git a/extensions/slack/src/accounts.ts b/extensions/slack/src/accounts.ts index 4297e74902b..e453067e485 100644 --- a/extensions/slack/src/accounts.ts +++ b/extensions/slack/src/accounts.ts @@ -1,12 +1,12 @@ import { - type OpenClawConfig, createAccountListHelpers, DEFAULT_ACCOUNT_ID, normalizeAccountId, normalizeChatType, resolveAccountEntry, -} from "../../../src/plugin-sdk-internal/accounts.js"; -import type { SlackAccountConfig } from "../../../src/plugin-sdk-internal/slack.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/account-resolution"; +import type { SlackAccountConfig } from "openclaw/plugin-sdk/slack"; import type { SlackAccountSurfaceFields } from "./account-surface-fields.js"; import { resolveSlackAppToken, resolveSlackBotToken, resolveSlackUserToken } from "./token.js"; diff --git a/extensions/slack/src/actions.ts b/extensions/slack/src/actions.ts index ba422ac50f2..20b32d15726 100644 --- a/extensions/slack/src/actions.ts +++ b/extensions/slack/src/actions.ts @@ -1,6 +1,6 @@ import type { Block, KnownBlock, WebClient } from "@slack/web-api"; -import { loadConfig } from "../../../src/config/config.js"; -import { logVerbose } from "../../../src/globals.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { resolveSlackAccount } from "./accounts.js"; import { buildSlackBlocksFallbackText } from "./blocks-fallback.js"; import { validateSlackBlocksArray } from "./blocks-input.js"; diff --git a/extensions/slack/src/blocks-render.ts b/extensions/slack/src/blocks-render.ts index f22b179223d..775b988c521 100644 --- a/extensions/slack/src/blocks-render.ts +++ b/extensions/slack/src/blocks-render.ts @@ -1,6 +1,6 @@ import type { Block, KnownBlock } from "@slack/web-api"; -import { reduceInteractiveReply } from "../../../src/channels/plugins/outbound/interactive.js"; -import type { InteractiveReply } from "../../../src/interactive/payload.js"; +import { reduceInteractiveReply } from "openclaw/plugin-sdk/channel-runtime"; +import type { InteractiveReply } from "openclaw/plugin-sdk/channel-runtime"; import { truncateSlackText } from "./truncate.js"; export const SLACK_REPLY_BUTTON_ACTION_ID = "openclaw:reply_button"; diff --git a/extensions/slack/src/blocks.test-helpers.ts b/extensions/slack/src/blocks.test-helpers.ts index 50f7d66b04d..3ee978a2d81 100644 --- a/extensions/slack/src/blocks.test-helpers.ts +++ b/extensions/slack/src/blocks.test-helpers.ts @@ -17,7 +17,7 @@ export type SlackSendTestClient = WebClient & { }; export function installSlackBlockTestMocks() { - vi.mock("../../../src/config/config.js", () => ({ + vi.mock("openclaw/plugin-sdk/config-runtime", () => ({ loadConfig: () => ({}), })); diff --git a/extensions/slack/src/channel-migration.ts b/extensions/slack/src/channel-migration.ts index e78ade084d4..f6b97eb798a 100644 --- a/extensions/slack/src/channel-migration.ts +++ b/extensions/slack/src/channel-migration.ts @@ -1,6 +1,6 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { SlackChannelConfig } from "../../../src/config/types.slack.js"; -import { normalizeAccountId } from "../../../src/routing/session-key.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { SlackChannelConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; type SlackChannels = Record; diff --git a/extensions/slack/src/channel.setup.ts b/extensions/slack/src/channel.setup.ts index 003c33e04b4..0eaf3053aa2 100644 --- a/extensions/slack/src/channel.setup.ts +++ b/extensions/slack/src/channel.setup.ts @@ -1,19 +1,61 @@ -import { type ChannelPlugin } from "openclaw/plugin-sdk/slack"; +import { + buildChannelConfigSchema, + getChatChannelMeta, + SlackConfigSchema, + type ChannelPlugin, +} from "openclaw/plugin-sdk/slack"; import { type ResolvedSlackAccount } from "./accounts.js"; -import { createSlackSetupWizardProxy, slackSetupAdapter } from "./setup-core.js"; -import { createSlackPluginBase } from "./shared.js"; - -async function loadSlackChannelRuntime() { - return await import("./channel.runtime.js"); -} - -const slackSetupWizard = createSlackSetupWizardProxy(async () => ({ - slackSetupWizard: (await loadSlackChannelRuntime()).slackSetupWizard, -})); +import { isSlackInteractiveRepliesEnabled } from "./interactive-replies.js"; +import { + isSlackPluginAccountConfigured, + slackConfigAccessors, + slackConfigBase, + slackSetupWizard, +} from "./plugin-shared.js"; +import { slackSetupAdapter } from "./setup-core.js"; export const slackSetupPlugin: ChannelPlugin = { - ...createSlackPluginBase({ - setupWizard: slackSetupWizard, - setup: slackSetupAdapter, - }), + id: "slack", + meta: { + ...getChatChannelMeta("slack"), + preferSessionLookupForAnnounceTarget: true, + }, + setupWizard: slackSetupWizard, + capabilities: { + chatTypes: ["direct", "channel", "thread"], + reactions: true, + threads: true, + media: true, + nativeCommands: true, + }, + agentPrompt: { + messageToolHints: ({ cfg, accountId }) => + isSlackInteractiveRepliesEnabled({ cfg, accountId }) + ? [ + "- Slack interactive replies: use `[[slack_buttons: Label:value, Other:other]]` to add action buttons that route clicks back as Slack interaction system events.", + "- Slack selects: use `[[slack_select: Placeholder | Label:value, Other:other]]` to add a static select menu that routes the chosen value back as a Slack interaction system event.", + ] + : [ + "- Slack interactive replies are disabled. If needed, ask to set `channels.slack.capabilities.interactiveReplies=true` (or the same under `channels.slack.accounts..capabilities`).", + ], + }, + streaming: { + blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 }, + }, + reload: { configPrefixes: ["channels.slack"] }, + configSchema: buildChannelConfigSchema(SlackConfigSchema), + config: { + ...slackConfigBase, + isConfigured: (account) => isSlackPluginAccountConfigured(account), + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: isSlackPluginAccountConfigured(account), + botTokenSource: account.botTokenSource, + appTokenSource: account.appTokenSource, + }), + ...slackConfigAccessors, + }, + setup: slackSetupAdapter, }; diff --git a/extensions/slack/src/channel.ts b/extensions/slack/src/channel.ts index 2980316a138..3dfb195be86 100644 --- a/extensions/slack/src/channel.ts +++ b/extensions/slack/src/channel.ts @@ -1,9 +1,10 @@ +import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/allowlist-config-edit"; import { - buildAccountScopedAllowlistConfigEditor, buildAccountScopedDmSecurityPolicy, - collectOpenProviderGroupPolicyWarnings, collectOpenGroupPolicyConfiguredRouteWarnings, -} from "openclaw/plugin-sdk/compat"; + collectOpenProviderGroupPolicyWarnings, +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; import { buildAgentSessionKey, resolveThreadSessionKeys, @@ -11,7 +12,9 @@ import { } from "openclaw/plugin-sdk/core"; import { buildComputedAccountStatusSnapshot, + buildChannelConfigSchema, DEFAULT_ACCOUNT_ID, + getChatChannelMeta, listSlackDirectoryGroupsFromConfig, listSlackDirectoryPeersFromConfig, looksLikeSlackTargetId, @@ -21,12 +24,10 @@ import { resolveConfiguredFromRequiredCredentialStatuses, resolveSlackGroupRequireMention, resolveSlackGroupToolPolicy, + SlackConfigSchema, type ChannelPlugin, type OpenClawConfig, } from "openclaw/plugin-sdk/slack"; -import { createSlackActions } from "../../../src/channels/plugins/slack.actions.js"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; -import { normalizeOutboundThreadId } from "../../../src/infra/outbound/thread-id.js"; import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js"; import { listEnabledSlackAccounts, @@ -37,26 +38,26 @@ import { import { parseSlackBlocksInput } from "./blocks-input.js"; import { createSlackWebClient } from "./client.js"; 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 { - createSlackPluginBase, - isSlackPluginAccountConfigured, - slackConfigAccessors, -} 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(); -async function loadSlackChannelRuntime() { - return await import("./channel.runtime.js"); -} - // Select the appropriate Slack token for read/write operations. function getTokenForOperation( account: ResolvedSlackAccount, @@ -136,6 +137,20 @@ function parseSlackExplicitTarget(raw: string) { }; } +function normalizeOutboundThreadId(value?: string | number | null): string | undefined { + if (value == null) { + return undefined; + } + if (typeof value === "number") { + if (!Number.isFinite(value)) { + return undefined; + } + return String(Math.trunc(value)); + } + const trimmed = value.trim(); + return trimmed ? trimmed : undefined; +} + function buildSlackBaseSessionKey(params: { cfg: OpenClawConfig; agentId: string; @@ -314,21 +329,13 @@ async function resolveSlackAllowlistNames(params: { return await resolveSlackUserAllowlist({ token, entries: params.entries }); } -const slackSetupWizard = createSlackSetupWizardProxy(async () => ({ - slackSetupWizard: (await loadSlackChannelRuntime()).slackSetupWizard, -})); - -const slackActions = createSlackActions("slack", { - invoke: () => async (action, cfg, toolContext) => - await getSlackRuntime().channel.slack.handleSlackAction(action, cfg, toolContext), - skipNormalizeChannelId: true, -}); - export const slackPlugin: ChannelPlugin = { - ...createSlackPluginBase({ - setupWizard: slackSetupWizard, - setup: slackSetupAdapter, - }), + id: "slack", + meta: { + ...meta, + preferSessionLookupForAnnounceTarget: true, + }, + setupWizard: slackSetupWizard, pairing: { idLabel: "slackUserId", normalizeAllowEntry: (entry) => entry.replace(/^(slack|user):/i, ""), @@ -357,6 +364,42 @@ export const slackPlugin: ChannelPlugin = { } }, }, + capabilities: { + chatTypes: ["direct", "channel", "thread"], + reactions: true, + threads: true, + media: true, + nativeCommands: true, + }, + agentPrompt: { + messageToolHints: ({ cfg, accountId }) => + isSlackInteractiveRepliesEnabled({ cfg, accountId }) + ? [ + "- Slack interactive replies: use `[[slack_buttons: Label:value, Other:other]]` to add action buttons that route clicks back as Slack interaction system events.", + "- Slack selects: use `[[slack_select: Placeholder | Label:value, Other:other]]` to add a static select menu that routes the chosen value back as a Slack interaction system event.", + ] + : [ + "- Slack interactive replies are disabled. If needed, ask to set `channels.slack.capabilities.interactiveReplies=true` (or the same under `channels.slack.accounts..capabilities`).", + ], + }, + streaming: { + blockStreamingCoalesceDefaults: { minChars: 1500, idleMs: 1000 }, + }, + reload: { configPrefixes: ["channels.slack"] }, + configSchema: buildChannelConfigSchema(SlackConfigSchema), + config: { + ...slackConfigBase, + isConfigured: (account) => isSlackPluginAccountConfigured(account), + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: isSlackPluginAccountConfigured(account), + botTokenSource: account.botTokenSource, + appTokenSource: account.appTokenSource, + }), + ...slackConfigAccessors, + }, allowlist: { supportsScope: ({ scope }) => scope === "dm", readConfig: ({ cfg, accountId }) => @@ -511,7 +554,29 @@ export const slackPlugin: ChannelPlugin = { return resolved.map((entry) => toResolvedTarget(entry, entry.note)); }, }, - actions: slackActions, + actions: { + listActions: ({ cfg }) => listSlackMessageActions(cfg), + getCapabilities: ({ cfg }) => { + const capabilities = new Set<"interactive" | "blocks">(); + if (listSlackMessageActions(cfg).includes("send")) { + capabilities.add("blocks"); + } + if (isSlackInteractiveRepliesEnabled({ cfg })) { + capabilities.add("interactive"); + } + return Array.from(capabilities); + }, + extractToolSend: ({ args }) => extractSlackToolSend(args), + handleAction: async (ctx) => + await handleSlackMessageAction({ + providerId: meta.id, + ctx, + includeReadThreadId: true, + invoke: async (action, cfg, toolContext) => + await getSlackRuntime().channel.slack.handleSlackAction(action, cfg, toolContext), + }), + }, + setup: slackSetupAdapter, outbound: { deliveryMode: "direct", chunker: null, diff --git a/extensions/slack/src/directory-live.ts b/extensions/slack/src/directory-live.ts index 225548c646d..0a8bd04af22 100644 --- a/extensions/slack/src/directory-live.ts +++ b/extensions/slack/src/directory-live.ts @@ -1,5 +1,5 @@ -import type { DirectoryConfigParams } from "../../../src/channels/plugins/directory-config.js"; -import type { ChannelDirectoryEntry } from "../../../src/channels/plugins/types.js"; +import type { DirectoryConfigParams } from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelDirectoryEntry } from "openclaw/plugin-sdk/channel-runtime"; import { resolveSlackAccount } from "./accounts.js"; import { createSlackWebClient } from "./client.js"; diff --git a/extensions/slack/src/draft-stream.ts b/extensions/slack/src/draft-stream.ts index bb80ff8d536..f122e2664c5 100644 --- a/extensions/slack/src/draft-stream.ts +++ b/extensions/slack/src/draft-stream.ts @@ -1,4 +1,4 @@ -import { createDraftStreamLoop } from "../../../src/channels/draft-stream-loop.js"; +import { createDraftStreamLoop } from "openclaw/plugin-sdk/channel-runtime"; import { deleteSlackMessage, editSlackMessage } from "./actions.js"; import { sendMessageSlack } from "./send.js"; diff --git a/extensions/slack/src/format.ts b/extensions/slack/src/format.ts index 69aeaa6b3b9..e5ab385fc6b 100644 --- a/extensions/slack/src/format.ts +++ b/extensions/slack/src/format.ts @@ -1,6 +1,10 @@ -import type { MarkdownTableMode } from "../../../src/config/types.base.js"; -import { chunkMarkdownIR, markdownToIR, type MarkdownLinkSpan } from "../../../src/markdown/ir.js"; -import { renderMarkdownWithMarkers } from "../../../src/markdown/render.js"; +import type { MarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { + chunkMarkdownIR, + markdownToIR, + type MarkdownLinkSpan, +} from "openclaw/plugin-sdk/text-runtime"; +import { renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-runtime"; // Escape special characters for Slack mrkdwn format. // Preserve Slack's angle-bracket tokens so mentions and links stay intact. diff --git a/extensions/slack/src/interactive-replies.ts b/extensions/slack/src/interactive-replies.ts index 31784bd3b40..2a9703872c4 100644 --- a/extensions/slack/src/interactive-replies.ts +++ b/extensions/slack/src/interactive-replies.ts @@ -1,4 +1,4 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { listSlackAccountIds, resolveSlackAccount } from "./accounts.js"; function resolveInteractiveRepliesFromCapabilities(capabilities: unknown): boolean { diff --git a/extensions/slack/src/message-action-dispatch.ts b/extensions/slack/src/message-action-dispatch.ts index 486acfd4b2b..a589d28fed7 100644 --- a/extensions/slack/src/message-action-dispatch.ts +++ b/extensions/slack/src/message-action-dispatch.ts @@ -1 +1 @@ -export { handleSlackMessageAction } from "../../../src/plugin-sdk-internal/slack.js"; +export { handleSlackMessageAction } from "openclaw/plugin-sdk/slack"; diff --git a/extensions/slack/src/message-actions.ts b/extensions/slack/src/message-actions.ts index 8e2a293f166..938659c9354 100644 --- a/extensions/slack/src/message-actions.ts +++ b/extensions/slack/src/message-actions.ts @@ -1,9 +1,9 @@ -import { createActionGate } from "../../../src/agents/tools/common.js"; +import { createActionGate } from "openclaw/plugin-sdk/agent-runtime"; import type { ChannelMessageActionName, ChannelToolSend, -} from "../../../src/channels/plugins/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { listEnabledSlackAccounts } from "./accounts.js"; export function listSlackMessageActions(cfg: OpenClawConfig): ChannelMessageActionName[] { diff --git a/extensions/slack/src/monitor.test-helpers.ts b/extensions/slack/src/monitor.test-helpers.ts index c62147dd4a4..08cf5810345 100644 --- a/extensions/slack/src/monitor.test-helpers.ts +++ b/extensions/slack/src/monitor.test-helpers.ts @@ -187,15 +187,15 @@ export function resetSlackTestState(config: Record = defaultSla getSlackHandlers()?.clear(); } -vi.mock("../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig: () => slackTestState.config, }; }); -vi.mock("../../../src/auto-reply/reply.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ getReplyFromConfig: (...args: unknown[]) => slackTestState.replyMock(...args), })); @@ -213,14 +213,14 @@ vi.mock("./send.js", () => ({ sendMessageSlack: (...args: unknown[]) => slackTestState.sendMock(...args), })); -vi.mock("../../../src/pairing/pairing-store.js", () => ({ +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore: (...args: unknown[]) => slackTestState.readAllowFromStoreMock(...args), upsertChannelPairingRequest: (...args: unknown[]) => slackTestState.upsertPairingRequestMock(...args), })); -vi.mock("../../../src/config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"), diff --git a/extensions/slack/src/monitor/allow-list.ts b/extensions/slack/src/monitor/allow-list.ts index 0e800047502..32fb7f40530 100644 --- a/extensions/slack/src/monitor/allow-list.ts +++ b/extensions/slack/src/monitor/allow-list.ts @@ -2,12 +2,12 @@ import { compileAllowlist, resolveCompiledAllowlistMatch, type AllowlistMatch, -} from "../../../../src/channels/allowlist-match.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import { normalizeHyphenSlug, normalizeStringEntries, normalizeStringEntriesLower, -} from "../../../../src/shared/string-normalization.js"; +} from "openclaw/plugin-sdk/text-runtime"; const SLACK_SLUG_CACHE_MAX = 512; const slackSlugCache = new Map(); diff --git a/extensions/slack/src/monitor/auth.ts b/extensions/slack/src/monitor/auth.ts index 5022a94ad18..df8946a01c0 100644 --- a/extensions/slack/src/monitor/auth.ts +++ b/extensions/slack/src/monitor/auth.ts @@ -1,4 +1,4 @@ -import { readStoreAllowFromForDmPolicy } from "../../../../src/security/dm-policy-shared.js"; +import { readStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/security-runtime"; import { allowListMatches, normalizeAllowList, diff --git a/extensions/slack/src/monitor/channel-config.ts b/extensions/slack/src/monitor/channel-config.ts index e5f380a7102..32ad0e6f022 100644 --- a/extensions/slack/src/monitor/channel-config.ts +++ b/extensions/slack/src/monitor/channel-config.ts @@ -3,8 +3,8 @@ import { buildChannelKeyCandidates, resolveChannelEntryMatchWithFallback, type ChannelMatchSource, -} from "../../../../src/channels/channel-config.js"; -import type { SlackReactionNotificationMode } from "../../../../src/config/config.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { SlackReactionNotificationMode } from "openclaw/plugin-sdk/config-runtime"; import type { SlackMessageEvent } from "../types.js"; import { allowListMatches, normalizeAllowListLower, normalizeSlackSlug } from "./allow-list.js"; diff --git a/extensions/slack/src/monitor/commands.ts b/extensions/slack/src/monitor/commands.ts index 25fbaeb1007..1d83d9f74d1 100644 --- a/extensions/slack/src/monitor/commands.ts +++ b/extensions/slack/src/monitor/commands.ts @@ -1,4 +1,4 @@ -import type { SlackSlashCommandConfig } from "../../../../src/config/config.js"; +import type { SlackSlashCommandConfig } from "openclaw/plugin-sdk/config-runtime"; /** * Strip Slack mentions (<@U123>, <@U123|name>) so command detection works on diff --git a/extensions/slack/src/monitor/context.ts b/extensions/slack/src/monitor/context.ts index ad485a5c202..f39a92ce207 100644 --- a/extensions/slack/src/monitor/context.ts +++ b/extensions/slack/src/monitor/context.ts @@ -1,17 +1,17 @@ import type { App } from "@slack/bolt"; -import type { HistoryEntry } from "../../../../src/auto-reply/reply/history.js"; -import { formatAllowlistMatchMeta } from "../../../../src/channels/allowlist-match.js"; +import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/channel-runtime"; import type { OpenClawConfig, SlackReactionNotificationMode, -} from "../../../../src/config/config.js"; -import { resolveSessionKey, type SessionScope } from "../../../../src/config/sessions.js"; -import type { DmPolicy, GroupPolicy } from "../../../../src/config/types.js"; -import { logVerbose } from "../../../../src/globals.js"; -import { createDedupeCache } from "../../../../src/infra/dedupe.js"; -import { getChildLogger } from "../../../../src/logging.js"; -import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { resolveSessionKey, type SessionScope } from "openclaw/plugin-sdk/config-runtime"; +import type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { createDedupeCache } from "openclaw/plugin-sdk/infra-runtime"; +import type { HistoryEntry } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import type { SlackMessageEvent } from "../types.js"; import { normalizeAllowList, normalizeAllowListLower, normalizeSlackSlug } from "./allow-list.js"; import type { SlackChannelConfigEntries } from "./channel-config.js"; @@ -53,7 +53,7 @@ export type SlackMonitorContext = { replyToMode: "off" | "first" | "all"; threadHistoryScope: "thread" | "channel"; threadInheritParent: boolean; - slashCommand: Required; + slashCommand: Required; textLimit: number; ackReactionScope: string; typingReaction: string; diff --git a/extensions/slack/src/monitor/dm-auth.ts b/extensions/slack/src/monitor/dm-auth.ts index 20d850d869a..930d31efdc5 100644 --- a/extensions/slack/src/monitor/dm-auth.ts +++ b/extensions/slack/src/monitor/dm-auth.ts @@ -1,6 +1,6 @@ -import { formatAllowlistMatchMeta } from "../../../../src/channels/allowlist-match.js"; -import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js"; -import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js"; +import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/channel-runtime"; +import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime"; +import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime"; import { resolveSlackAllowListMatch } from "./allow-list.js"; import type { SlackMonitorContext } from "./context.js"; diff --git a/extensions/slack/src/monitor/events/channels.ts b/extensions/slack/src/monitor/events/channels.ts index 283b6648cf9..e4940f80d9f 100644 --- a/extensions/slack/src/monitor/events/channels.ts +++ b/extensions/slack/src/monitor/events/channels.ts @@ -1,8 +1,8 @@ import type { SlackEventMiddlewareArgs } from "@slack/bolt"; -import { resolveChannelConfigWrites } from "../../../../../src/channels/plugins/config-writes.js"; -import { loadConfig, writeConfigFile } from "../../../../../src/config/config.js"; -import { danger, warn } from "../../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; +import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig, writeConfigFile } from "openclaw/plugin-sdk/config-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { danger, warn } from "openclaw/plugin-sdk/runtime-env"; import { migrateSlackChannelConfig } from "../../channel-migration.js"; import { resolveSlackChannelLabel } from "../channel-config.js"; import type { SlackMonitorContext } from "../context.js"; diff --git a/extensions/slack/src/monitor/events/interactions.block-actions.ts b/extensions/slack/src/monitor/events/interactions.block-actions.ts index 1f54df45a5d..f8a18720933 100644 --- a/extensions/slack/src/monitor/events/interactions.block-actions.ts +++ b/extensions/slack/src/monitor/events/interactions.block-actions.ts @@ -1,12 +1,12 @@ import type { SlackActionMiddlewareArgs } from "@slack/bolt"; import type { Block, KnownBlock } from "@slack/web-api"; -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; import { buildPluginBindingResolvedText, parsePluginBindingApprovalCustomId, resolvePluginConversationBindingApproval, -} from "../../../../../src/plugins/conversation-binding.js"; -import { dispatchPluginInteractiveHandler } from "../../../../../src/plugins/interactive.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime"; import { SLACK_REPLY_BUTTON_ACTION_ID, SLACK_REPLY_SELECT_ACTION_ID } from "../../blocks-render.js"; import { authorizeSlackSystemEventSender } from "../auth.js"; import type { SlackMonitorContext } from "../context.js"; diff --git a/extensions/slack/src/monitor/events/interactions.modal.ts b/extensions/slack/src/monitor/events/interactions.modal.ts index 48e163c317f..14f7a0af0cd 100644 --- a/extensions/slack/src/monitor/events/interactions.modal.ts +++ b/extensions/slack/src/monitor/events/interactions.modal.ts @@ -1,4 +1,4 @@ -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; import { parseSlackModalPrivateMetadata } from "../../modal-metadata.js"; import { authorizeSlackSystemEventSender } from "../auth.js"; import type { SlackMonitorContext } from "../context.js"; diff --git a/extensions/slack/src/monitor/events/members.ts b/extensions/slack/src/monitor/events/members.ts index 490c0bf6f04..26d02f11613 100644 --- a/extensions/slack/src/monitor/events/members.ts +++ b/extensions/slack/src/monitor/events/members.ts @@ -1,6 +1,6 @@ import type { SlackEventMiddlewareArgs } from "@slack/bolt"; -import { danger } from "../../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; import type { SlackMonitorContext } from "../context.js"; import type { SlackMemberChannelEvent } from "../types.js"; import { authorizeAndResolveSlackSystemEventContext } from "./system-event-context.js"; diff --git a/extensions/slack/src/monitor/events/messages.ts b/extensions/slack/src/monitor/events/messages.ts index b950d5d19ea..309308caa57 100644 --- a/extensions/slack/src/monitor/events/messages.ts +++ b/extensions/slack/src/monitor/events/messages.ts @@ -1,6 +1,6 @@ import type { SlackEventMiddlewareArgs } from "@slack/bolt"; -import { danger } from "../../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; import type { SlackAppMentionEvent, SlackMessageEvent } from "../../types.js"; import { normalizeSlackChannelType } from "../channel-type.js"; import type { SlackMonitorContext } from "../context.js"; diff --git a/extensions/slack/src/monitor/events/pins.ts b/extensions/slack/src/monitor/events/pins.ts index f051270624c..ba95f515810 100644 --- a/extensions/slack/src/monitor/events/pins.ts +++ b/extensions/slack/src/monitor/events/pins.ts @@ -1,6 +1,6 @@ import type { SlackEventMiddlewareArgs } from "@slack/bolt"; -import { danger } from "../../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; import type { SlackMonitorContext } from "../context.js"; import type { SlackPinEvent } from "../types.js"; import { authorizeAndResolveSlackSystemEventContext } from "./system-event-context.js"; diff --git a/extensions/slack/src/monitor/events/reactions.ts b/extensions/slack/src/monitor/events/reactions.ts index 439c15e6d12..f439168dfde 100644 --- a/extensions/slack/src/monitor/events/reactions.ts +++ b/extensions/slack/src/monitor/events/reactions.ts @@ -1,6 +1,6 @@ import type { SlackEventMiddlewareArgs } from "@slack/bolt"; -import { danger } from "../../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; import type { SlackMonitorContext } from "../context.js"; import type { SlackReactionEvent } from "../types.js"; import { authorizeAndResolveSlackSystemEventContext } from "./system-event-context.js"; diff --git a/extensions/slack/src/monitor/events/system-event-context.ts b/extensions/slack/src/monitor/events/system-event-context.ts index 278dd2324d7..544a889df5f 100644 --- a/extensions/slack/src/monitor/events/system-event-context.ts +++ b/extensions/slack/src/monitor/events/system-event-context.ts @@ -1,4 +1,4 @@ -import { logVerbose } from "../../../../../src/globals.js"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { authorizeSlackSystemEventSender } from "../auth.js"; import { resolveSlackChannelLabel } from "../channel-config.js"; import type { SlackMonitorContext } from "../context.js"; diff --git a/extensions/slack/src/monitor/external-arg-menu-store.ts b/extensions/slack/src/monitor/external-arg-menu-store.ts index e2cbf68479d..c3327ee88c6 100644 --- a/extensions/slack/src/monitor/external-arg-menu-store.ts +++ b/extensions/slack/src/monitor/external-arg-menu-store.ts @@ -1,4 +1,4 @@ -import { generateSecureToken } from "../../../../src/infra/secure-random.js"; +import { generateSecureToken } from "openclaw/plugin-sdk/infra-runtime"; const SLACK_EXTERNAL_ARG_MENU_TOKEN_BYTES = 18; const SLACK_EXTERNAL_ARG_MENU_TOKEN_LENGTH = Math.ceil( diff --git a/extensions/slack/src/monitor/media.ts b/extensions/slack/src/monitor/media.ts index ef494f2e48c..ef574a7381c 100644 --- a/extensions/slack/src/monitor/media.ts +++ b/extensions/slack/src/monitor/media.ts @@ -1,9 +1,9 @@ import type { WebClient as SlackWebClient } from "@slack/web-api"; +import { normalizeHostname } from "openclaw/plugin-sdk/infra-runtime"; +import type { FetchLike } from "openclaw/plugin-sdk/media-runtime"; +import { fetchRemoteMedia } from "openclaw/plugin-sdk/media-runtime"; +import { saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime"; import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url"; -import { normalizeHostname } from "../../../../src/infra/net/hostname.js"; -import type { FetchLike } from "../../../../src/media/fetch.js"; -import { fetchRemoteMedia } from "../../../../src/media/fetch.js"; -import { saveMediaBuffer } from "../../../../src/media/store.js"; import type { SlackAttachment, SlackFile } from "../types.js"; function isSlackHostname(hostname: string): boolean { diff --git a/extensions/slack/src/monitor/message-handler.ts b/extensions/slack/src/monitor/message-handler.ts index 37e0eb23bd3..feaddff98df 100644 --- a/extensions/slack/src/monitor/message-handler.ts +++ b/extensions/slack/src/monitor/message-handler.ts @@ -1,7 +1,7 @@ import { createChannelInboundDebouncer, shouldDebounceTextInbound, -} from "../../../../src/channels/inbound-debounce-policy.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import type { ResolvedSlackAccount } from "../accounts.js"; import type { SlackMessageEvent } from "../types.js"; import { stripSlackMentionsForCommandDetection } from "./commands.js"; diff --git a/extensions/slack/src/monitor/message-handler/dispatch.ts b/extensions/slack/src/monitor/message-handler/dispatch.ts index 43ee958bdda..569ca8f60a7 100644 --- a/extensions/slack/src/monitor/message-handler/dispatch.ts +++ b/extensions/slack/src/monitor/message-handler/dispatch.ts @@ -1,16 +1,16 @@ -import { resolveHumanDelayConfig } from "../../../../../src/agents/identity.js"; -import { dispatchInboundMessage } from "../../../../../src/auto-reply/dispatch.js"; -import { clearHistoryEntriesIfEnabled } from "../../../../../src/auto-reply/reply/history.js"; -import { createReplyDispatcherWithTyping } from "../../../../../src/auto-reply/reply/reply-dispatcher.js"; -import type { ReplyPayload } from "../../../../../src/auto-reply/types.js"; -import { removeAckReactionAfterReply } from "../../../../../src/channels/ack-reactions.js"; -import { logAckFailure, logTypingFailure } from "../../../../../src/channels/logging.js"; -import { createReplyPrefixOptions } from "../../../../../src/channels/reply-prefix.js"; -import { createTypingCallbacks } from "../../../../../src/channels/typing.js"; -import { resolveStorePath, updateLastRoute } from "../../../../../src/config/sessions.js"; -import { danger, logVerbose, shouldLogVerbose } from "../../../../../src/globals.js"; -import { resolveAgentOutboundIdentity } from "../../../../../src/infra/outbound/identity.js"; -import { resolvePinnedMainDmOwnerFromAllowlist } from "../../../../../src/security/dm-policy-shared.js"; +import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime"; +import { removeAckReactionAfterReply } from "openclaw/plugin-sdk/channel-runtime"; +import { logAckFailure, logTypingFailure } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/config-runtime"; +import { resolveAgentOutboundIdentity } from "openclaw/plugin-sdk/infra-runtime"; +import { dispatchInboundMessage } from "openclaw/plugin-sdk/reply-runtime"; +import { clearHistoryEntriesIfEnabled } from "openclaw/plugin-sdk/reply-runtime"; +import { createReplyDispatcherWithTyping } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime"; import { editSlackMessage, reactSlackMessage, removeSlackReaction } from "../../actions.js"; import { createSlackDraftStream } from "../../draft-stream.js"; import { normalizeSlackOutboundText } from "../../format.js"; diff --git a/extensions/slack/src/monitor/message-handler/prepare-content.ts b/extensions/slack/src/monitor/message-handler/prepare-content.ts index e1db426ad7e..54a5183bfb0 100644 --- a/extensions/slack/src/monitor/message-handler/prepare-content.ts +++ b/extensions/slack/src/monitor/message-handler/prepare-content.ts @@ -1,4 +1,4 @@ -import { logVerbose } from "../../../../../src/globals.js"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { SlackFile, SlackMessageEvent } from "../../types.js"; import { MAX_SLACK_MEDIA_FILES, diff --git a/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts b/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts index 9673e8d72cc..5d4020f1b46 100644 --- a/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts +++ b/extensions/slack/src/monitor/message-handler/prepare-thread-context.ts @@ -1,6 +1,6 @@ -import { formatInboundEnvelope } from "../../../../../src/auto-reply/envelope.js"; -import { readSessionUpdatedAt } from "../../../../../src/config/sessions.js"; -import { logVerbose } from "../../../../../src/globals.js"; +import { readSessionUpdatedAt } from "openclaw/plugin-sdk/config-runtime"; +import { formatInboundEnvelope } from "openclaw/plugin-sdk/reply-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { ResolvedSlackAccount } from "../../accounts.js"; import type { SlackMessageEvent } from "../../types.js"; import type { SlackMonitorContext } from "../context.js"; @@ -30,7 +30,7 @@ export async function resolveSlackThreadContextData(params: { storePath: string; sessionKey: string; envelopeOptions: ReturnType< - typeof import("../../../../../src/auto-reply/envelope.js").resolveEnvelopeFormatOptions + typeof import("openclaw/plugin-sdk/reply-runtime").resolveEnvelopeFormatOptions >; effectiveDirectMedia: SlackMediaResult[] | null; }): Promise { diff --git a/extensions/slack/src/monitor/message-handler/prepare.test-helpers.ts b/extensions/slack/src/monitor/message-handler/prepare.test-helpers.ts index cdc7a3bc411..f6d3ab21ce9 100644 --- a/extensions/slack/src/monitor/message-handler/prepare.test-helpers.ts +++ b/extensions/slack/src/monitor/message-handler/prepare.test-helpers.ts @@ -1,6 +1,6 @@ import type { App } from "@slack/bolt"; -import type { OpenClawConfig } from "../../../../../src/config/config.js"; -import type { RuntimeEnv } from "../../../../../src/runtime.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import type { ResolvedSlackAccount } from "../../accounts.js"; import { createSlackMonitorContext } from "../context.js"; diff --git a/extensions/slack/src/monitor/message-handler/prepare.ts b/extensions/slack/src/monitor/message-handler/prepare.ts index ba18b008d37..e6bc3a23446 100644 --- a/extensions/slack/src/monitor/message-handler/prepare.ts +++ b/extensions/slack/src/monitor/message-handler/prepare.ts @@ -1,35 +1,32 @@ -import { resolveAckReaction } from "../../../../../src/agents/identity.js"; -import { hasControlCommand } from "../../../../../src/auto-reply/command-detection.js"; -import { shouldHandleTextCommands } from "../../../../../src/auto-reply/commands-registry.js"; -import { - formatInboundEnvelope, - resolveEnvelopeFormatOptions, -} from "../../../../../src/auto-reply/envelope.js"; -import { - buildPendingHistoryContextFromMap, - recordPendingHistoryEntryIfEnabled, -} from "../../../../../src/auto-reply/reply/history.js"; -import { finalizeInboundContext } from "../../../../../src/auto-reply/reply/inbound-context.js"; -import { - buildMentionRegexes, - matchesMentionWithExplicit, -} from "../../../../../src/auto-reply/reply/mentions.js"; -import type { FinalizedMsgContext } from "../../../../../src/auto-reply/templating.js"; +import { resolveAckReaction } from "openclaw/plugin-sdk/agent-runtime"; import { shouldAckReaction as shouldAckReactionGate, type AckReactionScope, -} from "../../../../../src/channels/ack-reactions.js"; -import { resolveControlCommandGate } from "../../../../../src/channels/command-gating.js"; -import { resolveConversationLabel } from "../../../../../src/channels/conversation-label.js"; -import { logInboundDrop } from "../../../../../src/channels/logging.js"; -import { resolveMentionGatingWithBypass } from "../../../../../src/channels/mention-gating.js"; -import { recordInboundSession } from "../../../../../src/channels/session.js"; -import { readSessionUpdatedAt, resolveStorePath } from "../../../../../src/config/sessions.js"; -import { logVerbose, shouldLogVerbose } from "../../../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../../../src/infra/system-events.js"; -import { resolveAgentRoute } from "../../../../../src/routing/resolve-route.js"; -import { resolveThreadSessionKeys } from "../../../../../src/routing/session-key.js"; -import { resolvePinnedMainDmOwnerFromAllowlist } from "../../../../../src/security/dm-policy-shared.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { resolveControlCommandGate } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveConversationLabel } from "openclaw/plugin-sdk/channel-runtime"; +import { logInboundDrop } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk/channel-runtime"; +import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime"; +import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime"; +import { shouldHandleTextCommands } from "openclaw/plugin-sdk/reply-runtime"; +import { + formatInboundEnvelope, + resolveEnvelopeFormatOptions, +} from "openclaw/plugin-sdk/reply-runtime"; +import { + buildPendingHistoryContextFromMap, + recordPendingHistoryEntryIfEnabled, +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import { buildMentionRegexes, matchesMentionWithExplicit } from "openclaw/plugin-sdk/reply-runtime"; +import type { FinalizedMsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime"; import { resolveSlackReplyToMode, type ResolvedSlackAccount } from "../../accounts.js"; import { reactSlackMessage } from "../../actions.js"; import { sendMessageSlack } from "../../send.js"; diff --git a/extensions/slack/src/monitor/message-handler/types.ts b/extensions/slack/src/monitor/message-handler/types.ts index cd1e2bdc40c..bcff64cc470 100644 --- a/extensions/slack/src/monitor/message-handler/types.ts +++ b/extensions/slack/src/monitor/message-handler/types.ts @@ -1,5 +1,5 @@ -import type { FinalizedMsgContext } from "../../../../../src/auto-reply/templating.js"; -import type { ResolvedAgentRoute } from "../../../../../src/routing/resolve-route.js"; +import type { FinalizedMsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import type { ResolvedAgentRoute } from "openclaw/plugin-sdk/routing"; import type { ResolvedSlackAccount } from "../../accounts.js"; import type { SlackMessageEvent } from "../../types.js"; import type { SlackChannelConfigResolved } from "../channel-config.js"; diff --git a/extensions/slack/src/monitor/provider.ts b/extensions/slack/src/monitor/provider.ts index 2104a5355cf..5a382551b47 100644 --- a/extensions/slack/src/monitor/provider.ts +++ b/extensions/slack/src/monitor/provider.ts @@ -1,30 +1,30 @@ import type { IncomingMessage, ServerResponse } from "node:http"; import SlackBolt, * as SlackBoltNamespace from "@slack/bolt"; -import { resolveTextChunkLimit } from "../../../../src/auto-reply/chunk.js"; -import { DEFAULT_GROUP_HISTORY_LIMIT } from "../../../../src/auto-reply/reply/history.js"; import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, mergeAllowlist, patchAllowlistUsersInConfigEntries, summarizeMapping, -} from "../../../../src/channels/allowlists/resolve-utils.js"; -import { loadConfig } from "../../../../src/config/config.js"; -import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime"; import { resolveOpenProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce, -} from "../../../../src/config/runtime-group-policy.js"; -import type { SessionScope } from "../../../../src/config/sessions.js"; -import { normalizeResolvedSecretInputString } from "../../../../src/config/types.secrets.js"; -import { createConnectedChannelStatusPatch } from "../../../../src/gateway/channel-status-patches.js"; -import { warn } from "../../../../src/globals.js"; -import { computeBackoff, sleepWithAbort } from "../../../../src/infra/backoff.js"; -import { installRequestBodyLimitGuard } from "../../../../src/infra/http-body.js"; -import { normalizeMainKey } from "../../../../src/routing/session-key.js"; -import { createNonExitingRuntime, type RuntimeEnv } from "../../../../src/runtime.js"; -import { normalizeStringEntries } from "../../../../src/shared/string-normalization.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import type { SessionScope } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/config-runtime"; +import { createConnectedChannelStatusPatch } from "openclaw/plugin-sdk/gateway-runtime"; +import { computeBackoff, sleepWithAbort } from "openclaw/plugin-sdk/infra-runtime"; +import { installRequestBodyLimitGuard } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import { DEFAULT_GROUP_HISTORY_LIMIT } from "openclaw/plugin-sdk/reply-runtime"; +import { normalizeMainKey } from "openclaw/plugin-sdk/routing"; +import { warn } from "openclaw/plugin-sdk/runtime-env"; +import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { normalizeStringEntries } from "openclaw/plugin-sdk/text-runtime"; import { resolveSlackAccount } from "../accounts.js"; import { resolveSlackWebClientOptions } from "../client.js"; import { normalizeSlackWebhookPath, registerSlackHttpHandler } from "../http/index.js"; diff --git a/extensions/slack/src/monitor/replies.ts b/extensions/slack/src/monitor/replies.ts index 885e71b7818..a8ef26510f0 100644 --- a/extensions/slack/src/monitor/replies.ts +++ b/extensions/slack/src/monitor/replies.ts @@ -1,10 +1,10 @@ -import type { ChunkMode } from "../../../../src/auto-reply/chunk.js"; -import { chunkMarkdownTextWithMode } from "../../../../src/auto-reply/chunk.js"; -import { createReplyReferencePlanner } from "../../../../src/auto-reply/reply/reply-reference.js"; -import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../../../../src/auto-reply/tokens.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import type { MarkdownTableMode } from "../../../../src/config/types.base.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +import type { MarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import type { ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-runtime"; +import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-runtime"; +import { isSilentReplyText, SILENT_REPLY_TOKEN } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { parseSlackBlocksInput } from "../blocks-input.js"; import { markdownToSlackMrkdwnChunks } from "../format.js"; import { sendMessageSlack, type SlackSendIdentity } from "../send.js"; diff --git a/extensions/slack/src/monitor/room-context.ts b/extensions/slack/src/monitor/room-context.ts index 3cdf584566a..955f9f3c855 100644 --- a/extensions/slack/src/monitor/room-context.ts +++ b/extensions/slack/src/monitor/room-context.ts @@ -1,4 +1,4 @@ -import { buildUntrustedChannelMetadata } from "../../../../src/security/channel-metadata.js"; +import { buildUntrustedChannelMetadata } from "openclaw/plugin-sdk/security-runtime"; export function resolveSlackRoomContextHints(params: { isRoomish: boolean; diff --git a/extensions/slack/src/monitor/slash-commands.runtime.ts b/extensions/slack/src/monitor/slash-commands.runtime.ts index a87490f43bc..63fa59cd347 100644 --- a/extensions/slack/src/monitor/slash-commands.runtime.ts +++ b/extensions/slack/src/monitor/slash-commands.runtime.ts @@ -4,4 +4,4 @@ export { listNativeCommandSpecsForConfig, parseCommandArgs, resolveCommandArgMenu, -} from "../../../../src/auto-reply/commands-registry.js"; +} from "openclaw/plugin-sdk/reply-runtime"; diff --git a/extensions/slack/src/monitor/slash-dispatch.runtime.ts b/extensions/slack/src/monitor/slash-dispatch.runtime.ts index 01e47782467..0095471359c 100644 --- a/extensions/slack/src/monitor/slash-dispatch.runtime.ts +++ b/extensions/slack/src/monitor/slash-dispatch.runtime.ts @@ -1,9 +1,9 @@ -export { resolveChunkMode } from "../../../../src/auto-reply/chunk.js"; -export { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js"; -export { dispatchReplyWithDispatcher } from "../../../../src/auto-reply/reply/provider-dispatcher.js"; -export { resolveConversationLabel } from "../../../../src/channels/conversation-label.js"; -export { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js"; -export { recordInboundSessionMetaSafe } from "../../../../src/channels/session-meta.js"; -export { resolveMarkdownTableMode } from "../../../../src/config/markdown-tables.js"; -export { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; +export { resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +export { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +export { dispatchReplyWithDispatcher } from "openclaw/plugin-sdk/reply-runtime"; +export { resolveConversationLabel } from "openclaw/plugin-sdk/channel-runtime"; +export { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +export { recordInboundSessionMetaSafe } from "openclaw/plugin-sdk/channel-runtime"; +export { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +export { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; export { deliverSlackSlashReplies } from "./replies.js"; diff --git a/extensions/slack/src/monitor/slash-skill-commands.runtime.ts b/extensions/slack/src/monitor/slash-skill-commands.runtime.ts index 20da07b3ec5..738580cdc0f 100644 --- a/extensions/slack/src/monitor/slash-skill-commands.runtime.ts +++ b/extensions/slack/src/monitor/slash-skill-commands.runtime.ts @@ -1 +1 @@ -export { listSkillCommandsForAgents } from "../../../../src/auto-reply/skill-commands.js"; +export { listSkillCommandsForAgents } from "openclaw/plugin-sdk/reply-runtime"; diff --git a/extensions/slack/src/monitor/slash.test-harness.ts b/extensions/slack/src/monitor/slash.test-harness.ts index 4b6f5a4ea27..3172154739e 100644 --- a/extensions/slack/src/monitor/slash.test-harness.ts +++ b/extensions/slack/src/monitor/slash.test-harness.ts @@ -12,32 +12,32 @@ const mocks = vi.hoisted(() => ({ resolveStorePathMock: vi.fn(), })); -vi.mock("../../../../src/auto-reply/reply/provider-dispatcher.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ dispatchReplyWithDispatcher: (...args: unknown[]) => mocks.dispatchMock(...args), })); -vi.mock("../../../../src/pairing/pairing-store.js", () => ({ +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore: (...args: unknown[]) => mocks.readAllowFromStoreMock(...args), upsertChannelPairingRequest: (...args: unknown[]) => mocks.upsertPairingRequestMock(...args), })); -vi.mock("../../../../src/routing/resolve-route.js", () => ({ +vi.mock("openclaw/plugin-sdk/routing", () => ({ resolveAgentRoute: (...args: unknown[]) => mocks.resolveAgentRouteMock(...args), })); -vi.mock("../../../../src/auto-reply/reply/inbound-context.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ finalizeInboundContext: (...args: unknown[]) => mocks.finalizeInboundContextMock(...args), })); -vi.mock("../../../../src/channels/conversation-label.js", () => ({ +vi.mock("openclaw/plugin-sdk/channel-runtime", () => ({ resolveConversationLabel: (...args: unknown[]) => mocks.resolveConversationLabelMock(...args), })); -vi.mock("../../../../src/channels/reply-prefix.js", () => ({ +vi.mock("openclaw/plugin-sdk/channel-runtime", () => ({ createReplyPrefixOptions: (...args: unknown[]) => mocks.createReplyPrefixOptionsMock(...args), })); -vi.mock("../../../../src/config/sessions.js", () => ({ +vi.mock("openclaw/plugin-sdk/config-runtime", () => ({ recordSessionMetaFromInbound: (...args: unknown[]) => mocks.recordSessionMetaFromInboundMock(...args), resolveStorePath: (...args: unknown[]) => mocks.resolveStorePathMock(...args), diff --git a/extensions/slack/src/monitor/slash.ts b/extensions/slack/src/monitor/slash.ts index adf173a0961..a1c0bfa13a4 100644 --- a/extensions/slack/src/monitor/slash.ts +++ b/extensions/slack/src/monitor/slash.ts @@ -1,17 +1,14 @@ import type { SlackActionMiddlewareArgs, SlackCommandMiddlewareArgs } from "@slack/bolt"; -import { - type ChatCommandDefinition, - type CommandArgs, -} from "../../../../src/auto-reply/commands-registry.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import { resolveCommandAuthorizedFromAuthorizers } from "../../../../src/channels/command-gating.js"; -import { resolveNativeCommandSessionTargets } from "../../../../src/channels/native-command-session-targets.js"; +import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveNativeCommandSessionTargets } from "openclaw/plugin-sdk/channel-runtime"; import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled, -} from "../../../../src/config/commands.js"; -import { danger, logVerbose } from "../../../../src/globals.js"; -import { chunkItems } from "../../../../src/utils/chunk-items.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { type ChatCommandDefinition, type CommandArgs } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { chunkItems } from "openclaw/plugin-sdk/text-runtime"; import type { ResolvedSlackAccount } from "../accounts.js"; import { truncateSlackText } from "../truncate.js"; import { resolveSlackAllowListMatch, resolveSlackUserAllowed } from "./allow-list.js"; diff --git a/extensions/slack/src/monitor/thread-resolution.ts b/extensions/slack/src/monitor/thread-resolution.ts index 4230d5fc50f..11d54cd1ea6 100644 --- a/extensions/slack/src/monitor/thread-resolution.ts +++ b/extensions/slack/src/monitor/thread-resolution.ts @@ -1,6 +1,6 @@ import type { WebClient as SlackWebClient } from "@slack/web-api"; -import { logVerbose, shouldLogVerbose } from "../../../../src/globals.js"; -import { pruneMapToMaxSize } from "../../../../src/infra/map-size.js"; +import { pruneMapToMaxSize } from "openclaw/plugin-sdk/infra-runtime"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { SlackMessageEvent } from "../types.js"; type ThreadTsCacheEntry = { diff --git a/extensions/slack/src/monitor/types.ts b/extensions/slack/src/monitor/types.ts index 1239ab771f5..5543697dcfa 100644 --- a/extensions/slack/src/monitor/types.ts +++ b/extensions/slack/src/monitor/types.ts @@ -1,5 +1,5 @@ -import type { OpenClawConfig, SlackSlashCommandConfig } from "../../../../src/config/config.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +import type { OpenClawConfig, SlackSlashCommandConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import type { SlackFile, SlackMessageEvent } from "../types.js"; export type MonitorSlackOpts = { diff --git a/extensions/slack/src/outbound-adapter.ts b/extensions/slack/src/outbound-adapter.ts index 1c851c8f69e..56a5c995e40 100644 --- a/extensions/slack/src/outbound-adapter.ts +++ b/extensions/slack/src/outbound-adapter.ts @@ -2,15 +2,15 @@ import { resolvePayloadMediaUrls, sendPayloadMediaSequence, sendTextMediaPayload, -} from "../../../src/channels/plugins/outbound/direct-text-media.js"; -import type { ChannelOutboundAdapter } from "../../../src/channels/plugins/types.js"; -import type { OutboundIdentity } from "../../../src/infra/outbound/identity.js"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; import { resolveInteractiveTextFallback, type InteractiveReply, -} from "../../../src/interactive/payload.js"; -import { getGlobalHookRunner } from "../../../src/plugins/hook-runner-global.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { OutboundIdentity } from "openclaw/plugin-sdk/infra-runtime"; +import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime"; import { parseSlackBlocksInput } from "./blocks-input.js"; import { buildSlackInteractiveBlocks, type SlackBlock } from "./blocks-render.js"; import { sendMessageSlack, type SlackSendIdentity } from "./send.js"; diff --git a/extensions/slack/src/plugin-shared.ts b/extensions/slack/src/plugin-shared.ts index 0c5a6c7957e..0a5eb6ea3ec 100644 --- a/extensions/slack/src/plugin-shared.ts +++ b/extensions/slack/src/plugin-shared.ts @@ -1,9 +1,9 @@ +import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from"; import { createScopedAccountConfigAccessors, createScopedChannelConfigBase, - formatAllowFromLowercase, -} from "../../../src/plugin-sdk-internal/channel-config.js"; -import { type OpenClawConfig } from "../../../src/plugin-sdk-internal/slack.js"; +} from "openclaw/plugin-sdk/channel-config-helpers"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/slack"; import { inspectSlackAccount } from "./account-inspect.js"; import { listSlackAccountIds, diff --git a/extensions/slack/src/probe.ts b/extensions/slack/src/probe.ts index dba8744a18c..c370b11be9b 100644 --- a/extensions/slack/src/probe.ts +++ b/extensions/slack/src/probe.ts @@ -1,5 +1,5 @@ -import type { BaseProbeResult } from "../../../src/channels/plugins/types.js"; -import { withTimeout } from "../../../src/utils/with-timeout.js"; +import type { BaseProbeResult } from "openclaw/plugin-sdk/channel-runtime"; +import { withTimeout } from "openclaw/plugin-sdk/text-runtime"; import { createSlackWebClient } from "./client.js"; export type SlackProbe = BaseProbeResult & { diff --git a/extensions/slack/src/runtime.ts b/extensions/slack/src/runtime.ts index d7d09dbcb6b..2121ee9f902 100644 --- a/extensions/slack/src/runtime.ts +++ b/extensions/slack/src/runtime.ts @@ -1,7 +1,5 @@ -import { - createPluginRuntimeStore, - type PluginRuntime, -} from "../../../src/plugin-sdk-internal/core.js"; +import type { PluginRuntime } from "openclaw/plugin-sdk/core"; +import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; const { setRuntime: setSlackRuntime, getRuntime: getSlackRuntime } = createPluginRuntimeStore("Slack runtime not initialized"); diff --git a/extensions/slack/src/scopes.ts b/extensions/slack/src/scopes.ts index e0fe58161f3..fc7e14d741b 100644 --- a/extensions/slack/src/scopes.ts +++ b/extensions/slack/src/scopes.ts @@ -1,5 +1,5 @@ import type { WebClient } from "@slack/web-api"; -import { isRecord } from "../../../src/utils.js"; +import { isRecord } from "openclaw/plugin-sdk/text-runtime"; import { createSlackWebClient } from "./client.js"; export type SlackScopesResult = { diff --git a/extensions/slack/src/send.ts b/extensions/slack/src/send.ts index 293affe0218..cc352284ca3 100644 --- a/extensions/slack/src/send.ts +++ b/extensions/slack/src/send.ts @@ -1,17 +1,17 @@ import { type Block, type KnownBlock, type WebClient } from "@slack/web-api"; +import { loadConfig, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { + fetchWithSsrFGuard, + withTrustedEnvProxyGuardedFetchMode, +} from "openclaw/plugin-sdk/infra-runtime"; import { chunkMarkdownTextWithMode, resolveChunkMode, resolveTextChunkLimit, -} from "../../../src/auto-reply/chunk.js"; -import { isSilentReplyText } from "../../../src/auto-reply/tokens.js"; -import { loadConfig, type OpenClawConfig } from "../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { logVerbose } from "../../../src/globals.js"; -import { - fetchWithSsrFGuard, - withTrustedEnvProxyGuardedFetchMode, -} from "../../../src/infra/net/fetch-guard.js"; +} from "openclaw/plugin-sdk/reply-runtime"; +import { isSilentReplyText } from "openclaw/plugin-sdk/reply-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { loadWebMedia } from "../../whatsapp/src/media.js"; import type { SlackTokenSource } from "./accounts.js"; import { resolveSlackAccount } from "./accounts.js"; diff --git a/extensions/slack/src/sent-thread-cache.ts b/extensions/slack/src/sent-thread-cache.ts index 37cf8155472..f155571a1b4 100644 --- a/extensions/slack/src/sent-thread-cache.ts +++ b/extensions/slack/src/sent-thread-cache.ts @@ -1,4 +1,4 @@ -import { resolveGlobalMap } from "../../../src/shared/global-singleton.js"; +import { resolveGlobalMap } from "openclaw/plugin-sdk/text-runtime"; /** * In-memory cache of Slack threads the bot has participated in. diff --git a/extensions/slack/src/setup-core.ts b/extensions/slack/src/setup-core.ts index b53472c3ce9..2b3753a3c6d 100644 --- a/extensions/slack/src/setup-core.ts +++ b/extensions/slack/src/setup-core.ts @@ -1,7 +1,10 @@ -import { createPatchedAccountSetupAdapter } from "../../../src/channels/plugins/setup-helpers.js"; import { + applyAccountNameToChannelSection, DEFAULT_ACCOUNT_ID, + formatDocsLink, hasConfiguredSecretInput, + migrateBaseNameToDefaultAccount, + normalizeAccountId, type OpenClawConfig, noteChannelLookupFailure, noteChannelLookupSummary, @@ -10,14 +13,13 @@ import { setAccountGroupPolicyForChannel, setLegacyChannelDmPolicyWithAllowFrom, setSetupChannelEnabled, -} from "../../../src/plugin-sdk-internal/setup.js"; +} from "openclaw/plugin-sdk/setup"; import { type ChannelSetupAdapter, type ChannelSetupDmPolicy, type ChannelSetupWizard, type ChannelSetupWizardAllowFromEntry, -} from "../../../src/plugin-sdk-internal/setup.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; +} from "openclaw/plugin-sdk/setup"; import { inspectSlackAccount } from "./account-inspect.js"; import { listSlackAccountIds, resolveSlackAccount, type ResolvedSlackAccount } from "./accounts.js"; import { @@ -36,8 +38,15 @@ function enableSlackAccount(cfg: OpenClawConfig, accountId: string): OpenClawCon }); } -export const slackSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupAdapter({ - channelKey: channel, +export const slackSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + }), validateInput: ({ accountId, input }) => { if (input.useEnv && accountId !== DEFAULT_ACCOUNT_ID) { return "Slack env tokens can only be used for the default account."; @@ -47,93 +56,63 @@ export const slackSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupA } return null; }, - buildPatch: (input) => - input.useEnv - ? {} - : { - ...(input.botToken ? { botToken: input.botToken } : {}), - ...(input.appToken ? { appToken: input.appToken } : {}), - }, -}); - -type SlackAllowFromResolverParams = { - cfg: OpenClawConfig; - accountId: string; - credentialValues: { botToken?: string }; - entries: string[]; -}; - -type SlackGroupAllowlistResolverParams = SlackAllowFromResolverParams & { - prompter: { note: (message: string, title?: string) => Promise }; -}; - -type SlackSetupWizardHandlers = { - promptAllowFrom: (params: { - cfg: OpenClawConfig; - prompter: import("../../../src/plugin-sdk-internal/setup.js").WizardPrompter; - accountId?: string; - }) => Promise; - resolveAllowFromEntries: ( - params: SlackAllowFromResolverParams, - ) => Promise; - resolveGroupAllowlist: (params: SlackGroupAllowlistResolverParams) => Promise; -}; - -function buildSlackTokenCredential(params: { - inputKey: "botToken" | "appToken"; - providerHint: "slack-bot" | "slack-app"; - credentialLabel: string; - preferredEnvVar: "SLACK_BOT_TOKEN" | "SLACK_APP_TOKEN"; - inputPrompt: string; -}): NonNullable[number] { - const configKey = params.inputKey; - return { - inputKey: params.inputKey, - providerHint: params.providerHint, - credentialLabel: params.credentialLabel, - preferredEnvVar: params.preferredEnvVar, - envPrompt: `${params.preferredEnvVar} detected. Use env var?`, - keepPrompt: `${params.credentialLabel} already configured. Keep it?`, - inputPrompt: params.inputPrompt, - allowEnv: ({ accountId }: { accountId: string }) => accountId === DEFAULT_ACCOUNT_ID, - inspect: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId: string }) => { - const resolved = resolveSlackAccount({ cfg, accountId }); - const tokenValue = resolved[configKey]?.trim() || undefined; - const configuredValue = resolved.config[configKey]; - return { - accountConfigured: Boolean(tokenValue) || hasConfiguredSecretInput(configuredValue), - hasConfiguredValue: hasConfiguredSecretInput(configuredValue), - resolvedValue: tokenValue, - envValue: - accountId === DEFAULT_ACCOUNT_ID - ? process.env[params.preferredEnvVar]?.trim() - : undefined, - }; - }, - applyUseEnv: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId: string }) => - enableSlackAccount(cfg, accountId), - applySet: ({ + applyAccountConfig: ({ cfg, accountId, input }) => { + const namedConfig = applyAccountNameToChannelSection({ cfg, + channelKey: channel, accountId, - value, - }: { - cfg: OpenClawConfig; - accountId: string; - value: unknown; - }) => - patchChannelConfigForAccount({ - cfg, - channel, - accountId, - patch: { - enabled: true, - [configKey]: value, + name: input.name, + }); + const next = + accountId !== DEFAULT_ACCOUNT_ID + ? migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + }) + : namedConfig; + if (accountId === DEFAULT_ACCOUNT_ID) { + return { + ...next, + channels: { + ...next.channels, + slack: { + ...next.channels?.slack, + enabled: true, + ...(input.useEnv + ? {} + : { + ...(input.botToken ? { botToken: input.botToken } : {}), + ...(input.appToken ? { appToken: input.appToken } : {}), + }), + }, }, - }), - }; -} + }; + } + return { + ...next, + channels: { + ...next.channels, + slack: { + ...next.channels?.slack, + enabled: true, + accounts: { + ...next.channels?.slack?.accounts, + [accountId]: { + ...next.channels?.slack?.accounts?.[accountId], + enabled: true, + ...(input.botToken ? { botToken: input.botToken } : {}), + ...(input.appToken ? { appToken: input.appToken } : {}), + }, + }, + }, + }, + }; + }, +}; -export function createSlackSetupWizardBase(handlers: SlackSetupWizardHandlers): ChannelSetupWizard { +export function createSlackSetupWizardProxy( + loadWizard: () => Promise<{ slackSetupWizard: ChannelSetupWizard }>, +) { const slackDmPolicy: ChannelSetupDmPolicy = { label: "Slack", channel, @@ -147,7 +126,13 @@ export function createSlackSetupWizardBase(handlers: SlackSetupWizardHandlers): channel, dmPolicy: policy, }), - promptAllowFrom: handlers.promptAllowFrom, + promptAllowFrom: async ({ cfg, prompter, accountId }) => { + const wizard = (await loadWizard()).slackSetupWizard; + if (!wizard.dmPolicy?.promptAllowFrom) { + return cfg; + } + return await wizard.dmPolicy.promptAllowFrom({ cfg, prompter, accountId }); + }, }; return { @@ -182,20 +167,88 @@ export function createSlackSetupWizardBase(handlers: SlackSetupWizardHandlers): apply: ({ cfg, accountId }) => enableSlackAccount(cfg, accountId), }, credentials: [ - buildSlackTokenCredential({ + { inputKey: "botToken", providerHint: "slack-bot", credentialLabel: "Slack bot token", preferredEnvVar: "SLACK_BOT_TOKEN", + envPrompt: "SLACK_BOT_TOKEN detected. Use env var?", + keepPrompt: "Slack bot token already configured. Keep it?", inputPrompt: "Enter Slack bot token (xoxb-...)", - }), - buildSlackTokenCredential({ + allowEnv: ({ accountId }: { accountId: string }) => accountId === DEFAULT_ACCOUNT_ID, + inspect: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId: string }) => { + const resolved = resolveSlackAccount({ cfg, accountId }); + return { + accountConfigured: + Boolean(resolved.botToken) || hasConfiguredSecretInput(resolved.config.botToken), + hasConfiguredValue: hasConfiguredSecretInput(resolved.config.botToken), + resolvedValue: resolved.botToken?.trim() || undefined, + envValue: + accountId === DEFAULT_ACCOUNT_ID ? process.env.SLACK_BOT_TOKEN?.trim() : undefined, + }; + }, + applyUseEnv: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId: string }) => + enableSlackAccount(cfg, accountId), + applySet: ({ + cfg, + accountId, + value, + }: { + cfg: OpenClawConfig; + accountId: string; + value: unknown; + }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { + enabled: true, + botToken: value, + }, + }), + }, + { inputKey: "appToken", providerHint: "slack-app", credentialLabel: "Slack app token", preferredEnvVar: "SLACK_APP_TOKEN", + envPrompt: "SLACK_APP_TOKEN detected. Use env var?", + keepPrompt: "Slack app token already configured. Keep it?", inputPrompt: "Enter Slack app token (xapp-...)", - }), + allowEnv: ({ accountId }: { accountId: string }) => accountId === DEFAULT_ACCOUNT_ID, + inspect: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId: string }) => { + const resolved = resolveSlackAccount({ cfg, accountId }); + return { + accountConfigured: + Boolean(resolved.appToken) || hasConfiguredSecretInput(resolved.config.appToken), + hasConfiguredValue: hasConfiguredSecretInput(resolved.config.appToken), + resolvedValue: resolved.appToken?.trim() || undefined, + envValue: + accountId === DEFAULT_ACCOUNT_ID ? process.env.SLACK_APP_TOKEN?.trim() : undefined, + }; + }, + applyUseEnv: ({ cfg, accountId }: { cfg: OpenClawConfig; accountId: string }) => + enableSlackAccount(cfg, accountId), + applySet: ({ + cfg, + accountId, + value, + }: { + cfg: OpenClawConfig; + accountId: string; + value: unknown; + }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { + enabled: true, + appToken: value, + }, + }), + }, ], dmPolicy: slackDmPolicy, allowFrom: { @@ -220,7 +273,28 @@ export function createSlackSetupWizardBase(handlers: SlackSetupWizardHandlers): idPattern: /^[A-Z][A-Z0-9]+$/i, normalizeId: (id) => id.toUpperCase(), }), - resolveEntries: handlers.resolveAllowFromEntries, + resolveEntries: async ({ + cfg, + accountId, + credentialValues, + entries, + }: { + cfg: OpenClawConfig; + accountId: string; + credentialValues: { botToken?: string }; + entries: string[]; + }) => { + const wizard = (await loadWizard()).slackSetupWizard; + if (!wizard.allowFrom) { + return entries.map((input) => ({ input, resolved: false, id: null })); + } + return await wizard.allowFrom.resolveEntries({ + cfg, + accountId, + credentialValues, + entries, + }); + }, apply: ({ cfg, accountId, @@ -263,22 +337,44 @@ export function createSlackSetupWizardBase(handlers: SlackSetupWizardHandlers): accountId, groupPolicy: policy, }), - resolveAllowlist: async (params: SlackGroupAllowlistResolverParams) => { + resolveAllowlist: async ({ + cfg, + accountId, + credentialValues, + entries, + prompter, + }: { + cfg: OpenClawConfig; + accountId: string; + credentialValues: { botToken?: string }; + entries: string[]; + prompter: { note: (message: string, title?: string) => Promise }; + }) => { try { - return await handlers.resolveGroupAllowlist(params); + const wizard = (await loadWizard()).slackSetupWizard; + if (!wizard.groupAccess?.resolveAllowlist) { + return entries; + } + return await wizard.groupAccess.resolveAllowlist({ + cfg, + accountId, + credentialValues, + entries, + prompter, + }); } catch (error) { await noteChannelLookupFailure({ - prompter: params.prompter, + prompter, label: "Slack channels", error, }); await noteChannelLookupSummary({ - prompter: params.prompter, + prompter, label: "Slack channels", resolvedSections: [], - unresolved: params.entries, + unresolved: entries, }); - return params.entries; + return entries; } }, applyAllowlist: ({ @@ -294,42 +390,3 @@ export function createSlackSetupWizardBase(handlers: SlackSetupWizardHandlers): disable: (cfg: OpenClawConfig) => setSetupChannelEnabled(cfg, channel, false), } satisfies ChannelSetupWizard; } - -export function createSlackSetupWizardProxy( - loadWizard: () => Promise<{ slackSetupWizard: ChannelSetupWizard }>, -) { - return createSlackSetupWizardBase({ - promptAllowFrom: async ({ cfg, prompter, accountId }) => { - const wizard = (await loadWizard()).slackSetupWizard; - if (!wizard.dmPolicy?.promptAllowFrom) { - return cfg; - } - return await wizard.dmPolicy.promptAllowFrom({ cfg, prompter, accountId }); - }, - resolveAllowFromEntries: async ({ cfg, accountId, credentialValues, entries }) => { - const wizard = (await loadWizard()).slackSetupWizard; - if (!wizard.allowFrom) { - return entries.map((input) => ({ input, resolved: false, id: null })); - } - return await wizard.allowFrom.resolveEntries({ - cfg, - accountId, - credentialValues, - entries, - }); - }, - resolveGroupAllowlist: async ({ cfg, accountId, credentialValues, entries, prompter }) => { - const wizard = (await loadWizard()).slackSetupWizard; - if (!wizard.groupAccess?.resolveAllowlist) { - return entries; - } - return (await wizard.groupAccess.resolveAllowlist({ - cfg, - accountId, - credentialValues, - entries, - prompter, - })) as string[]; - }, - }); -} diff --git a/extensions/slack/src/setup-surface.ts b/extensions/slack/src/setup-surface.ts index 8f5024276ca..1dbfa4f02ce 100644 --- a/extensions/slack/src/setup-surface.ts +++ b/extensions/slack/src/setup-surface.ts @@ -1,22 +1,50 @@ import { + DEFAULT_ACCOUNT_ID, formatDocsLink, + hasConfiguredSecretInput, noteChannelLookupFailure, noteChannelLookupSummary, + normalizeAccountId, type OpenClawConfig, parseMentionOrPrefixedId, + patchChannelConfigForAccount, promptLegacyChannelAllowFrom, resolveSetupAccountId, + setAccountGroupPolicyForChannel, + setLegacyChannelDmPolicyWithAllowFrom, + setSetupChannelEnabled, type WizardPrompter, -} from "../../../src/plugin-sdk-internal/setup.js"; +} from "openclaw/plugin-sdk/setup"; import type { + ChannelSetupDmPolicy, ChannelSetupWizard, ChannelSetupWizardAllowFromEntry, -} from "../../../src/plugin-sdk-internal/setup.js"; -import { resolveDefaultSlackAccountId, resolveSlackAccount } from "./accounts.js"; +} from "openclaw/plugin-sdk/setup"; +import { inspectSlackAccount } from "./account-inspect.js"; +import { + listSlackAccountIds, + resolveDefaultSlackAccountId, + resolveSlackAccount, + type ResolvedSlackAccount, +} from "./accounts.js"; import { resolveSlackChannelAllowlist } from "./resolve-channels.js"; import { resolveSlackUserAllowlist } from "./resolve-users.js"; -import { createSlackSetupWizardBase } from "./setup-core.js"; -import { SLACK_CHANNEL as channel } from "./shared.js"; +import { slackSetupAdapter } from "./setup-core.js"; +import { + buildSlackSetupLines, + isSlackSetupAccountConfigured, + setSlackChannelAllowlist, + SLACK_CHANNEL as channel, +} from "./shared.js"; + +function enableSlackAccount(cfg: OpenClawConfig, accountId: string): OpenClawConfig { + return patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { enabled: true }, + }); +} async function resolveSlackAllowFromEntries(params: { token?: string; @@ -89,45 +117,211 @@ async function promptSlackAllowFrom(params: { }); } -export const slackSetupWizard: ChannelSetupWizard = createSlackSetupWizardBase({ - promptAllowFrom: promptSlackAllowFrom, - resolveAllowFromEntries: async ({ credentialValues, entries }) => - await resolveSlackAllowFromEntries({ - token: credentialValues.botToken, - entries, - }), - resolveGroupAllowlist: async ({ cfg, accountId, credentialValues, entries, prompter }) => { - let keys = entries; - const accountWithTokens = resolveSlackAccount({ +const slackDmPolicy: ChannelSetupDmPolicy = { + label: "Slack", + channel, + policyKey: "channels.slack.dmPolicy", + allowFromKey: "channels.slack.allowFrom", + getCurrent: (cfg) => + cfg.channels?.slack?.dmPolicy ?? cfg.channels?.slack?.dm?.policy ?? "pairing", + setPolicy: (cfg, policy) => + setLegacyChannelDmPolicyWithAllowFrom({ cfg, - accountId, - }); - const activeBotToken = accountWithTokens.botToken || credentialValues.botToken || ""; - if (activeBotToken && entries.length > 0) { - try { - const resolved = await resolveSlackChannelAllowlist({ - token: activeBotToken, - entries, - }); - const resolvedKeys = resolved - .filter((entry) => entry.resolved && entry.id) - .map((entry) => entry.id as string); - const unresolved = resolved.filter((entry) => !entry.resolved).map((entry) => entry.input); - keys = [...resolvedKeys, ...unresolved.map((entry) => entry.trim()).filter(Boolean)]; - await noteChannelLookupSummary({ - prompter, - label: "Slack channels", - resolvedSections: [{ title: "Resolved", values: resolvedKeys }], - unresolved, - }); - } catch (error) { - await noteChannelLookupFailure({ - prompter, - label: "Slack channels", - error, - }); - } - } - return keys; + channel, + dmPolicy: policy, + }), + promptAllowFrom: promptSlackAllowFrom, +}; + +export const slackSetupWizard: ChannelSetupWizard = { + channel, + status: { + configuredLabel: "configured", + unconfiguredLabel: "needs tokens", + configuredHint: "configured", + unconfiguredHint: "needs tokens", + configuredScore: 2, + unconfiguredScore: 1, + resolveConfigured: ({ cfg }) => + listSlackAccountIds(cfg).some((accountId) => { + const account = inspectSlackAccount({ cfg, accountId }); + return account.configured; + }), }, -}); + introNote: { + title: "Slack socket mode tokens", + lines: buildSlackSetupLines(), + shouldShow: ({ cfg, accountId }) => + !isSlackSetupAccountConfigured(resolveSlackAccount({ cfg, accountId })), + }, + envShortcut: { + prompt: "SLACK_BOT_TOKEN + SLACK_APP_TOKEN detected. Use env vars?", + preferredEnvVar: "SLACK_BOT_TOKEN", + isAvailable: ({ cfg, accountId }) => + accountId === DEFAULT_ACCOUNT_ID && + Boolean(process.env.SLACK_BOT_TOKEN?.trim()) && + Boolean(process.env.SLACK_APP_TOKEN?.trim()) && + !isSlackSetupAccountConfigured(resolveSlackAccount({ cfg, accountId })), + apply: ({ cfg, accountId }) => enableSlackAccount(cfg, accountId), + }, + credentials: [ + { + inputKey: "botToken", + providerHint: "slack-bot", + credentialLabel: "Slack bot token", + preferredEnvVar: "SLACK_BOT_TOKEN", + envPrompt: "SLACK_BOT_TOKEN detected. Use env var?", + keepPrompt: "Slack bot token already configured. Keep it?", + inputPrompt: "Enter Slack bot token (xoxb-...)", + allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID, + inspect: ({ cfg, accountId }) => { + const resolved = resolveSlackAccount({ cfg, accountId }); + return { + accountConfigured: + Boolean(resolved.botToken) || hasConfiguredSecretInput(resolved.config.botToken), + hasConfiguredValue: hasConfiguredSecretInput(resolved.config.botToken), + resolvedValue: resolved.botToken?.trim() || undefined, + envValue: + accountId === DEFAULT_ACCOUNT_ID ? process.env.SLACK_BOT_TOKEN?.trim() : undefined, + }; + }, + applyUseEnv: ({ cfg, accountId }) => enableSlackAccount(cfg, accountId), + applySet: ({ cfg, accountId, value }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { + enabled: true, + botToken: value, + }, + }), + }, + { + inputKey: "appToken", + providerHint: "slack-app", + credentialLabel: "Slack app token", + preferredEnvVar: "SLACK_APP_TOKEN", + envPrompt: "SLACK_APP_TOKEN detected. Use env var?", + keepPrompt: "Slack app token already configured. Keep it?", + inputPrompt: "Enter Slack app token (xapp-...)", + allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID, + inspect: ({ cfg, accountId }) => { + const resolved = resolveSlackAccount({ cfg, accountId }); + return { + accountConfigured: + Boolean(resolved.appToken) || hasConfiguredSecretInput(resolved.config.appToken), + hasConfiguredValue: hasConfiguredSecretInput(resolved.config.appToken), + resolvedValue: resolved.appToken?.trim() || undefined, + envValue: + accountId === DEFAULT_ACCOUNT_ID ? process.env.SLACK_APP_TOKEN?.trim() : undefined, + }; + }, + applyUseEnv: ({ cfg, accountId }) => enableSlackAccount(cfg, accountId), + applySet: ({ cfg, accountId, value }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { + enabled: true, + appToken: value, + }, + }), + }, + ], + dmPolicy: slackDmPolicy, + allowFrom: { + helpTitle: "Slack allowlist", + helpLines: [ + "Allowlist Slack DMs by username (we resolve to user ids).", + "Examples:", + "- U12345678", + "- @alice", + "Multiple entries: comma-separated.", + `Docs: ${formatDocsLink("/slack", "slack")}`, + ], + credentialInputKey: "botToken", + message: "Slack allowFrom (usernames or ids)", + placeholder: "@alice, U12345678", + invalidWithoutCredentialNote: "Slack token missing; use user ids (or mention form) only.", + parseId: (value) => + parseMentionOrPrefixedId({ + value, + mentionPattern: /^<@([A-Z0-9]+)>$/i, + prefixPattern: /^(slack:|user:)/i, + idPattern: /^[A-Z][A-Z0-9]+$/i, + normalizeId: (id) => id.toUpperCase(), + }), + resolveEntries: async ({ credentialValues, entries }) => + await resolveSlackAllowFromEntries({ + token: credentialValues.botToken, + entries, + }), + apply: ({ cfg, accountId, allowFrom }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { dmPolicy: "allowlist", allowFrom }, + }), + }, + groupAccess: { + label: "Slack channels", + placeholder: "#general, #private, C123", + currentPolicy: ({ cfg, accountId }) => + resolveSlackAccount({ cfg, accountId }).config.groupPolicy ?? "allowlist", + currentEntries: ({ cfg, accountId }) => + Object.entries(resolveSlackAccount({ cfg, accountId }).config.channels ?? {}) + .filter(([, value]) => value?.allow !== false && value?.enabled !== false) + .map(([key]) => key), + updatePrompt: ({ cfg, accountId }) => + Boolean(resolveSlackAccount({ cfg, accountId }).config.channels), + setPolicy: ({ cfg, accountId, policy }) => + setAccountGroupPolicyForChannel({ + cfg, + channel, + accountId, + groupPolicy: policy, + }), + resolveAllowlist: async ({ cfg, accountId, credentialValues, entries, prompter }) => { + let keys = entries; + const accountWithTokens = resolveSlackAccount({ + cfg, + accountId, + }); + const activeBotToken = accountWithTokens.botToken || credentialValues.botToken || ""; + if (activeBotToken && entries.length > 0) { + try { + const resolved = await resolveSlackChannelAllowlist({ + token: activeBotToken, + entries, + }); + const resolvedKeys = resolved + .filter((entry) => entry.resolved && entry.id) + .map((entry) => entry.id as string); + const unresolved = resolved + .filter((entry) => !entry.resolved) + .map((entry) => entry.input); + keys = [...resolvedKeys, ...unresolved.map((entry) => entry.trim()).filter(Boolean)]; + await noteChannelLookupSummary({ + prompter, + label: "Slack channels", + resolvedSections: [{ title: "Resolved", values: resolvedKeys }], + unresolved, + }); + } catch (error) { + await noteChannelLookupFailure({ + prompter, + label: "Slack channels", + error, + }); + } + } + return keys; + }, + applyAllowlist: ({ cfg, accountId, resolved }) => + setSlackChannelAllowlist(cfg, accountId, resolved as string[]), + }, + disable: (cfg) => setSetupChannelEnabled(cfg, channel, false), +}; diff --git a/extensions/slack/src/stream-mode.ts b/extensions/slack/src/stream-mode.ts index 819eb4fa722..f341c0a5304 100644 --- a/extensions/slack/src/stream-mode.ts +++ b/extensions/slack/src/stream-mode.ts @@ -4,7 +4,7 @@ import { resolveSlackStreamingMode, type SlackLegacyDraftStreamMode, type StreamingMode, -} from "../../../src/config/discord-preview-streaming.js"; +} from "openclaw/plugin-sdk/config-runtime"; export type SlackStreamMode = SlackLegacyDraftStreamMode; export type SlackStreamingMode = StreamingMode; diff --git a/extensions/slack/src/streaming.ts b/extensions/slack/src/streaming.ts index b6269412c9d..1685e378f61 100644 --- a/extensions/slack/src/streaming.ts +++ b/extensions/slack/src/streaming.ts @@ -13,7 +13,7 @@ import type { WebClient } from "@slack/web-api"; import type { ChatStreamer } from "@slack/web-api/dist/chat-stream.js"; -import { logVerbose } from "../../../src/globals.js"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; // --------------------------------------------------------------------------- // Types diff --git a/extensions/slack/src/targets.ts b/extensions/slack/src/targets.ts index 5d80650daff..43162a447d5 100644 --- a/extensions/slack/src/targets.ts +++ b/extensions/slack/src/targets.ts @@ -6,7 +6,7 @@ import { type MessagingTarget, type MessagingTargetKind, type MessagingTargetParseOptions, -} from "../../../src/channels/targets.js"; +} from "openclaw/plugin-sdk/channel-runtime"; export type SlackTargetKind = MessagingTargetKind; diff --git a/extensions/slack/src/threading-tool-context.ts b/extensions/slack/src/threading-tool-context.ts index 206ce98b42f..30451be5b6b 100644 --- a/extensions/slack/src/threading-tool-context.ts +++ b/extensions/slack/src/threading-tool-context.ts @@ -1,8 +1,8 @@ import type { ChannelThreadingContext, ChannelThreadingToolContext, -} from "../../../src/channels/plugins/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveSlackAccount, resolveSlackReplyToMode } from "./accounts.js"; export function buildSlackThreadingToolContext(params: { diff --git a/extensions/slack/src/threading.ts b/extensions/slack/src/threading.ts index ccef2e5e081..d072ab796c0 100644 --- a/extensions/slack/src/threading.ts +++ b/extensions/slack/src/threading.ts @@ -1,4 +1,4 @@ -import type { ReplyToMode } from "../../../src/config/types.js"; +import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; import type { SlackAppMentionEvent, SlackMessageEvent } from "./types.js"; export type SlackThreadContext = { diff --git a/extensions/slack/src/token.ts b/extensions/slack/src/token.ts index cebda65e335..36f31c89383 100644 --- a/extensions/slack/src/token.ts +++ b/extensions/slack/src/token.ts @@ -1,4 +1,4 @@ -import { normalizeResolvedSecretInputString } from "../../../src/config/types.secrets.js"; +import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/config-runtime"; export function normalizeSlackToken(raw?: unknown): string | undefined { return normalizeResolvedSecretInputString({ diff --git a/extensions/synthetic/index.ts b/extensions/synthetic/index.ts index ed029dc7cce..19e7424bfb7 100644 --- a/extensions/synthetic/index.ts +++ b/extensions/synthetic/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applySyntheticConfig, SYNTHETIC_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; import { buildSyntheticProvider } from "./provider-catalog.js"; diff --git a/extensions/synthetic/onboard.ts b/extensions/synthetic/onboard.ts index 34199d4db2b..d11f2cb0e9b 100644 --- a/extensions/synthetic/onboard.ts +++ b/extensions/synthetic/onboard.ts @@ -3,12 +3,12 @@ import { SYNTHETIC_BASE_URL, SYNTHETIC_DEFAULT_MODEL_REF, SYNTHETIC_MODEL_CATALOG, -} from "../../src/agents/synthetic-models.js"; +} from "openclaw/plugin-sdk/provider-models"; import { applyAgentDefaultModelPrimary, applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export { SYNTHETIC_DEFAULT_MODEL_REF }; diff --git a/extensions/synthetic/provider-catalog.ts b/extensions/synthetic/provider-catalog.ts index 181affdde2b..e46b08682c2 100644 --- a/extensions/synthetic/provider-catalog.ts +++ b/extensions/synthetic/provider-catalog.ts @@ -1,9 +1,9 @@ import { buildSyntheticModelDefinition, + type ModelProviderConfig, SYNTHETIC_BASE_URL, SYNTHETIC_MODEL_CATALOG, -} from "../../src/agents/synthetic-models.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +} from "openclaw/plugin-sdk/provider-models"; export function buildSyntheticProvider(): ModelProviderConfig { return { diff --git a/extensions/talk-voice/index.ts b/extensions/talk-voice/index.ts index 8f698262e3e..fb9e7bdb39d 100644 --- a/extensions/talk-voice/index.ts +++ b/extensions/talk-voice/index.ts @@ -1,6 +1,6 @@ +import { resolveActiveTalkProviderConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { SpeechVoiceOption } from "openclaw/plugin-sdk/speech"; import type { OpenClawPluginApi } from "openclaw/plugin-sdk/talk-voice"; -import { resolveActiveTalkProviderConfig } from "../../src/config/talk.js"; -import type { SpeechVoiceOption } from "../../src/tts/provider-types.js"; function mask(s: string, keep: number = 6): string { const trimmed = s.trim(); diff --git a/extensions/telegram/src/account-inspect.ts b/extensions/telegram/src/account-inspect.ts index 1e428c237fa..6295a231451 100644 --- a/extensions/telegram/src/account-inspect.ts +++ b/extensions/telegram/src/account-inspect.ts @@ -1,14 +1,14 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; +import { resolveAccountWithDefaultFallback } from "openclaw/plugin-sdk/account-resolution"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { coerceSecretRef, hasConfiguredSecretInput, normalizeSecretInputString, -} from "../../../src/config/types.secrets.js"; -import { tryReadSecretFileSync } from "../../../src/infra/secret-file.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"; +} from "openclaw/plugin-sdk/config-runtime"; +import { tryReadSecretFileSync } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveDefaultSecretProviderAlias } from "openclaw/plugin-sdk/provider-auth"; +import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing"; +import type { TelegramAccountConfig } from "openclaw/plugin-sdk/telegram"; import { mergeTelegramAccountConfig, resolveDefaultTelegramAccountId, diff --git a/extensions/telegram/src/accounts.ts b/extensions/telegram/src/accounts.ts index 6d2255e00a1..2e0c053d0d4 100644 --- a/extensions/telegram/src/accounts.ts +++ b/extensions/telegram/src/accounts.ts @@ -1,27 +1,22 @@ import util from "node:util"; -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"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; import { + createAccountActionGate, + DEFAULT_ACCOUNT_ID, listConfiguredAccountIds as listConfiguredAccountIdsFromSection, + normalizeAccountId, + normalizeOptionalAccountId, + resolveAccountEntry, resolveAccountWithDefaultFallback, -} 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"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/account-resolution"; +import { isTruthyEnvValue } from "openclaw/plugin-sdk/infra-runtime"; import { listBoundAccountIds, resolveDefaultAgentBoundAccountId, -} from "../../../src/routing/bindings.js"; -import { formatSetExplicitDefaultInstruction } from "../../../src/routing/default-account-warnings.js"; -import { - DEFAULT_ACCOUNT_ID, - normalizeAccountId, - normalizeOptionalAccountId, -} from "../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/routing"; +import { formatSetExplicitDefaultInstruction } from "openclaw/plugin-sdk/routing"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import type { TelegramAccountConfig, TelegramActionConfig } from "openclaw/plugin-sdk/telegram"; import { resolveTelegramToken } from "./token.js"; let log: ReturnType | null = null; diff --git a/extensions/telegram/src/api-logging.ts b/extensions/telegram/src/api-logging.ts index 6af9d7ae5a3..2abc74f0894 100644 --- a/extensions/telegram/src/api-logging.ts +++ b/extensions/telegram/src/api-logging.ts @@ -1,7 +1,7 @@ -import { danger } from "../../../src/globals.js"; -import { formatErrorMessage } from "../../../src/infra/errors.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; export type TelegramApiLogger = (message: string) => void; diff --git a/extensions/telegram/src/approval-buttons.ts b/extensions/telegram/src/approval-buttons.ts index a996ed3adf3..8ce836c754b 100644 --- a/extensions/telegram/src/approval-buttons.ts +++ b/extensions/telegram/src/approval-buttons.ts @@ -1,4 +1,4 @@ -import type { ExecApprovalReplyDecision } from "../../../src/infra/exec-approval-reply.js"; +import type { ExecApprovalReplyDecision } from "openclaw/plugin-sdk/infra-runtime"; import type { TelegramInlineButtons } from "./button-types.js"; const MAX_CALLBACK_DATA_BYTES = 64; diff --git a/extensions/telegram/src/audit-membership-runtime.ts b/extensions/telegram/src/audit-membership-runtime.ts index 694ad338c5b..930d768778e 100644 --- a/extensions/telegram/src/audit-membership-runtime.ts +++ b/extensions/telegram/src/audit-membership-runtime.ts @@ -1,5 +1,5 @@ -import { isRecord } from "../../../src/utils.js"; -import { fetchWithTimeout } from "../../../src/utils/fetch-timeout.js"; +import { isRecord } from "openclaw/plugin-sdk/text-runtime"; +import { fetchWithTimeout } from "openclaw/plugin-sdk/text-runtime"; import type { AuditTelegramGroupMembershipParams, TelegramGroupMembershipAudit, diff --git a/extensions/telegram/src/audit.ts b/extensions/telegram/src/audit.ts index 507f161edca..f7fb0969090 100644 --- a/extensions/telegram/src/audit.ts +++ b/extensions/telegram/src/audit.ts @@ -1,5 +1,5 @@ -import type { TelegramGroupConfig } from "../../../src/config/types.js"; -import type { TelegramNetworkConfig } from "../../../src/config/types.telegram.js"; +import type { TelegramGroupConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { TelegramNetworkConfig } from "openclaw/plugin-sdk/config-runtime"; export type TelegramGroupMembershipAuditEntry = { chatId: string; diff --git a/extensions/telegram/src/bot-access.ts b/extensions/telegram/src/bot-access.ts index bee8392e686..c89a8fe6f48 100644 --- a/extensions/telegram/src/bot-access.ts +++ b/extensions/telegram/src/bot-access.ts @@ -2,9 +2,9 @@ import { firstDefined, isSenderIdAllowed, mergeDmAllowFromSources, -} from "../../../src/channels/allow-from.js"; -import type { AllowlistMatch } from "../../../src/channels/allowlist-match.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { AllowlistMatch } from "openclaw/plugin-sdk/channel-runtime"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; export type NormalizedAllowFrom = { entries: string[]; diff --git a/extensions/telegram/src/bot-handlers.ts b/extensions/telegram/src/bot-handlers.ts index 88e61e1c567..18db7c3405f 100644 --- a/extensions/telegram/src/bot-handlers.ts +++ b/extensions/telegram/src/bot-handlers.ts @@ -1,47 +1,47 @@ import type { Message, ReactionTypeEmoji } from "@grammyjs/types"; -import { resolveAgentDir, resolveDefaultAgentId } from "../../../src/agents/agent-scope.js"; -import { resolveDefaultModelForAgent } from "../../../src/agents/model-selection.js"; -import { - createInboundDebouncer, - resolveInboundDebounceMs, -} from "../../../src/auto-reply/inbound-debounce.js"; -import { buildCommandsPaginationKeyboard } from "../../../src/auto-reply/reply/commands-info.js"; -import { - buildModelsProviderData, - formatModelsAvailableHeader, -} from "../../../src/auto-reply/reply/commands-models.js"; -import { resolveStoredModelOverride } from "../../../src/auto-reply/reply/model-selection.js"; -import { listSkillCommandsForAgents } from "../../../src/auto-reply/skill-commands.js"; -import { buildCommandsMessagePaginated } from "../../../src/auto-reply/status.js"; -import { shouldDebounceTextInbound } from "../../../src/channels/inbound-debounce-policy.js"; -import { resolveChannelConfigWrites } from "../../../src/channels/plugins/config-writes.js"; -import { loadConfig } from "../../../src/config/config.js"; -import { writeConfigFile } from "../../../src/config/io.js"; +import { resolveAgentDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime"; +import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime"; +import { shouldDebounceTextInbound } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { writeConfigFile } from "openclaw/plugin-sdk/config-runtime"; import { loadSessionStore, resolveSessionStoreEntry, resolveStorePath, updateSessionStore, -} from "../../../src/config/sessions.js"; -import type { DmPolicy } from "../../../src/config/types.base.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime"; import type { TelegramDirectConfig, TelegramGroupConfig, TelegramTopicConfig, -} from "../../../src/config/types.js"; -import { danger, logVerbose, warn } from "../../../src/globals.js"; -import { enqueueSystemEvent } from "../../../src/infra/system-events.js"; -import { MediaFetchError } from "../../../src/media/fetch.js"; -import { readChannelAllowFromStore } from "../../../src/pairing/pairing-store.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { applyModelOverrideToSessionEntry } from "openclaw/plugin-sdk/config-runtime"; +import { readChannelAllowFromStore } from "openclaw/plugin-sdk/conversation-runtime"; import { buildPluginBindingResolvedText, parsePluginBindingApprovalCustomId, resolvePluginConversationBindingApproval, -} from "../../../src/plugins/conversation-binding.js"; -import { dispatchPluginInteractiveHandler } from "../../../src/plugins/interactive.js"; -import { resolveAgentRoute } from "../../../src/routing/resolve-route.js"; -import { resolveThreadSessionKeys } from "../../../src/routing/session-key.js"; -import { applyModelOverrideToSessionEntry } from "../../../src/sessions/model-overrides.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { MediaFetchError } from "openclaw/plugin-sdk/media-runtime"; +import { dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime"; +import { + createInboundDebouncer, + resolveInboundDebounceMs, +} from "openclaw/plugin-sdk/reply-runtime"; +import { buildCommandsPaginationKeyboard } from "openclaw/plugin-sdk/reply-runtime"; +import { + buildModelsProviderData, + formatModelsAvailableHeader, +} from "openclaw/plugin-sdk/reply-runtime"; +import { resolveStoredModelOverride } from "openclaw/plugin-sdk/reply-runtime"; +import { listSkillCommandsForAgents } from "openclaw/plugin-sdk/reply-runtime"; +import { buildCommandsMessagePaginated } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; +import { danger, logVerbose, warn } from "openclaw/plugin-sdk/runtime-env"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { isSenderAllowed, diff --git a/extensions/telegram/src/bot-message-context.body.ts b/extensions/telegram/src/bot-message-context.body.ts index 8290b02169d..5b4dc2f9cae 100644 --- a/extensions/telegram/src/bot-message-context.body.ts +++ b/extensions/telegram/src/bot-message-context.body.ts @@ -2,29 +2,26 @@ import { findModelInCatalog, loadModelCatalog, modelSupportsVision, -} from "../../../src/agents/model-catalog.js"; -import { resolveDefaultModelForAgent } from "../../../src/agents/model-selection.js"; -import { hasControlCommand } from "../../../src/auto-reply/command-detection.js"; -import { - recordPendingHistoryEntryIfEnabled, - type HistoryEntry, -} from "../../../src/auto-reply/reply/history.js"; -import { - buildMentionRegexes, - matchesMentionWithExplicit, -} from "../../../src/auto-reply/reply/mentions.js"; -import type { MsgContext } from "../../../src/auto-reply/templating.js"; -import { resolveControlCommandGate } from "../../../src/channels/command-gating.js"; -import { formatLocationText, type NormalizedLocation } from "../../../src/channels/location.js"; -import { logInboundDrop } from "../../../src/channels/logging.js"; -import { resolveMentionGatingWithBypass } from "../../../src/channels/mention-gating.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime"; +import { resolveControlCommandGate } from "openclaw/plugin-sdk/channel-runtime"; +import { formatLocationText, type NormalizedLocation } from "openclaw/plugin-sdk/channel-runtime"; +import { logInboundDrop } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { TelegramDirectConfig, TelegramGroupConfig, TelegramTopicConfig, -} from "../../../src/config/types.js"; -import { logVerbose } from "../../../src/globals.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime"; +import { + recordPendingHistoryEntryIfEnabled, + type HistoryEntry, +} from "openclaw/plugin-sdk/reply-runtime"; +import { buildMentionRegexes, matchesMentionWithExplicit } from "openclaw/plugin-sdk/reply-runtime"; +import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { NormalizedAllowFrom } from "./bot-access.js"; import { isSenderAllowed } from "./bot-access.js"; import type { @@ -182,8 +179,7 @@ export async function resolveTelegramInboundBody(params: { if (needsPreflightTranscription) { try { - const { transcribeFirstAudio } = - await import("../../../src/media-understanding/audio-preflight.js"); + const { transcribeFirstAudio } = await import("openclaw/plugin-sdk/media-runtime"); const tempCtx: MsgContext = { MediaPaths: allMedia.length > 0 ? allMedia.map((m) => m.path) : undefined, MediaTypes: diff --git a/extensions/telegram/src/bot-message-context.session.ts b/extensions/telegram/src/bot-message-context.session.ts index 1a2f54cf22f..47bcda8592f 100644 --- a/extensions/telegram/src/bot-message-context.session.ts +++ b/extensions/telegram/src/bot-message-context.session.ts @@ -1,26 +1,26 @@ -import { normalizeCommandBody } from "../../../src/auto-reply/commands-registry.js"; -import { - formatInboundEnvelope, - resolveEnvelopeFormatOptions, -} from "../../../src/auto-reply/envelope.js"; -import { - buildPendingHistoryContextFromMap, - type HistoryEntry, -} from "../../../src/auto-reply/reply/history.js"; -import { finalizeInboundContext } from "../../../src/auto-reply/reply/inbound-context.js"; -import { toLocationContext } from "../../../src/channels/location.js"; -import { recordInboundSession } from "../../../src/channels/session.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { readSessionUpdatedAt, resolveStorePath } from "../../../src/config/sessions.js"; +import { toLocationContext } from "openclaw/plugin-sdk/channel-runtime"; +import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; import type { TelegramDirectConfig, TelegramGroupConfig, TelegramTopicConfig, -} from "../../../src/config/types.js"; -import { logVerbose, shouldLogVerbose } from "../../../src/globals.js"; -import type { ResolvedAgentRoute } from "../../../src/routing/resolve-route.js"; -import { resolveInboundLastRouteSessionKey } from "../../../src/routing/resolve-route.js"; -import { resolvePinnedMainDmOwnerFromAllowlist } from "../../../src/security/dm-policy-shared.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { normalizeCommandBody } from "openclaw/plugin-sdk/reply-runtime"; +import { + formatInboundEnvelope, + resolveEnvelopeFormatOptions, +} from "openclaw/plugin-sdk/reply-runtime"; +import { + buildPendingHistoryContextFromMap, + type HistoryEntry, +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import type { ResolvedAgentRoute } from "openclaw/plugin-sdk/routing"; +import { resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime"; import { normalizeAllowFrom } from "./bot-access.js"; import type { TelegramMediaRef, @@ -63,7 +63,7 @@ export async function buildTelegramInboundContextPayload(params: { stickerCacheHit: boolean; effectiveWasMentioned: boolean; commandAuthorized: boolean; - locationData?: import("../../../src/channels/location.js").NormalizedLocation; + locationData?: import("openclaw/plugin-sdk/channel-runtime").NormalizedLocation; options?: TelegramMessageContextOptions; dmAllowFrom?: Array; }): Promise<{ diff --git a/extensions/telegram/src/bot-message-context.ts b/extensions/telegram/src/bot-message-context.ts index 03bcd429018..d77fd52f2fc 100644 --- a/extensions/telegram/src/bot-message-context.ts +++ b/extensions/telegram/src/bot-message-context.ts @@ -1,17 +1,17 @@ -import { ensureConfiguredAcpRouteReady } from "../../../src/acp/persistent-bindings.route.js"; -import { resolveAckReaction } from "../../../src/agents/identity.js"; -import { shouldAckReaction as shouldAckReactionGate } from "../../../src/channels/ack-reactions.js"; -import { logInboundDrop } from "../../../src/channels/logging.js"; +import { resolveAckReaction } from "openclaw/plugin-sdk/agent-runtime"; +import { shouldAckReaction as shouldAckReactionGate } from "openclaw/plugin-sdk/channel-runtime"; +import { logInboundDrop } from "openclaw/plugin-sdk/channel-runtime"; import { createStatusReactionController, type StatusReactionController, -} from "../../../src/channels/status-reactions.js"; -import { loadConfig } from "../../../src/config/config.js"; -import type { TelegramDirectConfig, TelegramGroupConfig } from "../../../src/config/types.js"; -import { logVerbose } from "../../../src/globals.js"; -import { recordChannelActivity } from "../../../src/infra/channel-activity.js"; -import { buildAgentSessionKey, deriveLastRoutePolicy } from "../../../src/routing/resolve-route.js"; -import { DEFAULT_ACCOUNT_ID, resolveThreadSessionKeys } from "../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { TelegramDirectConfig, TelegramGroupConfig } from "openclaw/plugin-sdk/config-runtime"; +import { ensureConfiguredAcpRouteReady } from "openclaw/plugin-sdk/conversation-runtime"; +import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime"; +import { buildAgentSessionKey, deriveLastRoutePolicy } from "openclaw/plugin-sdk/routing"; +import { DEFAULT_ACCOUNT_ID, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { firstDefined, normalizeAllowFrom, normalizeDmAllowFromWithStore } from "./bot-access.js"; import { resolveTelegramInboundBody } from "./bot-message-context.body.js"; diff --git a/extensions/telegram/src/bot-message-context.types.ts b/extensions/telegram/src/bot-message-context.types.ts index 2853c1a8e34..ca0fbbf3376 100644 --- a/extensions/telegram/src/bot-message-context.types.ts +++ b/extensions/telegram/src/bot-message-context.types.ts @@ -1,12 +1,12 @@ import type { Bot } from "grammy"; -import type { HistoryEntry } from "../../../src/auto-reply/reply/history.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import type { DmPolicy, TelegramDirectConfig, TelegramGroupConfig, TelegramTopicConfig, -} from "../../../src/config/types.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import type { HistoryEntry } from "openclaw/plugin-sdk/reply-runtime"; import type { StickerMetadata, TelegramContext } from "./bot/types.js"; export type TelegramMediaRef = { diff --git a/extensions/telegram/src/bot-message-dispatch.ts b/extensions/telegram/src/bot-message-dispatch.ts index 9b603393450..a8a4c376b0b 100644 --- a/extensions/telegram/src/bot-message-dispatch.ts +++ b/extensions/telegram/src/bot-message-dispatch.ts @@ -1,33 +1,33 @@ import type { Bot } from "grammy"; -import { resolveAgentDir } from "../../../src/agents/agent-scope.js"; +import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime"; import { findModelInCatalog, loadModelCatalog, modelSupportsVision, -} from "../../../src/agents/model-catalog.js"; -import { resolveDefaultModelForAgent } from "../../../src/agents/model-selection.js"; -import { resolveChunkMode } from "../../../src/auto-reply/chunk.js"; -import { clearHistoryEntriesIfEnabled } from "../../../src/auto-reply/reply/history.js"; -import { dispatchReplyWithBufferedBlockDispatcher } from "../../../src/auto-reply/reply/provider-dispatcher.js"; -import type { ReplyPayload } from "../../../src/auto-reply/types.js"; -import { removeAckReactionAfterReply } from "../../../src/channels/ack-reactions.js"; -import { logAckFailure, logTypingFailure } from "../../../src/channels/logging.js"; -import { createReplyPrefixOptions } from "../../../src/channels/reply-prefix.js"; -import { createTypingCallbacks } from "../../../src/channels/typing.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime"; +import { removeAckReactionAfterReply } from "openclaw/plugin-sdk/channel-runtime"; +import { logAckFailure, logTypingFailure } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; import { loadSessionStore, resolveSessionStoreEntry, resolveStorePath, -} from "../../../src/config/sessions.js"; +} from "openclaw/plugin-sdk/config-runtime"; import type { OpenClawConfig, ReplyToMode, TelegramAccountConfig, -} from "../../../src/config/types.js"; -import { danger, logVerbose } from "../../../src/globals.js"; -import { getAgentScopedMediaLocalRoots } from "../../../src/media/local-roots.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +import { resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import { clearHistoryEntriesIfEnabled } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchReplyWithBufferedBlockDispatcher } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import type { TelegramMessageContext } from "./bot-message-context.js"; import type { TelegramBotOptions } from "./bot.js"; import { deliverReplies } from "./bot/delivery.js"; diff --git a/extensions/telegram/src/bot-message.ts b/extensions/telegram/src/bot-message.ts index 0a5d44c65db..cb625c7b965 100644 --- a/extensions/telegram/src/bot-message.ts +++ b/extensions/telegram/src/bot-message.ts @@ -1,7 +1,7 @@ -import type { ReplyToMode } from "../../../src/config/config.js"; -import type { TelegramAccountConfig } from "../../../src/config/types.telegram.js"; -import { danger } from "../../../src/globals.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; +import type { TelegramAccountConfig } from "openclaw/plugin-sdk/config-runtime"; +import { danger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { buildTelegramMessageContext, type BuildTelegramMessageContextParams, diff --git a/extensions/telegram/src/bot-native-command-menu.ts b/extensions/telegram/src/bot-native-command-menu.ts index 73fa2d2345a..091a6e52c1b 100644 --- a/extensions/telegram/src/bot-native-command-menu.ts +++ b/extensions/telegram/src/bot-native-command-menu.ts @@ -3,13 +3,13 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import type { Bot } from "grammy"; -import { resolveStateDir } from "../../../src/config/paths.js"; import { normalizeTelegramCommandName, TELEGRAM_COMMAND_NAME_PATTERN, -} from "../../../src/config/telegram-custom-commands.js"; -import { logVerbose } from "../../../src/globals.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; import { withTelegramApiErrorLogging } from "./api-logging.js"; export const TELEGRAM_MAX_COMMANDS = 100; diff --git a/extensions/telegram/src/bot-native-commands.test-helpers.ts b/extensions/telegram/src/bot-native-commands.test-helpers.ts index 33c3f04f904..a39bdd23da6 100644 --- a/extensions/telegram/src/bot-native-commands.test-helpers.ts +++ b/extensions/telegram/src/bot-native-commands.test-helpers.ts @@ -1,24 +1,24 @@ +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { ChannelGroupPolicy } from "openclaw/plugin-sdk/config-runtime"; +import type { TelegramAccountConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { vi } from "vitest"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { ChannelGroupPolicy } from "../../../src/config/group-policy.js"; -import type { TelegramAccountConfig } from "../../../src/config/types.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; -import type { MockFn } from "../../../src/test-utils/vitest-mock-fn.js"; import { registerTelegramNativeCommands } from "./bot-native-commands.js"; type RegisterTelegramNativeCommandsParams = Parameters[0]; type GetPluginCommandSpecsFn = - typeof import("../../../src/plugins/commands.js").getPluginCommandSpecs; -type MatchPluginCommandFn = typeof import("../../../src/plugins/commands.js").matchPluginCommand; + typeof import("openclaw/plugin-sdk/plugin-runtime").getPluginCommandSpecs; +type MatchPluginCommandFn = typeof import("openclaw/plugin-sdk/plugin-runtime").matchPluginCommand; type ExecutePluginCommandFn = - typeof import("../../../src/plugins/commands.js").executePluginCommand; + typeof import("openclaw/plugin-sdk/plugin-runtime").executePluginCommand; type DispatchReplyWithBufferedBlockDispatcherFn = - typeof import("../../../src/auto-reply/reply/provider-dispatcher.js").dispatchReplyWithBufferedBlockDispatcher; + typeof import("openclaw/plugin-sdk/reply-runtime").dispatchReplyWithBufferedBlockDispatcher; type DispatchReplyWithBufferedBlockDispatcherResult = Awaited< ReturnType >; type RecordInboundSessionMetaSafeFn = - typeof import("../../../src/channels/session-meta.js").recordInboundSessionMetaSafe; + typeof import("openclaw/plugin-sdk/channel-runtime").recordInboundSessionMetaSafe; type AnyMock = MockFn<(...args: unknown[]) => unknown>; type AnyAsyncMock = MockFn<(...args: unknown[]) => Promise>; type NativeCommandHarness = { @@ -44,7 +44,7 @@ export const getPluginCommandSpecs = pluginCommandMocks.getPluginCommandSpecs; export const matchPluginCommand = pluginCommandMocks.matchPluginCommand; export const executePluginCommand = pluginCommandMocks.executePluginCommand; -vi.mock("../../../src/plugins/commands.js", () => ({ +vi.mock("openclaw/plugin-sdk/plugin-runtime", () => ({ getPluginCommandSpecs: pluginCommandMocks.getPluginCommandSpecs, matchPluginCommand: pluginCommandMocks.matchPluginCommand, executePluginCommand: pluginCommandMocks.executePluginCommand, @@ -67,17 +67,17 @@ const replyPipelineMocks = vi.hoisted(() => { export const dispatchReplyWithBufferedBlockDispatcher = replyPipelineMocks.dispatchReplyWithBufferedBlockDispatcher; -vi.mock("../../../src/auto-reply/reply/inbound-context.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ finalizeInboundContext: replyPipelineMocks.finalizeInboundContext, })); -vi.mock("../../../src/auto-reply/reply/provider-dispatcher.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ dispatchReplyWithBufferedBlockDispatcher: replyPipelineMocks.dispatchReplyWithBufferedBlockDispatcher, })); -vi.mock("../../../src/channels/reply-prefix.js", () => ({ +vi.mock("openclaw/plugin-sdk/channel-runtime", () => ({ createReplyPrefixOptions: replyPipelineMocks.createReplyPrefixOptions, })); -vi.mock("../../../src/channels/session-meta.js", () => ({ +vi.mock("openclaw/plugin-sdk/channel-runtime", () => ({ recordInboundSessionMetaSafe: replyPipelineMocks.recordInboundSessionMetaSafe, })); @@ -86,7 +86,7 @@ const deliveryMocks = vi.hoisted(() => ({ })); export const deliverReplies = deliveryMocks.deliverReplies; vi.mock("./bot/delivery.js", () => ({ deliverReplies: deliveryMocks.deliverReplies })); -vi.mock("../../../src/pairing/pairing-store.js", () => ({ +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore: vi.fn(async () => []), })); diff --git a/extensions/telegram/src/bot-native-commands.ts b/extensions/telegram/src/bot-native-commands.ts index 64874d1f8eb..9cc757cec91 100644 --- a/extensions/telegram/src/bot-native-commands.ts +++ b/extensions/telegram/src/bot-native-commands.ts @@ -1,8 +1,33 @@ import type { Bot, Context } from "grammy"; -import { ensureConfiguredAcpRouteReady } from "../../../src/acp/persistent-bindings.route.js"; -import { resolveChunkMode } from "../../../src/auto-reply/chunk.js"; -import { resolveCommandAuthorization } from "../../../src/auto-reply/command-auth.js"; -import type { CommandArgs } from "../../../src/auto-reply/commands-registry.js"; +import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveNativeCommandSessionTargets } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { recordInboundSessionMetaSafe } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { ChannelGroupPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { + normalizeTelegramCommandName, + resolveTelegramCustomCommands, + TELEGRAM_COMMAND_NAME_PATTERN, +} from "openclaw/plugin-sdk/config-runtime"; +import type { + ReplyToMode, + TelegramAccountConfig, + TelegramDirectConfig, + TelegramGroupConfig, + TelegramTopicConfig, +} from "openclaw/plugin-sdk/config-runtime"; +import { ensureConfiguredAcpRouteReady } from "openclaw/plugin-sdk/conversation-runtime"; +import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +import { + executePluginCommand, + getPluginCommandSpecs, + matchPluginCommand, +} from "openclaw/plugin-sdk/plugin-runtime"; +import { resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveCommandAuthorization } from "openclaw/plugin-sdk/reply-runtime"; +import type { CommandArgs } from "openclaw/plugin-sdk/reply-runtime"; import { buildCommandTextFromArgs, findCommandByNativeName, @@ -10,40 +35,15 @@ import { listNativeCommandSpecsForConfig, parseCommandArgs, resolveCommandArgMenu, -} from "../../../src/auto-reply/commands-registry.js"; -import { finalizeInboundContext } from "../../../src/auto-reply/reply/inbound-context.js"; -import { dispatchReplyWithBufferedBlockDispatcher } from "../../../src/auto-reply/reply/provider-dispatcher.js"; -import { listSkillCommandsForAgents } from "../../../src/auto-reply/skill-commands.js"; -import { resolveCommandAuthorizedFromAuthorizers } from "../../../src/channels/command-gating.js"; -import { resolveNativeCommandSessionTargets } from "../../../src/channels/native-command-session-targets.js"; -import { createReplyPrefixOptions } from "../../../src/channels/reply-prefix.js"; -import { recordInboundSessionMetaSafe } from "../../../src/channels/session-meta.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { ChannelGroupPolicy } from "../../../src/config/group-policy.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { - normalizeTelegramCommandName, - resolveTelegramCustomCommands, - TELEGRAM_COMMAND_NAME_PATTERN, -} from "../../../src/config/telegram-custom-commands.js"; -import type { - ReplyToMode, - TelegramAccountConfig, - TelegramDirectConfig, - TelegramGroupConfig, - TelegramTopicConfig, -} from "../../../src/config/types.js"; -import { danger, logVerbose } from "../../../src/globals.js"; -import { getChildLogger } from "../../../src/logging.js"; -import { getAgentScopedMediaLocalRoots } from "../../../src/media/local-roots.js"; -import { - executePluginCommand, - getPluginCommandSpecs, - matchPluginCommand, -} from "../../../src/plugins/commands.js"; -import { resolveAgentRoute } from "../../../src/routing/resolve-route.js"; -import { resolveThreadSessionKeys } from "../../../src/routing/session-key.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchReplyWithBufferedBlockDispatcher } from "openclaw/plugin-sdk/reply-runtime"; +import { listSkillCommandsForAgents } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; +import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { isSenderAllowed, normalizeDmAllowFromWithStore } from "./bot-access.js"; import type { TelegramMediaRef } from "./bot-message-context.js"; diff --git a/extensions/telegram/src/bot-updates.ts b/extensions/telegram/src/bot-updates.ts index 3121f1a487e..4b08c747f8f 100644 --- a/extensions/telegram/src/bot-updates.ts +++ b/extensions/telegram/src/bot-updates.ts @@ -1,5 +1,5 @@ import type { Message } from "@grammyjs/types"; -import { createDedupeCache } from "../../../src/infra/dedupe.js"; +import { createDedupeCache } from "openclaw/plugin-sdk/infra-runtime"; import type { TelegramContext } from "./bot/types.js"; const MEDIA_GROUP_TIMEOUT_MS = 500; diff --git a/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts b/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts index 2f151066910..69c0557ee3a 100644 --- a/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts +++ b/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts @@ -1,9 +1,9 @@ +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-runtime"; +import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import type { GetReplyOptions, ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { beforeEach, vi } from "vitest"; -import { resetInboundDedupe } from "../../../src/auto-reply/reply/inbound-dedupe.js"; -import type { MsgContext } from "../../../src/auto-reply/templating.js"; -import type { GetReplyOptions, ReplyPayload } from "../../../src/auto-reply/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { MockFn } from "../../../src/test-utils/vitest-mock-fn.js"; type AnyMock = MockFn<(...args: unknown[]) => unknown>; type AnyAsyncMock = MockFn<(...args: unknown[]) => Promise>; @@ -31,16 +31,16 @@ const { loadConfig } = vi.hoisted((): { loadConfig: AnyMock } => ({ export function getLoadConfigMock(): AnyMock { return loadConfig; } -vi.mock("../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig, }; }); -vi.mock("../../../src/config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, resolveStorePath: vi.fn((storePath) => storePath ?? sessionStorePath), @@ -68,7 +68,7 @@ export function getUpsertChannelPairingRequestMock(): AnyAsyncMock { return upsertChannelPairingRequest; } -vi.mock("../../../src/pairing/pairing-store.js", () => ({ +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore, upsertChannelPairingRequest, })); @@ -78,7 +78,7 @@ const skillCommandsHoisted = vi.hoisted(() => ({ })); export const listSkillCommandsForAgents = skillCommandsHoisted.listSkillCommandsForAgents; -vi.mock("../../../src/auto-reply/skill-commands.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ listSkillCommandsForAgents, })); @@ -87,7 +87,7 @@ const systemEventsHoisted = vi.hoisted(() => ({ })); export const enqueueSystemEventSpy: AnyMock = systemEventsHoisted.enqueueSystemEventSpy; -vi.mock("../../../src/infra/system-events.js", () => ({ +vi.mock("openclaw/plugin-sdk/infra-runtime", () => ({ enqueueSystemEvent: enqueueSystemEventSpy, })); @@ -209,7 +209,7 @@ export const replySpy: MockFn< return undefined; }); -vi.mock("../../../src/auto-reply/reply.js", () => ({ +vi.mock("openclaw/plugin-sdk/reply-runtime", () => ({ getReplyFromConfig: replySpy, __replySpy: replySpy, })); diff --git a/extensions/telegram/src/bot.media.e2e-harness.ts b/extensions/telegram/src/bot.media.e2e-harness.ts index a91362702dd..54ae862ce87 100644 --- a/extensions/telegram/src/bot.media.e2e-harness.ts +++ b/extensions/telegram/src/bot.media.e2e-harness.ts @@ -1,5 +1,5 @@ +import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-runtime"; import { beforeEach, vi, type Mock } from "vitest"; -import { resetInboundDedupe } from "../../../src/auto-reply/reply/inbound-dedupe.js"; export const useSpy: Mock = vi.fn(); export const middlewareUseSpy: Mock = vi.fn(); @@ -92,8 +92,8 @@ vi.mock("undici", async (importOriginal) => { }; }); -vi.mock("../../../src/media/store.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/media-runtime", async (importOriginal) => { + const actual = await importOriginal(); const mockModule = Object.create(null) as Record; Object.defineProperties(mockModule, Object.getOwnPropertyDescriptors(actual)); Object.defineProperty(mockModule, "saveMediaBuffer", { @@ -105,8 +105,8 @@ vi.mock("../../../src/media/store.js", async (importOriginal) => { return mockModule; }); -vi.mock("../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig: () => ({ @@ -115,15 +115,15 @@ vi.mock("../../../src/config/config.js", async (importOriginal) => { }; }); -vi.mock("../../../src/config/sessions.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, updateLastRoute: vi.fn(async () => undefined), }; }); -vi.mock("../../../src/pairing/pairing-store.js", () => ({ +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore: vi.fn(async () => [] as string[]), upsertChannelPairingRequest: vi.fn(async () => ({ code: "PAIRCODE", @@ -131,7 +131,7 @@ vi.mock("../../../src/pairing/pairing-store.js", () => ({ })), })); -vi.mock("../../../src/auto-reply/reply.js", () => { +vi.mock("openclaw/plugin-sdk/reply-runtime", () => { const replySpy = vi.fn(async (_ctx, opts) => { await opts?.onReplyStart?.(); return undefined; diff --git a/extensions/telegram/src/bot.media.test-utils.ts b/extensions/telegram/src/bot.media.test-utils.ts index fde76f34e23..3fee9271e3e 100644 --- a/extensions/telegram/src/bot.media.test-utils.ts +++ b/extensions/telegram/src/bot.media.test-utils.ts @@ -1,5 +1,5 @@ +import * as ssrf from "openclaw/plugin-sdk/infra-runtime"; import { afterEach, beforeAll, beforeEach, expect, vi, type Mock } from "vitest"; -import * as ssrf from "../../../src/infra/net/ssrf.js"; import { onSpy, sendChatActionSpy } from "./bot.media.e2e-harness.js"; type StickerSpy = Mock<(...args: unknown[]) => unknown>; @@ -103,7 +103,7 @@ afterEach(() => { beforeAll(async () => { ({ createTelegramBot: createTelegramBotRef } = await import("./bot.js")); - const replyModule = await import("../../../src/auto-reply/reply.js"); + const replyModule = await import("openclaw/plugin-sdk/reply-runtime"); replySpyRef = (replyModule as unknown as { __replySpy: ReturnType }).__replySpy; }, TELEGRAM_BOT_IMPORT_TIMEOUT_MS); diff --git a/extensions/telegram/src/bot.ts b/extensions/telegram/src/bot.ts index a817e10cbac..6d1d7bc24b2 100644 --- a/extensions/telegram/src/bot.ts +++ b/extensions/telegram/src/bot.ts @@ -2,34 +2,31 @@ import { sequentialize } from "@grammyjs/runner"; import { apiThrottler } from "@grammyjs/transformer-throttler"; import type { ApiClientOptions } from "grammy"; import { Bot } from "grammy"; -import { resolveDefaultAgentId } from "../../../src/agents/agent-scope.js"; -import { resolveTextChunkLimit } from "../../../src/auto-reply/chunk.js"; -import { - DEFAULT_GROUP_HISTORY_LIMIT, - type HistoryEntry, -} from "../../../src/auto-reply/reply/history.js"; +import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime"; import { resolveThreadBindingIdleTimeoutMsForChannel, resolveThreadBindingMaxAgeMsForChannel, resolveThreadBindingSpawnPolicy, -} from "../../../src/channels/thread-bindings-policy.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import { isNativeCommandsExplicitlyDisabled, resolveNativeCommandsEnabled, resolveNativeSkillsEnabled, -} from "../../../src/config/commands.js"; -import type { OpenClawConfig, ReplyToMode } from "../../../src/config/config.js"; -import { loadConfig } from "../../../src/config/config.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import type { OpenClawConfig, ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention, -} from "../../../src/config/group-policy.js"; -import { loadSessionStore, resolveStorePath } from "../../../src/config/sessions.js"; -import { danger, logVerbose, shouldLogVerbose } from "../../../src/globals.js"; -import { formatUncaughtError } from "../../../src/infra/errors.js"; -import { getChildLogger } from "../../../src/logging.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; -import { createNonExitingRuntime, type RuntimeEnv } from "../../../src/runtime.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { loadSessionStore, resolveStorePath } from "openclaw/plugin-sdk/config-runtime"; +import { formatUncaughtError } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import { DEFAULT_GROUP_HISTORY_LIMIT, type HistoryEntry } from "openclaw/plugin-sdk/reply-runtime"; +import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { resolveTelegramAccount } from "./accounts.js"; import { registerTelegramHandlers } from "./bot-handlers.js"; import { createTelegramMessageProcessor } from "./bot-message.js"; diff --git a/extensions/telegram/src/bot/delivery.replies.ts b/extensions/telegram/src/bot/delivery.replies.ts index 2dfc1c8e956..d0a2d0fd610 100644 --- a/extensions/telegram/src/bot/delivery.replies.ts +++ b/extensions/telegram/src/bot/delivery.replies.ts @@ -1,25 +1,22 @@ import { type Bot, GrammyError, InputFile } from "grammy"; -import { chunkMarkdownTextWithMode, type ChunkMode } from "../../../../src/auto-reply/chunk.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import type { ReplyToMode } from "../../../../src/config/config.js"; -import type { MarkdownTableMode } from "../../../../src/config/types.base.js"; -import { danger, logVerbose } from "../../../../src/globals.js"; -import { fireAndForgetHook } from "../../../../src/hooks/fire-and-forget.js"; -import { - createInternalHookEvent, - triggerInternalHook, -} from "../../../../src/hooks/internal-hooks.js"; +import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; +import type { MarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { fireAndForgetHook } from "openclaw/plugin-sdk/hook-runtime"; +import { createInternalHookEvent, triggerInternalHook } from "openclaw/plugin-sdk/hook-runtime"; import { buildCanonicalSentMessageHookContext, toInternalMessageSentContext, toPluginMessageContext, toPluginMessageSentEvent, -} from "../../../../src/hooks/message-hook-mappers.js"; -import { formatErrorMessage } from "../../../../src/infra/errors.js"; -import { buildOutboundMediaLoadOptions } from "../../../../src/media/load-options.js"; -import { isGifMedia, kindFromMime } from "../../../../src/media/mime.js"; -import { getGlobalHookRunner } from "../../../../src/plugins/hook-runner-global.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +} from "openclaw/plugin-sdk/hook-runtime"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { buildOutboundMediaLoadOptions } from "openclaw/plugin-sdk/media-runtime"; +import { isGifMedia, kindFromMime } from "openclaw/plugin-sdk/media-runtime"; +import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime"; +import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { loadWebMedia } from "../../../whatsapp/src/media.js"; import type { TelegramInlineButtons } from "../button-types.js"; import { splitTelegramCaption } from "../caption.js"; diff --git a/extensions/telegram/src/bot/delivery.resolve-media.ts b/extensions/telegram/src/bot/delivery.resolve-media.ts index e42dd11aa1b..36b3bb50be9 100644 --- a/extensions/telegram/src/bot/delivery.resolve-media.ts +++ b/extensions/telegram/src/bot/delivery.resolve-media.ts @@ -1,9 +1,9 @@ import { GrammyError } from "grammy"; -import { logVerbose, warn } from "../../../../src/globals.js"; -import { formatErrorMessage } from "../../../../src/infra/errors.js"; -import { retryAsync } from "../../../../src/infra/retry.js"; -import { fetchRemoteMedia } from "../../../../src/media/fetch.js"; -import { saveMediaBuffer } from "../../../../src/media/store.js"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { retryAsync } from "openclaw/plugin-sdk/infra-runtime"; +import { fetchRemoteMedia } from "openclaw/plugin-sdk/media-runtime"; +import { saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime"; +import { logVerbose, warn } from "openclaw/plugin-sdk/runtime-env"; import { shouldRetryTelegramIpv4Fallback, type TelegramTransport } from "../fetch.js"; import { cacheSticker, getCachedSticker } from "../sticker-cache.js"; import { resolveTelegramMediaPlaceholder } from "./helpers.js"; diff --git a/extensions/telegram/src/bot/delivery.send.ts b/extensions/telegram/src/bot/delivery.send.ts index d8768899c28..9c0c6a77e10 100644 --- a/extensions/telegram/src/bot/delivery.send.ts +++ b/extensions/telegram/src/bot/delivery.send.ts @@ -1,6 +1,6 @@ import { type Bot, GrammyError } from "grammy"; -import { formatErrorMessage } from "../../../../src/infra/errors.js"; -import type { RuntimeEnv } from "../../../../src/runtime.js"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { withTelegramApiErrorLogging } from "../api-logging.js"; import { markdownToTelegramHtml } from "../format.js"; import { buildInlineKeyboard } from "../send.js"; diff --git a/extensions/telegram/src/bot/helpers.ts b/extensions/telegram/src/bot/helpers.ts index 3575da81efb..921cdf74e86 100644 --- a/extensions/telegram/src/bot/helpers.ts +++ b/extensions/telegram/src/bot/helpers.ts @@ -1,13 +1,13 @@ import type { Chat, Message, MessageOrigin, User } from "@grammyjs/types"; -import { formatLocationText, type NormalizedLocation } from "../../../../src/channels/location.js"; -import { resolveTelegramPreviewStreamMode } from "../../../../src/config/discord-preview-streaming.js"; +import { formatLocationText, type NormalizedLocation } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveTelegramPreviewStreamMode } from "openclaw/plugin-sdk/config-runtime"; import type { TelegramDirectConfig, TelegramGroupConfig, TelegramTopicConfig, -} from "../../../../src/config/types.js"; -import { readChannelAllowFromStore } from "../../../../src/pairing/pairing-store.js"; -import { normalizeAccountId } from "../../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { readChannelAllowFromStore } from "openclaw/plugin-sdk/conversation-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { firstDefined, normalizeAllowFrom, type NormalizedAllowFrom } from "../bot-access.js"; import type { TelegramStreamMode } from "./types.js"; diff --git a/extensions/telegram/src/bot/reply-threading.ts b/extensions/telegram/src/bot/reply-threading.ts index cdeeba7151b..11f4f099688 100644 --- a/extensions/telegram/src/bot/reply-threading.ts +++ b/extensions/telegram/src/bot/reply-threading.ts @@ -1,4 +1,4 @@ -import type { ReplyToMode } from "../../../../src/config/config.js"; +import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime"; export type DeliveryProgress = { hasReplied: boolean; diff --git a/extensions/telegram/src/button-types.ts b/extensions/telegram/src/button-types.ts index a6eae71995b..15c307ca8c0 100644 --- a/extensions/telegram/src/button-types.ts +++ b/extensions/telegram/src/button-types.ts @@ -1,9 +1,9 @@ -import { reduceInteractiveReply } from "../../../src/channels/plugins/outbound/interactive.js"; +import { reduceInteractiveReply } from "openclaw/plugin-sdk/channel-runtime"; import { normalizeInteractiveReply, type InteractiveReply, type InteractiveReplyButton, -} from "../../../src/interactive/payload.js"; +} from "openclaw/plugin-sdk/channel-runtime"; export type TelegramButtonStyle = "danger" | "success" | "primary"; diff --git a/extensions/telegram/src/channel-actions.ts b/extensions/telegram/src/channel-actions.ts index c9ae46ca823..50c472ea600 100644 --- a/extensions/telegram/src/channel-actions.ts +++ b/extensions/telegram/src/channel-actions.ts @@ -3,20 +3,21 @@ import { readStringArrayParam, readStringOrNumberParam, readStringParam, -} from "../../../src/agents/tools/common.js"; -import { handleTelegramAction } from "../../../src/agents/tools/telegram-actions.js"; -import { resolveReactionMessageId } from "../../../src/channels/plugins/actions/reaction-message-id.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { handleTelegramAction } from "openclaw/plugin-sdk/agent-runtime"; +import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param"; +import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-runtime"; import { createUnionActionGate, listTokenSourcedAccounts, -} from "../../../src/channels/plugins/actions/shared.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelMessageActionAdapter, ChannelMessageActionName, -} from "../../../src/channels/plugins/types.js"; -import type { TelegramActionConfig } from "../../../src/config/types.telegram.js"; -import { extractToolSend, readBooleanParam } from "../../../src/plugin-sdk-internal/telegram.js"; -import { resolveTelegramPollVisibility } from "../../../src/poll-params.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { TelegramActionConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveTelegramPollVisibility } from "openclaw/plugin-sdk/telegram"; +import { extractToolSend } from "openclaw/plugin-sdk/tool-send"; import { createTelegramActionGate, listEnabledTelegramAccounts, diff --git a/extensions/telegram/src/channel.setup.ts b/extensions/telegram/src/channel.setup.ts index 0ed71ae568c..1da52dbe885 100644 --- a/extensions/telegram/src/channel.setup.ts +++ b/extensions/telegram/src/channel.setup.ts @@ -1,12 +1,69 @@ -import { type ChannelPlugin } from "openclaw/plugin-sdk/telegram"; +import { + buildChannelConfigSchema, + getChatChannelMeta, + TelegramConfigSchema, + type ChannelPlugin, +} from "openclaw/plugin-sdk/telegram"; import { type ResolvedTelegramAccount } from "./accounts.js"; +import { + 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"; -import { createTelegramPluginBase } from "./shared.js"; -export const telegramSetupPlugin: ChannelPlugin = - createTelegramPluginBase({ - setupWizard: telegramSetupWizard, - setup: telegramSetupAdapter, - }); +export const telegramSetupPlugin: ChannelPlugin = { + id: "telegram", + meta: { + ...getChatChannelMeta("telegram"), + quickstartAllowFrom: true, + }, + setupWizard: telegramSetupWizard, + capabilities: { + chatTypes: ["direct", "group", "channel", "thread"], + reactions: true, + threads: true, + media: true, + polls: true, + nativeCommands: true, + blockStreaming: true, + }, + reload: { configPrefixes: ["channels.telegram"] }, + configSchema: buildChannelConfigSchema(TelegramConfigSchema), + config: { + ...telegramConfigBase, + isConfigured: (account, cfg) => { + if (!account.token?.trim()) { + return false; + } + return !findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId }); + }, + unconfiguredReason: (account, cfg) => { + if (!account.token?.trim()) { + return "not configured"; + } + const ownerAccountId = findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId }); + if (!ownerAccountId) { + return "not configured"; + } + return formatDuplicateTelegramTokenReason({ + accountId: account.accountId, + ownerAccountId, + }); + }, + describeAccount: (account, cfg) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: + Boolean(account.token?.trim()) && + !findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId }), + tokenSource: account.tokenSource, + }), + ...telegramConfigAccessors, + }, + setup: telegramSetupAdapter, +}; diff --git a/extensions/telegram/src/channel.ts b/extensions/telegram/src/channel.ts index 797b60c85d8..e157ea34ba7 100644 --- a/extensions/telegram/src/channel.ts +++ b/extensions/telegram/src/channel.ts @@ -1,18 +1,25 @@ +import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/allowlist-config-edit"; import { - buildAccountScopedAllowlistConfigEditor, collectAllowlistProviderGroupPolicyWarnings, collectOpenGroupPolicyRouteAllowlistWarnings, createScopedDmSecurityResolver, -} from "openclaw/plugin-sdk/compat"; +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { type OutboundSendDeps, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; +import { normalizeMessageChannel } from "openclaw/plugin-sdk/channel-runtime"; import { buildAgentSessionKey, resolveThreadSessionKeys, type RoutePeer, } from "openclaw/plugin-sdk/core"; +import { resolveExecApprovalCommandDisplay } from "openclaw/plugin-sdk/infra-runtime"; +import { buildExecApprovalPendingReplyPayload } from "openclaw/plugin-sdk/infra-runtime"; +import { parseTelegramTopicConversation } from "openclaw/plugin-sdk/telegram"; import { + buildChannelConfigSchema, buildTokenChannelStatusSummary, clearAccountEntryFields, DEFAULT_ACCOUNT_ID, + getChatChannelMeta, listTelegramDirectoryGroupsFromConfig, listTelegramDirectoryPeersFromConfig, PAIRING_APPROVED_MESSAGE, @@ -20,23 +27,13 @@ import { resolveConfiguredFromCredentialStatuses, resolveTelegramGroupRequireMention, resolveTelegramGroupToolPolicy, - type ChannelMessageActionAdapter, + TelegramConfigSchema, type ChannelPlugin, + 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"; -import { normalizeOutboundThreadId } from "../../../src/infra/outbound/thread-id.js"; -import { normalizeMessageChannel } from "../../../src/utils/message-channel.js"; -import { inspectTelegramAccount } from "./account-inspect.js"; import { listTelegramAccountIds, - resolveDefaultTelegramAccountId, resolveTelegramAccount, type ResolvedTelegramAccount, } from "./accounts.js"; @@ -51,17 +48,17 @@ 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"; import { telegramSetupAdapter } from "./setup-core.js"; import { telegramSetupWizard } from "./setup-surface.js"; -import { - createTelegramPluginBase, - findTelegramTokenOwnerAccountId, - formatDuplicateTelegramTokenReason, - telegramConfigAccessors, -} from "./shared.js"; import { collectTelegramStatusIssues } from "./status-issues.js"; import { parseTelegramTarget } from "./targets.js"; @@ -69,6 +66,8 @@ type TelegramSendFn = ReturnType< typeof getTelegramRuntime >["channel"]["telegram"]["sendMessageTelegram"]; +const meta = getChatChannelMeta("telegram"); + type TelegramSendOptions = NonNullable[2]>; function buildTelegramSendOptions(params: { @@ -186,6 +185,20 @@ function parseTelegramExplicitTarget(raw: string) { }; } +function normalizeOutboundThreadId(value?: string | number | null): string | undefined { + if (value == null) { + return undefined; + } + if (typeof value === "number") { + if (!Number.isFinite(value)) { + return undefined; + } + return String(Math.trunc(value)); + } + const trimmed = value.trim(); + return trimmed ? trimmed : undefined; +} + function buildTelegramBaseSessionKey(params: { cfg: OpenClawConfig; agentId: string; @@ -311,10 +324,12 @@ function readTelegramAllowlistConfig(account: ResolvedTelegramAccount) { } export const telegramPlugin: ChannelPlugin = { - ...createTelegramPluginBase({ - setupWizard: telegramSetupWizard, - setup: telegramSetupAdapter, - }), + id: "telegram", + meta: { + ...meta, + quickstartAllowFrom: true, + }, + setupWizard: telegramSetupWizard, pairing: { idLabel: "telegramUserId", normalizeAllowEntry: (entry) => entry.replace(/^(telegram|tg):/i, ""), @@ -332,6 +347,49 @@ export const telegramPlugin: ChannelPlugin { + if (!account.token?.trim()) { + return false; + } + return !findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId }); + }, + unconfiguredReason: (account, cfg) => { + if (!account.token?.trim()) { + return "not configured"; + } + const ownerAccountId = findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId }); + if (!ownerAccountId) { + return "not configured"; + } + return formatDuplicateTelegramTokenReason({ + accountId: account.accountId, + ownerAccountId, + }); + }, + describeAccount: (account, cfg) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: + Boolean(account.token?.trim()) && + !findTelegramTokenOwnerAccountId({ cfg, accountId: account.accountId }), + tokenSource: account.tokenSource, + }), + ...telegramConfigAccessors, + }, allowlist: { supportsScope: ({ scope }) => scope === "dm" || scope === "group" || scope === "all", readConfig: ({ cfg, accountId }) => @@ -487,6 +545,7 @@ export const telegramPlugin: ChannelPlugin listTelegramDirectoryGroupsFromConfig(params), }, actions: telegramMessageActions, + setup: telegramSetupAdapter, outbound: { deliveryMode: "direct", chunker: (text, limit) => getTelegramRuntime().channel.text.chunkMarkdownText(text, limit), diff --git a/extensions/telegram/src/conversation-route.ts b/extensions/telegram/src/conversation-route.ts index f12c896d0ca..fc06221936f 100644 --- a/extensions/telegram/src/conversation-route.ts +++ b/extensions/telegram/src/conversation-route.ts @@ -1,18 +1,18 @@ -import { resolveConfiguredAcpRoute } from "../../../src/acp/persistent-bindings.route.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { logVerbose } from "../../../src/globals.js"; -import { getSessionBindingService } from "../../../src/infra/outbound/session-binding-service.js"; -import { isPluginOwnedSessionBindingRecord } from "../../../src/plugins/conversation-binding.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveConfiguredAcpRoute } from "openclaw/plugin-sdk/conversation-runtime"; +import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime"; +import { isPluginOwnedSessionBindingRecord } from "openclaw/plugin-sdk/conversation-runtime"; import { buildAgentSessionKey, deriveLastRoutePolicy, resolveAgentRoute, -} from "../../../src/routing/resolve-route.js"; +} from "openclaw/plugin-sdk/routing"; import { buildAgentMainSessionKey, resolveAgentIdFromSessionKey, sanitizeAgentId, -} from "../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { buildTelegramGroupPeerId, buildTelegramParentPeer, diff --git a/extensions/telegram/src/dm-access.ts b/extensions/telegram/src/dm-access.ts index db8cc419c6a..5bcacf95567 100644 --- a/extensions/telegram/src/dm-access.ts +++ b/extensions/telegram/src/dm-access.ts @@ -1,9 +1,9 @@ import type { Message } from "@grammyjs/types"; import type { Bot } from "grammy"; -import type { DmPolicy } from "../../../src/config/types.js"; -import { logVerbose } from "../../../src/globals.js"; -import { issuePairingChallenge } from "../../../src/pairing/pairing-challenge.js"; -import { upsertChannelPairingRequest } from "../../../src/pairing/pairing-store.js"; +import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime"; +import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { resolveSenderAllowMatch, type NormalizedAllowFrom } from "./bot-access.js"; diff --git a/extensions/telegram/src/draft-chunking.ts b/extensions/telegram/src/draft-chunking.ts index 76edc1b1811..42911f4fd0e 100644 --- a/extensions/telegram/src/draft-chunking.ts +++ b/extensions/telegram/src/draft-chunking.ts @@ -1,7 +1,7 @@ -import { resolveTextChunkLimit } from "../../../src/auto-reply/chunk.js"; -import { type OpenClawConfig } from "../../../src/config/config.js"; -import { resolveAccountEntry } from "../../../src/routing/account-lookup.js"; -import { normalizeAccountId } from "../../../src/routing/session-key.js"; +import { type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAccountEntry } from "openclaw/plugin-sdk/routing"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; import { TELEGRAM_TEXT_CHUNK_LIMIT } from "./outbound-adapter.js"; const DEFAULT_TELEGRAM_DRAFT_STREAM_MIN = 200; diff --git a/extensions/telegram/src/draft-stream.ts b/extensions/telegram/src/draft-stream.ts index 5641b042d30..baebe687c50 100644 --- a/extensions/telegram/src/draft-stream.ts +++ b/extensions/telegram/src/draft-stream.ts @@ -1,6 +1,6 @@ import type { Bot } from "grammy"; -import { createFinalizableDraftLifecycle } from "../../../src/channels/draft-stream-controls.js"; -import { resolveGlobalSingleton } from "../../../src/shared/global-singleton.js"; +import { createFinalizableDraftLifecycle } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveGlobalSingleton } from "openclaw/plugin-sdk/text-runtime"; import { buildTelegramThreadParams, type TelegramThreadSpec } from "./bot/helpers.js"; import { isSafeToRetrySendError, isTelegramClientRejection } from "./network-errors.js"; diff --git a/extensions/telegram/src/exec-approvals-handler.ts b/extensions/telegram/src/exec-approvals-handler.ts index a9d32d0887d..97cc2228b98 100644 --- a/extensions/telegram/src/exec-approvals-handler.ts +++ b/extensions/telegram/src/exec-approvals-handler.ts @@ -1,21 +1,18 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { GatewayClient } from "../../../src/gateway/client.js"; -import { createOperatorApprovalsGatewayClient } from "../../../src/gateway/operator-approvals-client.js"; -import type { EventFrame } from "../../../src/gateway/protocol/index.js"; -import { resolveExecApprovalCommandDisplay } from "../../../src/infra/exec-approval-command-display.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { GatewayClient } from "openclaw/plugin-sdk/gateway-runtime"; +import { createOperatorApprovalsGatewayClient } from "openclaw/plugin-sdk/gateway-runtime"; +import type { EventFrame } from "openclaw/plugin-sdk/gateway-runtime"; +import { resolveExecApprovalCommandDisplay } from "openclaw/plugin-sdk/infra-runtime"; import { buildExecApprovalPendingReplyPayload, type ExecApprovalPendingReplyParams, -} from "../../../src/infra/exec-approval-reply.js"; -import { resolveExecApprovalSessionTarget } from "../../../src/infra/exec-approval-session-target.js"; -import type { - ExecApprovalRequest, - ExecApprovalResolved, -} from "../../../src/infra/exec-approvals.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; -import { normalizeAccountId, parseAgentSessionKey } from "../../../src/routing/session-key.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; -import { compileSafeRegex, testRegexWithBoundedInput } from "../../../src/security/safe-regex.js"; +} from "openclaw/plugin-sdk/infra-runtime"; +import { resolveExecApprovalSessionTarget } from "openclaw/plugin-sdk/infra-runtime"; +import type { ExecApprovalRequest, ExecApprovalResolved } from "openclaw/plugin-sdk/infra-runtime"; +import { normalizeAccountId, parseAgentSessionKey } from "openclaw/plugin-sdk/routing"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { compileSafeRegex, testRegexWithBoundedInput } from "openclaw/plugin-sdk/security-runtime"; import { buildTelegramExecApprovalButtons } from "./approval-buttons.js"; import { getTelegramExecApprovalApprovers, diff --git a/extensions/telegram/src/exec-approvals.ts b/extensions/telegram/src/exec-approvals.ts index b1b0eed8d4f..10ae8dd35a0 100644 --- a/extensions/telegram/src/exec-approvals.ts +++ b/extensions/telegram/src/exec-approvals.ts @@ -1,7 +1,7 @@ -import type { ReplyPayload } from "../../../src/auto-reply/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { TelegramExecApprovalConfig } from "../../../src/config/types.telegram.js"; -import { getExecApprovalReplyMetadata } from "../../../src/infra/exec-approval-reply.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { TelegramExecApprovalConfig } from "openclaw/plugin-sdk/config-runtime"; +import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/infra-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { resolveTelegramAccount } from "./accounts.js"; import { resolveTelegramTargetChatType } from "./targets.js"; diff --git a/extensions/telegram/src/fetch.ts b/extensions/telegram/src/fetch.ts index 4b234c8d107..962d0256af1 100644 --- a/extensions/telegram/src/fetch.ts +++ b/extensions/telegram/src/fetch.ts @@ -1,10 +1,10 @@ import * as dns from "node:dns"; +import type { TelegramNetworkConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveFetch } from "openclaw/plugin-sdk/infra-runtime"; +import { hasEnvHttpProxyConfigured } from "openclaw/plugin-sdk/infra-runtime"; +import type { PinnedDispatcherPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; import { Agent, EnvHttpProxyAgent, ProxyAgent, fetch as undiciFetch } from "undici"; -import type { TelegramNetworkConfig } from "../../../src/config/types.telegram.js"; -import { resolveFetch } from "../../../src/infra/fetch.js"; -import { hasEnvHttpProxyConfigured } from "../../../src/infra/net/proxy-env.js"; -import type { PinnedDispatcherPolicy } from "../../../src/infra/net/ssrf.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; import { resolveTelegramAutoSelectFamilyDecision, resolveTelegramDnsResultOrderDecision, diff --git a/extensions/telegram/src/format.ts b/extensions/telegram/src/format.ts index 0c1bec2a62a..a9a10965243 100644 --- a/extensions/telegram/src/format.ts +++ b/extensions/telegram/src/format.ts @@ -1,11 +1,11 @@ -import type { MarkdownTableMode } from "../../../src/config/types.base.js"; +import type { MarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; import { chunkMarkdownIR, markdownToIR, type MarkdownLinkSpan, type MarkdownIR, -} from "../../../src/markdown/ir.js"; -import { renderMarkdownWithMarkers } from "../../../src/markdown/render.js"; +} from "openclaw/plugin-sdk/text-runtime"; +import { renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-runtime"; export type TelegramFormattedChunk = { html: string; diff --git a/extensions/telegram/src/group-access.ts b/extensions/telegram/src/group-access.ts index e42646a7dcd..d4802a9f0cf 100644 --- a/extensions/telegram/src/group-access.ts +++ b/extensions/telegram/src/group-access.ts @@ -1,13 +1,13 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { ChannelGroupPolicy } from "../../../src/config/group-policy.js"; -import { resolveOpenProviderRuntimeGroupPolicy } from "../../../src/config/runtime-group-policy.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { ChannelGroupPolicy } from "openclaw/plugin-sdk/config-runtime"; +import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/config-runtime"; import type { TelegramAccountConfig, TelegramDirectConfig, TelegramGroupConfig, TelegramTopicConfig, -} from "../../../src/config/types.js"; -import { evaluateMatchedGroupAccessForPolicy } from "../../../src/plugin-sdk-internal/telegram.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { evaluateMatchedGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access"; import { isSenderAllowed, type NormalizedAllowFrom } from "./bot-access.js"; import { firstDefined } from "./bot-access.js"; diff --git a/extensions/telegram/src/group-config-helpers.ts b/extensions/telegram/src/group-config-helpers.ts index 5a60d116dd3..8c0f4652282 100644 --- a/extensions/telegram/src/group-config-helpers.ts +++ b/extensions/telegram/src/group-config-helpers.ts @@ -2,7 +2,7 @@ import type { TelegramDirectConfig, TelegramGroupConfig, TelegramTopicConfig, -} from "../../../src/config/types.js"; +} from "openclaw/plugin-sdk/config-runtime"; import { firstDefined } from "./bot-access.js"; export function resolveTelegramGroupPromptSettings(params: { diff --git a/extensions/telegram/src/group-migration.ts b/extensions/telegram/src/group-migration.ts index 0609fcf4b5a..95b4529e51f 100644 --- a/extensions/telegram/src/group-migration.ts +++ b/extensions/telegram/src/group-migration.ts @@ -1,6 +1,6 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { TelegramGroupConfig } from "../../../src/config/types.telegram.js"; -import { normalizeAccountId } from "../../../src/routing/session-key.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { TelegramGroupConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; type TelegramGroups = Record; diff --git a/extensions/telegram/src/inline-buttons.ts b/extensions/telegram/src/inline-buttons.ts index ead8068feba..5341f2d09f1 100644 --- a/extensions/telegram/src/inline-buttons.ts +++ b/extensions/telegram/src/inline-buttons.ts @@ -1,5 +1,5 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { TelegramInlineButtonsScope } from "../../../src/config/types.telegram.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { TelegramInlineButtonsScope } from "openclaw/plugin-sdk/config-runtime"; import { listTelegramAccountIds, resolveTelegramAccount } from "./accounts.js"; const DEFAULT_INLINE_BUTTONS_SCOPE: TelegramInlineButtonsScope = "allowlist"; diff --git a/extensions/telegram/src/lane-delivery-text-deliverer.ts b/extensions/telegram/src/lane-delivery-text-deliverer.ts index 08875329649..c99dc52661a 100644 --- a/extensions/telegram/src/lane-delivery-text-deliverer.ts +++ b/extensions/telegram/src/lane-delivery-text-deliverer.ts @@ -1,4 +1,4 @@ -import type { ReplyPayload } from "../../../src/auto-reply/types.js"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import type { TelegramInlineButtons } from "./button-types.js"; import type { TelegramDraftStream } from "./draft-stream.js"; import { diff --git a/extensions/telegram/src/monitor.ts b/extensions/telegram/src/monitor.ts index 8620fb01c2b..11530ad66ef 100644 --- a/extensions/telegram/src/monitor.ts +++ b/extensions/telegram/src/monitor.ts @@ -1,11 +1,11 @@ import type { RunOptions } from "@grammyjs/runner"; -import { resolveAgentMaxConcurrent } from "../../../src/config/agent-limits.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { loadConfig } from "../../../src/config/config.js"; -import { waitForAbortSignal } from "../../../src/infra/abort-signal.js"; -import { formatErrorMessage } from "../../../src/infra/errors.js"; -import { registerUnhandledRejectionHandler } from "../../../src/infra/unhandled-rejections.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +import { resolveAgentMaxConcurrent } from "openclaw/plugin-sdk/config-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { waitForAbortSignal } from "openclaw/plugin-sdk/runtime-env"; +import { registerUnhandledRejectionHandler } from "openclaw/plugin-sdk/runtime-env"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { resolveTelegramAccount } from "./accounts.js"; import { resolveTelegramAllowedUpdates } from "./allowed-updates.js"; import { TelegramExecApprovalHandler } from "./exec-approvals-handler.js"; diff --git a/extensions/telegram/src/network-config.ts b/extensions/telegram/src/network-config.ts index 81156ce67ac..a37a8656203 100644 --- a/extensions/telegram/src/network-config.ts +++ b/extensions/telegram/src/network-config.ts @@ -1,7 +1,7 @@ import process from "node:process"; -import type { TelegramNetworkConfig } from "../../../src/config/types.telegram.js"; -import { isTruthyEnvValue } from "../../../src/infra/env.js"; -import { isWSL2Sync } from "../../../src/infra/wsl.js"; +import type { TelegramNetworkConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isTruthyEnvValue } from "openclaw/plugin-sdk/infra-runtime"; +import { isWSL2Sync } from "openclaw/plugin-sdk/infra-runtime"; export const TELEGRAM_DISABLE_AUTO_SELECT_FAMILY_ENV = "OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY"; diff --git a/extensions/telegram/src/network-errors.ts b/extensions/telegram/src/network-errors.ts index 59753f9d8c1..1e7c8523767 100644 --- a/extensions/telegram/src/network-errors.ts +++ b/extensions/telegram/src/network-errors.ts @@ -3,7 +3,7 @@ import { extractErrorCode, formatErrorMessage, readErrorName, -} from "../../../src/infra/errors.js"; +} from "openclaw/plugin-sdk/infra-runtime"; const TELEGRAM_NETWORK_ORIGIN = Symbol("openclaw.telegram.network-origin"); diff --git a/extensions/telegram/src/outbound-adapter.ts b/extensions/telegram/src/outbound-adapter.ts index 25bd2329ed7..1b12c5203a1 100644 --- a/extensions/telegram/src/outbound-adapter.ts +++ b/extensions/telegram/src/outbound-adapter.ts @@ -1,14 +1,11 @@ -import type { ReplyPayload } from "../../../src/auto-reply/types.js"; import { resolvePayloadMediaUrls, sendPayloadMediaSequence, -} from "../../../src/channels/plugins/outbound/direct-text-media.js"; -import type { ChannelOutboundAdapter } from "../../../src/channels/plugins/types.js"; -import { - resolveOutboundSendDep, - type OutboundSendDeps, -} from "../../../src/infra/outbound/send-deps.js"; -import { resolveInteractiveTextFallback } from "../../../src/interactive/payload.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveOutboundSendDep, type OutboundSendDeps } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveInteractiveTextFallback } from "openclaw/plugin-sdk/channel-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import type { TelegramInlineButtons } from "./button-types.js"; import { resolveTelegramInlineButtons } from "./button-types.js"; import { markdownToTelegramHtmlChunks } from "./format.js"; diff --git a/extensions/telegram/src/plugin-shared.ts b/extensions/telegram/src/plugin-shared.ts index 4d33a6ed6f8..12562f0da61 100644 --- a/extensions/telegram/src/plugin-shared.ts +++ b/extensions/telegram/src/plugin-shared.ts @@ -1,12 +1,9 @@ +import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from"; import { createScopedAccountConfigAccessors, createScopedChannelConfigBase, - formatAllowFromLowercase, -} from "../../../src/plugin-sdk-internal/channel-config.js"; -import { - normalizeAccountId, - type OpenClawConfig, -} from "../../../src/plugin-sdk-internal/telegram.js"; +} from "openclaw/plugin-sdk/channel-config-helpers"; +import { normalizeAccountId, type OpenClawConfig } from "openclaw/plugin-sdk/telegram"; import { inspectTelegramAccount } from "./account-inspect.js"; import { listTelegramAccountIds, diff --git a/extensions/telegram/src/polling-session.ts b/extensions/telegram/src/polling-session.ts index 5506ce4e434..89342994387 100644 --- a/extensions/telegram/src/polling-session.ts +++ b/extensions/telegram/src/polling-session.ts @@ -1,7 +1,7 @@ import { type RunOptions, run } from "@grammyjs/runner"; -import { computeBackoff, sleepWithAbort } from "../../../src/infra/backoff.js"; -import { formatErrorMessage } from "../../../src/infra/errors.js"; -import { formatDurationPrecise } from "../../../src/infra/format-time/format-duration.ts"; +import { computeBackoff, sleepWithAbort } from "openclaw/plugin-sdk/infra-runtime"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { formatDurationPrecise } from "openclaw/plugin-sdk/infra-runtime"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { createTelegramBot } from "./bot.js"; import { isRecoverableTelegramNetworkError } from "./network-errors.js"; diff --git a/extensions/telegram/src/probe.ts b/extensions/telegram/src/probe.ts index cade90c5ad5..660b9c9fb62 100644 --- a/extensions/telegram/src/probe.ts +++ b/extensions/telegram/src/probe.ts @@ -1,6 +1,6 @@ -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 type { BaseProbeResult } from "openclaw/plugin-sdk/channel-runtime"; +import type { TelegramNetworkConfig } from "openclaw/plugin-sdk/telegram"; +import { fetchWithTimeout } from "openclaw/plugin-sdk/text-runtime"; import { resolveTelegramFetch } from "./fetch.js"; import { makeProxyFetch } from "./proxy.js"; diff --git a/extensions/telegram/src/proxy.ts b/extensions/telegram/src/proxy.ts index d74710c9cbd..1a06877b90f 100644 --- a/extensions/telegram/src/proxy.ts +++ b/extensions/telegram/src/proxy.ts @@ -1 +1 @@ -export { getProxyUrlFromFetch, makeProxyFetch } from "../../../src/infra/net/proxy-fetch.js"; +export { getProxyUrlFromFetch, makeProxyFetch } from "openclaw/plugin-sdk/infra-runtime"; diff --git a/extensions/telegram/src/reaction-level.ts b/extensions/telegram/src/reaction-level.ts index 4597ce0602e..3f33277d19a 100644 --- a/extensions/telegram/src/reaction-level.ts +++ b/extensions/telegram/src/reaction-level.ts @@ -1,9 +1,9 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveReactionLevel, type ReactionLevel, type ResolvedReactionLevel as BaseResolvedReactionLevel, -} from "../../../src/utils/reaction-level.js"; +} from "openclaw/plugin-sdk/text-runtime"; import { resolveTelegramAccount } from "./accounts.js"; export type TelegramReactionLevel = ReactionLevel; diff --git a/extensions/telegram/src/reasoning-lane-coordinator.ts b/extensions/telegram/src/reasoning-lane-coordinator.ts index 4bc0da94dfe..a4e414a6727 100644 --- a/extensions/telegram/src/reasoning-lane-coordinator.ts +++ b/extensions/telegram/src/reasoning-lane-coordinator.ts @@ -1,7 +1,7 @@ -import { formatReasoningMessage } from "../../../src/agents/pi-embedded-utils.js"; -import type { ReplyPayload } from "../../../src/auto-reply/types.js"; -import { findCodeRegions, isInsideCode } from "../../../src/shared/text/code-regions.js"; -import { stripReasoningTagsFromText } from "../../../src/shared/text/reasoning-tags.js"; +import { formatReasoningMessage } from "openclaw/plugin-sdk/agent-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { findCodeRegions, isInsideCode } from "openclaw/plugin-sdk/text-runtime"; +import { stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-runtime"; const REASONING_MESSAGE_PREFIX = "Reasoning:\n"; const REASONING_TAG_PREFIXES = [ diff --git a/extensions/telegram/src/runtime.ts b/extensions/telegram/src/runtime.ts index 768c15e28f5..1cc0c75b5dc 100644 --- a/extensions/telegram/src/runtime.ts +++ b/extensions/telegram/src/runtime.ts @@ -1,7 +1,5 @@ -import { - createPluginRuntimeStore, - type PluginRuntime, -} from "../../../src/plugin-sdk-internal/core.js"; +import type { PluginRuntime } from "openclaw/plugin-sdk/core"; +import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; const { setRuntime: setTelegramRuntime, getRuntime: getTelegramRuntime } = createPluginRuntimeStore("Telegram runtime not initialized"); diff --git a/extensions/telegram/src/send.test-harness.ts b/extensions/telegram/src/send.test-harness.ts index 604a7d27dd1..c12a571c642 100644 --- a/extensions/telegram/src/send.test-harness.ts +++ b/extensions/telegram/src/send.test-harness.ts @@ -1,5 +1,5 @@ +import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { beforeEach, vi } from "vitest"; -import type { MockFn } from "../../../src/test-utils/vitest-mock-fn.js"; const { botApi, botCtorSpy } = vi.hoisted(() => ({ botApi: { @@ -64,8 +64,8 @@ vi.mock("grammy", () => ({ InputFile: class {}, })); -vi.mock("../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig, diff --git a/extensions/telegram/src/send.ts b/extensions/telegram/src/send.ts index b215be835e8..0682fda6786 100644 --- a/extensions/telegram/src/send.ts +++ b/extensions/telegram/src/send.ts @@ -5,20 +5,20 @@ import type { ReactionTypeEmoji, } from "@grammyjs/types"; import { type ApiClientOptions, Bot, HttpError, InputFile } from "grammy"; -import { loadConfig } from "../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { logVerbose } from "../../../src/globals.js"; -import { recordChannelActivity } from "../../../src/infra/channel-activity.js"; -import { isDiagnosticFlagEnabled } from "../../../src/infra/diagnostic-flags.js"; -import { formatErrorMessage, formatUncaughtError } from "../../../src/infra/errors.js"; -import { createTelegramRetryRunner } from "../../../src/infra/retry-policy.js"; -import type { RetryConfig } from "../../../src/infra/retry.js"; -import { redactSensitiveText } from "../../../src/logging/redact.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; -import type { MediaKind } from "../../../src/media/constants.js"; -import { buildOutboundMediaLoadOptions } from "../../../src/media/load-options.js"; -import { isGifMedia, kindFromMime } from "../../../src/media/mime.js"; -import { normalizePollInput, type PollInput } from "../../../src/polls.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime"; +import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/infra-runtime"; +import { formatErrorMessage, formatUncaughtError } from "openclaw/plugin-sdk/infra-runtime"; +import { createTelegramRetryRunner } from "openclaw/plugin-sdk/infra-runtime"; +import type { RetryConfig } from "openclaw/plugin-sdk/infra-runtime"; +import type { MediaKind } from "openclaw/plugin-sdk/media-runtime"; +import { buildOutboundMediaLoadOptions } from "openclaw/plugin-sdk/media-runtime"; +import { isGifMedia, kindFromMime } from "openclaw/plugin-sdk/media-runtime"; +import { normalizePollInput, type PollInput } from "openclaw/plugin-sdk/media-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { redactSensitiveText } from "openclaw/plugin-sdk/text-runtime"; import { loadWebMedia } from "../../whatsapp/src/media.js"; import { type ResolvedTelegramAccount, resolveTelegramAccount } from "./accounts.js"; import { withTelegramApiErrorLogging } from "./api-logging.js"; diff --git a/extensions/telegram/src/sendchataction-401-backoff.ts b/extensions/telegram/src/sendchataction-401-backoff.ts index 72ac8690403..0c9865eb2b3 100644 --- a/extensions/telegram/src/sendchataction-401-backoff.ts +++ b/extensions/telegram/src/sendchataction-401-backoff.ts @@ -1,4 +1,8 @@ -import { computeBackoff, sleepWithAbort, type BackoffPolicy } from "../../../src/infra/backoff.js"; +import { + computeBackoff, + sleepWithAbort, + type BackoffPolicy, +} from "openclaw/plugin-sdk/infra-runtime"; export type TelegramSendChatActionLogger = (message: string) => void; diff --git a/extensions/telegram/src/sent-message-cache.ts b/extensions/telegram/src/sent-message-cache.ts index 49a6ab4c3d9..bb48bce3c0f 100644 --- a/extensions/telegram/src/sent-message-cache.ts +++ b/extensions/telegram/src/sent-message-cache.ts @@ -1,4 +1,4 @@ -import { resolveGlobalMap } from "../../../src/shared/global-singleton.js"; +import { resolveGlobalMap } from "openclaw/plugin-sdk/text-runtime"; /** * In-memory cache of sent message IDs per chat. diff --git a/extensions/telegram/src/sequential-key.ts b/extensions/telegram/src/sequential-key.ts index 334c18dc485..5309a88a32c 100644 --- a/extensions/telegram/src/sequential-key.ts +++ b/extensions/telegram/src/sequential-key.ts @@ -1,6 +1,6 @@ import { type Message, type UserFromGetMe } from "@grammyjs/types"; -import { isAbortRequestText } from "../../../src/auto-reply/reply/abort.js"; -import { isBtwRequestText } from "../../../src/auto-reply/reply/btw-command.js"; +import { isAbortRequestText } from "openclaw/plugin-sdk/reply-runtime"; +import { isBtwRequestText } from "openclaw/plugin-sdk/reply-runtime"; import { resolveTelegramForumThreadId } from "./bot/helpers.js"; export type TelegramSequentialKeyContext = { diff --git a/extensions/telegram/src/setup-core.ts b/extensions/telegram/src/setup-core.ts index 33ce824d17d..13fb01f3a51 100644 --- a/extensions/telegram/src/setup-core.ts +++ b/extensions/telegram/src/setup-core.ts @@ -1,27 +1,18 @@ -import { createPatchedAccountSetupAdapter } from "../../../src/channels/plugins/setup-helpers.js"; import { + applyAccountNameToChannelSection, DEFAULT_ACCOUNT_ID, formatCliCommand, + formatDocsLink, + migrateBaseNameToDefaultAccount, + normalizeAccountId, patchChannelConfigForAccount, promptResolvedAllowFrom, - setSetupChannelEnabled, - setChannelDmPolicyWithAllowFrom, splitSetupEntries, type OpenClawConfig, type WizardPrompter, -} from "../../../src/plugin-sdk-internal/setup.js"; -import type { - ChannelSetupAdapter, - ChannelSetupDmPolicy, - ChannelSetupWizard, -} from "../../../src/plugin-sdk-internal/setup.js"; -import { formatDocsLink } from "../../../src/terminal/links.js"; -import { inspectTelegramAccount } from "./account-inspect.js"; -import { - listTelegramAccountIds, - resolveDefaultTelegramAccountId, - resolveTelegramAccount, -} from "./accounts.js"; +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupAdapter, ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup"; +import { resolveDefaultTelegramAccountId, resolveTelegramAccount } from "./accounts.js"; import { fetchTelegramChatId } from "./api-fetch.js"; const channel = "telegram" as const; @@ -118,93 +109,15 @@ export async function promptTelegramAllowFromForAccount(params: { }); } -type TelegramSetupWizardHandlers = { - inspectToken: (params: { cfg: OpenClawConfig; accountId: string }) => { - accountConfigured: boolean; - hasConfiguredValue: boolean; - resolvedValue?: string; - envValue?: string; - }; -}; - -export function createTelegramSetupWizardBase( - handlers: TelegramSetupWizardHandlers, -): ChannelSetupWizard { - const dmPolicy: ChannelSetupDmPolicy = { - label: "Telegram", - channel, - policyKey: "channels.telegram.dmPolicy", - allowFromKey: "channels.telegram.allowFrom", - getCurrent: (cfg) => cfg.channels?.telegram?.dmPolicy ?? "pairing", - setPolicy: (cfg, policy) => - setChannelDmPolicyWithAllowFrom({ - cfg, - channel, - dmPolicy: policy, - }), - promptAllowFrom: promptTelegramAllowFromForAccount, - }; - - return { - channel, - status: { - configuredLabel: "configured", - unconfiguredLabel: "needs token", - configuredHint: "recommended · configured", - unconfiguredHint: "recommended · newcomer-friendly", - configuredScore: 1, - unconfiguredScore: 10, - resolveConfigured: ({ cfg }) => - listTelegramAccountIds(cfg).some((accountId) => { - const account = inspectTelegramAccount({ cfg, accountId }); - return account.configured; - }), - }, - credentials: [ - { - inputKey: "token", - providerHint: channel, - credentialLabel: "Telegram bot token", - preferredEnvVar: "TELEGRAM_BOT_TOKEN", - helpTitle: "Telegram bot token", - helpLines: TELEGRAM_TOKEN_HELP_LINES, - envPrompt: "TELEGRAM_BOT_TOKEN detected. Use env var?", - keepPrompt: "Telegram token already configured. Keep it?", - inputPrompt: "Enter Telegram bot token", - allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID, - inspect: ({ cfg, accountId }) => handlers.inspectToken({ cfg, accountId }), - }, - ], - allowFrom: { - helpTitle: "Telegram user id", - helpLines: TELEGRAM_USER_ID_HELP_LINES, - credentialInputKey: "token", - message: "Telegram allowFrom (numeric sender id; @username resolves to id)", - placeholder: "@username", - invalidWithoutCredentialNote: - "Telegram token missing; use numeric sender ids (usernames require a bot token).", - parseInputs: splitSetupEntries, - parseId: parseTelegramAllowFromId, - resolveEntries: async ({ credentialValues, entries }) => - resolveTelegramAllowFromEntries({ - credentialValue: credentialValues.token, - entries, - }), - apply: async ({ cfg, accountId, allowFrom }) => - patchChannelConfigForAccount({ - cfg, - channel, - accountId, - patch: { dmPolicy: "allowlist", allowFrom }, - }), - }, - dmPolicy, - disable: (cfg) => setSetupChannelEnabled(cfg, channel, false), - } satisfies ChannelSetupWizard; -} - -export const telegramSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupAdapter({ - channelKey: channel, +export const telegramSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + }), validateInput: ({ accountId, input }) => { if (input.useEnv && accountId !== DEFAULT_ACCOUNT_ID) { return "TELEGRAM_BOT_TOKEN can only be used for the default account."; @@ -214,12 +127,60 @@ export const telegramSetupAdapter: ChannelSetupAdapter = createPatchedAccountSet } return null; }, - buildPatch: (input) => - input.useEnv - ? {} - : input.tokenFile - ? { tokenFile: input.tokenFile } - : input.token - ? { botToken: input.token } - : {}, -}); + applyAccountConfig: ({ cfg, accountId, input }) => { + const namedConfig = applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name: input.name, + }); + const next = + accountId !== DEFAULT_ACCOUNT_ID + ? migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + }) + : namedConfig; + if (accountId === DEFAULT_ACCOUNT_ID) { + return { + ...next, + channels: { + ...next.channels, + telegram: { + ...next.channels?.telegram, + enabled: true, + ...(input.useEnv + ? {} + : input.tokenFile + ? { tokenFile: input.tokenFile } + : input.token + ? { botToken: input.token } + : {}), + }, + }, + }; + } + return { + ...next, + channels: { + ...next.channels, + telegram: { + ...next.channels?.telegram, + enabled: true, + accounts: { + ...next.channels?.telegram?.accounts, + [accountId]: { + ...next.channels?.telegram?.accounts?.[accountId], + enabled: true, + ...(input.tokenFile + ? { tokenFile: input.tokenFile } + : input.token + ? { botToken: input.token } + : {}), + }, + }, + }, + }, + }; + }, +}; diff --git a/extensions/telegram/src/setup-surface.ts b/extensions/telegram/src/setup-surface.ts index 4417fc1764a..934fa0688e9 100644 --- a/extensions/telegram/src/setup-surface.ts +++ b/extensions/telegram/src/setup-surface.ts @@ -1,30 +1,110 @@ import { DEFAULT_ACCOUNT_ID, hasConfiguredSecretInput, -} from "../../../src/plugin-sdk-internal/setup.js"; -import type { ChannelSetupWizard } from "../../../src/plugin-sdk-internal/setup.js"; -import { resolveTelegramAccount } from "./accounts.js"; + type OpenClawConfig, + patchChannelConfigForAccount, + setChannelDmPolicyWithAllowFrom, + setSetupChannelEnabled, + splitSetupEntries, +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupDmPolicy, ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { inspectTelegramAccount } from "./account-inspect.js"; +import { listTelegramAccountIds, resolveTelegramAccount } from "./accounts.js"; import { - createTelegramSetupWizardBase, parseTelegramAllowFromId, + promptTelegramAllowFromForAccount, + resolveTelegramAllowFromEntries, + TELEGRAM_TOKEN_HELP_LINES, + TELEGRAM_USER_ID_HELP_LINES, telegramSetupAdapter, } from "./setup-core.js"; -export const telegramSetupWizard: ChannelSetupWizard = createTelegramSetupWizardBase({ - inspectToken: ({ cfg, accountId }) => { - const resolved = resolveTelegramAccount({ cfg, accountId }); - const hasConfiguredBotToken = hasConfiguredSecretInput(resolved.config.botToken); - const hasConfiguredValue = hasConfiguredBotToken || Boolean(resolved.config.tokenFile?.trim()); - return { - accountConfigured: Boolean(resolved.token) || hasConfiguredValue, - hasConfiguredValue, - resolvedValue: resolved.token?.trim() || undefined, - envValue: - accountId === DEFAULT_ACCOUNT_ID - ? process.env.TELEGRAM_BOT_TOKEN?.trim() || undefined - : undefined, - }; +const channel = "telegram" as const; + +const dmPolicy: ChannelSetupDmPolicy = { + label: "Telegram", + channel, + policyKey: "channels.telegram.dmPolicy", + allowFromKey: "channels.telegram.allowFrom", + getCurrent: (cfg) => cfg.channels?.telegram?.dmPolicy ?? "pairing", + setPolicy: (cfg, policy) => + setChannelDmPolicyWithAllowFrom({ + cfg, + channel, + dmPolicy: policy, + }), + promptAllowFrom: promptTelegramAllowFromForAccount, +}; + +export const telegramSetupWizard: ChannelSetupWizard = { + channel, + status: { + configuredLabel: "configured", + unconfiguredLabel: "needs token", + configuredHint: "recommended · configured", + unconfiguredHint: "recommended · newcomer-friendly", + configuredScore: 1, + unconfiguredScore: 10, + resolveConfigured: ({ cfg }) => + listTelegramAccountIds(cfg).some((accountId) => { + const account = inspectTelegramAccount({ cfg, accountId }); + return account.configured; + }), }, -}); + credentials: [ + { + inputKey: "token", + providerHint: channel, + credentialLabel: "Telegram bot token", + preferredEnvVar: "TELEGRAM_BOT_TOKEN", + helpTitle: "Telegram bot token", + helpLines: TELEGRAM_TOKEN_HELP_LINES, + envPrompt: "TELEGRAM_BOT_TOKEN detected. Use env var?", + keepPrompt: "Telegram token already configured. Keep it?", + inputPrompt: "Enter Telegram bot token", + allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID, + inspect: ({ cfg, accountId }) => { + const resolved = resolveTelegramAccount({ cfg, accountId }); + const hasConfiguredBotToken = hasConfiguredSecretInput(resolved.config.botToken); + const hasConfiguredValue = + hasConfiguredBotToken || Boolean(resolved.config.tokenFile?.trim()); + return { + accountConfigured: Boolean(resolved.token) || hasConfiguredValue, + hasConfiguredValue, + resolvedValue: resolved.token?.trim() || undefined, + envValue: + accountId === DEFAULT_ACCOUNT_ID + ? process.env.TELEGRAM_BOT_TOKEN?.trim() || undefined + : undefined, + }; + }, + }, + ], + allowFrom: { + helpTitle: "Telegram user id", + helpLines: TELEGRAM_USER_ID_HELP_LINES, + credentialInputKey: "token", + message: "Telegram allowFrom (numeric sender id; @username resolves to id)", + placeholder: "@username", + invalidWithoutCredentialNote: + "Telegram token missing; use numeric sender ids (usernames require a bot token).", + parseInputs: splitSetupEntries, + parseId: parseTelegramAllowFromId, + resolveEntries: async ({ credentialValues, entries }) => + resolveTelegramAllowFromEntries({ + credentialValue: credentialValues.token, + entries, + }), + apply: async ({ cfg, accountId, allowFrom }) => + patchChannelConfigForAccount({ + cfg, + channel, + accountId, + patch: { dmPolicy: "allowlist", allowFrom }, + }), + }, + dmPolicy, + disable: (cfg) => setSetupChannelEnabled(cfg, channel, false), +}; export { parseTelegramAllowFromId, telegramSetupAdapter }; diff --git a/extensions/telegram/src/status-issues.ts b/extensions/telegram/src/status-issues.ts index b970f533dd0..0178c0c7346 100644 --- a/extensions/telegram/src/status-issues.ts +++ b/extensions/telegram/src/status-issues.ts @@ -3,11 +3,11 @@ import { asString, isRecord, resolveEnabledConfiguredAccountId, -} from "../../../src/channels/plugins/status-issues/shared.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelAccountSnapshot, ChannelStatusIssue, -} from "../../../src/channels/plugins/types.js"; +} from "openclaw/plugin-sdk/channel-runtime"; type TelegramAccountStatus = { accountId?: unknown; diff --git a/extensions/telegram/src/status-reaction-variants.ts b/extensions/telegram/src/status-reaction-variants.ts index 6c5c80e9fd8..8c04a87554e 100644 --- a/extensions/telegram/src/status-reaction-variants.ts +++ b/extensions/telegram/src/status-reaction-variants.ts @@ -1,7 +1,4 @@ -import { - DEFAULT_EMOJIS, - type StatusReactionEmojis, -} from "../../../src/channels/status-reactions.js"; +import { DEFAULT_EMOJIS, type StatusReactionEmojis } from "openclaw/plugin-sdk/channel-runtime"; type StatusReactionEmojiKey = keyof Required; diff --git a/extensions/telegram/src/sticker-cache.ts b/extensions/telegram/src/sticker-cache.ts index e6cdfbd9015..18bfbbf4421 100644 --- a/extensions/telegram/src/sticker-cache.ts +++ b/extensions/telegram/src/sticker-cache.ts @@ -1,22 +1,19 @@ import fs from "node:fs/promises"; import path from "node:path"; -import { resolveApiKeyForProvider } from "../../../src/agents/model-auth.js"; -import type { ModelCatalogEntry } from "../../../src/agents/model-catalog.js"; +import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/agent-runtime"; +import type { ModelCatalogEntry } from "openclaw/plugin-sdk/agent-runtime"; import { findModelInCatalog, loadModelCatalog, modelSupportsVision, -} from "../../../src/agents/model-catalog.js"; -import { resolveDefaultModelForAgent } from "../../../src/agents/model-selection.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { STATE_DIR } from "../../../src/config/paths.js"; -import { logVerbose } from "../../../src/globals.js"; -import { loadJsonFile, saveJsonFile } from "../../../src/infra/json-file.js"; -import { - AUTO_IMAGE_KEY_PROVIDERS, - DEFAULT_IMAGE_MODELS, -} from "../../../src/media-understanding/defaults.js"; -import { resolveAutoImageModel } from "../../../src/media-understanding/runner.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { loadJsonFile, saveJsonFile } from "openclaw/plugin-sdk/json-store"; +import { AUTO_IMAGE_KEY_PROVIDERS, DEFAULT_IMAGE_MODELS } from "openclaw/plugin-sdk/media-runtime"; +import { resolveAutoImageModel } from "openclaw/plugin-sdk/media-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { STATE_DIR } from "openclaw/plugin-sdk/state-paths"; const CACHE_FILE = path.join(STATE_DIR, "telegram", "sticker-cache.json"); const CACHE_VERSION = 1; @@ -146,12 +143,10 @@ export function getCacheStats(): { count: number; oldestAt?: string; newestAt?: const STICKER_DESCRIPTION_PROMPT = "Describe this sticker image in 1-2 sentences. Focus on what the sticker depicts (character, object, action, emotion). Be concise and objective."; -let imageRuntimePromise: Promise< - typeof import("../../../src/media-understanding/providers/image-runtime.js") -> | null = null; +let imageRuntimePromise: Promise | null = null; function loadImageRuntime() { - imageRuntimePromise ??= import("../../../src/media-understanding/providers/image-runtime.js"); + imageRuntimePromise ??= import("openclaw/plugin-sdk/media-runtime"); return imageRuntimePromise; } diff --git a/extensions/telegram/src/target-writeback.ts b/extensions/telegram/src/target-writeback.ts index 6423215ffa2..8e5bf197a23 100644 --- a/extensions/telegram/src/target-writeback.ts +++ b/extensions/telegram/src/target-writeback.ts @@ -1,7 +1,14 @@ -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { readConfigFileSnapshotForWrite, writeConfigFile } from "../../../src/config/config.js"; -import { loadCronStore, resolveCronStorePath, saveCronStore } from "../../../src/cron/store.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { + readConfigFileSnapshotForWrite, + writeConfigFile, +} from "openclaw/plugin-sdk/config-runtime"; +import { + loadCronStore, + resolveCronStorePath, + saveCronStore, +} from "openclaw/plugin-sdk/config-runtime"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; import { normalizeTelegramChatId, normalizeTelegramLookupTarget, diff --git a/extensions/telegram/src/thread-bindings.ts b/extensions/telegram/src/thread-bindings.ts index d10fef7f72c..aaf13e15561 100644 --- a/extensions/telegram/src/thread-bindings.ts +++ b/extensions/telegram/src/thread-bindings.ts @@ -1,19 +1,19 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { resolveThreadBindingConversationIdFromBindingId } from "../../../src/channels/thread-binding-id.js"; -import { formatThreadBindingDurationLabel } from "../../../src/channels/thread-bindings-messages.js"; -import { resolveStateDir } from "../../../src/config/paths.js"; -import { logVerbose } from "../../../src/globals.js"; -import { writeJsonAtomic } from "../../../src/infra/json-files.js"; +import { resolveThreadBindingConversationIdFromBindingId } from "openclaw/plugin-sdk/channel-runtime"; +import { formatThreadBindingDurationLabel } from "openclaw/plugin-sdk/channel-runtime"; import { registerSessionBindingAdapter, unregisterSessionBindingAdapter, type BindingTargetKind, type SessionBindingRecord, -} from "../../../src/infra/outbound/session-binding-service.js"; -import { normalizeAccountId } from "../../../src/routing/session-key.js"; -import { resolveGlobalSingleton } from "../../../src/shared/global-singleton.js"; +} from "openclaw/plugin-sdk/conversation-runtime"; +import { writeJsonAtomic } from "openclaw/plugin-sdk/infra-runtime"; +import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; +import { resolveGlobalSingleton } from "openclaw/plugin-sdk/text-runtime"; const DEFAULT_THREAD_BINDING_IDLE_TIMEOUT_MS = 24 * 60 * 60 * 1000; const DEFAULT_THREAD_BINDING_MAX_AGE_MS = 0; diff --git a/extensions/telegram/src/token.ts b/extensions/telegram/src/token.ts index d26d9657ca1..7a23a34ab12 100644 --- a/extensions/telegram/src/token.ts +++ b/extensions/telegram/src/token.ts @@ -1,9 +1,9 @@ -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"; +import type { BaseTokenResolution } from "openclaw/plugin-sdk/channel-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/config-runtime"; +import { tryReadSecretFileSync } from "openclaw/plugin-sdk/infra-runtime"; +import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing"; +import type { TelegramAccountConfig } from "openclaw/plugin-sdk/telegram"; export type TelegramTokenSource = "env" | "tokenFile" | "config" | "none"; diff --git a/extensions/telegram/src/update-offset-store.ts b/extensions/telegram/src/update-offset-store.ts index 55b4e96ae23..395b5c1e450 100644 --- a/extensions/telegram/src/update-offset-store.ts +++ b/extensions/telegram/src/update-offset-store.ts @@ -1,8 +1,8 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { resolveStateDir } from "../../../src/config/paths.js"; -import { writeJsonAtomic } from "../../../src/infra/json-files.js"; +import { writeJsonAtomic } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; const STORE_VERSION = 2; diff --git a/extensions/telegram/src/voice.ts b/extensions/telegram/src/voice.ts index 865bd82d72e..8a452471603 100644 --- a/extensions/telegram/src/voice.ts +++ b/extensions/telegram/src/voice.ts @@ -1,4 +1,4 @@ -import { isTelegramVoiceCompatibleAudio } from "../../../src/media/audio.js"; +import { isTelegramVoiceCompatibleAudio } from "openclaw/plugin-sdk/media-runtime"; export function resolveTelegramVoiceDecision(opts: { wantsVoice: boolean; diff --git a/extensions/telegram/src/webhook.ts b/extensions/telegram/src/webhook.ts index 39458ae036a..076bd12b279 100644 --- a/extensions/telegram/src/webhook.ts +++ b/extensions/telegram/src/webhook.ts @@ -1,19 +1,19 @@ import { timingSafeEqual } from "node:crypto"; import { createServer } from "node:http"; import { InputFile, webhookCallback } from "grammy"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import { isDiagnosticsEnabled } from "../../../src/infra/diagnostic-events.js"; -import { formatErrorMessage } from "../../../src/infra/errors.js"; -import { readJsonBodyWithLimit } from "../../../src/infra/http-body.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { isDiagnosticsEnabled } from "openclaw/plugin-sdk/infra-runtime"; +import { formatErrorMessage } from "openclaw/plugin-sdk/infra-runtime"; +import { readJsonBodyWithLimit } from "openclaw/plugin-sdk/infra-runtime"; +import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { defaultRuntime } from "openclaw/plugin-sdk/runtime-env"; import { logWebhookError, logWebhookProcessed, logWebhookReceived, startDiagnosticHeartbeat, stopDiagnosticHeartbeat, -} from "../../../src/logging/diagnostic.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; -import { defaultRuntime } from "../../../src/runtime.js"; +} from "openclaw/plugin-sdk/text-runtime"; import { resolveTelegramAllowedUpdates } from "./allowed-updates.js"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { createTelegramBot } from "./bot.js"; diff --git a/extensions/test-utils/directory.ts b/extensions/test-utils/directory.ts index 90d2ed445d3..b4edaa12ded 100644 --- a/extensions/test-utils/directory.ts +++ b/extensions/test-utils/directory.ts @@ -1,4 +1,4 @@ -import type { ChannelDirectoryAdapter } from "../../src/channels/plugins/types.js"; +import type { ChannelDirectoryAdapter } from "openclaw/plugin-sdk/channel-runtime"; export function createDirectoryTestRuntime() { return { diff --git a/extensions/test-utils/plugin-api.ts b/extensions/test-utils/plugin-api.ts index 82fe818fdec..2080359d961 100644 --- a/extensions/test-utils/plugin-api.ts +++ b/extensions/test-utils/plugin-api.ts @@ -1,4 +1,4 @@ -import type { OpenClawPluginApi } from "../../src/plugins/types.js"; +import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-runtime"; type TestPluginApiInput = Partial & Pick; diff --git a/extensions/test-utils/plugin-runtime-mock.ts b/extensions/test-utils/plugin-runtime-mock.ts index b7ca386028b..a5003620a59 100644 --- a/extensions/test-utils/plugin-runtime-mock.ts +++ b/extensions/test-utils/plugin-runtime-mock.ts @@ -1,7 +1,7 @@ +import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "openclaw/plugin-sdk/agent-runtime"; import type { PluginRuntime } from "openclaw/plugin-sdk/test-utils"; import { removeAckReactionAfterReply, shouldAckReaction } from "openclaw/plugin-sdk/test-utils"; import { vi } from "vitest"; -import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../../src/agents/defaults.js"; type DeepPartial = { [K in keyof T]?: T[K] extends (...args: never[]) => unknown diff --git a/extensions/together/index.ts b/extensions/together/index.ts index a32031f0634..5f6dfb3e7c4 100644 --- a/extensions/together/index.ts +++ b/extensions/together/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyTogetherConfig, TOGETHER_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; import { buildTogetherProvider } from "./provider-catalog.js"; diff --git a/extensions/together/onboard.ts b/extensions/together/onboard.ts index a540401e01a..e18595ab21e 100644 --- a/extensions/together/onboard.ts +++ b/extensions/together/onboard.ts @@ -2,12 +2,12 @@ import { buildTogetherModelDefinition, TOGETHER_BASE_URL, TOGETHER_MODEL_CATALOG, -} from "../../src/agents/together-models.js"; +} from "openclaw/plugin-sdk/provider-models"; import { applyAgentDefaultModelPrimary, applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export const TOGETHER_DEFAULT_MODEL_REF = "together/moonshotai/Kimi-K2.5"; diff --git a/extensions/together/provider-catalog.ts b/extensions/together/provider-catalog.ts index 3d902d3bb1a..45d3b5de130 100644 --- a/extensions/together/provider-catalog.ts +++ b/extensions/together/provider-catalog.ts @@ -1,9 +1,9 @@ import { buildTogetherModelDefinition, + type ModelProviderConfig, TOGETHER_BASE_URL, TOGETHER_MODEL_CATALOG, -} from "../../src/agents/together-models.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +} from "openclaw/plugin-sdk/provider-models"; export function buildTogetherProvider(): ModelProviderConfig { return { diff --git a/extensions/twitch/src/plugin.ts b/extensions/twitch/src/plugin.ts index 3958a05fd8b..490b741d989 100644 --- a/extensions/twitch/src/plugin.ts +++ b/extensions/twitch/src/plugin.ts @@ -136,7 +136,7 @@ export const twitchPlugin: ChannelPlugin = { accountId?: string | null; inputs: string[]; kind: ChannelResolveKind; - runtime: import("../../../src/runtime.js").RuntimeEnv; + runtime: import("openclaw/plugin-sdk/runtime-env").RuntimeEnv; }): Promise => { const account = getAccountConfig(cfg, accountId ?? DEFAULT_ACCOUNT_ID); diff --git a/extensions/venice/index.ts b/extensions/venice/index.ts index 92ff17e6df5..d25e8ffb9b8 100644 --- a/extensions/venice/index.ts +++ b/extensions/venice/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyVeniceConfig, VENICE_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; import { buildVeniceProvider } from "./provider-catalog.js"; diff --git a/extensions/venice/onboard.ts b/extensions/venice/onboard.ts index fbd535d6264..23634a18540 100644 --- a/extensions/venice/onboard.ts +++ b/extensions/venice/onboard.ts @@ -3,12 +3,12 @@ import { VENICE_BASE_URL, VENICE_DEFAULT_MODEL_REF, VENICE_MODEL_CATALOG, -} from "../../src/agents/venice-models.js"; +} from "openclaw/plugin-sdk/provider-models"; import { applyAgentDefaultModelPrimary, applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export { VENICE_DEFAULT_MODEL_REF }; diff --git a/extensions/venice/provider-catalog.ts b/extensions/venice/provider-catalog.ts index ec7087a08db..d207ab581b1 100644 --- a/extensions/venice/provider-catalog.ts +++ b/extensions/venice/provider-catalog.ts @@ -1,5 +1,8 @@ -import { discoverVeniceModels, VENICE_BASE_URL } from "../../src/agents/venice-models.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import { + discoverVeniceModels, + type ModelProviderConfig, + VENICE_BASE_URL, +} from "openclaw/plugin-sdk/provider-models"; export async function buildVeniceProvider(): Promise { const models = await discoverVeniceModels(); diff --git a/extensions/vercel-ai-gateway/index.ts b/extensions/vercel-ai-gateway/index.ts index ea7c734f310..1f126260321 100644 --- a/extensions/vercel-ai-gateway/index.ts +++ b/extensions/vercel-ai-gateway/index.ts @@ -1,5 +1,5 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; import { applyVercelAiGatewayConfig, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; import { buildVercelAiGatewayProvider } from "./provider-catalog.js"; diff --git a/extensions/vercel-ai-gateway/onboard.ts b/extensions/vercel-ai-gateway/onboard.ts index d65d7224781..5ca89c8ad33 100644 --- a/extensions/vercel-ai-gateway/onboard.ts +++ b/extensions/vercel-ai-gateway/onboard.ts @@ -1,5 +1,7 @@ -import { applyAgentDefaultModelPrimary } from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; +import { + applyAgentDefaultModelPrimary, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; export const VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF = "vercel-ai-gateway/anthropic/claude-opus-4.6"; diff --git a/extensions/vercel-ai-gateway/provider-catalog.ts b/extensions/vercel-ai-gateway/provider-catalog.ts index 0e219264ab7..d3475efe9b9 100644 --- a/extensions/vercel-ai-gateway/provider-catalog.ts +++ b/extensions/vercel-ai-gateway/provider-catalog.ts @@ -1,8 +1,8 @@ import { discoverVercelAiGatewayModels, VERCEL_AI_GATEWAY_BASE_URL, -} from "../../src/agents/vercel-ai-gateway.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; + type ModelProviderConfig, +} from "openclaw/plugin-sdk/provider-models"; export async function buildVercelAiGatewayProvider(): Promise { return { diff --git a/extensions/vllm/index.ts b/extensions/vllm/index.ts index 938fb78c9bd..24805e700a6 100644 --- a/extensions/vllm/index.ts +++ b/extensions/vllm/index.ts @@ -1,14 +1,14 @@ -import { - emptyPluginConfigSchema, - type OpenClawPluginApi, - type ProviderAuthMethodNonInteractiveContext, -} from "openclaw/plugin-sdk/core"; import { VLLM_DEFAULT_API_KEY_ENV_VAR, VLLM_DEFAULT_BASE_URL, VLLM_MODEL_PLACEHOLDER, VLLM_PROVIDER_LABEL, -} from "../../src/agents/vllm-defaults.js"; +} from "openclaw/plugin-sdk/agent-runtime"; +import { + emptyPluginConfigSchema, + type OpenClawPluginApi, + type ProviderAuthMethodNonInteractiveContext, +} from "openclaw/plugin-sdk/core"; const PROVIDER_ID = "vllm"; diff --git a/extensions/volcengine/index.ts b/extensions/volcengine/index.ts index f9e3fb72010..975bcce610d 100644 --- a/extensions/volcengine/index.ts +++ b/extensions/volcengine/index.ts @@ -1,7 +1,6 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { ensureModelAllowlistEntry } from "../../src/commands/model-allowlist.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import { buildPairedProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { ensureModelAllowlistEntry } from "openclaw/plugin-sdk/provider-onboard"; import { buildDoubaoCodingProvider, buildDoubaoProvider } from "./provider-catalog.js"; const PROVIDER_ID = "volcengine"; @@ -46,15 +45,18 @@ const volcenginePlugin = { ], catalog: { order: "paired", - run: (ctx) => - buildPairedProviderApiKeyCatalog({ - ctx, - providerId: PROVIDER_ID, - buildProviders: () => ({ - volcengine: buildDoubaoProvider(), - "volcengine-plan": buildDoubaoCodingProvider(), - }), - }), + run: async (ctx) => { + const apiKey = ctx.resolveProviderApiKey(PROVIDER_ID).apiKey; + if (!apiKey) { + return null; + } + return { + providers: { + volcengine: { ...buildDoubaoProvider(), apiKey }, + "volcengine-plan": { ...buildDoubaoCodingProvider(), apiKey }, + }, + }; + }, }, }); }, diff --git a/extensions/volcengine/provider-catalog.ts b/extensions/volcengine/provider-catalog.ts index ef57e0a86e7..f01a3079bcc 100644 --- a/extensions/volcengine/provider-catalog.ts +++ b/extensions/volcengine/provider-catalog.ts @@ -4,8 +4,8 @@ import { DOUBAO_CODING_BASE_URL, DOUBAO_CODING_MODEL_CATALOG, DOUBAO_MODEL_CATALOG, -} from "../../src/agents/doubao-models.js"; -import type { ModelProviderConfig } from "../../src/config/types.models.js"; + type ModelProviderConfig, +} from "openclaw/plugin-sdk/provider-models"; export function buildDoubaoProvider(): ModelProviderConfig { return { diff --git a/extensions/whatsapp/src/accounts.ts b/extensions/whatsapp/src/accounts.ts index 1d17404a6a2..d2a4e277846 100644 --- a/extensions/whatsapp/src/accounts.ts +++ b/extensions/whatsapp/src/accounts.ts @@ -1,19 +1,15 @@ import fs from "node:fs"; import path from "node:path"; -import { resolveOAuthDir } from "../../../src/config/paths.js"; import { - type OpenClawConfig, createAccountListHelpers, DEFAULT_ACCOUNT_ID, normalizeAccountId, resolveAccountEntry, resolveUserPath, -} from "../../../src/plugin-sdk-internal/accounts.js"; -import type { - DmPolicy, - GroupPolicy, - WhatsAppAccountConfig, -} from "../../../src/plugin-sdk-internal/whatsapp.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/account-resolution"; +import { resolveOAuthDir } from "openclaw/plugin-sdk/state-paths"; +import type { DmPolicy, GroupPolicy, WhatsAppAccountConfig } from "openclaw/plugin-sdk/whatsapp"; import { hasWebCredsSync } from "./auth-store.js"; export type ResolvedWhatsAppAccount = { diff --git a/extensions/whatsapp/src/active-listener.ts b/extensions/whatsapp/src/active-listener.ts index fc8f11fe20e..71b6086f3a0 100644 --- a/extensions/whatsapp/src/active-listener.ts +++ b/extensions/whatsapp/src/active-listener.ts @@ -1,6 +1,6 @@ -import { formatCliCommand } from "../../../src/cli/command-format.js"; -import type { PollInput } from "../../../src/polls.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js"; +import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; +import type { PollInput } from "openclaw/plugin-sdk/media-runtime"; +import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing"; export type ActiveWebSendOptions = { gifPlayback?: boolean; diff --git a/extensions/whatsapp/src/agent-tools-login.ts b/extensions/whatsapp/src/agent-tools-login.ts index a1ac87a3976..9343e83d21a 100644 --- a/extensions/whatsapp/src/agent-tools-login.ts +++ b/extensions/whatsapp/src/agent-tools-login.ts @@ -1,5 +1,5 @@ import { Type } from "@sinclair/typebox"; -import type { ChannelAgentTool } from "../../../src/channels/plugins/types.js"; +import type { ChannelAgentTool } from "openclaw/plugin-sdk/channel-runtime"; export function createWhatsAppLoginTool(): ChannelAgentTool { return { diff --git a/extensions/whatsapp/src/auth-store.ts b/extensions/whatsapp/src/auth-store.ts index 636c114676f..991be6dff7d 100644 --- a/extensions/whatsapp/src/auth-store.ts +++ b/extensions/whatsapp/src/auth-store.ts @@ -1,14 +1,14 @@ import fsSync from "node:fs"; import fs from "node:fs/promises"; import path from "node:path"; -import { formatCliCommand } from "../../../src/cli/command-format.js"; -import { resolveOAuthDir } from "../../../src/config/paths.js"; -import { info, success } from "../../../src/globals.js"; -import { getChildLogger } from "../../../src/logging.js"; -import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js"; -import { defaultRuntime, type RuntimeEnv } from "../../../src/runtime.js"; -import type { WebChannel } from "../../../src/utils.js"; -import { jidToE164, resolveUserPath } from "../../../src/utils.js"; +import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; +import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing"; +import { info, success } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; +import { defaultRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { resolveOAuthDir } from "openclaw/plugin-sdk/state-paths"; +import type { WebChannel } from "openclaw/plugin-sdk/text-runtime"; +import { jidToE164, resolveUserPath } from "openclaw/plugin-sdk/text-runtime"; export function resolveDefaultWebAuthDir(): string { return path.join(resolveOAuthDir(), "whatsapp", DEFAULT_ACCOUNT_ID); diff --git a/extensions/whatsapp/src/auto-reply.impl.ts b/extensions/whatsapp/src/auto-reply.impl.ts index 57feff1ab4d..e936c63e732 100644 --- a/extensions/whatsapp/src/auto-reply.impl.ts +++ b/extensions/whatsapp/src/auto-reply.impl.ts @@ -1,5 +1,5 @@ -export { HEARTBEAT_PROMPT, stripHeartbeatToken } from "../../../src/auto-reply/heartbeat.js"; -export { HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN } from "../../../src/auto-reply/tokens.js"; +export { HEARTBEAT_PROMPT, stripHeartbeatToken } from "openclaw/plugin-sdk/reply-runtime"; +export { HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN } from "openclaw/plugin-sdk/reply-runtime"; export { DEFAULT_WEB_MEDIA_BYTES } from "./auto-reply/constants.js"; export { resolveHeartbeatRecipients, runWebHeartbeatOnce } from "./auto-reply/heartbeat-runner.js"; diff --git a/extensions/whatsapp/src/auto-reply.test-harness.ts b/extensions/whatsapp/src/auto-reply.test-harness.ts index dfbcf447fa9..f3707f87679 100644 --- a/extensions/whatsapp/src/auto-reply.test-harness.ts +++ b/extensions/whatsapp/src/auto-reply.test-harness.ts @@ -2,10 +2,10 @@ import "./test-helpers.js"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; +import * as ssrf from "openclaw/plugin-sdk/infra-runtime"; +import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-runtime"; +import { resetLogger, setLoggerOverride } from "openclaw/plugin-sdk/runtime-env"; import { afterAll, afterEach, beforeAll, beforeEach, vi } from "vitest"; -import { resetInboundDedupe } from "../../../src/auto-reply/reply/inbound-dedupe.js"; -import * as ssrf from "../../../src/infra/net/ssrf.js"; -import { resetLogger, setLoggerOverride } from "../../../src/logging.js"; import type { WebInboundMessage, WebListenerCloseReason } from "./inbound.js"; import { resetBaileysMocks as _resetBaileysMocks, @@ -29,7 +29,7 @@ type MockWebListener = { export const TEST_NET_IP = "203.0.113.10"; -vi.mock("../../../src/agents/pi-embedded.js", () => ({ +vi.mock("openclaw/plugin-sdk/agent-runtime", () => ({ abortEmbeddedPiRun: vi.fn().mockReturnValue(false), isEmbeddedPiRunActive: vi.fn().mockReturnValue(false), isEmbeddedPiRunStreaming: vi.fn().mockReturnValue(false), diff --git a/extensions/whatsapp/src/auto-reply/deliver-reply.ts b/extensions/whatsapp/src/auto-reply/deliver-reply.ts index 6fb4ce39143..6d9d8b541ae 100644 --- a/extensions/whatsapp/src/auto-reply/deliver-reply.ts +++ b/extensions/whatsapp/src/auto-reply/deliver-reply.ts @@ -1,10 +1,10 @@ -import { chunkMarkdownTextWithMode, type ChunkMode } from "../../../../src/auto-reply/chunk.js"; -import type { ReplyPayload } from "../../../../src/auto-reply/types.js"; -import type { MarkdownTableMode } from "../../../../src/config/types.base.js"; -import { logVerbose, shouldLogVerbose } from "../../../../src/globals.js"; -import { convertMarkdownTables } from "../../../../src/markdown/tables.js"; -import { markdownToWhatsApp } from "../../../../src/markdown/whatsapp.js"; -import { sleep } from "../../../../src/utils.js"; +import type { MarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; +import { markdownToWhatsApp } from "openclaw/plugin-sdk/text-runtime"; +import { sleep } from "openclaw/plugin-sdk/text-runtime"; import { loadWebMedia } from "../media.js"; import { newConnectionId } from "../reconnect.js"; import { formatError } from "../session.js"; diff --git a/extensions/whatsapp/src/auto-reply/heartbeat-runner.ts b/extensions/whatsapp/src/auto-reply/heartbeat-runner.ts index 0b423a3f116..7aa35705f43 100644 --- a/extensions/whatsapp/src/auto-reply/heartbeat-runner.ts +++ b/extensions/whatsapp/src/auto-reply/heartbeat-runner.ts @@ -1,28 +1,25 @@ -import { appendCronStyleCurrentTimeLine } from "../../../../src/agents/current-time.js"; -import { resolveHeartbeatReplyPayload } from "../../../../src/auto-reply/heartbeat-reply-payload.js"; -import { - DEFAULT_HEARTBEAT_ACK_MAX_CHARS, - resolveHeartbeatPrompt, - stripHeartbeatToken, -} from "../../../../src/auto-reply/heartbeat.js"; -import { getReplyFromConfig } from "../../../../src/auto-reply/reply.js"; -import { HEARTBEAT_TOKEN } from "../../../../src/auto-reply/tokens.js"; -import { resolveWhatsAppHeartbeatRecipients } from "../../../../src/channels/plugins/whatsapp-heartbeat.js"; -import { loadConfig } from "../../../../src/config/config.js"; +import { appendCronStyleCurrentTimeLine } from "openclaw/plugin-sdk/agent-runtime"; +import { resolveWhatsAppHeartbeatRecipients } from "openclaw/plugin-sdk/channel-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { loadSessionStore, resolveSessionKey, resolveStorePath, updateSessionStore, -} from "../../../../src/config/sessions.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { emitHeartbeatEvent, resolveIndicatorType } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveHeartbeatVisibility } from "openclaw/plugin-sdk/infra-runtime"; +import { resolveHeartbeatReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { - emitHeartbeatEvent, - resolveIndicatorType, -} from "../../../../src/infra/heartbeat-events.js"; -import { resolveHeartbeatVisibility } from "../../../../src/infra/heartbeat-visibility.js"; -import { getChildLogger } from "../../../../src/logging.js"; -import { redactIdentifier } from "../../../../src/logging/redact-identifier.js"; -import { normalizeMainKey } from "../../../../src/routing/session-key.js"; + DEFAULT_HEARTBEAT_ACK_MAX_CHARS, + resolveHeartbeatPrompt, + stripHeartbeatToken, +} from "openclaw/plugin-sdk/reply-runtime"; +import { getReplyFromConfig } from "openclaw/plugin-sdk/reply-runtime"; +import { HEARTBEAT_TOKEN } from "openclaw/plugin-sdk/reply-runtime"; +import { normalizeMainKey } from "openclaw/plugin-sdk/routing"; +import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; +import { redactIdentifier } from "openclaw/plugin-sdk/text-runtime"; import { newConnectionId } from "../reconnect.js"; import { sendMessageWhatsApp } from "../send.js"; import { formatError } from "../session.js"; diff --git a/extensions/whatsapp/src/auto-reply/loggers.ts b/extensions/whatsapp/src/auto-reply/loggers.ts index 71575671b2e..1201a412a59 100644 --- a/extensions/whatsapp/src/auto-reply/loggers.ts +++ b/extensions/whatsapp/src/auto-reply/loggers.ts @@ -1,4 +1,4 @@ -import { createSubsystemLogger } from "../../../../src/logging/subsystem.js"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; export const whatsappLog = createSubsystemLogger("gateway/channels/whatsapp"); export const whatsappInboundLog = whatsappLog.child("inbound"); diff --git a/extensions/whatsapp/src/auto-reply/mentions.ts b/extensions/whatsapp/src/auto-reply/mentions.ts index 3891810c617..ad42c814c26 100644 --- a/extensions/whatsapp/src/auto-reply/mentions.ts +++ b/extensions/whatsapp/src/auto-reply/mentions.ts @@ -1,9 +1,6 @@ -import { - buildMentionRegexes, - normalizeMentionText, -} from "../../../../src/auto-reply/reply/mentions.js"; -import type { loadConfig } from "../../../../src/config/config.js"; -import { isSelfChatMode, jidToE164, normalizeE164 } from "../../../../src/utils.js"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { buildMentionRegexes, normalizeMentionText } from "openclaw/plugin-sdk/reply-runtime"; +import { isSelfChatMode, jidToE164, normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import type { WebInboundMsg } from "./types.js"; export type MentionConfig = { diff --git a/extensions/whatsapp/src/auto-reply/monitor.ts b/extensions/whatsapp/src/auto-reply/monitor.ts index 1222c69b71a..2f83e65079a 100644 --- a/extensions/whatsapp/src/auto-reply/monitor.ts +++ b/extensions/whatsapp/src/auto-reply/monitor.ts @@ -1,18 +1,18 @@ -import { hasControlCommand } from "../../../../src/auto-reply/command-detection.js"; -import { resolveInboundDebounceMs } from "../../../../src/auto-reply/inbound-debounce.js"; -import { getReplyFromConfig } from "../../../../src/auto-reply/reply.js"; -import { DEFAULT_GROUP_HISTORY_LIMIT } from "../../../../src/auto-reply/reply/history.js"; -import { formatCliCommand } from "../../../../src/cli/command-format.js"; -import { waitForever } from "../../../../src/cli/wait.js"; -import { loadConfig } from "../../../../src/config/config.js"; -import { createConnectedChannelStatusPatch } from "../../../../src/gateway/channel-status-patches.js"; -import { logVerbose } from "../../../../src/globals.js"; -import { formatDurationPrecise } from "../../../../src/infra/format-time/format-duration.ts"; -import { enqueueSystemEvent } from "../../../../src/infra/system-events.js"; -import { registerUnhandledRejectionHandler } from "../../../../src/infra/unhandled-rejections.js"; -import { getChildLogger } from "../../../../src/logging.js"; -import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js"; -import { defaultRuntime, type RuntimeEnv } from "../../../../src/runtime.js"; +import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; +import { waitForever } from "openclaw/plugin-sdk/cli-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { createConnectedChannelStatusPatch } from "openclaw/plugin-sdk/gateway-runtime"; +import { formatDurationPrecise } from "openclaw/plugin-sdk/infra-runtime"; +import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveInboundDebounceMs } from "openclaw/plugin-sdk/reply-runtime"; +import { getReplyFromConfig } from "openclaw/plugin-sdk/reply-runtime"; +import { DEFAULT_GROUP_HISTORY_LIMIT } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { registerUnhandledRejectionHandler } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; +import { defaultRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { resolveWhatsAppAccount, resolveWhatsAppMediaMaxBytes } from "../accounts.js"; import { setActiveWebListener } from "../active-listener.js"; import { monitorWebInbox } from "../inbound.js"; diff --git a/extensions/whatsapp/src/auto-reply/monitor/ack-reaction.ts b/extensions/whatsapp/src/auto-reply/monitor/ack-reaction.ts index c5a5d149ab7..126c485ec6f 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/ack-reaction.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/ack-reaction.ts @@ -1,6 +1,6 @@ -import { shouldAckReactionForWhatsApp } from "../../../../../src/channels/ack-reactions.js"; -import type { loadConfig } from "../../../../../src/config/config.js"; -import { logVerbose } from "../../../../../src/globals.js"; +import { shouldAckReactionForWhatsApp } from "openclaw/plugin-sdk/channel-runtime"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { sendReactionWhatsApp } from "../../send.js"; import { formatError } from "../../session.js"; import type { WebInboundMsg } from "../types.js"; diff --git a/extensions/whatsapp/src/auto-reply/monitor/broadcast.ts b/extensions/whatsapp/src/auto-reply/monitor/broadcast.ts index b00ba7aff9b..b2dc74cffe5 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/broadcast.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/broadcast.ts @@ -1,14 +1,11 @@ -import type { loadConfig } from "../../../../../src/config/config.js"; -import type { resolveAgentRoute } from "../../../../../src/routing/resolve-route.js"; -import { - buildAgentSessionKey, - deriveLastRoutePolicy, -} from "../../../../../src/routing/resolve-route.js"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { buildAgentSessionKey, deriveLastRoutePolicy } from "openclaw/plugin-sdk/routing"; import { buildAgentMainSessionKey, DEFAULT_MAIN_KEY, normalizeAgentId, -} from "../../../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/routing"; import { formatError } from "../../session.js"; import { whatsappInboundLog } from "../loggers.js"; import type { WebInboundMsg } from "../types.js"; diff --git a/extensions/whatsapp/src/auto-reply/monitor/group-activation.ts b/extensions/whatsapp/src/auto-reply/monitor/group-activation.ts index 60b15f5b3c6..745e62fa17a 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/group-activation.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/group-activation.ts @@ -1,14 +1,14 @@ -import { normalizeGroupActivation } from "../../../../../src/auto-reply/group-activation.js"; -import type { loadConfig } from "../../../../../src/config/config.js"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention, -} from "../../../../../src/config/group-policy.js"; +} from "openclaw/plugin-sdk/config-runtime"; import { loadSessionStore, resolveGroupSessionKey, resolveStorePath, -} from "../../../../../src/config/sessions.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { normalizeGroupActivation } from "openclaw/plugin-sdk/reply-runtime"; export function resolveGroupPolicyFor(cfg: ReturnType, conversationId: string) { const groupId = resolveGroupSessionKey({ diff --git a/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts b/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts index 418d5ebee83..847e5e3182f 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/group-gating.ts @@ -1,9 +1,9 @@ -import { hasControlCommand } from "../../../../../src/auto-reply/command-detection.js"; -import { parseActivationCommand } from "../../../../../src/auto-reply/group-activation.js"; -import { recordPendingHistoryEntryIfEnabled } from "../../../../../src/auto-reply/reply/history.js"; -import { resolveMentionGating } from "../../../../../src/channels/mention-gating.js"; -import type { loadConfig } from "../../../../../src/config/config.js"; -import { normalizeE164 } from "../../../../../src/utils.js"; +import { resolveMentionGating } from "openclaw/plugin-sdk/channel-runtime"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime"; +import { parseActivationCommand } from "openclaw/plugin-sdk/reply-runtime"; +import { recordPendingHistoryEntryIfEnabled } from "openclaw/plugin-sdk/reply-runtime"; +import { normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import type { MentionConfig } from "../mentions.js"; import { buildMentionConfig, debugMention, resolveOwnerList } from "../mentions.js"; import type { WebInboundMsg } from "../types.js"; diff --git a/extensions/whatsapp/src/auto-reply/monitor/group-members.ts b/extensions/whatsapp/src/auto-reply/monitor/group-members.ts index fc2d541bcf5..a037dcfb38b 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/group-members.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/group-members.ts @@ -1,4 +1,4 @@ -import { normalizeE164 } from "../../../../../src/utils.js"; +import { normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; function appendNormalizedUnique(entries: Iterable, seen: Set, ordered: string[]) { for (const entry of entries) { diff --git a/extensions/whatsapp/src/auto-reply/monitor/last-route.ts b/extensions/whatsapp/src/auto-reply/monitor/last-route.ts index 9fbe17d104d..915db0ba761 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/last-route.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/last-route.ts @@ -1,6 +1,6 @@ -import type { MsgContext } from "../../../../../src/auto-reply/templating.js"; -import type { loadConfig } from "../../../../../src/config/config.js"; -import { resolveStorePath, updateLastRoute } from "../../../../../src/config/sessions.js"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/config-runtime"; +import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime"; import { formatError } from "../../session.js"; export function trackBackgroundTask( diff --git a/extensions/whatsapp/src/auto-reply/monitor/message-line.ts b/extensions/whatsapp/src/auto-reply/monitor/message-line.ts index 299d5868bf8..b9494f0325c 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/message-line.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/message-line.ts @@ -1,9 +1,9 @@ -import { resolveMessagePrefix } from "../../../../../src/agents/identity.js"; +import { resolveMessagePrefix } from "openclaw/plugin-sdk/agent-runtime"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { formatInboundEnvelope, type EnvelopeFormatOptions, -} from "../../../../../src/auto-reply/envelope.js"; -import type { loadConfig } from "../../../../../src/config/config.js"; +} from "openclaw/plugin-sdk/reply-runtime"; import type { WebInboundMsg } from "../types.js"; export function formatReplyContext(msg: WebInboundMsg) { diff --git a/extensions/whatsapp/src/auto-reply/monitor/on-message.ts b/extensions/whatsapp/src/auto-reply/monitor/on-message.ts index caa519f5cf0..fe91ffff547 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/on-message.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/on-message.ts @@ -1,10 +1,10 @@ -import type { getReplyFromConfig } from "../../../../../src/auto-reply/reply.js"; -import type { MsgContext } from "../../../../../src/auto-reply/templating.js"; -import { loadConfig } from "../../../../../src/config/config.js"; -import { logVerbose } from "../../../../../src/globals.js"; -import { resolveAgentRoute } from "../../../../../src/routing/resolve-route.js"; -import { buildGroupHistoryKey } from "../../../../../src/routing/session-key.js"; -import { normalizeE164 } from "../../../../../src/utils.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { getReplyFromConfig } from "openclaw/plugin-sdk/reply-runtime"; +import type { MsgContext } from "openclaw/plugin-sdk/reply-runtime"; +import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; +import { buildGroupHistoryKey } from "openclaw/plugin-sdk/routing"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import type { MentionConfig } from "../mentions.js"; import type { WebInboundMsg } from "../types.js"; import { maybeBroadcastMessage } from "./broadcast.js"; @@ -26,7 +26,7 @@ export function createWebOnMessageHandler(params: { echoTracker: EchoTracker; backgroundTasks: Set>; replyResolver: typeof getReplyFromConfig; - replyLogger: ReturnType<(typeof import("../../../../../src/logging.js"))["getChildLogger"]>; + replyLogger: ReturnType<(typeof import("openclaw/plugin-sdk/runtime-env"))["getChildLogger"]>; baseMentionConfig: MentionConfig; account: { authDir?: string; accountId?: string }; }) { diff --git a/extensions/whatsapp/src/auto-reply/monitor/peer.ts b/extensions/whatsapp/src/auto-reply/monitor/peer.ts index 7795ac7c4d1..daaa5a50f01 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/peer.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/peer.ts @@ -1,4 +1,4 @@ -import { jidToE164, normalizeE164 } from "../../../../../src/utils.js"; +import { jidToE164, normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import type { WebInboundMsg } from "../types.js"; export function resolvePeerId(msg: WebInboundMsg) { diff --git a/extensions/whatsapp/src/auto-reply/monitor/process-message.ts b/extensions/whatsapp/src/auto-reply/monitor/process-message.ts index 094e4570bdb..beaa564fe28 100644 --- a/extensions/whatsapp/src/auto-reply/monitor/process-message.ts +++ b/extensions/whatsapp/src/auto-reply/monitor/process-message.ts @@ -1,34 +1,34 @@ -import { resolveIdentityNamePrefix } from "../../../../../src/agents/identity.js"; -import { resolveChunkMode, resolveTextChunkLimit } from "../../../../../src/auto-reply/chunk.js"; -import { shouldComputeCommandAuthorized } from "../../../../../src/auto-reply/command-detection.js"; -import { formatInboundEnvelope } from "../../../../../src/auto-reply/envelope.js"; -import type { getReplyFromConfig } from "../../../../../src/auto-reply/reply.js"; +import { resolveIdentityNamePrefix } from "openclaw/plugin-sdk/agent-runtime"; +import { toLocationContext } from "openclaw/plugin-sdk/channel-runtime"; +import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveInboundSessionEnvelopeContext } from "openclaw/plugin-sdk/channel-runtime"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { recordSessionMetaFromInbound } from "openclaw/plugin-sdk/config-runtime"; +import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime"; +import { shouldComputeCommandAuthorized } from "openclaw/plugin-sdk/reply-runtime"; +import { formatInboundEnvelope } from "openclaw/plugin-sdk/reply-runtime"; +import type { getReplyFromConfig } from "openclaw/plugin-sdk/reply-runtime"; import { buildHistoryContextFromEntries, type HistoryEntry, -} from "../../../../../src/auto-reply/reply/history.js"; -import { finalizeInboundContext } from "../../../../../src/auto-reply/reply/inbound-context.js"; -import { dispatchReplyWithBufferedBlockDispatcher } from "../../../../../src/auto-reply/reply/provider-dispatcher.js"; -import type { ReplyPayload } from "../../../../../src/auto-reply/types.js"; -import { toLocationContext } from "../../../../../src/channels/location.js"; -import { createReplyPrefixOptions } from "../../../../../src/channels/reply-prefix.js"; -import { resolveInboundSessionEnvelopeContext } from "../../../../../src/channels/session-envelope.js"; -import type { loadConfig } from "../../../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../../../src/config/markdown-tables.js"; -import { recordSessionMetaFromInbound } from "../../../../../src/config/sessions.js"; -import { logVerbose, shouldLogVerbose } from "../../../../../src/globals.js"; -import type { getChildLogger } from "../../../../../src/logging.js"; -import { getAgentScopedMediaLocalRoots } from "../../../../../src/media/local-roots.js"; +} from "openclaw/plugin-sdk/reply-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime"; +import { dispatchReplyWithBufferedBlockDispatcher } from "openclaw/plugin-sdk/reply-runtime"; +import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { resolveInboundLastRouteSessionKey, type resolveAgentRoute, -} from "../../../../../src/routing/resolve-route.js"; +} from "openclaw/plugin-sdk/routing"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import type { getChildLogger } from "openclaw/plugin-sdk/runtime-env"; import { readStoreAllowFromForDmPolicy, resolvePinnedMainDmOwnerFromAllowlist, resolveDmGroupAccessWithCommandGate, -} from "../../../../../src/security/dm-policy-shared.js"; -import { jidToE164, normalizeE164 } from "../../../../../src/utils.js"; +} from "openclaw/plugin-sdk/security-runtime"; +import { jidToE164, normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import { resolveWhatsAppAccount } from "../../accounts.js"; import { newConnectionId } from "../../reconnect.js"; import { formatError } from "../../session.js"; diff --git a/extensions/whatsapp/src/auto-reply/session-snapshot.ts b/extensions/whatsapp/src/auto-reply/session-snapshot.ts index 53b7e3ae615..ff4899d0d52 100644 --- a/extensions/whatsapp/src/auto-reply/session-snapshot.ts +++ b/extensions/whatsapp/src/auto-reply/session-snapshot.ts @@ -1,4 +1,4 @@ -import type { loadConfig } from "../../../../src/config/config.js"; +import type { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { evaluateSessionFreshness, loadSessionStore, @@ -8,8 +8,8 @@ import { resolveSessionResetType, resolveSessionKey, resolveStorePath, -} from "../../../../src/config/sessions.js"; -import { normalizeMainKey } from "../../../../src/routing/session-key.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { normalizeMainKey } from "openclaw/plugin-sdk/routing"; export function getSessionSnapshot( cfg: ReturnType, diff --git a/extensions/whatsapp/src/channel.setup.ts b/extensions/whatsapp/src/channel.setup.ts index 919a75c1a8c..6cf2a75d1ce 100644 --- a/extensions/whatsapp/src/channel.setup.ts +++ b/extensions/whatsapp/src/channel.setup.ts @@ -1,21 +1,150 @@ -import { type ChannelPlugin } from "openclaw/plugin-sdk/whatsapp"; -import { type ResolvedWhatsAppAccount } from "./accounts.js"; +import { + buildAccountScopedDmSecurityPolicy, + buildChannelConfigSchema, + collectAllowlistProviderGroupPolicyWarnings, + collectOpenGroupPolicyRouteAllowlistWarnings, + DEFAULT_ACCOUNT_ID, + formatWhatsAppConfigAllowFromEntries, + getChatChannelMeta, + normalizeE164, + resolveWhatsAppConfigAllowFrom, + resolveWhatsAppConfigDefaultTo, + resolveWhatsAppGroupIntroHint, + resolveWhatsAppGroupRequireMention, + resolveWhatsAppGroupToolPolicy, + WhatsAppConfigSchema, + type ChannelPlugin, +} from "openclaw/plugin-sdk/whatsapp"; +import { + listWhatsAppAccountIds, + resolveDefaultWhatsAppAccountId, + resolveWhatsAppAccount, + type ResolvedWhatsAppAccount, +} from "./accounts.js"; import { webAuthExists } from "./auth-store.js"; +import { whatsappSetupWizardProxy } from "./plugin-shared.js"; import { whatsappSetupAdapter } from "./setup-core.js"; -import { createWhatsAppPluginBase, createWhatsAppSetupWizardProxy } from "./shared.js"; - -async function loadWhatsAppChannelRuntime() { - return await import("./channel.runtime.js"); -} - -const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => ({ - whatsappSetupWizard: (await loadWhatsAppChannelRuntime()).whatsappSetupWizard, -})); export const whatsappSetupPlugin: ChannelPlugin = { - ...createWhatsAppPluginBase({ - setupWizard: whatsappSetupWizardProxy, - setup: whatsappSetupAdapter, + id: "whatsapp", + meta: { + ...getChatChannelMeta("whatsapp"), + showConfigured: false, + quickstartAllowFrom: true, + forceAccountBinding: true, + preferSessionLookupForAnnounceTarget: true, + }, + setupWizard: whatsappSetupWizardProxy, + capabilities: { + chatTypes: ["direct", "group"], + polls: true, + reactions: true, + media: true, + }, + reload: { configPrefixes: ["web"], noopPrefixes: ["channels.whatsapp"] }, + gatewayMethods: ["web.login.start", "web.login.wait"], + configSchema: buildChannelConfigSchema(WhatsAppConfigSchema), + config: { + listAccountIds: (cfg) => listWhatsAppAccountIds(cfg), + resolveAccount: (cfg, accountId) => resolveWhatsAppAccount({ cfg, accountId }), + defaultAccountId: (cfg) => resolveDefaultWhatsAppAccountId(cfg), + setAccountEnabled: ({ cfg, accountId, enabled }) => { + const accountKey = accountId || DEFAULT_ACCOUNT_ID; + const accounts = { ...cfg.channels?.whatsapp?.accounts }; + const existing = accounts[accountKey] ?? {}; + return { + ...cfg, + channels: { + ...cfg.channels, + whatsapp: { + ...cfg.channels?.whatsapp, + accounts: { + ...accounts, + [accountKey]: { + ...existing, + enabled, + }, + }, + }, + }, + }; + }, + deleteAccount: ({ cfg, accountId }) => { + const accountKey = accountId || DEFAULT_ACCOUNT_ID; + const accounts = { ...cfg.channels?.whatsapp?.accounts }; + delete accounts[accountKey]; + return { + ...cfg, + channels: { + ...cfg.channels, + whatsapp: { + ...cfg.channels?.whatsapp, + accounts: Object.keys(accounts).length ? accounts : undefined, + }, + }, + }; + }, + isEnabled: (account, cfg) => account.enabled && cfg.web?.enabled !== false, + disabledReason: () => "disabled", isConfigured: async (account) => await webAuthExists(account.authDir), - }), + unconfiguredReason: () => "not linked", + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: Boolean(account.authDir), + linked: Boolean(account.authDir), + dmPolicy: account.dmPolicy, + allowFrom: account.allowFrom, + }), + resolveAllowFrom: ({ cfg, accountId }) => resolveWhatsAppConfigAllowFrom({ cfg, accountId }), + formatAllowFrom: ({ allowFrom }) => formatWhatsAppConfigAllowFromEntries(allowFrom), + resolveDefaultTo: ({ cfg, accountId }) => resolveWhatsAppConfigDefaultTo({ cfg, accountId }), + }, + security: { + resolveDmPolicy: ({ cfg, accountId, account }) => + buildAccountScopedDmSecurityPolicy({ + cfg, + channelKey: "whatsapp", + accountId, + fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID, + policy: account.dmPolicy, + allowFrom: account.allowFrom ?? [], + policyPathSuffix: "dmPolicy", + normalizeEntry: (raw) => normalizeE164(raw), + }), + collectWarnings: ({ account, cfg }) => { + const groupAllowlistConfigured = + Boolean(account.groups) && Object.keys(account.groups ?? {}).length > 0; + return collectAllowlistProviderGroupPolicyWarnings({ + cfg, + providerConfigPresent: cfg.channels?.whatsapp !== undefined, + configuredGroupPolicy: account.groupPolicy, + collect: (groupPolicy) => + collectOpenGroupPolicyRouteAllowlistWarnings({ + groupPolicy, + routeAllowlistConfigured: groupAllowlistConfigured, + restrictSenders: { + surface: "WhatsApp groups", + openScope: "any member in allowed groups", + groupPolicyPath: "channels.whatsapp.groupPolicy", + groupAllowFromPath: "channels.whatsapp.groupAllowFrom", + }, + noRouteAllowlist: { + surface: "WhatsApp groups", + routeAllowlistPath: "channels.whatsapp.groups", + routeScope: "group", + groupPolicyPath: "channels.whatsapp.groupPolicy", + groupAllowFromPath: "channels.whatsapp.groupAllowFrom", + }, + }), + }); + }, + }, + setup: whatsappSetupAdapter, + groups: { + resolveRequireMention: resolveWhatsAppGroupRequireMention, + resolveToolPolicy: resolveWhatsAppGroupToolPolicy, + resolveGroupIntroHint: resolveWhatsAppGroupIntroHint, + }, }; diff --git a/extensions/whatsapp/src/channel.ts b/extensions/whatsapp/src/channel.ts index 6fe1663e55f..4701c80070b 100644 --- a/extensions/whatsapp/src/channel.ts +++ b/extensions/whatsapp/src/channel.ts @@ -1,34 +1,45 @@ -import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/compat"; +import { buildAccountScopedAllowlistConfigEditor } from "openclaw/plugin-sdk/allowlist-config-edit"; import { + buildAccountScopedDmSecurityPolicy, + buildChannelConfigSchema, + collectAllowlistProviderGroupPolicyWarnings, + collectOpenGroupPolicyRouteAllowlistWarnings, createActionGate, createWhatsAppOutboundBase, DEFAULT_ACCOUNT_ID, + getChatChannelMeta, listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig, + normalizeE164, formatWhatsAppConfigAllowFromEntries, readStringParam, resolveWhatsAppOutboundTarget, + resolveWhatsAppConfigAllowFrom, + resolveWhatsAppConfigDefaultTo, + resolveWhatsAppGroupRequireMention, + resolveWhatsAppGroupIntroHint, + resolveWhatsAppGroupToolPolicy, resolveWhatsAppHeartbeatRecipients, resolveWhatsAppMentionStripRegexes, + WhatsAppConfigSchema, type ChannelMessageActionName, type ChannelPlugin, } from "openclaw/plugin-sdk/whatsapp"; -import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../../../src/whatsapp/normalize.js"; +import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "openclaw/plugin-sdk/whatsapp"; // WhatsApp-specific imports from local extension code (moved from src/web/ and src/channels/plugins/) -import { resolveWhatsAppAccount, type ResolvedWhatsAppAccount } from "./accounts.js"; +import { + listWhatsAppAccountIds, + resolveDefaultWhatsAppAccountId, + resolveWhatsAppAccount, + 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 { - createWhatsAppPluginBase, - createWhatsAppSetupWizardProxy, - WHATSAPP_CHANNEL, -} from "./shared.js"; import { collectWhatsAppStatusIssues } from "./status-issues.js"; -async function loadWhatsAppChannelRuntime() { - return await import("./channel.runtime.js"); -} +const meta = getChatChannelMeta("whatsapp"); function normalizeWhatsAppPayloadText(text: string | undefined): string { return (text ?? "").replace(/^(?:[ \t]*\r?\n)+/, ""); @@ -45,21 +56,87 @@ function parseWhatsAppExplicitTarget(raw: string) { }; } -const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => ({ - whatsappSetupWizard: (await loadWhatsAppChannelRuntime()).whatsappSetupWizard, -})); - export const whatsappPlugin: ChannelPlugin = { - ...createWhatsAppPluginBase({ - setupWizard: whatsappSetupWizardProxy, - setup: whatsappSetupAdapter, - isConfigured: async (account) => - await getWhatsAppRuntime().channel.whatsapp.webAuthExists(account.authDir), - }), + id: "whatsapp", + meta: { + ...meta, + showConfigured: false, + quickstartAllowFrom: true, + forceAccountBinding: true, + preferSessionLookupForAnnounceTarget: true, + }, + setupWizard: whatsappSetupWizardProxy, agentTools: () => [getWhatsAppRuntime().channel.whatsapp.createLoginTool()], pairing: { idLabel: "whatsappSenderId", }, + capabilities: { + chatTypes: ["direct", "group"], + polls: true, + reactions: true, + media: true, + }, + reload: { configPrefixes: ["web"], noopPrefixes: ["channels.whatsapp"] }, + gatewayMethods: ["web.login.start", "web.login.wait"], + configSchema: buildChannelConfigSchema(WhatsAppConfigSchema), + config: { + listAccountIds: (cfg) => listWhatsAppAccountIds(cfg), + resolveAccount: (cfg, accountId) => resolveWhatsAppAccount({ cfg, accountId }), + defaultAccountId: (cfg) => resolveDefaultWhatsAppAccountId(cfg), + setAccountEnabled: ({ cfg, accountId, enabled }) => { + const accountKey = accountId || DEFAULT_ACCOUNT_ID; + const accounts = { ...cfg.channels?.whatsapp?.accounts }; + const existing = accounts[accountKey] ?? {}; + return { + ...cfg, + channels: { + ...cfg.channels, + whatsapp: { + ...cfg.channels?.whatsapp, + accounts: { + ...accounts, + [accountKey]: { + ...existing, + enabled, + }, + }, + }, + }, + }; + }, + deleteAccount: ({ cfg, accountId }) => { + const accountKey = accountId || DEFAULT_ACCOUNT_ID; + const accounts = { ...cfg.channels?.whatsapp?.accounts }; + delete accounts[accountKey]; + return { + ...cfg, + channels: { + ...cfg.channels, + whatsapp: { + ...cfg.channels?.whatsapp, + accounts: Object.keys(accounts).length ? accounts : undefined, + }, + }, + }; + }, + isEnabled: (account, cfg) => account.enabled && cfg.web?.enabled !== false, + disabledReason: () => "disabled", + isConfigured: async (account) => + await getWhatsAppRuntime().channel.whatsapp.webAuthExists(account.authDir), + unconfiguredReason: () => "not linked", + describeAccount: (account) => ({ + accountId: account.accountId, + name: account.name, + enabled: account.enabled, + configured: Boolean(account.authDir), + linked: Boolean(account.authDir), + dmPolicy: account.dmPolicy, + allowFrom: account.allowFrom, + }), + resolveAllowFrom: ({ cfg, accountId }) => resolveWhatsAppConfigAllowFrom({ cfg, accountId }), + formatAllowFrom: ({ allowFrom }) => formatWhatsAppConfigAllowFromEntries(allowFrom), + resolveDefaultTo: ({ cfg, accountId }) => resolveWhatsAppConfigDefaultTo({ cfg, accountId }), + }, allowlist: { supportsScope: ({ scope }) => scope === "dm" || scope === "group" || scope === "all", readConfig: ({ cfg, accountId }) => { @@ -80,6 +157,53 @@ export const whatsappPlugin: ChannelPlugin = { }), }), }, + security: { + resolveDmPolicy: ({ cfg, accountId, account }) => { + return buildAccountScopedDmSecurityPolicy({ + cfg, + channelKey: "whatsapp", + accountId, + fallbackAccountId: account.accountId ?? DEFAULT_ACCOUNT_ID, + policy: account.dmPolicy, + allowFrom: account.allowFrom ?? [], + policyPathSuffix: "dmPolicy", + normalizeEntry: (raw) => normalizeE164(raw), + }); + }, + collectWarnings: ({ account, cfg }) => { + const groupAllowlistConfigured = + Boolean(account.groups) && Object.keys(account.groups ?? {}).length > 0; + return collectAllowlistProviderGroupPolicyWarnings({ + cfg, + providerConfigPresent: cfg.channels?.whatsapp !== undefined, + configuredGroupPolicy: account.groupPolicy, + collect: (groupPolicy) => + collectOpenGroupPolicyRouteAllowlistWarnings({ + groupPolicy, + routeAllowlistConfigured: groupAllowlistConfigured, + restrictSenders: { + surface: "WhatsApp groups", + openScope: "any member in allowed groups", + groupPolicyPath: "channels.whatsapp.groupPolicy", + groupAllowFromPath: "channels.whatsapp.groupAllowFrom", + }, + noRouteAllowlist: { + surface: "WhatsApp groups", + routeAllowlistPath: "channels.whatsapp.groups", + routeScope: "group", + groupPolicyPath: "channels.whatsapp.groupPolicy", + groupAllowFromPath: "channels.whatsapp.groupAllowFrom", + }, + }), + }); + }, + }, + setup: whatsappSetupAdapter, + groups: { + resolveRequireMention: resolveWhatsAppGroupRequireMention, + resolveToolPolicy: resolveWhatsAppGroupToolPolicy, + resolveGroupIntroHint: resolveWhatsAppGroupIntroHint, + }, mentions: { stripRegexes: ({ ctx }) => resolveWhatsAppMentionStripRegexes(ctx), }, @@ -132,7 +256,7 @@ export const whatsappPlugin: ChannelPlugin = { supportsAction: ({ action }) => action === "react", handleAction: async ({ action, params, cfg, accountId }) => { if (action !== "react") { - throw new Error(`Action ${action} is not supported for provider ${WHATSAPP_CHANNEL}.`); + throw new Error(`Action ${action} is not supported for provider ${meta.id}.`); } const messageId = readStringParam(params, "messageId", { required: true, diff --git a/extensions/whatsapp/src/inbound/access-control.test-harness.ts b/extensions/whatsapp/src/inbound/access-control.test-harness.ts index a8bf7a9df19..495615a3cbb 100644 --- a/extensions/whatsapp/src/inbound/access-control.test-harness.ts +++ b/extensions/whatsapp/src/inbound/access-control.test-harness.ts @@ -33,15 +33,15 @@ export function setupAccessControlTestHarness(): void { }); } -vi.mock("../../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig: () => config, }; }); -vi.mock("../../../../src/pairing/pairing-store.js", () => ({ +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args), upsertChannelPairingRequest: (...args: unknown[]) => upsertPairingRequestMock(...args), })); diff --git a/extensions/whatsapp/src/inbound/access-control.ts b/extensions/whatsapp/src/inbound/access-control.ts index ee81e119392..2c57abe8bbf 100644 --- a/extensions/whatsapp/src/inbound/access-control.ts +++ b/extensions/whatsapp/src/inbound/access-control.ts @@ -1,17 +1,17 @@ -import { loadConfig } from "../../../../src/config/config.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveOpenProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce, -} from "../../../../src/config/runtime-group-policy.js"; -import { logVerbose } from "../../../../src/globals.js"; -import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js"; -import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js"; +} from "openclaw/plugin-sdk/config-runtime"; +import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime"; +import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import { readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithLists, -} from "../../../../src/security/dm-policy-shared.js"; -import { isSelfChatMode, normalizeE164 } from "../../../../src/utils.js"; +} from "openclaw/plugin-sdk/security-runtime"; +import { isSelfChatMode, normalizeE164 } from "openclaw/plugin-sdk/text-runtime"; import { resolveWhatsAppAccount } from "../accounts.js"; export type InboundAccessControlResult = { diff --git a/extensions/whatsapp/src/inbound/dedupe.ts b/extensions/whatsapp/src/inbound/dedupe.ts index 9d20a25b8c4..cfc74185519 100644 --- a/extensions/whatsapp/src/inbound/dedupe.ts +++ b/extensions/whatsapp/src/inbound/dedupe.ts @@ -1,4 +1,4 @@ -import { createDedupeCache } from "../../../../src/infra/dedupe.js"; +import { createDedupeCache } from "openclaw/plugin-sdk/infra-runtime"; const RECENT_WEB_MESSAGE_TTL_MS = 20 * 60_000; const RECENT_WEB_MESSAGE_MAX = 5000; diff --git a/extensions/whatsapp/src/inbound/extract.ts b/extensions/whatsapp/src/inbound/extract.ts index a34937c9793..9fa663847a6 100644 --- a/extensions/whatsapp/src/inbound/extract.ts +++ b/extensions/whatsapp/src/inbound/extract.ts @@ -4,9 +4,9 @@ import { getContentType, normalizeMessageContent, } from "@whiskeysockets/baileys"; -import { formatLocationText, type NormalizedLocation } from "../../../../src/channels/location.js"; -import { logVerbose } from "../../../../src/globals.js"; -import { jidToE164 } from "../../../../src/utils.js"; +import { formatLocationText, type NormalizedLocation } from "openclaw/plugin-sdk/channel-runtime"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { jidToE164 } from "openclaw/plugin-sdk/text-runtime"; import { parseVcard } from "../vcard.js"; function unwrapMessage(message: proto.IMessage | undefined): proto.IMessage | undefined { diff --git a/extensions/whatsapp/src/inbound/media.ts b/extensions/whatsapp/src/inbound/media.ts index 9f2fe70698a..128b4d945d5 100644 --- a/extensions/whatsapp/src/inbound/media.ts +++ b/extensions/whatsapp/src/inbound/media.ts @@ -1,6 +1,6 @@ import type { proto, WAMessage } from "@whiskeysockets/baileys"; import { downloadMediaMessage, normalizeMessageContent } from "@whiskeysockets/baileys"; -import { logVerbose } from "../../../../src/globals.js"; +import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { createWaSocket } from "../session.js"; function unwrapMessage(message: proto.IMessage | undefined): proto.IMessage | undefined { diff --git a/extensions/whatsapp/src/inbound/monitor.ts b/extensions/whatsapp/src/inbound/monitor.ts index 5337c5d6a43..35669bc1b49 100644 --- a/extensions/whatsapp/src/inbound/monitor.ts +++ b/extensions/whatsapp/src/inbound/monitor.ts @@ -1,13 +1,13 @@ import type { AnyMessageContent, proto, WAMessage } from "@whiskeysockets/baileys"; import { DisconnectReason, isJidGroup } from "@whiskeysockets/baileys"; -import { createInboundDebouncer } from "../../../../src/auto-reply/inbound-debounce.js"; -import { formatLocationText } from "../../../../src/channels/location.js"; -import { logVerbose, shouldLogVerbose } from "../../../../src/globals.js"; -import { recordChannelActivity } from "../../../../src/infra/channel-activity.js"; -import { getChildLogger } from "../../../../src/logging/logger.js"; -import { createSubsystemLogger } from "../../../../src/logging/subsystem.js"; -import { saveMediaBuffer } from "../../../../src/media/store.js"; -import { jidToE164, resolveJidToE164 } from "../../../../src/utils.js"; +import { formatLocationText } from "openclaw/plugin-sdk/channel-runtime"; +import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime"; +import { saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime"; +import { createInboundDebouncer } from "openclaw/plugin-sdk/reply-runtime"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/text-runtime"; +import { jidToE164, resolveJidToE164 } from "openclaw/plugin-sdk/text-runtime"; import { createWaSocket, getStatusCode, waitForWaConnection } from "../session.js"; import { checkInboundAccessControl } from "./access-control.js"; import { isRecentInboundMessage } from "./dedupe.js"; diff --git a/extensions/whatsapp/src/inbound/send-api.ts b/extensions/whatsapp/src/inbound/send-api.ts index a5619383415..bb0761431f7 100644 --- a/extensions/whatsapp/src/inbound/send-api.ts +++ b/extensions/whatsapp/src/inbound/send-api.ts @@ -1,6 +1,6 @@ import type { AnyMessageContent, WAPresence } from "@whiskeysockets/baileys"; -import { recordChannelActivity } from "../../../../src/infra/channel-activity.js"; -import { toWhatsappJid } from "../../../../src/utils.js"; +import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime"; +import { toWhatsappJid } from "openclaw/plugin-sdk/text-runtime"; import type { ActiveWebSendOptions } from "../active-listener.js"; function recordWhatsAppOutbound(accountId: string) { diff --git a/extensions/whatsapp/src/inbound/types.ts b/extensions/whatsapp/src/inbound/types.ts index c9c97810bad..42e4b5121d1 100644 --- a/extensions/whatsapp/src/inbound/types.ts +++ b/extensions/whatsapp/src/inbound/types.ts @@ -1,5 +1,5 @@ import type { AnyMessageContent } from "@whiskeysockets/baileys"; -import type { NormalizedLocation } from "../../../../src/channels/location.js"; +import type { NormalizedLocation } from "openclaw/plugin-sdk/channel-runtime"; export type WebListenerCloseReason = { status?: number; diff --git a/extensions/whatsapp/src/login-qr.ts b/extensions/whatsapp/src/login-qr.ts index 3681d646252..352cf6e86b6 100644 --- a/extensions/whatsapp/src/login-qr.ts +++ b/extensions/whatsapp/src/login-qr.ts @@ -1,9 +1,9 @@ import { randomUUID } from "node:crypto"; import { DisconnectReason } from "@whiskeysockets/baileys"; -import { loadConfig } from "../../../src/config/config.js"; -import { danger, info, success } from "../../../src/globals.js"; -import { logInfo } from "../../../src/logger.js"; -import { defaultRuntime, type RuntimeEnv } from "../../../src/runtime.js"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { danger, info, success } from "openclaw/plugin-sdk/runtime-env"; +import { defaultRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { logInfo } from "openclaw/plugin-sdk/text-runtime"; import { resolveWhatsAppAccount } from "./accounts.js"; import { renderQrPngBase64 } from "./qr-image.js"; import { diff --git a/extensions/whatsapp/src/login.ts b/extensions/whatsapp/src/login.ts index 0923a38a122..43c16e1d298 100644 --- a/extensions/whatsapp/src/login.ts +++ b/extensions/whatsapp/src/login.ts @@ -1,9 +1,9 @@ import { DisconnectReason } from "@whiskeysockets/baileys"; -import { formatCliCommand } from "../../../src/cli/command-format.js"; -import { loadConfig } from "../../../src/config/config.js"; -import { danger, info, success } from "../../../src/globals.js"; -import { logInfo } from "../../../src/logger.js"; -import { defaultRuntime, type RuntimeEnv } from "../../../src/runtime.js"; +import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; +import { loadConfig } from "openclaw/plugin-sdk/config-runtime"; +import { danger, info, success } from "openclaw/plugin-sdk/runtime-env"; +import { defaultRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; +import { logInfo } from "openclaw/plugin-sdk/text-runtime"; import { resolveWhatsAppAccount } from "./accounts.js"; import { createWaSocket, diff --git a/extensions/whatsapp/src/media.ts b/extensions/whatsapp/src/media.ts index 2b297ef8907..33339451ec8 100644 --- a/extensions/whatsapp/src/media.ts +++ b/extensions/whatsapp/src/media.ts @@ -1,20 +1,20 @@ import fs from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; -import { logVerbose, shouldLogVerbose } from "../../../src/globals.js"; -import { SafeOpenError, readLocalFileSafely } from "../../../src/infra/fs-safe.js"; -import type { SsrFPolicy } from "../../../src/infra/net/ssrf.js"; -import { type MediaKind, maxBytesForKind } from "../../../src/media/constants.js"; -import { fetchRemoteMedia } from "../../../src/media/fetch.js"; +import { SafeOpenError, readLocalFileSafely } from "openclaw/plugin-sdk/infra-runtime"; +import type { SsrFPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import { type MediaKind, maxBytesForKind } from "openclaw/plugin-sdk/media-runtime"; +import { fetchRemoteMedia } from "openclaw/plugin-sdk/media-runtime"; import { convertHeicToJpeg, hasAlphaChannel, optimizeImageToPng, resizeToJpeg, -} from "../../../src/media/image-ops.js"; -import { getDefaultMediaLocalRoots } from "../../../src/media/local-roots.js"; -import { detectMime, extensionForMime, kindFromMime } from "../../../src/media/mime.js"; -import { resolveUserPath } from "../../../src/utils.js"; +} from "openclaw/plugin-sdk/media-runtime"; +import { getDefaultMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +import { detectMime, extensionForMime, kindFromMime } from "openclaw/plugin-sdk/media-runtime"; +import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { resolveUserPath } from "openclaw/plugin-sdk/text-runtime"; export type WebMediaResult = { buffer: Buffer; diff --git a/extensions/whatsapp/src/monitor-inbox.test-harness.ts b/extensions/whatsapp/src/monitor-inbox.test-harness.ts index 43bc731c459..3aefaf7a4f1 100644 --- a/extensions/whatsapp/src/monitor-inbox.test-harness.ts +++ b/extensions/whatsapp/src/monitor-inbox.test-harness.ts @@ -2,8 +2,8 @@ import { EventEmitter } from "node:events"; import fsSync from "node:fs"; import os from "node:os"; import path from "node:path"; +import { resetLogger, setLoggerOverride } from "openclaw/plugin-sdk/runtime-env"; import { afterEach, beforeEach, expect, vi } from "vitest"; -import { resetLogger, setLoggerOverride } from "../../../src/logging.js"; // Avoid exporting vitest mock types (TS2742 under pnpm + d.ts emit). // oxlint-disable-next-line typescript/no-explicit-any @@ -81,8 +81,8 @@ function getPairingStoreMocks() { const sock: MockSock = createMockSock(); -vi.mock("../../../src/media/store.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/media-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, saveMediaBuffer: vi.fn().mockResolvedValue({ @@ -94,15 +94,15 @@ vi.mock("../../../src/media/store.js", async (importOriginal) => { }; }); -vi.mock("../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig: () => mockLoadConfig(), }; }); -vi.mock("../../../src/pairing/pairing-store.js", () => getPairingStoreMocks()); +vi.mock("openclaw/plugin-sdk/conversation-runtime", () => getPairingStoreMocks()); vi.mock("./session.js", () => ({ createWaSocket: vi.fn().mockResolvedValue(sock), diff --git a/extensions/whatsapp/src/normalize.ts b/extensions/whatsapp/src/normalize.ts index 82ee5d8296d..bfecb31e4a5 100644 --- a/extensions/whatsapp/src/normalize.ts +++ b/extensions/whatsapp/src/normalize.ts @@ -2,4 +2,4 @@ export { looksLikeWhatsAppTargetId, normalizeWhatsAppAllowFromEntries, normalizeWhatsAppMessagingTarget, -} from "../../../src/channels/plugins/normalize/whatsapp.js"; +} from "openclaw/plugin-sdk/channel-runtime"; diff --git a/extensions/whatsapp/src/outbound-adapter.ts b/extensions/whatsapp/src/outbound-adapter.ts index ba84e336d0e..0cd0290e913 100644 --- a/extensions/whatsapp/src/outbound-adapter.ts +++ b/extensions/whatsapp/src/outbound-adapter.ts @@ -1,9 +1,9 @@ -import { chunkText } from "../../../src/auto-reply/chunk.js"; -import { sendTextMediaPayload } from "../../../src/channels/plugins/outbound/direct-text-media.js"; -import type { ChannelOutboundAdapter } from "../../../src/channels/plugins/types.js"; -import { shouldLogVerbose } from "../../../src/globals.js"; -import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js"; -import { resolveWhatsAppOutboundTarget } from "../../../src/whatsapp/resolve-outbound-target.js"; +import { sendTextMediaPayload } from "openclaw/plugin-sdk/channel-runtime"; +import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-runtime"; +import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; +import { chunkText } from "openclaw/plugin-sdk/reply-runtime"; +import { shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; +import { resolveWhatsAppOutboundTarget } from "openclaw/plugin-sdk/whatsapp"; import { sendMessageWhatsApp, sendPollWhatsApp } from "./send.js"; function trimLeadingWhitespace(text: string | undefined): string { diff --git a/extensions/whatsapp/src/plugin-shared.ts b/extensions/whatsapp/src/plugin-shared.ts index 1ab5d80220c..96a5f86e6f9 100644 --- a/extensions/whatsapp/src/plugin-shared.ts +++ b/extensions/whatsapp/src/plugin-shared.ts @@ -1,4 +1,4 @@ -import { type ChannelPlugin } from "../../../src/plugin-sdk-internal/whatsapp.js"; +import type { ChannelPlugin } from "openclaw/plugin-sdk/whatsapp"; import { type ResolvedWhatsAppAccount } from "./accounts.js"; async function loadWhatsAppChannelRuntime() { diff --git a/extensions/whatsapp/src/qr-image.ts b/extensions/whatsapp/src/qr-image.ts index d4d8b9c7b2f..be6b10f5b0e 100644 --- a/extensions/whatsapp/src/qr-image.ts +++ b/extensions/whatsapp/src/qr-image.ts @@ -1,6 +1,6 @@ +import { encodePngRgba, fillPixel } from "openclaw/plugin-sdk/media-runtime"; import QRCodeModule from "qrcode-terminal/vendor/QRCode/index.js"; import QRErrorCorrectLevelModule from "qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js"; -import { encodePngRgba, fillPixel } from "../../../src/media/png-encode.js"; type QRCodeConstructor = new ( typeNumber: number, diff --git a/extensions/whatsapp/src/reconnect.ts b/extensions/whatsapp/src/reconnect.ts index d99ddf98ad6..e5e34888cef 100644 --- a/extensions/whatsapp/src/reconnect.ts +++ b/extensions/whatsapp/src/reconnect.ts @@ -1,8 +1,8 @@ import { randomUUID } from "node:crypto"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { BackoffPolicy } from "../../../src/infra/backoff.js"; -import { computeBackoff, sleepWithAbort } from "../../../src/infra/backoff.js"; -import { clamp } from "../../../src/utils.js"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import type { BackoffPolicy } from "openclaw/plugin-sdk/infra-runtime"; +import { computeBackoff, sleepWithAbort } from "openclaw/plugin-sdk/infra-runtime"; +import { clamp } from "openclaw/plugin-sdk/text-runtime"; export type ReconnectPolicy = BackoffPolicy & { maxAttempts: number; diff --git a/extensions/whatsapp/src/runtime.ts b/extensions/whatsapp/src/runtime.ts index e103cc878f0..8fc8b9e7ed9 100644 --- a/extensions/whatsapp/src/runtime.ts +++ b/extensions/whatsapp/src/runtime.ts @@ -1,7 +1,5 @@ -import { - createPluginRuntimeStore, - type PluginRuntime, -} from "../../../src/plugin-sdk-internal/core.js"; +import type { PluginRuntime } from "openclaw/plugin-sdk/core"; +import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; const { setRuntime: setWhatsAppRuntime, getRuntime: getWhatsAppRuntime } = createPluginRuntimeStore("WhatsApp runtime not initialized"); diff --git a/extensions/whatsapp/src/send.ts b/extensions/whatsapp/src/send.ts index 4ac9c03faf4..c59c5dd2008 100644 --- a/extensions/whatsapp/src/send.ts +++ b/extensions/whatsapp/src/send.ts @@ -1,13 +1,13 @@ -import { loadConfig, type OpenClawConfig } from "../../../src/config/config.js"; -import { resolveMarkdownTableMode } from "../../../src/config/markdown-tables.js"; -import { generateSecureUuid } from "../../../src/infra/secure-random.js"; -import { getChildLogger } from "../../../src/logging/logger.js"; -import { redactIdentifier } from "../../../src/logging/redact-identifier.js"; -import { createSubsystemLogger } from "../../../src/logging/subsystem.js"; -import { convertMarkdownTables } from "../../../src/markdown/tables.js"; -import { markdownToWhatsApp } from "../../../src/markdown/whatsapp.js"; -import { normalizePollInput, type PollInput } from "../../../src/polls.js"; -import { toWhatsappJid } from "../../../src/utils.js"; +import { loadConfig, type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime"; +import { generateSecureUuid } from "openclaw/plugin-sdk/infra-runtime"; +import { normalizePollInput, type PollInput } from "openclaw/plugin-sdk/media-runtime"; +import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger } from "openclaw/plugin-sdk/text-runtime"; +import { redactIdentifier } from "openclaw/plugin-sdk/text-runtime"; +import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime"; +import { markdownToWhatsApp } from "openclaw/plugin-sdk/text-runtime"; +import { toWhatsappJid } from "openclaw/plugin-sdk/text-runtime"; import { resolveWhatsAppAccount, resolveWhatsAppMediaMaxBytes } from "./accounts.js"; import { type ActiveWebSendOptions, requireActiveWebListener } from "./active-listener.js"; import { loadWebMedia } from "./media.js"; diff --git a/extensions/whatsapp/src/session.ts b/extensions/whatsapp/src/session.ts index 8fc7f9fd1fc..80690b110eb 100644 --- a/extensions/whatsapp/src/session.ts +++ b/extensions/whatsapp/src/session.ts @@ -7,12 +7,12 @@ import { makeWASocket, useMultiFileAuthState, } from "@whiskeysockets/baileys"; +import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; +import { VERSION } from "openclaw/plugin-sdk/cli-runtime"; +import { danger, success } from "openclaw/plugin-sdk/runtime-env"; +import { getChildLogger, toPinoLikeLogger } from "openclaw/plugin-sdk/runtime-env"; +import { ensureDir, resolveUserPath } from "openclaw/plugin-sdk/text-runtime"; import qrcode from "qrcode-terminal"; -import { formatCliCommand } from "../../../src/cli/command-format.js"; -import { danger, success } from "../../../src/globals.js"; -import { getChildLogger, toPinoLikeLogger } from "../../../src/logging.js"; -import { ensureDir, resolveUserPath } from "../../../src/utils.js"; -import { VERSION } from "../../../src/version.js"; import { maybeRestoreCredsFromBackup, readCredsJsonRaw, diff --git a/extensions/whatsapp/src/setup-core.ts b/extensions/whatsapp/src/setup-core.ts index 346c9aa0e8d..e7a11eedbf6 100644 --- a/extensions/whatsapp/src/setup-core.ts +++ b/extensions/whatsapp/src/setup-core.ts @@ -1,12 +1,52 @@ -import { createPatchedAccountSetupAdapter } from "../../../src/channels/plugins/setup-helpers.js"; -import type { ChannelSetupAdapter } from "../../../src/plugin-sdk-internal/setup.js"; +import { + applyAccountNameToChannelSection, + type ChannelSetupAdapter, + migrateBaseNameToDefaultAccount, + normalizeAccountId, +} from "openclaw/plugin-sdk/setup"; const channel = "whatsapp" as const; -export const whatsappSetupAdapter: ChannelSetupAdapter = createPatchedAccountSetupAdapter({ - channelKey: channel, - alwaysUseAccounts: true, - buildPatch: (input) => ({ - ...(input.authDir ? { authDir: input.authDir } : {}), - }), -}); +export const whatsappSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + alwaysUseAccounts: true, + }), + applyAccountConfig: ({ cfg, accountId, input }) => { + const namedConfig = applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name: input.name, + alwaysUseAccounts: true, + }); + const next = migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + alwaysUseAccounts: true, + }); + const entry = { + ...next.channels?.whatsapp?.accounts?.[accountId], + ...(input.authDir ? { authDir: input.authDir } : {}), + enabled: true, + }; + return { + ...next, + channels: { + ...next.channels, + whatsapp: { + ...next.channels?.whatsapp, + accounts: { + ...next.channels?.whatsapp?.accounts, + [accountId]: entry, + }, + }, + }, + }; + }, +}; diff --git a/extensions/whatsapp/src/setup-surface.ts b/extensions/whatsapp/src/setup-surface.ts index 47e84de6860..bb87fc5b962 100644 --- a/extensions/whatsapp/src/setup-surface.ts +++ b/extensions/whatsapp/src/setup-surface.ts @@ -9,10 +9,10 @@ import { pathExists, splitSetupEntries, setSetupChannelEnabled, - type DmPolicy, type OpenClawConfig, -} from "../../../src/plugin-sdk-internal/setup.js"; -import type { ChannelSetupWizard } from "../../../src/plugin-sdk-internal/setup.js"; +} from "openclaw/plugin-sdk/setup"; +import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup"; +import { type DmPolicy } from "openclaw/plugin-sdk/whatsapp"; import { listWhatsAppAccountIds, resolveWhatsAppAuthDir } from "./accounts.js"; import { loginWeb } from "./login.js"; import { whatsappSetupAdapter } from "./setup-core.js"; diff --git a/extensions/whatsapp/src/status-issues.ts b/extensions/whatsapp/src/status-issues.ts index bddd6dd7d9d..f369ba29cda 100644 --- a/extensions/whatsapp/src/status-issues.ts +++ b/extensions/whatsapp/src/status-issues.ts @@ -2,12 +2,12 @@ import { asString, collectIssuesForEnabledAccounts, isRecord, -} from "../../../src/channels/plugins/status-issues/shared.js"; +} from "openclaw/plugin-sdk/channel-runtime"; import type { ChannelAccountSnapshot, ChannelStatusIssue, -} from "../../../src/channels/plugins/types.js"; -import { formatCliCommand } from "../../../src/cli/command-format.js"; +} from "openclaw/plugin-sdk/channel-runtime"; +import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime"; type WhatsAppAccountStatus = { accountId?: unknown; diff --git a/extensions/whatsapp/src/test-helpers.ts b/extensions/whatsapp/src/test-helpers.ts index b3289164463..bb2cd3d6fa0 100644 --- a/extensions/whatsapp/src/test-helpers.ts +++ b/extensions/whatsapp/src/test-helpers.ts @@ -30,8 +30,8 @@ export function resetLoadConfigMock() { (globalThis as Record)[CONFIG_KEY] = () => DEFAULT_CONFIG; } -vi.mock("../../../src/config/config.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadConfig: () => { @@ -51,7 +51,7 @@ vi.mock("../../config/config.js", async (importOriginal) => { // `../../config/config.js` is correct for modules under `src/web/auto-reply/*`. // For typing in this file (which lives in `src/web/*`), refer to the same module // via the local relative path. - const actual = await importOriginal(); + const actual = await importOriginal(); return { ...actual, loadConfig: () => { @@ -64,8 +64,8 @@ vi.mock("../../config/config.js", async (importOriginal) => { }; }); -vi.mock("../../../src/media/store.js", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("openclaw/plugin-sdk/media-runtime", async (importOriginal) => { + const actual = await importOriginal(); const mockModule = Object.create(null) as Record; Object.defineProperties(mockModule, Object.getOwnPropertyDescriptors(actual)); Object.defineProperty(mockModule, "saveMediaBuffer", { diff --git a/extensions/xai/index.ts b/extensions/xai/index.ts index b5f6830fd2e..7771575795a 100644 --- a/extensions/xai/index.ts +++ b/extensions/xai/index.ts @@ -1,12 +1,11 @@ -import { normalizeProviderId } from "../../src/agents/provider-id.js"; +import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { normalizeProviderId } from "openclaw/plugin-sdk/provider-models"; import { createPluginBackedWebSearchProvider, getScopedCredentialValue, setScopedCredentialValue, -} from "../../src/agents/tools/web-search-plugin-factory.js"; -import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; -import type { OpenClawPluginApi } from "../../src/plugins/types.js"; +} from "openclaw/plugin-sdk/provider-web-search"; import { applyXaiConfig, XAI_DEFAULT_MODEL_REF } from "./onboard.js"; const PROVIDER_ID = "xai"; diff --git a/extensions/xai/onboard.ts b/extensions/xai/onboard.ts index ee5cfbc92cf..6abc7477e6c 100644 --- a/extensions/xai/onboard.ts +++ b/extensions/xai/onboard.ts @@ -1,16 +1,15 @@ -import { - applyAgentDefaultModelPrimary, - applyProviderConfigWithDefaultModel, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; import { buildXaiModelDefinition, XAI_BASE_URL, XAI_DEFAULT_MODEL_ID, - XAI_DEFAULT_MODEL_REF, -} from "./model-definitions.js"; +} from "openclaw/plugin-sdk/provider-models"; +import { + applyAgentDefaultModelPrimary, + applyProviderConfigWithDefaultModel, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; -export { XAI_DEFAULT_MODEL_REF }; +export const XAI_DEFAULT_MODEL_REF = `xai/${XAI_DEFAULT_MODEL_ID}`; export function applyXaiProviderConfig(cfg: OpenClawConfig): OpenClawConfig { const models = { ...cfg.agents?.defaults?.models }; diff --git a/extensions/xiaomi/index.ts b/extensions/xiaomi/index.ts index 33eb6e47bf9..1badf6e2d9d 100644 --- a/extensions/xiaomi/index.ts +++ b/extensions/xiaomi/index.ts @@ -1,6 +1,6 @@ import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core"; -import { PROVIDER_LABELS } from "../../src/infra/provider-usage.shared.js"; -import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js"; +import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth"; +import { PROVIDER_LABELS } from "openclaw/plugin-sdk/provider-usage"; import { applyXiaomiConfig, XIAOMI_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildSingleProviderApiKeyCatalog } from "../../src/plugins/provider-catalog.js"; import { buildXiaomiProvider } from "./provider-catalog.js"; diff --git a/extensions/xiaomi/onboard.ts b/extensions/xiaomi/onboard.ts index 3f3eef149c4..80d0ad1cd16 100644 --- a/extensions/xiaomi/onboard.ts +++ b/extensions/xiaomi/onboard.ts @@ -1,8 +1,8 @@ import { applyAgentDefaultModelPrimary, applyProviderConfigWithDefaultModels, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; import { buildXiaomiProvider, XIAOMI_DEFAULT_MODEL_ID } from "./provider-catalog.js"; export const XIAOMI_DEFAULT_MODEL_REF = `xiaomi/${XIAOMI_DEFAULT_MODEL_ID}`; diff --git a/extensions/xiaomi/provider-catalog.ts b/extensions/xiaomi/provider-catalog.ts index b62de84cf68..91329eeb87d 100644 --- a/extensions/xiaomi/provider-catalog.ts +++ b/extensions/xiaomi/provider-catalog.ts @@ -1,4 +1,4 @@ -import type { ModelProviderConfig } from "../../src/config/types.models.js"; +import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-models"; const XIAOMI_BASE_URL = "https://api.xiaomimimo.com/anthropic"; export const XIAOMI_DEFAULT_MODEL_ID = "mimo-v2-flash"; diff --git a/extensions/zai/detect.ts b/extensions/zai/detect.ts index 07f06a9f052..9bd1f25f50a 100644 --- a/extensions/zai/detect.ts +++ b/extensions/zai/detect.ts @@ -2,7 +2,7 @@ import { detectZaiEndpoint as detectZaiEndpointCore, type ZaiDetectedEndpoint, type ZaiEndpointId, -} from "../../src/commands/zai-endpoint-detect.js"; +} from "openclaw/plugin-sdk/zai"; type DetectZaiEndpointFn = typeof detectZaiEndpointCore; diff --git a/extensions/zai/index.ts b/extensions/zai/index.ts index 21ddc902902..0faef49c4fb 100644 --- a/extensions/zai/index.ts +++ b/extensions/zai/index.ts @@ -10,23 +10,21 @@ import { type ProviderResolveDynamicModelContext, type ProviderRuntimeModel, } from "openclaw/plugin-sdk/core"; -import { upsertAuthProfile } from "../../src/agents/auth-profiles.js"; -import { DEFAULT_CONTEXT_TOKENS } from "../../src/agents/defaults.js"; -import { normalizeModelCompat } from "../../src/agents/model-compat.js"; -import { createZaiToolStreamWrapper } from "../../src/agents/pi-embedded-runner/zai-stream-wrappers.js"; +import { resolveRequiredHomeDir } from "openclaw/plugin-sdk/infra-runtime"; import { + applyAuthProfileConfig, + buildApiKeyCredential, + ensureApiKeyFromOptionEnvOrPrompt, normalizeApiKeyInput, + normalizeOptionalSecretInput, + type SecretInput, + upsertAuthProfile, validateApiKeyInput, -} from "../../src/commands/auth-choice.api-key.js"; -import { ensureApiKeyFromOptionEnvOrPrompt } from "../../src/commands/auth-choice.apply-helpers.js"; -import { buildApiKeyCredential } from "../../src/commands/auth-credentials.js"; -import { applyAuthProfileConfig } from "../../src/commands/onboard-auth.js"; -import type { SecretInput } from "../../src/config/types.secrets.js"; -import { resolveRequiredHomeDir } from "../../src/infra/home-dir.js"; -import { fetchZaiUsage } from "../../src/infra/provider-usage.fetch.js"; -import { normalizeOptionalSecretInput } from "../../src/utils/normalize-secret-input.js"; +} from "openclaw/plugin-sdk/provider-auth"; +import { DEFAULT_CONTEXT_TOKENS, normalizeModelCompat } from "openclaw/plugin-sdk/provider-models"; +import { createZaiToolStreamWrapper } from "openclaw/plugin-sdk/provider-stream"; +import { fetchZaiUsage } from "openclaw/plugin-sdk/provider-usage"; import { detectZaiEndpoint, type ZaiEndpointId } from "./detect.js"; -import { zaiMediaUnderstandingProvider } from "./media-understanding-provider.js"; import { applyZaiConfig, applyZaiProviderConfig, ZAI_DEFAULT_MODEL_REF } from "./onboard.js"; const PROVIDER_ID = "zai"; @@ -335,7 +333,6 @@ const zaiPlugin = { fetchUsageSnapshot: async (ctx) => await fetchZaiUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn), isCacheTtlEligible: () => true, }); - api.registerMediaUnderstandingProvider(zaiMediaUnderstandingProvider); }, }; diff --git a/extensions/zai/onboard.ts b/extensions/zai/onboard.ts index a440387cf7b..f293e0f7632 100644 --- a/extensions/zai/onboard.ts +++ b/extensions/zai/onboard.ts @@ -1,16 +1,15 @@ -import { - applyAgentDefaultModelPrimary, - applyProviderConfigWithModelCatalog, -} from "../../src/commands/onboard-auth.config-shared.js"; -import type { OpenClawConfig } from "../../src/config/config.js"; import { buildZaiModelDefinition, resolveZaiBaseUrl, ZAI_DEFAULT_MODEL_ID, - ZAI_DEFAULT_MODEL_REF, -} from "./model-definitions.js"; +} from "openclaw/plugin-sdk/provider-models"; +import { + applyAgentDefaultModelPrimary, + applyProviderConfigWithModelCatalog, + type OpenClawConfig, +} from "openclaw/plugin-sdk/provider-onboard"; -export { ZAI_DEFAULT_MODEL_REF }; +export const ZAI_DEFAULT_MODEL_REF = `zai/${ZAI_DEFAULT_MODEL_ID}`; const ZAI_DEFAULT_MODELS = [ buildZaiModelDefinition({ id: "glm-5" }), diff --git a/package.json b/package.json index 95763eb8a0f..456603ea22c 100644 --- a/package.json +++ b/package.json @@ -70,10 +70,82 @@ "types": "./dist/plugin-sdk/routing.d.ts", "default": "./dist/plugin-sdk/routing.js" }, + "./plugin-sdk/runtime": { + "types": "./dist/plugin-sdk/runtime.d.ts", + "default": "./dist/plugin-sdk/runtime.js" + }, + "./plugin-sdk/runtime-env": { + "types": "./dist/plugin-sdk/runtime-env.d.ts", + "default": "./dist/plugin-sdk/runtime-env.js" + }, "./plugin-sdk/setup": { "types": "./dist/plugin-sdk/setup.d.ts", "default": "./dist/plugin-sdk/setup.js" }, + "./plugin-sdk/config-runtime": { + "types": "./dist/plugin-sdk/config-runtime.d.ts", + "default": "./dist/plugin-sdk/config-runtime.js" + }, + "./plugin-sdk/reply-runtime": { + "types": "./dist/plugin-sdk/reply-runtime.d.ts", + "default": "./dist/plugin-sdk/reply-runtime.js" + }, + "./plugin-sdk/channel-runtime": { + "types": "./dist/plugin-sdk/channel-runtime.d.ts", + "default": "./dist/plugin-sdk/channel-runtime.js" + }, + "./plugin-sdk/infra-runtime": { + "types": "./dist/plugin-sdk/infra-runtime.d.ts", + "default": "./dist/plugin-sdk/infra-runtime.js" + }, + "./plugin-sdk/media-runtime": { + "types": "./dist/plugin-sdk/media-runtime.d.ts", + "default": "./dist/plugin-sdk/media-runtime.js" + }, + "./plugin-sdk/conversation-runtime": { + "types": "./dist/plugin-sdk/conversation-runtime.d.ts", + "default": "./dist/plugin-sdk/conversation-runtime.js" + }, + "./plugin-sdk/text-runtime": { + "types": "./dist/plugin-sdk/text-runtime.d.ts", + "default": "./dist/plugin-sdk/text-runtime.js" + }, + "./plugin-sdk/agent-runtime": { + "types": "./dist/plugin-sdk/agent-runtime.d.ts", + "default": "./dist/plugin-sdk/agent-runtime.js" + }, + "./plugin-sdk/plugin-runtime": { + "types": "./dist/plugin-sdk/plugin-runtime.d.ts", + "default": "./dist/plugin-sdk/plugin-runtime.js" + }, + "./plugin-sdk/security-runtime": { + "types": "./dist/plugin-sdk/security-runtime.d.ts", + "default": "./dist/plugin-sdk/security-runtime.js" + }, + "./plugin-sdk/gateway-runtime": { + "types": "./dist/plugin-sdk/gateway-runtime.d.ts", + "default": "./dist/plugin-sdk/gateway-runtime.js" + }, + "./plugin-sdk/cli-runtime": { + "types": "./dist/plugin-sdk/cli-runtime.d.ts", + "default": "./dist/plugin-sdk/cli-runtime.js" + }, + "./plugin-sdk/hook-runtime": { + "types": "./dist/plugin-sdk/hook-runtime.d.ts", + "default": "./dist/plugin-sdk/hook-runtime.js" + }, + "./plugin-sdk/process-runtime": { + "types": "./dist/plugin-sdk/process-runtime.d.ts", + "default": "./dist/plugin-sdk/process-runtime.js" + }, + "./plugin-sdk/acp-runtime": { + "types": "./dist/plugin-sdk/acp-runtime.d.ts", + "default": "./dist/plugin-sdk/acp-runtime.js" + }, + "./plugin-sdk/zai": { + "types": "./dist/plugin-sdk/zai.d.ts", + "default": "./dist/plugin-sdk/zai.js" + }, "./plugin-sdk/telegram": { "types": "./dist/plugin-sdk/telegram.d.ts", "default": "./dist/plugin-sdk/telegram.js" @@ -230,10 +302,18 @@ "types": "./dist/plugin-sdk/account-id.d.ts", "default": "./dist/plugin-sdk/account-id.js" }, + "./plugin-sdk/account-resolution": { + "types": "./dist/plugin-sdk/account-resolution.d.ts", + "default": "./dist/plugin-sdk/account-resolution.js" + }, "./plugin-sdk/allow-from": { "types": "./dist/plugin-sdk/allow-from.d.ts", "default": "./dist/plugin-sdk/allow-from.js" }, + "./plugin-sdk/allowlist-config-edit": { + "types": "./dist/plugin-sdk/allowlist-config-edit.d.ts", + "default": "./dist/plugin-sdk/allowlist-config-edit.js" + }, "./plugin-sdk/boolean-param": { "types": "./dist/plugin-sdk/boolean-param.d.ts", "default": "./dist/plugin-sdk/boolean-param.js" @@ -254,10 +334,50 @@ "types": "./dist/plugin-sdk/keyed-async-queue.d.ts", "default": "./dist/plugin-sdk/keyed-async-queue.js" }, + "./plugin-sdk/provider-auth": { + "types": "./dist/plugin-sdk/provider-auth.d.ts", + "default": "./dist/plugin-sdk/provider-auth.js" + }, + "./plugin-sdk/provider-models": { + "types": "./dist/plugin-sdk/provider-models.d.ts", + "default": "./dist/plugin-sdk/provider-models.js" + }, + "./plugin-sdk/provider-onboard": { + "types": "./dist/plugin-sdk/provider-onboard.d.ts", + "default": "./dist/plugin-sdk/provider-onboard.js" + }, + "./plugin-sdk/provider-stream": { + "types": "./dist/plugin-sdk/provider-stream.d.ts", + "default": "./dist/plugin-sdk/provider-stream.js" + }, + "./plugin-sdk/provider-usage": { + "types": "./dist/plugin-sdk/provider-usage.d.ts", + "default": "./dist/plugin-sdk/provider-usage.js" + }, + "./plugin-sdk/provider-web-search": { + "types": "./dist/plugin-sdk/provider-web-search.d.ts", + "default": "./dist/plugin-sdk/provider-web-search.js" + }, "./plugin-sdk/request-url": { "types": "./dist/plugin-sdk/request-url.d.ts", "default": "./dist/plugin-sdk/request-url.js" }, + "./plugin-sdk/runtime-store": { + "types": "./dist/plugin-sdk/runtime-store.d.ts", + "default": "./dist/plugin-sdk/runtime-store.js" + }, + "./plugin-sdk/speech": { + "types": "./dist/plugin-sdk/speech.d.ts", + "default": "./dist/plugin-sdk/speech.js" + }, + "./plugin-sdk/state-paths": { + "types": "./dist/plugin-sdk/state-paths.d.ts", + "default": "./dist/plugin-sdk/state-paths.js" + }, + "./plugin-sdk/tool-send": { + "types": "./dist/plugin-sdk/tool-send.d.ts", + "default": "./dist/plugin-sdk/tool-send.js" + }, "./cli-entry": "./openclaw.mjs" }, "scripts": { diff --git a/scripts/lib/plugin-sdk-entrypoints.json b/scripts/lib/plugin-sdk-entrypoints.json index f99be019a69..e2de1d74f1f 100644 --- a/scripts/lib/plugin-sdk-entrypoints.json +++ b/scripts/lib/plugin-sdk-entrypoints.json @@ -7,7 +7,25 @@ "sandbox", "self-hosted-provider-setup", "routing", + "runtime", + "runtime-env", "setup", + "config-runtime", + "reply-runtime", + "channel-runtime", + "infra-runtime", + "media-runtime", + "conversation-runtime", + "text-runtime", + "agent-runtime", + "plugin-runtime", + "security-runtime", + "gateway-runtime", + "cli-runtime", + "hook-runtime", + "process-runtime", + "acp-runtime", + "zai", "telegram", "discord", "slack", @@ -47,11 +65,23 @@ "zalo", "zalouser", "account-id", + "account-resolution", "allow-from", + "allowlist-config-edit", "boolean-param", "channel-config-helpers", "group-access", "json-store", "keyed-async-queue", - "request-url" + "provider-auth", + "provider-models", + "provider-onboard", + "provider-stream", + "provider-usage", + "provider-web-search", + "request-url", + "runtime-store", + "speech", + "state-paths", + "tool-send" ] diff --git a/src/agents/pi-embedded-runner/compact.ts b/src/agents/pi-embedded-runner/compact.ts index ba001a6746a..4daef42a21f 100644 --- a/src/agents/pi-embedded-runner/compact.ts +++ b/src/agents/pi-embedded-runner/compact.ts @@ -19,11 +19,11 @@ import { createInternalHookEvent, triggerInternalHook } from "../../hooks/intern import { getMachineDisplayName } from "../../infra/machine-name.js"; import { generateSecureToken } from "../../infra/secure-random.js"; import { getMemorySearchManager } from "../../memory/index.js"; -import { resolveSignalReactionLevel } from "../../plugin-sdk-internal/signal.js"; +import { resolveSignalReactionLevel } from "../../plugin-sdk/signal.js"; import { resolveTelegramInlineButtonsScope, resolveTelegramReactionLevel, -} from "../../plugin-sdk-internal/telegram.js"; +} from "../../plugin-sdk/telegram.js"; import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js"; import { prepareProviderRuntimeAuth } from "../../plugins/provider-runtime.js"; import { type enqueueCommand, enqueueCommandInLane } from "../../process/command-queue.js"; diff --git a/src/agents/pi-embedded-runner/run/attempt.ts b/src/agents/pi-embedded-runner/run/attempt.ts index e8efa015137..0ea66825ff1 100644 --- a/src/agents/pi-embedded-runner/run/attempt.ts +++ b/src/agents/pi-embedded-runner/run/attempt.ts @@ -16,11 +16,11 @@ import { ensureGlobalUndiciStreamTimeouts, } from "../../../infra/net/undici-global-dispatcher.js"; import { MAX_IMAGE_BYTES } from "../../../media/constants.js"; -import { resolveSignalReactionLevel } from "../../../plugin-sdk-internal/signal.js"; +import { resolveSignalReactionLevel } from "../../../plugin-sdk/signal.js"; import { resolveTelegramInlineButtonsScope, resolveTelegramReactionLevel, -} from "../../../plugin-sdk-internal/telegram.js"; +} from "../../../plugin-sdk/telegram.js"; import { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js"; import type { PluginHookAgentContext, diff --git a/src/agents/tools/discord-actions-guild.ts b/src/agents/tools/discord-actions-guild.ts index 54386ad4267..fa427d87650 100644 --- a/src/agents/tools/discord-actions-guild.ts +++ b/src/agents/tools/discord-actions-guild.ts @@ -19,8 +19,8 @@ import { setChannelPermissionDiscord, uploadEmojiDiscord, uploadStickerDiscord, -} from "../../plugin-sdk-internal/discord.js"; -import { getPresence } from "../../plugin-sdk-internal/discord.js"; +} from "../../plugin-sdk/discord.js"; +import { getPresence } from "../../plugin-sdk/discord.js"; import { type ActionGate, jsonResult, diff --git a/src/agents/tools/discord-actions-messaging.ts b/src/agents/tools/discord-actions-messaging.ts index 8a7f93aacbb..20fdfcc6a02 100644 --- a/src/agents/tools/discord-actions-messaging.ts +++ b/src/agents/tools/discord-actions-messaging.ts @@ -1,6 +1,7 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import type { DiscordActionConfig } from "../../config/config.js"; import type { OpenClawConfig } from "../../config/config.js"; +import { readBooleanParam } from "../../plugin-sdk/boolean-param.js"; import { createThreadDiscord, deleteMessageDiscord, @@ -22,16 +23,9 @@ import { sendStickerDiscord, sendVoiceMessageDiscord, unpinMessageDiscord, -} from "../../plugin-sdk-internal/discord.js"; -import type { - DiscordSendComponents, - DiscordSendEmbeds, -} from "../../plugin-sdk-internal/discord.js"; -import { - readDiscordComponentSpec, - resolveDiscordChannelId, -} from "../../plugin-sdk-internal/discord.js"; -import { readBooleanParam } from "../../plugin-sdk/boolean-param.js"; +} from "../../plugin-sdk/discord.js"; +import type { DiscordSendComponents, DiscordSendEmbeds } from "../../plugin-sdk/discord.js"; +import { readDiscordComponentSpec, resolveDiscordChannelId } from "../../plugin-sdk/discord.js"; import { resolvePollMaxSelections } from "../../polls.js"; import { withNormalizedTimestamp } from "../date-time.js"; import { assertMediaNotDataUrl } from "../sandbox-paths.js"; diff --git a/src/agents/tools/discord-actions-moderation.ts b/src/agents/tools/discord-actions-moderation.ts index 63c3cc601bc..56d7a80d4c9 100644 --- a/src/agents/tools/discord-actions-moderation.ts +++ b/src/agents/tools/discord-actions-moderation.ts @@ -5,7 +5,7 @@ import { hasAnyGuildPermissionDiscord, kickMemberDiscord, timeoutMemberDiscord, -} from "../../plugin-sdk-internal/discord.js"; +} from "../../plugin-sdk/discord.js"; import { type ActionGate, jsonResult, readStringParam } from "./common.js"; import { isDiscordModerationAction, diff --git a/src/agents/tools/discord-actions-presence.ts b/src/agents/tools/discord-actions-presence.ts index fdfa53e2323..53c42829bb0 100644 --- a/src/agents/tools/discord-actions-presence.ts +++ b/src/agents/tools/discord-actions-presence.ts @@ -1,7 +1,7 @@ import type { Activity, UpdatePresenceData } from "@buape/carbon/gateway"; import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import type { DiscordActionConfig } from "../../config/config.js"; -import { getGateway } from "../../plugin-sdk-internal/discord.js"; +import { getGateway } from "../../plugin-sdk/discord.js"; import { type ActionGate, jsonResult, readStringParam } from "./common.js"; const ACTIVITY_TYPE_MAP: Record = { diff --git a/src/agents/tools/discord-actions.ts b/src/agents/tools/discord-actions.ts index 0e380b8d383..b953e56cffd 100644 --- a/src/agents/tools/discord-actions.ts +++ b/src/agents/tools/discord-actions.ts @@ -1,6 +1,6 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import type { OpenClawConfig } from "../../config/config.js"; -import { createDiscordActionGate } from "../../plugin-sdk-internal/discord.js"; +import { createDiscordActionGate } from "../../plugin-sdk/discord.js"; import { readStringParam } from "./common.js"; import { handleDiscordGuildAction } from "./discord-actions-guild.js"; import { handleDiscordMessagingAction } from "./discord-actions-messaging.js"; diff --git a/src/agents/tools/slack-actions.ts b/src/agents/tools/slack-actions.ts index c7fc16ed8b1..e9089cbfdcc 100644 --- a/src/agents/tools/slack-actions.ts +++ b/src/agents/tools/slack-actions.ts @@ -15,14 +15,14 @@ import { removeSlackReaction, sendSlackMessage, unpinSlackMessage, -} from "../../plugin-sdk-internal/slack.js"; +} from "../../plugin-sdk/slack.js"; import { parseSlackBlocksInput, parseSlackTarget, recordSlackThreadParticipation, resolveSlackAccount, resolveSlackChannelId, -} from "../../plugin-sdk-internal/slack.js"; +} from "../../plugin-sdk/slack.js"; import { withNormalizedTimestamp } from "../date-time.js"; import { createActionGate, diff --git a/src/agents/tools/telegram-actions.ts b/src/agents/tools/telegram-actions.ts index 9f2d48831c3..d648b1e5f41 100644 --- a/src/agents/tools/telegram-actions.ts +++ b/src/agents/tools/telegram-actions.ts @@ -1,17 +1,15 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import type { OpenClawConfig } from "../../config/config.js"; +import { readBooleanParam } from "../../plugin-sdk/boolean-param.js"; import { createTelegramActionGate, resolveTelegramPollActionGateState, -} from "../../plugin-sdk-internal/telegram.js"; -import type { - TelegramButtonStyle, - TelegramInlineButtons, -} from "../../plugin-sdk-internal/telegram.js"; +} from "../../plugin-sdk/telegram.js"; +import type { TelegramButtonStyle, TelegramInlineButtons } from "../../plugin-sdk/telegram.js"; import { resolveTelegramInlineButtonsScope, resolveTelegramTargetChatType, -} from "../../plugin-sdk-internal/telegram.js"; +} from "../../plugin-sdk/telegram.js"; import { createForumTopicTelegram, deleteMessageTelegram, @@ -21,14 +19,13 @@ import { sendMessageTelegram, sendPollTelegram, sendStickerTelegram, -} from "../../plugin-sdk-internal/telegram.js"; +} from "../../plugin-sdk/telegram.js"; import { getCacheStats, resolveTelegramReactionLevel, resolveTelegramToken, searchStickers, -} from "../../plugin-sdk-internal/telegram.js"; -import { readBooleanParam } from "../../plugin-sdk/boolean-param.js"; +} from "../../plugin-sdk/telegram.js"; import { resolvePollMaxSelections } from "../../polls.js"; import { jsonResult, diff --git a/src/agents/tools/whatsapp-actions.ts b/src/agents/tools/whatsapp-actions.ts index 30f36331d18..a84dc0a3d5b 100644 --- a/src/agents/tools/whatsapp-actions.ts +++ b/src/agents/tools/whatsapp-actions.ts @@ -1,6 +1,6 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import type { OpenClawConfig } from "../../config/config.js"; -import { sendReactionWhatsApp } from "../../plugin-sdk-internal/whatsapp.js"; +import { sendReactionWhatsApp } from "../../plugin-sdk/whatsapp.js"; import { createActionGate, jsonResult, readReactionParams, readStringParam } from "./common.js"; import { resolveAuthorizedWhatsAppOutboundTarget } from "./whatsapp-target-auth.js"; diff --git a/src/agents/tools/whatsapp-target-auth.ts b/src/agents/tools/whatsapp-target-auth.ts index 76e7e15d084..edc0052fbab 100644 --- a/src/agents/tools/whatsapp-target-auth.ts +++ b/src/agents/tools/whatsapp-target-auth.ts @@ -1,5 +1,5 @@ import type { OpenClawConfig } from "../../config/config.js"; -import { resolveWhatsAppAccount } from "../../plugin-sdk-internal/whatsapp.js"; +import { resolveWhatsAppAccount } from "../../plugin-sdk/whatsapp.js"; import { resolveWhatsAppOutboundTarget } from "../../whatsapp/resolve-outbound-target.js"; import { ToolAuthorizationError } from "./common.js"; diff --git a/src/auto-reply/reply/commands-approve.ts b/src/auto-reply/reply/commands-approve.ts index 5f259c1b45a..630ea988c05 100644 --- a/src/auto-reply/reply/commands-approve.ts +++ b/src/auto-reply/reply/commands-approve.ts @@ -3,7 +3,7 @@ import { logVerbose } from "../../globals.js"; import { isTelegramExecApprovalApprover, isTelegramExecApprovalClientEnabled, -} from "../../plugin-sdk-internal/telegram.js"; +} from "../../plugin-sdk/telegram.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js"; import { requireGatewayClientScopeForInternalChannel } from "./command-gates.js"; import type { CommandHandler } from "./commands-types.js"; diff --git a/src/auto-reply/reply/commands-models.ts b/src/auto-reply/reply/commands-models.ts index 99e02cfa81e..25f309361d2 100644 --- a/src/auto-reply/reply/commands-models.ts +++ b/src/auto-reply/reply/commands-models.ts @@ -16,7 +16,7 @@ import { calculateTotalPages, getModelsPageSize, type ProviderInfo, -} from "../../plugin-sdk-internal/telegram.js"; +} from "../../plugin-sdk/telegram.js"; import type { ReplyPayload } from "../types.js"; import { rejectUnauthorizedCommand } from "./command-gates.js"; import type { CommandHandler } from "./commands-types.js"; diff --git a/src/auto-reply/reply/directive-handling.model.ts b/src/auto-reply/reply/directive-handling.model.ts index d27bdb25d61..521d3bd6fea 100644 --- a/src/auto-reply/reply/directive-handling.model.ts +++ b/src/auto-reply/reply/directive-handling.model.ts @@ -8,7 +8,7 @@ import { } from "../../agents/model-selection.js"; import type { OpenClawConfig } from "../../config/config.js"; import type { SessionEntry } from "../../config/sessions.js"; -import { buildBrowseProvidersButton } from "../../plugin-sdk-internal/telegram.js"; +import { buildBrowseProvidersButton } from "../../plugin-sdk/telegram.js"; import { shortenHomePath } from "../../utils.js"; import { resolveSelectedAndActiveModel } from "../model-runtime.js"; import type { ReplyPayload } from "../types.js"; diff --git a/src/auto-reply/templating.ts b/src/auto-reply/templating.ts index b426b18eab5..a32fdc3ba87 100644 --- a/src/auto-reply/templating.ts +++ b/src/auto-reply/templating.ts @@ -3,7 +3,7 @@ import type { MediaUnderstandingDecision, MediaUnderstandingOutput, } from "../media-understanding/types.js"; -import type { StickerMetadata } from "../plugin-sdk-internal/telegram.js"; +import type { StickerMetadata } from "../plugin-sdk/telegram.js"; import type { InputProvenance } from "../sessions/input-provenance.js"; import type { InternalMessageChannel } from "../utils/message-channel.js"; import type { CommandArgs } from "./commands-registry.types.js"; diff --git a/src/channel-web.ts b/src/channel-web.ts index f7e451b142a..e6df4bda0d7 100644 --- a/src/channel-web.ts +++ b/src/channel-web.ts @@ -7,15 +7,11 @@ export { monitorWebChannel, resolveHeartbeatRecipients, runWebHeartbeatOnce, -} from "./plugin-sdk-internal/whatsapp.js"; -export { - extractMediaPlaceholder, - extractText, - monitorWebInbox, -} from "./plugin-sdk-internal/whatsapp.js"; -export { loginWeb } from "./plugin-sdk-internal/whatsapp.js"; -export { loadWebMedia, optimizeImageToJpeg } from "./plugin-sdk-internal/whatsapp.js"; -export { sendMessageWhatsApp } from "./plugin-sdk-internal/whatsapp.js"; +} from "./plugin-sdk/whatsapp.js"; +export { extractMediaPlaceholder, extractText, monitorWebInbox } from "./plugin-sdk/whatsapp.js"; +export { loginWeb } from "./plugin-sdk/whatsapp.js"; +export { loadWebMedia, optimizeImageToJpeg } from "./plugin-sdk/whatsapp.js"; +export { sendMessageWhatsApp } from "./plugin-sdk/whatsapp.js"; export { createWaSocket, formatError, @@ -26,4 +22,4 @@ export { WA_WEB_AUTH_DIR, waitForWaConnection, webAuthExists, -} from "./plugin-sdk-internal/whatsapp.js"; +} from "./plugin-sdk/whatsapp.js"; diff --git a/src/channels/plugins/actions/discord.ts b/src/channels/plugins/actions/discord.ts index ec11ca6c970..4615a88f3c5 100644 --- a/src/channels/plugins/actions/discord.ts +++ b/src/channels/plugins/actions/discord.ts @@ -1,2 +1,2 @@ // Public entrypoint for the Discord channel action adapter. -export * from "../../../plugin-sdk-internal/discord.js"; +export * from "../../../plugin-sdk/discord.js"; diff --git a/src/channels/plugins/actions/signal.ts b/src/channels/plugins/actions/signal.ts index 7db723f305e..60a70bac4c0 100644 --- a/src/channels/plugins/actions/signal.ts +++ b/src/channels/plugins/actions/signal.ts @@ -5,7 +5,7 @@ import { resolveSignalAccount, resolveSignalReactionLevel, sendReactionSignal, -} from "../../../plugin-sdk-internal/signal.js"; +} from "../../../plugin-sdk/signal.js"; import type { ChannelMessageActionAdapter, ChannelMessageActionName } from "../types.js"; import { resolveReactionMessageId } from "./reaction-message-id.js"; diff --git a/src/channels/plugins/actions/telegram.ts b/src/channels/plugins/actions/telegram.ts index e34c4598ade..e811e757b94 100644 --- a/src/channels/plugins/actions/telegram.ts +++ b/src/channels/plugins/actions/telegram.ts @@ -1,2 +1,2 @@ // Public entrypoint for the Telegram channel action adapter. -export * from "../../../plugin-sdk-internal/telegram.js"; +export * from "../../../plugin-sdk/telegram.js"; diff --git a/src/channels/plugins/agent-tools/whatsapp-login.ts b/src/channels/plugins/agent-tools/whatsapp-login.ts index 661b49e083b..2204225bdda 100644 --- a/src/channels/plugins/agent-tools/whatsapp-login.ts +++ b/src/channels/plugins/agent-tools/whatsapp-login.ts @@ -1,2 +1,2 @@ // Shim: keep legacy import path while the runtime loads the plugin SDK surface. -export * from "../../../plugin-sdk-internal/whatsapp.js"; +export * from "../../../plugin-sdk/whatsapp.js"; diff --git a/src/channels/plugins/group-mentions.ts b/src/channels/plugins/group-mentions.ts index 94079daed04..f825fc73fe5 100644 --- a/src/channels/plugins/group-mentions.ts +++ b/src/channels/plugins/group-mentions.ts @@ -10,7 +10,7 @@ import type { GroupToolPolicyConfig, } from "../../config/types.tools.js"; import { resolveExactLineGroupConfigKey } from "../../line/group-keys.js"; -import { inspectSlackAccount } from "../../plugin-sdk-internal/slack.js"; +import { inspectSlackAccount } from "../../plugin-sdk/slack.js"; import { normalizeAtHashSlug, normalizeHyphenSlug } from "../../shared/string-normalization.js"; import type { ChannelGroupContext } from "./types.js"; diff --git a/src/channels/plugins/slack.actions.ts b/src/channels/plugins/slack.actions.ts index df53d1ff0e0..d559ca99b6a 100644 --- a/src/channels/plugins/slack.actions.ts +++ b/src/channels/plugins/slack.actions.ts @@ -4,22 +4,11 @@ import { isSlackInteractiveRepliesEnabled, listSlackMessageActions, resolveSlackChannelId, -} from "../../plugin-sdk-internal/slack.js"; -import { handleSlackMessageAction } from "../../plugin-sdk/slack-message-actions.js"; -import type { ChannelMessageActionAdapter, ChannelMessageActionContext } from "./types.js"; + handleSlackMessageAction, +} from "../../plugin-sdk/slack.js"; +import type { ChannelMessageActionAdapter } from "./types.js"; -type SlackActionAdapterOptions = { - includeReadThreadId?: boolean; - invoke?: ( - ctx: ChannelMessageActionContext, - ) => Parameters[0]["invoke"]; - skipNormalizeChannelId?: boolean; -}; - -export function createSlackActions( - providerId: string, - options?: SlackActionAdapterOptions, -): ChannelMessageActionAdapter { +export function createSlackActions(providerId: string): ChannelMessageActionAdapter { return { listActions: ({ cfg }) => listSlackMessageActions(cfg), getCapabilities: ({ cfg }) => { @@ -34,19 +23,16 @@ export function createSlackActions( }, extractToolSend: ({ args }) => extractSlackToolSend(args), handleAction: async (ctx) => { - const invoke = - options?.invoke?.(ctx) ?? - (async (action, cfg, toolContext) => - await handleSlackAction(action, cfg, { - ...(toolContext as SlackActionContext | undefined), - mediaLocalRoots: ctx.mediaLocalRoots, - })); return await handleSlackMessageAction({ providerId, ctx, - normalizeChannelId: options?.skipNormalizeChannelId ? undefined : resolveSlackChannelId, - includeReadThreadId: options?.includeReadThreadId ?? true, - invoke, + normalizeChannelId: resolveSlackChannelId, + includeReadThreadId: true, + invoke: async (action, cfg, toolContext) => + await handleSlackAction(action, cfg, { + ...(toolContext as SlackActionContext | undefined), + mediaLocalRoots: ctx.mediaLocalRoots, + }), }); }, }; diff --git a/src/channels/read-only-account-inspect.discord.runtime.ts b/src/channels/read-only-account-inspect.discord.runtime.ts index 00d0943b1ec..9d2ac6ef427 100644 --- a/src/channels/read-only-account-inspect.discord.runtime.ts +++ b/src/channels/read-only-account-inspect.discord.runtime.ts @@ -1,2 +1,2 @@ -export { inspectDiscordAccount } from "../plugin-sdk-internal/discord.js"; -export type { InspectedDiscordAccount } from "../plugin-sdk-internal/discord.js"; +export { inspectDiscordAccount } from "../plugin-sdk/discord.js"; +export type { InspectedDiscordAccount } from "../plugin-sdk/discord.js"; diff --git a/src/channels/read-only-account-inspect.slack.runtime.ts b/src/channels/read-only-account-inspect.slack.runtime.ts index c3e2bd5d83c..a7526e2ea95 100644 --- a/src/channels/read-only-account-inspect.slack.runtime.ts +++ b/src/channels/read-only-account-inspect.slack.runtime.ts @@ -1,2 +1,2 @@ -export { inspectSlackAccount } from "../plugin-sdk-internal/slack.js"; -export type { InspectedSlackAccount } from "../plugin-sdk-internal/slack.js"; +export { inspectSlackAccount } from "../plugin-sdk/slack.js"; +export type { InspectedSlackAccount } from "../plugin-sdk/slack.js"; diff --git a/src/channels/read-only-account-inspect.telegram.runtime.ts b/src/channels/read-only-account-inspect.telegram.runtime.ts index 1e633a0ff8e..0ab48f2c241 100644 --- a/src/channels/read-only-account-inspect.telegram.runtime.ts +++ b/src/channels/read-only-account-inspect.telegram.runtime.ts @@ -1,2 +1,2 @@ -export { inspectTelegramAccount } from "../plugin-sdk-internal/telegram.js"; -export type { InspectedTelegramAccount } from "../plugin-sdk-internal/telegram.js"; +export { inspectTelegramAccount } from "../plugin-sdk/telegram.js"; +export type { InspectedTelegramAccount } from "../plugin-sdk/telegram.js"; diff --git a/src/cli/deps.ts b/src/cli/deps.ts index 84bb107f97e..7ebfbf74f5b 100644 --- a/src/cli/deps.ts +++ b/src/cli/deps.ts @@ -35,32 +35,32 @@ export function createDefaultDeps(): CliDeps { return { whatsapp: createLazySender( "whatsapp", - () => import("../plugin-sdk-internal/whatsapp.js") as Promise>, + () => import("../plugin-sdk/whatsapp.js") as Promise>, "sendMessageWhatsApp", ), telegram: createLazySender( "telegram", - () => import("../plugin-sdk-internal/telegram.js") as Promise>, + () => import("../plugin-sdk/telegram.js") as Promise>, "sendMessageTelegram", ), discord: createLazySender( "discord", - () => import("../plugin-sdk-internal/discord.js") as Promise>, + () => import("../plugin-sdk/discord.js") as Promise>, "sendMessageDiscord", ), slack: createLazySender( "slack", - () => import("../plugin-sdk-internal/slack.js") as Promise>, + () => import("../plugin-sdk/slack.js") as Promise>, "sendMessageSlack", ), signal: createLazySender( "signal", - () => import("../plugin-sdk-internal/signal.js") as Promise>, + () => import("../plugin-sdk/signal.js") as Promise>, "sendMessageSignal", ), imessage: createLazySender( "imessage", - () => import("../plugin-sdk-internal/imessage.js") as Promise>, + () => import("../plugin-sdk/imessage.js") as Promise>, "sendMessageIMessage", ), }; @@ -70,4 +70,4 @@ export function createOutboundSendDeps(deps: CliDeps): OutboundSendDeps { return createOutboundSendDepsFromCliSource(deps); } -export { logWebSelfId } from "../plugin-sdk-internal/whatsapp.js"; +export { logWebSelfId } from "../plugin-sdk/whatsapp.js"; diff --git a/src/commands/doctor-config-flow.ts b/src/commands/doctor-config-flow.ts index 0c52c9b582a..a1cbf5fa6d9 100644 --- a/src/commands/doctor-config-flow.ts +++ b/src/commands/doctor-config-flow.ts @@ -29,7 +29,7 @@ import { listTelegramAccountIds, normalizeTelegramAllowFromEntry, resolveTelegramAccount, -} from "../plugin-sdk-internal/telegram.js"; +} from "../plugin-sdk/telegram.js"; import { formatChannelAccountsDefaultPath, formatSetExplicitDefaultInstruction, diff --git a/src/config/plugin-auto-enable.ts b/src/config/plugin-auto-enable.ts index c1297e7de4c..1deaad96d6f 100644 --- a/src/config/plugin-auto-enable.ts +++ b/src/config/plugin-auto-enable.ts @@ -9,7 +9,7 @@ import { listChatChannels, normalizeChatChannelId, } from "../channels/registry.js"; -import { hasAnyWhatsAppAuth } from "../plugin-sdk-internal/whatsapp.js"; +import { hasAnyWhatsAppAuth } from "../plugin-sdk/whatsapp.js"; import { loadPluginManifestRegistry, type PluginManifestRegistry, diff --git a/src/config/schema.help.ts b/src/config/schema.help.ts index 1b048bc9aa1..02103650589 100644 --- a/src/config/schema.help.ts +++ b/src/config/schema.help.ts @@ -1,7 +1,7 @@ import { DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, -} from "../plugin-sdk-internal/discord.js"; +} from "../plugin-sdk/discord.js"; import { MEDIA_AUDIO_FIELD_HELP } from "./media-audio-field-metadata.js"; import { IRC_FIELD_HELP } from "./schema.irc.js"; import { describeTalkSilenceTimeoutDefaults } from "./talk-defaults.js"; diff --git a/src/config/sessions/explicit-session-key-normalization.ts b/src/config/sessions/explicit-session-key-normalization.ts index 16b43a7c43c..08543e5a6d0 100644 --- a/src/config/sessions/explicit-session-key-normalization.ts +++ b/src/config/sessions/explicit-session-key-normalization.ts @@ -1,5 +1,5 @@ import type { MsgContext } from "../../auto-reply/templating.js"; -import { normalizeExplicitDiscordSessionKey } from "../../plugin-sdk-internal/discord.js"; +import { normalizeExplicitDiscordSessionKey } from "../../plugin-sdk/discord.js"; type ExplicitSessionKeyNormalizer = (sessionKey: string, ctx: MsgContext) => string; type ExplicitSessionKeyNormalizerEntry = { diff --git a/src/config/types.discord.ts b/src/config/types.discord.ts index aea4e7f8cfd..c9269c6b8fd 100644 --- a/src/config/types.discord.ts +++ b/src/config/types.discord.ts @@ -1,4 +1,4 @@ -import type { DiscordPluralKitConfig } from "../plugin-sdk-internal/discord.js"; +import type { DiscordPluralKitConfig } from "../plugin-sdk/discord.js"; import type { BlockStreamingChunkConfig, BlockStreamingCoalesceConfig, diff --git a/src/cron/isolated-agent/delivery-target.ts b/src/cron/isolated-agent/delivery-target.ts index 585e273e613..e903cd15cab 100644 --- a/src/cron/isolated-agent/delivery-target.ts +++ b/src/cron/isolated-agent/delivery-target.ts @@ -13,7 +13,7 @@ import { resolveSessionDeliveryTarget, } from "../../infra/outbound/targets.js"; import { readChannelAllowFromStoreSync } from "../../pairing/pairing-store.js"; -import { resolveWhatsAppAccount } from "../../plugin-sdk-internal/whatsapp.js"; +import { resolveWhatsAppAccount } from "../../plugin-sdk/whatsapp.js"; import { buildChannelAccountBindings } from "../../routing/bindings.js"; import { normalizeAccountId, normalizeAgentId } from "../../routing/session-key.js"; import { normalizeWhatsAppTarget } from "../../whatsapp/normalize.js"; diff --git a/src/gateway/server-http.ts b/src/gateway/server-http.ts index fe35da1f356..0ad655f4990 100644 --- a/src/gateway/server-http.ts +++ b/src/gateway/server-http.ts @@ -13,7 +13,7 @@ import { CANVAS_WS_PATH, handleA2uiHttpRequest } from "../canvas-host/a2ui.js"; import type { CanvasHostHandler } from "../canvas-host/server.js"; import { loadConfig } from "../config/config.js"; import type { createSubsystemLogger } from "../logging/subsystem.js"; -import { handleSlackHttpRequest } from "../plugin-sdk-internal/slack.js"; +import { handleSlackHttpRequest } from "../plugin-sdk/slack.js"; import { safeEqualSecret } from "../security/secret-equal.js"; import { AUTH_RATE_LIMIT_SCOPE_HOOK_AUTH, diff --git a/src/infra/state-migrations.ts b/src/infra/state-migrations.ts index 6646ab02e75..b429365a4a4 100644 --- a/src/infra/state-migrations.ts +++ b/src/infra/state-migrations.ts @@ -15,7 +15,7 @@ import { canonicalizeMainSessionAlias } from "../config/sessions/main-session.js import type { SessionScope } from "../config/sessions/types.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { resolveChannelAllowFromPath } from "../pairing/pairing-store.js"; -import { listTelegramAccountIds } from "../plugin-sdk-internal/telegram.js"; +import { listTelegramAccountIds } from "../plugin-sdk/telegram.js"; import { buildAgentMainSessionKey, DEFAULT_ACCOUNT_ID, diff --git a/src/plugin-sdk/account-resolution.ts b/src/plugin-sdk/account-resolution.ts index 4aceec2c945..cb819f57354 100644 --- a/src/plugin-sdk/account-resolution.ts +++ b/src/plugin-sdk/account-resolution.ts @@ -1,3 +1,16 @@ +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 { resolveAccountEntry } from "../routing/account-lookup.js"; +export { + DEFAULT_ACCOUNT_ID, + normalizeAccountId, + normalizeOptionalAccountId, +} from "../routing/session-key.js"; +export { normalizeE164, pathExists, resolveUserPath } from "../utils.js"; + /** Resolve an account by id, then fall back to the default account when the primary lacks credentials. */ export function resolveAccountWithDefaultFallback(params: { accountId?: string | null; diff --git a/src/plugin-sdk/acp-runtime.ts b/src/plugin-sdk/acp-runtime.ts new file mode 100644 index 00000000000..c50c36419bb --- /dev/null +++ b/src/plugin-sdk/acp-runtime.ts @@ -0,0 +1,6 @@ +// Public ACP runtime helpers for plugins that integrate with ACP control/session state. + +export { getAcpSessionManager } from "../acp/control-plane/manager.js"; +export { isAcpRuntimeError } from "../acp/runtime/errors.js"; +export { readAcpSessionEntry } from "../acp/runtime/session-meta.js"; +export type { AcpSessionStoreEntry } from "../acp/runtime/session-meta.js"; diff --git a/src/plugin-sdk/agent-runtime.ts b/src/plugin-sdk/agent-runtime.ts new file mode 100644 index 00000000000..4eddbd51a29 --- /dev/null +++ b/src/plugin-sdk/agent-runtime.ts @@ -0,0 +1,28 @@ +// Public agent/model/runtime helpers for plugins that integrate with core agent flows. + +export * from "../agents/agent-scope.js"; +export * from "../agents/auth-profiles.js"; +export * from "../agents/current-time.js"; +export * from "../agents/defaults.js"; +export * from "../agents/identity-avatar.js"; +export * from "../agents/identity.js"; +export * from "../agents/model-auth-markers.js"; +export * from "../agents/model-auth.js"; +export * from "../agents/model-catalog.js"; +export * from "../agents/model-selection.js"; +export * from "../agents/pi-embedded-block-chunker.js"; +export * from "../agents/pi-embedded-utils.js"; +export * from "../agents/provider-id.js"; +export * from "../agents/schema/typebox.js"; +export * from "../agents/sglang-defaults.js"; +export * from "../agents/tools/common.js"; +export * from "../agents/tools/discord-actions-shared.js"; +export * from "../agents/tools/discord-actions.js"; +export * from "../agents/tools/telegram-actions.js"; +export * from "../agents/tools/web-guarded-fetch.js"; +export * from "../agents/tools/web-shared.js"; +export * from "../agents/tools/discord-actions-moderation-shared.js"; +export * from "../agents/tools/web-fetch-utils.js"; +export * from "../agents/vllm-defaults.js"; +export * from "../commands/agent.js"; +export * from "../tts/tts.js"; diff --git a/src/plugin-sdk/channel-config-helpers.ts b/src/plugin-sdk/channel-config-helpers.ts index 564bc86bc68..556e2a0c1c1 100644 --- a/src/plugin-sdk/channel-config-helpers.ts +++ b/src/plugin-sdk/channel-config-helpers.ts @@ -2,6 +2,13 @@ import { deleteAccountFromConfigSection, setAccountEnabledInConfigSection, } from "../channels/plugins/config-helpers.js"; +import { + collectAllowlistProviderGroupPolicyWarnings, + collectAllowlistProviderRestrictSendersWarnings, + collectOpenGroupPolicyConfiguredRouteWarnings, + collectOpenGroupPolicyRouteAllowlistWarnings, + collectOpenProviderGroupPolicyWarnings, +} from "../channels/plugins/group-policy-warnings.js"; import { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js"; import { normalizeWhatsAppAllowFromEntries } from "../channels/plugins/normalize/whatsapp.js"; import { getChannelPlugin } from "../channels/plugins/registry.js"; @@ -149,6 +156,15 @@ export function createScopedDmSecurityResolver< }); } +export { buildAccountScopedDmSecurityPolicy }; +export { + collectAllowlistProviderGroupPolicyWarnings, + collectAllowlistProviderRestrictSendersWarnings, + collectOpenGroupPolicyConfiguredRouteWarnings, + collectOpenGroupPolicyRouteAllowlistWarnings, + collectOpenProviderGroupPolicyWarnings, +}; + /** Read the effective WhatsApp allowlist through the active plugin contract. */ export function resolveWhatsAppConfigAllowFrom(params: { cfg: OpenClawConfig; diff --git a/src/plugin-sdk/channel-runtime.ts b/src/plugin-sdk/channel-runtime.ts new file mode 100644 index 00000000000..4fda751b6cb --- /dev/null +++ b/src/plugin-sdk/channel-runtime.ts @@ -0,0 +1,53 @@ +// Shared channel/runtime helpers for plugins. Channel plugins should use this +// surface instead of reaching into src/channels or adjacent infra modules. + +export * from "../channels/ack-reactions.js"; +export * from "../channels/allow-from.js"; +export * from "../channels/allowlists/resolve-utils.js"; +export * from "../channels/allowlist-match.js"; +export * from "../channels/channel-config.js"; +export * from "../channels/chat-type.js"; +export * from "../channels/command-gating.js"; +export * from "../channels/conversation-label.js"; +export * from "../channels/draft-stream-controls.js"; +export * from "../channels/draft-stream-loop.js"; +export * from "../channels/inbound-debounce-policy.js"; +export * from "../channels/location.js"; +export * from "../channels/logging.js"; +export * from "../channels/mention-gating.js"; +export * from "../channels/native-command-session-targets.js"; +export * from "../channels/reply-prefix.js"; +export * from "../channels/run-state-machine.js"; +export * from "../channels/session.js"; +export * from "../channels/session-envelope.js"; +export * from "../channels/session-meta.js"; +export * from "../channels/status-reactions.js"; +export * from "../channels/targets.js"; +export * from "../channels/thread-binding-id.js"; +export * from "../channels/thread-bindings-messages.js"; +export * from "../channels/thread-bindings-policy.js"; +export * from "../channels/transport/stall-watchdog.js"; +export * from "../channels/typing.js"; +export * from "../channels/plugins/actions/reaction-message-id.js"; +export * from "../channels/plugins/actions/shared.js"; +export type * from "../channels/plugins/types.js"; +export * from "../channels/plugins/config-writes.js"; +export * from "../channels/plugins/directory-config.js"; +export * from "../channels/plugins/media-payload.js"; +export * from "../channels/plugins/normalize/signal.js"; +export * from "../channels/plugins/normalize/whatsapp.js"; +export * from "../channels/plugins/outbound/direct-text-media.js"; +export * from "../channels/plugins/outbound/interactive.js"; +export * from "../channels/plugins/status-issues/shared.js"; +export * from "../channels/plugins/whatsapp-heartbeat.js"; +export * from "../infra/outbound/send-deps.js"; +export * from "../utils/message-channel.js"; +export type { + InteractiveButtonStyle, + InteractiveReplyButton, + InteractiveReply, +} from "../interactive/payload.js"; +export { + normalizeInteractiveReply, + resolveInteractiveTextFallback, +} from "../interactive/payload.js"; diff --git a/src/plugin-sdk/cli-runtime.ts b/src/plugin-sdk/cli-runtime.ts new file mode 100644 index 00000000000..23a881da23a --- /dev/null +++ b/src/plugin-sdk/cli-runtime.ts @@ -0,0 +1,6 @@ +// Public CLI/output helpers for plugins that share terminal-facing command behavior. + +export * from "../cli/command-format.js"; +export * from "../cli/parse-duration.js"; +export * from "../cli/wait.js"; +export * from "../version.js"; diff --git a/src/plugin-sdk/config-runtime.ts b/src/plugin-sdk/config-runtime.ts new file mode 100644 index 00000000000..67b2ec82fee --- /dev/null +++ b/src/plugin-sdk/config-runtime.ts @@ -0,0 +1,42 @@ +// Shared config/runtime boundary for plugins that need config loading, +// config writes, or session-store helpers without importing src internals. + +export * from "../config/config.js"; +export * from "../config/markdown-tables.js"; +export * from "../config/group-policy.js"; +export * from "../config/runtime-group-policy.js"; +export * from "../config/commands.js"; +export * from "../config/discord-preview-streaming.js"; +export * from "../config/io.js"; +export * from "../config/telegram-custom-commands.js"; +export * from "../config/talk.js"; +export * from "../config/agent-limits.js"; +export * from "../cron/store.js"; +export * from "../sessions/model-overrides.js"; +export type * from "../config/types.slack.js"; +export { + loadSessionStore, + readSessionUpdatedAt, + recordSessionMetaFromInbound, + resolveSessionKey, + resolveStorePath, + updateLastRoute, + updateSessionStore, + type SessionResetMode, + type SessionScope, +} from "../config/sessions.js"; +export { resolveGroupSessionKey } from "../config/sessions/group.js"; +export { + evaluateSessionFreshness, + resolveChannelResetConfig, + resolveSessionResetPolicy, + resolveSessionResetType, + resolveThreadFlag, +} from "../config/sessions/reset.js"; +export { resolveSessionStoreEntry } from "../config/sessions/store.js"; +export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js"; +export { + hasConfiguredSecretInput, + normalizeResolvedSecretInputString, + normalizeSecretInputString, +} from "../config/types.secrets.js"; diff --git a/src/plugin-sdk/conversation-runtime.ts b/src/plugin-sdk/conversation-runtime.ts new file mode 100644 index 00000000000..77380f6aa9a --- /dev/null +++ b/src/plugin-sdk/conversation-runtime.ts @@ -0,0 +1,41 @@ +// Public pairing/session-binding helpers for plugins that manage conversation ownership. + +export * from "../acp/persistent-bindings.route.js"; +export { + type BindingStatus, + type BindingTargetKind, + type ConversationRef, + SessionBindingError, + type SessionBindingAdapter, + type SessionBindingAdapterCapabilities, + type SessionBindingBindInput, + type SessionBindingCapabilities, + type SessionBindingPlacement, + type SessionBindingRecord, + type SessionBindingService, + type SessionBindingUnbindInput, + getSessionBindingService, + isSessionBindingError, + registerSessionBindingAdapter, + unregisterSessionBindingAdapter, +} from "../infra/outbound/session-binding-service.js"; +export * from "../pairing/pairing-challenge.js"; +export * from "../pairing/pairing-messages.js"; +export * from "../pairing/pairing-store.js"; +export { + buildPluginBindingApprovalCustomId, + buildPluginBindingDeclinedText, + buildPluginBindingErrorText, + buildPluginBindingResolvedText, + buildPluginBindingUnavailableText, + detachPluginConversationBinding, + getCurrentPluginConversationBinding, + hasShownPluginBindingFallbackNotice, + isPluginOwnedBindingMetadata, + isPluginOwnedSessionBindingRecord, + markPluginBindingFallbackNoticeShown, + parsePluginBindingApprovalCustomId, + requestPluginConversationBinding, + resolvePluginConversationBindingApproval, + toPluginConversationBinding, +} from "../plugins/conversation-binding.js"; diff --git a/src/plugin-sdk/discord.ts b/src/plugin-sdk/discord.ts index d15f5091b9d..b31c796e2d6 100644 --- a/src/plugin-sdk/discord.ts +++ b/src/plugin-sdk/discord.ts @@ -1,6 +1,18 @@ export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js"; export type { OpenClawConfig } from "../config/config.js"; export type { DiscordAccountConfig, DiscordActionConfig } from "../config/types.js"; +export type { DiscordPluralKitConfig } from "../../extensions/discord/src/pluralkit.js"; +export type { InspectedDiscordAccount } from "../../extensions/discord/src/account-inspect.js"; +export type { ResolvedDiscordAccount } from "../../extensions/discord/src/accounts.js"; +export type { + DiscordSendComponents, + DiscordSendEmbeds, +} from "../../extensions/discord/src/send.shared.js"; +export type { + ThreadBindingManager, + ThreadBindingRecord, + ThreadBindingTargetKind, +} from "../../extensions/discord/src/monitor/thread-bindings.js"; export type { ChannelMessageActionContext, ChannelPlugin, @@ -44,3 +56,77 @@ export { buildComputedAccountStatusSnapshot, buildTokenChannelStatusSummary, } from "./status-helpers.js"; + +export { + createDiscordActionGate, + listDiscordAccountIds, + resolveDefaultDiscordAccountId, + resolveDiscordAccount, +} from "../../extensions/discord/src/accounts.js"; +export { inspectDiscordAccount } from "../../extensions/discord/src/account-inspect.js"; +export { + looksLikeDiscordTargetId, + normalizeDiscordMessagingTarget, + normalizeDiscordOutboundTarget, +} from "../../extensions/discord/src/normalize.js"; +export { collectDiscordAuditChannelIds } from "../../extensions/discord/src/audit.js"; +export { collectDiscordStatusIssues } from "../../extensions/discord/src/status-issues.js"; +export { + DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, + DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, +} from "../../extensions/discord/src/monitor/timeouts.js"; +export { normalizeExplicitDiscordSessionKey } from "../../extensions/discord/src/session-key-normalization.js"; +export { + autoBindSpawnedDiscordSubagent, + listThreadBindingsBySessionKey, + unbindThreadBindingsBySessionKey, +} from "../../extensions/discord/src/monitor/thread-bindings.js"; +export { getGateway } from "../../extensions/discord/src/monitor/gateway-registry.js"; +export { getPresence } from "../../extensions/discord/src/monitor/presence-cache.js"; +export { readDiscordComponentSpec } from "../../extensions/discord/src/components.js"; +export { resolveDiscordChannelId } from "../../extensions/discord/src/targets.js"; +export { + addRoleDiscord, + banMemberDiscord, + createChannelDiscord, + createScheduledEventDiscord, + createThreadDiscord, + deleteChannelDiscord, + deleteMessageDiscord, + editChannelDiscord, + editMessageDiscord, + fetchChannelInfoDiscord, + fetchChannelPermissionsDiscord, + fetchMemberInfoDiscord, + fetchMessageDiscord, + fetchReactionsDiscord, + fetchRoleInfoDiscord, + fetchVoiceStatusDiscord, + hasAnyGuildPermissionDiscord, + kickMemberDiscord, + listGuildChannelsDiscord, + listGuildEmojisDiscord, + listPinsDiscord, + listScheduledEventsDiscord, + listThreadsDiscord, + moveChannelDiscord, + pinMessageDiscord, + reactMessageDiscord, + readMessagesDiscord, + removeChannelPermissionDiscord, + removeOwnReactionsDiscord, + removeReactionDiscord, + removeRoleDiscord, + searchMessagesDiscord, + sendDiscordComponentMessage, + sendMessageDiscord, + sendPollDiscord, + sendStickerDiscord, + sendVoiceMessageDiscord, + setChannelPermissionDiscord, + timeoutMemberDiscord, + unpinMessageDiscord, + uploadEmojiDiscord, + uploadStickerDiscord, +} from "../../extensions/discord/src/send.js"; +export { discordMessageActions } from "../../extensions/discord/src/channel-actions.js"; diff --git a/src/plugin-sdk/gateway-runtime.ts b/src/plugin-sdk/gateway-runtime.ts new file mode 100644 index 00000000000..f1ef78ef14c --- /dev/null +++ b/src/plugin-sdk/gateway-runtime.ts @@ -0,0 +1,6 @@ +// Public gateway/client helpers for plugins that talk to the host gateway surface. + +export * from "../gateway/channel-status-patches.js"; +export { GatewayClient } from "../gateway/client.js"; +export { createOperatorApprovalsGatewayClient } from "../gateway/operator-approvals-client.js"; +export type { EventFrame } from "../gateway/protocol/index.js"; diff --git a/src/plugin-sdk/hook-runtime.ts b/src/plugin-sdk/hook-runtime.ts new file mode 100644 index 00000000000..dd67f98cf04 --- /dev/null +++ b/src/plugin-sdk/hook-runtime.ts @@ -0,0 +1,5 @@ +// Public hook helpers for plugins that need the shared internal/webhook hook pipeline. + +export * from "../hooks/fire-and-forget.js"; +export * from "../hooks/internal-hooks.js"; +export * from "../hooks/message-hook-mappers.js"; diff --git a/src/plugin-sdk/imessage.ts b/src/plugin-sdk/imessage.ts index a974910e680..5481c117be6 100644 --- a/src/plugin-sdk/imessage.ts +++ b/src/plugin-sdk/imessage.ts @@ -40,3 +40,4 @@ export { IMessageConfigSchema } from "../config/zod-schema.providers-core.js"; export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js"; export { collectStatusIssuesFromLastError } from "./status-helpers.js"; +export { sendMessageIMessage } from "../../extensions/imessage/src/send.js"; diff --git a/src/plugin-sdk/infra-runtime.ts b/src/plugin-sdk/infra-runtime.ts new file mode 100644 index 00000000000..dd75ac4fea2 --- /dev/null +++ b/src/plugin-sdk/infra-runtime.ts @@ -0,0 +1,39 @@ +// Public runtime/transport helpers for plugins that need shared infra behavior. + +export * from "../infra/backoff.js"; +export * from "../infra/channel-activity.js"; +export * from "../infra/dedupe.js"; +export * from "../infra/diagnostic-events.js"; +export * from "../infra/diagnostic-flags.js"; +export * from "../infra/env.js"; +export * from "../infra/errors.js"; +export * from "../infra/exec-approval-command-display.ts"; +export * from "../infra/exec-approval-reply.ts"; +export * from "../infra/exec-approval-session-target.ts"; +export * from "../infra/exec-approvals.ts"; +export * from "../infra/fetch.js"; +export * from "../infra/file-lock.js"; +export * from "../infra/format-time/format-duration.ts"; +export * from "../infra/fs-safe.ts"; +export * from "../infra/heartbeat-events.ts"; +export * from "../infra/heartbeat-visibility.ts"; +export * from "../infra/home-dir.js"; +export * from "../infra/http-body.js"; +export * from "../infra/json-files.js"; +export * from "../infra/map-size.js"; +export * from "../infra/net/hostname.ts"; +export * from "../infra/net/fetch-guard.js"; +export * from "../infra/net/proxy-env.js"; +export * from "../infra/net/proxy-fetch.js"; +export * from "../infra/net/ssrf.js"; +export * from "../infra/outbound/identity.js"; +export * from "../infra/retry.js"; +export * from "../infra/retry-policy.js"; +export * from "../infra/scp-host.ts"; +export * from "../infra/secret-file.js"; +export * from "../infra/secure-random.js"; +export * from "../infra/system-events.js"; +export * from "../infra/system-message.ts"; +export * from "../infra/tmp-openclaw-dir.js"; +export * from "../infra/transport-ready.js"; +export * from "../infra/wsl.ts"; diff --git a/src/plugin-sdk/json-store.ts b/src/plugin-sdk/json-store.ts index faff8f64e59..b95ee5b819b 100644 --- a/src/plugin-sdk/json-store.ts +++ b/src/plugin-sdk/json-store.ts @@ -1,7 +1,14 @@ import fs from "node:fs"; +import { loadJsonFile, saveJsonFile } from "../infra/json-file.js"; import { writeJsonAtomic } from "../infra/json-files.js"; import { safeParseJson } from "../utils.js"; +/** Read small JSON blobs synchronously for token/state caches. */ +export { loadJsonFile }; + +/** Persist small JSON blobs synchronously with restrictive permissions. */ +export { saveJsonFile }; + /** Read JSON from disk and fall back cleanly when the file is missing or invalid. */ export async function readJsonFileWithFallback( filePath: string, diff --git a/src/plugin-sdk/media-runtime.ts b/src/plugin-sdk/media-runtime.ts new file mode 100644 index 00000000000..2f2d81b0d46 --- /dev/null +++ b/src/plugin-sdk/media-runtime.ts @@ -0,0 +1,21 @@ +// Public media/payload helpers for plugins that fetch, transform, or send attachments. + +export * from "../media/audio.js"; +export * from "../media/constants.js"; +export * from "../media/fetch.js"; +export * from "../media/ffmpeg-exec.js"; +export * from "../media/ffmpeg-limits.js"; +export * from "../media/image-ops.js"; +export * from "../media/inbound-path-policy.js"; +export * from "../media/load-options.js"; +export * from "../media/local-roots.js"; +export * from "../media/mime.js"; +export * from "../media/outbound-attachment.js"; +export * from "../media/png-encode.ts"; +export * from "../media/store.js"; +export * from "../media/temp-files.js"; +export * from "../media-understanding/audio-preflight.ts"; +export * from "../media-understanding/defaults.js"; +export * from "../media-understanding/providers/image-runtime.ts"; +export * from "../media-understanding/runner.js"; +export * from "../polls.js"; diff --git a/src/plugin-sdk/plugin-runtime.ts b/src/plugin-sdk/plugin-runtime.ts new file mode 100644 index 00000000000..ecc80f8f224 --- /dev/null +++ b/src/plugin-sdk/plugin-runtime.ts @@ -0,0 +1,6 @@ +// Public plugin-command/hook helpers for plugins that extend shared command or hook flows. + +export * from "../plugins/commands.js"; +export * from "../plugins/hook-runner-global.js"; +export * from "../plugins/interactive.js"; +export * from "../plugins/types.js"; diff --git a/src/plugin-sdk/process-runtime.ts b/src/plugin-sdk/process-runtime.ts new file mode 100644 index 00000000000..826ed2d1197 --- /dev/null +++ b/src/plugin-sdk/process-runtime.ts @@ -0,0 +1,3 @@ +// Public process helpers for plugins that spawn or probe local commands. + +export * from "../process/exec.js"; diff --git a/src/plugin-sdk/provider-auth.ts b/src/plugin-sdk/provider-auth.ts new file mode 100644 index 00000000000..40669e51d97 --- /dev/null +++ b/src/plugin-sdk/provider-auth.ts @@ -0,0 +1,43 @@ +// Public auth/onboarding helpers for provider plugins. + +export type { OpenClawConfig } from "../config/config.js"; +export type { SecretInput } from "../config/types.secrets.js"; +export type { ProviderAuthResult } from "../plugins/types.js"; +export type { AuthProfileStore, OAuthCredential } from "../agents/auth-profiles/types.js"; + +export { + CLAUDE_CLI_PROFILE_ID, + CODEX_CLI_PROFILE_ID, + ensureAuthProfileStore, + listProfilesForProvider, + suggestOAuthProfileIdForLegacyDefault, + upsertAuthProfile, +} from "../agents/auth-profiles.js"; +export { + MINIMAX_OAUTH_MARKER, + resolveNonEnvSecretRefApiKeyMarker, +} from "../agents/model-auth-markers.js"; +export { + formatApiKeyPreview, + normalizeApiKeyInput, + validateApiKeyInput, +} from "../commands/auth-choice.api-key.js"; +export { + ensureApiKeyFromOptionEnvOrPrompt, + normalizeSecretInputModeInput, + promptSecretRefForSetup, + resolveSecretInputModeForEnvSelection, +} from "../commands/auth-choice.apply-helpers.js"; +export { buildTokenProfileId, validateAnthropicSetupToken } from "../commands/auth-token.js"; +export { buildApiKeyCredential } from "../commands/onboard-auth.credentials.js"; +export { applyAuthProfileConfig } from "../commands/onboard-auth.js"; +export { githubCopilotLoginCommand } from "../providers/github-copilot-auth.js"; +export { loginOpenAICodexOAuth } from "../commands/openai-codex-oauth.js"; +export { createProviderApiKeyAuthMethod } from "../plugins/provider-api-key-auth.js"; +export { coerceSecretRef } from "../config/types.secrets.js"; +export { resolveDefaultSecretProviderAlias } from "../secrets/ref-contract.js"; +export { resolveRequiredHomeDir } from "../infra/home-dir.js"; +export { + normalizeOptionalSecretInput, + normalizeSecretInput, +} from "../utils/normalize-secret-input.js"; diff --git a/src/plugin-sdk/provider-models.ts b/src/plugin-sdk/provider-models.ts new file mode 100644 index 00000000000..5221daec1cd --- /dev/null +++ b/src/plugin-sdk/provider-models.ts @@ -0,0 +1,86 @@ +// Public model/catalog helpers for provider plugins. + +export type { + ModelApi, + ModelDefinitionConfig, + ModelProviderConfig, +} from "../config/types.models.js"; +export type { ProviderPlugin } from "../plugins/types.js"; + +export { DEFAULT_CONTEXT_TOKENS } from "../agents/defaults.js"; +export { normalizeModelCompat } from "../agents/model-compat.js"; +export { normalizeProviderId } from "../agents/provider-id.js"; + +export { + applyGoogleGeminiModelDefault, + GOOGLE_GEMINI_DEFAULT_MODEL, +} from "../commands/google-gemini-model-default.js"; +export { applyOpenAIConfig, OPENAI_DEFAULT_MODEL } from "../commands/openai-model-default.js"; +export { OPENCODE_GO_DEFAULT_MODEL_REF } from "../commands/opencode-go-model-default.js"; +export { OPENCODE_ZEN_DEFAULT_MODEL } from "../commands/opencode-zen-model-default.js"; +export { OPENCODE_ZEN_DEFAULT_MODEL_REF } from "../agents/opencode-zen-models.js"; + +export * from "../commands/onboard-auth.models.js"; + +export { + buildCloudflareAiGatewayModelDefinition, + CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF, + resolveCloudflareAiGatewayBaseUrl, +} from "../agents/cloudflare-ai-gateway.js"; +export { + discoverHuggingfaceModels, + HUGGINGFACE_BASE_URL, + HUGGINGFACE_MODEL_CATALOG, + buildHuggingfaceModelDefinition, +} from "../agents/huggingface-models.js"; +export { discoverKilocodeModels } from "../agents/kilocode-models.js"; +export { resolveOllamaApiBase } from "../agents/ollama-models.js"; +export { + buildSyntheticModelDefinition, + SYNTHETIC_BASE_URL, + SYNTHETIC_DEFAULT_MODEL_REF, + SYNTHETIC_MODEL_CATALOG, +} from "../agents/synthetic-models.js"; +export { + buildTogetherModelDefinition, + TOGETHER_BASE_URL, + TOGETHER_MODEL_CATALOG, +} from "../agents/together-models.js"; +export { + discoverVeniceModels, + VENICE_BASE_URL, + VENICE_DEFAULT_MODEL_REF, + VENICE_MODEL_CATALOG, + buildVeniceModelDefinition, +} from "../agents/venice-models.js"; +export { + BYTEPLUS_BASE_URL, + BYTEPLUS_CODING_BASE_URL, + BYTEPLUS_CODING_MODEL_CATALOG, + BYTEPLUS_MODEL_CATALOG, + buildBytePlusModelDefinition, +} from "../agents/byteplus-models.js"; +export { + DOUBAO_BASE_URL, + DOUBAO_CODING_BASE_URL, + DOUBAO_CODING_MODEL_CATALOG, + DOUBAO_MODEL_CATALOG, + buildDoubaoModelDefinition, +} from "../agents/doubao-models.js"; +export { OLLAMA_DEFAULT_BASE_URL } from "../agents/ollama-defaults.js"; +export { VLLM_DEFAULT_BASE_URL } from "../agents/vllm-defaults.js"; +export { SGLANG_DEFAULT_BASE_URL } from "../agents/sglang-defaults.js"; +export { + KILOCODE_BASE_URL, + KILOCODE_DEFAULT_CONTEXT_WINDOW, + KILOCODE_DEFAULT_COST, + KILOCODE_DEFAULT_MODEL_REF, + KILOCODE_DEFAULT_MAX_TOKENS, + KILOCODE_DEFAULT_MODEL_ID, + KILOCODE_DEFAULT_MODEL_NAME, + KILOCODE_MODEL_CATALOG, +} from "../providers/kilocode-shared.js"; +export { + discoverVercelAiGatewayModels, + VERCEL_AI_GATEWAY_BASE_URL, +} from "../agents/vercel-ai-gateway.js"; diff --git a/src/plugin-sdk/provider-onboard.ts b/src/plugin-sdk/provider-onboard.ts new file mode 100644 index 00000000000..b2175f092fe --- /dev/null +++ b/src/plugin-sdk/provider-onboard.ts @@ -0,0 +1,16 @@ +// Public config patch helpers for provider onboarding flows. + +export type { OpenClawConfig } from "../config/config.js"; +export type { + ModelApi, + ModelDefinitionConfig, + ModelProviderConfig, +} from "../config/types.models.js"; +export { + applyAgentDefaultModelPrimary, + applyOnboardAuthAgentModelsAndProviders, + applyProviderConfigWithDefaultModel, + applyProviderConfigWithDefaultModels, + applyProviderConfigWithModelCatalog, +} from "../commands/onboard-auth.config-shared.js"; +export { ensureModelAllowlistEntry } from "../commands/model-allowlist.js"; diff --git a/src/plugin-sdk/provider-stream.ts b/src/plugin-sdk/provider-stream.ts new file mode 100644 index 00000000000..19b8fe76092 --- /dev/null +++ b/src/plugin-sdk/provider-stream.ts @@ -0,0 +1,17 @@ +// Public stream-wrapper helpers for provider plugins. + +export { + createKilocodeWrapper, + createOpenRouterSystemCacheWrapper, + createOpenRouterWrapper, + isProxyReasoningUnsupported, +} from "../agents/pi-embedded-runner/proxy-stream-wrappers.js"; +export { + createMoonshotThinkingWrapper, + resolveMoonshotThinkingType, +} from "../agents/pi-embedded-runner/moonshot-stream-wrappers.js"; +export { createZaiToolStreamWrapper } from "../agents/pi-embedded-runner/zai-stream-wrappers.js"; +export { + getOpenRouterModelCapabilities, + loadOpenRouterModelCapabilities, +} from "../agents/pi-embedded-runner/openrouter-model-capabilities.js"; diff --git a/src/plugin-sdk/provider-usage.ts b/src/plugin-sdk/provider-usage.ts new file mode 100644 index 00000000000..33757596965 --- /dev/null +++ b/src/plugin-sdk/provider-usage.ts @@ -0,0 +1,21 @@ +// Public usage fetch helpers for provider plugins. + +export type { + ProviderUsageSnapshot, + UsageProviderId, + UsageWindow, +} from "../infra/provider-usage.types.js"; + +export { + fetchClaudeUsage, + fetchCodexUsage, + fetchGeminiUsage, + fetchMinimaxUsage, + fetchZaiUsage, +} from "../infra/provider-usage.fetch.js"; +export { clampPercent, PROVIDER_LABELS } from "../infra/provider-usage.shared.js"; +export { + buildUsageErrorSnapshot, + buildUsageHttpErrorSnapshot, + fetchJson, +} from "../infra/provider-usage.fetch.shared.js"; diff --git a/src/plugin-sdk/provider-web-search.ts b/src/plugin-sdk/provider-web-search.ts new file mode 100644 index 00000000000..551c3d5ed5d --- /dev/null +++ b/src/plugin-sdk/provider-web-search.ts @@ -0,0 +1,18 @@ +// Public web-search registration helpers for provider plugins. + +export { + createPluginBackedWebSearchProvider, + getScopedCredentialValue, + getTopLevelCredentialValue, + setScopedCredentialValue, + setTopLevelCredentialValue, +} from "../agents/tools/web-search-plugin-factory.js"; +export { withTrustedWebToolsEndpoint } from "../agents/tools/web-guarded-fetch.js"; +export { + DEFAULT_CACHE_TTL_MINUTES, + normalizeCacheKey, + readCache, + readResponseText, + resolveCacheTtlMs, + writeCache, +} from "../agents/tools/web-shared.js"; diff --git a/src/plugin-sdk/qwen-portal-auth.ts b/src/plugin-sdk/qwen-portal-auth.ts index 01533a77e8c..f6cde98b90f 100644 --- a/src/plugin-sdk/qwen-portal-auth.ts +++ b/src/plugin-sdk/qwen-portal-auth.ts @@ -8,4 +8,7 @@ export type { ProviderAuthContext, ProviderCatalogContext, } from "../plugins/types.js"; +export { ensureAuthProfileStore, listProfilesForProvider } from "../agents/auth-profiles.js"; +export { QWEN_OAUTH_MARKER } from "../agents/model-auth-markers.js"; +export { refreshQwenPortalCredentials } from "../providers/qwen-portal-oauth.js"; export { generatePkceVerifierChallenge, toFormUrlEncoded } from "./oauth-utils.js"; diff --git a/src/plugin-sdk/reply-runtime.ts b/src/plugin-sdk/reply-runtime.ts new file mode 100644 index 00000000000..689cf4cdba7 --- /dev/null +++ b/src/plugin-sdk/reply-runtime.ts @@ -0,0 +1,31 @@ +// Shared agent/reply runtime helpers for channel plugins. Keep channel plugins +// off direct src/auto-reply imports by routing common reply primitives here. + +export * from "../auto-reply/chunk.js"; +export * from "../auto-reply/command-auth.js"; +export * from "../auto-reply/command-detection.js"; +export * from "../auto-reply/commands-registry.js"; +export * from "../auto-reply/dispatch.js"; +export * from "../auto-reply/group-activation.js"; +export * from "../auto-reply/heartbeat.js"; +export * from "../auto-reply/heartbeat-reply-payload.js"; +export * from "../auto-reply/inbound-debounce.js"; +export * from "../auto-reply/reply.js"; +export * from "../auto-reply/tokens.js"; +export * from "../auto-reply/envelope.js"; +export * from "../auto-reply/reply/history.js"; +export * from "../auto-reply/reply/abort.js"; +export * from "../auto-reply/reply/btw-command.js"; +export * from "../auto-reply/reply/commands-models.js"; +export * from "../auto-reply/reply/inbound-dedupe.js"; +export * from "../auto-reply/reply/inbound-context.js"; +export * from "../auto-reply/reply/mentions.js"; +export * from "../auto-reply/reply/reply-dispatcher.js"; +export * from "../auto-reply/reply/reply-reference.js"; +export * from "../auto-reply/reply/provider-dispatcher.js"; +export * from "../auto-reply/reply/model-selection.js"; +export * from "../auto-reply/reply/commands-info.js"; +export * from "../auto-reply/skill-commands.js"; +export * from "../auto-reply/status.js"; +export type { ReplyPayload } from "../auto-reply/types.js"; +export type { FinalizedMsgContext, MsgContext } from "../auto-reply/templating.js"; diff --git a/src/plugin-sdk/routing.ts b/src/plugin-sdk/routing.ts index 921d085ae55..144304a607c 100644 --- a/src/plugin-sdk/routing.ts +++ b/src/plugin-sdk/routing.ts @@ -1,6 +1,31 @@ export { buildAgentSessionKey, + deriveLastRoutePolicy, + resolveAgentRoute, + resolveInboundLastRouteSessionKey, + type ResolvedAgentRoute, type RoutePeer, type RoutePeerKind, } from "../routing/resolve-route.js"; -export { resolveThreadSessionKeys } from "../routing/session-key.js"; +export { + buildAgentMainSessionKey, + DEFAULT_ACCOUNT_ID, + DEFAULT_MAIN_KEY, + buildGroupHistoryKey, + isCronSessionKey, + isSubagentSessionKey, + normalizeAccountId, + normalizeAgentId, + normalizeMainKey, + normalizeOptionalAccountId, + parseAgentSessionKey, + resolveAgentIdFromSessionKey, + resolveThreadSessionKeys, + sanitizeAgentId, +} from "../routing/session-key.js"; +export { resolveAccountEntry } from "../routing/account-lookup.js"; +export { listBoundAccountIds, resolveDefaultAgentBoundAccountId } from "../routing/bindings.js"; +export { + formatSetExplicitDefaultInstruction, + formatSetExplicitDefaultToConfiguredInstruction, +} from "../routing/default-account-warnings.js"; diff --git a/src/plugin-sdk/runtime-env.ts b/src/plugin-sdk/runtime-env.ts new file mode 100644 index 00000000000..c216bbbfbe6 --- /dev/null +++ b/src/plugin-sdk/runtime-env.ts @@ -0,0 +1,21 @@ +// Shared process/runtime utilities for plugins. This is the public boundary for +// logger wiring, runtime env shims, and global verbose console helpers. + +export type { RuntimeEnv } from "../runtime.js"; +export { createNonExitingRuntime, defaultRuntime } from "../runtime.js"; +export { + danger, + info, + isVerbose, + isYes, + logVerbose, + logVerboseConsole, + setVerbose, + setYes, + shouldLogVerbose, + success, + warn, +} from "../globals.js"; +export * from "../logging.js"; +export { waitForAbortSignal } from "../infra/abort-signal.js"; +export { registerUnhandledRejectionHandler } from "../infra/unhandled-rejections.js"; diff --git a/src/plugin-sdk/runtime-store.ts b/src/plugin-sdk/runtime-store.ts index 67e8bb3644c..34257c918b0 100644 --- a/src/plugin-sdk/runtime-store.ts +++ b/src/plugin-sdk/runtime-store.ts @@ -1,3 +1,5 @@ +export type { PluginRuntime } from "../plugins/runtime/types.js"; + /** Create a tiny mutable runtime slot with strict access when the runtime has not been initialized. */ export function createPluginRuntimeStore(errorMessage: string): { setRuntime: (next: T) => void; diff --git a/src/plugin-sdk/runtime.ts b/src/plugin-sdk/runtime.ts index 75b6f955dc7..ec39c97a549 100644 --- a/src/plugin-sdk/runtime.ts +++ b/src/plugin-sdk/runtime.ts @@ -1,5 +1,23 @@ import { format } from "node:util"; import type { RuntimeEnv } from "../runtime.js"; +export type { RuntimeEnv } from "../runtime.js"; +export { createNonExitingRuntime, defaultRuntime } from "../runtime.js"; +export { + danger, + info, + isVerbose, + isYes, + logVerbose, + logVerboseConsole, + setVerbose, + setYes, + shouldLogVerbose, + success, + warn, +} from "../globals.js"; +export * from "../logging.js"; +export { waitForAbortSignal } from "../infra/abort-signal.js"; +export { registerUnhandledRejectionHandler } from "../infra/unhandled-rejections.js"; type LoggerLike = { info: (message: string) => void; diff --git a/src/plugin-sdk/security-runtime.ts b/src/plugin-sdk/security-runtime.ts new file mode 100644 index 00000000000..4b7c42bbef3 --- /dev/null +++ b/src/plugin-sdk/security-runtime.ts @@ -0,0 +1,6 @@ +// Public security/policy helpers for plugins that need shared trust and DM gating logic. + +export * from "../security/channel-metadata.js"; +export * from "../security/dm-policy-shared.js"; +export * from "../security/external-content.js"; +export * from "../security/safe-regex.js"; diff --git a/src/plugin-sdk/setup.ts b/src/plugin-sdk/setup.ts index e77af2904c3..a2a7cf5c302 100644 --- a/src/plugin-sdk/setup.ts +++ b/src/plugin-sdk/setup.ts @@ -7,11 +7,16 @@ export type { WizardPrompter } from "../wizard/prompts.js"; export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js"; export type { ChannelSetupInput } from "../channels/plugins/types.core.js"; export type { ChannelSetupDmPolicy } from "../channels/plugins/setup-wizard-types.js"; +export type { ChannelSetupWizardAllowFromEntry } from "../channels/plugins/setup-wizard.js"; export type { ChannelSetupWizard } from "../channels/plugins/setup-wizard.js"; export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; +export { formatCliCommand } from "../cli/command-format.js"; +export { detectBinary } from "../commands/onboard-helpers.js"; +export { installSignalCli } from "../commands/signal-install.js"; export { formatDocsLink } from "../terminal/links.js"; export { hasConfiguredSecretInput, normalizeSecretInputString } from "../config/types.secrets.js"; +export { normalizeE164, pathExists } from "../utils.js"; export { applyAccountNameToChannelSection, @@ -23,10 +28,22 @@ export { addWildcardAllowFrom, buildSingleChannelSecretPromptState, mergeAllowFromEntries, + normalizeAllowFromEntries, + noteChannelLookupFailure, + noteChannelLookupSummary, + parseMentionOrPrefixedId, + parseSetupEntriesAllowingWildcard, + parseSetupEntriesWithParser, patchChannelConfigForAccount, + promptLegacyChannelAllowFrom, + promptParsedAllowFromForScopedChannel, promptSingleChannelSecretInput, + promptResolvedAllowFrom, resolveSetupAccountId, runSingleChannelSecretStep, + setAccountGroupPolicyForChannel, + setChannelDmPolicyWithAllowFrom, + setLegacyChannelDmPolicyWithAllowFrom, setSetupChannelEnabled, setTopLevelChannelAllowFrom, setTopLevelChannelDmPolicyWithAllowFrom, diff --git a/src/plugin-sdk/signal.ts b/src/plugin-sdk/signal.ts index 8fd6fd2afd0..f7d3ec2d84d 100644 --- a/src/plugin-sdk/signal.ts +++ b/src/plugin-sdk/signal.ts @@ -1,5 +1,7 @@ export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js"; +export type { OpenClawConfig } from "../config/config.js"; export type { SignalAccountConfig } from "../config/types.js"; +export type { ResolvedSignalAccount } from "../../extensions/signal/src/accounts.js"; export type { ChannelMessageActionContext, ChannelPlugin, @@ -40,3 +42,16 @@ export { collectStatusIssuesFromLastError, createDefaultChannelRuntimeState, } from "./status-helpers.js"; + +export { + listEnabledSignalAccounts, + listSignalAccountIds, + resolveDefaultSignalAccountId, + resolveSignalAccount, +} from "../../extensions/signal/src/accounts.js"; +export { resolveSignalReactionLevel } from "../../extensions/signal/src/reaction-level.js"; +export { + removeReactionSignal, + sendReactionSignal, +} from "../../extensions/signal/src/send-reactions.js"; +export { sendMessageSignal } from "../../extensions/signal/src/send.js"; diff --git a/src/plugin-sdk/slack.ts b/src/plugin-sdk/slack.ts index f7533b95687..b883aebac95 100644 --- a/src/plugin-sdk/slack.ts +++ b/src/plugin-sdk/slack.ts @@ -1,5 +1,7 @@ export type { OpenClawConfig } from "../config/config.js"; export type { SlackAccountConfig } from "../config/types.slack.js"; +export type { InspectedSlackAccount } from "../../extensions/slack/src/account-inspect.js"; +export type { ResolvedSlackAccount } from "../../extensions/slack/src/accounts.js"; export type { ChannelMessageActionContext, ChannelPlugin, @@ -43,3 +45,40 @@ export { } from "../channels/plugins/group-mentions.js"; export { SlackConfigSchema } from "../config/zod-schema.providers-core.js"; export { buildComputedAccountStatusSnapshot } from "./status-helpers.js"; + +export { + listEnabledSlackAccounts, + listSlackAccountIds, + resolveDefaultSlackAccountId, + resolveSlackAccount, + resolveSlackReplyToMode, +} from "../../extensions/slack/src/accounts.js"; +export { isSlackInteractiveRepliesEnabled } from "../../extensions/slack/src/interactive-replies.js"; +export { inspectSlackAccount } from "../../extensions/slack/src/account-inspect.js"; +export { parseSlackTarget, resolveSlackChannelId } from "./slack-targets.js"; +export { + extractSlackToolSend, + listSlackMessageActions, +} from "../../extensions/slack/src/message-actions.js"; +export { buildSlackThreadingToolContext } from "../../extensions/slack/src/threading-tool-context.js"; +export { parseSlackBlocksInput } from "../../extensions/slack/src/blocks-input.js"; +export { handleSlackHttpRequest } from "../../extensions/slack/src/http/index.js"; +export { sendMessageSlack } from "../../extensions/slack/src/send.js"; +export { + deleteSlackMessage, + downloadSlackFile, + editSlackMessage, + getSlackMemberInfo, + listSlackEmojis, + listSlackPins, + listSlackReactions, + pinSlackMessage, + reactSlackMessage, + readSlackMessages, + removeOwnSlackReactions, + removeSlackReaction, + sendSlackMessage, + unpinSlackMessage, +} from "../../extensions/slack/src/actions.js"; +export { recordSlackThreadParticipation } from "../../extensions/slack/src/sent-thread-cache.js"; +export { handleSlackMessageAction } from "./slack-message-actions.js"; diff --git a/src/plugin-sdk/speech.ts b/src/plugin-sdk/speech.ts new file mode 100644 index 00000000000..3fb9758ffdc --- /dev/null +++ b/src/plugin-sdk/speech.ts @@ -0,0 +1,7 @@ +// Public speech-provider builders for bundled or third-party plugins. + +export { buildElevenLabsSpeechProvider } from "../tts/providers/elevenlabs.js"; +export { buildMicrosoftSpeechProvider } from "../tts/providers/microsoft.js"; +export { buildOpenAISpeechProvider } from "../tts/providers/openai.js"; +export { parseTtsDirectives } from "../tts/tts-core.js"; +export type { SpeechVoiceOption } from "../tts/provider-types.js"; diff --git a/src/plugin-sdk/state-paths.ts b/src/plugin-sdk/state-paths.ts new file mode 100644 index 00000000000..aeae39fa1f1 --- /dev/null +++ b/src/plugin-sdk/state-paths.ts @@ -0,0 +1,3 @@ +// Public state/config path helpers for plugins that persist small caches. + +export { resolveOAuthDir, resolveStateDir, STATE_DIR } from "../config/paths.js"; diff --git a/src/plugin-sdk/telegram.ts b/src/plugin-sdk/telegram.ts index 6551baffe87..cb26a82cb13 100644 --- a/src/plugin-sdk/telegram.ts +++ b/src/plugin-sdk/telegram.ts @@ -12,9 +12,18 @@ export type { 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"; +export type { + TelegramButtonStyle, + TelegramInlineButtons, +} from "../../extensions/telegram/src/button-types.js"; +export type { StickerMetadata } from "../../extensions/telegram/src/bot/types.js"; export { emptyPluginConfigSchema } from "../plugins/config-schema.js"; export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js"; +export { parseTelegramTopicConversation } from "../acp/conversation-id.js"; export { PAIRING_APPROVED_MESSAGE, @@ -28,6 +37,7 @@ export { } from "./channel-plugin-common.js"; export { clearAccountEntryFields } from "../channels/plugins/config-helpers.js"; +export { resolveTelegramPollVisibility } from "../poll-params.js"; export { projectCredentialSnapshotFields, @@ -49,3 +59,57 @@ export { export { TelegramConfigSchema } from "../config/zod-schema.providers-core.js"; export { buildTokenChannelStatusSummary } from "./status-helpers.js"; + +export { + createTelegramActionGate, + listTelegramAccountIds, + resolveDefaultTelegramAccountId, + resolveTelegramPollActionGateState, + resolveTelegramAccount, +} from "../../extensions/telegram/src/accounts.js"; +export { inspectTelegramAccount } from "../../extensions/telegram/src/account-inspect.js"; +export { + looksLikeTelegramTargetId, + normalizeTelegramMessagingTarget, +} from "../../extensions/telegram/src/normalize.js"; +export { + parseTelegramReplyToMessageId, + parseTelegramThreadId, +} from "../../extensions/telegram/src/outbound-params.js"; +export { + isNumericTelegramUserId, + normalizeTelegramAllowFromEntry, +} from "../../extensions/telegram/src/allow-from.js"; +export { fetchTelegramChatId } from "../../extensions/telegram/src/api-fetch.js"; +export { + resolveTelegramInlineButtonsScope, + resolveTelegramTargetChatType, +} from "../../extensions/telegram/src/inline-buttons.js"; +export { resolveTelegramReactionLevel } from "../../extensions/telegram/src/reaction-level.js"; +export { + createForumTopicTelegram, + deleteMessageTelegram, + editForumTopicTelegram, + editMessageTelegram, + reactMessageTelegram, + sendMessageTelegram, + sendPollTelegram, + sendStickerTelegram, +} from "../../extensions/telegram/src/send.js"; +export { getCacheStats, searchStickers } from "../../extensions/telegram/src/sticker-cache.js"; +export { resolveTelegramToken } from "../../extensions/telegram/src/token.js"; +export { telegramMessageActions } from "../../extensions/telegram/src/channel-actions.js"; +export { collectTelegramStatusIssues } from "../../extensions/telegram/src/status-issues.js"; +export { sendTelegramPayloadMessages } from "../../extensions/telegram/src/outbound-adapter.js"; +export { + buildBrowseProvidersButton, + buildModelsKeyboard, + buildProviderKeyboard, + calculateTotalPages, + getModelsPageSize, + type ProviderInfo, +} from "../../extensions/telegram/src/model-buttons.js"; +export { + isTelegramExecApprovalApprover, + isTelegramExecApprovalClientEnabled, +} from "../../extensions/telegram/src/exec-approvals.js"; diff --git a/src/plugin-sdk/test-utils.ts b/src/plugin-sdk/test-utils.ts index 78307f694a6..5d825813d0e 100644 --- a/src/plugin-sdk/test-utils.ts +++ b/src/plugin-sdk/test-utils.ts @@ -6,3 +6,4 @@ export type { ChannelAccountSnapshot, ChannelGatewayContext } from "../channels/ export type { OpenClawConfig } from "../config/config.js"; export type { PluginRuntime } from "../plugins/runtime/types.js"; export type { RuntimeEnv } from "../runtime.js"; +export type { MockFn } from "../test-utils/vitest-mock-fn.js"; diff --git a/src/plugin-sdk/text-runtime.ts b/src/plugin-sdk/text-runtime.ts new file mode 100644 index 00000000000..bfdb2db690f --- /dev/null +++ b/src/plugin-sdk/text-runtime.ts @@ -0,0 +1,23 @@ +// Public shared text/formatting helpers for plugins that parse or rewrite message text. + +export * from "../logger.js"; +export * from "../logging/diagnostic.js"; +export * from "../logging/logger.js"; +export * from "../logging/redact.js"; +export * from "../logging/redact-identifier.js"; +export * from "../markdown/ir.js"; +export * from "../markdown/render.js"; +export * from "../markdown/tables.js"; +export * from "../markdown/whatsapp.js"; +export * from "../shared/global-singleton.js"; +export * from "../shared/string-normalization.js"; +export * from "../shared/string-sample.js"; +export * from "../shared/text/assistant-visible-text.js"; +export * from "../shared/text/code-regions.js"; +export * from "../shared/text/reasoning-tags.js"; +export * from "../terminal/safe-text.js"; +export * from "../utils.js"; +export * from "../utils/chunk-items.js"; +export * from "../utils/fetch-timeout.js"; +export * from "../utils/reaction-level.js"; +export * from "../utils/with-timeout.js"; diff --git a/src/plugin-sdk/whatsapp.ts b/src/plugin-sdk/whatsapp.ts index df814fa04eb..3727cc802ec 100644 --- a/src/plugin-sdk/whatsapp.ts +++ b/src/plugin-sdk/whatsapp.ts @@ -1,6 +1,14 @@ export type { ChannelMessageActionName } from "../channels/plugins/types.js"; export type { OpenClawConfig } from "../config/config.js"; export type { DmPolicy, GroupPolicy, WhatsAppAccountConfig } from "../config/types.js"; +export type { + WebChannelStatus, + WebMonitorTuning, +} from "../../extensions/whatsapp/src/auto-reply.js"; +export type { + WebInboundMessage, + WebListenerCloseReason, +} from "../../extensions/whatsapp/src/inbound.js"; export type { ChannelMessageActionContext, ChannelPlugin, @@ -36,6 +44,7 @@ export { } from "../channels/plugins/group-policy-warnings.js"; export { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js"; export { resolveWhatsAppOutboundTarget } from "../whatsapp/resolve-outbound-target.js"; +export { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../whatsapp/normalize.js"; export { resolveAllowlistProviderRuntimeGroupPolicy, @@ -56,3 +65,48 @@ export { WhatsAppConfigSchema } from "../config/zod-schema.providers-whatsapp.js export { createActionGate, readStringParam } from "../agents/tools/common.js"; export { createPluginRuntimeStore } from "./runtime-store.js"; export { normalizeE164 } from "../utils.js"; + +export { + hasAnyWhatsAppAuth, + listEnabledWhatsAppAccounts, + resolveWhatsAppAccount, +} from "../../extensions/whatsapp/src/accounts.js"; +export { + WA_WEB_AUTH_DIR, + logWebSelfId, + logoutWeb, + pickWebChannel, + webAuthExists, +} from "../../extensions/whatsapp/src/auth-store.js"; +export { + DEFAULT_WEB_MEDIA_BYTES, + HEARTBEAT_PROMPT, + HEARTBEAT_TOKEN, + monitorWebChannel, + resolveHeartbeatRecipients, + runWebHeartbeatOnce, +} from "../../extensions/whatsapp/src/auto-reply.js"; +export { + extractMediaPlaceholder, + extractText, + monitorWebInbox, +} from "../../extensions/whatsapp/src/inbound.js"; +export { loginWeb } from "../../extensions/whatsapp/src/login.js"; +export { + getDefaultLocalRoots, + loadWebMedia, + loadWebMediaRaw, + optimizeImageToJpeg, +} from "../../extensions/whatsapp/src/media.js"; +export { + sendMessageWhatsApp, + sendPollWhatsApp, + sendReactionWhatsApp, +} from "../../extensions/whatsapp/src/send.js"; +export { + createWaSocket, + formatError, + getStatusCode, + waitForWaConnection, +} from "../../extensions/whatsapp/src/session.js"; +export { createWhatsAppLoginTool } from "../../extensions/whatsapp/src/agent-tools-login.js"; diff --git a/src/plugin-sdk/zai.ts b/src/plugin-sdk/zai.ts new file mode 100644 index 00000000000..6981a0994bf --- /dev/null +++ b/src/plugin-sdk/zai.ts @@ -0,0 +1,7 @@ +// Public Z.ai helpers for provider plugins that need endpoint detection. + +export { + detectZaiEndpoint, + type ZaiDetectedEndpoint, + type ZaiEndpointId, +} from "../commands/zai-endpoint-detect.js"; diff --git a/src/security/audit-channel.runtime.ts b/src/security/audit-channel.runtime.ts index c3435fc2a64..867f0a91162 100644 --- a/src/security/audit-channel.runtime.ts +++ b/src/security/audit-channel.runtime.ts @@ -6,4 +6,4 @@ export { export { isNumericTelegramUserId, normalizeTelegramAllowFromEntry, -} from "../plugin-sdk-internal/telegram.js"; +} from "../plugin-sdk/telegram.js";