refactor: streamline target resolver helpers

This commit is contained in:
Peter Steinberger
2026-01-17 07:33:43 +00:00
parent cf0ea6c756
commit 07c93dfd30
8 changed files with 63 additions and 49 deletions

View File

@@ -164,13 +164,15 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount> = {
},
messaging: {
normalizeTarget: normalizeMatrixMessagingTarget,
looksLikeTargetId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
if (/^(matrix:)?[!#@]/i.test(trimmed)) return true;
return trimmed.includes(":");
targetResolver: {
looksLikeId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
if (/^(matrix:)?[!#@]/i.test(trimmed)) return true;
return trimmed.includes(":");
},
hint: "<room|alias|user>",
},
targetHint: "<room|alias|user>",
},
directory: {
self: async () => null,

View File

@@ -133,13 +133,15 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
},
messaging: {
normalizeTarget: normalizeMSTeamsMessagingTarget,
looksLikeTargetId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
if (/^(conversation:|user:)/i.test(trimmed)) return true;
return trimmed.includes("@thread");
targetResolver: {
looksLikeId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
if (/^(conversation:|user:)/i.test(trimmed)) return true;
return trimmed.includes("@thread");
},
hint: "<conversationId|user:ID|conversation:ID>",
},
targetHint: "<conversationId|user:ID|conversation:ID>",
},
directory: {
self: async () => null,

View File

@@ -150,12 +150,14 @@ export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
actions: zaloMessageActions,
messaging: {
normalizeTarget: normalizeZaloMessagingTarget,
looksLikeTargetId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
return /^\d{3,}$/.test(trimmed);
targetResolver: {
looksLikeId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
return /^\d{3,}$/.test(trimmed);
},
hint: "<chatId>",
},
targetHint: "<chatId>",
},
directory: {
self: async () => null,

View File

@@ -218,12 +218,14 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
if (!trimmed) return undefined;
return trimmed.replace(/^(zalouser|zlu):/i, "");
},
looksLikeTargetId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
return /^\d{3,}$/.test(trimmed);
targetResolver: {
looksLikeId: (raw) => {
const trimmed = raw.trim();
if (!trimmed) return false;
return /^\d{3,}$/.test(trimmed);
},
hint: "<threadId>",
},
targetHint: "<threadId>",
},
directory: {
self: async ({ cfg, accountId, runtime }) => {

View File

@@ -74,4 +74,15 @@ export function normalizeChannelId(raw?: string | null): ChannelId | null {
}
export { discordPlugin, imessagePlugin, signalPlugin, slackPlugin, telegramPlugin, whatsappPlugin };
export {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
listWhatsAppDirectoryGroupsFromConfig,
listWhatsAppDirectoryPeersFromConfig,
type DirectoryConfigParams,
} from "./directory-config.js";
export type { ChannelId, ChannelPlugin } from "./types.js";

View File

@@ -1,5 +1,7 @@
import { formatTargetHint } from "./target-format.js";
export function missingTargetMessage(provider: string, hint?: string): string {
return `Delivering to ${provider} requires target${formatHint(hint)}`;
return `Delivering to ${provider} requires target${formatTargetHint(hint)}`;
}
export function missingTargetError(provider: string, hint?: string): Error {
@@ -7,7 +9,7 @@ export function missingTargetError(provider: string, hint?: string): Error {
}
export function ambiguousTargetMessage(provider: string, raw: string, hint?: string): string {
return `Ambiguous target "${raw}" for ${provider}. Provide a unique name or an explicit id.${formatHint(hint, true)}`;
return `Ambiguous target "${raw}" for ${provider}. Provide a unique name or an explicit id.${formatTargetHint(hint, true)}`;
}
export function ambiguousTargetError(provider: string, raw: string, hint?: string): Error {
@@ -15,14 +17,9 @@ export function ambiguousTargetError(provider: string, raw: string, hint?: strin
}
export function unknownTargetMessage(provider: string, raw: string, hint?: string): string {
return `Unknown target "${raw}" for ${provider}.${formatHint(hint, true)}`;
return `Unknown target "${raw}" for ${provider}.${formatTargetHint(hint, true)}`;
}
export function unknownTargetError(provider: string, raw: string, hint?: string): Error {
return new Error(unknownTargetMessage(provider, raw, hint));
}
function formatHint(hint?: string, withLabel = false): string {
if (!hint) return "";
return withLabel ? ` Hint: ${hint}` : ` ${hint}`;
}

View File

@@ -0,0 +1,4 @@
export function formatTargetHint(hint?: string, withLabel = false): string {
if (!hint) return "";
return withLabel ? ` Hint: ${hint}` : ` ${hint}`;
}

View File

@@ -164,24 +164,6 @@ function resolveMatch(params: {
return { kind: "ambiguous" as const, entries: matches };
}
function looksLikeTargetId(params: {
channel: ChannelId;
raw: string;
normalized: string;
}): boolean {
const raw = params.raw.trim();
if (!raw) return false;
const plugin = getChannelPlugin(params.channel);
const lookup = plugin?.messaging?.targetResolver?.looksLikeId;
if (lookup) return lookup(raw, params.normalized);
if (/^(channel|group|user):/i.test(raw)) return true;
if (/^[@#]/.test(raw)) return true;
if (/^\+?\d{6,}$/.test(raw)) return true;
if (raw.includes("@thread")) return true;
if (/^(conversation|user):/i.test(raw)) return true;
return false;
}
async function listDirectoryEntries(params: {
cfg: ClawdbotConfig;
channel: ChannelId;
@@ -288,7 +270,19 @@ export async function resolveMessagingTarget(params: {
const hint = plugin?.messaging?.targetResolver?.hint;
const kind = detectTargetKind(raw, params.preferredKind);
const normalized = normalizeTargetForProvider(params.channel, raw) ?? raw;
if (looksLikeTargetId({ channel: params.channel, raw, normalized })) {
const looksLikeTargetId = (): boolean => {
const trimmed = raw.trim();
if (!trimmed) return false;
const lookup = plugin?.messaging?.targetResolver?.looksLikeId;
if (lookup) return lookup(trimmed, normalized);
if (/^(channel|group|user):/i.test(trimmed)) return true;
if (/^[@#]/.test(trimmed)) return true;
if (/^\+?\d{6,}$/.test(trimmed)) return true;
if (trimmed.includes("@thread")) return true;
if (/^(conversation|user):/i.test(trimmed)) return true;
return false;
};
if (looksLikeTargetId()) {
const directTarget = preserveTargetCase(params.channel, raw, normalized);
return {
ok: true,