@@ -117,6 +117,82 @@ export class SessionDiscovery {
117117 return paths ;
118118 }
119119
120+ /** Returns true when the extension host is running inside WSL. */
121+ isWSL ( ) : boolean {
122+ return os . platform ( ) === 'linux' && (
123+ typeof process . env . WSL_DISTRO_NAME === 'string' ||
124+ typeof process . env . WSL_INTEROP === 'string'
125+ ) ;
126+ }
127+
128+ /**
129+ * When running inside WSL, probes the Windows-side VS Code user paths
130+ * (mounted at /mnt/c/...) so sessions created in a native Windows VS Code
131+ * window are also discovered.
132+ *
133+ * This is intentionally async and non-blocking: all path existence checks
134+ * use async fs.promises.access; errors at any level are silently ignored so
135+ * a missing or inaccessible /mnt/c mount never throws.
136+ */
137+ async getWSLWindowsPaths ( ) : Promise < string [ ] > {
138+ if ( ! this . isWSL ( ) ) {
139+ return [ ] ;
140+ }
141+
142+ const wslPaths : string [ ] = [ ] ;
143+
144+ const vscodeVariants = [
145+ 'Code' ,
146+ 'Code - Insiders' ,
147+ 'Code - Exploration' ,
148+ 'VSCodium' ,
149+ 'Cursor'
150+ ] ;
151+
152+ // Derive candidate Windows usernames (safe, multiple fallbacks).
153+ const windowsUsernames : string [ ] = [ ] ;
154+
155+ // USERPROFILE in WSL is sometimes set to the Windows path e.g. /mnt/c/Users/alice
156+ const userprofile = process . env . USERPROFILE ;
157+ if ( userprofile ) {
158+ const match = userprofile . match ( / ^ \/ m n t \/ [ a - z ] \/ U s e r s \/ ( [ ^ / ] + ) / ) ;
159+ if ( match ) {
160+ windowsUsernames . push ( match [ 1 ] ) ;
161+ }
162+ }
163+
164+ // Enumerate /mnt/c/Users/ if accessible — gives us every Windows profile
165+ // without guessing. We read only the top-level directory names.
166+ const windowsUsersDir = '/mnt/c/Users' ;
167+ try {
168+ const entries = await fs . promises . readdir ( windowsUsersDir , { withFileTypes : true } ) ;
169+ for ( const entry of entries ) {
170+ // Skip system pseudo-folders
171+ if ( ! entry . isDirectory ( ) ) { continue ; }
172+ const name = entry . name ;
173+ if ( name === 'Public' || name === 'Default' || name === 'Default User' ||
174+ name === 'All Users' || name . startsWith ( '.' ) ) {
175+ continue ;
176+ }
177+ if ( ! windowsUsernames . includes ( name ) ) {
178+ windowsUsernames . push ( name ) ;
179+ }
180+ }
181+ } catch {
182+ // /mnt/c/Users is not accessible — WSL drive not mounted or no Windows partition
183+ return [ ] ;
184+ }
185+
186+ for ( const winUser of windowsUsernames ) {
187+ const appData = path . join ( windowsUsersDir , winUser , 'AppData' , 'Roaming' ) ;
188+ for ( const variant of vscodeVariants ) {
189+ wslPaths . push ( path . join ( appData , variant , 'User' ) ) ;
190+ }
191+ }
192+
193+ return wslPaths ;
194+ }
195+
120196 /**
121197 * Returns all candidate paths the extension considers when scanning for session files,
122198 * along with whether each path exists on disk. Used for diagnostics display.
@@ -132,6 +208,26 @@ export class SessionDiscovery {
132208 candidates . push ( { path : p , exists, source : 'VS Code' } ) ;
133209 }
134210
211+ // When in WSL, synchronously check the top-level Windows users dir and add
212+ // candidate paths so they appear in the diagnostics panel.
213+ if ( this . isWSL ( ) ) {
214+ const vscodeVariants = [ 'Code' , 'Code - Insiders' , 'Code - Exploration' , 'VSCodium' , 'Cursor' ] ;
215+ const windowsUsersDir = '/mnt/c/Users' ;
216+ try {
217+ const entries = fs . readdirSync ( windowsUsersDir , { withFileTypes : true } ) ;
218+ const systemNames = new Set ( [ 'Public' , 'Default' , 'Default User' , 'All Users' ] ) ;
219+ for ( const entry of entries ) {
220+ if ( ! entry . isDirectory ( ) || entry . name . startsWith ( '.' ) || systemNames . has ( entry . name ) ) { continue ; }
221+ for ( const variant of vscodeVariants ) {
222+ const p = path . join ( windowsUsersDir , entry . name , 'AppData' , 'Roaming' , variant , 'User' ) ;
223+ let exists = false ;
224+ try { exists = fs . existsSync ( p ) ; } catch { /* ignore */ }
225+ candidates . push ( { path : p , exists, source : 'VS Code (Windows via WSL)' } ) ;
226+ }
227+ }
228+ } catch { /* /mnt/c not accessible — skip */ }
229+ }
230+
135231 // Copilot CLI
136232 const copilotCliPath = path . join ( os . homedir ( ) , '.copilot' , 'session-state' ) ;
137233 let copilotCliExists = false ;
@@ -218,6 +314,20 @@ export class SessionDiscovery {
218314
219315 // Get all possible VS Code user paths (stable, insiders, remote, etc.)
220316 const allVSCodePaths = this . getVSCodeUserPaths ( ) ;
317+
318+ // When running inside WSL also probe the Windows-side paths so sessions
319+ // created in a native Windows VS Code window are not missed.
320+ if ( this . isWSL ( ) ) {
321+ this . deps . log ( `🪟 WSL environment detected — probing Windows-side VS Code paths` ) ;
322+ const wslWinPaths = await this . getWSLWindowsPaths ( ) ;
323+ if ( wslWinPaths . length > 0 ) {
324+ this . deps . log ( `🪟 Adding ${ wslWinPaths . length } Windows-side candidate paths from WSL` ) ;
325+ allVSCodePaths . push ( ...wslWinPaths ) ;
326+ } else {
327+ this . deps . log ( `🪟 No Windows-side paths found (Windows drive may not be mounted)` ) ;
328+ }
329+ }
330+
221331 this . deps . log ( `📂 Considering ${ allVSCodePaths . length } candidate VS Code paths:` ) ;
222332 for ( const candidatePath of allVSCodePaths ) {
223333 this . deps . log ( ` 📁 ${ candidatePath } ` ) ;
0 commit comments