@@ -50,31 +50,113 @@ class TerminalManager {
5050 return nextNumber ;
5151 }
5252
53- async getPersistedSessions ( ) {
53+ normalizePersistedSessions ( stored ) {
54+ if ( ! Array . isArray ( stored ) ) {
55+ return {
56+ sessions : [ ] ,
57+ changed : stored != null ,
58+ } ;
59+ }
60+
61+ const sessions = [ ] ;
62+ const uniqueSessions = [ ] ;
63+ const seenPids = new Set ( ) ;
64+ let changed = false ;
65+
66+ for ( const entry of stored ) {
67+ if ( ! entry ) {
68+ changed = true ;
69+ continue ;
70+ }
71+
72+ if ( typeof entry === "string" ) {
73+ sessions . push ( {
74+ pid : entry ,
75+ name : `Terminal ${ entry } ` ,
76+ } ) ;
77+ changed = true ;
78+ continue ;
79+ }
80+
81+ if ( typeof entry !== "object" || ! entry . pid ) {
82+ changed = true ;
83+ continue ;
84+ }
85+
86+ const pid = String ( entry . pid ) ;
87+ const name =
88+ typeof entry . name === "string" && entry . name . trim ( )
89+ ? entry . name . trim ( )
90+ : `Terminal ${ pid } ` ;
91+
92+ if ( entry . pid !== pid || entry . name !== name ) {
93+ changed = true ;
94+ }
95+
96+ sessions . push ( { pid, name } ) ;
97+ }
98+
99+ for ( const session of sessions ) {
100+ const pid = String ( session . pid ) ;
101+ if ( seenPids . has ( pid ) ) {
102+ changed = true ;
103+ continue ;
104+ }
105+ seenPids . add ( pid ) ;
106+ uniqueSessions . push ( {
107+ pid,
108+ name :
109+ typeof session . name === "string" && session . name . trim ( )
110+ ? session . name . trim ( )
111+ : `Terminal ${ pid } ` ,
112+ } ) ;
113+ }
114+
115+ if ( uniqueSessions . length !== stored . length ) {
116+ changed = true ;
117+ }
118+
119+ return {
120+ sessions : uniqueSessions ,
121+ changed,
122+ } ;
123+ }
124+
125+ readPersistedSessions ( ) {
54126 try {
55- const stored = helpers . parseJSON (
56- localStorage . getItem ( TERMINAL_SESSION_STORAGE_KEY ) ,
127+ return this . normalizePersistedSessions (
128+ helpers . parseJSON ( localStorage . getItem ( TERMINAL_SESSION_STORAGE_KEY ) ) ,
57129 ) ;
58- if ( ! Array . isArray ( stored ) ) return [ ] ;
130+ } catch ( error ) {
131+ console . error ( "Failed to read persisted terminal sessions:" , error ) ;
132+ return {
133+ sessions : [ ] ,
134+ changed : false ,
135+ } ;
136+ }
137+ }
138+
139+ async getPersistedSessions ( ) {
140+ try {
141+ const { sessions, changed } = this . readPersistedSessions ( ) ;
142+ if ( ! sessions . length ) {
143+ if ( changed ) {
144+ this . savePersistedSessions ( [ ] ) ;
145+ }
146+ return [ ] ;
147+ }
148+
59149 if ( ! ( await Terminal . isAxsRunning ( ) ) ) {
150+ // Once the backend is gone, previously persisted PIDs are invalid.
151+ this . savePersistedSessions ( [ ] ) ;
60152 return [ ] ;
61153 }
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 ) ;
154+
155+ if ( changed ) {
156+ this . savePersistedSessions ( sessions ) ;
157+ }
158+
159+ return sessions ;
78160 } catch ( error ) {
79161 console . error ( "Failed to read persisted terminal sessions:" , error ) ;
80162 return [ ] ;
@@ -96,7 +178,7 @@ class TerminalManager {
96178 if ( ! pid ) return ;
97179
98180 const pidStr = String ( pid ) ;
99- const sessions = await this . getPersistedSessions ( ) ;
181+ const { sessions } = this . readPersistedSessions ( ) ;
100182 const existingIndex = sessions . findIndex (
101183 ( session ) => session . pid === pidStr ,
102184 ) ;
@@ -121,7 +203,7 @@ class TerminalManager {
121203 if ( ! pid ) return ;
122204
123205 const pidStr = String ( pid ) ;
124- const sessions = await this . getPersistedSessions ( ) ;
206+ const { sessions } = this . readPersistedSessions ( ) ;
125207 const nextSessions = sessions . filter ( ( session ) => session . pid !== pidStr ) ;
126208
127209 if ( nextSessions . length !== sessions . length ) {
@@ -156,17 +238,17 @@ class TerminalManager {
156238 error ,
157239 ) ;
158240 failedSessions . push ( session . name || session . pid ) ;
159- this . removePersistedSession ( session . pid ) ;
241+ await this . removePersistedSession ( session . pid ) ;
160242 }
161243 }
162244
163- // Show alert for failed sessions (don't await to not block UI)
245+ // Stale session entries are expected after force-closes; keep startup quiet.
164246 if ( failedSessions . length > 0 ) {
165247 const message =
166248 failedSessions . length === 1
167- ? `Failed to restore terminal: ${ failedSessions [ 0 ] } `
168- : `Failed to restore ${ failedSessions . length } terminals: ${ failedSessions . join ( ", " ) } ` ;
169- alert ( strings [ "error" ] , message ) ;
249+ ? `Skipped unavailable terminal: ${ failedSessions [ 0 ] } `
250+ : `Skipped ${ failedSessions . length } unavailable terminals ` ;
251+ toast ( message ) ;
170252 }
171253
172254 if ( activeFileId && manager ?. getFile ) {
@@ -184,9 +266,10 @@ class TerminalManager {
184266 */
185267 async createTerminal ( options = { } ) {
186268 try {
187- const { render, serverMode, ...terminalOptions } = options ;
269+ const { render, serverMode, reconnecting , ...terminalOptions } = options ;
188270 const shouldRender = render !== false ;
189271 const isServerMode = serverMode !== false ;
272+ const isReconnecting = reconnecting === true ;
190273
191274 const terminalId = `terminal_${ ++ this . terminalCounter } ` ;
192275 const providedName =
@@ -305,11 +388,13 @@ class TerminalManager {
305388 }
306389
307390 // 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- ) ;
391+ if ( ! isReconnecting ) {
392+ const errorMessage = error ?. message || "Unknown error" ;
393+ alert (
394+ strings [ "error" ] ,
395+ `Failed to create terminal: ${ errorMessage } ` ,
396+ ) ;
397+ }
313398
314399 reject ( error ) ;
315400 }
0 commit comments