diff --git a/docs/plugins/sdk-subpaths.md b/docs/plugins/sdk-subpaths.md index 31d863e6252..89b13f6f6c0 100644 --- a/docs/plugins/sdk-subpaths.md +++ b/docs/plugins/sdk-subpaths.md @@ -119,6 +119,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview) | `plugin-sdk/approval-handler-runtime` | Broader approval handler runtime helpers; prefer the narrower adapter/gateway seams when they are enough | | `plugin-sdk/approval-native-runtime` | Native approval target + account-binding helpers | | `plugin-sdk/approval-reply-runtime` | Exec/plugin approval reply payload helpers | + | `plugin-sdk/channel-contract-testing` | Narrow channel contract test helpers without the broad testing barrel | | `plugin-sdk/command-auth-native` | Native command auth + native session-target helpers | | `plugin-sdk/command-detection` | Shared command detection helpers | | `plugin-sdk/command-primitives-runtime` | Lightweight command text predicates for hot channel paths | diff --git a/extensions/slack/src/monitor/message-handler/prepare.test.ts b/extensions/slack/src/monitor/message-handler/prepare.test.ts index ff01e085e7d..dc8b249d6f2 100644 --- a/extensions/slack/src/monitor/message-handler/prepare.test.ts +++ b/extensions/slack/src/monitor/message-handler/prepare.test.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import type { App } from "@slack/bolt"; +import { expectChannelInboundContextContract as expectInboundContextContract } from "openclaw/plugin-sdk/channel-contract-testing"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { registerSessionBindingAdapter, @@ -9,7 +10,6 @@ import { } from "openclaw/plugin-sdk/conversation-runtime"; import { resolveAgentRoute } from "openclaw/plugin-sdk/routing"; import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; -import { expectChannelInboundContextContract as expectInboundContextContract } from "openclaw/plugin-sdk/testing"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import type { ResolvedSlackAccount } from "../../accounts.js"; import type { SlackMessageEvent } from "../../types.js"; diff --git a/extensions/slack/src/monitor/message-handler/prepare.ts b/extensions/slack/src/monitor/message-handler/prepare.ts index 10c2d468c33..efbded936ce 100644 --- a/extensions/slack/src/monitor/message-handler/prepare.ts +++ b/extensions/slack/src/monitor/message-handler/prepare.ts @@ -17,6 +17,7 @@ import { resolveControlCommandGate } from "openclaw/plugin-sdk/command-gating"; import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime"; +import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-dispatch-runtime"; import { buildPendingHistoryContextFromMap, recordPendingHistoryEntryIfEnabled, @@ -50,7 +51,6 @@ import { normalizeSlackChannelType, type SlackMonitorContext } from "../context. import { recordInboundSession, resolveConversationLabel } from "../conversation.runtime.js"; import { authorizeSlackDirectMessage } from "../dm-auth.js"; import { resolveSlackThreadStarter } from "../media.js"; -import { finalizeInboundContext } from "../reply.runtime.js"; import { resolveSlackRoomContextHints } from "../room-context.js"; import { sendMessageSlack } from "../send.runtime.js"; import { resolveSlackMessageContent } from "./prepare-content.js"; diff --git a/extensions/slack/src/monitor/replies.ts b/extensions/slack/src/monitor/replies.ts index c1fca8fd9ab..8c5ef919064 100644 --- a/extensions/slack/src/monitor/replies.ts +++ b/extensions/slack/src/monitor/replies.ts @@ -1,20 +1,20 @@ import type { MarkdownTableMode, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; +import { + chunkMarkdownTextWithMode, + isSilentReplyText, + SILENT_REPLY_TOKEN, + type ChunkMode, +} from "openclaw/plugin-sdk/reply-chunking"; import { deliverTextOrMediaReply, resolveSendableOutboundReplyParts, + type ReplyPayload, } from "openclaw/plugin-sdk/reply-payload"; -import type { ChunkMode } from "openclaw/plugin-sdk/reply-runtime"; -import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; +import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-reference"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { markdownToSlackMrkdwnChunks } from "../format.js"; import { SLACK_TEXT_LIMIT } from "../limits.js"; import { resolveSlackReplyBlocks } from "../reply-blocks.js"; -import { - chunkMarkdownTextWithMode, - createReplyReferencePlanner, - isSilentReplyText, - SILENT_REPLY_TOKEN, -} from "./reply.runtime.js"; import { sendMessageSlack, type SlackSendIdentity } from "./send.runtime.js"; export function readSlackReplyBlocks(payload: ReplyPayload) { diff --git a/extensions/slack/src/outbound-payload.test.ts b/extensions/slack/src/outbound-payload.test.ts index f67c8cd9133..7d54f4d14e2 100644 --- a/extensions/slack/src/outbound-payload.test.ts +++ b/extensions/slack/src/outbound-payload.test.ts @@ -1,5 +1,5 @@ +import { installChannelOutboundPayloadContractSuite } from "openclaw/plugin-sdk/channel-contract-testing"; import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; -import { installChannelOutboundPayloadContractSuite } from "openclaw/plugin-sdk/testing"; import { describe, expect, it } from "vitest"; import { createSlackOutboundPayloadHarness } from "../test-api.js"; diff --git a/package.json b/package.json index 90db1ab5461..ac33940ba7c 100644 --- a/package.json +++ b/package.json @@ -509,6 +509,10 @@ "types": "./dist/plugin-sdk/boolean-param.d.ts", "default": "./dist/plugin-sdk/boolean-param.js" }, + "./plugin-sdk/channel-contract-testing": { + "types": "./dist/plugin-sdk/channel-contract-testing.d.ts", + "default": "./dist/plugin-sdk/channel-contract-testing.js" + }, "./plugin-sdk/dangerous-name-runtime": { "types": "./dist/plugin-sdk/dangerous-name-runtime.d.ts", "default": "./dist/plugin-sdk/dangerous-name-runtime.js" diff --git a/scripts/lib/plugin-sdk-entrypoints.json b/scripts/lib/plugin-sdk-entrypoints.json index 312c91c380a..517698b374f 100644 --- a/scripts/lib/plugin-sdk-entrypoints.json +++ b/scripts/lib/plugin-sdk-entrypoints.json @@ -113,6 +113,7 @@ "browser-setup-tools", "browser-support", "boolean-param", + "channel-contract-testing", "dangerous-name-runtime", "command-auth", "command-auth-native", diff --git a/src/plugin-sdk/channel-contract-testing.ts b/src/plugin-sdk/channel-contract-testing.ts new file mode 100644 index 00000000000..c5c87d46bb6 --- /dev/null +++ b/src/plugin-sdk/channel-contract-testing.ts @@ -0,0 +1,8 @@ +export { + expectChannelInboundContextContract, + primeChannelOutboundSendMock, +} from "../channels/plugins/contracts/test-helpers.js"; +export { + installChannelOutboundPayloadContractSuite, + type OutboundPayloadHarnessParams, +} from "../channels/plugins/contracts/outbound-payload-testkit.js"; diff --git a/src/plugin-sdk/reply-chunking.ts b/src/plugin-sdk/reply-chunking.ts index f572c0835ad..687f4c7ac88 100644 --- a/src/plugin-sdk/reply-chunking.ts +++ b/src/plugin-sdk/reply-chunking.ts @@ -6,5 +6,5 @@ export { resolveTextChunkLimit, } from "../auto-reply/chunk.js"; export type { ChunkMode } from "../auto-reply/chunk.js"; -export { isSilentReplyText } from "../auto-reply/tokens.js"; +export { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; export type { ReplyPayload } from "./reply-payload.js";