mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 00:20:22 +00:00
fix(regression): preserve discord thread bindings for plugin commands
This commit is contained in:
@@ -39,6 +39,7 @@ vi.mock("openclaw/plugin-sdk/reply-runtime", async (importOriginal) => {
|
||||
function createInteraction(params?: {
|
||||
channelType?: ChannelType;
|
||||
channelId?: string;
|
||||
threadParentId?: string | null;
|
||||
guildId?: string;
|
||||
guildName?: string;
|
||||
}): MockCommandInteraction {
|
||||
@@ -48,6 +49,7 @@ function createInteraction(params?: {
|
||||
globalName: "Tester",
|
||||
channelType: params?.channelType ?? ChannelType.DM,
|
||||
channelId: params?.channelId ?? "dm-1",
|
||||
threadParentId: params?.threadParentId,
|
||||
guildId: params?.guildId ?? null,
|
||||
guildName: params?.guildName,
|
||||
interactionId: "interaction-1",
|
||||
@@ -501,6 +503,73 @@ describe("Discord native plugin command dispatch", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards Discord thread metadata into direct plugin command execution", async () => {
|
||||
const cfg = {
|
||||
commands: {
|
||||
useAccessGroups: false,
|
||||
},
|
||||
channels: {
|
||||
discord: {
|
||||
groupPolicy: "allowlist",
|
||||
guilds: {
|
||||
"345678901234567890": {
|
||||
channels: {
|
||||
"thread-123": {
|
||||
allow: true,
|
||||
requireMention: false,
|
||||
},
|
||||
"parent-456": {
|
||||
allow: true,
|
||||
requireMention: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const commandSpec: NativeCommandSpec = {
|
||||
name: "cron_jobs",
|
||||
description: "List cron jobs",
|
||||
acceptsArgs: false,
|
||||
};
|
||||
const interaction = createInteraction({
|
||||
channelType: ChannelType.PublicThread,
|
||||
channelId: "thread-123",
|
||||
threadParentId: "parent-456",
|
||||
guildId: "345678901234567890",
|
||||
guildName: "Test Guild",
|
||||
});
|
||||
const pluginMatch = {
|
||||
command: {
|
||||
name: "cron_jobs",
|
||||
description: "List cron jobs",
|
||||
pluginId: "cron-jobs",
|
||||
acceptsArgs: false,
|
||||
handler: vi.fn().mockResolvedValue({ text: "jobs" }),
|
||||
},
|
||||
args: undefined,
|
||||
};
|
||||
|
||||
runtimeModuleMocks.matchPluginCommand.mockReturnValue(pluginMatch as never);
|
||||
const executeSpy = runtimeModuleMocks.executePluginCommand.mockResolvedValue({
|
||||
text: "direct plugin output",
|
||||
});
|
||||
const command = await createNativeCommand(cfg, commandSpec);
|
||||
|
||||
await (command as { run: (interaction: unknown) => Promise<void> }).run(interaction as unknown);
|
||||
|
||||
expect(executeSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
channel: "discord",
|
||||
from: "discord:channel:thread-123",
|
||||
to: "slash:owner",
|
||||
messageThreadId: "thread-123",
|
||||
threadParentId: "parent-456",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("routes native slash commands through configured ACP Discord channel bindings", async () => {
|
||||
const { cfg, interaction } = createConfiguredAcpCase({
|
||||
channelType: ChannelType.GuildText,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { vi } from "vitest";
|
||||
|
||||
export type MockCommandInteraction = {
|
||||
user: { id: string; username: string; globalName: string };
|
||||
channel: { type: ChannelType; id: string };
|
||||
channel: { type: ChannelType; id: string; parentId?: string | null };
|
||||
guild: { id: string; name?: string } | null;
|
||||
rawData: { id: string; member: { roles: string[] } };
|
||||
options: {
|
||||
@@ -22,6 +22,7 @@ type CreateMockCommandInteractionParams = {
|
||||
globalName?: string;
|
||||
channelType?: ChannelType;
|
||||
channelId?: string;
|
||||
threadParentId?: string | null;
|
||||
guildId?: string | null;
|
||||
guildName?: string;
|
||||
interactionId?: string;
|
||||
@@ -42,6 +43,7 @@ export function createMockCommandInteraction(
|
||||
channel: {
|
||||
type: params.channelType ?? ChannelType.DM,
|
||||
id: params.channelId ?? "dm-1",
|
||||
parentId: params.threadParentId,
|
||||
},
|
||||
guild,
|
||||
rawData: {
|
||||
|
||||
@@ -917,6 +917,13 @@ async function dispatchDiscordCommandInteraction(params: {
|
||||
return;
|
||||
}
|
||||
const channelId = rawChannelId || "unknown";
|
||||
const isThreadChannel =
|
||||
interaction.channel?.type === ChannelType.PublicThread ||
|
||||
interaction.channel?.type === ChannelType.PrivateThread ||
|
||||
interaction.channel?.type === ChannelType.AnnouncementThread;
|
||||
const messageThreadId = !isDirectMessage && isThreadChannel ? channelId : undefined;
|
||||
const threadParentId =
|
||||
!isDirectMessage && isThreadChannel ? (interaction.channel.parentId ?? undefined) : undefined;
|
||||
const pluginReply = await executePluginCommandImpl({
|
||||
command: pluginMatch.command,
|
||||
args: pluginMatch.args,
|
||||
@@ -933,6 +940,8 @@ async function dispatchDiscordCommandInteraction(params: {
|
||||
: `discord:channel:${channelId}`,
|
||||
to: `slash:${user.id}`,
|
||||
accountId,
|
||||
messageThreadId,
|
||||
threadParentId,
|
||||
});
|
||||
if (!hasRenderableReplyPayload(pluginReply)) {
|
||||
await respond("Done.");
|
||||
|
||||
Reference in New Issue
Block a user