Changelog
사용자에게 보이는 변경을 판마다 적어요. 형식은 Keep a Changelog, 판 번호는 유의적 버전을 따르고, 무엇이 깨는 변경인지는 버전 정책에 있어요. 릴리스 파일은 GitHub Releases에 있어요.
Unreleased
0.1.5 - 2026-10-21 최신
Fixed
zeropty-tty로 띄운 job control 셸(zsh,bash -i)에서 작업에 친C-c,C-\,C-z가 작업이 아니라 셸로 갔어요. 그래서sleep 30을 멈출 수 없었어요. 작업은 자기 프로세스 그룹을 이끄는데, 셸의tcsetpgrp를 shim이 삼켰기 때문이에요. 이제 shim이 이를 알리고, zeropty는 tty가 포그라운드 그룹에 하듯 그 그룹에 시그널을 보내요. 그래서 파이프라인을 포함해C-z와fg도 돼요. 세션 프로그램 아래에 멤버가 있는 프로세스 그룹만 받아들여요. 업그레이드 전에 띄운 셸은 예전 shim을 그대로 쓰니 다시 띄워야 해요.
0.1.4 - 2026-10-21
Fixed
zeropty-tty:ssh,ssh-keygen,ssh-add등readpassphrase나getpass를 쓰는 프로그램에 친 암호가 세션 화면에 보였고, 그래서capture-pane결과와 스크롤백에도 남았어요. libc가 거기서 에코를 자기 내부 호출로 끄는데 shim이 그 호출에 닿지 못했기 때문이에요. 이제 세션 터미널에서는 shim이 이 두 함수를 직접 처리해요.zeropty-tty ssh-keygen처럼 shim이 들어간 프로그램에 해당하고, 세션 안 셸에서 친/usr/bin프로그램은 여전히 shim 없이 돌아요. 세션 밖에서는 바뀐 게 없어요.
0.1.3 - 2026-10-21
Added
- 이제 릴리스마다 미리 빌드한 macOS 묶음
zeropty-<버전>-darwin-universal.tar.gz(Apple silicon·Intel, macOS 11 이상)와SHA256SUMS가 붙어서, Rust 없이 설치할 수 있어요. 받고,shasum -a 256 -c SHA256SUMS로 확인하고, 풀어서 그 폴더에서 실행하면 돼요.zeropty,shim.dylib,zeropty-tty,claude-zeropty와 라이선스가 들어 있고 ad-hoc 서명돼 있어요. 임베딩 라이브러리와 bash builtin은 여전히./build.sh로 만들어요(README).
0.1.2 - 2026-10-20
Fixed
zeropty-tty:/dev/tty를 읽기+쓰기로 연 프로그램(stdin을 파이프로 받은fzf)은 키는 읽어도 쓰기가 모두EBADF로 실패해서, fzf가 목록을 그리지 못하고 선택도 받지 못했어요. 이제 세션의 터미널은 PTY가 파일 하나인 것처럼 소켓 하나예요. stdin, stdout, stderr가 모두 그 소켓이고(stdin은 파이프였어요), 어느 모드로 연/dev/tty도 그 소켓이에요.C-d는 여전히 입력을 아주 끝내고, 그 뒤에도 출력은 계속 나와요. PTY처럼 stdin, stdout, stderr 중 하나에 건O_NONBLOCK은 이제 셋 모두에 걸려요. 예전 서버가 시작해서restart-server로 이어진 세션은 입력 파이프를 그대로 써요. 이 버전이 시작한 세션을 0.1.1 이하로 되돌려 넘기지는 마세요(C-d가 닿지 않아요).
0.1.1 - 2026-10-20
Fixed
zeropty-tty: shim이 어느 프로그램이든 fd 0-2를 터미널로 쳐서, stdout을 파이프나 파일로 돌린 프로그램의 출력에\e]zeropty-tty;N\a모드 신호가 섞이고, stdin이/dev/null인 프로그램이 실패하고(kqueueEINVAL), 자식 프로세스도 같은 영향을 받았어요. 이제 서버가 새ZEROPTY_TTY_ID변수로 알려 주는 세션 자신의 파이프와 소켓만 터미널로 치고, 모드 신호는 세션 출력으로만 보내요.zeropty-tty: 서명한 사본이 링크 대상의 이름을 써서(claude가claude.exe로 실행됨)ps,pgrep claude로 찾을 수 없었어요. 이제 사본이든 아니든 프로그램은 실행할 때 쓴 이름으로 돌아요.display-message의-t가 없는 세션을 가리키면 이제 tmux처럼 세션 변수를 비운 포맷을 출력하고 종료 코드 0이에요(전에는 종료 코드 1로 실패). 세션이 있는지 확인하려면has-session을 쓰세요. 다른 명령은 tmux처럼 여전히 종료 코드 1로 실패해요.- 없는
-t대상에 대한 오류 문구를 tmux와 같게 맞췄어요.:가 없을 때 이름만 쓰면can't find pane: x(capture-pane,send-keys,pipe-pane,paste-buffer,resize-pane)나can't find window: x(resize-window), id는$·@·%에 따라 세션·창·pane 오류,x.0은can't find window: x예요.set-environment는no such session:과 받은 대상 그대로예요. 종료 코드는 그대로(1)예요.
0.1.0 - 2026-10-20
첫 공개 버전이에요. 터미널 프로그램을 많이 다루는 프로그램(코딩 에이전트, 스크립트, 테스트 하네스)을 위한 세션 엔진으로, tmux의 명령 형식을 PTY 없이 받아요. macOS 전용이에요. 첫 공개 커밋 c612089에 v0.1.0 태그를 달았어요.
알려진 한계: macOS만 돼요(kqueue, DYLD shim). 세션 하나에 프로그램 하나라서 창·패널·상태 줄·복사 모드·키 바인딩·설정 파일이 없어요. wait-pane은 임베디드 함수 호출로는 못 쓰고 소켓으로만 돼요(임베디드 listen 포함). SIP로 보호되거나 hardened runtime으로 서명된 프로그램은 shim을 못 읽어서 zeropty-tty가 다시 서명한 복사본을 실행하고, setuid·entitlement 프로그램(top, ps)은 안 돼요. C-d의 파일 끝은 세션 입력을 닫아요(파이프에는 한 번짜리 EOF가 없어요). 1.0 전에는 MINOR 릴리스가 docs/VERSIONING.md의 인터페이스를 깰 수 있어요.
Added
- 서버와 CLI(
zeropty), tmux와 같은 인자:new-session,has-session,kill-session,list-sessions,kill-server,send-keys(키 이름을 tmux 3과 바이트 단위로 대조),capture-pane(-p -e -J -N -S -E -b -q),load-buffer,paste-buffer,display-message,pipe-pane,rename-session,resize-window/resize-pane,set-environment -g/show-environment -g,attach-session(-r읽기 전용),-V, tmux 포맷 변수 25개. 모르는 플래그는 오류예요. 첫new-session이 서버를 띄워요. - tmux에 없는 명령:
wait-pane(폴링 없이 글자나 조용해짐을 기다림),grep-panes(모든 세션 화면 검색),pull-sessions/push-sessions(프로그램을 건드리지 않고 실행 중인 세션을 다른 프로세스로 옮김),restart-server(세션을 끝내지 않고 서버 업그레이드). - PTY 없음: 세션의 프로그램은 파이프와 이야기하고, 줄 규칙(Enter,
C-c시그널, 줄 편집, 에코,C-d)은 엔진이 흉내 내요. 터미널이 필요한 프로그램(claude, vim, less, python)에는shim.dylib과claude-zeropty,zeropty-tty가isatty,tcgetattr, 창 크기,/dev/tty에 답해요. - 화면 에뮬레이터: 칸당 6바이트이고, 녹화한 claude 세션과 무작위 입력으로
vt100크레이트(0.16)와 대조해요. 조용한 화면은 접어 두었다가 나중에 zstd로 압축해요. - 소켓 프로토콜:
~/.zeropty/mux.sock(ZEROPTY_SOCK)에서 요청과 응답 한 줄씩 JSON, 선택할 수 있는 raw 응답 형식, attach 프레임. - 임베드: C ABI(
libzeropty_c.dylib,zeropty.h:zeropty_open,zeropty_command,zeropty_listen, polled용zeropty_open_polled/zeropty_fd/zeropty_timeout_ms/zeropty_process)와 Node 모듈(zeropty.node,client/embedded.mjs)로 엔진을 프로세스 안에서 돌려요.listen은 같은 소켓 프로토콜을 호스트 프로세스에서 제공해요. - 클라이언트:
client/zeropty.mjs(Node, 연결 하나를 유지), 프로세스를 띄우지 않고 소켓과 이야기하는 zsh 함수 (shell/zeropty.zsh)와 bash builtin(shell/zeropty_bash.c). - 환경변수
ZEROPTY_SOCK,ZEROPTY_HISTORY,ZEROPTY_COALESCE_MS,ZEROPTY_FREEZE_MS,ZEROPTY_COLD,ZEROPTY_COLD_DIR,ZEROPTY_RECORD(docs/USAGE.md). - tmux 3.7c와 Mac mini M1 한 대에서 번갈아 잰 벤치마크(docs/BENCHMARKS.md): 잰 14개 항목 중 11개가 10배 이상이고, 3개는 아직이에요(독립 서버의 대기 400개 메모리 6.2배, tmux 제어 모드 대비
send-keys임베디드 8~10배·소켓 2.2~2.8배). 이유는 그 문서에 적었어요. - 플러그인 시스템(플러그인 API): 세션 생성·종료·이름 변경·출력 이벤트를 받고 새 명령을 더해요. Rust
Plugin트레이트(API_VERSION1), 소켓의plugin-attach(언어 무관, 프로세스 밖), C 콜백zeropty_add_plugin, dylib 플러그인zeropty plugin-run/zeropty_load_plugin, 옵트인 자동 시작 디렉터리ZEROPTY_PLUGIN_DIR, 상태 확인list-plugins. 플러그인이 없으면 비용이 없고, 패닉·멈춤·느린 플러그인은 엔진을 붙잡지 못해요. - 기다리지 않는 명령 호출: C
zeropty_command_start·zeropty_call_poll·zeropty_call_due_ms·zeropty_call_free, NodeEngine.commandStart. zeropty --version:zeropty -V와 같은 출력(zeropty 0.1.0)이에요. zsh 함수, bash builtin,client/zeropty.mjs도-V처럼 프로그램을 실행해 답해요.- 포맷 변수
#{version}: 실행 중인 서버(또는 임베디드 엔진)의 버전이에요. 이 변수만 쓰는display-message -p는 세션이 없어도 돼요(zeropty display -p '#{version}'). - C ABI:
zeropty.h에ZEROPTY_VERSION_MAJOR·_MINOR·_PATCH·_PRERELEASE·_IS_PRERELEASE·_STRING·_NUMBER, 링크된 라이브러리의 버전을 돌려주는zeropty_version().ZEROPTY_VERSION_NUMBER는 프리릴리스를 담지 않아서0.2.0-rc.1과0.2.0이 같은 값이에요. 둘은ZEROPTY_VERSION_IS_PRERELEASE로 구별해요. - Node:
zeropty.node와client/embedded.mjs의version(),client/zeropty.mjs와client/embedded.mjs의VERSION. - 버전 정책
docs/VERSIONING.md: 깨는 변경으로 보는 호환 범위(CLI의 인자·출력·종료 코드, 소켓 프로토콜, 세션 레코드, C ABI, Node API, 환경변수,dist/이름)와 MSRV(Rust 1.88). 1.0 전에는 MINOR 릴리스가 이 범위를 깰 수 있고, 그때는**BREAKING**항목으로 알려요. zeropty --help(-h,help): 명령과 옵션 목록을,zeropty help <명령>은 그 명령의 사용법과 문서 링크를 출력해요. 서버 없이 답해요.- 문서: 한국어 README 개편, 문서 목록(
docs/README.md), FAQ, 실행되는 예제(examples/), 모든 공개 Rust 항목의 rustdoc과 예제.
Fixed
- 출력을 읽는 쪽이 파이프를 일찍 닫아도(
zeropty capture-pane -p ... | head -1) CLI가 패닉하지 않아요.