File tree Expand file tree Collapse file tree 4 files changed +60
-7
lines changed Expand file tree Collapse file tree 4 files changed +60
-7
lines changed Original file line number Diff line number Diff line change @@ -360,6 +360,33 @@ export class Config {
360360 return workspaceMetadata ;
361361 }
362362
363+ /**
364+ * Get workspace metadata by ID synchronously.
365+ * Used for executor registration when creating sessions for existing workspaces.
366+ * Only returns workspaces that have complete metadata in config (not legacy).
367+ */
368+ getWorkspaceMetadataSync ( workspaceId : string ) : WorkspaceMetadata | null {
369+ const config = this . loadConfigOrDefault ( ) ;
370+
371+ for ( const [ projectPath , projectConfig ] of config . projects ) {
372+ for ( const workspace of projectConfig . workspaces ) {
373+ // Only check new format workspaces (have id and name in config)
374+ if ( workspace . id === workspaceId && workspace . name ) {
375+ return {
376+ id : workspace . id ,
377+ name : workspace . name ,
378+ projectName : this . getProjectName ( projectPath ) ,
379+ projectPath,
380+ createdAt : workspace . createdAt ,
381+ runtimeConfig : workspace . runtimeConfig ?? DEFAULT_RUNTIME_CONFIG ,
382+ } ;
383+ }
384+ }
385+ }
386+
387+ return null ;
388+ }
389+
363390 /**
364391 * Add a workspace to config.json (single source of truth for workspace metadata).
365392 * Creates project entry if it doesn't exist.
Original file line number Diff line number Diff line change @@ -33,10 +33,14 @@ export class BackgroundProcessManager {
3333
3434 /**
3535 * Register an executor for a workspace.
36- * Called when workspace is created - local workspaces get LocalBackgroundExecutor,
37- * SSH workspaces get SSHBackgroundExecutor.
36+ * Called when workspace is created or session is started for existing workspace.
37+ * Local workspaces get LocalBackgroundExecutor, SSH workspaces get SSHBackgroundExecutor.
38+ * Idempotent - no-op if executor already registered.
3839 */
3940 registerExecutor ( workspaceId : string , executor : BackgroundExecutor ) : void {
41+ if ( this . executors . has ( workspaceId ) ) {
42+ return ; // Already registered
43+ }
4044 log . debug ( `BackgroundProcessManager.registerExecutor(${ workspaceId } )` ) ;
4145 this . executors . set ( workspaceId , executor ) ;
4246 }
@@ -194,7 +198,7 @@ export class BackgroundProcessManager {
194198 proc . exitTime ??= Date . now ( ) ;
195199 // Ensure handle is cleaned up even on error
196200 if ( proc . handle ) {
197- await proc . handle . dispose ( ) . catch ( ( ) => { } ) ;
201+ await proc . handle . dispose ( ) ;
198202 }
199203 return { success : true } ;
200204 }
Original file line number Diff line number Diff line change @@ -121,6 +121,25 @@ export class IpcMain {
121121 return new LocalBackgroundExecutor ( this . bashExecutionService ) ;
122122 }
123123
124+ /**
125+ * Ensure a background executor is registered for a workspace.
126+ * Called when creating sessions for existing workspaces (after app restart).
127+ * No-op if executor already registered or workspace not found (new workspace being created).
128+ */
129+ private ensureExecutorRegistered ( workspaceId : string ) : void {
130+ // Look up workspace metadata synchronously from config
131+ const metadata = this . config . getWorkspaceMetadataSync ( workspaceId ) ;
132+ if ( ! metadata ) {
133+ // Workspace not in config yet - executor will be registered by creation path
134+ return ;
135+ }
136+
137+ const runtime = createRuntime ( metadata . runtimeConfig ) ;
138+ const executor = this . createBackgroundExecutor ( metadata . runtimeConfig , runtime ) ;
139+ // registerExecutor is idempotent - no-op if already registered
140+ this . backgroundProcessManager . registerExecutor ( workspaceId , executor ) ;
141+ }
142+
124143 /**
125144 * Initialize the service. Call this after construction.
126145 * This is separate from the constructor to support async initialization.
@@ -420,6 +439,9 @@ export class IpcMain {
420439 return session ;
421440 }
422441
442+ // Ensure executor is registered for existing workspaces (handles app restart case)
443+ this . ensureExecutorRegistered ( trimmed ) ;
444+
423445 session = new AgentSession ( {
424446 workspaceId : trimmed ,
425447 config : this . config ,
Original file line number Diff line number Diff line change @@ -88,8 +88,8 @@ class LocalBackgroundHandle implements BackgroundHandle {
8888 }
8989 }
9090
91- async isRunning ( ) : Promise < boolean > {
92- return this . disposable . child . exitCode === null ;
91+ isRunning ( ) : Promise < boolean > {
92+ return Promise . resolve ( this . disposable . child . exitCode === null ) ;
9393 }
9494
9595 async terminate ( ) : Promise < void > {
@@ -126,8 +126,8 @@ class LocalBackgroundHandle implements BackgroundHandle {
126126 this . terminated = true ;
127127 }
128128
129- async dispose ( ) : Promise < void > {
130- this . disposable [ Symbol . dispose ] ( ) ;
129+ dispose ( ) : Promise < void > {
130+ return Promise . resolve ( this . disposable [ Symbol . dispose ] ( ) ) ;
131131 }
132132
133133 /** Get the child process (for spawn event waiting) */
You can’t perform that action at this time.
0 commit comments