























@@ -1,3 +1,4 @@
1+import { ChannelType } from "discord-api-types/v10";
12import type {
23DiscordGuildChannelConfig,
34DiscordGuildEntry,
@@ -23,7 +24,21 @@ export type DiscordChannelPermissionsAudit = {
2324elapsedMs: number;
2425};
252626-const REQUIRED_CHANNEL_PERMISSIONS = ["ViewChannel", "SendMessages"] as const;
27+const REQUIRED_TEXT_CHANNEL_PERMISSIONS = ["ViewChannel", "SendMessages"] as const;
28+const REQUIRED_VOICE_CHANNEL_PERMISSIONS = [
29+"ViewChannel",
30+"Connect",
31+"Speak",
32+"SendMessages",
33+"ReadMessageHistory",
34+] as const;
35+36+export function resolveRequiredDiscordChannelPermissions(channelType?: number): string[] {
37+if (channelType === ChannelType.GuildVoice || channelType === ChannelType.GuildStageVoice) {
38+return [...REQUIRED_VOICE_CHANNEL_PERMISSIONS];
39+}
40+return [...REQUIRED_TEXT_CHANNEL_PERMISSIONS];
41+}
27422843function shouldAuditChannelConfig(config: DiscordGuildChannelConfig | undefined) {
2944if (!config) {
@@ -76,6 +91,27 @@ export function collectDiscordAuditChannelIdsForGuilds(
7691return { channelIds, unresolvedChannels };
7792}
789394+export function collectDiscordAuditChannelIdsForAccount(config: {
95+guilds?: Record<string, DiscordGuildEntry>;
96+voice?: { autoJoin?: Array<{ guildId?: string; channelId?: string }> };
97+}) {
98+const collected = collectDiscordAuditChannelIdsForGuilds(config.guilds);
99+const channelIds = new Set(collected.channelIds);
100+let unresolvedVoiceChannels = 0;
101+for (const entry of config.voice?.autoJoin ?? []) {
102+const channelId = normalizeOptionalString(entry?.channelId) ?? "";
103+if (/^\d+$/.test(channelId)) {
104+channelIds.add(channelId);
105+} else if (channelId) {
106+unresolvedVoiceChannels++;
107+}
108+}
109+return {
110+channelIds: [...channelIds].toSorted((a, b) => a.localeCompare(b)),
111+unresolvedChannels: collected.unresolvedChannels + unresolvedVoiceChannels,
112+};
113+}
114+79115export async function auditDiscordChannelPermissionsWithFetcher(params: {
80116cfg: OpenClawConfig;
81117token: string;
@@ -87,6 +123,7 @@ export async function auditDiscordChannelPermissionsWithFetcher(params: {
87123params: { cfg: OpenClawConfig; token: string; accountId?: string },
88124) => Promise<{
89125permissions: string[];
126+channelType?: number;
90127}>;
91128}): Promise<DiscordChannelPermissionsAudit> {
92129const started = Date.now();
@@ -101,7 +138,6 @@ export async function auditDiscordChannelPermissionsWithFetcher(params: {
101138};
102139}
103140104-const required = [...REQUIRED_CHANNEL_PERMISSIONS];
105141const channels: DiscordChannelPermissionsAuditEntry[] = [];
106142107143for (const channelId of params.channelIds) {
@@ -111,6 +147,7 @@ export async function auditDiscordChannelPermissionsWithFetcher(params: {
111147 token,
112148accountId: params.accountId ?? undefined,
113149});
150+const required = resolveRequiredDiscordChannelPermissions(perms.channelType);
114151const missing = required.filter((p) => !perms.permissions.includes(p));
115152channels.push({
116153 channelId,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。