@@ -50,31 +50,74 @@ class TerminalManager {
5050 return nextNumber ;
5151 }
5252
53+ normalizePersistedSessions ( stored ) {
54+ if ( ! Array . isArray ( stored ) ) return [ ] ;
55+
56+ const sessions = stored
57+ . map ( ( entry ) => {
58+ if ( ! entry ) return null ;
59+ if ( typeof entry === "string" ) {
60+ return { pid : entry , name : `Terminal ${ entry } ` } ;
61+ }
62+ if ( typeof entry === "object" && entry . pid ) {
63+ const pid = String ( entry . pid ) ;
64+ return {
65+ pid,
66+ name : entry . name || `Terminal ${ pid } ` ,
67+ } ;
68+ }
69+ return null ;
70+ } )
71+ . filter ( Boolean ) ;
72+ const uniqueSessions = [ ] ;
73+ const seenPids = new Set ( ) ;
74+
75+ for ( const session of sessions ) {
76+ const pid = String ( session . pid ) ;
77+ if ( seenPids . has ( pid ) ) continue ;
78+ seenPids . add ( pid ) ;
79+ uniqueSessions . push ( {
80+ pid,
81+ name :
82+ typeof session . name === "string" && session . name . trim ( )
83+ ? session . name . trim ( )
84+ : `Terminal ${ pid } ` ,
85+ } ) ;
86+ }
87+
88+ return uniqueSessions ;
89+ }
90+
91+ readPersistedSessions ( ) {
92+ try {
93+ return this . normalizePersistedSessions (
94+ helpers . parseJSON ( localStorage . getItem ( TERMINAL_SESSION_STORAGE_KEY ) ) ,
95+ ) ;
96+ } catch ( error ) {
97+ console . error ( "Failed to read persisted terminal sessions:" , error ) ;
98+ return [ ] ;
99+ }
100+ }
101+
53102 async getPersistedSessions ( ) {
54103 try {
104+ const sessions = this . readPersistedSessions ( ) ;
105+ if ( ! sessions . length ) return [ ] ;
106+
107+ if ( ! ( await Terminal . isAxsRunning ( ) ) ) {
108+ // Once the backend is gone, previously persisted PIDs are invalid.
109+ this . savePersistedSessions ( [ ] ) ;
110+ return [ ] ;
111+ }
112+
55113 const stored = helpers . parseJSON (
56114 localStorage . getItem ( TERMINAL_SESSION_STORAGE_KEY ) ,
57115 ) ;
58- if ( ! Array . isArray ( stored ) ) return [ ] ;
59- if ( ! ( await Terminal . isAxsRunning ( ) ) ) {
60- return [ ] ;
116+ if ( Array . isArray ( stored ) && sessions . length !== stored . length ) {
117+ this . savePersistedSessions ( sessions ) ;
61118 }
62- return stored
63- . map ( ( entry ) => {
64- if ( ! entry ) return null ;
65- if ( typeof entry === "string" ) {
66- return { pid : entry , name : `Terminal ${ entry } ` } ;
67- }
68- if ( typeof entry === "object" && entry . pid ) {
69- const pid = String ( entry . pid ) ;
70- return {
71- pid,
72- name : entry . name || `Terminal ${ pid } ` ,
73- } ;
74- }
75- return null ;
76- } )
77- . filter ( Boolean ) ;
119+
120+ return sessions ;
78121 } catch ( error ) {
79122 console . error ( "Failed to read persisted terminal sessions:" , error ) ;
80123 return [ ] ;
@@ -96,7 +139,7 @@ class TerminalManager {
96139 if ( ! pid ) return ;
97140
98141 const pidStr = String ( pid ) ;
99- const sessions = await this . getPersistedSessions ( ) ;
142+ const sessions = this . readPersistedSessions ( ) ;
100143 const existingIndex = sessions . findIndex (
101144 ( session ) => session . pid === pidStr ,
102145 ) ;
@@ -121,7 +164,7 @@ class TerminalManager {
121164 if ( ! pid ) return ;
122165
123166 const pidStr = String ( pid ) ;
124- const sessions = await this . getPersistedSessions ( ) ;
167+ const sessions = this . readPersistedSessions ( ) ;
125168 const nextSessions = sessions . filter ( ( session ) => session . pid !== pidStr ) ;
126169
127170 if ( nextSessions . length !== sessions . length ) {
@@ -156,17 +199,17 @@ class TerminalManager {
156199 error ,
157200 ) ;
158201 failedSessions . push ( session . name || session . pid ) ;
159- this . removePersistedSession ( session . pid ) ;
202+ await this . removePersistedSession ( session . pid ) ;
160203 }
161204 }
162205
163- // Show alert for failed sessions (don't await to not block UI)
206+ // Stale session entries are expected after force-closes; keep startup quiet.
164207 if ( failedSessions . length > 0 ) {
165208 const message =
166209 failedSessions . length === 1
167- ? `Failed to restore terminal: ${ failedSessions [ 0 ] } `
168- : `Failed to restore ${ failedSessions . length } terminals: ${ failedSessions . join ( ", " ) } ` ;
169- alert ( strings [ "error" ] , message ) ;
210+ ? `Skipped unavailable terminal: ${ failedSessions [ 0 ] } `
211+ : `Skipped ${ failedSessions . length } unavailable terminals ` ;
212+ toast ( message ) ;
170213 }
171214
172215 if ( activeFileId && manager ?. getFile ) {
@@ -184,9 +227,10 @@ class TerminalManager {
184227 */
185228 async createTerminal ( options = { } ) {
186229 try {
187- const { render, serverMode, ...terminalOptions } = options ;
230+ const { render, serverMode, reconnecting , ...terminalOptions } = options ;
188231 const shouldRender = render !== false ;
189232 const isServerMode = serverMode !== false ;
233+ const isReconnecting = reconnecting === true ;
190234
191235 const terminalId = `terminal_${ ++ this . terminalCounter } ` ;
192236 const providedName =
@@ -305,11 +349,13 @@ class TerminalManager {
305349 }
306350
307351 // Show alert for terminal creation failure
308- const errorMessage = error ?. message || "Unknown error" ;
309- alert (
310- strings [ "error" ] ,
311- `Failed to create terminal: ${ errorMessage } ` ,
312- ) ;
352+ if ( ! isReconnecting ) {
353+ const errorMessage = error ?. message || "Unknown error" ;
354+ alert (
355+ strings [ "error" ] ,
356+ `Failed to create terminal: ${ errorMessage } ` ,
357+ ) ;
358+ }
313359
314360 reject ( error ) ;
315361 }
0 commit comments