콘텐츠로 이동

0019. Claude 탭의 채팅 뷰는 기존 훅이 알려 주는 transcript 파일을 읽어 그린다

탭 바의 + 메뉴에서 “Claude”로 연 탭에서 대화를 말풍선으로 보여 주려고 한다. 입력과 권한 승인은 지금처럼 Claude Code 터미널 화면에서 한다.

터미널이 받는 것은 메시지가 아니라 글자와 커서 이동 명령이라, 화면 출력만으로는 어디까지가 사용자 입력이고 어디부터가 응답인지 가를 수 없다. Claude Code는 대화를 세션마다 ~/.claude/projects/<폴더>/<세션ID>.jsonl에 메시지 단위로 기록한다. 그러므로 어느 탭이 어느 파일을 쓰는지만 알면 채팅 뷰를 그릴 수 있다.

제약은 터미널에서 직접 친 claude의 동작을 바꾸지 않는 것이다. Belloga 훅은 ~/.claude/settings.json에 전역으로 설치되므로(ADR 0012), 훅을 바꾸면 모든 Claude 세션이 영향을 받는다.

이미 설치된 상태 훅 스크립트가 Claude가 stdin으로 넘기는 transcript_path를 /hook 요청에 함께 싣는다. 훅 서버는 pane별 최신 경로를 기억하고, Claude 탭이 열려 있으면 main 프로세스가 그 파일의 늘어난 부분을 읽어 채팅 항목으로 바꾼 뒤 렌더러에 보낸다.

  • 훅 이벤트를 새로 더하지 않는다. 훅 목록, 실행 횟수, 대기 시간은 지금과 같다.
  • 경로를 기록만 하고, 파일 감시는 Claude 탭이 요청할 때만 한다. 일반 터미널 탭과 Belloga 밖의 세션에는 채팅 뷰가 생기지 않는다.
  • transcript 줄을 채팅 항목으로 바꾸는 규칙은 한 함수에 모으고, 모르는 줄은 버린다.
  • 터미널 화면을 해석한다. 추가 연동이 필요 없지만, 스피너와 입력 박스가 화면을 계속 덮어써 메시지 경계를 추측해야 한다. Claude Code가 업데이트될 때마다 깨진다.
  • Agent SDK나 claude -p --output-format stream-json으로 직접 구동한다. 메시지를 구조화된 형태로 받지만, 권한 승인, slash command, 모드 전환을 Belloga가 다시 구현해야 한다. “터미널에 친 claude”라는 요구와도 맞지 않는다.
  • claude --session-id <uuid>로 띄우고 경로를 직접 계산한다. 훅이 필요 없지만, 폴더 이름 인코딩은 Claude Code 내부 규칙이고 /clear나 /resume으로 세션이 바뀌면 경로가 틀려진다.
  • SessionStart 훅을 더해 경로를 받는다. 세션이 바뀌는 순간 바로 알 수 있지만, 터미널에서 직접 친 claude도 시작할 때마다 훅 스크립트를 한 번 더 실행하고 기다려야 한다. 기존 동작을 바꾸므로 기각했다.
  • 채택안: 기존 훅 요청에 필드만 더한다. 이미 있는 pane 연결(BELLOGA_PANE_ID)을 그대로 쓰므로 어느 탭의 세션인지 추측하지 않고, 세션이 바뀌어도 다음 훅에서 새 경로를 받는다.
  • /clear나 /resume 직후에는 채팅 뷰가 바로 바뀌지 않고, 다음 메시지를 보낼 때(UserPromptSubmit) 새 세션으로 바뀐다.
  • transcript 형식은 Claude Code의 공개 API가 아니다. 형식이 바뀌면 채팅 뷰가 비거나 일부 항목이 빠질 수 있지만, 터미널 사용에는 영향이 없다.
  • 상태 훅 스위치를 끄면 경로를 받을 수 없으므로, Claude 탭은 채팅 뷰 대신 연동을 켜라는 안내를 보여 준다.
  • 훅 스크립트 내용이 바뀌지만 이벤트 수는 그대로라, 이미 설치된 사용자는 앱 시작 시 installed로 판정되어 스크립트를 다시 쓰지 않는다. 그래서 스위치가 켜져 있고 훅이 설치돼 있으면, 앱이 켜질 때 스크립트 파일의 내용을 비교해 다를 때만 다시 쓴다. settings.json은 건드리지 않는다.