fix(doctor): migrate Feishu account bot names (#86081)

This commit is contained in:
Gio Della-Libera
2026-05-24 14:40:16 -07:00
committed by GitHub
parent 500c95b1ba
commit 9e8cc7e077
2 changed files with 110 additions and 0 deletions

View File

@@ -333,6 +333,57 @@ describe("legacy thread binding spawn migrate", () => {
});
});
describe("legacy Feishu account bot name migrate", () => {
it("moves legacy account botName to name", () => {
const res = migrateLegacyConfigForTest({
channels: {
feishu: {
accounts: {
main: {
appId: "cli_xxx",
appSecret: "redacted",
botName: "Legacy Feishu Bot",
domain: "feishu",
},
},
},
},
});
expect(res.config?.channels?.feishu?.accounts?.main).toEqual({
appId: "cli_xxx",
appSecret: "redacted",
name: "Legacy Feishu Bot",
domain: "feishu",
});
expect(res.changes).toStrictEqual([
"Moved channels.feishu.accounts.main.botName → channels.feishu.accounts.main.name.",
]);
});
it("removes legacy account botName when name is already set", () => {
const res = migrateLegacyConfigForTest({
channels: {
feishu: {
accounts: {
main: {
name: "Current Feishu Bot",
botName: "Legacy Feishu Bot",
},
},
},
},
});
expect(res.config?.channels?.feishu?.accounts?.main).toEqual({
name: "Current Feishu Bot",
});
expect(res.changes).toStrictEqual([
"Removed channels.feishu.accounts.main.botName (channels.feishu.accounts.main.name already set).",
]);
});
});
describe("legacy message queue mode migrate", () => {
it("moves retired queue steering modes to followup mode", () => {
const res = migrateLegacyConfigForTest({

View File

@@ -200,6 +200,48 @@ function migrateTelegramRequireMention(raw: Record<string, unknown>, changes: st
raw.channels = channels;
}
function hasLegacyFeishuAccountBotName(value: unknown): boolean {
const accounts = getRecord(value);
if (!accounts) {
return false;
}
return Object.values(accounts).some((entry) => {
const account = getRecord(entry);
return Boolean(account && hasOwnKey(account, "botName"));
});
}
function migrateFeishuAccountBotName(raw: Record<string, unknown>, changes: string[]): void {
const channels = getRecord(raw.channels);
const feishu = getRecord(channels?.feishu);
const accounts = getRecord(feishu?.accounts);
if (!channels || !feishu || !accounts) {
return;
}
for (const [accountId, accountRaw] of Object.entries(accounts)) {
const account = getRecord(accountRaw);
if (!account || !hasOwnKey(account, "botName")) {
continue;
}
const legacyPath = `channels.feishu.accounts.${accountId}.botName`;
const currentPath = `channels.feishu.accounts.${accountId}.name`;
if (account.name === undefined) {
account.name = account.botName;
changes.push(`Moved ${legacyPath}${currentPath}.`);
} else {
changes.push(`Removed ${legacyPath} (${currentPath} already set).`);
}
delete account.botName;
accounts[accountId] = account;
}
feishu.accounts = accounts;
channels.feishu = feishu;
raw.channels = channels;
}
function hasLegacyThreadBindingTtl(value: unknown): boolean {
const threadBindings = getRecord(value);
return Boolean(threadBindings && hasOwnKey(threadBindings, "ttlHours"));
@@ -409,6 +451,15 @@ const GROUP_ROUTING_RULES: LegacyConfigRule[] = [
},
];
const FEISHU_ACCOUNT_RULES: LegacyConfigRule[] = [
{
path: ["channels", "feishu", "accounts"],
message:
'channels.feishu.accounts.<id>.botName was renamed to channels.feishu.accounts.<id>.name. Run "openclaw doctor --fix".',
match: (value) => hasLegacyFeishuAccountBotName(value),
},
];
export const LEGACY_CONFIG_MIGRATIONS_CHANNELS: LegacyConfigMigrationSpec[] = [
defineLegacyConfigMigration({
id: "legacy-group-routing->channel-groups",
@@ -421,6 +472,14 @@ export const LEGACY_CONFIG_MIGRATIONS_CHANNELS: LegacyConfigMigrationSpec[] = [
migrateTelegramRequireMention(raw, changes);
},
}),
defineLegacyConfigMigration({
id: "feishu.accounts.botName->name",
describe: "Move legacy Feishu account botName config to account name",
legacyRules: FEISHU_ACCOUNT_RULES,
apply: (raw, changes) => {
migrateFeishuAccountBotName(raw, changes);
},
}),
defineLegacyConfigMigration({
id: "thread-bindings.ttlHours->idleHours",
describe: