AI와 함께 기획부터 배포까지 — 윈도우 터미널 wTerm2 만들기

in #kr12 days ago

Gemini_Generated_Image_p05xu5p05xu5p05x.png

AI와 함께 기획부터 배포까지 — 윈도우 터미널 wTerm2 만들기

안녕하세요 가야태자 @talkit 입니다.

요즘 제가 클로드와 친하게 지내고 있습니다.

그런데, 이번에는 기획, 설계, 개발, 배포까지 클로드와 github를 통해서 모두 해본 프로젝트라는 의미가 있어서 기록으로 남기려고 합니다.

그리고, 보통 공공기관 프로젝트를 하기 때문에 깃허브로 출시까지 해본 것은 진짜로 이번이 처음 인 것 같습니다.

프라이빗 프로젝트에서 진행하고 있어서 바이너리를 공개 프로젝트에 공개할 계획입니다. 잠시 기다려 주십시오.

어제도 말씀 드렸지만, 이번 프로젝트의 이름은 윈도우즈 터미널 대체 도구 wTerm2 입니다.

제가 요즘 맥도 사용하는데 iTerm2라는 프로그램을 보고 이게 윈도우에도 있으면 좋겠다라는 생각으로, iTerm2에 없는 기능도 넣어 개발 하고 있습니다.


3일간의 숫자

먼저 결과부터 보여드리겠습니다.

항목
기간2026-08-06 ~ 08-08 (3일)
커밋81개
소스src/main.rs 8,874줄 (Rust)
문서11,024줄
테스트121개
GitHub 이슈8건
릴리스v0.2.0 ~ v0.6.0 (v0.6.1 준비 중)
연구노트25건

소스보다 문서가 많습니다. 이게 이 프로젝트의 성격을 그대로 보여줍니다. 뒤에서 왜 그렇게 됐는지 말씀드리겠습니다.


1. 기획 — 진짜 이유는 AWS SSM 이었습니다

처음엔 "iTerm2 같은 게 윈도우에도 있으면 좋겠다"로 시작했습니다. 그런데 만들다 보니 진짜 이유가 따로 있었습니다.

제가 AA로 일하면서 매일 AWS SSM 명령어를 칩니다.

aws ssm start-session --target i-0abc123... --profile prod --region ap-northeast-2

이걸 서버마다, 하루에 몇 번씩 칩니다. 인스턴스 ID는 외울 수도 없습니다.

그래서 클로드에게 물었더니 몇 가지 선택지를 주더군요. 저는 "버튼 하나 누르면 바로 접속", 터미우스(Termius)처럼 되는 걸 원했습니다. 그래서 프로필 시스템을 먼저 만들기로 정했습니다.

여기서 좋았던 건, 클로드가 제 요구를 그대로 코드로 옮기지 않고 "그러면 이런 문제가 생깁니다" 를 먼저 말해준 거였습니다.

예를 들어 비밀번호를 설정 파일에 저장해 달라고 했더니, 그렇게 하지 말고 Windows 자격 증명 관리자에 맡기자고 했습니다. 설정 파일은 실수로 깃허브에 올라가지만 자격 증명 관리자는 그럴 일이 없으니까요. 저도 동의해서 그렇게 갔습니다.

기능이 붙어간 순서

  • 화면 분할, 탭 (iTerm2 흉내)
  • 접속 프로필 (SSH · AWS SSM · 로컬 셸)
  • 프로필 복제 — 제가 AWS 인스턴스 7대를 쓰는데 1대만 등록해놓고 나머지를 안 만들고 있었습니다
  • 다중 접속과 동일 입력 전송 — was01, was02, was03에 cd /usr/local/tomcat 을 매번 세 번 치는 그 일
  • 즐겨찾기 (명령어 보관함)

마지막 두 개가 iTerm2에도 있긴 하지만, 제 작업 방식에 맞춰 다르게 만들었습니다. 그 얘기는 뒤에 하겠습니다.


2. 설계 — 순수 Rust, 그리고 "테스트할 수 있는 형태"

기술 선택은 단순했습니다.

언어Rust
GUIegui / eframe
터미널portable-pty (ConPTY) + vt100
설치WiX Toolset → MSI

타우리(Tauri)나 일렉트론은 아예 검토하지 않았습니다. 터미널은 자주 띄우는 프로그램인데 실행 파일이 100MB를 넘고 브라우저 엔진을 끌고 다니는 건 아니라고 봤습니다. wTerm2 실행 파일은 17MB입니다.

