This commit is contained in:
jaydenfyi 2026-01-25 16:15:28 +08:00
parent cf311730df
commit 196ea43f78
2 changed files with 27 additions and 42 deletions

View File

@ -10,25 +10,12 @@ import {
type WizardPrompter,
} from "clawdbot/plugin-sdk";
import { DEFAULT_ACCOUNT_ID, getAccountConfig } from "./config.js";
import { isAccountConfigured } from "./utils/twitch.js";
import type { TwitchAccountConfig, TwitchRole } from "./types.js";
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
const channel = "twitch" as const;
/**
* Get the current Twitch account config
*/
function getTwitchAccount(cfg: ClawdbotConfig): TwitchAccountConfig | null {
return getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
}
/**
* Check if Twitch is configured
*/
function isTwitchConfigured(account: TwitchAccountConfig | null): boolean {
return Boolean(account?.token && account?.username && account?.clientId);
}
/**
* Set Twitch account configuration
*/
@ -36,12 +23,12 @@ function setTwitchAccount(
cfg: ClawdbotConfig,
account: Partial<TwitchAccountConfig>,
): ClawdbotConfig {
const existing = getTwitchAccount(cfg);
const existing = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
const merged: TwitchAccountConfig = {
username: account.username ?? existing?.username ?? "",
token: account.token ?? existing?.token ?? "",
clientId: account.clientId ?? existing?.clientId ?? "",
channel: account.channel ?? existing?.channel,
channel: account.channel ?? existing?.channel ?? "",
enabled: account.enabled ?? existing?.enabled ?? true,
allowFrom: account.allowFrom ?? existing?.allowFrom,
allowedRoles: account.allowedRoles ?? existing?.allowedRoles,
@ -257,7 +244,7 @@ function setTwitchAccessControl(
allowedRoles: TwitchRole[],
requireMention: boolean,
): ClawdbotConfig {
const account = getTwitchAccount(cfg);
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
if (!account) {
return cfg;
}
@ -275,7 +262,7 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
policyKey: "channels.twitch.allowedRoles", // Twitch uses roles instead of DM policy
allowFromKey: "channels.twitch.accounts.default.allowFrom",
getCurrent: (cfg) => {
const account = getTwitchAccount(cfg);
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
// Map allowedRoles to policy equivalent
if (account?.allowedRoles?.includes("all")) return "open";
if (account?.allowFrom && account.allowFrom.length > 0) return "allowlist";
@ -312,8 +299,8 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
export const twitchOnboardingAdapter: ChannelOnboardingAdapter = {
channel,
getStatus: async ({ cfg }) => {
const account = getTwitchAccount(cfg);
const configured = isTwitchConfigured(account);
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
const configured = account ? isAccountConfigured(account) : false;
return {
channel,
@ -323,9 +310,9 @@ export const twitchOnboardingAdapter: ChannelOnboardingAdapter = {
};
},
configure: async ({ cfg, prompter, forceAllowFrom }) => {
const account = getTwitchAccount(cfg);
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
if (!isTwitchConfigured(account)) {
if (!account || !isAccountConfigured(account)) {
await noteTwitchSetupHelp(prompter);
}

View File

@ -17,6 +17,7 @@ import { resolveTwitchTargets } from "./resolver.js";
import { collectTwitchStatusIssues } from "./status.js";
import { removeClientManager } from "./client-manager-registry.js";
import { resolveTwitchToken } from "./token.js";
import { isAccountConfigured } from "./utils/twitch.js";
import type {
ChannelAccountSnapshot,
ChannelCapabilities,
@ -28,18 +29,6 @@ import type {
TwitchAccountConfig,
} from "./types.js";
/**
* Check if an account is properly configured.
*/
function isConfigured(
account: TwitchAccountConfig | null | undefined,
cfg: ClawdbotConfig,
accountId: string,
): boolean {
const tokenResolution = resolveTwitchToken(cfg, { accountId });
return Boolean(account?.username && account?.clientId && tokenResolution.token);
}
/**
* Twitch channel plugin.
*
@ -111,18 +100,21 @@ export const twitchPlugin: ChannelPlugin<TwitchAccountConfig> = {
/** Check if an account is configured */
isConfigured: (_account: unknown, cfg: ClawdbotConfig): boolean => {
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
return isConfigured(account, cfg, DEFAULT_ACCOUNT_ID);
const tokenResolution = resolveTwitchToken(cfg, { accountId: DEFAULT_ACCOUNT_ID });
return account ? isAccountConfigured(account, tokenResolution.token) : false;
},
/** Check if an account is enabled */
isEnabled: (account: TwitchAccountConfig | undefined): boolean => account?.enabled !== false,
/** Describe account status */
describeAccount: (account: TwitchAccountConfig | undefined) => ({
accountId: DEFAULT_ACCOUNT_ID,
enabled: account?.enabled !== false,
configured: account ? isConfigured(account, cfg, DEFAULT_ACCOUNT_ID) : false,
}),
describeAccount: (account: TwitchAccountConfig | undefined) => {
return {
accountId: DEFAULT_ACCOUNT_ID,
enabled: account?.enabled !== false,
configured: account ? isAccountConfigured(account, account?.token) : false,
};
},
},
/** Outbound message adapter */
@ -203,6 +195,7 @@ export const twitchPlugin: ChannelPlugin<TwitchAccountConfig> = {
/** Build account snapshot with current status */
buildAccountSnapshot: ({
account,
cfg,
runtime,
probe,
}: {
@ -211,14 +204,19 @@ export const twitchPlugin: ChannelPlugin<TwitchAccountConfig> = {
runtime?: ChannelAccountSnapshot;
probe?: unknown;
}): ChannelAccountSnapshot => {
const accountMap = cfg.channels?.twitch?.accounts ?? {};
const twitch = (cfg as Record<string, unknown>).channels as
| Record<string, unknown>
| undefined;
const twitchCfg = twitch?.twitch as Record<string, unknown> | undefined;
const accountMap = (twitchCfg?.accounts as Record<string, unknown> | undefined) ?? {};
const resolvedAccountId =
Object.entries(accountMap).find(([, value]) => value === account)?.[0] ??
DEFAULT_ACCOUNT_ID;
const tokenResolution = resolveTwitchToken(cfg, { accountId: resolvedAccountId });
return {
accountId: DEFAULT_ACCOUNT_ID,
enabled: account?.enabled !== false,
configured: isConfigured(account, cfg, resolvedAccountId),
configured: isAccountConfigured(account, tokenResolution.token),
running: runtime?.running ?? false,
lastStartAt: runtime?.lastStartAt ?? null,
lastStopAt: runtime?.lastStopAt ?? null,