hermes - 💡(How to fix) Fix Bug: Windows compatibility issues — TUI mouse leak, log rotation PermissionError, console window flash

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When running hermes --tui in Git Bash (mintty 3.8.1) on Windows, truncated SGR mouse tracking sequences leak as literal text into the terminal. The leaked text (e.g. 5;695;695;69) progressively fills the screen, forcing the user to close the terminal window.

A secondary issue: RotatingFileHandler.doRollover() raises PermissionError [WinError 32] on Windows when background threads hold concurrent handles to agent.log, producing noisy tracebacks on every log rotation.

Error Message

PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。 File ".../logging/handlers.py", line 115, in rotate os.rename(source, dest)

Root Cause

Six subprocess.run() calls spawn console programs (PowerShell, tasklist.exe, wmic.exe) without creationflags=CREATE_NO_WINDOW (0x08000000). On Windows, this creates a visible console window that briefly flashes on screen before closing.

Fix Action

Fix

Add creationflags=0x08000000 to each subprocess.run() call on Windows. Other parts of the codebase (tools/environments/local.py, hermes_cli/gateway_windows.py, cron/scheduler.py) already use this flag correctly.


Code Example

Chunk 1: ESC          → tokenizer buffers as incomplete escape
Chunk 2: [<5;695;695  → arrives as text after flushIncomplete fires (50ms timeout)
Chunk 3: M            → arrives later as text

---

const SGR_MOUSE_FRAGMENT_RE = /(?<!\d)(?:\[<|<)?(?:[0-9]|[1-9][0-9]|1\d{2}|2[0-4]\d|25[0-5]);\d+;\d+[Mm]/g

---

if (!keypress.name && /^\[<\d+;\d+;\d+[Mm]/.test(input)) {
  input = ''
}

---

// Suppress truncated SGR mouse parameter fragments (Windows / MSYS2).
// On MSYS2 (Git Bash), stdin is a pipe rather than a true PTY.  SGR mouse
// responses can be fragmented more aggressively.  When a fragment arrives as
// a bare text token like "5;695;695;69" (no ESC, no [<, no terminating M/m),
// the SGR_MOUSE_FRAGMENT_RE fails to match because it requires the [Mm] suffix.
if (!keypress.name && /^(?:\[?<?\d+(?:;\d+){1,3})/.test(input) && !/^[a-zA-Z]/.test(input)) {
  input = ''
}

---

PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。
  File ".../logging/handlers.py", line 115, in rotate
    os.rename(source, dest)

---

def doRollover(self):
    import sys as _sys
    import time as _time

    if _sys.platform == "win32":
        for _attempt in range(5):
            try:
                super().doRollover()
                self._chmod_if_managed()
                return
            except PermissionError:
                if _attempt < 4:
                    _time.sleep(0.05)
        logging.getLogger(__name__).warning(
            "Log rotation failed for %s (file locked); log will continue to grow",
            self.baseFilename,
        )
    else:
        super().doRollover()
        self._chmod_if_managed()
RAW_BUFFERClick to expand / collapse

Bug: TUI SGR mouse escape sequences leak as text on Windows / MSYS2 (mintty)

Summary

When running hermes --tui in Git Bash (mintty 3.8.1) on Windows, truncated SGR mouse tracking sequences leak as literal text into the terminal. The leaked text (e.g. 5;695;695;69) progressively fills the screen, forcing the user to close the terminal window.

A secondary issue: RotatingFileHandler.doRollover() raises PermissionError [WinError 32] on Windows when background threads hold concurrent handles to agent.log, producing noisy tracebacks on every log rotation.

Environment

  • OS: Windows 10, MSYS2 (MINGW64)
  • Terminal: mintty 3.8.1 (Git Bash window, NOT Windows Terminal)
  • Hermes: v0.14.0 (60 commits behind upstream)
  • Node: v20.x
  • Python: 3.11.15
  • Ink: 6.8.0 (via @hermes/ink fork)
  • TERM: xterm-256color

Issue 1: SGR Mouse Sequence Leakage

Root Cause

The TUI enables SGR mouse tracking (DECSET 1003 + 1006) via ENABLE_MOUSE_TRACKING in packages/hermes-ink/src/ink/termio/dec.ts. The terminal responds with ESC[<btn;col;row M/m sequences on mouse events (move, click, scroll).

On MSYS2, stdin is a pipe (not a true PTY). SGR mouse responses can be fragmented into 3+ chunks:

Chunk 1: ESC          → tokenizer buffers as incomplete escape
Chunk 2: [<5;695;695  → arrives as text after flushIncomplete fires (50ms timeout)
Chunk 3: M            → arrives later as text

The existing defense in packages/hermes-ink/src/ink/parse-keypress.ts (SGR_MOUSE_FRAGMENT_RE) only matches fragments ending with [Mm]:

const SGR_MOUSE_FRAGMENT_RE = /(?<!\d)(?:\[<|<)?(?:[0-9]|[1-9][0-9]|1\d{2}|2[0-4]\d|25[0-5]);\d+;\d+[Mm]/g

And the secondary defense in events/input-event.ts only matches complete fragments:

if (!keypress.name && /^\[<\d+;\d+;\d+[Mm]/.test(input)) {
  input = ''
}

When a fragment arrives as bare 5;695;695;69 (no [< prefix, no [Mm] suffix), neither defense catches it. The fragment passes through parseKey(), gets its potential ESC stripped, and renders as literal text.

Reproduction

  1. Install Hermes on Windows
  2. Open Git Bash (mintty) — NOT Windows Terminal
  3. Run hermes --tui
  4. Move mouse or scroll — observe 5;695;695;69 style text appearing
  5. Text accumulates until terminal is unusable

Fix

Add a truncated-fragment defense in packages/hermes-ink/src/ink/events/input-event.ts after the existing SGR guard:

// Suppress truncated SGR mouse parameter fragments (Windows / MSYS2).
// On MSYS2 (Git Bash), stdin is a pipe rather than a true PTY.  SGR mouse
// responses can be fragmented more aggressively.  When a fragment arrives as
// a bare text token like "5;695;695;69" (no ESC, no [<, no terminating M/m),
// the SGR_MOUSE_FRAGMENT_RE fails to match because it requires the [Mm] suffix.
if (!keypress.name && /^(?:\[?<?\d+(?:;\d+){1,3})/.test(input) && !/^[a-zA-Z]/.test(input)) {
  input = ''
}

The !(/^[a-zA-Z]/.test(input)) guard prevents false positives on normal text that happens to start with digits and semicolons.

After modifying the TypeScript source, rebuild: cd ui-tui && npm run build

Related Issues

  • #18658 — SGR mouse sequence leakage into composer under heavy render load (tmux)
  • #28419 — TUI input box flooded by ANSI escape sequences after gateway restart
  • #7316 — Bracketed-paste markers leak in Ghostty terminal

All share the same root pattern: terminal response sequences fragmented across stdin chunks bypass the existing defenses.


Issue 2: Log Rotation PermissionError on Windows

Root Cause

hermes_logging.py uses _ManagedRotatingFileHandler (extends RotatingFileHandler). The stdlib doRollover() calls os.rename() to rotate agent.logagent.log.1. On Windows, if any background thread (TTS, event publisher, etc.) holds an open file handle, os.rename() raises PermissionError [WinError 32].

The handler does not catch this, so the logging framework emits a full traceback to stderr on every rotation attempt. Since the agent logs on every conversation turn, this produces continuous noise.

Traceback (from user report)

PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。
  File ".../logging/handlers.py", line 115, in rotate
    os.rename(source, dest)

Fix

Override doRollover() in _ManagedRotatingFileHandler with Windows-aware retry logic:

def doRollover(self):
    import sys as _sys
    import time as _time

    if _sys.platform == "win32":
        for _attempt in range(5):
            try:
                super().doRollover()
                self._chmod_if_managed()
                return
            except PermissionError:
                if _attempt < 4:
                    _time.sleep(0.05)
        logging.getLogger(__name__).warning(
            "Log rotation failed for %s (file locked); log will continue to grow",
            self.baseFilename,
        )
    else:
        super().doRollover()
        self._chmod_if_managed()

5 retries (first 4 with 50ms delay, last without) handles transient handle contention. Final failure logs a WARNING instead of a noisy traceback — the log file simply grows past maxBytes until the next successful rotation.


Issue 3: Console Window Flash on Windows (PowerShell/tasklist/wmic)

Root Cause

Six subprocess.run() calls spawn console programs (PowerShell, tasklist.exe, wmic.exe) without creationflags=CREATE_NO_WINDOW (0x08000000). On Windows, this creates a visible console window that briefly flashes on screen before closing.

Affected Call Sites

FileFunctionProgramTrigger
hermes_cli/clipboard.py_run_powershell()powershellClipboard image paste (WinForms extraction)
hermes_cli/clipboard.py_find_powershell()powershellOne-time PowerShell availability probe
hermes_cli/claw.py_detect_openclaw_processes()tasklistGateway startup — OpenClaw process detection
hermes_cli/claw.py_detect_openclaw_processes()powershellNode.js-hosted OpenClaw process detection
hermes_cli/gateway.py_scan_gateway_pids()wmicProcess list scan (primary path)
hermes_cli/gateway.py_scan_gateway_pids()powershellProcess list scan (wmic unavailable fallback)

Fix

Add creationflags=0x08000000 to each subprocess.run() call on Windows. Other parts of the codebase (tools/environments/local.py, hermes_cli/gateway_windows.py, cron/scheduler.py) already use this flag correctly.


Files Affected

FileChange
ui-tui/packages/hermes-ink/src/ink/events/input-event.tsAdd truncated SGR fragment regex guard
hermes_logging.pyAdd Windows-aware doRollover() with retry + warning
hermes_cli/clipboard.pyAdd CREATE_NO_WINDOW to _run_powershell() and _find_powershell()
hermes_cli/claw.pyAdd CREATE_NO_WINDOW to tasklist and PowerShell calls
hermes_cli/gateway.pyAdd CREATE_NO_WINDOW to wmic and PowerShell fallback calls

Severity

  • Issue 1 (TUI leak): High — renders TUI unusable on Git Bash, the primary Windows terminal
  • Issue 2 (log rotation): Medium — noisy tracebacks on every rotation but does not lose data
  • Issue 3 (PowerShell flash): Low-Medium — does not break functionality, but is visually jarring and confusing to users

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix Bug: Windows compatibility issues — TUI mouse leak, log rotation PermissionError, console window flash