개발 블로그로 돌아가기 엔지니어링 업데이트

2026년 7월 개발 업데이트: 더 안정적인 Desk, 더 똑똑해질 키보드

이번 달은 세 가지입니다. 오늘 바로 내려받을 수 있는 SharkTTY Desk 수정 빌드, iPhone·iPad 앱 개발 진행 상황의 솔직한 보고(진행 중 — 아직 아무것도 출시되지 않았습니다), 그리고 실험적인 터미널 전송 방식의 상태 리포트. 여기는 엔지니어링 관점의 기록이고, 간결한 사용자용 노트는 새로운 기능에 있습니다.

SharkTTY Desk 0.8.0 — 7월 10일 빌드(지금 사용 가능)

지난주 0.8.0 릴리스의 후속 빌드로, 버전 번호는 그대로 0.8.0입니다. 여기서 내려받으세요.

「공유 중단」 버그

이 버그는 우리가 일상적으로 쓰다가 직접 밟았습니다. 화면이 보여지고 있는 동안 macOS는 메뉴 막대에 자체 표시기를 띄우고, 거기에 자체 「공유 중단」 버튼이 있습니다. SharkTTY 안이 아니라 거기서 세션을 끝내면 Desk가 먹통이 될 수 있었습니다. QR 코드는 사라지고, 서비스는 시작 중이라고 우기고, 재연결은 전부 실패 — 앱을 종료하고 다시 켤 때까지요. 원격 제어 스위치를 껐다 켜도 소용없었습니다. 최악의 부류의 고장입니다. 신고할 수 있는 크래시가 아니라, 조용히 서비스이기를 그만둔 서비스.

실제로 벌어진 일은 이렇습니다. 세션이 끝나면 에이전트는 다음 연결을 위해 네트워크 리스너를 다시 만들고, 그 재구축에는 같은 로컬 포트가 필요합니다. 그런데 옛 리스너의 포트 해제는 내부 정리의 부수 효과일 뿐이었고, 그 시점은 세션이 어떻게 끝났는지에 달려 있었습니다 — 이 특정 경로에서는 정리가 재구축보다 한참 늦거나 아예 끝나지 않을 수 있었죠. 재구축은 바인드를 시도하고, 포트가 아직 점유된 걸 보고, 결과적으로 정리보다 짧았던 재시도 창 안에서 포기한 뒤, 에이전트를 리스너 없는 상태로 남겨 둡니다. 밖에서 보면: 영원한 「시작 중」.

수정은 이 인수인계를 우연에서 계약으로 바꿉니다. 이제 종료는 포트를 명시적으로 해제하고, 해제가 확인된 뒤에야 재구축이 진행됩니다. 리바인드 자체도 더 참을성 있게 바뀌었고 시도마다 로그를 남겨서, 앞으로의 리포트는 콘솔에서 바로 진단할 수 있습니다. 우리가 가져가는 교훈: teardown은 startup과 같은 결정성을 누릴 자격이 있다. 「포트는 언젠가 알아서 풀린다」는 계약이 아닙니다.

연결 키 표시

Mac의 연결 키 표시에 관한 작은 수정 세 가지 — 전부 표시만의 문제이고, 키가 생성되거나 보호되는 방식은 전혀 바뀌지 않습니다. 숨긴 키는 이제 글자 수만큼 점을 찍는 대신 고정 길이 자리 표시자를 보여 줘서, 가려진 상태가 키의 길이를 흘리지 않습니다. 아주 긴 사용자 지정 키는 카드를 넘치는 대신 한 줄에 맞게 줄어듭니다(범인은 글꼴과 함께 줄어들지 않던 자간이었습니다). 그리고 Desk는 키를 숨기기로 한 선택을 재시동 후에도 기억합니다 — 숨기기가 매일 아침 반복하는 잡일이어서는 안 되니까요. 표시에는 여전히 Touch ID나 암호가 필요합니다. 이전과 같습니다.

호환성은 그대로입니다. 이 빌드는 iPhone·iPad의 SharkTTY 1.6 이상과 함께 동작합니다. 앱이 더 오래되었다면 SharkTTY Desk 0.5.0 빌드를 계속 쓸 수 있습니다.

SharkTTY for iPhone & iPad — 개발 중

먼저 분명히 해 둡니다. 이 섹션의 내용은 아직 아무것도 출시되지 않았습니다. 개발 빌드에서 이미 동작하고 있고 다음 App Store 업데이트를 향해 가는 것들입니다 — 출시까지 침묵하는 것보다 어디까지 왔는지 말씀드리는 쪽을 택했습니다.

플로팅 키보드, 2막

