mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-27 00:17:29 +00:00
fix: honor twitch default setup account
This commit is contained in:
@@ -201,5 +201,60 @@ describe("setup surface helpers", () => {
|
|||||||
expect(result?.cfg.channels?.twitch?.accounts?.default?.username).toBe("testbot");
|
expect(result?.cfg.channels?.twitch?.accounts?.default?.username).toBe("testbot");
|
||||||
expect(result?.cfg.channels?.twitch?.accounts?.default?.clientId).toBe("test-client-id");
|
expect(result?.cfg.channels?.twitch?.accounts?.default?.clientId).toBe("test-client-id");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("writes env-token setup to the configured default account", async () => {
|
||||||
|
const { configureWithEnvToken } = await import("./setup-surface.js");
|
||||||
|
|
||||||
|
mockPromptConfirm.mockReset().mockResolvedValue(true as never);
|
||||||
|
mockPromptText
|
||||||
|
.mockReset()
|
||||||
|
.mockResolvedValueOnce("secondary-bot" as never)
|
||||||
|
.mockResolvedValueOnce("secondary-client" as never);
|
||||||
|
|
||||||
|
const result = await configureWithEnvToken(
|
||||||
|
{
|
||||||
|
channels: {
|
||||||
|
twitch: {
|
||||||
|
defaultAccount: "secondary",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as Parameters<typeof configureWithEnvToken>[0],
|
||||||
|
mockPrompter,
|
||||||
|
null,
|
||||||
|
"oauth:fromenv",
|
||||||
|
false,
|
||||||
|
{} as Parameters<typeof configureWithEnvToken>[5],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result?.cfg.channels?.twitch?.accounts?.secondary?.username).toBe("secondary-bot");
|
||||||
|
expect(result?.cfg.channels?.twitch?.accounts?.secondary?.clientId).toBe("secondary-client");
|
||||||
|
expect(result?.cfg.channels?.twitch?.accounts?.default).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("defaultAccount setup resolution", () => {
|
||||||
|
it("reports status for the configured default account", async () => {
|
||||||
|
const { twitchSetupWizard } = await import("./setup-surface.js");
|
||||||
|
|
||||||
|
const lines = twitchSetupWizard.status?.resolveStatusLines?.({
|
||||||
|
cfg: {
|
||||||
|
channels: {
|
||||||
|
twitch: {
|
||||||
|
defaultAccount: "secondary",
|
||||||
|
accounts: {
|
||||||
|
secondary: {
|
||||||
|
username: "secondary-bot",
|
||||||
|
accessToken: "oauth:secondary",
|
||||||
|
clientId: "secondary-client",
|
||||||
|
channel: "#secondary",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as never);
|
||||||
|
|
||||||
|
expect(lines).toEqual(["Twitch (secondary): configured"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,17 +10,27 @@ import {
|
|||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
type WizardPrompter,
|
type WizardPrompter,
|
||||||
} from "openclaw/plugin-sdk/setup";
|
} from "openclaw/plugin-sdk/setup";
|
||||||
import { DEFAULT_ACCOUNT_ID, getAccountConfig } from "./config.js";
|
import {
|
||||||
|
DEFAULT_ACCOUNT_ID,
|
||||||
|
getAccountConfig,
|
||||||
|
resolveDefaultTwitchAccountId,
|
||||||
|
} from "./config.js";
|
||||||
import type { TwitchAccountConfig, TwitchRole } from "./types.js";
|
import type { TwitchAccountConfig, TwitchRole } from "./types.js";
|
||||||
import { isAccountConfigured } from "./utils/twitch.js";
|
import { isAccountConfigured } from "./utils/twitch.js";
|
||||||
|
|
||||||
const channel = "twitch" as const;
|
const channel = "twitch" as const;
|
||||||
|
|
||||||
|
function resolveSetupAccountId(cfg: OpenClawConfig): string {
|
||||||
|
const preferred = cfg.channels?.twitch?.defaultAccount?.trim();
|
||||||
|
return preferred || resolveDefaultTwitchAccountId(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
export function setTwitchAccount(
|
export function setTwitchAccount(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
account: Partial<TwitchAccountConfig>,
|
account: Partial<TwitchAccountConfig>,
|
||||||
|
accountId: string = resolveSetupAccountId(cfg),
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const existing = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
|
const existing = getAccountConfig(cfg, accountId);
|
||||||
const merged: TwitchAccountConfig = {
|
const merged: TwitchAccountConfig = {
|
||||||
username: account.username ?? existing?.username ?? "",
|
username: account.username ?? existing?.username ?? "",
|
||||||
accessToken: account.accessToken ?? existing?.accessToken ?? "",
|
accessToken: account.accessToken ?? existing?.accessToken ?? "",
|
||||||
@@ -49,7 +59,7 @@ export function setTwitchAccount(
|
|||||||
...((
|
...((
|
||||||
(cfg.channels as Record<string, unknown>)?.twitch as Record<string, unknown> | undefined
|
(cfg.channels as Record<string, unknown>)?.twitch as Record<string, unknown> | undefined
|
||||||
)?.accounts as Record<string, unknown> | undefined),
|
)?.accounts as Record<string, unknown> | undefined),
|
||||||
[DEFAULT_ACCOUNT_ID]: merged,
|
[accountId]: merged,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -217,7 +227,8 @@ function setTwitchAccessControl(
|
|||||||
allowedRoles: TwitchRole[],
|
allowedRoles: TwitchRole[],
|
||||||
requireMention: boolean,
|
requireMention: boolean,
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
|
const accountId = resolveSetupAccountId(cfg);
|
||||||
|
const account = getAccountConfig(cfg, accountId);
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
@@ -226,11 +237,11 @@ function setTwitchAccessControl(
|
|||||||
...account,
|
...account,
|
||||||
allowedRoles,
|
allowedRoles,
|
||||||
requireMention,
|
requireMention,
|
||||||
});
|
}, accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveTwitchGroupPolicy(cfg: OpenClawConfig): "open" | "allowlist" | "disabled" {
|
function resolveTwitchGroupPolicy(cfg: OpenClawConfig): "open" | "allowlist" | "disabled" {
|
||||||
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
|
const account = getAccountConfig(cfg, resolveSetupAccountId(cfg));
|
||||||
if (account?.allowedRoles?.includes("all")) {
|
if (account?.allowedRoles?.includes("all")) {
|
||||||
return "open";
|
return "open";
|
||||||
}
|
}
|
||||||
@@ -253,9 +264,9 @@ const twitchDmPolicy: ChannelSetupDmPolicy = {
|
|||||||
label: "Twitch",
|
label: "Twitch",
|
||||||
channel,
|
channel,
|
||||||
policyKey: "channels.twitch.allowedRoles",
|
policyKey: "channels.twitch.allowedRoles",
|
||||||
allowFromKey: "channels.twitch.accounts.default.allowFrom",
|
allowFromKey: "channels.twitch.accounts.<default>.allowFrom",
|
||||||
getCurrent: (cfg) => {
|
getCurrent: (cfg) => {
|
||||||
const account = getAccountConfig(cfg as OpenClawConfig, DEFAULT_ACCOUNT_ID);
|
const account = getAccountConfig(cfg as OpenClawConfig, resolveSetupAccountId(cfg as OpenClawConfig));
|
||||||
if (account?.allowedRoles?.includes("all")) {
|
if (account?.allowedRoles?.includes("all")) {
|
||||||
return "open";
|
return "open";
|
||||||
}
|
}
|
||||||
@@ -270,7 +281,8 @@ const twitchDmPolicy: ChannelSetupDmPolicy = {
|
|||||||
return setTwitchAccessControl(cfg as OpenClawConfig, allowedRoles, true);
|
return setTwitchAccessControl(cfg as OpenClawConfig, allowedRoles, true);
|
||||||
},
|
},
|
||||||
promptAllowFrom: async ({ cfg, prompter }) => {
|
promptAllowFrom: async ({ cfg, prompter }) => {
|
||||||
const account = getAccountConfig(cfg as OpenClawConfig, DEFAULT_ACCOUNT_ID);
|
const accountId = resolveSetupAccountId(cfg as OpenClawConfig);
|
||||||
|
const account = getAccountConfig(cfg as OpenClawConfig, accountId);
|
||||||
const existingAllowFrom = account?.allowFrom ?? [];
|
const existingAllowFrom = account?.allowFrom ?? [];
|
||||||
|
|
||||||
const entry = await prompter.text({
|
const entry = await prompter.text({
|
||||||
@@ -287,7 +299,7 @@ const twitchDmPolicy: ChannelSetupDmPolicy = {
|
|||||||
return setTwitchAccount(cfg as OpenClawConfig, {
|
return setTwitchAccount(cfg as OpenClawConfig, {
|
||||||
...(account ?? undefined),
|
...(account ?? undefined),
|
||||||
allowFrom,
|
allowFrom,
|
||||||
});
|
}, accountId);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -297,11 +309,11 @@ const twitchGroupAccess: NonNullable<ChannelSetupWizard["groupAccess"]> = {
|
|||||||
skipAllowlistEntries: true,
|
skipAllowlistEntries: true,
|
||||||
currentPolicy: ({ cfg }) => resolveTwitchGroupPolicy(cfg as OpenClawConfig),
|
currentPolicy: ({ cfg }) => resolveTwitchGroupPolicy(cfg as OpenClawConfig),
|
||||||
currentEntries: ({ cfg }) => {
|
currentEntries: ({ cfg }) => {
|
||||||
const account = getAccountConfig(cfg as OpenClawConfig, DEFAULT_ACCOUNT_ID);
|
const account = getAccountConfig(cfg as OpenClawConfig, resolveSetupAccountId(cfg as OpenClawConfig));
|
||||||
return account?.allowFrom ?? [];
|
return account?.allowFrom ?? [];
|
||||||
},
|
},
|
||||||
updatePrompt: ({ cfg }) => {
|
updatePrompt: ({ cfg }) => {
|
||||||
const account = getAccountConfig(cfg as OpenClawConfig, DEFAULT_ACCOUNT_ID);
|
const account = getAccountConfig(cfg as OpenClawConfig, resolveSetupAccountId(cfg as OpenClawConfig));
|
||||||
return Boolean(account?.allowedRoles?.length || account?.allowFrom?.length);
|
return Boolean(account?.allowedRoles?.length || account?.allowFrom?.length);
|
||||||
},
|
},
|
||||||
setPolicy: ({ cfg, policy }) => setTwitchGroupPolicy(cfg as OpenClawConfig, policy),
|
setPolicy: ({ cfg, policy }) => setTwitchGroupPolicy(cfg as OpenClawConfig, policy),
|
||||||
@@ -310,16 +322,16 @@ const twitchGroupAccess: NonNullable<ChannelSetupWizard["groupAccess"]> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const twitchSetupAdapter: ChannelSetupAdapter = {
|
export const twitchSetupAdapter: ChannelSetupAdapter = {
|
||||||
resolveAccountId: () => DEFAULT_ACCOUNT_ID,
|
resolveAccountId: ({ cfg }) => resolveSetupAccountId(cfg as OpenClawConfig),
|
||||||
applyAccountConfig: ({ cfg }) =>
|
applyAccountConfig: ({ cfg, accountId }) =>
|
||||||
setTwitchAccount(cfg, {
|
setTwitchAccount(cfg, {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}),
|
}, accountId),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const twitchSetupWizard: ChannelSetupWizard = {
|
export const twitchSetupWizard: ChannelSetupWizard = {
|
||||||
channel,
|
channel,
|
||||||
resolveAccountIdForConfigure: () => DEFAULT_ACCOUNT_ID,
|
resolveAccountIdForConfigure: ({ defaultAccountId }) => defaultAccountId,
|
||||||
resolveShouldPromptAccountIds: () => false,
|
resolveShouldPromptAccountIds: () => false,
|
||||||
status: {
|
status: {
|
||||||
configuredLabel: "configured",
|
configuredLabel: "configured",
|
||||||
@@ -327,18 +339,22 @@ export const twitchSetupWizard: ChannelSetupWizard = {
|
|||||||
configuredHint: "configured",
|
configuredHint: "configured",
|
||||||
unconfiguredHint: "needs setup",
|
unconfiguredHint: "needs setup",
|
||||||
resolveConfigured: ({ cfg }) => {
|
resolveConfigured: ({ cfg }) => {
|
||||||
const account = getAccountConfig(cfg as OpenClawConfig, DEFAULT_ACCOUNT_ID);
|
const account = getAccountConfig(cfg as OpenClawConfig, resolveSetupAccountId(cfg as OpenClawConfig));
|
||||||
return account ? isAccountConfigured(account) : false;
|
return account ? isAccountConfigured(account) : false;
|
||||||
},
|
},
|
||||||
resolveStatusLines: ({ cfg }) => {
|
resolveStatusLines: ({ cfg }) => {
|
||||||
const account = getAccountConfig(cfg as OpenClawConfig, DEFAULT_ACCOUNT_ID);
|
const accountId = resolveSetupAccountId(cfg as OpenClawConfig);
|
||||||
|
const account = getAccountConfig(cfg as OpenClawConfig, accountId);
|
||||||
const configured = account ? isAccountConfigured(account) : false;
|
const configured = account ? isAccountConfigured(account) : false;
|
||||||
return [`Twitch: ${configured ? "configured" : "needs username, token, and clientId"}`];
|
return [
|
||||||
|
`Twitch${accountId !== DEFAULT_ACCOUNT_ID ? ` (${accountId})` : ""}: ${configured ? "configured" : "needs username, token, and clientId"}`,
|
||||||
|
];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
credentials: [],
|
credentials: [],
|
||||||
finalize: async ({ cfg, prompter, forceAllowFrom }) => {
|
finalize: async ({ cfg, prompter, forceAllowFrom }) => {
|
||||||
const account = getAccountConfig(cfg as OpenClawConfig, DEFAULT_ACCOUNT_ID);
|
const accountId = resolveSetupAccountId(cfg as OpenClawConfig);
|
||||||
|
const account = getAccountConfig(cfg as OpenClawConfig, accountId);
|
||||||
|
|
||||||
if (!account || !isAccountConfigured(account)) {
|
if (!account || !isAccountConfigured(account)) {
|
||||||
await noteTwitchSetupHelp(prompter);
|
await noteTwitchSetupHelp(prompter);
|
||||||
@@ -374,7 +390,7 @@ export const twitchSetupWizard: ChannelSetupWizard = {
|
|||||||
clientSecret,
|
clientSecret,
|
||||||
refreshToken,
|
refreshToken,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
});
|
}, accountId);
|
||||||
|
|
||||||
const cfgWithAllowFrom =
|
const cfgWithAllowFrom =
|
||||||
forceAllowFrom && twitchDmPolicy.promptAllowFrom
|
forceAllowFrom && twitchDmPolicy.promptAllowFrom
|
||||||
|
|||||||
Reference in New Issue
Block a user