Skip to content

feat: Windows에서 ConPTY 기반 interactive trigger 지원 - #14

Closed
kjh0718 wants to merge 7 commits into
wavever:mainfrom
kjh0718:feat/windows-conpty
Closed

feat: Windows에서 ConPTY 기반 interactive trigger 지원#14
kjh0718 wants to merge 7 commits into
wavever:mainfrom
kjh0718:feat/windows-conpty

Conversation

@kjh0718

@kjh0718 kjh0718 commented Sep 8, 2026

Copy link
Copy Markdown

Summary

Windows에서도 Claude Code / Codex의 interactive trigger를 사용할 수 있도록

공통 terminal session abstraction과 native ConPTY backend를 추가합니다.

주요 변경:

  • Claude/Codex의 직접 PTY 의존을 internal/terminal.Session으로 통합

  • Unix/macOS는 기존 github.com/creack/pty backend 유지

  • Windows는 golang.org/x/sys/windows 기반 native ConPTY 사용

  • Job Object로 child/descendant process lifecycle 관리

  • .cmd / .bat CLI shim을 COMSPEC 경유로 안전하게 실행

  • Windows lifecycle / I/O / cancellation / cleanup 테스트 추가

  • Unix Session.Kill에서 이미 종료된 process를 성공으로 처리하도록 lifecycle contract 통일

  • README / README.zh-CN에 Windows 지원 범위와 설치 방법 반영

Windows에서 실제로 검증한 범위:

  • Claude Code interactive trigger — PASS

  • Codex interactive trigger — PASS

  • native ConPTY terminal — PASS

  • .cmd / .bat shim 실행 — PASS

  • child / descendant process cleanup — PASS

limitping continue는 Windows에서 아직 지원하지 않으며 이번 PR 범위에 포함하지 않습니다.

Checks

  • gofmt -l . prints nothing

  • go build ./...

  • go vet ./...

  • go test ./...

추가 검증:

  • WSL2 Ubuntu 20.04 / Go 1.27.0 clean clone에서 위 전체 Checks — PASS

  • go test -race ./internal/terminal/... -count=1 -timeout 180s on WSL2 — PASS

  • Windows go test ./internal/terminal/... -count=1 — PASS

  • Windows go test ./internal/provider/... -count=1 — PASS

  • Windows terminal race test — PASS (MSYS2 UCRT64 GCC)

  • Windows Claude Code interactive trigger manual E2E — PASS

  • Windows Codex interactive trigger manual E2E — PASS

  • 기존 Windows interactive failed to start: unsupported 문제 재현되지 않음

현재 upstream CI는 Ubuntu에서 실행되므로 Windows-specific path는 위 Windows 환경에서 별도로 검증했습니다.

Safety

  • I did not include credentials, raw usage responses, or private account metadata

  • I updated README/config examples for user-facing behavior changes

  • I considered whether this change can unexpectedly consume provider quota

자동 테스트에서는 실제 Claude/Codex 계정이나 provider quota를 사용하지 않습니다.

최종 Windows manual E2E에서만 Claude Code와 Codex interactive trigger를 각각 1회 실행했습니다.

Out of scope

이번 PR에는 다음 작업을 포함하지 않습니다.

  • Windows continue interactive proxy

  • Windows terminal resize

  • Windows self-upgrade 지원

  • Windows notification 지원

  • Spark의 Windows 실제 E2E 검증

  • Windows CI workflow 추가

  • 실제 provider 계정을 사용하는 automated E2E

Claude/Codex interactive trigger의 PTY 및 process lifecycle을
internal/terminal.Session으로 추상화한다.

- Unix/macOS는 기존 creack/pty 동작 유지
- Windows는 현재 unsupported stub 유지
- provider의 직접 PTY 의존 제거
- terminal abstraction 최소 테스트 추가

ConPTY backend와 Windows continue proxy는 후속 작업으로 분리한다.

Refs #1
CodeRabbit PR #2 리뷰를 반영해 Unix PTY 테스트의 cleanup을 정리한다.

- 같은 Session이 두 번 Close되지 않도록 guard 적용
- Close() error를 무시하지 않고 테스트 실패로 보고
- 조기 실패 경로는 t.Cleanup으로 안전하게 정리

production 코드 변경 없음.

Refs #1
Windows에서도 interactive provider trigger를 실행할 수 있도록
golang.org/x/sys/windows 기반 ConPTY backend를 구현한다.

- CreatePseudoConsole과 PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE로
  interactive child를 pseudoconsole에 연결
- CREATE_SUSPENDED → Job Object 할당 → ResumeThread 순서로
  descendant process의 job escape race 차단
- background 실행 환경에서도 child stdio가 ConPTY로 연결되도록
  STARTF_USESTDHANDLES와 NULL standard handles 적용
- raw ReadFile/WriteFile로 ConPTY I/O 처리
- child 종료 시 HPCON을 비동기로 닫아 blocked Read의 EOF 보장
- Job Object와 conhost bounded reap으로 process tree와 console host 정리
- Wait/Kill/Close/context cancellation lifecycle 동기화
- Windows lifecycle, stdin round-trip, process tree, conhost, Ctrl-C,
  반복/동시 session 테스트 추가

Refs #1
Windows에서 .cmd/.bat shim을 CreateProcess의 lpApplicationName으로
직접 실행하던 경로를 문서화된 COMSPEC 경유 방식으로 변경한다.

기존 방식은 일부 Windows 환경에서 동작하지만 cmd.exe의 추가 parsing을
고려하지 않아 공백이 있는 shim 경로가 실패하고, 특정 argument가 별도
명령으로 해석되는 command injection을 실제로 허용했다.

- .cmd/.bat을 case-insensitive하게 판별하고 COMSPEC /d /v:off /s /c로 실행
- COMSPEC이 없으면 System32의 cmd.exe 절대 경로 사용
- native executable은 기존 ComposeCommandLine 경로 유지
- batch argument를 cmd 규칙에 맞게 quote하고 metacharacter injection 차단
- literal %, NUL, 개행은 batch를 통해 안전하게 보존할 수 없어 명시적으로 거부
- /v:off로 delayed expansion을 강제 비활성화해 !VAR!을 literal로 유지
- 오류 메시지에 사용자 argument 값을 직접 노출하지 않고 위치만 표시
- .BAT casing, 공백 경로, 공백 argument, metacharacter, injection,
  COMSPEC fallback, percent 거부 및 delayed expansion 테스트 추가

ConPTY, Job Object, Wait/Kill/Close 및 pipe lifecycle은 변경하지 않는다.

Refs #1
@kjh0718 kjh0718 closed this Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant