Skip to content

Commit e420592

Browse files
committed
refactor(discord): split runtime helpers
1 parent 6de9d71 commit e420592

15 files changed

Lines changed: 1106 additions & 1048 deletions
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import {
2+
normalizeLowercaseStringOrEmpty,
3+
normalizeOptionalString,
4+
normalizeOptionalStringifiedId,
5+
} from "openclaw/plugin-sdk/text-runtime";
6+
import { resolveDiscordCurrentConversationIdentity } from "./conversation-identity.js";
7+
import { normalizeDiscordMessagingTarget } from "./normalize.js";
8+
import { parseDiscordTarget } from "./target-parsing.js";
9+
10+
export function resolveDiscordAttachedOutboundTarget(params: {
11+
to: string;
12+
threadId?: string | number | null;
13+
}): string {
14+
if (params.threadId == null) {
15+
return params.to;
16+
}
17+
const threadId = normalizeOptionalStringifiedId(params.threadId) ?? "";
18+
return threadId ? `channel:${threadId}` : params.to;
19+
}
20+
21+
export function buildDiscordCrossContextPresentation(params: {
22+
originLabel: string;
23+
message: string;
24+
}) {
25+
const trimmed = params.message.trim();
26+
return {
27+
tone: "neutral" as const,
28+
blocks: [
29+
...(trimmed
30+
? ([{ type: "text" as const, text: params.message }, { type: "divider" as const }] as const)
31+
: []),
32+
{ type: "context" as const, text: `From ${params.originLabel}` },
33+
],
34+
};
35+
}
36+
37+
export function normalizeDiscordAcpConversationId(conversationId: string) {
38+
const normalized = conversationId.trim();
39+
return normalized ? { conversationId: normalized } : null;
40+
}
41+
42+
export function matchDiscordAcpConversation(params: {
43+
bindingConversationId: string;
44+
conversationId: string;
45+
parentConversationId?: string;
46+
}) {
47+
if (params.bindingConversationId === params.conversationId) {
48+
return { conversationId: params.conversationId, matchPriority: 2 };
49+
}
50+
if (
51+
params.parentConversationId &&
52+
params.parentConversationId !== params.conversationId &&
53+
params.bindingConversationId === params.parentConversationId
54+
) {
55+
return {
56+
conversationId: params.parentConversationId,
57+
matchPriority: 1,
58+
};
59+
}
60+
return null;
61+
}
62+
63+
function resolveDiscordConversationIdFromTargets(
64+
targets: Array<string | undefined>,
65+
): string | undefined {
66+
for (const raw of targets) {
67+
const trimmed = raw?.trim();
68+
if (!trimmed) {
69+
continue;
70+
}
71+
try {
72+
const target = parseDiscordTarget(trimmed, { defaultKind: "channel" });
73+
if (target?.normalized) {
74+
return target.normalized;
75+
}
76+
} catch {
77+
const mentionMatch = trimmed.match(/^<#(\d+)>$/);
78+
if (mentionMatch?.[1]) {
79+
return `channel:${mentionMatch[1]}`;
80+
}
81+
if (/^\d{6,}$/.test(trimmed)) {
82+
return normalizeDiscordMessagingTarget(trimmed);
83+
}
84+
}
85+
}
86+
return undefined;
87+
}
88+
89+
function parseDiscordParentChannelFromSessionKey(raw: unknown): string | undefined {
90+
const sessionKey = normalizeLowercaseStringOrEmpty(raw);
91+
if (!sessionKey) {
92+
return undefined;
93+
}
94+
const match = sessionKey.match(/(?:^|:)channel:([^:]+)$/);
95+
return match?.[1] ? `channel:${match[1]}` : undefined;
96+
}
97+
98+
export function resolveDiscordCommandConversation(params: {
99+
threadId?: string;
100+
threadParentId?: string;
101+
parentSessionKey?: string;
102+
from?: string;
103+
chatType?: string;
104+
originatingTo?: string;
105+
commandTo?: string;
106+
fallbackTo?: string;
107+
}) {
108+
const targets = [params.originatingTo, params.commandTo, params.fallbackTo];
109+
if (params.threadId) {
110+
const parentConversationId =
111+
normalizeDiscordMessagingTarget(normalizeOptionalString(params.threadParentId) ?? "") ||
112+
parseDiscordParentChannelFromSessionKey(params.parentSessionKey) ||
113+
resolveDiscordConversationIdFromTargets(targets);
114+
return {
115+
conversationId: params.threadId,
116+
...(parentConversationId && parentConversationId !== params.threadId
117+
? { parentConversationId }
118+
: {}),
119+
};
120+
}
121+
const conversationId = resolveDiscordCurrentConversationIdentity({
122+
from: params.from,
123+
chatType: params.chatType,
124+
originatingTo: params.originatingTo,
125+
commandTo: params.commandTo,
126+
fallbackTo: params.fallbackTo,
127+
});
128+
return conversationId ? { conversationId } : null;
129+
}
130+
131+
export function resolveDiscordInboundConversation(params: {
132+
from?: string;
133+
to?: string;
134+
conversationId?: string;
135+
isGroup: boolean;
136+
}) {
137+
const conversationId = resolveDiscordCurrentConversationIdentity({
138+
from: params.from,
139+
chatType: params.isGroup ? "group" : "direct",
140+
originatingTo: params.to,
141+
fallbackTo: params.conversationId,
142+
});
143+
return conversationId ? { conversationId } : null;
144+
}
145+
146+
export function parseDiscordExplicitTarget(raw: string) {
147+
try {
148+
const target = parseDiscordTarget(raw, { defaultKind: "channel" });
149+
if (!target) {
150+
return null;
151+
}
152+
return {
153+
to: target.normalized,
154+
chatType: target.kind === "user" ? ("direct" as const) : ("channel" as const),
155+
};
156+
} catch {
157+
return null;
158+
}
159+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
2+
3+
let discordProviderRuntimePromise:
4+
| Promise<typeof import("./monitor/provider.runtime.js")>
5+
| undefined;
6+
let discordProbeRuntimePromise: Promise<typeof import("./probe.runtime.js")> | undefined;
7+
let discordAuditModulePromise: Promise<typeof import("./audit.js")> | undefined;
8+
let discordSendModulePromise: Promise<typeof import("./send.js")> | undefined;
9+
let discordDirectoryLiveModulePromise: Promise<typeof import("./directory-live.js")> | undefined;
10+
11+
export const loadDiscordDirectoryConfigModule = createLazyRuntimeModule(
12+
() => import("./directory-config.js"),
13+
);
14+
export const loadDiscordResolveChannelsModule = createLazyRuntimeModule(
15+
() => import("./resolve-channels.js"),
16+
);
17+
export const loadDiscordResolveUsersModule = createLazyRuntimeModule(
18+
() => import("./resolve-users.js"),
19+
);
20+
export const loadDiscordThreadBindingsManagerModule = createLazyRuntimeModule(
21+
() => import("./monitor/thread-bindings.manager.js"),
22+
);
23+
24+
export async function loadDiscordProviderRuntime() {
25+
discordProviderRuntimePromise ??= import("./monitor/provider.runtime.js");
26+
return await discordProviderRuntimePromise;
27+
}
28+
29+
export async function loadDiscordProbeRuntime() {
30+
discordProbeRuntimePromise ??= import("./probe.runtime.js");
31+
return await discordProbeRuntimePromise;
32+
}
33+
34+
export async function loadDiscordAuditModule() {
35+
discordAuditModulePromise ??= import("./audit.js");
36+
return await discordAuditModulePromise;
37+
}
38+
39+
export async function loadDiscordSendModule() {
40+
discordSendModulePromise ??= import("./send.js");
41+
return await discordSendModulePromise;
42+
}
43+
44+
export async function loadDiscordDirectoryLiveModule() {
45+
discordDirectoryLiveModulePromise ??= import("./directory-live.js");
46+
return await discordDirectoryLiveModulePromise;
47+
}
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1 @@
1-
import { createDiscordSetupWizardProxy } from "./setup-core.js";
2-
3-
type DiscordSetupWizard = typeof import("./setup-surface.js").discordSetupWizard;
4-
5-
export const discordSetupWizard: DiscordSetupWizard = createDiscordSetupWizardProxy(
6-
async () => (await import("./setup-surface.js")).discordSetupWizard,
7-
);
1+
export { discordSetupWizard } from "./setup-surface.js";

0 commit comments

Comments
 (0)