mirror of https://github.com/openclaw/openclaw.git
161 lines
5.6 KiB
TypeScript
161 lines
5.6 KiB
TypeScript
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
|
import {
|
|
createStandardChannelSetupStatus,
|
|
hasConfiguredSecretInput,
|
|
setSetupChannelEnabled,
|
|
} from "openclaw/plugin-sdk/setup";
|
|
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup";
|
|
import { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
|
|
import {
|
|
DEFAULT_ACCOUNT_ID,
|
|
listQQBotAccountIds,
|
|
resolveQQBotAccount,
|
|
applyQQBotAccountConfig,
|
|
} from "./config.js";
|
|
|
|
const channel = "qqbot" as const;
|
|
|
|
type QQBotEnvCredentialField = "appId" | "clientSecret";
|
|
|
|
/**
|
|
* Clear only the credential fields owned by the setup prompt that switched to
|
|
* env-backed resolution. This preserves mixed-source setups such as config
|
|
* AppID + env AppSecret.
|
|
*/
|
|
function clearQQBotCredentialField(
|
|
cfg: OpenClawConfig,
|
|
accountId: string,
|
|
field: QQBotEnvCredentialField,
|
|
): OpenClawConfig {
|
|
const next = { ...cfg };
|
|
const qqbot = { ...((next.channels?.qqbot as Record<string, unknown>) || {}) };
|
|
|
|
const clearField = (entry: Record<string, unknown>) => {
|
|
if (field === "appId") {
|
|
delete entry.appId;
|
|
return;
|
|
}
|
|
delete entry.clientSecret;
|
|
delete entry.clientSecretFile;
|
|
};
|
|
|
|
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
clearField(qqbot);
|
|
} else {
|
|
const accounts = { ...((qqbot.accounts as Record<string, Record<string, unknown>>) || {}) };
|
|
if (accounts[accountId]) {
|
|
const entry = { ...accounts[accountId] };
|
|
clearField(entry);
|
|
accounts[accountId] = entry;
|
|
qqbot.accounts = accounts;
|
|
}
|
|
}
|
|
|
|
next.channels = { ...next.channels, qqbot };
|
|
return next;
|
|
}
|
|
|
|
const QQBOT_SETUP_HELP_LINES = [
|
|
"To create a QQ Bot, visit the QQ Open Platform:",
|
|
` ${formatDocsLink("https://q.qq.com", "q.qq.com")}`,
|
|
"",
|
|
"1. Create an application and note the AppID.",
|
|
"2. Go to development settings to find the AppSecret.",
|
|
];
|
|
|
|
export const qqbotSetupWizard: ChannelSetupWizard = {
|
|
channel,
|
|
status: createStandardChannelSetupStatus({
|
|
channelLabel: "QQ Bot",
|
|
configuredLabel: "configured",
|
|
unconfiguredLabel: "needs AppID + AppSecret",
|
|
configuredHint: "configured",
|
|
unconfiguredHint: "needs AppID + AppSecret",
|
|
configuredScore: 1,
|
|
unconfiguredScore: 6,
|
|
resolveConfigured: ({ cfg }) =>
|
|
listQQBotAccountIds(cfg).some((accountId) => {
|
|
const account = resolveQQBotAccount(cfg, accountId, { allowUnresolvedSecretRef: true });
|
|
return Boolean(
|
|
account.appId &&
|
|
(Boolean(account.clientSecret) ||
|
|
hasConfiguredSecretInput(account.config.clientSecret) ||
|
|
Boolean(account.config.clientSecretFile?.trim())),
|
|
);
|
|
}),
|
|
}),
|
|
credentials: [
|
|
{
|
|
inputKey: "token",
|
|
providerHint: channel,
|
|
credentialLabel: "AppID",
|
|
preferredEnvVar: "QQBOT_APP_ID",
|
|
helpTitle: "QQ Bot AppID",
|
|
helpLines: QQBOT_SETUP_HELP_LINES,
|
|
envPrompt: "QQBOT_APP_ID detected. Use env var?",
|
|
keepPrompt: "QQ Bot AppID already configured. Keep it?",
|
|
inputPrompt: "Enter QQ Bot AppID",
|
|
allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID,
|
|
inspect: ({ cfg, accountId }) => {
|
|
const resolved = resolveQQBotAccount(cfg, accountId, { allowUnresolvedSecretRef: true });
|
|
const hasConfiguredValue = Boolean(
|
|
hasConfiguredSecretInput(resolved.config.clientSecret) ||
|
|
resolved.config.clientSecretFile?.trim() ||
|
|
resolved.clientSecret,
|
|
);
|
|
return {
|
|
accountConfigured: Boolean(resolved.appId && hasConfiguredValue),
|
|
hasConfiguredValue: Boolean(resolved.appId),
|
|
resolvedValue: resolved.appId || undefined,
|
|
envValue:
|
|
accountId === DEFAULT_ACCOUNT_ID
|
|
? process.env.QQBOT_APP_ID?.trim() || undefined
|
|
: undefined,
|
|
};
|
|
},
|
|
applyUseEnv: ({ cfg, accountId }) =>
|
|
clearQQBotCredentialField(applyQQBotAccountConfig(cfg, accountId, {}), accountId, "appId"),
|
|
applySet: ({ cfg, accountId, resolvedValue }) =>
|
|
applyQQBotAccountConfig(cfg, accountId, { appId: resolvedValue }),
|
|
},
|
|
{
|
|
inputKey: "password",
|
|
providerHint: "qqbot-secret",
|
|
credentialLabel: "AppSecret",
|
|
preferredEnvVar: "QQBOT_CLIENT_SECRET",
|
|
helpTitle: "QQ Bot AppSecret",
|
|
helpLines: QQBOT_SETUP_HELP_LINES,
|
|
envPrompt: "QQBOT_CLIENT_SECRET detected. Use env var?",
|
|
keepPrompt: "QQ Bot AppSecret already configured. Keep it?",
|
|
inputPrompt: "Enter QQ Bot AppSecret",
|
|
allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID,
|
|
inspect: ({ cfg, accountId }) => {
|
|
const resolved = resolveQQBotAccount(cfg, accountId, { allowUnresolvedSecretRef: true });
|
|
const hasConfiguredValue = Boolean(
|
|
hasConfiguredSecretInput(resolved.config.clientSecret) ||
|
|
resolved.config.clientSecretFile?.trim() ||
|
|
resolved.clientSecret,
|
|
);
|
|
return {
|
|
accountConfigured: Boolean(resolved.appId && hasConfiguredValue),
|
|
hasConfiguredValue,
|
|
resolvedValue: resolved.clientSecret || undefined,
|
|
envValue:
|
|
accountId === DEFAULT_ACCOUNT_ID
|
|
? process.env.QQBOT_CLIENT_SECRET?.trim() || undefined
|
|
: undefined,
|
|
};
|
|
},
|
|
applyUseEnv: ({ cfg, accountId }) =>
|
|
clearQQBotCredentialField(
|
|
applyQQBotAccountConfig(cfg, accountId, {}),
|
|
accountId,
|
|
"clientSecret",
|
|
),
|
|
applySet: ({ cfg, accountId, resolvedValue }) =>
|
|
applyQQBotAccountConfig(cfg, accountId, { clientSecret: resolvedValue }),
|
|
},
|
|
],
|
|
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
|
|
};
|