fix(channels): ensure all default account keys are correctly mirrored to top-level config
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user