이번 프로젝트에서 제일 잘한 설계

만들다 보니 알게 된 게 있습니다. 판단 로직이 화면 그리는 코드 안에 있으면 절대 검증할 수 없습니다.

egui는 즉시 모드(immediate mode) GUI라 화면 그리는 함수가 매 프레임 다시 실행됩니다. 그 안에 "이 키를 어떻게 해석할까" 같은 판단이 섞여 있으면, 확인하려면 프로그램을 띄우고 직접 눌러보는 수밖에 없습니다.

그래서 판단을 전부 밖으로 빼냈습니다.

key_to_pty         키 → 터미널로 보낼 바이트열
shortcut_action    수정자 조합 → 앱 동작
should_send_text   이 글자를 서버로 보낼까
copy_event_outcome 복사인가 SIGINT인가
should_remove_pane 이 창을 닫을까

전부 입력을 넣으면 답이 나오는 순수 함수입니다. 테스트로 고정할 수 있습니다.

이 구조 덕분에 나중에 "우리 버그인가, 아닌가"를 몇 초 만에 가릴 수 있었습니다. 실제로 Ctrl+Shift+E가 안 된다는 제보를 받았을 때, 테스트가 통과하는 걸 확인하고 "다른 프로그램이 그 단축키를 선점한 겁니다" 라고 답할 수 있었습니다. 실제로 그랬고요.


3. 개발 — 제 컴퓨터에서 안 보이는 버그들

여기가 이 프로젝트의 핵심이자 가장 재미있었던 부분입니다.

개발은 맥에서, 대상은 윈도우입니다. 이 간극에서 나온 버그가 절반이 넘습니다.

화면 분할이 절반 확률로 실패했습니다

분할 기능을 만들었는데 제보가 왔습니다. "새 탭은 되는데 상하분할 좌우분할은 안 되네."

원인은 트리 구조를 다루는 코드였습니다. 부모를 찾는 함수가 HashMap을 순회하는데, 그 사이에 새 컨테이너를 만들어버려서 방금 만든 그 컨테이너를 부모로 돌려주는 일이 생겼습니다.

클로드가 확인용 코드를 짜서 200번 돌려봤더니 97번 실패했습니다. 정확히 절반이었죠. 컨테이너를 만들기 전에 부모를 잡아두는 것으로 고쳤고, 50번 반복하는 테스트를 붙였습니다.

같은 함정을 네 번 밟았습니다

egui에는 함정이 하나 있습니다. 나중에 그린 위젯이 앞의 위젯을 가리면, 앞 위젯의 클릭됨·마우스 올림 판정이 조용히 거짓이 됩니다.

  • 휠 스크롤이 글자 위에서만 안 됨
  • 클릭해도 포커스가 안 옮겨짐
  • 우클릭 메뉴가 절반 영역에서 안 열림

전부 같은 원인입니다. 세 번째까지는 당하고 나서야 알았는데, 네 번째는 미리 확인했습니다. 클로드가 코드를 짜기 전에 실험부터 했거든요.

본문 위     pane=false  label=true
아래 빈 곳   pane=true   label=false

상보적이었습니다. 그래서 두 곳 모두에 메뉴를 붙였습니다. 한쪽만 붙였으면 절반에서 조용히 안 됐을 겁니다.

Ctrl+R이 프로젝트 내내 죽어 있었습니다

이건 좀 창피한데, 그래서 더 기록할 값어치가 있습니다.

키를 터미널로 보내는 표에 딱 세 줄만 있었습니다.

Key::C if ctrl_only => Send("\x03"),   // SIGINT
Key::D if ctrl_only => Send("\x04"),   // EOF
Key::L if ctrl_only => Send("\x0C"),   // 화면 지우기

그래서 Ctrl+R(히스토리 검색), Ctrl+A/Ctrl+E(줄 처음·끝), Ctrl+U/Ctrl+W(지우기), Ctrl+Z(중단)가 전부 안 됐습니다. 쉘의 줄 편집이 통째로 죽어 있었던 겁니다.

더 재미있는 건 아무도 제보하지 않았다는 겁니다. 눌러도 화면이 그대로니까요. "안 되네" 하고 를 여러 번 누르고 넘어갔던 거죠.

이건 제보가 아니라 클로드가 릴리스 노트의 "알려진 제약"을 쓰다가 발견했습니다. 사용자에게 "이건 안 됩니다"라고 문장으로 쓰려니 이상했던 거죠.