플로팅 키보드가 2막을 엽니다. 배열이 하나에서 여섯으로 — US, UK ISO, 일본어 JIS, 프랑스어 AZERTY, 독일어 QWERTZ, 스페인어 ISO — 그것도 키캡만 바꿔 붙인 게 아닌 진짜 배열입니다. 유럽 배열은 제대로 된 AltGr 3단( | { } [ ] \를 못 치는 터미널은 터미널이 아닙니다)을 갖추고, ISO 배열엔 왼쪽 Shift 옆 추가 키가 생기며, fn→F1–F12 줄은 배열마다 물리적 위치로 매핑됩니다. 모든 배열을 순회하며 터미널 필수 문자가 전부 입력 가능한지 증명하는 테스트도 썼습니다 — 개발 중에 실제로 빠진 키 두 개를 잡아냈는데, 테스트란 바로 이런 일로 낯 뜨겁게 만들어 줘야 하는 물건입니다. 플로팅 키보드·음성 보드·시스템 키보드 사이의 전환은 이제 키보드 자체의 설정 팝오버에 들어갔습니다. 원래부터 있어야 했던 자리죠.

키 위에는 새 후보 스트립이 얹힙니다. 자동 완성은 터미널이 최근 출력한 텍스트, 이번 세션에 입력한 단어들, 그리고 짧은 상용 셸 명령 목록에서 나옵니다. 전부 화면에 이미 있는 텍스트로 기기 안에서 계산되며 — 제안을 만들기 위해 어디로도 아무것도 보내지 않습니다. 키보드의 마이크 버튼은 눌러서 말하는 받아쓰기를 지원하고, 실시간 미리보기가 같은 스트립에 표시되며, 결과는 탭했을 때만 삽입됩니다. 마지막 부분은 의도된 설계입니다. 터미널은 잘못 들은 단어에 가차 없으니, 음성은 절대 셸로 직행하지 않습니다.

음성 입력 보드

음성 입력 보드는 플로팅 키보드가 이미 가진 창 예절을 그대로 물려받습니다. 옮기고, 크기를 바꾸고, 셸이 비쳐 읽힐 때까지 불투명도를 낮추고. 컨트롤은 한 벌, 보드는 둘, 놀랄 일은 없음.

연결이 끊겨도 살아남는 원격 데스크탑 탭

진작 했어야 할 일관성 수정입니다. 원격 데스크탑 세션의 연결을 끊으면 탭이 닫혔는데, SSH 세션은 끊어도 탭이 남고 재연결 버튼이 나왔습니다. 같은 앱, 두 개의 철학. 이제 Desk 탭은 SSH 탭과 똑같이 동작합니다 — 끊어도 탭은 남고, 재연결은 한 번의 탭이며, 탭을 닫는 건 오직 탭 자체에서만 일어나는 일입니다.

동기화 견고성

이번 달 가장 눈에 안 띄는, 그러나 아마 가장 중요한 작업. 저장된 호스트·스크립트·설정은 기기 간에 동기화되는데, 어떤 배포 기간이든 당신의 기기들은 서로 다른 앱 버전을 섞어 돌리게 됩니다 — 이건 엣지 케이스가 아니라 릴리스 전후 몇 주간의 세상 기본값입니다. 동기화 포맷 처리를 다시 만들었습니다. 새 버전이 쓴 데이터는 옛 버전을 그대로 통과합니다. 옛 앱은 이해 못 하는 부분을 보관했다가 그대로 되써 넣지, 목이 메거나 자기가 아는 모양으로 슬쩍 눌러 펴지 않습니다. 이제 우리가 스스로 지키는 규칙은 단순합니다. 옛 앱은 새 앱이 쓴 것을 절대 파괴할 수 없어야 한다. 이 기능을 당신이 볼 일은 없을 겁니다 — 바로 그게 핵심입니다.

실험적: Eternal Terminal 전송

SharkTTY는 SSH와 Mosh를 말합니다. 터미널이 기차 터널을 살아서 통과하게 해 주는 게 Mosh인데 — UDP 위에서 돌고, 어떤 네트워크는 UDP를 아예 통과시키지 않습니다. Eternal Terminal은 같은 문제를 순수 TCP로 풀고, 이미 많은 사람이 자기 머신에서 etserver를 돌리고 있습니다. 우리 입장은 단순합니다. 이 문제를 푸는 서버를 이미 운영하고 있다면, 그 혜택을 보는 데 우리 인프라가 필요해선 안 된다 — 앱이 당신 서버의 언어를 말해야 합니다.

그래서 공개 ET 프로토콜의 클라이언트를 Rust로 처음부터 구현했고, 이제 실제 etserver를 상대로 전 여정을 완주합니다. 연결하고, 입력하고, 도중에 링크를 끊고, 재연결해도, 아무것도 잃지 않습니다. 지금은 실전 주행거리를 쌓는 동안 실험 플래그 뒤에 있습니다. 충분히 쌓이면 SSH·Mosh 곁에 호스트별로 고르는 세 번째 전송으로 등장합니다. 오늘도 etserver를 돌리고 있고 플래그가 열릴 때 발로 차며 시험해 보고 싶다면, 이 블로그를 지켜봐 주세요.

위 내용에 관한 질문이나 버그 제보는? 피드백 보드가 가장 빠른 길입니다.