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, 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); await writeOpenClawConfig(currentConfig);
logger.info('Channel config saved', { logger.info('Channel config saved', {
channelType, channelType,

View File

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