고친 방법은 표를 늘리는 게 아니라 계산으로 바꾸는 것이었습니다. ASCII에서 제어 코드는 글자 & 0x1f 입니다. 그러면 빠뜨릴 수가 없습니다.

저는 그때 "Ctrl + R은 뭐였지 ㅋㅋㅋ" 라고 물어봤습니다. 저도 몰랐던 기능이었어요.

창이 깜빡이며 수십 개 켜지던 문제

이건 증거가 없는 제보였습니다. 제가 이렇게 썼거든요.

창이 깜빡에 많이 켜지는 경우가 있어 이걸 캡처하지는 못했는데 창이 너무 많이 켜져서 캡쳐도구도 튕겨내가지고

클로드가 재현하지 못하는 상황에서 증상이 무엇을 함의하는지로 좁혀 들어갔습니다. "OS 창이 반복 생성된다" → 이 앱에서 창을 만드는 건 셋뿐 → 자식 프로세스의 콘솔 창.

찾아보니 키 파일 권한을 표시하는 코드가 화면을 다시 그릴 때마다 icacls 를 실행하고 있었습니다. 프레임마다 프로세스가 하나씩 뜬 거죠.

캐시를 무력화해서 크기를 재봤더니 이렇게 나왔습니다.

assertion failed: 프레임마다 검사하면 Windows 에서 앱이 멈춘다
  left: 100
 right: 1

100프레임에 프로세스 100개. 이게 버그의 크기였습니다.

진단이 반대였던 적도 있습니다

클로드가 하루 전에 문서에 이렇게 써놨습니다.

Ctrl+C 문제는 관례가 아니라 기능 오류입니다. macOS에서 SIGINT 대신 복사로 동작합니다.

그런데 실제로 깨져 있던 쪽은 윈도우였습니다. GUI 라이브러리가 Ctrl+C를 복사 이벤트로 삼켜서 키 이벤트를 아예 만들지 않았고, 윈도우에서는 그게 SIGINT 경로를 막고 있었습니다. 맥은 멀쩡했고요.

클로드가 이걸 발견하고 남긴 교훈이 좋았습니다.

내가 쓴 문서를 근거로 삼지 않는다. 내 추론이 문서가 되고, 문서가 다시 근거가 되면 검증 없이 굳는다.


4. 배포와 테스트 — 깃허브 이슈로 주고받기

이 부분이 이번 프로젝트에서 제일 특이했습니다.

클로드는 맥에서 코드를 짜고, 저는 윈도우에서 테스트합니다. 그 사이를 깃허브가 이어줬습니다.

클로드: 코드 수정 → 커밋 → 푸시
   나: git pull → 빌드 → 실행 → 스크린샷 → 이슈에 등록
클로드: 이슈 읽고 → 원인 분석 → 다시 수정

이슈 8건이 전부 이 왕복이었습니다. 스크린샷을 올리면 클로드가 그걸 보고 분석합니다. 한번은 제가 붙여넣은 터미널 출력을 클로드가 글자 수까지 세어서 원인을 짚어냈습니다.

붙여주신 내용을 재보니 110자로 패딩된 줄이 41개 있습니다. 줄 끝 공백 트리밍은 ba309cd에서 들어갔고 이슈 #7에서 없어진 것을 확인하셨습니다. 다시 나온다는 건 그 수정이 없는 빌드에서 복사했다는 뜻입니다.

정확했습니다. 제가 옛날 창에서 복사한 거였어요.

MSI 만들고 릴리스 올리기

깃허브 액션즈는 안 썼습니다. 나중에 젠킨스를 쓸 계획이라 로컬 수동 경로만 만들었습니다.

cargo wix --nocapture
gh release create "v$v" "target\wix\wTerm2-$v-x86_64.msi" --notes-file "docs/release_notes/v$v.md"

gh CLI 하나로 릴리스까지 올라갑니다. 코드 서명은 안 했습니다. 개인 프로젝트에 인증서 값을 쓸 단계는 아니라서요. 대신 SmartScreen 경고가 왜 뜨는지 릴리스 노트에 적어뒀습니다.

릴리스 한 번은 조용히 실패했습니다

cargo wix오류 없이 성공했는데 MSI가 없었습니다.

원인은 git pull 을 안 한 것이었습니다. 버전 올림 커밋을 못 받아서, 제가 $v = "0.6.0" 이라고 정해놓고 실제로는 v0.5.0을 빌드하고 있었던 거죠. cargo wix 는 제 의도를 모르니 오류를 낼 이유가 없었고요.

