@@ -205,6 +205,29 @@ def delete_account(self, name: str):
205205 """Alias for remove_account (Legacy compatibility)."""
206206 self .remove_account (name )
207207
208+ def _restore_target_session (self , target_account : Account , vault_slug : str ):
209+ """Restores sessions from storage to ~/.codex/sessions."""
210+ legacy_auth_file = self ._get_legacy_auth_file ()
211+ live_sessions_dir = legacy_auth_file .parent / "sessions"
212+
213+ # Ensure it's clean (should be clean from shelving, but just in case)
214+ if live_sessions_dir .exists ():
215+ shutil .rmtree (live_sessions_dir )
216+
217+ # Derive canonical key for retrieval
218+ if vault_slug == "personal" :
219+ storage_key = target_account .name
220+ else :
221+ storage_key = f"{ vault_slug } /{ target_account .name } "
222+
223+ storage_dir = self ._get_session_storage_dir (storage_key )
224+
225+ if storage_dir .exists ():
226+ shutil .copytree (storage_dir , live_sessions_dir )
227+ else :
228+ # If no stored session, just ensure the dir exists empty
229+ live_sessions_dir .mkdir (parents = True , exist_ok = True )
230+
208231 def switch_account (self , name : str ):
209232 """Switches active account. Validates existence first."""
210233 # 1. Validate & Normalize
@@ -216,9 +239,15 @@ def switch_account(self, name: str):
216239 # Check existence in vault (slugifies internally)
217240 acc = vault .get_account (acc_slug )
218241
219- # 2. Sync Legacy Auth
242+ # 2a. Shelve Current Session (Save state of the OLD account)
243+ self ._shelve_current_session ()
244+
245+ # 2b. Sync Legacy Auth (Update credentials)
220246 self .sync_legacy_auth (acc )
221247
248+ # 2c. Restore Target Session (Load state of the NEW account)
249+ self ._restore_target_session (acc , vault_slug )
250+
222251 # 3. Update Config with Canonical Reference
223252 cfg = self .load_config ()
224253
@@ -231,6 +260,42 @@ def switch_account(self, name: str):
231260
232261 self .save_config (cfg )
233262
263+ def _get_session_storage_dir (self , account_name : str ) -> Path :
264+ """Returns the directory where sessions for a specific account are stored."""
265+ # We store shelved sessions in the root config dir separated by account
266+ return self .root / "shelved_sessions" / slugify (account_name )
267+
268+ def _shelve_current_session (self ):
269+ """Moves current ~/.codex/sessions to storage."""
270+ cfg = self .load_config ()
271+ if not cfg .active_account :
272+ return # No active account to save session for
273+
274+ legacy_auth_file = self ._get_legacy_auth_file ()
275+ live_sessions_dir = legacy_auth_file .parent / "sessions"
276+
277+ if not live_sessions_dir .exists ():
278+ return
279+
280+ # Identify where to save it
281+ # We handle 'personal/slug' vs 'slug' normalisation via the config
282+ # We just need a unique folder name.
283+ storage_dir = self ._get_session_storage_dir (cfg .active_account )
284+ storage_dir .parent .mkdir (parents = True , exist_ok = True )
285+
286+ # If storage dir exists, we merge or replace?
287+ # rmtree+copytree is safest to ensure exact mirroring of state
288+ if storage_dir .exists ():
289+ shutil .rmtree (storage_dir )
290+
291+ # Move mechanism: We copytree then rmtree orig, or move.
292+ # shutil.move can fail across filesystems, copytree is robust.
293+ # But we want to LEAVE the directory empty for the next guy? No, we restore next.
294+ shutil .copytree (live_sessions_dir , storage_dir )
295+
296+ # Clean up the live directory to be ready for the new account (or just to leave it clean)
297+ shutil .rmtree (live_sessions_dir )
298+
234299 def sync_legacy_auth (self , account : Account ):
235300 """Writes credentials to ~/.codex/auth.json (Legacy Support)."""
236301 # This logic used to be implicit in `list` or `status` checks.
@@ -260,11 +325,14 @@ def sync_legacy_auth(self, account: Account):
260325 f .write (json .dumps (data , indent = 2 ))
261326
262327
263- # Clear sessions to prevent "Token data not available" error
264- sessions_dir = legacy_dir / "sessions"
265- if sessions_dir .exists ():
266- shutil .rmtree (sessions_dir )
267- sessions_dir .mkdir () # Recreate empty
328+ # STOP DELETING SESSIONS
329+ # sessions_dir = legacy_dir / "sessions"
330+ # if sessions_dir.exists():
331+ # shutil.rmtree(sessions_dir)
332+ # sessions_dir.mkdir() # Recreate empty
333+
334+ # Just ensure the directory exists so Codex doesn't crash if it expects it
335+ (legacy_dir / "sessions" ).mkdir (exist_ok = True )
268336
269337 os .chmod (legacy_auth_file , 0o600 )
270338
0 commit comments