fix(discord): align wildcard channel matching

This commit is contained in:
Peter Steinberger
2026-01-21 17:54:31 +00:00
parent 64d29b0c31
commit f0a8b34198
2 changed files with 30 additions and 21 deletions

View File

@@ -299,6 +299,7 @@ describe("discord guild/channel resolution", () => {
expect(general?.allowed).toBe(true); expect(general?.allowed).toBe(true);
expect(general?.requireMention).toBe(false); expect(general?.requireMention).toBe(false);
expect(general?.autoThread).toBeUndefined(); expect(general?.autoThread).toBeUndefined();
expect(general?.matchSource).toBe("direct");
// Unknown channel should use wildcard // Unknown channel should use wildcard
const random = resolveDiscordChannelConfig({ const random = resolveDiscordChannelConfig({
@@ -310,6 +311,28 @@ describe("discord guild/channel resolution", () => {
expect(random?.allowed).toBe(true); expect(random?.allowed).toBe(true);
expect(random?.autoThread).toBe(true); expect(random?.autoThread).toBe(true);
expect(random?.requireMention).toBe(true); expect(random?.requireMention).toBe(true);
expect(random?.matchSource).toBe("wildcard");
});
it("falls back to wildcard when thread channel and parent are missing", () => {
const guildInfo: DiscordGuildEntryResolved = {
channels: {
"*": { allow: true, requireMention: false },
},
};
const thread = resolveDiscordChannelConfigWithFallback({
guildInfo,
channelId: "thread-123",
channelName: "topic",
channelSlug: "topic",
parentId: "parent-999",
parentName: "general",
parentSlug: "general",
scope: "thread",
});
expect(thread?.allowed).toBe(true);
expect(thread?.matchKey).toBe("*");
expect(thread?.matchSource).toBe("wildcard");
}); });
}); });

View File

@@ -3,6 +3,7 @@ import type { Guild, User } from "@buape/carbon";
import { import {
buildChannelKeyCandidates, buildChannelKeyCandidates,
resolveChannelEntryMatchWithFallback, resolveChannelEntryMatchWithFallback,
type ChannelMatchSource,
} from "../../channels/channel-config.js"; } from "../../channels/channel-config.js";
import type { AllowlistMatch } from "../../channels/allowlist-match.js"; import type { AllowlistMatch } from "../../channels/allowlist-match.js";
import { formatDiscordUserTag } from "./format.js"; import { formatDiscordUserTag } from "./format.js";
@@ -44,7 +45,7 @@ export type DiscordChannelConfigResolved = {
systemPrompt?: string; systemPrompt?: string;
autoThread?: boolean; autoThread?: boolean;
matchKey?: string; matchKey?: string;
matchSource?: "direct" | "parent"; matchSource?: ChannelMatchSource;
}; };
export function normalizeDiscordAllowList( export function normalizeDiscordAllowList(
@@ -198,13 +199,14 @@ function resolveDiscordChannelEntryMatch(
entries: channels, entries: channels,
keys, keys,
parentKeys, parentKeys,
wildcardKey: "*",
}); });
} }
function resolveDiscordChannelConfigEntry( function resolveDiscordChannelConfigEntry(
entry: DiscordChannelEntry, entry: DiscordChannelEntry,
matchKey: string | undefined, matchKey: string | undefined,
matchSource: "direct" | "parent", matchSource: ChannelMatchSource,
): DiscordChannelConfigResolved { ): DiscordChannelConfigResolved {
const resolved: DiscordChannelConfigResolved = { const resolved: DiscordChannelConfigResolved = {
allowed: entry.allow !== false, allowed: entry.allow !== false,
@@ -234,15 +236,8 @@ export function resolveDiscordChannelConfig(params: {
name: channelName, name: channelName,
slug: channelSlug, slug: channelSlug,
}); });
if (!match.entry || !match.matchKey) { if (!match.entry || !match.matchKey || !match.matchSource) return { allowed: false };
// Wildcard fallback: apply to all channels if "*" is configured return resolveDiscordChannelConfigEntry(match.entry, match.matchKey, match.matchSource);
const wildcard = channels["*"];
if (wildcard) {
return resolveDiscordChannelConfigEntry(wildcard, "*", "direct");
}
return { allowed: false };
}
return resolveDiscordChannelConfigEntry(match.entry, match.matchKey, "direct");
} }
export function resolveDiscordChannelConfigWithFallback(params: { export function resolveDiscordChannelConfigWithFallback(params: {
@@ -285,16 +280,7 @@ export function resolveDiscordChannelConfigWithFallback(params: {
: undefined, : undefined,
); );
if (match.entry && match.matchKey && match.matchSource) { if (match.entry && match.matchKey && match.matchSource) {
return resolveDiscordChannelConfigEntry( return resolveDiscordChannelConfigEntry(match.entry, match.matchKey, match.matchSource);
match.entry,
match.matchKey,
match.matchSource === "parent" ? "parent" : "direct",
);
}
// Wildcard fallback: apply to all channels if "*" is configured
const wildcard = channels["*"];
if (wildcard) {
return resolveDiscordChannelConfigEntry(wildcard, "*", "direct");
} }
return { allowed: false }; return { allowed: false };
} }