클로드가 릴리스 가이드에 버전 대조 세 줄을 넣었습니다.

$actual = (Select-String -Path Cargo.toml -Pattern '^version = "(.+)"').Matches[0].Groups[1].Value
if ($actual -ne $v) { throw "Cargo.toml 은 $actual 인데 목표는 $v 입니다" }

교훈은 이거였습니다. 도구의 입력과 사람의 의도가 다른 곳에 있으면, 언젠가 반드시 어긋납니다.

라이선스를 어기고 있었습니다

"어바웃 화면 만들어줘" 라고 부탁했더니, 클로드가 무엇을 적을지 확인하다가 문제를 하나 찾았습니다.

한글 표시를 위해 D2Coding 글꼴을 실행 파일에 심어서 배포하고 있는데, 라이선스 파일을 같이 넣지 않고 있었습니다.

D2Coding은 SIL Open Font License 1.1인데, 이 라이선스는 "라이선스를 함께 배포하는 조건"으로 재배포를 허용합니다. 즉 v0.2.0부터 v0.6.0까지 전부 조건을 어긴 상태였습니다.

클로드가 기억으로 라이선스 전문을 쓰지 않고 네이버 저장소에서 원본을 받아 넣었습니다. 그리고 의존성 447개의 라이선스 목록을 자동 생성하는 스크립트도 만들었습니다.

include_bytes! 는 코드에서 한 줄입니다. 그 한 줄이 4MB짜리 남의 저작물을 배포본에 넣는 행위라는 사실이 코드 모양에 전혀 드러나지 않습니다.

이거 하나만으로도 이번 작업이 값어치가 있었다고 생각합니다.


5. 유지보수 — 연구노트 25건

이번 프로젝트에서 가장 마음에 드는 부분입니다.

버그를 고칠 때마다 연구노트를 씁니다. 증상 → 조사 → 원인 → 조치 → 교훈 순서로요. 틀린 진단도 지우지 않고 남깁니다.

지금 25건입니다. 몇 개만 제목을 보여드리면 이렇습니다.

#제목
01화면 분할이 절반 확률로 실패
02같은 레이어링 함정을 세 번 밟다
14물려받은 환경 변수가 비밀번호를 가로챘다
18UI 그리는 코드에 프로세스 실행을 넣었다
20내가 쓴 진단이 반대였다
21손으로 적은 표는 빠뜨린다
22통과하는데 아무것도 지키지 않던 테스트
24절반만 고치고 다 고쳤다고 했다
25자기 자신으로 자기 자신을 테스트할 때

22번이 특히 재미있었습니다

도움말 기능을 만들면서, 도움말에 적힌 단축키가 실제 동작과 어긋나지 않도록 테스트를 붙였습니다. 100개 테스트가 통과했죠.

그런데 클로드가 테스트가 진짜로 잡는지 확인하려고 일부러 도움말을 틀리게 바꿔봤습니다.

-  ("Ctrl+Shift+D", "좌우로 분할"),
+  ("Ctrl+Alt+D", "좌우로 분할"),
test result: ok. 100 passed; 0 failed

통과했습니다. 검사가 "이 이름이 어딘가에 있는가"였는데, 지켜야 할 건 "적힌 것이 전부 실제로 되는가"였던 거죠. 방향이 반대였습니다.

통과한 테스트를 믿기 전에 깨뜨려 본다. 작성한 직후가 가장 위험하다. 방금 고친 코드로 돌리면 당연히 통과하고, 그게 "테스트가 작동한다"는 증거처럼 느껴진다. 한 번 깨뜨리는 데 1분이 든다.

25번 — 자기 자신으로 자기 자신을 테스트하기

wTerm2가 쓸 만해지니까 제가 wTerm2 안에서 wTerm2를 개발하기 시작했습니다. 그러자 하루에 세 건이 터졌습니다.

증상실제 원인
창이 안 뜨고 종료 코드 1우리가 심은 환경 변수를 자식이 물려받았다
고쳤는데 그대로옛 창에서 복사했다
다시 빌드가 안 됨실행 중인 exe를 덮어쓸 수 없다

셋 다 원인이 다른데 증상은 "안 되네"로 똑같습니다. 첫 번째는 어떤 단위 테스트로도 잡을 수 없었습니다. 프로세스 두 개가 있어야 드러나고, 그중 하나가 우리 자신이어야 그 증상이 되니까요.

