Plugins: move config-backed directories behind channel plugins

This commit is contained in:
Gustavo Madeira Santana
2026-03-18 04:27:29 +00:00
parent b86bc9de95
commit 2b5fa0931d
22 changed files with 285 additions and 312 deletions

View File

@@ -18,6 +18,10 @@ import {
type ResolvedDiscordAccount,
} from "./accounts.js";
import { auditDiscordChannelPermissions, collectDiscordAuditChannelIds } from "./audit.js";
import {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
} from "./directory-config.js";
import {
isDiscordExecApprovalClientEnabled,
shouldSuppressLocalDiscordExecApprovalPrompt,
@@ -41,8 +45,6 @@ import {
type ChannelPlugin,
DEFAULT_ACCOUNT_ID,
getChatChannelMeta,
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
PAIRING_APPROVED_MESSAGE,
projectCredentialSnapshotFields,
resolveConfiguredFromCredentialStatuses,

View File

@@ -0,0 +1,57 @@
import {
applyDirectoryQueryAndLimit,
collectNormalizedDirectoryIds,
toDirectoryEntries,
type DirectoryConfigParams,
} from "openclaw/plugin-sdk/directory-runtime";
import type { InspectedDiscordAccount } from "../../../src/channels/read-only-account-inspect.discord.runtime.js";
import { inspectReadOnlyChannelAccount } from "../../../src/channels/read-only-account-inspect.js";
export async function listDiscordDirectoryPeersFromConfig(params: DirectoryConfigParams) {
const account = (await inspectReadOnlyChannelAccount({
channelId: "discord",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedDiscordAccount | null;
if (!account || !("config" in account)) {
return [];
}
const allowFrom = account.config.allowFrom ?? account.config.dm?.allowFrom ?? [];
const guildUsers = Object.values(account.config.guilds ?? {}).flatMap((guild) => [
...(guild.users ?? []),
...Object.values(guild.channels ?? {}).flatMap((channel) => channel.users ?? []),
]);
const ids = collectNormalizedDirectoryIds({
sources: [allowFrom, Object.keys(account.config.dms ?? {}), guildUsers],
normalizeId: (raw) => {
const mention = raw.match(/^<@!?(\d+)>$/);
const cleaned = (mention?.[1] ?? raw).replace(/^(discord|user):/i, "").trim();
return /^\d+$/.test(cleaned) ? `user:${cleaned}` : null;
},
});
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
}
export async function listDiscordDirectoryGroupsFromConfig(params: DirectoryConfigParams) {
const account = (await inspectReadOnlyChannelAccount({
channelId: "discord",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedDiscordAccount | null;
if (!account || !("config" in account)) {
return [];
}
const ids = collectNormalizedDirectoryIds({
sources: Object.values(account.config.guilds ?? {}).map((guild) =>
Object.keys(guild.channels ?? {}),
),
normalizeId: (raw) => {
const mention = raw.match(/^<#(\d+)>$/);
const cleaned = (mention?.[1] ?? raw).replace(/^(discord|channel|group):/i, "").trim();
return /^\d+$/.test(cleaned) ? `channel:${cleaned}` : null;
},
});
return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
}

View File

@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { DirectoryConfigParams } from "../../../src/channels/plugins/directory-config.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { DirectoryConfigParams } from "../../../src/plugin-sdk/directory-runtime.js";
import { listDiscordDirectoryGroupsLive, listDiscordDirectoryPeersLive } from "./directory-live.js";
function makeParams(overrides: Partial<DirectoryConfigParams> = {}): DirectoryConfigParams {

View File

@@ -1,8 +1,6 @@
export {
buildComputedAccountStatusSnapshot,
buildTokenChannelStatusSummary,
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
PAIRING_APPROVED_MESSAGE,
projectCredentialSnapshotFields,
resolveConfiguredFromCredentialStatuses,
@@ -20,6 +18,10 @@ export {
} from "openclaw/plugin-sdk/discord-core";
export { DiscordConfigSchema } from "openclaw/plugin-sdk/discord-core";
export { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
export {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
} from "./directory-config.js";
export {
createScopedAccountConfigAccessors,
createScopedChannelConfigBase,

View File

@@ -13,8 +13,6 @@ import { resolveThreadSessionKeys, type RoutePeer } from "openclaw/plugin-sdk/ro
import {
buildComputedAccountStatusSnapshot,
DEFAULT_ACCOUNT_ID,
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
looksLikeSlackTargetId,
normalizeSlackMessagingTarget,
PAIRING_APPROVED_MESSAGE,
@@ -34,6 +32,10 @@ import {
import { parseSlackBlocksInput } from "./blocks-input.js";
import { createSlackActions } from "./channel-actions.js";
import { createSlackWebClient } from "./client.js";
import {
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
} from "./directory-config.js";
import { resolveSlackGroupRequireMention, resolveSlackGroupToolPolicy } from "./group-policy.js";
import { isSlackInteractiveRepliesEnabled } from "./interactive-replies.js";
import { normalizeAllowListLower } from "./monitor/allow-list.js";

View File

@@ -0,0 +1,60 @@
import {
applyDirectoryQueryAndLimit,
collectNormalizedDirectoryIds,
listDirectoryGroupEntriesFromMapKeys,
toDirectoryEntries,
type DirectoryConfigParams,
} from "openclaw/plugin-sdk/directory-runtime";
import { normalizeSlackMessagingTarget } from "../../../src/channels/plugins/normalize/slack.js";
import { inspectReadOnlyChannelAccount } from "../../../src/channels/read-only-account-inspect.js";
import type { InspectedSlackAccount } from "../../../src/channels/read-only-account-inspect.slack.runtime.js";
export async function listSlackDirectoryPeersFromConfig(params: DirectoryConfigParams) {
const account = (await inspectReadOnlyChannelAccount({
channelId: "slack",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedSlackAccount | null;
if (!account || !("config" in account)) {
return [];
}
const allowFrom = account.config.allowFrom ?? account.dm?.allowFrom ?? [];
const channelUsers = Object.values(account.config.channels ?? {}).flatMap(
(channel) => channel.users ?? [],
);
const ids = collectNormalizedDirectoryIds({
sources: [allowFrom, Object.keys(account.config.dms ?? {}), channelUsers],
normalizeId: (raw) => {
const mention = raw.match(/^<@([A-Z0-9]+)>$/i);
const normalizedUserId = (mention?.[1] ?? raw).replace(/^(slack|user):/i, "").trim();
if (!normalizedUserId) {
return null;
}
const target = `user:${normalizedUserId}`;
const normalized = normalizeSlackMessagingTarget(target) ?? target.toLowerCase();
return normalized.startsWith("user:") ? normalized : null;
},
});
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
}
export async function listSlackDirectoryGroupsFromConfig(params: DirectoryConfigParams) {
const account = (await inspectReadOnlyChannelAccount({
channelId: "slack",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedSlackAccount | null;
if (!account || !("config" in account)) {
return [];
}
return listDirectoryGroupEntriesFromMapKeys({
groups: account.config.channels,
query: params.query,
limit: params.limit,
normalizeId: (raw) => {
const normalized = normalizeSlackMessagingTarget(raw) ?? raw.toLowerCase();
return normalized.startsWith("channel:") ? normalized : null;
},
});
}

View File

@@ -15,8 +15,6 @@ import {
buildTokenChannelStatusSummary,
clearAccountEntryFields,
DEFAULT_ACCOUNT_ID,
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
PAIRING_APPROVED_MESSAGE,
projectCredentialSnapshotFields,
resolveConfiguredFromCredentialStatuses,
@@ -32,6 +30,10 @@ import {
import { buildTelegramExecApprovalButtons } from "./approval-buttons.js";
import { auditTelegramGroupMembership, collectTelegramUnmentionedGroupIds } from "./audit.js";
import { buildTelegramGroupPeerId } from "./bot/helpers.js";
import {
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
} from "./directory-config.js";
import {
isTelegramExecApprovalClientEnabled,
resolveTelegramExecApprovalTarget,

View File

@@ -0,0 +1,52 @@
import { mapAllowFromEntries } from "openclaw/plugin-sdk/channel-config-helpers";
import {
applyDirectoryQueryAndLimit,
collectNormalizedDirectoryIds,
listDirectoryGroupEntriesFromMapKeys,
toDirectoryEntries,
type DirectoryConfigParams,
} from "openclaw/plugin-sdk/directory-runtime";
import { inspectReadOnlyChannelAccount } from "../../../src/channels/read-only-account-inspect.js";
import type { InspectedTelegramAccount } from "../../../src/channels/read-only-account-inspect.telegram.runtime.js";
export async function listTelegramDirectoryPeersFromConfig(params: DirectoryConfigParams) {
const account = (await inspectReadOnlyChannelAccount({
channelId: "telegram",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedTelegramAccount | null;
if (!account || !("config" in account)) {
return [];
}
const ids = collectNormalizedDirectoryIds({
sources: [mapAllowFromEntries(account.config.allowFrom), Object.keys(account.config.dms ?? {})],
normalizeId: (entry) => {
const trimmed = entry.replace(/^(telegram|tg):/i, "").trim();
if (!trimmed) {
return null;
}
if (/^-?\d+$/.test(trimmed)) {
return trimmed;
}
return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
},
});
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
}
export async function listTelegramDirectoryGroupsFromConfig(params: DirectoryConfigParams) {
const account = (await inspectReadOnlyChannelAccount({
channelId: "telegram",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedTelegramAccount | null;
if (!account || !("config" in account)) {
return [];
}
return listDirectoryGroupEntriesFromMapKeys({
groups: account.config.groups,
query: params.query,
limit: params.limit,
});
}

View File

@@ -4,8 +4,6 @@ import {
createWhatsAppOutboundBase,
DEFAULT_ACCOUNT_ID,
formatWhatsAppConfigAllowFromEntries,
listWhatsAppDirectoryGroupsFromConfig,
listWhatsAppDirectoryPeersFromConfig,
readStringParam,
resolveWhatsAppOutboundTarget,
resolveWhatsAppHeartbeatRecipients,
@@ -16,6 +14,10 @@ import {
import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "openclaw/plugin-sdk/whatsapp";
// WhatsApp-specific imports from local extension code (moved from src/web/ and src/channels/plugins/)
import { resolveWhatsAppAccount, type ResolvedWhatsAppAccount } from "./accounts.js";
import {
listWhatsAppDirectoryGroupsFromConfig,
listWhatsAppDirectoryPeersFromConfig,
} from "./directory-config.js";
import { looksLikeWhatsAppTargetId, normalizeWhatsAppMessagingTarget } from "./normalize.js";
import { getWhatsAppRuntime } from "./runtime.js";
import { resolveWhatsAppOutboundSessionRoute } from "./session-route.js";

View File

@@ -0,0 +1,32 @@
import {
listDirectoryGroupEntriesFromMapKeys,
listDirectoryUserEntriesFromAllowFrom,
type DirectoryConfigParams,
} from "openclaw/plugin-sdk/directory-runtime";
import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../../../src/whatsapp/normalize.js";
import { resolveWhatsAppAccount } from "./accounts.js";
export async function listWhatsAppDirectoryPeersFromConfig(params: DirectoryConfigParams) {
const account = resolveWhatsAppAccount({ cfg: params.cfg, accountId: params.accountId });
return listDirectoryUserEntriesFromAllowFrom({
allowFrom: account.allowFrom,
query: params.query,
limit: params.limit,
normalizeId: (entry) => {
const normalized = normalizeWhatsAppTarget(entry);
if (!normalized || isWhatsAppGroupJid(normalized)) {
return null;
}
return normalized;
},
});
}
export async function listWhatsAppDirectoryGroupsFromConfig(params: DirectoryConfigParams) {
const account = resolveWhatsAppAccount({ cfg: params.cfg, accountId: params.accountId });
return listDirectoryGroupEntriesFromMapKeys({
groups: account.groups,
query: params.query,
limit: params.limit,
});
}

View File

@@ -60,6 +60,27 @@ function dedupeDirectoryIds(ids: string[]): string[] {
return Array.from(new Set(ids));
}
export function collectNormalizedDirectoryIds(params: {
sources: Iterable<unknown>[];
normalizeId: (entry: string) => string | null | undefined;
}): string[] {
const ids = new Set<string>();
for (const source of params.sources) {
for (const value of source) {
const raw = String(value).trim();
if (!raw || raw === "*") {
continue;
}
const normalized = params.normalizeId(raw);
const trimmed = typeof normalized === "string" ? normalized.trim() : "";
if (trimmed) {
ids.add(trimmed);
}
}
}
return Array.from(ids);
}
export function listDirectoryUserEntriesFromAllowFrom(params: {
allowFrom?: readonly unknown[];
query?: string | null;

View File

@@ -1,263 +0,0 @@
import type { OpenClawConfig } from "../../config/types.js";
import { mapAllowFromEntries } from "../../plugin-sdk/channel-config-helpers.js";
import { isWhatsAppGroupJid, normalizeWhatsAppTarget } from "../../whatsapp/normalize.js";
import type { InspectedDiscordAccount } from "../read-only-account-inspect.discord.runtime.js";
import { inspectReadOnlyChannelAccount } from "../read-only-account-inspect.js";
import type { InspectedSlackAccount } from "../read-only-account-inspect.slack.runtime.js";
import type { InspectedTelegramAccount } from "../read-only-account-inspect.telegram.runtime.js";
import { applyDirectoryQueryAndLimit, toDirectoryEntries } from "./directory-config-helpers.js";
import { normalizeSlackMessagingTarget } from "./normalize/slack.js";
import { getChannelPlugin } from "./registry.js";
import type { ChannelDirectoryEntry } from "./types.js";
export type DirectoryConfigParams = {
cfg: OpenClawConfig;
accountId?: string | null;
query?: string | null;
limit?: number | null;
};
function addAllowFromAndDmsIds(
ids: Set<string>,
allowFrom: readonly unknown[] | undefined,
dms: Record<string, unknown> | undefined,
) {
for (const entry of allowFrom ?? []) {
const raw = String(entry).trim();
if (!raw || raw === "*") {
continue;
}
ids.add(raw);
}
addTrimmedEntries(ids, Object.keys(dms ?? {}));
}
function addTrimmedId(ids: Set<string>, value: unknown) {
const trimmed = String(value).trim();
if (trimmed) {
ids.add(trimmed);
}
}
function addTrimmedEntries(ids: Set<string>, values: Iterable<unknown>) {
for (const value of values) {
addTrimmedId(ids, value);
}
}
function normalizeTrimmedSet(
ids: Set<string>,
normalize: (raw: string) => string | null,
): string[] {
return Array.from(ids)
.map((raw) => raw.trim())
.filter(Boolean)
.map((raw) => normalize(raw))
.filter((id): id is string => Boolean(id));
}
function objectValues<T>(value: Record<string, T> | undefined): T[] {
return Object.values(value ?? {});
}
export async function listSlackDirectoryPeersFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = (await inspectReadOnlyChannelAccount({
channelId: "slack",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedSlackAccount | null;
if (!account || !("config" in account)) {
return [];
}
const ids = new Set<string>();
addAllowFromAndDmsIds(ids, account.config.allowFrom ?? account.dm?.allowFrom, account.config.dms);
for (const channel of Object.values(account.config.channels ?? {})) {
addTrimmedEntries(ids, channel.users ?? []);
}
const normalizedIds = normalizeTrimmedSet(ids, (raw) => {
const mention = raw.match(/^<@([A-Z0-9]+)>$/i);
const normalizedUserId = (mention?.[1] ?? raw).replace(/^(slack|user):/i, "").trim();
if (!normalizedUserId) {
return null;
}
const target = `user:${normalizedUserId}`;
return normalizeSlackMessagingTarget(target) ?? target.toLowerCase();
}).filter((id) => id.startsWith("user:"));
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(normalizedIds, params));
}
export async function listSlackDirectoryGroupsFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = (await inspectReadOnlyChannelAccount({
channelId: "slack",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedSlackAccount | null;
if (!account || !("config" in account)) {
return [];
}
const ids = Object.keys(account.config.channels ?? {})
.map((raw) => raw.trim())
.filter(Boolean)
.map((raw) => normalizeSlackMessagingTarget(raw) ?? raw.toLowerCase())
.filter((id) => id.startsWith("channel:"));
return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
}
export async function listDiscordDirectoryPeersFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = (await inspectReadOnlyChannelAccount({
channelId: "discord",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedDiscordAccount | null;
if (!account || !("config" in account)) {
return [];
}
const ids = new Set<string>();
addAllowFromAndDmsIds(
ids,
account.config.allowFrom ?? account.config.dm?.allowFrom,
account.config.dms,
);
for (const guild of objectValues(account.config.guilds)) {
addTrimmedEntries(ids, guild.users ?? []);
for (const channel of objectValues(guild.channels)) {
addTrimmedEntries(ids, channel.users ?? []);
}
}
const normalizedIds = normalizeTrimmedSet(ids, (raw) => {
const mention = raw.match(/^<@!?(\d+)>$/);
const cleaned = (mention?.[1] ?? raw).replace(/^(discord|user):/i, "").trim();
if (!/^\d+$/.test(cleaned)) {
return null;
}
return `user:${cleaned}`;
});
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(normalizedIds, params));
}
export async function listDiscordDirectoryGroupsFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = (await inspectReadOnlyChannelAccount({
channelId: "discord",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedDiscordAccount | null;
if (!account || !("config" in account)) {
return [];
}
const ids = new Set<string>();
for (const guild of objectValues(account.config.guilds)) {
addTrimmedEntries(ids, Object.keys(guild.channels ?? {}));
}
const normalizedIds = normalizeTrimmedSet(ids, (raw) => {
const mention = raw.match(/^<#(\d+)>$/);
const cleaned = (mention?.[1] ?? raw).replace(/^(discord|channel|group):/i, "").trim();
if (!/^\d+$/.test(cleaned)) {
return null;
}
return `channel:${cleaned}`;
});
return toDirectoryEntries("group", applyDirectoryQueryAndLimit(normalizedIds, params));
}
export async function listTelegramDirectoryPeersFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = (await inspectReadOnlyChannelAccount({
channelId: "telegram",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedTelegramAccount | null;
if (!account || !("config" in account)) {
return [];
}
const raw = [
...mapAllowFromEntries(account.config.allowFrom),
...Object.keys(account.config.dms ?? {}),
];
const ids = Array.from(
new Set(
raw
.map((entry) => entry.trim())
.filter(Boolean)
.map((entry) => entry.replace(/^(telegram|tg):/i, "")),
),
)
.map((entry) => {
const trimmed = entry.trim();
if (!trimmed) {
return null;
}
if (/^-?\d+$/.test(trimmed)) {
return trimmed;
}
const withAt = trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
return withAt;
})
.filter((id): id is string => Boolean(id));
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
}
export async function listTelegramDirectoryGroupsFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = (await inspectReadOnlyChannelAccount({
channelId: "telegram",
cfg: params.cfg,
accountId: params.accountId,
})) as InspectedTelegramAccount | null;
if (!account || !("config" in account)) {
return [];
}
const ids = Object.keys(account.config.groups ?? {})
.map((id) => id.trim())
.filter((id) => Boolean(id) && id !== "*");
return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
}
export async function listWhatsAppDirectoryPeersFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = getChannelPlugin("whatsapp")?.config.resolveAccount(
params.cfg,
params.accountId,
) as { allowFrom?: unknown[] } | null | undefined;
if (!account || typeof account !== "object") {
return [];
}
const ids = (account.allowFrom ?? [])
.map((entry: unknown) => String(entry).trim())
.filter((entry) => Boolean(entry) && entry !== "*")
.map((entry) => normalizeWhatsAppTarget(entry) ?? "")
.filter(Boolean)
.filter((id) => !isWhatsAppGroupJid(id));
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
}
export async function listWhatsAppDirectoryGroupsFromConfig(
params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> {
const account = getChannelPlugin("whatsapp")?.config.resolveAccount(
params.cfg,
params.accountId,
) as { groups?: Record<string, unknown> } | null | undefined;
if (!account || typeof account !== "object") {
return [];
}
const ids = Object.keys(account.groups ?? {})
.map((id) => id.trim())
.filter((id) => Boolean(id) && id !== "*");
return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
}

View File

@@ -0,0 +1,8 @@
import type { OpenClawConfig } from "../../config/types.js";
export type DirectoryConfigParams = {
cfg: OpenClawConfig;
accountId?: string | null;
query?: string | null;
limit?: number | null;
};

View File

@@ -1,14 +1,4 @@
export { getChannelPlugin, listChannelPlugins, normalizeChannelId } from "./registry.js";
export {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
listWhatsAppDirectoryGroupsFromConfig,
listWhatsAppDirectoryPeersFromConfig,
} from "./directory-config.js";
export {
applyChannelMatchMeta,
buildChannelKeyCandidates,

View File

@@ -2,13 +2,29 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, expectTypeOf, it } from "vitest";
import {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
} from "../../../extensions/discord/src/directory-config.js";
import type { DiscordProbe } from "../../../extensions/discord/src/probe.js";
import type { DiscordTokenResolution } from "../../../extensions/discord/src/token.js";
import type { IMessageProbe } from "../../../extensions/imessage/src/probe.js";
import type { SignalProbe } from "../../../extensions/signal/src/probe.js";
import {
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
} from "../../../extensions/slack/src/directory-config.js";
import type { SlackProbe } from "../../../extensions/slack/src/probe.js";
import {
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
} from "../../../extensions/telegram/src/directory-config.js";
import type { TelegramProbe } from "../../../extensions/telegram/src/probe.js";
import type { TelegramTokenResolution } from "../../../extensions/telegram/src/token.js";
import {
listWhatsAppDirectoryGroupsFromConfig,
listWhatsAppDirectoryPeersFromConfig,
} from "../../../extensions/whatsapp/src/directory-config.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { LineProbeResult } from "../../line/types.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
@@ -29,16 +45,6 @@ import {
resolveChannelConfigWrites,
resolveConfigWriteTargetFromPath,
} from "./config-writes.js";
import {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
listWhatsAppDirectoryGroupsFromConfig,
listWhatsAppDirectoryPeersFromConfig,
} from "./directory-config.js";
import { listChannelPlugins } from "./index.js";
import { loadChannelPlugin } from "./load.js";
import { loadChannelOutboundAdapter } from "./outbound/load.js";

View File

@@ -1,4 +1,4 @@
export type { DirectoryConfigParams } from "./plugins/directory-config.js";
export type { DirectoryConfigParams } from "./plugins/directory-types.js";
export type { ChannelDirectoryEntry } from "./plugins/types.js";
export type MessagingTargetKind = "user" | "channel";

View File

@@ -32,7 +32,6 @@ export * from "../channels/plugins/actions/reaction-message-id.js";
export * from "../channels/plugins/actions/shared.js";
export type * from "../channels/plugins/types.js";
export * from "../channels/plugins/config-writes.js";
export * from "../channels/plugins/directory-config.js";
export * from "../channels/plugins/media-payload.js";
export * from "../channels/plugins/message-tool-schema.js";
export * from "../channels/plugins/normalize/signal.js";
@@ -46,6 +45,7 @@ export * from "../polls.js";
export * from "../utils/message-channel.js";
export { createActionGate, jsonResult, readStringParam } from "../agents/tools/common.js";
export * from "./channel-lifecycle.js";
export * from "./directory-runtime.js";
export type {
InteractiveButtonStyle,
InteractiveReplyButton,

View File

@@ -1,6 +1,8 @@
/** Shared directory listing helpers for plugins that derive users/groups from config maps. */
export type { DirectoryConfigParams } from "../channels/plugins/directory-types.js";
export {
applyDirectoryQueryAndLimit,
collectNormalizedDirectoryIds,
listDirectoryGroupEntriesFromMapKeys,
listDirectoryGroupEntriesFromMapKeysAndAllowFrom,
listDirectoryUserEntriesFromAllowFrom,

View File

@@ -45,15 +45,14 @@ export {
projectCredentialSnapshotFields,
resolveConfiguredFromCredentialStatuses,
} from "../channels/account-snapshot-fields.js";
export {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
} from "../channels/plugins/directory-config.js";
export {
resolveDefaultGroupPolicy,
resolveOpenProviderRuntimeGroupPolicy,
} from "../config/runtime-group-policy.js";
export {
listDiscordDirectoryGroupsFromConfig,
listDiscordDirectoryPeersFromConfig,
} from "../../extensions/discord/src/directory-config.js";
export {
resolveDiscordGroupRequireMention,
resolveDiscordGroupToolPolicy,

View File

@@ -28,14 +28,14 @@ export {
resolveConfiguredFromCredentialStatuses,
resolveConfiguredFromRequiredCredentialStatuses,
} from "../channels/account-snapshot-fields.js";
export {
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
} from "../channels/plugins/directory-config.js";
export {
looksLikeSlackTargetId,
normalizeSlackMessagingTarget,
} from "../channels/plugins/normalize/slack.js";
export {
listSlackDirectoryGroupsFromConfig,
listSlackDirectoryPeersFromConfig,
} from "../../extensions/slack/src/directory-config.js";
export {
resolveDefaultGroupPolicy,
resolveOpenProviderRuntimeGroupPolicy,

View File

@@ -45,15 +45,14 @@ export {
projectCredentialSnapshotFields,
resolveConfiguredFromCredentialStatuses,
} from "../channels/account-snapshot-fields.js";
export {
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
} from "../channels/plugins/directory-config.js";
export {
resolveAllowlistProviderRuntimeGroupPolicy,
resolveDefaultGroupPolicy,
} from "../config/runtime-group-policy.js";
export {
listTelegramDirectoryGroupsFromConfig,
listTelegramDirectoryPeersFromConfig,
} from "../../extensions/telegram/src/directory-config.js";
export {
resolveTelegramGroupRequireMention,
resolveTelegramGroupToolPolicy,

View File

@@ -32,11 +32,11 @@ export {
resolveWhatsAppConfigAllowFrom,
resolveWhatsAppConfigDefaultTo,
} from "./channel-config-helpers.js";
export { normalizeWhatsAppAllowFromEntries } from "../channels/plugins/normalize/whatsapp.js";
export {
listWhatsAppDirectoryGroupsFromConfig,
listWhatsAppDirectoryPeersFromConfig,
} from "../channels/plugins/directory-config.js";
export { normalizeWhatsAppAllowFromEntries } from "../channels/plugins/normalize/whatsapp.js";
} from "../../extensions/whatsapp/src/directory-config.js";
export {
collectAllowlistProviderGroupPolicyWarnings,
collectOpenGroupPolicyRouteAllowlistWarnings,