@@ -3795,52 +3795,12 @@ class Dashboard {
37953795 async openWorkspace ( workspaceId ) {
37963796 console . log ( 'Opening workspace:' , workspaceId ) ;
37973797
3798- // Get recovery settings
3799- const recoverySettings = this . orchestrator . userSettings ?. global ?. sessionRecovery || { } ;
3800- const recoveryEnabled = recoverySettings . enabled !== false ;
3801- const recoveryMode = recoverySettings . mode || 'ask' ;
3802-
3803- // Check for recovery state first (if enabled)
3804- if ( recoveryEnabled ) {
3805- const recoveryInfo = await this . checkRecoveryState ( workspaceId ) ;
3806- if ( recoveryInfo && recoveryInfo . recoverableSessions > 0 ) {
3807- // If the user previously dismissed this exact snapshot, don't nag again.
3808- const savedAt = String ( recoveryInfo . savedAt || '' ) . trim ( ) ;
3809- const dismissKey = `orchestrator-recovery-dismissed:${ workspaceId } ` ;
3810- let dismissedSnapshot = false ;
3811- if ( savedAt ) {
3812- try {
3813- const dismissedAt = String ( localStorage . getItem ( dismissKey ) || '' ) . trim ( ) ;
3814- if ( dismissedAt && dismissedAt === savedAt ) {
3815- console . log ( 'Skipping recovery dialog - dismissed for this snapshot' ) ;
3816- dismissedSnapshot = true ;
3817- } else {
3818- // Clear stale dismiss markers when the snapshot changes.
3819- if ( dismissedAt ) localStorage . removeItem ( dismissKey ) ;
3820- }
3821- } catch {
3822- // ignore
3823- }
3824- }
3825-
3826- if ( dismissedSnapshot ) {
3827- // Do nothing: proceed to open workspace with no recovery.
3828- } else if ( recoveryMode === 'auto' ) {
3829- // Auto-recover all sessions
3830- this . pendingRecovery = { workspaceId, mode : 'all' , sessions : recoveryInfo . sessions } ;
3831- console . log ( 'Auto-recovering all sessions' ) ;
3832- } else if ( recoveryMode === 'ask' ) {
3833- // Show recovery dialog and wait for user choice
3834- const shouldRecover = await this . showRecoveryDialog ( workspaceId , recoveryInfo ) ;
3835- if ( shouldRecover === 'cancel' ) {
3836- return ; // User cancelled
3837- }
3838- this . pendingRecovery = shouldRecover && typeof shouldRecover === 'object'
3839- ? { workspaceId, ...shouldRecover }
3840- : shouldRecover ;
3841- }
3842- // If mode === 'skip', don't set pendingRecovery
3843- }
3798+ const recoveryPlan = await this . planRecoveryForWorkspace ( workspaceId , { interactive : true } ) ;
3799+ if ( recoveryPlan ?. action === 'cancel' ) {
3800+ return ;
3801+ }
3802+ if ( recoveryPlan ?. pending ) {
3803+ this . pendingRecovery = recoveryPlan . pending ;
38443804 }
38453805
38463806 // Show loading state
@@ -3866,6 +3826,61 @@ class Dashboard {
38663826 this . orchestrator . socket . emit ( 'switch-workspace' , { workspaceId } ) ;
38673827 }
38683828
3829+ async planRecoveryForWorkspace ( workspaceId , { interactive = true } = { } ) {
3830+ const targetWorkspaceId = String ( workspaceId || '' ) . trim ( ) ;
3831+ if ( ! targetWorkspaceId ) {
3832+ return { action : 'skip' , pending : null } ;
3833+ }
3834+
3835+ const recoverySettings = this . orchestrator . userSettings ?. global ?. sessionRecovery || { } ;
3836+ const recoveryEnabled = recoverySettings . enabled !== false ;
3837+ const recoveryMode = recoverySettings . mode || 'ask' ;
3838+ if ( ! recoveryEnabled ) {
3839+ return { action : 'skip' , pending : null } ;
3840+ }
3841+
3842+ const recoveryInfo = await this . checkRecoveryState ( targetWorkspaceId ) ;
3843+ if ( ! ( recoveryInfo && recoveryInfo . recoverableSessions > 0 ) ) {
3844+ return { action : 'skip' , pending : null } ;
3845+ }
3846+
3847+ const savedAt = String ( recoveryInfo . savedAt || '' ) . trim ( ) ;
3848+ const dismissKey = `orchestrator-recovery-dismissed:${ targetWorkspaceId } ` ;
3849+ if ( savedAt ) {
3850+ try {
3851+ const dismissedAt = String ( localStorage . getItem ( dismissKey ) || '' ) . trim ( ) ;
3852+ if ( dismissedAt && dismissedAt === savedAt ) {
3853+ console . log ( 'Skipping recovery dialog - dismissed for this snapshot' ) ;
3854+ return { action : 'dismissed' , pending : null } ;
3855+ }
3856+ if ( dismissedAt ) localStorage . removeItem ( dismissKey ) ;
3857+ } catch {
3858+ // ignore
3859+ }
3860+ }
3861+
3862+ if ( recoveryMode === 'auto' ) {
3863+ console . log ( 'Auto-recovering all sessions' ) ;
3864+ return {
3865+ action : 'recover' ,
3866+ pending : { workspaceId : targetWorkspaceId , mode : 'all' , sessions : recoveryInfo . sessions }
3867+ } ;
3868+ }
3869+
3870+ if ( recoveryMode === 'ask' && interactive ) {
3871+ const shouldRecover = await this . showRecoveryDialog ( targetWorkspaceId , recoveryInfo ) ;
3872+ if ( shouldRecover === 'cancel' ) {
3873+ return { action : 'cancel' , pending : null } ;
3874+ }
3875+ const pending = shouldRecover && typeof shouldRecover === 'object'
3876+ ? { workspaceId : targetWorkspaceId , ...shouldRecover }
3877+ : null ;
3878+ return pending ? { action : 'recover' , pending } : { action : 'skip' , pending : null } ;
3879+ }
3880+
3881+ return { action : 'skip' , pending : null } ;
3882+ }
3883+
38693884 showCreateWorkspaceWizard ( options = { } ) {
38703885 console . log ( 'Opening workspace creation wizard...' ) ;
38713886 if ( ! window . WorkspaceWizard ) {
0 commit comments