fix(channels): ensure all default account keys are correctly mirrored to top-level config

This commit is contained in:
paisley
2026-03-12 11:13:26 +08:00
Unverified
parent 706789cf4d
commit 5c07ad77fc
2 changed files with 33 additions and 15 deletions

View File

@@ -371,6 +371,17 @@ export async function saveChannelConfig(
enabled: transformedConfig.enabled ?? true,
};
// Most OpenClaw channel plugins read the default account's credentials
// from the top level of `channels.<type>` (e.g. channels.feishu.appId),
// not from `accounts.default`. Mirror them there so plugins can discover
// the credentials correctly. We use the final account entry (not
// transformedConfig) because `enabled` is only added at the account level.
if (resolvedAccountId === DEFAULT_ACCOUNT_ID) {
for (const [key, value] of Object.entries(accounts[resolvedAccountId])) {
channelSection[key] = value;
}
}
await writeOpenClawConfig(currentConfig);
logger.info('Channel config saved', {
channelType,

View File

@@ -1016,24 +1016,31 @@ export async function sanitizeOpenClawConfig(): Promise<void> {
}
}
// ── channels.feishu migration ──────────────────────────────────
// The official feishu plugin reads the default account's credentials from
// the top level of `channels.feishu` (appId, appSecret), but ClawX
// historically stored them only under `channels.feishu.accounts.default`.
// Mirror the default account credentials at the top level so the plugin
// can discover them.
const feishuSection = (config.channels as Record<string, Record<string, unknown>> | undefined)?.feishu;
if (feishuSection) {
const feishuAccounts = feishuSection.accounts as Record<string, Record<string, unknown>> | undefined;
const defaultAccount = feishuAccounts?.default;
if (defaultAccount?.appId && defaultAccount?.appSecret && !feishuSection.appId) {
// ── channels default-account migration ─────────────────────────
// Most OpenClaw channel plugins read the default account's credentials
// from the top level of `channels.<type>` (e.g. channels.feishu.appId),
// but ClawX historically stored them only under `channels.<type>.accounts.default`.
// Mirror the default account credentials at the top level so plugins can
// discover them.
const channelsObj = config.channels as Record<string, Record<string, unknown>> | undefined;
if (channelsObj && typeof channelsObj === 'object') {
for (const [channelType, section] of Object.entries(channelsObj)) {
if (!section || typeof section !== 'object') continue;
const accounts = section.accounts as Record<string, Record<string, unknown>> | undefined;
const defaultAccount = accounts?.default;
if (!defaultAccount || typeof defaultAccount !== 'object') continue;
// Mirror each missing key from accounts.default to the top level
let mirrored = false;
for (const [key, value] of Object.entries(defaultAccount)) {
if (key !== 'enabled' && !(key in feishuSection)) {
feishuSection[key] = value;
if (!(key in section)) {
section[key] = value;
mirrored = true;
}
}
modified = true;
console.log('[sanitize] Mirrored feishu default account credentials to top-level channels.feishu');
if (mirrored) {
modified = true;
console.log(`[sanitize] Mirrored ${channelType} default account credentials to top-level channels.${channelType}`);
}
}
}