Force UTF-8 on clicker output so Windows stops failing runs

A run died with "'charmap' codec can't encode character '▶'" at step 1.
Python picks the console code page for stdout, and under PM2 - where stdout is
a pipe rather than a console - that is cp1252 on Windows. cp1252 handles the em
dashes in these files but not the run markers, so the first one raised
UnicodeEncodeError from inside run_steps and the runner reported it as a step
failure rather than an output problem.

Reconfigure stdout and stderr to UTF-8 at the top of each entry point, with
errors="replace" as a backstop for streams that cannot be reconfigured. Fixing
the encoding once beats stripping the glyphs from ~30 call sites, and covers
manual runs in a plain console too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-08-30 18:28:39 -05:00
co-authored by Claude Opus 5
parent 724ba5581c
commit fbe2c47ed4
3 changed files with 22 additions and 1 deletions
+17
View File
@@ -31,6 +31,22 @@ import urllib.request
import actions
import focus
def force_utf8_output() -> None:
"""Make stdout/stderr accept the status glyphs this tool prints.
Windows picks the console code page for stdout, and under PM2 (where stdout
is a pipe, not a console) that is cp1252. It can encode em dashes but not
the run markers, so the first one raised UnicodeEncodeError mid-run and the
runner reported it as a step failure. errors="replace" is a backstop for any
stream that cannot be reconfigured at all.
"""
for stream in (sys.stdout, sys.stderr):
try:
stream.reconfigure(encoding="utf-8", errors="replace")
except (AttributeError, ValueError):
pass
DEFAULT_API = "http://localhost:3000"
POLL_INTERVAL = 0.25
@@ -176,6 +192,7 @@ def describe(found: dict, factor: float) -> str:
def main() -> int:
force_utf8_output()
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("action", choices=["locate", "click", "type"],
help="locate = measure only; click = measure then click; "