DAY 01작업 1일째
플러그인은 파일만 쓰고 위젯이 그리게 나눴다
앱 안 패널로는 여러 세션을 한곳에 띄울 수 없어서, 플러그인과 바깥 위젯이 폴더 하나로 주고받게 했다.
앱 안 패널로는 부족했다
처음에는 Claude Code 플러그인이 앱 안에 그리는 패널로 사용량과 작업 현황을 보여 주려고 했다. 그런데 패널은 대화 입력창 위에 붙어서 첨부한 그림처럼 보였고, 원하는 위치에 띄울 수 없었다. 입력창 밖으로 꺼내려고 하면 잘려 나갔다.
더 큰 문제는 세션이 여러 개일 때였다. 플러그인은 세션마다 하나씩 돈다. 패널도 세션마다 따로 생기니 여러 세션을 한눈에 모아 볼 방법이 없었다.
아는 쪽과 그리는 쪽을 나눴다
세션 안에서만 알 수 있는 것(작업 상태, 컨텍스트, 사용량, 질문)은 플러그인이 모으고, 화면에 그리는 일은 컴퓨터에 하나만 뜨는 바깥 위젯이 맡게 나눴다. 둘 사이는 ~/.claude/ 아래 폴더 하나로 주고받는다.
| 파일 | 쓰는 쪽 | 내용 |
|---|---|---|
sessions/<세션 id>.json | 플러그인 | 세션 상태 스냅숏 |
commands/<세션 id>.json | 위젯 | 압축 요청 |
answers/<세션 id>.json | 위젯 | 질문에 고른 답 |
prompts/<세션 id>.json | 위젯 | 보낼 메시지 |
플러그인은 상태가 바뀔 때마다 자기 세션 파일을 다시 쓰고, 바뀐 게 없어도 30초마다 한 번 쓴다. 위젯은 0.5초마다 폴더를 읽어서, 2분 넘게 갱신이 없는 파일은 끝난 세션으로 본다. 반대 방향 요청은 플러그인이 1초마다 자기 세션 이름의 파일만 확인한다. 받으면 파일을 {}로 비워서 같은 요청을 두 번 처리하지 않는다.
파일로 정한 건 양쪽 다 손이 덜 가서였다. 플러그인 쪽은 엔진이 주는 파일 쓰기 함수만 있으면 되고, 위젯 쪽은 폴더를 읽기만 하면 된다. 세션이 몇 개든 위젯은 폴더 안 파일 개수만큼 줄을 그리면 된다.
위젯은 하나만 뜬다
위젯은 PowerShell로 띄우는 WPF 창이다. 세션이 시작될 때 플러그인이 띄우는데, 세션이 다섯 개면 다섯 번 띄우게 된다. 그래서 위젯이 시작하자마자 이름 붙은 뮤텍스를 잡고, 이미 잡혀 있으면 바로 끝나게 했다.
$mutex = New-Object System.Threading.Mutex($true, 'Local\orbit-hud-widget', [ref]$isFirst)
if (-not $isFirst) { exit }
창은 테두리 없이 투명하게 항상 위에 띄우고, 뜰 때 포커스를 가져가지 않게 했다.
감수한 것
폴더를 주기적으로 읽는 방식이라 반응이 최대 1초쯤 늦다. 요청 파일도 세션마다 한 칸뿐이라, 플러그인이 받아 가기 전에 위젯이 다시 쓰면 앞의 요청은 덮인다. 그래서 메시지처럼 연달아 보낼 수 있는 요청은 위젯이 들고 있다가 앞의 것이 비워진 걸 확인하고 하나씩 넘긴다.