diff --git a/scripts/execute.py b/scripts/execute.py index 953a7a6..e5219c2 100644 --- a/scripts/execute.py +++ b/scripts/execute.py @@ -26,6 +26,14 @@ class CodexEnvironmentError(RuntimeError): """재시도로 해결할 수 없는 Codex CLI 환경 오류.""" +def _configure_utf8_stdio(): + """Windows 콘솔에서도 Harness 진행 문자를 안정적으로 출력한다.""" + for stream in (sys.stdout, sys.stderr): + reconfigure = getattr(stream, "reconfigure", None) + if reconfigure is not None: + reconfigure(encoding="utf-8") + + @contextlib.contextmanager def progress_indicator(label: str): """터미널 진행 표시기. with 문으로 사용하며 .elapsed 로 경과 시간을 읽는다.""" @@ -468,6 +476,7 @@ class StepExecutor: def main(): + _configure_utf8_stdio() parser = argparse.ArgumentParser(description="Harness Step Executor") parser.add_argument("phase_dir", help="Phase directory name (e.g. 0-mvp)") parser.add_argument("--push", action="store_true", help="Push branch after completion") diff --git a/tests/test_execute.py b/tests/test_execute.py index de9d7c1..108354b 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -59,3 +59,22 @@ def test_feature_commit_message_is_windows_console_safe(): ) message.encode("cp949") + + +def test_configure_utf8_stdio_reconfigures_both_streams(monkeypatch): + class ReconfigurableStream: + def __init__(self): + self.encodings = [] + + def reconfigure(self, *, encoding): + self.encodings.append(encoding) + + stdout = ReconfigurableStream() + stderr = ReconfigurableStream() + monkeypatch.setattr(execute.sys, "stdout", stdout) + monkeypatch.setattr(execute.sys, "stderr", stderr) + + execute._configure_utf8_stdio() + + assert stdout.encodings == ["utf-8"] + assert stderr.encodings == ["utf-8"]