





















@@ -5,9 +5,12 @@ import {
55} from "openclaw/plugin-sdk/text-runtime";
66import { resolveDiscordDirectoryUserId } from "./directory-cache.js";
778+type DiscordMentionAliasesConfig = Record<string, string>;
9+810const MARKDOWN_CODE_SEGMENT_PATTERN = /```[\s\S]*?```|`[^`\n]*`/g;
911const MENTION_CANDIDATE_PATTERN = /(^|[\s([{"'.,;:!?])@([a-z0-9_.-]{2,32}(?:#[0-9]{4})?)/gi;
1012const DISCORD_RESERVED_MENTIONS = new Set(["everyone", "here"]);
13+const DISCORD_DISCRIMINATOR_SUFFIX = /#\d{4}$/;
11141215function normalizeSnowflake(value: string | number | bigint): string | null {
1316const text = normalizeOptionalStringifiedId(value) ?? "";
@@ -43,7 +46,58 @@ export function formatMention(params: {
4346return `<#${target.id}>`;
4447}
454846-function rewritePlainTextMentions(text: string, accountId?: string | null): string {
49+function normalizeHandleKey(raw: string): string | null {
50+let handle = normalizeOptionalString(raw) ?? "";
51+if (!handle) {
52+return null;
53+}
54+if (handle.startsWith("@")) {
55+handle = normalizeOptionalString(handle.slice(1)) ?? "";
56+}
57+if (!handle || /\s/.test(handle)) {
58+return null;
59+}
60+return normalizeLowercaseStringOrEmpty(handle);
61+}
62+63+function resolveConfiguredMentionAlias(
64+handle: string,
65+mentionAliases?: DiscordMentionAliasesConfig | null,
66+): string | undefined {
67+const key = normalizeHandleKey(handle);
68+if (!key || !mentionAliases) {
69+return undefined;
70+}
71+const withoutDiscriminator = key.replace(DISCORD_DISCRIMINATOR_SUFFIX, "");
72+for (const [rawAlias, rawUserId] of Object.entries(mentionAliases)) {
73+const alias = normalizeHandleKey(rawAlias);
74+if (!alias) {
75+continue;
76+}
77+const aliasWithoutDiscriminator = alias.replace(DISCORD_DISCRIMINATOR_SUFFIX, "");
78+if (
79+alias === key ||
80+(withoutDiscriminator && withoutDiscriminator !== key && alias === withoutDiscriminator) ||
81+(aliasWithoutDiscriminator &&
82+aliasWithoutDiscriminator !== alias &&
83+aliasWithoutDiscriminator === key)
84+) {
85+const userId = normalizeSnowflake(rawUserId);
86+if (userId) {
87+return userId;
88+}
89+}
90+}
91+return undefined;
92+}
93+94+function rewritePlainTextMentions(
95+text: string,
96+params: {
97+accountId?: string | null;
98+mentionAliases?: DiscordMentionAliasesConfig | null;
99+},
100+): string {
47101if (!text.includes("@")) {
48102return text;
49103}
@@ -56,10 +110,12 @@ function rewritePlainTextMentions(text: string, accountId?: string | null): stri
56110if (DISCORD_RESERVED_MENTIONS.has(lookup)) {
57111return match;
58112}
59-const userId = resolveDiscordDirectoryUserId({
60- accountId,
61- handle,
62-});
113+const userId =
114+resolveConfiguredMentionAlias(handle, params.mentionAliases) ??
115+resolveDiscordDirectoryUserId({
116+accountId: params.accountId,
117+ handle,
118+});
63119if (!userId) {
64120return match;
65121}
@@ -69,7 +125,10 @@ function rewritePlainTextMentions(text: string, accountId?: string | null): stri
6912570126export function rewriteDiscordKnownMentions(
71127text: string,
72-params: { accountId?: string | null },
128+params: {
129+accountId?: string | null;
130+mentionAliases?: DiscordMentionAliasesConfig | null;
131+},
73132): string {
74133if (!text.includes("@")) {
75134return text;
@@ -79,10 +138,10 @@ export function rewriteDiscordKnownMentions(
79138MARKDOWN_CODE_SEGMENT_PATTERN.lastIndex = 0;
80139for (const match of text.matchAll(MARKDOWN_CODE_SEGMENT_PATTERN)) {
81140const matchIndex = match.index ?? 0;
82-rewritten += rewritePlainTextMentions(text.slice(offset, matchIndex), params.accountId);
141+rewritten += rewritePlainTextMentions(text.slice(offset, matchIndex), params);
83142rewritten += match[0];
84143offset = matchIndex + match[0].length;
85144}
86-rewritten += rewritePlainTextMentions(text.slice(offset), params.accountId);
145+rewritten += rewritePlainTextMentions(text.slice(offset), params);
87146return rewritten;
88147}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。