@@ -330,6 +330,64 @@ describe("shell-terminal", () => {
330330 } ) ;
331331} ) ;
332332
333+ // ---------------------------------------------------------------------------
334+ // Concurrent openShell() session isolation
335+ // ---------------------------------------------------------------------------
336+
337+ describe ( "concurrent openShell sessions" , ( ) => {
338+ let harnessA : TerminalHarness ;
339+ let harnessB : TerminalHarness ;
340+
341+ afterEach ( async ( ) => {
342+ await harnessA ?. dispose ( ) ;
343+ await harnessB ?. dispose ( ) ;
344+ } ) ;
345+
346+ it ( "output isolation — data from shell A never appears in shell B" , async ( ) => {
347+ const driver = new MockShellDriver ( ) ;
348+ const { kernel } = await createTestKernel ( { drivers : [ driver ] } ) ;
349+
350+ harnessA = new TerminalHarness ( kernel ) ;
351+ harnessB = new TerminalHarness ( kernel ) ;
352+
353+ await harnessA . waitFor ( "$" ) ;
354+ await harnessB . waitFor ( "$" ) ;
355+
356+ // Send different commands to each shell
357+ await harnessA . type ( "echo ALPHA\n" ) ;
358+ await harnessB . type ( "echo BRAVO\n" ) ;
359+
360+ // Shell A has ALPHA, never BRAVO
361+ const screenA = harnessA . screenshotTrimmed ( ) ;
362+ expect ( screenA ) . toBe ( [ "$ echo ALPHA" , "ALPHA" , "$ " ] . join ( "\n" ) ) ;
363+
364+ // Shell B has BRAVO, never ALPHA
365+ const screenB = harnessB . screenshotTrimmed ( ) ;
366+ expect ( screenB ) . toBe ( [ "$ echo BRAVO" , "BRAVO" , "$ " ] . join ( "\n" ) ) ;
367+ } ) ;
368+
369+ it ( "exit one shell — surviving shell is unaffected" , async ( ) => {
370+ const driver = new MockShellDriver ( ) ;
371+ const { kernel } = await createTestKernel ( { drivers : [ driver ] } ) ;
372+
373+ harnessA = new TerminalHarness ( kernel ) ;
374+ harnessB = new TerminalHarness ( kernel ) ;
375+
376+ await harnessA . waitFor ( "$" ) ;
377+ await harnessB . waitFor ( "$" ) ;
378+
379+ // Exit shell A
380+ const codeA = await harnessA . exit ( ) ;
381+ expect ( codeA ) . toBe ( 0 ) ;
382+
383+ // Shell B still works — run a command
384+ await harnessB . type ( "echo STILL_ALIVE\n" ) ;
385+ expect ( harnessB . screenshotTrimmed ( ) ) . toBe (
386+ [ "$ echo STILL_ALIVE" , "STILL_ALIVE" , "$ " ] . join ( "\n" ) ,
387+ ) ;
388+ } ) ;
389+ } ) ;
390+
333391// ---------------------------------------------------------------------------
334392// readPump lifecycle tests — verify pump is tracked, exits on shell exit,
335393// errors are propagated, and wait() drains before resolving.
0 commit comments