@@ -4503,6 +4503,75 @@ describe("codex manager cli commands", () => {
45034503 ) ;
45044504 } ) ;
45054505
4506+ it ( "supports sync hotkeys from experimental menu through preview and applied status" , async ( ) => {
4507+ const now = Date . now ( ) ;
4508+ setupInteractiveSettingsLogin ( createSettingsStorage ( now ) ) ;
4509+ detectOcChatgptMultiAuthTargetMock . mockReturnValue ( {
4510+ kind : "target" ,
4511+ descriptor : {
4512+ scope : "global" ,
4513+ root : "C:/target" ,
4514+ accountPath : "C:/target/openai-codex-accounts.json" ,
4515+ backupRoot : "C:/target/backups" ,
4516+ source : "default-global" ,
4517+ resolution : "accounts" ,
4518+ } ,
4519+ } ) ;
4520+ planOcChatgptSyncMock . mockResolvedValue ( {
4521+ kind : "ready" ,
4522+ target : {
4523+ scope : "global" ,
4524+ root : "C:/target" ,
4525+ accountPath : "C:/target/openai-codex-accounts.json" ,
4526+ backupRoot : "C:/target/backups" ,
4527+ source : "default-global" ,
4528+ resolution : "accounts" ,
4529+ } ,
4530+ preview : {
4531+ payload : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4532+ merged : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4533+ toAdd : [ { refreshTokenLast4 : "1234" } ] ,
4534+ toUpdate : [ ] ,
4535+ toSkip : [ ] ,
4536+ unchangedDestinationOnly : [ ] ,
4537+ activeSelectionBehavior : "preserve-destination" ,
4538+ } ,
4539+ payload : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4540+ destination : null ,
4541+ } ) ;
4542+ applyOcChatgptSyncMock . mockResolvedValue ( {
4543+ kind : "applied" ,
4544+ target : {
4545+ scope : "global" ,
4546+ root : "C:/target" ,
4547+ accountPath : "C:/target/openai-codex-accounts.json" ,
4548+ backupRoot : "C:/target/backups" ,
4549+ source : "default-global" ,
4550+ resolution : "accounts" ,
4551+ } ,
4552+ preview : { merged : { version : 3 , accounts : [ ] , activeIndex : 0 } } ,
4553+ merged : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4554+ destination : null ,
4555+ persistedPath : "C:/target/openai-codex-accounts.json" ,
4556+ } ) ;
4557+ const selectSequence = queueSettingsSelectSequence ( [
4558+ { type : "experimental" } ,
4559+ requireSettingsHotkey ( "1" , { type : "sync" } ) ,
4560+ requireSettingsHotkey ( "a" , { type : "apply" } ) ,
4561+ requireSettingsHotkey ( "q" , { type : "back" } ) ,
4562+ { type : "back" } ,
4563+ { type : "back" } ,
4564+ ] ) ;
4565+
4566+ const { runCodexMultiAuthCli } = await import ( "../lib/codex-manager.js" ) ;
4567+ const exitCode = await runCodexMultiAuthCli ( [ "auth" , "login" ] ) ;
4568+
4569+ expect ( exitCode ) . toBe ( 0 ) ;
4570+ expect ( selectSequence . remaining ( ) ) . toBe ( 0 ) ;
4571+ expect ( planOcChatgptSyncMock ) . toHaveBeenCalledOnce ( ) ;
4572+ expect ( applyOcChatgptSyncMock ) . toHaveBeenCalledOnce ( ) ;
4573+ } ) ;
4574+
45064575 it ( "shows guidance when experimental oc sync target is ambiguous or unreadable" , async ( ) => {
45074576 const now = Date . now ( ) ;
45084577 setupInteractiveSettingsLogin ( createSettingsStorage ( now ) ) ;
@@ -4551,6 +4620,33 @@ describe("codex manager cli commands", () => {
45514620 expect ( runNamedBackupExportMock ) . toHaveBeenCalledWith ( { name : "backup-2026-03-10" } ) ;
45524621 } ) ;
45534622
4623+ it ( "supports backup hotkeys from experimental menu through result status" , async ( ) => {
4624+ const now = Date . now ( ) ;
4625+ setupInteractiveSettingsLogin ( createSettingsStorage ( now ) ) ;
4626+ promptQuestionMock . mockResolvedValueOnce ( "backup-2026-03-11" ) ;
4627+ runNamedBackupExportMock . mockResolvedValueOnce ( {
4628+ kind : "exported" ,
4629+ path : "/mock/backups/backup-2026-03-11.json" ,
4630+ } ) ;
4631+ const selectSequence = queueSettingsSelectSequence ( [
4632+ { type : "experimental" } ,
4633+ requireSettingsHotkey ( "2" , { type : "backup" } ) ,
4634+ requireSettingsHotkey ( "q" , { type : "back" } ) ,
4635+ { type : "back" } ,
4636+ { type : "back" } ,
4637+ ] ) ;
4638+
4639+ const { runCodexMultiAuthCli } = await import ( "../lib/codex-manager.js" ) ;
4640+ const exitCode = await runCodexMultiAuthCli ( [ "auth" , "login" ] ) ;
4641+
4642+ expect ( exitCode ) . toBe ( 0 ) ;
4643+ expect ( selectSequence . remaining ( ) ) . toBe ( 0 ) ;
4644+ expect ( promptQuestionMock ) . toHaveBeenCalledOnce ( ) ;
4645+ expect ( runNamedBackupExportMock ) . toHaveBeenCalledWith ( {
4646+ name : "backup-2026-03-11" ,
4647+ } ) ;
4648+ } ) ;
4649+
45544650 it ( "rejects invalid or colliding experimental backup filenames" , async ( ) => {
45554651 const now = Date . now ( ) ;
45564652 setupInteractiveSettingsLogin ( createSettingsStorage ( now ) ) ;
@@ -4663,6 +4759,59 @@ describe("codex manager cli commands", () => {
46634759 expect ( applyOcChatgptSyncMock ) . not . toHaveBeenCalled ( ) ;
46644760 } ) ;
46654761
4762+ it ( "supports q hotkey to back out of experimental sync preview" , async ( ) => {
4763+ const now = Date . now ( ) ;
4764+ setupInteractiveSettingsLogin ( createSettingsStorage ( now ) ) ;
4765+ detectOcChatgptMultiAuthTargetMock . mockReturnValue ( {
4766+ kind : "target" ,
4767+ descriptor : {
4768+ scope : "global" ,
4769+ root : "C:/target" ,
4770+ accountPath : "C:/target/openai-codex-accounts.json" ,
4771+ backupRoot : "C:/target/backups" ,
4772+ source : "default-global" ,
4773+ resolution : "accounts" ,
4774+ } ,
4775+ } ) ;
4776+ planOcChatgptSyncMock . mockResolvedValue ( {
4777+ kind : "ready" ,
4778+ target : {
4779+ scope : "global" ,
4780+ root : "C:/target" ,
4781+ accountPath : "C:/target/openai-codex-accounts.json" ,
4782+ backupRoot : "C:/target/backups" ,
4783+ source : "default-global" ,
4784+ resolution : "accounts" ,
4785+ } ,
4786+ preview : {
4787+ payload : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4788+ merged : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4789+ toAdd : [ ] ,
4790+ toUpdate : [ ] ,
4791+ toSkip : [ ] ,
4792+ unchangedDestinationOnly : [ ] ,
4793+ activeSelectionBehavior : "preserve-destination" ,
4794+ } ,
4795+ payload : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4796+ destination : { version : 3 , accounts : [ ] , activeIndex : 0 } ,
4797+ } ) ;
4798+ const selectSequence = queueSettingsSelectSequence ( [
4799+ { type : "experimental" } ,
4800+ requireSettingsHotkey ( "1" , { type : "sync" } ) ,
4801+ requireSettingsHotkey ( "q" , { type : "back" } ) ,
4802+ { type : "back" } ,
4803+ { type : "back" } ,
4804+ ] ) ;
4805+
4806+ const { runCodexMultiAuthCli } = await import ( "../lib/codex-manager.js" ) ;
4807+ const exitCode = await runCodexMultiAuthCli ( [ "auth" , "login" ] ) ;
4808+
4809+ expect ( exitCode ) . toBe ( 0 ) ;
4810+ expect ( selectSequence . remaining ( ) ) . toBe ( 0 ) ;
4811+ expect ( planOcChatgptSyncMock ) . toHaveBeenCalledOnce ( ) ;
4812+ expect ( applyOcChatgptSyncMock ) . not . toHaveBeenCalled ( ) ;
4813+ } ) ;
4814+
46664815 it ( "cancels experimental backup prompt on blank or q input" , async ( ) => {
46674816 const now = Date . now ( ) ;
46684817 setupInteractiveSettingsLogin ( createSettingsStorage ( now ) ) ;
0 commit comments