@@ -77,11 +77,11 @@ vi.mock("../lib/accounts.js", () => ({
7777 resolveRequestAccountId : vi . fn (
7878 (
7979 storedAccountId : string | undefined ,
80- source : string | undefined ,
80+ currentAccountIdSource : string | undefined ,
8181 tokenId : string | undefined ,
8282 ) => {
8383 if ( ! storedAccountId ) return tokenId ;
84- if ( source === "org" || source === "manual" ) {
84+ if ( currentAccountIdSource === "org" || currentAccountIdSource === "manual" ) {
8585 return storedAccountId ;
8686 }
8787 return tokenId ?? storedAccountId ;
@@ -92,10 +92,10 @@ vi.mock("../lib/accounts.js", () => ({
9292 ) ,
9393 selectBestAccountCandidate : vi . fn ( ( ) => null ) ,
9494 shouldUpdateAccountIdFromToken : vi . fn (
95- ( source : string | undefined , currentAccountId : string | undefined ) => {
95+ ( currentAccountIdSource : string | undefined , currentAccountId : string | undefined ) => {
9696 if ( ! currentAccountId ) return true ;
97- if ( ! source ) return true ;
98- return source === "token" || source === "id_token" ;
97+ if ( ! currentAccountIdSource ) return true ;
98+ return currentAccountIdSource === "token" || currentAccountIdSource === "id_token" ;
9999 } ,
100100 ) ,
101101} ) ) ;
@@ -824,6 +824,75 @@ describe("codex manager cli commands", () => {
824824 extractAccountIdMock . mockImplementation ( ( ) => "acc_test" ) ;
825825 } ) ;
826826
827+ it ( "does not clear an existing workspace binding when flagged recovery refresh has no account id" , async ( ) => {
828+ const now = Date . now ( ) ;
829+ loadFlaggedAccountsMock . mockResolvedValueOnce ( {
830+ version : 1 ,
831+ accounts : [
832+ {
833+ refreshToken : "flagged-refresh" ,
834+ email : "a@example.com" ,
835+ addedAt : now - 1_000 ,
836+ lastUsed : now - 1_000 ,
837+ flaggedAt : now - 5_000 ,
838+ } ,
839+ ] ,
840+ } ) ;
841+ loadAccountsMock . mockResolvedValueOnce ( {
842+ version : 3 ,
843+ activeIndex : 0 ,
844+ activeIndexByFamily : { codex : 0 } ,
845+ accounts : [
846+ {
847+ refreshToken : "refresh-existing" ,
848+ accountId : "workspace-alpha" ,
849+ accountIdSource : "org" ,
850+ accountLabel : "Workspace Alpha [id:alpha]" ,
851+ email : "a@example.com" ,
852+ addedAt : now - 3_000 ,
853+ lastUsed : now - 3_000 ,
854+ } ,
855+ ] ,
856+ } ) ;
857+ queuedRefreshMock . mockResolvedValueOnce ( {
858+ type : "success" ,
859+ access : "access-restored" ,
860+ refresh : "refresh-restored" ,
861+ expires : now + 3_600_000 ,
862+ } ) ;
863+ const accountsModule = await import ( "../lib/accounts.js" ) ;
864+ const extractAccountIdMock = vi . mocked ( accountsModule . extractAccountId ) ;
865+ extractAccountIdMock . mockImplementation ( ( accessToken ?: string ) =>
866+ accessToken === "access-restored" ? undefined : "workspace-alpha" ,
867+ ) ;
868+ const { runCodexMultiAuthCli } = await import ( "../lib/codex-manager.js" ) ;
869+
870+ const exitCode = await runCodexMultiAuthCli ( [
871+ "auth" ,
872+ "verify-flagged" ,
873+ "--json" ,
874+ ] ) ;
875+
876+ expect ( exitCode ) . toBe ( 0 ) ;
877+ const savedStorage = saveAccountsMock . mock . calls . at ( - 1 ) ?. [ 0 ] as {
878+ accounts : Array < {
879+ accountId ?: string ;
880+ accountIdSource ?: string ;
881+ refreshToken ?: string ;
882+ email ?: string ;
883+ } > ;
884+ } ;
885+ expect ( savedStorage . accounts [ 0 ] ) . toEqual (
886+ expect . objectContaining ( {
887+ accountId : "workspace-alpha" ,
888+ accountIdSource : "org" ,
889+ refreshToken : "refresh-restored" ,
890+ email : "a@example.com" ,
891+ } ) ,
892+ ) ;
893+ extractAccountIdMock . mockImplementation ( ( ) => "acc_test" ) ;
894+ } ) ;
895+
827896 it ( "rolls back active storage when flagged persistence fails during recovery" , async ( ) => {
828897 const now = Date . now ( ) ;
829898 loadFlaggedAccountsMock . mockResolvedValueOnce ( {
0 commit comments