@@ -19,6 +19,7 @@ const assessNamedBackupRestoreMock = vi.fn();
1919const getNamedBackupsDirectoryPathMock = vi . fn ( ) ;
2020const resolveNamedBackupRestorePathMock = vi . fn ( ) ;
2121const importAccountsMock = vi . fn ( ) ;
22+ const restoreAssessedNamedBackupMock = vi . fn ( ) ;
2223const queuedRefreshMock = vi . fn ( ) ;
2324const setCodexCliActiveSelectionMock = vi . fn ( ) ;
2425const promptAddAnotherAccountMock = vi . fn ( ) ;
@@ -121,6 +122,7 @@ vi.mock("../lib/storage.js", async () => {
121122 getNamedBackupsDirectoryPath : getNamedBackupsDirectoryPathMock ,
122123 resolveNamedBackupRestorePath : resolveNamedBackupRestorePathMock ,
123124 importAccounts : importAccountsMock ,
125+ restoreAssessedNamedBackup : restoreAssessedNamedBackupMock ,
124126 exportNamedBackup : exportNamedBackupMock ,
125127 normalizeAccountStorage : normalizeAccountStorageMock ,
126128 } ;
@@ -519,6 +521,7 @@ describe("codex manager cli commands", () => {
519521 getNamedBackupsDirectoryPathMock . mockReset ( ) ;
520522 resolveNamedBackupRestorePathMock . mockReset ( ) ;
521523 importAccountsMock . mockReset ( ) ;
524+ restoreAssessedNamedBackupMock . mockReset ( ) ;
522525 confirmMock . mockReset ( ) ;
523526 listNamedBackupsMock . mockResolvedValue ( [ ] ) ;
524527 assessNamedBackupRestoreMock . mockResolvedValue ( {
@@ -552,6 +555,11 @@ describe("codex manager cli commands", () => {
552555 total : 1 ,
553556 changed : true ,
554557 } ) ;
558+ restoreAssessedNamedBackupMock . mockImplementation ( async ( assessment ) =>
559+ importAccountsMock (
560+ await resolveNamedBackupRestorePathMock ( assessment . backup . name ) ,
561+ ) ,
562+ ) ;
555563 confirmMock . mockResolvedValue ( true ) ;
556564 withAccountStorageTransactionMock . mockImplementation (
557565 async ( handler ) => {
@@ -2446,6 +2454,72 @@ describe("codex manager cli commands", () => {
24462454 expect ( setCodexCliActiveSelectionMock ) . toHaveBeenCalledOnce ( ) ;
24472455 } ) ;
24482456
2457+ it ( "restores a named backup from the direct restore-backup command" , async ( ) => {
2458+ setInteractiveTTY ( true ) ;
2459+ const now = Date . now ( ) ;
2460+ loadAccountsMock . mockResolvedValue ( {
2461+ version : 3 ,
2462+ activeIndex : 0 ,
2463+ activeIndexByFamily : { codex : 0 } ,
2464+ accounts : [
2465+ {
2466+ email : "settings@example.com" ,
2467+ accountId : "acc_settings" ,
2468+ refreshToken : "refresh-settings" ,
2469+ accessToken : "access-settings" ,
2470+ expiresAt : now + 3_600_000 ,
2471+ addedAt : now - 1_000 ,
2472+ lastUsed : now - 1_000 ,
2473+ enabled : true ,
2474+ } ,
2475+ ] ,
2476+ } ) ;
2477+ const assessment = {
2478+ backup : {
2479+ name : "named-backup" ,
2480+ path : mockBackupPath ( "named-backup" ) ,
2481+ createdAt : null ,
2482+ updatedAt : now ,
2483+ sizeBytes : 128 ,
2484+ version : 3 ,
2485+ accountCount : 1 ,
2486+ schemaErrors : [ ] ,
2487+ valid : true ,
2488+ loadError : undefined ,
2489+ } ,
2490+ currentAccountCount : 1 ,
2491+ mergedAccountCount : 2 ,
2492+ imported : 1 ,
2493+ skipped : 0 ,
2494+ wouldExceedLimit : false ,
2495+ eligibleForRestore : true ,
2496+ error : undefined ,
2497+ } ;
2498+ listNamedBackupsMock . mockResolvedValue ( [ assessment . backup ] ) ;
2499+ assessNamedBackupRestoreMock . mockResolvedValue ( assessment ) ;
2500+ selectMock . mockResolvedValueOnce ( { type : "restore" , assessment } ) ;
2501+
2502+ const { runCodexMultiAuthCli } = await import ( "../lib/codex-manager.js" ) ;
2503+ const exitCode = await runCodexMultiAuthCli ( [ "auth" , "restore-backup" ] ) ;
2504+
2505+ expect ( exitCode ) . toBe ( 0 ) ;
2506+ expect ( promptLoginModeMock ) . not . toHaveBeenCalled ( ) ;
2507+ expect ( listNamedBackupsMock ) . toHaveBeenCalledTimes ( 1 ) ;
2508+ expect ( assessNamedBackupRestoreMock ) . toHaveBeenCalledWith (
2509+ "named-backup" ,
2510+ expect . objectContaining ( {
2511+ currentStorage : expect . objectContaining ( {
2512+ accounts : expect . any ( Array ) ,
2513+ } ) ,
2514+ } ) ,
2515+ ) ;
2516+ expect ( confirmMock ) . toHaveBeenCalledOnce ( ) ;
2517+ expect ( importAccountsMock ) . toHaveBeenCalledWith (
2518+ mockBackupPath ( "named-backup" ) ,
2519+ ) ;
2520+ expect ( setCodexCliActiveSelectionMock ) . toHaveBeenCalledOnce ( ) ;
2521+ } ) ;
2522+
24492523 it ( "rejects a restore when the backup root changes before the final import path check" , async ( ) => {
24502524 setInteractiveTTY ( true ) ;
24512525 const now = Date . now ( ) ;
0 commit comments