두 번째 때문에 클로드가 정보 화면에 실행 파일 경로를 표시하게 했습니다.

버전       0.6.1
실행 파일   C:\dev\wTerm2\target\release\wTerm2.exe

개발 중에는 설치본과 방금 빌드한 게 같은 버전을 달고 동시에 떠 있어서, 버전만으로는 구별이 안 되거든요. 한 줄로 이 혼선이 끝났습니다.


클로드와 일해보니

좋았던 것

추측하지 않고 실험합니다. 우클릭 메뉴를 붙이기 전에 클릭이 어디로 가는지 재현해봤고, 테스트를 쓰고 나면 일부러 깨뜨려봤습니다. "아마 될 겁니다"가 아니라 숫자를 보여줍니다.

모르는 걸 모른다고 합니다. "macOS에서 테스트는 통과했지만 윈도우 실기 확인이 필요합니다"를 매번 명시했고, 그 목록이 그대로 제 확인 체크리스트가 됐습니다.

요청을 그대로 만들지 않을 때가 있습니다. 비밀번호를 파일에 저장해달라고 했을 때가 그랬습니다. 이유를 설명하고 대안을 냈고, 제가 납득해서 그쪽으로 갔습니다.

제가 배운 것

기록을 남기는 게 이렇게 큰 차이를 만드는지 몰랐습니다. 소스 8,874줄에 문서 11,024줄 인데, 그 문서 덕분에 사흘 전에 왜 그렇게 정했는지를 지금도 알 수 있습니다.

그리고 이런 것도 알게 됐습니다. 아무 일도 안 일어나는 버그는 제보되지 않습니다. Ctrl+R도, Ctrl+C도, 글꼴 라이선스도 전부 배포된 뒤에 발견됐습니다. 셋 다 눌러도 화면이 그대로였거든요.


지금 상태와 다음

v0.6.1 배포를 준비하고 있습니다. 지금까지 들어간 기능은 이렇습니다.

  • 탭 · 화면 분할 · 스크롤백
  • 접속 프로필 (SSH · AWS SSM · 로컬 셸), 복제, 색상 구분
  • 다중 접속 · 동일 입력 전송 (여러 서버에 같은 명령)
  • 드래그하면 바로 복사 (PuTTY 방식), 우클릭 메뉴, 가운데 클릭 붙여넣기
  • 즐겨찾기 — 자주 쓰는 명령을 담아두고 클릭
  • 한글 입력(IME), F1 도움말, 비밀번호 보관(자격 증명 관리자)

남은 건 화면 정리 하나입니다. 상단 크롬이 세 겹이라 터미널이 좁아 보이거든요. 클로드가 시안까지 만들어놨습니다.

맥 버전도 사실 이미 동작합니다. 개발을 맥에서 해왔으니까요. 다만 .app/.dmg 패키징과 코드 서명이 남아서 "추후 출시 가능"으로만 문서화해뒀습니다.

바이너리는 베타 시절 까지는 비공개 저장소에 올릴 계획입니다.

출시하게 되면 공개 저장소로 옮길 계획 입니다.

준비되면 다시 글 올리겠습니다.

읽어주셔서 감사합니다.


이 글에 나온 숫자와 사례는 전부 실제 저장소의 커밋·이슈·연구노트에서 가져온 것입니다.

Sort:  

와... 기록으로 남겨놓는 일이...
저도 중요하다는 건 알지만,
번거로워서 잘 남겨놓기 힘들던데... ㅎ

이렇게 꼼꼼하게 문서 정리를 해놓으시다니...
정말 대단하십니다~! 👍👍👍

[booming-kr-auto]
보팅 완료했습니다 🙌

  • 여러분이 작성한 댓글: @talkit/ai-wterm2--uv94gy
  • 여러분이 보팅한 수치: 30.00% / rshares=186,709,069,736
  • @support-kr이 여러분의 댓글에 드리는 보팅: 총 447,854.72SP 중 11.03%
    IMG_9947.jpeg
  • 여러분의 임대와 보팅이 kr 커뮤니티를 활성화 하는데 큰 힘이 됩니다

음 에이아이를 이용하면서 저는 일단 문자 중독이고 ^^
에이아이가 코딩하는 부분은 어쩔 수 없이 모르더라도
트러벌 슈팅 하는 부분은 알고자 연구노트와 기술 노트라는 것을 작성하라고 지시를 했고
클로드가 잘 작성해 주고 있습니다.
베타 참여 공지 올렸으니 참여해주세요 ^^