From f93fdadc6ffe191b33a097100338f95b9af6e7f5 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Thu, 13 Aug 2026 11:09:51 +0900 Subject: [PATCH] fix(oauth): preserve legacy account on forced login --- src/oauth/index.ts | 2 +- tests/oauth-reauth-bind.test.ts | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/oauth/index.ts b/src/oauth/index.ts index 348702392..e3cfe719d 100644 --- a/src/oauth/index.ts +++ b/src/oauth/index.ts @@ -978,7 +978,7 @@ export async function runLogin( await (deps.saveAccountCredential ?? saveAccountCredential)(provider, opts.reauthAccountId, cred); } else { await (deps.saveCredential ?? saveCredential)(provider, cred, { - preserveIdentityless: provider === "kiro" && opts?.forceLogin === true, + preserveIdentityless: opts?.forceLogin === true, }); } if (provider !== "chatgpt") { diff --git a/tests/oauth-reauth-bind.test.ts b/tests/oauth-reauth-bind.test.ts index 8a236a9f0..6d7fd82f5 100644 --- a/tests/oauth-reauth-bind.test.ts +++ b/tests/oauth-reauth-bind.test.ts @@ -136,6 +136,31 @@ describe("OAuth account-scoped reauth", () => { expect(getAccountCredential("kiro", set.activeAccountId)?.access).toBe("identified-access"); }); + test("forced Kimi add-account preserves a legacy identity-less account", async () => { + await saveCredential("kimi", { + access: "legacy-access", + refresh: "legacy-refresh", + expires: Date.now() + 60_000, + }); + const original = OAUTH_PROVIDERS.kimi.login; + OAUTH_PROVIDERS.kimi.login = async () => ({ + access: "identified-access", + refresh: "identified-refresh", + expires: Date.now() + 60_000, + accountId: "new-kimi-user", + }); + try { + await runLogin("kimi", {} as OAuthController, { forceLogin: true }); + } finally { + OAUTH_PROVIDERS.kimi.login = original; + } + + const set = getAccountSet("kimi")!; + expect(set.accounts).toHaveLength(2); + expect(set.accounts.some(account => account.credential.access === "legacy-access")).toBe(true); + expect(getAccountCredential("kimi", set.activeAccountId)?.access).toBe("identified-access"); + }); + test("non-force Kiro login upgrades a legacy identity-less slot in place", async () => { await saveCredential("kiro", { access: "legacy-access",