Found while porting the emulator to Rust for BossConsoleRust. Verified against the current checkout.
1. The documented shell-integration setup does nothing — OSC 7 is never dispatched
BossEmulator1.kt:403:
7 -> // Support for OSC 7 is pending
The arm returns true, which suppresses the unhandled-sequence log, and then never dispatches anything. Bare OSC 7 is unimplemented.
Meanwhile .claude/rules/shell-integration.md instructs users to emit exactly that sequence:
:11 PROMPT_COMMAND='echo -ne "\033]7;file://${HOSTNAME}${PWD}\007"'
:16 precmd() { echo -ne "\033]7;file://${HOST}${PWD}\007" }
So a user who follows the documented setup gets silently no cwd tracking and no cwd-derived tab titles. Nothing warns them; the sequence is accepted and discarded. It works only for users running BossTerm's own shell-integration scripts, because those report cwd through the private OSC 1341;7;file://… sub-protocol, which is routed.
Two ways to close it, and the choice matters:
- Route OSC 7 to the same handler
1341;7 reaches. This is the standard sequence (VTE, iTerm2, WezTerm, Kitty all honour it), so supporting it also means cwd tracking works for users arriving with an existing dotfile setup.
- Or correct the docs to stop advertising a sequence the emulator drops.
The first is preferable — OSC 7 is the interoperable spelling, and the private sub-protocol then becomes an addition rather than the only path.
2. Inline images are fully decoded on the emulator's parse thread
processITerm2File calls ImageIO.read solely to obtain width and height. That decodes the entire image on the thread parsing PTY output, so a large inline image stalls parsing of everything queued behind it in the stream — visible as the terminal freezing mid-output.
Dimensions are available from the header alone (PNG IHDR, JPEG SOF, GIF logical screen descriptor, WebP VP8X), which is O(header) and yields identical numbers. Decode can then happen off-thread, or lazily at render time.
3. Three pinned Dispatchers.IO workers per shell session
Confirmed in source, and consistent with the known symptom: ~20 sessions exhausts the 64-thread Dispatchers.IO cap, at which point terminals freeze and new tabs open with no shell at all.
For reference, the Rust port needs 2 threads per session plus one process-wide reaper: child-exit waiting does not need a thread per child, since liveness comes from PTY EOF and only the exit code trails (bounded there at ≤200 ms). A tests/thread_budget.rs opens 6 real PTYs and asserts the exact per-session cost and full teardown, so the budget is measured rather than assumed — worth doing here too, since this class of bug is invisible until it is severe.
Found while porting the emulator to Rust for BossConsoleRust. Verified against the current checkout.
1. The documented shell-integration setup does nothing — OSC 7 is never dispatched
BossEmulator1.kt:403:The arm returns
true, which suppresses the unhandled-sequence log, and then never dispatches anything. Bare OSC 7 is unimplemented.Meanwhile
.claude/rules/shell-integration.mdinstructs users to emit exactly that sequence:So a user who follows the documented setup gets silently no cwd tracking and no cwd-derived tab titles. Nothing warns them; the sequence is accepted and discarded. It works only for users running BossTerm's own shell-integration scripts, because those report cwd through the private
OSC 1341;7;file://…sub-protocol, which is routed.Two ways to close it, and the choice matters:
1341;7reaches. This is the standard sequence (VTE, iTerm2, WezTerm, Kitty all honour it), so supporting it also means cwd tracking works for users arriving with an existing dotfile setup.The first is preferable — OSC 7 is the interoperable spelling, and the private sub-protocol then becomes an addition rather than the only path.
2. Inline images are fully decoded on the emulator's parse thread
processITerm2FilecallsImageIO.readsolely to obtain width and height. That decodes the entire image on the thread parsing PTY output, so a large inline image stalls parsing of everything queued behind it in the stream — visible as the terminal freezing mid-output.Dimensions are available from the header alone (PNG IHDR, JPEG SOF, GIF logical screen descriptor, WebP VP8X), which is O(header) and yields identical numbers. Decode can then happen off-thread, or lazily at render time.
3. Three pinned
Dispatchers.IOworkers per shell sessionConfirmed in source, and consistent with the known symptom: ~20 sessions exhausts the 64-thread
Dispatchers.IOcap, at which point terminals freeze and new tabs open with no shell at all.For reference, the Rust port needs 2 threads per session plus one process-wide reaper: child-exit waiting does not need a thread per child, since liveness comes from PTY EOF and only the exit code trails (bounded there at ≤200 ms). A
tests/thread_budget.rsopens 6 real PTYs and asserts the exact per-session cost and full teardown, so the budget is measured rather than assumed — worth doing here too, since this class of bug is invisible until it is severe.