mirror of https://github.com/openclaw/openclaw.git
plugin-sdk: add channel subpaths and migrate bundled plugins
This commit is contained in:
parent
1c200ca7ae
commit
1278ee9248
|
|
@ -17,6 +17,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Plugins/startup loading: lazily initialize plugin runtime, split startup-critical plugin SDK imports into `openclaw/plugin-sdk/core` and `openclaw/plugin-sdk/telegram`, and preserve `api.runtime` reflection semantics for plugin compatibility. (#28620) thanks @hmemcpy.
|
||||
- Build/lazy runtime boundaries: replace ineffective dynamic import sites with dedicated lazy runtime boundaries across Slack slash handling, Telegram audit, CLI send deps, memory fallback, and outbound delivery paths while preserving behavior. (#33690) thanks @gumadeiras.
|
||||
- Config/heartbeat legacy-path handling: auto-migrate top-level `heartbeat` into `agents.defaults.heartbeat` (with merge semantics that preserve explicit defaults), and keep startup failures on non-migratable legacy entries in the detailed invalid-config path instead of generic migration-failed errors. (#32706) thanks @xiwan.
|
||||
- Plugins/SDK subpath parity: add channel-specific plugin SDK subpaths for Discord, Slack, Signal, iMessage, WhatsApp, and LINE; migrate bundled plugin entrypoints to scoped subpaths/core with CI guardrails; and keep `openclaw/plugin-sdk` root import compatibility for existing external plugins. (#33737) thanks @gumadeiras.
|
||||
- Security/auth labels: remove token and API-key snippets from user-facing auth status labels so `/status` and `/models` do not expose credential fragments. (#33262) thanks @cu1ch3n.
|
||||
- Auth/credential semantics: align profile eligibility + probe diagnostics with SecretRef/expiry rules and harden browser download atomic writes. (#33733) thanks @joshavant.
|
||||
- Security/audit denyCommands guidance: suggest likely exact node command IDs for unknown `gateway.nodes.denyCommands` entries so ineffective denylist entries are easier to correct. (#29713) thanks @liquidhorizon88-bot.
|
||||
|
|
|
|||
|
|
@ -106,6 +106,26 @@ Notes:
|
|||
- Uses core media-understanding audio configuration (`tools.media.audio`) and provider fallback order.
|
||||
- Returns `{ text: undefined }` when no transcription output is produced (for example skipped/unsupported input).
|
||||
|
||||
## Plugin SDK import paths
|
||||
|
||||
Use SDK subpaths instead of the monolithic `openclaw/plugin-sdk` import when
|
||||
authoring plugins:
|
||||
|
||||
- `openclaw/plugin-sdk/core` for generic plugin APIs, provider auth types, and shared helpers.
|
||||
- `openclaw/plugin-sdk/telegram` for Telegram channel plugins.
|
||||
- `openclaw/plugin-sdk/discord` for Discord channel plugins.
|
||||
- `openclaw/plugin-sdk/slack` for Slack channel plugins.
|
||||
- `openclaw/plugin-sdk/signal` for Signal channel plugins.
|
||||
- `openclaw/plugin-sdk/imessage` for iMessage channel plugins.
|
||||
- `openclaw/plugin-sdk/whatsapp` for WhatsApp channel plugins.
|
||||
- `openclaw/plugin-sdk/line` for LINE channel plugins.
|
||||
|
||||
Compatibility note:
|
||||
|
||||
- `openclaw/plugin-sdk` remains supported for existing external plugins.
|
||||
- New and migrated bundled plugins should use channel subpaths (or `core`) to
|
||||
keep startup imports scoped.
|
||||
|
||||
## Discovery & precedence
|
||||
|
||||
OpenClaw scans, in order:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { createAcpxPluginConfigSchema } from "./src/config.js";
|
||||
import { createAcpxRuntimeService } from "./src/service.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { bluebubblesPlugin } from "./src/channel.js";
|
||||
import { setBlueBubblesRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
type OpenClawPluginApi,
|
||||
type ProviderAuthContext,
|
||||
type ProviderAuthResult,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/core";
|
||||
|
||||
const DEFAULT_BASE_URL = "http://localhost:3000/v1";
|
||||
const DEFAULT_API_KEY = "n/a";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { listDevicePairing } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { listDevicePairing } from "openclaw/plugin-sdk/core";
|
||||
|
||||
const NOTIFY_STATE_FILE = "device-pair-notify.json";
|
||||
const NOTIFY_POLL_INTERVAL_MS = 10_000;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { createDiagnosticsOtelService } from "./src/service.js";
|
||||
|
||||
const plugin = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import path from "node:path";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/core";
|
||||
import {
|
||||
diffsPluginConfigSchema,
|
||||
resolveDiffsPluginDefaults,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/discord";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/discord";
|
||||
import { discordPlugin } from "./src/channel.js";
|
||||
import { setDiscordRuntime } from "./src/runtime.js";
|
||||
import { registerDiscordSubagentHooks } from "./src/subagent-hooks.js";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk/discord";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { discordPlugin } from "./channel.js";
|
||||
import { setDiscordRuntime } from "./runtime.js";
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import {
|
|||
type ChannelMessageActionAdapter,
|
||||
type ChannelPlugin,
|
||||
type ResolvedDiscordAccount,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/discord";
|
||||
import { getDiscordRuntime } from "./runtime.js";
|
||||
|
||||
const meta = getChatChannelMeta("discord");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk/discord";
|
||||
|
||||
let runtime: PluginRuntime | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/discord";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerDiscordSubagentHooks } from "./subagent-hooks.js";
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ const hookMocks = vi.hoisted(() => ({
|
|||
unbindThreadBindingsBySessionKey: vi.fn(() => []),
|
||||
}));
|
||||
|
||||
vi.mock("openclaw/plugin-sdk", () => ({
|
||||
vi.mock("openclaw/plugin-sdk/discord", () => ({
|
||||
resolveDiscordAccount: hookMocks.resolveDiscordAccount,
|
||||
autoBindSpawnedDiscordSubagent: hookMocks.autoBindSpawnedDiscordSubagent,
|
||||
listThreadBindingsBySessionKey: hookMocks.listThreadBindingsBySessionKey,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/discord";
|
||||
import {
|
||||
autoBindSpawnedDiscordSubagent,
|
||||
listThreadBindingsBySessionKey,
|
||||
resolveDiscordAccount,
|
||||
unbindThreadBindingsBySessionKey,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/discord";
|
||||
|
||||
function summarizeError(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { registerFeishuBitableTools } from "./src/bitable.js";
|
||||
import { feishuPlugin } from "./src/channel.js";
|
||||
import { registerFeishuChatTools } from "./src/chat.js";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
emptyPluginConfigSchema,
|
||||
type OpenClawPluginApi,
|
||||
type ProviderAuthContext,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/core";
|
||||
import { loginGeminiCliOAuth } from "./oauth.js";
|
||||
|
||||
const PROVIDER_ID = "google-gemini-cli";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { googlechatDock, googlechatPlugin } from "./src/channel.js";
|
||||
import { setGoogleChatRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"google-auth-library": "^10.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"openclaw": ">=2026.3.1"
|
||||
"openclaw": ">=2026.3.2"
|
||||
},
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/imessage";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/imessage";
|
||||
import { imessagePlugin } from "./src/channel.js";
|
||||
import { setIMessageRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import {
|
|||
setAccountEnabledInConfigSection,
|
||||
type ChannelPlugin,
|
||||
type ResolvedIMessageAccount,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/imessage";
|
||||
import { getIMessageRuntime } from "./runtime.js";
|
||||
|
||||
const meta = getChatChannelMeta("imessage");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk/imessage";
|
||||
|
||||
let runtime: PluginRuntime | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ChannelPlugin, OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { ChannelPlugin, OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { ircPlugin } from "./src/channel.js";
|
||||
import { setIrcRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/line";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/line";
|
||||
import { registerLineCardCommand } from "./src/card-command.js";
|
||||
import { linePlugin } from "./src/channel.js";
|
||||
import { setLineRuntime } from "./src/runtime.js";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { LineChannelData, OpenClawPluginApi, ReplyPayload } from "openclaw/plugin-sdk";
|
||||
import type { LineChannelData, OpenClawPluginApi, ReplyPayload } from "openclaw/plugin-sdk/line";
|
||||
import {
|
||||
createActionCard,
|
||||
createImageCard,
|
||||
|
|
@ -7,7 +7,7 @@ import {
|
|||
createReceiptCard,
|
||||
type CardAction,
|
||||
type ListItem,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/line";
|
||||
|
||||
const CARD_USAGE = `Usage: /card <type> "title" "body" [options]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenClawConfig, PluginRuntime, ResolvedLineAccount } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawConfig, PluginRuntime, ResolvedLineAccount } from "openclaw/plugin-sdk/line";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createRuntimeEnv } from "../../test-utils/runtime-env.js";
|
||||
import { linePlugin } from "./channel.js";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk/line";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { linePlugin } from "./channel.js";
|
||||
import { setLineRuntime } from "./runtime.js";
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type {
|
|||
OpenClawConfig,
|
||||
PluginRuntime,
|
||||
ResolvedLineAccount,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/line";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createRuntimeEnv } from "../../test-utils/runtime-env.js";
|
||||
import { linePlugin } from "./channel.js";
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
type LineConfig,
|
||||
type LineChannelData,
|
||||
type ResolvedLineAccount,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/line";
|
||||
import { getLineRuntime } from "./runtime.js";
|
||||
|
||||
// LINE channel metadata
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk/line";
|
||||
|
||||
let runtime: PluginRuntime | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { matrixPlugin } from "./src/channel.js";
|
||||
import { ensureMatrixCryptoRuntime } from "./src/matrix/deps.js";
|
||||
import { setMatrixRuntime } from "./src/runtime.js";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { mattermostPlugin } from "./src/channel.js";
|
||||
import { getSlashCommandState, registerSlashCommandRoute } from "./src/mattermost/slash-state.js";
|
||||
import { setMattermostRuntime } from "./src/runtime.js";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
"description": "OpenClaw core memory search plugin",
|
||||
"type": "module",
|
||||
"peerDependencies": {
|
||||
"openclaw": ">=2026.3.1"
|
||||
"openclaw": ">=2026.3.2"
|
||||
},
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { randomUUID } from "node:crypto";
|
|||
import type * as LanceDB from "@lancedb/lancedb";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import OpenAI from "openai";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import {
|
||||
DEFAULT_CAPTURE_MAX_CHARS,
|
||||
MEMORY_CATEGORIES,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
type OpenClawPluginApi,
|
||||
type ProviderAuthContext,
|
||||
type ProviderAuthResult,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/core";
|
||||
import { loginMiniMaxPortalOAuth, type MiniMaxRegion } from "./oauth.js";
|
||||
|
||||
const PROVIDER_ID = "minimax-portal";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { msteamsPlugin } from "./src/channel.js";
|
||||
import { setMSTeamsRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { nextcloudTalkPlugin } from "./src/channel.js";
|
||||
import { setNextcloudTalkRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { nostrPlugin } from "./src/channel.js";
|
||||
import type { NostrProfile } from "./src/config-schema.js";
|
||||
import { createNostrProfileHttpHandler } from "./src/nostr-profile-http.js";
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {
|
|||
emptyPluginConfigSchema,
|
||||
type OpenClawPluginApi,
|
||||
type ProviderAuthContext,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/core";
|
||||
import { loginQwenPortalOAuth } from "./oauth.js";
|
||||
|
||||
const PROVIDER_ID = "qwen-portal";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/signal";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/signal";
|
||||
import { signalPlugin } from "./src/channel.js";
|
||||
import { setSignalRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import {
|
|||
type ChannelMessageActionAdapter,
|
||||
type ChannelPlugin,
|
||||
type ResolvedSignalAccount,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/signal";
|
||||
import { getSignalRuntime } from "./runtime.js";
|
||||
|
||||
const signalMessageActions: ChannelMessageActionAdapter = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk/signal";
|
||||
|
||||
let runtime: PluginRuntime | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/slack";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/slack";
|
||||
import { slackPlugin } from "./src/channel.js";
|
||||
import { setSlackRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/slack";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const handleSlackActionMock = vi.fn();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import {
|
|||
SlackConfigSchema,
|
||||
type ChannelPlugin,
|
||||
type ResolvedSlackAccount,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/slack";
|
||||
import { getSlackRuntime } from "./runtime.js";
|
||||
|
||||
const meta = getChatChannelMeta("slack");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk/slack";
|
||||
|
||||
let runtime: PluginRuntime | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { createSynologyChatPlugin } from "./src/channel.js";
|
||||
import { setSynologyRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { OpenClawConfig, OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawConfig, OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
|
||||
type ThreadOwnershipConfig = {
|
||||
forwarderUrl?: string;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { spawn } from "node:child_process";
|
|||
import { existsSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { tlonPlugin } from "./src/channel.js";
|
||||
import { setTlonRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { twitchPlugin } from "./src/plugin.js";
|
||||
import { setTwitchRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Type } from "@sinclair/typebox";
|
||||
import type { GatewayRequestHandlerOptions, OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import type { GatewayRequestHandlerOptions, OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { registerVoiceCallCli } from "./src/cli.js";
|
||||
import {
|
||||
VoiceCallConfigSchema,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/whatsapp";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/whatsapp";
|
||||
import { whatsappPlugin } from "./src/channel.js";
|
||||
import { setWhatsAppRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import {
|
|||
type ChannelMessageActionName,
|
||||
type ChannelPlugin,
|
||||
type ResolvedWhatsAppAccount,
|
||||
} from "openclaw/plugin-sdk";
|
||||
} from "openclaw/plugin-sdk/whatsapp";
|
||||
import { getWhatsAppRuntime } from "./runtime.js";
|
||||
|
||||
const meta = getChatChannelMeta("whatsapp");
|
||||
|
|
|
|||
|
|
@ -1,82 +1,60 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { installCommonResolveTargetErrorCases } from "../../shared/resolve-target-test-helpers.js";
|
||||
|
||||
vi.mock("openclaw/plugin-sdk", () => ({
|
||||
getChatChannelMeta: () => ({ id: "whatsapp", label: "WhatsApp" }),
|
||||
normalizeWhatsAppTarget: (value: string) => {
|
||||
vi.mock("openclaw/plugin-sdk/whatsapp", async () => {
|
||||
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/whatsapp")>(
|
||||
"openclaw/plugin-sdk/whatsapp",
|
||||
);
|
||||
const normalizeWhatsAppTarget = (value: string) => {
|
||||
if (value === "invalid-target") return null;
|
||||
// Simulate E.164 normalization: strip leading + and whatsapp: prefix
|
||||
// Simulate E.164 normalization: strip leading + and whatsapp: prefix.
|
||||
const stripped = value.replace(/^whatsapp:/i, "").replace(/^\+/, "");
|
||||
return stripped.includes("@g.us") ? stripped : `${stripped}@s.whatsapp.net`;
|
||||
},
|
||||
isWhatsAppGroupJid: (value: string) => value.endsWith("@g.us"),
|
||||
resolveWhatsAppOutboundTarget: ({
|
||||
to,
|
||||
allowFrom,
|
||||
mode,
|
||||
}: {
|
||||
to?: string;
|
||||
allowFrom: string[];
|
||||
mode: "explicit" | "implicit";
|
||||
}) => {
|
||||
const raw = typeof to === "string" ? to.trim() : "";
|
||||
if (!raw) {
|
||||
return { ok: false, error: new Error("missing target") };
|
||||
}
|
||||
const normalizeWhatsAppTarget = (value: string) => {
|
||||
if (value === "invalid-target") return null;
|
||||
const stripped = value.replace(/^whatsapp:/i, "").replace(/^\+/, "");
|
||||
return stripped.includes("@g.us") ? stripped : `${stripped}@s.whatsapp.net`;
|
||||
};
|
||||
const normalized = normalizeWhatsAppTarget(raw);
|
||||
if (!normalized) {
|
||||
return { ok: false, error: new Error("invalid target") };
|
||||
}
|
||||
};
|
||||
|
||||
if (mode === "implicit" && !normalized.endsWith("@g.us")) {
|
||||
const allowAll = allowFrom.includes("*");
|
||||
const allowExact = allowFrom.some((entry) => {
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
const normalizedEntry = normalizeWhatsAppTarget(entry.trim());
|
||||
return normalizedEntry?.toLowerCase() === normalized.toLowerCase();
|
||||
});
|
||||
if (!allowAll && !allowExact) {
|
||||
return { ok: false, error: new Error("target not allowlisted") };
|
||||
return {
|
||||
...actual,
|
||||
getChatChannelMeta: () => ({ id: "whatsapp", label: "WhatsApp" }),
|
||||
normalizeWhatsAppTarget,
|
||||
isWhatsAppGroupJid: (value: string) => value.endsWith("@g.us"),
|
||||
resolveWhatsAppOutboundTarget: ({
|
||||
to,
|
||||
allowFrom,
|
||||
mode,
|
||||
}: {
|
||||
to?: string;
|
||||
allowFrom: string[];
|
||||
mode: "explicit" | "implicit";
|
||||
}) => {
|
||||
const raw = typeof to === "string" ? to.trim() : "";
|
||||
if (!raw) {
|
||||
return { ok: false, error: new Error("missing target") };
|
||||
}
|
||||
const normalized = normalizeWhatsAppTarget(raw);
|
||||
if (!normalized) {
|
||||
return { ok: false, error: new Error("invalid target") };
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: true, to: normalized };
|
||||
},
|
||||
missingTargetError: (provider: string, hint: string) =>
|
||||
new Error(`Delivering to ${provider} requires target ${hint}`),
|
||||
WhatsAppConfigSchema: {},
|
||||
whatsappOnboardingAdapter: {},
|
||||
resolveWhatsAppHeartbeatRecipients: vi.fn(),
|
||||
buildChannelConfigSchema: vi.fn(),
|
||||
collectWhatsAppStatusIssues: vi.fn(),
|
||||
createActionGate: vi.fn(),
|
||||
DEFAULT_ACCOUNT_ID: "default",
|
||||
escapeRegExp: vi.fn(),
|
||||
formatPairingApproveHint: vi.fn(),
|
||||
listWhatsAppAccountIds: vi.fn(),
|
||||
listWhatsAppDirectoryGroupsFromConfig: vi.fn(),
|
||||
listWhatsAppDirectoryPeersFromConfig: vi.fn(),
|
||||
looksLikeWhatsAppTargetId: vi.fn(),
|
||||
migrateBaseNameToDefaultAccount: vi.fn(),
|
||||
normalizeAccountId: vi.fn(),
|
||||
normalizeE164: vi.fn(),
|
||||
normalizeWhatsAppMessagingTarget: vi.fn(),
|
||||
readStringParam: vi.fn(),
|
||||
resolveDefaultWhatsAppAccountId: vi.fn(),
|
||||
resolveWhatsAppAccount: vi.fn(),
|
||||
resolveWhatsAppGroupIntroHint: vi.fn(),
|
||||
resolveWhatsAppGroupRequireMention: vi.fn(),
|
||||
resolveWhatsAppGroupToolPolicy: vi.fn(),
|
||||
resolveWhatsAppMentionStripPatterns: vi.fn(() => []),
|
||||
applyAccountNameToChannelSection: vi.fn(),
|
||||
}));
|
||||
if (mode === "implicit" && !normalized.endsWith("@g.us")) {
|
||||
const allowAll = allowFrom.includes("*");
|
||||
const allowExact = allowFrom.some((entry) => {
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
const normalizedEntry = normalizeWhatsAppTarget(entry.trim());
|
||||
return normalizedEntry?.toLowerCase() === normalized.toLowerCase();
|
||||
});
|
||||
if (!allowAll && !allowExact) {
|
||||
return { ok: false, error: new Error("target not allowlisted") };
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: true, to: normalized };
|
||||
},
|
||||
missingTargetError: (provider: string, hint: string) =>
|
||||
new Error(`Delivering to ${provider} requires target ${hint}`),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./runtime.js", () => ({
|
||||
getWhatsAppRuntime: vi.fn(() => ({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk/whatsapp";
|
||||
|
||||
let runtime: PluginRuntime | null = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { zaloDock, zaloPlugin } from "./src/channel.js";
|
||||
import { setZaloRuntime } from "./src/runtime.js";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { AnyAgentTool, OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
||||
import type { AnyAgentTool, OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
import { zalouserDock, zalouserPlugin } from "./src/channel.js";
|
||||
import { setZalouserRuntime } from "./src/runtime.js";
|
||||
import { ZalouserToolSchema, executeZalouserTool } from "./src/tool.js";
|
||||
|
|
|
|||
27
package.json
27
package.json
|
|
@ -48,6 +48,30 @@
|
|||
"types": "./dist/plugin-sdk/telegram.d.ts",
|
||||
"default": "./dist/plugin-sdk/telegram.js"
|
||||
},
|
||||
"./plugin-sdk/discord": {
|
||||
"types": "./dist/plugin-sdk/discord.d.ts",
|
||||
"default": "./dist/plugin-sdk/discord.js"
|
||||
},
|
||||
"./plugin-sdk/slack": {
|
||||
"types": "./dist/plugin-sdk/slack.d.ts",
|
||||
"default": "./dist/plugin-sdk/slack.js"
|
||||
},
|
||||
"./plugin-sdk/signal": {
|
||||
"types": "./dist/plugin-sdk/signal.d.ts",
|
||||
"default": "./dist/plugin-sdk/signal.js"
|
||||
},
|
||||
"./plugin-sdk/imessage": {
|
||||
"types": "./dist/plugin-sdk/imessage.d.ts",
|
||||
"default": "./dist/plugin-sdk/imessage.js"
|
||||
},
|
||||
"./plugin-sdk/whatsapp": {
|
||||
"types": "./dist/plugin-sdk/whatsapp.d.ts",
|
||||
"default": "./dist/plugin-sdk/whatsapp.js"
|
||||
},
|
||||
"./plugin-sdk/line": {
|
||||
"types": "./dist/plugin-sdk/line.d.ts",
|
||||
"default": "./dist/plugin-sdk/line.js"
|
||||
},
|
||||
"./plugin-sdk/account-id": {
|
||||
"types": "./dist/plugin-sdk/account-id.d.ts",
|
||||
"default": "./dist/plugin-sdk/account-id.js"
|
||||
|
|
@ -71,7 +95,7 @@
|
|||
"build:plugin-sdk:dts": "tsc -p tsconfig.plugin-sdk.dts.json",
|
||||
"build:strict-smoke": "pnpm canvas:a2ui:bundle && tsdown && pnpm build:plugin-sdk:dts",
|
||||
"canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh",
|
||||
"check": "pnpm format:check && pnpm tsgo && pnpm lint && pnpm lint:tmp:no-random-messaging && pnpm lint:tmp:channel-agnostic-boundaries && pnpm lint:tmp:no-raw-channel-fetch && pnpm lint:agent:ingress-owner && pnpm lint:plugins:no-register-http-handler && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope && pnpm check:host-env-policy:swift",
|
||||
"check": "pnpm format:check && pnpm tsgo && pnpm lint && pnpm lint:tmp:no-random-messaging && pnpm lint:tmp:channel-agnostic-boundaries && pnpm lint:tmp:no-raw-channel-fetch && pnpm lint:agent:ingress-owner && pnpm lint:plugins:no-register-http-handler && pnpm lint:plugins:no-monolithic-plugin-sdk-entry-imports && pnpm lint:webhook:no-low-level-body-read && pnpm lint:auth:no-pairing-store-group && pnpm lint:auth:pairing-account-scope && pnpm check:host-env-policy:swift",
|
||||
"check:docs": "pnpm format:docs:check && pnpm lint:docs && pnpm docs:check-links",
|
||||
"check:host-env-policy:swift": "node scripts/generate-host-env-security-policy-swift.mjs --check",
|
||||
"check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500",
|
||||
|
|
@ -115,6 +139,7 @@
|
|||
"lint:docs": "pnpm dlx markdownlint-cli2",
|
||||
"lint:docs:fix": "pnpm dlx markdownlint-cli2 --fix",
|
||||
"lint:fix": "oxlint --type-aware --fix && pnpm format",
|
||||
"lint:plugins:no-monolithic-plugin-sdk-entry-imports": "node --import tsx scripts/check-no-monolithic-plugin-sdk-entry-imports.ts",
|
||||
"lint:plugins:no-register-http-handler": "node scripts/check-no-register-http-handler.mjs",
|
||||
"lint:swift": "swiftlint lint --config .swiftlint.yml && (cd apps/ios && swiftlint lint --config .swiftlint.yml)",
|
||||
"lint:tmp:channel-agnostic-boundaries": "node scripts/check-channel-agnostic-boundaries.mjs",
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ importers:
|
|||
version: 3.1000.0
|
||||
'@buape/carbon':
|
||||
specifier: 0.0.0-beta-20260216184201
|
||||
version: 0.0.0-beta-20260216184201(hono@4.11.10)(opusscript@0.1.1)
|
||||
version: 0.0.0-beta-20260216184201(@discordjs/opus@0.10.0)(hono@4.11.10)(opusscript@0.1.1)
|
||||
'@clack/prompts':
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
'@discordjs/voice':
|
||||
specifier: ^0.19.0
|
||||
version: 0.19.0(opusscript@0.1.1)
|
||||
version: 0.19.0(@discordjs/opus@0.10.0)(opusscript@0.1.1)
|
||||
'@grammyjs/runner':
|
||||
specifier: ^2.0.3
|
||||
version: 2.0.3(grammy@1.41.0)
|
||||
|
|
@ -341,8 +341,8 @@ importers:
|
|||
specifier: ^10.6.1
|
||||
version: 10.6.1
|
||||
openclaw:
|
||||
specifier: '>=2026.3.1'
|
||||
version: 2026.3.1(@napi-rs/canvas@0.1.95)(@types/express@5.0.6)(audio-decode@2.2.3)(hono@4.11.10)(node-llama-cpp@3.16.2(typescript@5.9.3))
|
||||
specifier: '>=2026.3.2'
|
||||
version: 2026.3.2(@napi-rs/canvas@0.1.95)(@types/express@5.0.6)(audio-decode@2.2.3)(hono@4.11.10)(node-llama-cpp@3.16.2(typescript@5.9.3))
|
||||
|
||||
extensions/imessage: {}
|
||||
|
||||
|
|
@ -402,8 +402,8 @@ importers:
|
|||
extensions/memory-core:
|
||||
dependencies:
|
||||
openclaw:
|
||||
specifier: '>=2026.3.1'
|
||||
version: 2026.3.1(@napi-rs/canvas@0.1.95)(@types/express@5.0.6)(audio-decode@2.2.3)(hono@4.11.10)(node-llama-cpp@3.16.2(typescript@5.9.3))
|
||||
specifier: '>=2026.3.2'
|
||||
version: 2026.3.2(@napi-rs/canvas@0.1.95)(@types/express@5.0.6)(audio-decode@2.2.3)(hono@4.11.10)(node-llama-cpp@3.16.2(typescript@5.9.3))
|
||||
|
||||
extensions/memory-lancedb:
|
||||
dependencies:
|
||||
|
|
@ -461,7 +461,7 @@ importers:
|
|||
dependencies:
|
||||
'@tloncorp/api':
|
||||
specifier: github:tloncorp/api-beta#7eede1c1a756977b09f96aa14a92e2b06318ae87
|
||||
version: https://codeload.github.com/tloncorp/api-beta/tar.gz/7eede1c1a756977b09f96aa14a92e2b06318ae87
|
||||
version: git+https://git@github.com:tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87
|
||||
'@tloncorp/tlon-skill':
|
||||
specifier: 0.1.9
|
||||
version: 0.1.9
|
||||
|
|
@ -925,6 +925,10 @@ packages:
|
|||
resolution: {integrity: sha512-YJOVVZ545x24mHzANfYoy0BJX5PDyeZlpiJjDkUBM/V/Ao7TFX9lcUvCN4nr0tbr5ubeaXxtEBILUrHtTphVeQ==}
|
||||
hasBin: true
|
||||
|
||||
'@discordjs/opus@0.10.0':
|
||||
resolution: {integrity: sha512-HHEnSNrSPmFEyndRdQBJN2YE6egyXS9JUnJWyP6jficK0Y+qKMEZXyYTgmzpjrxXP1exM/hKaNP7BRBUEWkU5w==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@discordjs/voice@0.19.0':
|
||||
resolution: {integrity: sha512-UyX6rGEXzVyPzb1yvjHtPfTlnLvB5jX/stAMdiytHhfoydX+98hfympdOwsnTktzr+IRvphxTbdErgYDJkEsvw==}
|
||||
engines: {node: '>=22.12.0'}
|
||||
|
|
@ -2933,8 +2937,8 @@ packages:
|
|||
resolution: {integrity: sha512-5Kc5CM2Ysn3vTTArBs2vESUt0AQiWZA86yc1TI3B+lxXmtEq133C1nxXNOgnzhrivdPZIh3zLj5gDnZjoLL5GA==}
|
||||
engines: {node: '>=12.17.0'}
|
||||
|
||||
'@tloncorp/api@https://codeload.github.com/tloncorp/api-beta/tar.gz/7eede1c1a756977b09f96aa14a92e2b06318ae87':
|
||||
resolution: {tarball: https://codeload.github.com/tloncorp/api-beta/tar.gz/7eede1c1a756977b09f96aa14a92e2b06318ae87}
|
||||
'@tloncorp/api@git+https://git@github.com:tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87':
|
||||
resolution: {commit: 7eede1c1a756977b09f96aa14a92e2b06318ae87, repo: git@github.com:tloncorp/api-beta.git, type: git}
|
||||
version: 0.0.2
|
||||
|
||||
'@tloncorp/tlon-skill-darwin-arm64@0.1.9':
|
||||
|
|
@ -4973,8 +4977,8 @@ packages:
|
|||
zod:
|
||||
optional: true
|
||||
|
||||
openclaw@2026.3.1:
|
||||
resolution: {integrity: sha512-7Pt5ykhaYa8TYpLWnBhaMg6Lp6kfk3rMKgqJ3WWESKM9BizYu1fkH/rF9BLeXlsNASgZdLp4oR8H0XfvIIoXIg==}
|
||||
openclaw@2026.3.2:
|
||||
resolution: {integrity: sha512-Gkqx24m7PF1DUXPI968DuC9n52lTZ5hI3X5PIi0HosC7J7d6RLkgVppj1mxvgiQAWMp41E41elvoi/h4KBjFcQ==}
|
||||
engines: {node: '>=22.12.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
|
|
@ -5185,10 +5189,13 @@ packages:
|
|||
prism-media@1.3.5:
|
||||
resolution: {integrity: sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==}
|
||||
peerDependencies:
|
||||
'@discordjs/opus': '>=0.8.0 <1.0.0'
|
||||
ffmpeg-static: ^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0
|
||||
node-opus: ^0.3.3
|
||||
opusscript: ^0.0.8
|
||||
peerDependenciesMeta:
|
||||
'@discordjs/opus':
|
||||
optional: true
|
||||
ffmpeg-static:
|
||||
optional: true
|
||||
node-opus:
|
||||
|
|
@ -6813,18 +6820,19 @@ snapshots:
|
|||
|
||||
'@borewit/text-codec@0.2.1': {}
|
||||
|
||||
'@buape/carbon@0.0.0-beta-20260216184201(hono@4.11.10)(opusscript@0.1.1)':
|
||||
'@buape/carbon@0.0.0-beta-20260216184201(@discordjs/opus@0.10.0)(hono@4.11.10)(opusscript@0.1.1)':
|
||||
dependencies:
|
||||
'@types/node': 25.3.3
|
||||
discord-api-types: 0.38.37
|
||||
optionalDependencies:
|
||||
'@cloudflare/workers-types': 4.20260120.0
|
||||
'@discordjs/voice': 0.19.0(opusscript@0.1.1)
|
||||
'@discordjs/voice': 0.19.0(@discordjs/opus@0.10.0)(opusscript@0.1.1)
|
||||
'@hono/node-server': 1.19.9(hono@4.11.10)
|
||||
'@types/bun': 1.3.9
|
||||
'@types/ws': 8.18.1
|
||||
ws: 8.19.0
|
||||
transitivePeerDependencies:
|
||||
- '@discordjs/opus'
|
||||
- bufferutil
|
||||
- ffmpeg-static
|
||||
- hono
|
||||
|
|
@ -6959,14 +6967,24 @@ snapshots:
|
|||
- supports-color
|
||||
optional: true
|
||||
|
||||
'@discordjs/voice@0.19.0(opusscript@0.1.1)':
|
||||
'@discordjs/opus@0.10.0':
|
||||
dependencies:
|
||||
'@discordjs/node-pre-gyp': 0.4.5
|
||||
node-addon-api: 8.5.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
'@discordjs/voice@0.19.0(@discordjs/opus@0.10.0)(opusscript@0.1.1)':
|
||||
dependencies:
|
||||
'@types/ws': 8.18.1
|
||||
discord-api-types: 0.38.40
|
||||
prism-media: 1.3.5(opusscript@0.1.1)
|
||||
prism-media: 1.3.5(@discordjs/opus@0.10.0)(opusscript@0.1.1)
|
||||
tslib: 2.8.1
|
||||
ws: 8.19.0
|
||||
transitivePeerDependencies:
|
||||
- '@discordjs/opus'
|
||||
- bufferutil
|
||||
- ffmpeg-static
|
||||
- node-opus
|
||||
|
|
@ -8889,7 +8907,7 @@ snapshots:
|
|||
|
||||
'@tinyhttp/content-disposition@2.2.4': {}
|
||||
|
||||
'@tloncorp/api@https://codeload.github.com/tloncorp/api-beta/tar.gz/7eede1c1a756977b09f96aa14a92e2b06318ae87':
|
||||
'@tloncorp/api@git+https://git@github.com:tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87':
|
||||
dependencies:
|
||||
'@aws-sdk/client-s3': 3.1000.0
|
||||
'@aws-sdk/s3-request-presigner': 3.1000.0
|
||||
|
|
@ -11171,13 +11189,13 @@ snapshots:
|
|||
ws: 8.19.0
|
||||
zod: 4.3.6
|
||||
|
||||
openclaw@2026.3.1(@napi-rs/canvas@0.1.95)(@types/express@5.0.6)(audio-decode@2.2.3)(hono@4.11.10)(node-llama-cpp@3.16.2(typescript@5.9.3)):
|
||||
openclaw@2026.3.2(@napi-rs/canvas@0.1.95)(@types/express@5.0.6)(audio-decode@2.2.3)(hono@4.11.10)(node-llama-cpp@3.16.2(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@agentclientprotocol/sdk': 0.14.1(zod@4.3.6)
|
||||
'@aws-sdk/client-bedrock': 3.1000.0
|
||||
'@buape/carbon': 0.0.0-beta-20260216184201(hono@4.11.10)(opusscript@0.1.1)
|
||||
'@buape/carbon': 0.0.0-beta-20260216184201(@discordjs/opus@0.10.0)(hono@4.11.10)(opusscript@0.1.1)
|
||||
'@clack/prompts': 1.0.1
|
||||
'@discordjs/voice': 0.19.0(opusscript@0.1.1)
|
||||
'@discordjs/voice': 0.19.0(@discordjs/opus@0.10.0)(opusscript@0.1.1)
|
||||
'@grammyjs/runner': 2.0.3(grammy@1.41.0)
|
||||
'@grammyjs/transformer-throttler': 1.2.1(grammy@1.41.0)
|
||||
'@homebridge/ciao': 1.3.5
|
||||
|
|
@ -11226,12 +11244,15 @@ snapshots:
|
|||
qrcode-terminal: 0.12.0
|
||||
sharp: 0.34.5
|
||||
sqlite-vec: 0.1.7-alpha.2
|
||||
strip-ansi: 7.2.0
|
||||
tar: 7.5.9
|
||||
tslog: 4.10.2
|
||||
undici: 7.22.0
|
||||
ws: 8.19.0
|
||||
yaml: 2.8.2
|
||||
zod: 4.3.6
|
||||
optionalDependencies:
|
||||
'@discordjs/opus': 0.10.0
|
||||
transitivePeerDependencies:
|
||||
- '@modelcontextprotocol/sdk'
|
||||
- '@types/express'
|
||||
|
|
@ -11485,8 +11506,9 @@ snapshots:
|
|||
dependencies:
|
||||
parse-ms: 4.0.0
|
||||
|
||||
prism-media@1.3.5(opusscript@0.1.1):
|
||||
prism-media@1.3.5(@discordjs/opus@0.10.0)(opusscript@0.1.1):
|
||||
optionalDependencies:
|
||||
'@discordjs/opus': 0.10.0
|
||||
opusscript: 0.1.1
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { discoverOpenClawPlugins } from "../src/plugins/discovery.js";
|
||||
|
||||
const ROOT_IMPORT_PATTERNS = [
|
||||
/\b(?:import|export)\b[\s\S]*?\bfrom\s+["']openclaw\/plugin-sdk["']/,
|
||||
/\bimport\s+["']openclaw\/plugin-sdk["']/,
|
||||
/\bimport\s*\(\s*["']openclaw\/plugin-sdk["']\s*\)/,
|
||||
/\brequire\s*\(\s*["']openclaw\/plugin-sdk["']\s*\)/,
|
||||
];
|
||||
|
||||
function hasMonolithicRootImport(content: string): boolean {
|
||||
return ROOT_IMPORT_PATTERNS.some((pattern) => pattern.test(content));
|
||||
}
|
||||
|
||||
function main() {
|
||||
const discovery = discoverOpenClawPlugins({});
|
||||
const bundledEntryFiles = [
|
||||
...new Set(discovery.candidates.filter((c) => c.origin === "bundled").map((c) => c.source)),
|
||||
];
|
||||
|
||||
const offenders: string[] = [];
|
||||
for (const entryFile of bundledEntryFiles) {
|
||||
let content = "";
|
||||
try {
|
||||
content = fs.readFileSync(entryFile, "utf8");
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if (hasMonolithicRootImport(content)) {
|
||||
offenders.push(entryFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (offenders.length > 0) {
|
||||
console.error("Bundled plugin entrypoints must not import monolithic openclaw/plugin-sdk.");
|
||||
for (const file of offenders.toSorted()) {
|
||||
const relative = path.relative(process.cwd(), file) || file;
|
||||
console.error(`- ${relative}`);
|
||||
}
|
||||
console.error("Use openclaw/plugin-sdk/<channel> for channel plugins or /core for others.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`OK: bundled entrypoints use scoped plugin-sdk subpaths (${bundledEntryFiles.length} checked).`,
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -41,6 +41,18 @@ const exportedNames = exportMatch[1]
|
|||
|
||||
const exportSet = new Set(exportedNames);
|
||||
|
||||
const requiredSubpathEntries = [
|
||||
"core",
|
||||
"telegram",
|
||||
"discord",
|
||||
"slack",
|
||||
"signal",
|
||||
"imessage",
|
||||
"whatsapp",
|
||||
"line",
|
||||
"account-id",
|
||||
];
|
||||
|
||||
// Critical functions that channel extension plugins import from openclaw/plugin-sdk.
|
||||
// If any of these are missing, plugins will fail at runtime with:
|
||||
// TypeError: (0 , _pluginSdk.<name>) is not a function
|
||||
|
|
@ -76,10 +88,25 @@ for (const name of requiredExports) {
|
|||
}
|
||||
}
|
||||
|
||||
for (const entry of requiredSubpathEntries) {
|
||||
const jsPath = resolve(__dirname, "..", "dist", "plugin-sdk", `${entry}.js`);
|
||||
const dtsPath = resolve(__dirname, "..", "dist", "plugin-sdk", `${entry}.d.ts`);
|
||||
if (!existsSync(jsPath)) {
|
||||
console.error(`MISSING SUBPATH JS: dist/plugin-sdk/${entry}.js`);
|
||||
missing += 1;
|
||||
}
|
||||
if (!existsSync(dtsPath)) {
|
||||
console.error(`MISSING SUBPATH DTS: dist/plugin-sdk/${entry}.d.ts`);
|
||||
missing += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (missing > 0) {
|
||||
console.error(`\nERROR: ${missing} required export(s) missing from dist/plugin-sdk/index.js.`);
|
||||
console.error(
|
||||
`\nERROR: ${missing} required plugin-sdk artifact(s) missing (named exports or subpath files).`,
|
||||
);
|
||||
console.error("This will break channel extension plugins at runtime.");
|
||||
console.error("Check src/plugin-sdk/index.ts and rebuild.");
|
||||
console.error("Check src/plugin-sdk/index.ts, subpath entries, and rebuild.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ const requiredPathGroups = [
|
|||
["dist/entry.js", "dist/entry.mjs"],
|
||||
"dist/plugin-sdk/index.js",
|
||||
"dist/plugin-sdk/index.d.ts",
|
||||
"dist/plugin-sdk/core.js",
|
||||
"dist/plugin-sdk/core.d.ts",
|
||||
"dist/plugin-sdk/telegram.js",
|
||||
"dist/plugin-sdk/telegram.d.ts",
|
||||
"dist/plugin-sdk/discord.js",
|
||||
"dist/plugin-sdk/discord.d.ts",
|
||||
"dist/plugin-sdk/slack.js",
|
||||
"dist/plugin-sdk/slack.d.ts",
|
||||
"dist/plugin-sdk/signal.js",
|
||||
"dist/plugin-sdk/signal.d.ts",
|
||||
"dist/plugin-sdk/imessage.js",
|
||||
"dist/plugin-sdk/imessage.d.ts",
|
||||
"dist/plugin-sdk/whatsapp.js",
|
||||
"dist/plugin-sdk/whatsapp.d.ts",
|
||||
"dist/plugin-sdk/line.js",
|
||||
"dist/plugin-sdk/line.d.ts",
|
||||
"dist/build-info.json",
|
||||
];
|
||||
const forbiddenPrefixes = ["dist/OpenClaw.app/"];
|
||||
|
|
|
|||
|
|
@ -6,7 +6,18 @@ import path from "node:path";
|
|||
//
|
||||
// Our package export map points subpath `types` at `dist/plugin-sdk/<entry>.d.ts`, so we
|
||||
// generate stable entry d.ts files that re-export the real declarations.
|
||||
const entrypoints = ["index", "core", "telegram", "account-id"] as const;
|
||||
const entrypoints = [
|
||||
"index",
|
||||
"core",
|
||||
"telegram",
|
||||
"discord",
|
||||
"slack",
|
||||
"signal",
|
||||
"imessage",
|
||||
"whatsapp",
|
||||
"line",
|
||||
"account-id",
|
||||
] as const;
|
||||
for (const entry of entrypoints) {
|
||||
const out = path.join(process.cwd(), `dist/plugin-sdk/${entry}.d.ts`);
|
||||
fs.mkdirSync(path.dirname(out), { recursive: true });
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
export type { OpenClawPluginApi, OpenClawPluginService } from "../plugins/types.js";
|
||||
export type {
|
||||
AnyAgentTool,
|
||||
OpenClawPluginApi,
|
||||
OpenClawPluginService,
|
||||
ProviderAuthContext,
|
||||
ProviderAuthResult,
|
||||
} from "../plugins/types.js";
|
||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { GatewayRequestHandlerOptions } from "../gateway/server-methods/types.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
export { buildOauthProviderAuthResult } from "./provider-auth-result.js";
|
||||
|
||||
export {
|
||||
approveDevicePairing,
|
||||
|
|
@ -15,6 +24,7 @@ export {
|
|||
type PluginCommandRunOptions,
|
||||
type PluginCommandRunResult,
|
||||
} from "./run-command.js";
|
||||
export { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
|
||||
|
||||
export { resolveGatewayBindUrl } from "../shared/gateway-bind-url.js";
|
||||
export type { GatewayBindUrlResult } from "../shared/gateway-bind-url.js";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js";
|
||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { ResolvedDiscordAccount } from "../discord/accounts.js";
|
||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
export type { OpenClawPluginApi } from "../plugins/types.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
|
||||
export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
|
||||
|
||||
export {
|
||||
applyAccountNameToChannelSection,
|
||||
migrateBaseNameToDefaultAccount,
|
||||
} from "../channels/plugins/setup-helpers.js";
|
||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
export {
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
} from "../channels/plugins/config-helpers.js";
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js";
|
||||
|
||||
export { getChatChannelMeta } from "../channels/registry.js";
|
||||
|
||||
export {
|
||||
listDiscordAccountIds,
|
||||
resolveDefaultDiscordAccountId,
|
||||
resolveDiscordAccount,
|
||||
} from "../discord/accounts.js";
|
||||
export {
|
||||
listDiscordDirectoryGroupsFromConfig,
|
||||
listDiscordDirectoryPeersFromConfig,
|
||||
} from "../channels/plugins/directory-config.js";
|
||||
export {
|
||||
looksLikeDiscordTargetId,
|
||||
normalizeDiscordMessagingTarget,
|
||||
normalizeDiscordOutboundTarget,
|
||||
} from "../channels/plugins/normalize/discord.js";
|
||||
export { collectDiscordAuditChannelIds } from "../discord/audit.js";
|
||||
export { collectDiscordStatusIssues } from "../channels/plugins/status-issues/discord.js";
|
||||
|
||||
export {
|
||||
resolveDefaultGroupPolicy,
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
export {
|
||||
resolveDiscordGroupRequireMention,
|
||||
resolveDiscordGroupToolPolicy,
|
||||
} from "../channels/plugins/group-mentions.js";
|
||||
export { discordOnboardingAdapter } from "../channels/plugins/onboarding/discord.js";
|
||||
export { DiscordConfigSchema } from "../config/zod-schema.providers-core.js";
|
||||
|
||||
export {
|
||||
autoBindSpawnedDiscordSubagent,
|
||||
listThreadBindingsBySessionKey,
|
||||
unbindThreadBindingsBySessionKey,
|
||||
} from "../discord/monitor/thread-bindings.js";
|
||||
|
||||
export { buildTokenChannelStatusSummary } from "./status-helpers.js";
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { ResolvedIMessageAccount } from "../imessage/accounts.js";
|
||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
export type { OpenClawPluginApi } from "../plugins/types.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
|
||||
export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
|
||||
|
||||
export {
|
||||
applyAccountNameToChannelSection,
|
||||
migrateBaseNameToDefaultAccount,
|
||||
} from "../channels/plugins/setup-helpers.js";
|
||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
export {
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
} from "../channels/plugins/config-helpers.js";
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js";
|
||||
|
||||
export { getChatChannelMeta } from "../channels/registry.js";
|
||||
export {
|
||||
listIMessageAccountIds,
|
||||
resolveDefaultIMessageAccountId,
|
||||
resolveIMessageAccount,
|
||||
} from "../imessage/accounts.js";
|
||||
export {
|
||||
formatTrimmedAllowFromEntries,
|
||||
resolveIMessageConfigAllowFrom,
|
||||
resolveIMessageConfigDefaultTo,
|
||||
} from "./channel-config-helpers.js";
|
||||
export {
|
||||
looksLikeIMessageTargetId,
|
||||
normalizeIMessageMessagingTarget,
|
||||
} from "../channels/plugins/normalize/imessage.js";
|
||||
|
||||
export {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
resolveDefaultGroupPolicy,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
export {
|
||||
resolveIMessageGroupRequireMention,
|
||||
resolveIMessageGroupToolPolicy,
|
||||
} from "../channels/plugins/group-mentions.js";
|
||||
export { imessageOnboardingAdapter } from "../channels/plugins/onboarding/imessage.js";
|
||||
export { IMessageConfigSchema } from "../config/zod-schema.providers-core.js";
|
||||
|
||||
export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js";
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
export type {
|
||||
ChannelAccountSnapshot,
|
||||
ChannelGatewayContext,
|
||||
ChannelStatusIssue,
|
||||
} from "../channels/plugins/types.js";
|
||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { ReplyPayload } from "../auto-reply/types.js";
|
||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
export type { OpenClawPluginApi } from "../plugins/types.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
|
||||
export { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";
|
||||
|
||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
|
||||
export {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
resolveDefaultGroupPolicy,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
|
||||
export { buildTokenChannelStatusSummary } from "./status-helpers.js";
|
||||
|
||||
export { LineConfigSchema } from "../line/config-schema.js";
|
||||
export type { LineChannelData, LineConfig, ResolvedLineAccount } from "../line/types.js";
|
||||
export {
|
||||
createActionCard,
|
||||
createImageCard,
|
||||
createInfoCard,
|
||||
createListCard,
|
||||
createReceiptCard,
|
||||
type CardAction,
|
||||
type ListItem,
|
||||
} from "../line/flex-templates.js";
|
||||
export { processLineMessage } from "../line/markdown-to-line.js";
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
export type { ChannelMessageActionAdapter } from "../channels/plugins/types.js";
|
||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { ResolvedSignalAccount } from "../signal/accounts.js";
|
||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
export type { OpenClawPluginApi } from "../plugins/types.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
|
||||
export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
|
||||
|
||||
export {
|
||||
applyAccountNameToChannelSection,
|
||||
migrateBaseNameToDefaultAccount,
|
||||
} from "../channels/plugins/setup-helpers.js";
|
||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
export {
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
} from "../channels/plugins/config-helpers.js";
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js";
|
||||
|
||||
export { getChatChannelMeta } from "../channels/registry.js";
|
||||
export {
|
||||
listSignalAccountIds,
|
||||
resolveDefaultSignalAccountId,
|
||||
resolveSignalAccount,
|
||||
} from "../signal/accounts.js";
|
||||
export {
|
||||
looksLikeSignalTargetId,
|
||||
normalizeSignalMessagingTarget,
|
||||
} from "../channels/plugins/normalize/signal.js";
|
||||
|
||||
export {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
resolveDefaultGroupPolicy,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
export { signalOnboardingAdapter } from "../channels/plugins/onboarding/signal.js";
|
||||
export { SignalConfigSchema } from "../config/zod-schema.providers-core.js";
|
||||
|
||||
export { normalizeE164 } from "../utils.js";
|
||||
export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js";
|
||||
|
||||
export {
|
||||
buildBaseAccountStatusSnapshot,
|
||||
buildBaseChannelStatusSummary,
|
||||
collectStatusIssuesFromLastError,
|
||||
createDefaultChannelRuntimeState,
|
||||
} from "./status-helpers.js";
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { OpenClawConfig } from "../config/config.js";
|
||||
export type { ResolvedSlackAccount } from "../slack/accounts.js";
|
||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
export type { OpenClawPluginApi } from "../plugins/types.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
|
||||
export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
|
||||
|
||||
export {
|
||||
applyAccountNameToChannelSection,
|
||||
migrateBaseNameToDefaultAccount,
|
||||
} from "../channels/plugins/setup-helpers.js";
|
||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
export {
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
} from "../channels/plugins/config-helpers.js";
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js";
|
||||
|
||||
export { getChatChannelMeta } from "../channels/registry.js";
|
||||
export {
|
||||
listSlackAccountIds,
|
||||
resolveDefaultSlackAccountId,
|
||||
resolveSlackAccount,
|
||||
resolveSlackReplyToMode,
|
||||
} from "../slack/accounts.js";
|
||||
export {
|
||||
listSlackDirectoryGroupsFromConfig,
|
||||
listSlackDirectoryPeersFromConfig,
|
||||
} from "../channels/plugins/directory-config.js";
|
||||
export {
|
||||
looksLikeSlackTargetId,
|
||||
normalizeSlackMessagingTarget,
|
||||
} from "../channels/plugins/normalize/slack.js";
|
||||
export { extractSlackToolSend, listSlackMessageActions } from "../slack/message-actions.js";
|
||||
export { buildSlackThreadingToolContext } from "../slack/threading-tool-context.js";
|
||||
|
||||
export {
|
||||
resolveDefaultGroupPolicy,
|
||||
resolveOpenProviderRuntimeGroupPolicy,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
export {
|
||||
resolveSlackGroupRequireMention,
|
||||
resolveSlackGroupToolPolicy,
|
||||
} from "../channels/plugins/group-mentions.js";
|
||||
export { slackOnboardingAdapter } from "../channels/plugins/onboarding/slack.js";
|
||||
export { SlackConfigSchema } from "../config/zod-schema.providers-core.js";
|
||||
|
||||
export { handleSlackMessageAction } from "./slack-message-actions.js";
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import * as discordSdk from "openclaw/plugin-sdk/discord";
|
||||
import * as imessageSdk from "openclaw/plugin-sdk/imessage";
|
||||
import * as lineSdk from "openclaw/plugin-sdk/line";
|
||||
import * as signalSdk from "openclaw/plugin-sdk/signal";
|
||||
import * as slackSdk from "openclaw/plugin-sdk/slack";
|
||||
import * as whatsappSdk from "openclaw/plugin-sdk/whatsapp";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
describe("plugin-sdk subpath exports", () => {
|
||||
it("exports Discord helpers", () => {
|
||||
expect(typeof discordSdk.resolveDiscordAccount).toBe("function");
|
||||
expect(typeof discordSdk.discordOnboardingAdapter).toBe("object");
|
||||
});
|
||||
|
||||
it("exports Slack helpers", () => {
|
||||
expect(typeof slackSdk.resolveSlackAccount).toBe("function");
|
||||
expect(typeof slackSdk.handleSlackMessageAction).toBe("function");
|
||||
});
|
||||
|
||||
it("exports Signal helpers", () => {
|
||||
expect(typeof signalSdk.resolveSignalAccount).toBe("function");
|
||||
expect(typeof signalSdk.signalOnboardingAdapter).toBe("object");
|
||||
});
|
||||
|
||||
it("exports iMessage helpers", () => {
|
||||
expect(typeof imessageSdk.resolveIMessageAccount).toBe("function");
|
||||
expect(typeof imessageSdk.imessageOnboardingAdapter).toBe("object");
|
||||
});
|
||||
|
||||
it("exports WhatsApp helpers", () => {
|
||||
expect(typeof whatsappSdk.resolveWhatsAppAccount).toBe("function");
|
||||
expect(typeof whatsappSdk.whatsappOnboardingAdapter).toBe("object");
|
||||
});
|
||||
|
||||
it("exports LINE helpers", () => {
|
||||
expect(typeof lineSdk.processLineMessage).toBe("function");
|
||||
expect(typeof lineSdk.createInfoCard).toBe("function");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
export type { ChannelMessageActionName } from "../channels/plugins/types.js";
|
||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||
export type { ResolvedWhatsAppAccount } from "../web/accounts.js";
|
||||
export type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
export type { OpenClawPluginApi } from "../plugins/types.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
|
||||
export { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
|
||||
|
||||
export {
|
||||
applyAccountNameToChannelSection,
|
||||
migrateBaseNameToDefaultAccount,
|
||||
} from "../channels/plugins/setup-helpers.js";
|
||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
|
||||
|
||||
export { getChatChannelMeta } from "../channels/registry.js";
|
||||
export {
|
||||
listWhatsAppAccountIds,
|
||||
resolveDefaultWhatsAppAccountId,
|
||||
resolveWhatsAppAccount,
|
||||
} from "../web/accounts.js";
|
||||
export {
|
||||
formatWhatsAppConfigAllowFromEntries,
|
||||
resolveWhatsAppConfigAllowFrom,
|
||||
resolveWhatsAppConfigDefaultTo,
|
||||
} from "./channel-config-helpers.js";
|
||||
export {
|
||||
listWhatsAppDirectoryGroupsFromConfig,
|
||||
listWhatsAppDirectoryPeersFromConfig,
|
||||
} from "../channels/plugins/directory-config.js";
|
||||
export {
|
||||
looksLikeWhatsAppTargetId,
|
||||
normalizeWhatsAppMessagingTarget,
|
||||
} from "../channels/plugins/normalize/whatsapp.js";
|
||||
export { resolveWhatsAppOutboundTarget } from "../whatsapp/resolve-outbound-target.js";
|
||||
|
||||
export {
|
||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||
resolveDefaultGroupPolicy,
|
||||
} from "../config/runtime-group-policy.js";
|
||||
export {
|
||||
resolveWhatsAppGroupRequireMention,
|
||||
resolveWhatsAppGroupToolPolicy,
|
||||
} from "../channels/plugins/group-mentions.js";
|
||||
export {
|
||||
resolveWhatsAppGroupIntroHint,
|
||||
resolveWhatsAppMentionStripPatterns,
|
||||
} from "../channels/plugins/whatsapp-shared.js";
|
||||
export { resolveWhatsAppHeartbeatRecipients } from "../channels/plugins/whatsapp-heartbeat.js";
|
||||
export { whatsappOnboardingAdapter } from "../channels/plugins/onboarding/whatsapp.js";
|
||||
export { collectWhatsAppStatusIssues } from "../channels/plugins/status-issues/whatsapp.js";
|
||||
export { WhatsAppConfigSchema } from "../config/zod-schema.providers-whatsapp.js";
|
||||
|
||||
export { createActionGate, readStringParam } from "../agents/tools/common.js";
|
||||
|
||||
export { normalizeE164 } from "../utils.js";
|
||||
|
|
@ -1005,6 +1005,29 @@ describe("loadOpenClawPlugins", () => {
|
|||
expect(record?.status).toBe("loaded");
|
||||
});
|
||||
|
||||
it("supports legacy plugins importing monolithic plugin-sdk root", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "legacy-root-import",
|
||||
filename: "legacy-root-import.cjs",
|
||||
body: `module.exports = {
|
||||
id: "legacy-root-import",
|
||||
configSchema: (require("openclaw/plugin-sdk").emptyPluginConfigSchema)(),
|
||||
register() {},
|
||||
};`,
|
||||
});
|
||||
|
||||
const registry = loadRegistryFromSinglePlugin({
|
||||
plugin,
|
||||
pluginConfig: {
|
||||
allow: ["legacy-root-import"],
|
||||
},
|
||||
});
|
||||
|
||||
const record = registry.plugins.find((entry) => entry.id === "legacy-root-import");
|
||||
expect(record?.status).toBe("loaded");
|
||||
});
|
||||
|
||||
it("prefers dist plugin-sdk alias when loader runs from dist", () => {
|
||||
const { root, distFile } = createPluginSdkAliasFixture();
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,30 @@ const resolvePluginSdkTelegramAlias = (): string | null => {
|
|||
return resolvePluginSdkAliasFile({ srcFile: "telegram.ts", distFile: "telegram.js" });
|
||||
};
|
||||
|
||||
const resolvePluginSdkDiscordAlias = (): string | null => {
|
||||
return resolvePluginSdkAliasFile({ srcFile: "discord.ts", distFile: "discord.js" });
|
||||
};
|
||||
|
||||
const resolvePluginSdkSlackAlias = (): string | null => {
|
||||
return resolvePluginSdkAliasFile({ srcFile: "slack.ts", distFile: "slack.js" });
|
||||
};
|
||||
|
||||
const resolvePluginSdkSignalAlias = (): string | null => {
|
||||
return resolvePluginSdkAliasFile({ srcFile: "signal.ts", distFile: "signal.js" });
|
||||
};
|
||||
|
||||
const resolvePluginSdkIMessageAlias = (): string | null => {
|
||||
return resolvePluginSdkAliasFile({ srcFile: "imessage.ts", distFile: "imessage.js" });
|
||||
};
|
||||
|
||||
const resolvePluginSdkWhatsAppAlias = (): string | null => {
|
||||
return resolvePluginSdkAliasFile({ srcFile: "whatsapp.ts", distFile: "whatsapp.js" });
|
||||
};
|
||||
|
||||
const resolvePluginSdkLineAlias = (): string | null => {
|
||||
return resolvePluginSdkAliasFile({ srcFile: "line.ts", distFile: "line.js" });
|
||||
};
|
||||
|
||||
export const __testing = {
|
||||
resolvePluginSdkAliasFile,
|
||||
};
|
||||
|
|
@ -478,10 +502,22 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
|||
const pluginSdkAccountIdAlias = resolvePluginSdkAccountIdAlias();
|
||||
const pluginSdkCoreAlias = resolvePluginSdkCoreAlias();
|
||||
const pluginSdkTelegramAlias = resolvePluginSdkTelegramAlias();
|
||||
const pluginSdkDiscordAlias = resolvePluginSdkDiscordAlias();
|
||||
const pluginSdkSlackAlias = resolvePluginSdkSlackAlias();
|
||||
const pluginSdkSignalAlias = resolvePluginSdkSignalAlias();
|
||||
const pluginSdkIMessageAlias = resolvePluginSdkIMessageAlias();
|
||||
const pluginSdkWhatsAppAlias = resolvePluginSdkWhatsAppAlias();
|
||||
const pluginSdkLineAlias = resolvePluginSdkLineAlias();
|
||||
const aliasMap = {
|
||||
...(pluginSdkAlias ? { "openclaw/plugin-sdk": pluginSdkAlias } : {}),
|
||||
...(pluginSdkCoreAlias ? { "openclaw/plugin-sdk/core": pluginSdkCoreAlias } : {}),
|
||||
...(pluginSdkTelegramAlias ? { "openclaw/plugin-sdk/telegram": pluginSdkTelegramAlias } : {}),
|
||||
...(pluginSdkDiscordAlias ? { "openclaw/plugin-sdk/discord": pluginSdkDiscordAlias } : {}),
|
||||
...(pluginSdkSlackAlias ? { "openclaw/plugin-sdk/slack": pluginSdkSlackAlias } : {}),
|
||||
...(pluginSdkSignalAlias ? { "openclaw/plugin-sdk/signal": pluginSdkSignalAlias } : {}),
|
||||
...(pluginSdkIMessageAlias ? { "openclaw/plugin-sdk/imessage": pluginSdkIMessageAlias } : {}),
|
||||
...(pluginSdkWhatsAppAlias ? { "openclaw/plugin-sdk/whatsapp": pluginSdkWhatsAppAlias } : {}),
|
||||
...(pluginSdkLineAlias ? { "openclaw/plugin-sdk/line": pluginSdkLineAlias } : {}),
|
||||
...(pluginSdkAccountIdAlias
|
||||
? { "openclaw/plugin-sdk/account-id": pluginSdkAccountIdAlias }
|
||||
: {}),
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@
|
|||
"src/plugin-sdk/index.ts",
|
||||
"src/plugin-sdk/core.ts",
|
||||
"src/plugin-sdk/telegram.ts",
|
||||
"src/plugin-sdk/discord.ts",
|
||||
"src/plugin-sdk/slack.ts",
|
||||
"src/plugin-sdk/signal.ts",
|
||||
"src/plugin-sdk/imessage.ts",
|
||||
"src/plugin-sdk/whatsapp.ts",
|
||||
"src/plugin-sdk/line.ts",
|
||||
"src/plugin-sdk/account-id.ts",
|
||||
"src/plugin-sdk/keyed-async-queue.ts",
|
||||
"src/types/**/*.d.ts"
|
||||
|
|
|
|||
|
|
@ -69,6 +69,48 @@ export default defineConfig([
|
|||
fixedExtension: false,
|
||||
platform: "node",
|
||||
},
|
||||
{
|
||||
entry: "src/plugin-sdk/discord.ts",
|
||||
outDir: "dist/plugin-sdk",
|
||||
env,
|
||||
fixedExtension: false,
|
||||
platform: "node",
|
||||
},
|
||||
{
|
||||
entry: "src/plugin-sdk/slack.ts",
|
||||
outDir: "dist/plugin-sdk",
|
||||
env,
|
||||
fixedExtension: false,
|
||||
platform: "node",
|
||||
},
|
||||
{
|
||||
entry: "src/plugin-sdk/signal.ts",
|
||||
outDir: "dist/plugin-sdk",
|
||||
env,
|
||||
fixedExtension: false,
|
||||
platform: "node",
|
||||
},
|
||||
{
|
||||
entry: "src/plugin-sdk/imessage.ts",
|
||||
outDir: "dist/plugin-sdk",
|
||||
env,
|
||||
fixedExtension: false,
|
||||
platform: "node",
|
||||
},
|
||||
{
|
||||
entry: "src/plugin-sdk/whatsapp.ts",
|
||||
outDir: "dist/plugin-sdk",
|
||||
env,
|
||||
fixedExtension: false,
|
||||
platform: "node",
|
||||
},
|
||||
{
|
||||
entry: "src/plugin-sdk/line.ts",
|
||||
outDir: "dist/plugin-sdk",
|
||||
env,
|
||||
fixedExtension: false,
|
||||
platform: "node",
|
||||
},
|
||||
{
|
||||
entry: "src/plugin-sdk/account-id.ts",
|
||||
outDir: "dist/plugin-sdk",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,30 @@ export default defineConfig({
|
|||
find: "openclaw/plugin-sdk/telegram",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "telegram.ts"),
|
||||
},
|
||||
{
|
||||
find: "openclaw/plugin-sdk/discord",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "discord.ts"),
|
||||
},
|
||||
{
|
||||
find: "openclaw/plugin-sdk/slack",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "slack.ts"),
|
||||
},
|
||||
{
|
||||
find: "openclaw/plugin-sdk/signal",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "signal.ts"),
|
||||
},
|
||||
{
|
||||
find: "openclaw/plugin-sdk/imessage",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "imessage.ts"),
|
||||
},
|
||||
{
|
||||
find: "openclaw/plugin-sdk/whatsapp",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "whatsapp.ts"),
|
||||
},
|
||||
{
|
||||
find: "openclaw/plugin-sdk/line",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "line.ts"),
|
||||
},
|
||||
{
|
||||
find: "openclaw/plugin-sdk/keyed-async-queue",
|
||||
replacement: path.join(repoRoot, "src", "plugin-sdk", "keyed-async-queue.ts"),
|
||||
|
|
|
|||
Loading…
Reference in New Issue