@sejuneoh/aitop 0.21.1 → 0.21.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,236 +1,41 @@
1
1
  # ⣠⣴⣾ aitop
2
2
 
3
- 터미널에서 지금 돌고 있는 AI 코딩 세션(Claude Code · Codex CLI · Antigravity CLI · Gemini CLI)과 진행 내용, 토큰을 실시간으로 보는 읽기 전용 모니터.
3
+ [![npm](https://img.shields.io/npm/v/@sejuneoh/aitop)](https://www.npmjs.com/package/@sejuneoh/aitop)
4
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/SejuneOh/aitop/blob/main/LICENSE)
4
5
 
5
- - 포트를 열지 않고, 네트워크 요청을 하지 않는다. 각 CLI 가 내 PC 에 남기는 세션 파일만 읽는다.
6
- - 세션 파일은 읽기 전용으로만 연다. 디스크에 쓰는 곳은 읽은 위치·합계를 기억하는 `~/.cache/aitop` 뿐이다 (지워도 된다). `--debug` 를 켰을 때만 디버그 로그를 따로 쓴다.
7
- - 화면에 표시되는 텍스트 중 API 키·토큰처럼 보이는 값은 `••••` 로 가린다.
8
- - 외부 라이브러리 없음 (Node 22 이상). Antigravity CLI 의 세부 정보는 Node 내장 `node:sqlite` 로 기록을 immutable(파일을 하나도 만들거나 고치지 않는 열기)로 열 수 있는 Node 22.15 이상에서만 읽는다.
6
+ **`top` for your AI coding agents.** A read-only terminal monitor that shows every Claude Code, Codex CLI and Antigravity CLI session on your machine in one live screen: what each one is doing, which ones are waiting for you, and how many tokens they used.
9
7
 
10
- ## 설치
8
+ - **Live status** of every session and its subagents: thinking, running a tool, waiting for you, idle
9
+ - **Waiting alerts**: blocked sessions jump to the top, with optional bell, desktop notification or hook command
10
+ - **Tokens and cost** per session and for today / last 7 days, at public API list prices
11
+ - **Changed files and diffs** per session and per prompt
12
+ - **Read-only**: no network, no ports, no dependencies. It only reads the session logs each CLI already writes
11
13
 
12
- npmjs.com 에 공개로 올린다 (MIT).
14
+ > The interface text is currently in Korean. Keys and options work the same everywhere.
13
15
 
14
- ```bash
15
- npm install -g @sejuneoh/aitop # 설치·업데이트
16
- aitop
17
- ```
16
+ ## Install
18
17
 
19
- 예전에 비공개 GitHub Packages 에서 설치했다면 그 레지스트리 설정을 지워야 npmjs.com 에서 받는다.
18
+ Requires Node.js 22+ on Linux, macOS or WSL.
20
19
 
21
20
  ```bash
22
- npm config delete @sejuneoh:registry
23
- npm config delete //npm.pkg.github.com/:_authToken
24
- ```
25
-
26
- 로컬 코드로 바로 써 보려면 저장소에서 `npm install -g .`
27
-
28
- ## 릴리스
29
-
30
- | 브랜치 | 하는 일 |
31
- |---|---|
32
- | 기능 브랜치 → `dev` | PR 마다 CI(단위 테스트 → e2e → 실행 확인 → `npm pack` 설치 확인, Node 22/22.13/22.15/24, macOS 22) 실행. 병합 후 로컬에서 `npm install -g .` 로 확인. `dev` 에 들어오면 `release-pr` 워크플로가 `dev` → `main` release PR 을 만들거나 제목·본문(포함된 PR, 닫는 이슈)을 갱신한다 |
33
- | `dev` → `main` | 단위 테스트와 e2e 를 통과하고 `package.json` 의 `version` 이 아직 배포되지 않은 값이면 npmjs.com 에 공개로 배포하고(provenance 포함, 저장소 시크릿 `NPM_TOKEN` 필요), `v<버전>` 릴리스가 없으면 태그·릴리스 생성 (배포 뒤 릴리스 생성만 실패했으면 재실행하면 배포는 건너뛰고 릴리스만 만든다) |
34
-
35
- 테스트
36
-
37
- ```
38
- npm test # 단위 테스트 (test/*.test.mjs)
39
- npm run test:e2e # e2e: 실제 bin 실행(--json/--once/--help), 가상 터미널에서 키 입력·종료 확인 (Linux, util-linux script 필요)
40
- ```
41
-
42
- 버전 올리기는 `dev` 에서 `npm version patch|minor|major --no-git-tag-version` 후 커밋한다. 버전을 올리지 않은 `main` 병합은 테스트만 돌고 배포하지 않는다.
43
-
44
- `NPM_TOKEN` 은 npmjs.com 에서 `@sejuneoh` 범위에 배포 권한이 있는 토큰(Granular access token)으로 만들어 저장소 Settings → Secrets and variables → Actions 에 넣는다. 0.21.0 까지는 비공개 GitHub Packages 에만 있다.
45
-
46
- ## 사용
47
-
48
- ```
49
- aitop 실시간 화면
50
- aitop --all 종료된 세션(24시간 이내)도 함께
51
- aitop --once 현재 상태를 한 번 출력
52
- aitop --json 세션 목록과 오늘·7일 사용량을 JSON 으로 한 번 출력 (--all 과 함께 가능)
53
- 0.5.0 부터 files[] 의 줄 수 필드는 writtenLines·deletedLines (편집 누적, 예전 added·removed)
54
- 0.6.1 부터 비용(cost 등)은 소수 넷째 자리까지 반올림
55
- aitop --version 설치된 버전
56
- aitop --doctor 도구별 연결 점검 (기록 폴더, 기록 수, 마지막 기록, 실행 수). --json 과 함께 가능
57
- aitop --theme light|dark 밝은 배경 / 어두운 배경 색. 없으면 AITOP_THEME 환경변수, 설정 파일의 theme, 그다음 COLORFGBG 로 고르고, 모르면 어두운 배경
58
- aitop --color-blind 적록 색약(1형·2형)용 색. --theme 과 따로 고르며 밝은·어두운 배경 모두 있다 (AITOP_COLOR_BLIND=1, 설정 파일 colorBlind). 아래 '색약 팔레트' 참고
59
- aitop --show-requests 응답 대기 요청 전체(명령·경로)를 상세 패널과 --json(waitDetail)에 보인다. AITOP_SHOW_REQUESTS=1 과 같다
60
- aitop --budget-day <달러> 하루 예산 (AITOP_BUDGET_DAY, 설정 파일 budgetDay). 아래 '하루 예산' 참고
61
- aitop --no-bell · --no-all · --no-show-requests · --no-notify · --no-on-waiting · --no-budget-day · --no-debug · --no-color-blind 설정 파일에서 켠 값을 이번 실행만 끈다
62
- aitop --debug 디버그 로그 (AITOP_DEBUG=1, 설정 파일 debug). 아래 '디버그 로그' 참고
63
- AITOP_AMBIGUOUS=wide 폭이 모호한 기호를 2칸으로 그리는 터미널용 (설정 파일 ambiguous). 아래 '폭이 모호한 기호' 참고
64
- aitop --print-config 설정 값마다 값과 출처(flag/env/file/default), 설정 파일 위치를 보인다. --json 과 함께 가능
65
- ```
66
-
67
- ### 설정 파일
68
-
69
- `$XDG_CONFIG_HOME/aitop/config.json` (없으면 `~/.config/aitop/config.json`). 옵션 > 환경 변수 > 설정 파일 > 기본값 순서로 정한다.
70
-
71
- ```json
72
- { "theme": "light", "icons": "plain", "bell": true, "showRequests": false, "all": false }
21
+ npm install -g @sejuneoh/aitop
22
+ aitop
73
23
  ```
74
24
 
75
- | 키 | 값 | 같은 옵션·환경 변수 |
76
- |---|---|---|
77
- | `theme` | `light` · `dark` | `--theme`, `AITOP_THEME` |
78
- | `colorBlind` | true · false | `--color-blind` · `--no-color-blind`, `AITOP_COLOR_BLIND=1`·`0` |
79
- | `icons` | `plain` · `ascii` | `AITOP_ICONS` |
80
- | `bell` | true · false | `--bell` · `--no-bell` |
81
- | `showRequests` | true · false | `--show-requests` · `--no-show-requests`, `AITOP_SHOW_REQUESTS=1`·`0` |
82
- | `all` | true · false | `--all` · `--no-all` |
83
- | `notify` | true · false | `--notify` · `--no-notify` |
84
- | `onWaiting` | 명령 문자열 | `--on-waiting` · `--no-on-waiting` |
85
- | `debug` | true · false | `--debug` · `--no-debug`, `AITOP_DEBUG=1`·`0` |
86
- | `budgetDay` | 0 보다 큰 수 (달러) | `--budget-day <usd>` · `--budget-day=<usd>` · `--no-budget-day`, `AITOP_BUDGET_DAY` |
87
- | `hideIdleTools` | true (기본) · false | 없음. 실행 중 세션이 없고 7일 동안 쓰지 않은 도구를 도구 줄에서 숨긴다 |
88
- | `ambiguous` | `narrow` (기본) · `wide` | `AITOP_AMBIGUOUS` |
89
-
90
- 잘못된 JSON, 모르는 키, 잘못된 값은 그 키만 무시하고 `aitop --doctor` 에 알린다. `showRequests` 는 설정 파일로도 켤 수 있다 (내 파일이라 권한 검사는 하지 않는다). 켜면 위의 `--show-requests` 주의가 그대로 적용된다. `onWaiting` 은 파일 소유자가 나이고 그룹·다른 사용자가 쓸 수 없을 때(예: `chmod 600`)만 받는다.
91
-
92
- `--show-requests` 는 기본으로 꺼져 있다. 비밀값 가림은 최선일 뿐이라, 켜면 명령 속 비밀값이 그대로 보일 수 있다. 가림을 거친 요청 내용은 옵션과 관계없이 로컬 캐시(`~/.cache/aitop`)에 저장된다.
93
-
94
- ### 디버그 로그
95
-
96
- CLI 기록 형식이 바뀌어 값이 비어 보이면 `aitop --debug` 로 실행해 `$XDG_STATE_HOME/aitop/aitop.log` (없으면 `~/.local/state/aitop/aitop.log`) 를 본다. 꺼져 있으면 파일을 만들지 않는다.
97
- 읽기·해석 실패마다 출처, 오류 이름·코드, 파일 이름만 한 줄로 남긴다. 기록 내용·도구 입력은 쓰지 않고 비밀값처럼 보이는 글은 가린다. 같은 실패는 1분에 한 줄, 1MB 를 넘으면 `aitop.log.1` 로 옮겨 하나만 남긴다. 폴더는 0700, 파일은 0600. 위치와 켜짐 여부는 `--doctor` 에 보인다.
98
-
99
- 동료 PC 에서 Codex · Gemini 가 잡히는지 볼 때는 `aitop --doctor` 결과를 그대로 붙여 넣으면 된다. 기록 내용은 나오지 않는다 (Gemini 는 형식 확인용 JSON 키 이름만).
100
- `--json` 에는 `version` 과 같은 점검 결과 `tools` 가 들어 있다.
101
-
102
- 색 없이도(NO_COLOR) 보이도록 비용 상위 두 세션에는 `▲`, 컨텍스트 85% 이상에는 `!` 가 붙는다.
103
-
104
- ### 색약 팔레트
105
-
106
- `aitop --color-blind` (또는 `AITOP_COLOR_BLIND=1`, 설정 파일 `"colorBlind": true`) 는 적록 색약이 헷갈리는 색 쌍을 노랑 계열과 파랑 계열로 가른다. Okabe-Ito 색 계열을 바탕으로 했다.
107
-
108
- | 뜻 | 기본 (어두운 배경) | 색약 (어두운 · 밝은 배경) | 색 말고 구분하는 기호 |
109
- |---|---|---|---|
110
- | 응답 대기 | 호박색 | 노랑 `#f0e442` · `#6e5f00` | `◆`, 행 배경, 헤더 `◆ N 응답 대기` |
111
- | 돈 (비용) | 연두 | 옅은 파랑 `#d4dcff` · `#3a4fc0` | `$`, 비용 상위 `▲` |
112
- | 작업 중 · diff 더한 줄 | 초록 | 청록 `#3cc8a0` · `#00735a` | 스피너, STATUS 글, 줄 앞 `+` |
113
- | 경고 · diff 지운 줄 | 빨강 | 주홍 `#ff8060` · `#c03010` | `!`, 줄 앞 `-` |
114
- | 예산 주의 | 분홍 | 자주 `#e8a0c8` · `#9a3d76` | `예상 $45` (경고는 `예상 $60!`) |
115
-
116
- 밝기(`--theme`)와는 따로 고르므로 `COLORFGBG` 자동 판별도 그대로 쓴다. 글자 대비 규칙(배경·선택 행·대기 행·띠 위 4.5:1 이상)은 기본 팔레트와 같다. 청황 색약(3형)용 팔레트는 아직 없다.
117
-
118
- 실시간 화면은 창(탭) 제목을 `󰚩 (2◆ 1●) aitop` 처럼 아이콘과 응답 대기·확인 전 수로 바꾼다. `--bell` 을 주면 응답 대기가 새로 생길 때 벨을 한 번 울린다.
119
-
120
- 다른 창에서 일할 때는 알림을 켤 수 있다 (둘 다 기본으로 꺼져 있고, 실시간 화면에서만 동작한다. `--bell` 처럼 aitop 을 켰을 때 이미 응답 대기인 세션은 알리지 않는다).
25
+ ## Usage
121
26
 
122
27
  ```
123
- aitop --notify 데스크톱 알림. Linux 는 notify-send, macOS 는 osascript. 없으면 조용히 건너뛴다 (--doctor 에 보임)
124
- aitop --on-waiting 'my-hook.sh' 응답 대기가 새로 생길 때마다 /bin/sh -c 로 명령 실행 (--on-waiting=<명령> 도 됨)
125
- ```
126
-
127
- `--on-waiting` 명령은 **aitop 을 실행한 사용자 권한 그대로** 돈다. 세션 정보는 명령 문자열에 끼워 넣지 않고 환경변수로만 넘긴다 (명령 안에서 쓸 때는 `"$AITOP_PROJECT"` 처럼 따옴표로 감싼다).
128
-
129
- | 환경변수 | 값 |
130
- |---|---|
131
- | `AITOP_TOOL` | claude · codex · agy 등 |
132
- | `AITOP_PROJECT` | 프로젝트 이름 |
133
- | `AITOP_SESSION_ID` | 세션 id |
134
- | `AITOP_CWD` | 작업 폴더 |
135
- | `AITOP_WAITING_FOR` | 짧은 대기 사유 (예: `Bash`, 비밀값처럼 보이는 것은 가림) |
136
-
137
- 출력은 버리고, 10초가 지나면 명령(과 그 자식)을 끝낸다. 한 번에 하나만 실행하며, 실행 중에 새 대기가 생기면 가장 최근 것 하나만 기다렸다가 이어서 실행한다 (그 사이 것은 건너뜀). 그래서 여러 세션이 한꺼번에 응답 대기가 되면, 지금 명령이 끝난 뒤 그중 가장 최근 하나만 실행된다. aitop 을 끝내면 실행 중인 명령도 함께 끝낸다. 한 번 갱신에서 여러 세션이 함께 응답 대기가 되면 첫 세션과 마지막 세션만 실행되고 그 사이 세션은 건너뛴다. 명령이 자식을 백그라운드로 띄우고(`cmd &`) 먼저 끝나면, 그 자식은 10초 제한과 종료 정리 밖에 남으므로 정리는 명령이 맡는다. WSL 에서 notify-send 가 없으면 Windows 알림을 대신 띄우지 않는다. 필요하면 `--on-waiting` 으로 직접 부른다.
138
-
139
- ### 로고와 탭 아이콘
140
-
141
- 로고 `⣠⣴⣾` 는 점점 높아지는 막대 세 개다 (top 미터, 도구 셋). 점자 글자라 한글 터미널에서도 폭이 1칸으로 정해져 있다.
142
-
143
- | `AITOP_ICONS` | 헤더 로고 | 창·탭 제목 | WezTerm user var |
144
- |---|---|---|---|
145
- | (기본) | `⣠⣴⣾` | `󰚩 (2◆) aitop` (Nerd Font 로봇 U+F06A9) | 내보냄 |
146
- | `plain` | `⣠⣴⣾` | `⣾ (2◆) aitop` | 끔 |
147
- | `ascii` | `>_ai` | `(2◆) aitop` | 끔 |
148
-
149
- Nerd Font 를 쓰지 않는 터미널에서는 탭 제목 아이콘이 빈 네모로 보일 수 있다. 그때는 `export AITOP_ICONS=plain` 으로 끈다.
150
-
151
- ### 폭이 모호한 기호 (`AITOP_AMBIGUOUS=wide`)
152
-
153
- `·` `→` `…` `─` `│` `●` `◆` `▃` 같은 글자는 유니코드에서 폭이 '모호(A)' 하다. 동아시아 폭 설정을 켠 터미널(iTerm2 의 'Ambiguous characters are double-width', Windows Terminal·mintty 의 CJK 폭, vim 의 `ambiwidth=double` 과 같은 설정)은 이 글자들을 2칸으로 그려서 표 칸과 상자 테두리가 밀린다. 그런 터미널이면 `export AITOP_AMBIGUOUS=wide` (또는 설정 파일 `"ambiguous": "wide"`) 로 켠다.
154
-
155
- - 칸 수가 정해진 자리의 기호는 1칸 ASCII 로 바꾼다: 상자 `+ - |`, 가로줄 `-`, 컨텍스트 막대 `#`, 7일·활동 막대 `_.:-=+*#`, 상태 기호 `!`(응답 대기) `*`(확인 전·실행 중) `o`(대기) `.`(종료), 선택 `>`, 고정 `*`(★), 팀원 가지 `|-` `` `- ``.
156
- - 글 속의 `·` `→` `…` 등은 그대로 두고 2칸으로 세어 줄 끝을 맞춘다.
157
- - 로고 `⣠⣴⣾` 와 스피너는 점자라 폭이 모호하지 않아 그대로다.
158
-
159
- WezTerm 은 aitop 이 내보내는 user var(`aitop`, `aitop_waiting`, `aitop_unseen`)로 탭을 꾸밀 수 있다. `wezterm.lua` 예:
160
-
161
- ```lua
162
- local wezterm = require 'wezterm'
163
- wezterm.on('format-tab-title', function(tab)
164
- local v = tab.active_pane.user_vars
165
- if v.aitop == '1' then
166
- local w = tonumber(v.aitop_waiting or '0') or 0
167
- return { { Foreground = { Color = w > 0 and '#fbbf24' or '#7dd3fc' } }, { Text = ' 󰚩 aitop' .. (w > 0 and (' ' .. w .. '◆') or '') .. ' ' } }
168
- end
169
- end)
28
+ aitop live screen
29
+ aitop --all include sessions that ended in the last 24 hours
30
+ aitop --json print a snapshot as JSON and exit
31
+ aitop --doctor check which tools and logs aitop can see
32
+ aitop --help all options
170
33
  ```
171
34
 
172
- - `format-tab-title` 핸들러는 하나만 쓰인다. 이미 있으면 그 안에 위 조건을 합친다.
173
- - tmux 안에서 돌리면 tmux 가 user var 를 전달하지 않아 탭 값이 오지 않는다.
174
-
175
- - 모르는 옵션을 주면 오류와 도움말을 보이고 2 로 끝난다.
176
- - `--once` 를 파이프나 파일로 받으면 색 코드를 넣지 않고(`FORCE_COLOR=1` 이면 넣음), 크기는 `COLUMNS`·`LINES` 를 따른다.
177
-
178
- | 키 | 동작 |
179
- |---|---|
180
- | / | 세션 검색 (이름·폴더·모델). Enter 적용, Esc 지우기 |
181
- | ↑↓ / j k | 세션 선택 |
182
- | n | 다음 볼 세션으로 이동 (응답 대기 → 완료 · 확인 전) |
183
- | p | 고른 세션을 표 맨 위(응답 대기 바로 아래)에 고정, 다시 누르면 해제. 여러 개는 고정한 순서로 두고 정렬(`s`)이 바꾸지 않는다. 묶기(`g`)에서는 `고정` 묶음으로 모인다. 고정한 행은 SESSION 칸 앞에 `★` (좁은 화면에서도 이름보다 먼저 남는다). 종료 세션을 함께 볼 때(`e`) 고정한 종료 세션도 실행 중인 세션보다 위에 남는다. 이번 실행에만 기억한다 |
184
- | f / Tab | 변경 파일 목록으로. ←→ 지시 탭, ↑↓ 파일 고르기, Enter diff 보기 |
185
- | diff 에서 ↑↓ · space · [ ] | 스크롤 · 페이지 · 이전·다음 파일 |
186
- | d | 상세 열기·닫기 |
187
- | e | 종료된 세션 보이기·숨기기 |
188
- | c | 비용 기준 전환: API 환산(캐시 포함, 기본) ↔ 캐시 제외(입력·출력만). 표·헤더·상세가 같이 바뀐다 |
189
- | ? | 도움말. 지금 화면(세션 표·검색어가 걸린 표·상세·파일 목록·diff)의 키부터, 다른 화면 · 옵션 · 지금 설정 값 순으로 보인다. 열려 있는 동안은 ↑↓ j k space PgUp PgDn 스크롤, ? · Esc 닫기, q 나가기만 듣는다 |
190
- | Esc | 한 단계 뒤로 (도움말 닫기, 검색 지우기, diff → 파일 목록 → 세션). 종료하지 않는다 |
191
- | q / Ctrl-C | 나가기 |
192
-
193
- ## 화면
194
-
195
- - 헤더 오른쪽: 오늘·최근 7일 Claude · Codex CLI · Antigravity CLI 사용량(토큰, API 환산 비용). 최근 7일 안에 바뀐 기록(서브에이전트 포함)을 날짜별로 모은다. agy 는 호출마다 그 직전 단계의 만든 시각을 호출 날짜로 본다. Codex 는 `token_count` 누적값이 직전보다 늘어난 만큼을 그 줄의 시각에, 그 앞의 마지막 모델 가격으로 더한다 (누적값이 줄면 새로 시작한 것으로 본다). 처음 실행 때는 `7일 집계 중 N%` 로 채워진다. 폭이 모자라면 토큰 수, 7일, 오늘 순으로 줄인다.
196
- - 7일 막대: `7일 $644 ▅▁▃█▄▂▃` 는 오래된 날 → 오늘의 날짜별 비용을 7일 중 가장 큰 날 기준(█)으로 그린다. 0 인 날은 흐린 `▁`, 쓴 날은 `▂` 이상이라 색이 없어도 갈린다. 집계 중에는 숨기고, 폭이 모자라면 지출 속도 다음으로 뺀다. `--json` 에는 `usage.last7days.daily: [{ date, cost }]` (API 환산)로 나간다.
197
- - 지출 속도: `오늘 $194 ($31/h)` 의 괄호는 최근 1시간(5분 단위 근사) 비용이다. 0 이면 숨기고, 폭이 모자라면 가장 먼저 뺀다. `--json` 에는 `usage.lastHour` 로 나간다.
198
- - 하루 예산(`budgetDay`): 오늘 금액 옆에 `오늘 $12.30/$50` 처럼 보인다. 예상 비용 = 오늘 비용 + 최근 지출 속도 × 로컬 자정까지 남은 시간. 속도는 최근 1시간 중 자정 이후 몫만 시간당으로 늘린 값이고, 자정 뒤 15분이 안 됐거나 집계 중이면 예상 = 오늘 비용이다. 예상이 예산의 80% 이상이면 `· 예상 $45`, 100% 이상이면 경고 색과 `· 예상 $60!`. 예산은 비용 기준(`c`)과 상관없이 늘 API 환산으로 보며, 캐시 제외 화면에서는 `예산 $12.30/$50` 칸이 따로 붙는다. 폭이 모자라면 `/$50`, 오늘 금액 순으로 빼서 예상 경고를 시각 다음으로 오래 남긴다. 잘못된 `AITOP_BUDGET_DAY` 는 무시하고 `--doctor` 에 알린다. `--json` 에는 예산이 있을 때만 `usage.budget: { day, projected, unknown, level: ok·caution·warn }` 로 나간다 (화면과 같은 단계).
199
- - 도구 줄(헤더 아래 `▍claude 2 · 1.2M codex gemini`): 폭이 모자라면 간격, 토큰 수·`미설치`, 이름(`cla` `cdx` `gem`) 순으로 줄이고, 그래도 넘치면 세션이 없는 도구부터 빼고 끝에 `+N` 을 붙인다. 이름이 글자 중간에서 잘리지 않는다. 실행 중 세션이 없고 7일 동안 세션(기록 폴더의 가장 새 기록 포함)이 없는 도구는 숨기고 줄 끝에 `숨김 codex gemini` (자리가 모자라면 `숨김 2`, 아주 좁으면 뺌) 를 적는다. 기록 폴더가 없는(미설치) 도구도 함께 숨는다. 숨기면 남는 도구가 하나도 없을 때는 숨기지 않고 예전처럼 흐리게 다 보인다 (`미설치` 포함). 끝의 `+N` 은 화면이 좁아 접은 도구 수다. 실행 중 세션이나 프로세스가 있으면 늘 보인다. 설정 파일 `"hideIdleTools": false` 로 끈다.
200
- - 화면 높이가 30줄 이상이면 세션 표를 `세션 N` 상자로 감싼다. 비용 색은 화면에서 가장 큰 금액 두 개에만 칠한다.
201
- - 키 안내 줄은 폭이 모자라면 오른쪽부터 줄이고 `?`·`q` 는 늘 남긴다. `NO_COLOR` 이면 키가 `[q]` 처럼 괄호로 보이고, 포커스된 상자는 굵은 선(`┏━┃`)으로 그린다.
202
- - `● 완료 · 확인 전`: 작업 중이던 세션이 끝났는데 아직 선택해 보지 않은 세션. aitop 을 다시 켜면 초기화된다.
203
-
204
- - STATUS: 지금 단계 (`도구 실행 · Bash`, `생각 중`, `답변 작성 중`, `팀원 N명 작업 중`, `응답 대기`, `다음 지시 대기`). 큰 기록을 처음 읽는 동안은 `기록 읽는 중 N%`
205
- - 응답 대기 세션은 맨 위에 배경색으로 보인다. 화면이 작아 표가 잘리면 마지막 줄에 `… +N 세션` 이 나온다.
206
- - 서브에이전트는 메인 세션 아래 `├─` 행으로 붙고, 하는 일(description) 뒤에 타입이 흐리게 붙는다. 첫 응답 전에는 `시작 중`, 끝나면 6초간 `완료`로 보였다가 사라진다.
207
- - COST: Claude API 정가로 환산한 비용. 구독 요금제 사용분도 같은 기준으로 계산한다 (`src/pricing.mjs`). 가격표에 없는 모델이 섞이면 `$1.20?` 처럼 `?` 가 붙는다. Codex 는 OpenAI API 정가로 환산한다 (gpt-5.3-codex, gpt-5.1-codex(-mini), codex-mini, gpt-4o-mini). 값은 2026-11 가격 비교 사이트 기준 추정이며, 세션 중 모델이 바뀌면 마지막 모델 가격으로 계산한다. Antigravity CLI 는 Google 공식 Gemini API 가격표(유료 등급 standard, https://aistudio.google.com/docs/pricing, 2026-11-06 확인)로 호출마다 그 호출 시각의 가격으로 환산한다: gemini-4-argon 은 2026-12-01 부터, gemini-3.8-flash·gemini-3.6-flash 는 2027-01-01 부터 두 배 가격이다 (UTC 기준). gemini-3.5-flash-lite, gemini-3.1-flash-lite 도 표에 있다. 모델 이름이 표와 똑같을 때만 가격을 매기고, 그 밖의 모델(gemini-3.5-flash, gemini-3-flash-preview 등)은 추측하지 않고 `?` 로 보인다. 서브에이전트 비용은 부모 세션에 더한다.
208
- - IDLE: 마지막 활동 후 지난 시간. 작업 중이면 `now`.
209
- - 상세 패널의 토큰 합계 = 메인 + 서브에이전트 = 입력 + 출력 + 캐시 읽기 + 캐시 쓰기. 비용은 캐시 제외 금액도 함께 보인다.
210
- - `--all`: 24시간 안에 바뀐 기록을 종료 세션으로 보인다. 본문은 선택했을 때 읽는다.
211
- - 변경 파일: 세션(서브에이전트 포함)이 Edit/Write(Codex 는 apply_patch)로 고친 파일이 있으면 상세 패널 오른쪽 위에 `src/ui.mjs 편집 ×3 14:02` 처럼 편집 횟수와 마지막 시각이 보인다. git diff 가 아니라 이 세션의 편집 기록이다. diff 머리의 `쓴 줄 · 지운 줄` 은 편집마다 더한 누적값이라 최종 변경량과 다르다.
212
- - 지시 탭: `[이번 지시] T5 T3 전체`. 처음에는 마지막 지시 뒤에 고친 파일만 보인다. 편집이 있었던 이전 지시는 `T번호` 탭으로, 세션 전체는 `전체` 탭으로 본다. 서브에이전트 편집은 그 서브에이전트를 부른 지시에 들어간다. lock·빌드 결과 파일은 목록 끝에 흐리게 보인다. 지시는 최근 50개까지 기억한다. 파일을 열면 고친 순서의 역순으로 변경 조각마다 `시각 · 누가 · @@ 위치` 를 붙여 보인다. `.env`, `*.pem` 같은 비밀 파일은 목록에만 보이고 내용은 숨긴다.
213
-
214
- ## 읽는 곳
35
+ Keys: `↑↓` select · `n` next session to check · `/` search · `s` sort · `g` group · `p` pin · `f` changed files · `?` help · `q` quit
215
36
 
216
- | 도구 | 실행 중 판단 | 진행 내용·토큰 |
217
- |---|---|---|
218
- | Claude Code | `~/.claude/sessions/<pid>.json` + pid 가 살아 있는지 | `~/.claude/projects/*/<sessionId>.jsonl`, `…/subagents/agent-*.jsonl` |
219
- | Codex CLI | `codex` 프로세스와 작업 폴더 (Linux `/proc`, macOS `ps`·`lsof`) | `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl` |
220
- | Antigravity CLI (`agy`) | `agy` 프로세스가 열어 둔 `presence/<id>.lock` (Linux `/proc/<pid>/fd`). macOS 는 작업 폴더로 짝짓는다 | `~/.gemini/antigravity-cli/conversation_summaries.db`(제목·상태·서브에이전트), `conversations/<id>.db` 의 `gen_metadata`(모델·토큰)·`steps`(지시·답변·도구 호출) |
221
- | Gemini CLI | `gemini` 프로세스 | 아직 미지원 |
37
+ Settings can also go in `~/.config/aitop/config.json`. See `aitop --help` or the [detailed manual (Korean)](https://github.com/SejuneOh/aitop/blob/main/docs/README.ko.md).
222
38
 
223
- ## 알려진 한계
39
+ ## License
224
40
 
225
- - Linux·WSL·macOS 만 지원한다. Windows(PowerShell)는 설치되지 않는다. macOS 는 `ps`·`lsof` 를 2초에 한 번 부른다.
226
- - 배경색 자동 판별은 `COLORFGBG` 에 기대는데 Windows Terminal 은 이 값을 넣지 않는다. 밝은 배경의 Windows Terminal 에서는 `aitop --theme light` 로 실행한다.
227
- - 세션 파일 형식은 각 CLI 의 내부 형식이라, CLI 업데이트로 바뀌면 `src/sources/` 의 해당 파일을 고쳐야 한다.
228
- - 컨텍스트 창 크기는 기록에 없어서 모델별 표(`src/pricing.mjs`)로 정한다. 표에 없는 모델은 200k 를 넘으면 1M 으로 가정한다.
229
- - 같은 폴더에서 codex 를 여러 개 띄우면, 최근에 바뀐 세션 파일부터 순서대로 짝짓는다.
230
- - Antigravity CLI 세션은 Gemini 탭에 보인다. 지시·답변·도구 호출은 `conversations/<id>.db` 의 `steps` 에서 읽지만 변경 파일은 아직 읽지 않는다. 토큰·단계 필드 번호는 실제 기록에서 확인한 값이라(출력 = 생각 + 답변) agy 업데이트로 바뀔 수 있다. Windows Antigravity 앱(`/mnt/c/…/.gemini/antigravity`)은 읽지 않는다.
231
- - agy 기록은 파일을 하나도 건드리지 않으려고 `-wal` 을 읽지 않는다. 그래서 진행 내용과 응답 대기(도구 허락 대기)는 agy 가 `-wal` 을 본 파일에 합친 뒤에야 보이고, 보통 30초쯤 늦다. 허락한 뒤에는 `-wal` 이 다시 바뀌는 것을 보고 바로 작업 중으로 돌린다.
232
- - 토큰 합계에는 캐시 읽기 토큰이 포함된다. 세부 구성은 상세 패널에서 본다.
233
- - 실시간 화면은 한 번 갱신에 기록을 24MB 까지만 읽는다. 아주 큰 기록은 처음 몇 초 동안 합계가 채워지는 중으로 보인다.
234
- - 캐시 폴더 이름에 가격표 지문이 들어가서, 가격표를 바꾼 버전으로 올리면 첫 실행 때 비용을 다시 계산한다.
235
- - 변경 파일은 Edit/Write 도구 결과와 Codex 의 성공한 apply_patch 만 본다. Codex 패치에는 줄 번호가 없어 diff 에 `@@ 문맥` 만 보인다. Bash(`sed`, `git checkout` 등)로 바꾼 파일과 사람이 직접 고친 내용은 빠진다. 파일 60개, 파일당 변경 조각 8개, 세션당 1500줄까지만 보관하고, 넘치면 오래된 조각부터 버린다 (줄 수 통계는 남는다).
236
- - 서브에이전트는 `finished` 표시 없이 끊긴 기록이 남기 때문에, 메인이 결과를 기다리는 중이거나 15분 안에 기록이 바뀐 경우만 실행 중으로 본다.
41
+ [MIT](https://github.com/SejuneOh/aitop/blob/main/LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sejuneoh/aitop",
3
- "version": "0.21.1",
3
+ "version": "0.21.3",
4
4
  "description": "터미널에서 Claude Code · Codex · Antigravity · Gemini 세션과 토큰을 실시간으로 보는 읽기 전용 모니터",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/notify.mjs CHANGED
@@ -67,10 +67,11 @@ export function which(name, envPath = process.env.PATH ?? '') {
67
67
  return null;
68
68
  }
69
69
 
70
- export function isWsl(env = process.env) {
70
+ // WSL 인지. --doctor 의 알림 안내에 쓴다. readVersion 은 테스트에서 /proc/version 대신 넣는다.
71
+ export function isWsl(env = process.env, readVersion = () => readFileSync('/proc/version', 'utf8')) {
71
72
  if (env.WSL_DISTRO_NAME || env.WSL_INTEROP) return true;
72
73
  try {
73
- return /microsoft/i.test(readFileSync('/proc/version', 'utf8'));
74
+ return /microsoft/i.test(readVersion());
74
75
  } catch {
75
76
  return false;
76
77
  }
package/src/pricing.mjs CHANGED
@@ -39,8 +39,8 @@ const GEMINI_PRICES = {
39
39
  'gemini-3.1-flash-lite': [{ input: 0.25, output: 1.5, cacheRead: 0.025 }],
40
40
  };
41
41
 
42
- // 가격표가 바뀌면 이 값이 바뀌고, 캐시 폴더도 바뀌어 예전 비용이 다시 계산된다.
43
- export const PRICE_TAG = createHash('sha1').update(JSON.stringify([PRICES, GEMINI_PRICES])).digest('hex').slice(0, 8);
42
+ // 가격표의 지문(8자리). 표의 값이 하나라도 바뀌면 지문도 바뀐다.
43
+ export const priceTag = (tables) => createHash('sha1').update(JSON.stringify(tables)).digest('hex').slice(0, 8);
44
44
 
45
45
  // 모델별 컨텍스트 창 크기(토큰). 출처: Anthropic 모델 표(2026-10). 표에 없는 모델은 contextWindow 가 추측한다.
46
46
  const WINDOWS = {
@@ -93,7 +93,9 @@ export function claudeCost(model, u) {
93
93
  }
94
94
 
95
95
  // Codex(OpenAI) API 정가 기준 환산 비용 (USD / 100만 토큰). Claude 와 같이 "API 로 썼다면" 기준이다.
96
- // 출처: 2026-11 가격 비교 사이트(pricepertoken.com, computeprices.com)의 OpenAI 정가. 추정값이라 README 에 적어 둔다.
96
+ // 출처: OpenAI 공식 가격표 https://developers.openai.com/api/docs/pricing 와 모델별 문서
97
+ // (https://developers.openai.com/api/docs/models/gpt-5.3-codex, gpt-5.1-codex, gpt-5.1-codex-mini, codex-mini-latest, gpt-4o-mini).
98
+ // 2026-11-11 확인, 다섯 모델 모두 공식 값과 같다. cacheRead 는 cached input 가격이다.
97
99
  const OPENAI_PRICES = {
98
100
  'gpt-5.3-codex': { input: 1.75, cacheRead: 0.175, output: 14 },
99
101
  'gpt-5.1-codex-mini': { input: 0.25, cacheRead: 0.025, output: 2 },
@@ -102,6 +104,10 @@ const OPENAI_PRICES = {
102
104
  'gpt-4o-mini': { input: 0.15, cacheRead: 0.075, output: 0.6 },
103
105
  };
104
106
 
107
+ // 가격표가 바뀌면 이 값이 바뀌고, 캐시 폴더도 바뀌어 예전 비용이 다시 계산된다. 세 표(Claude, Gemini, Codex)를 모두 넣는다.
108
+ export const PRICE_TABLES = [PRICES, GEMINI_PRICES, OPENAI_PRICES];
109
+ export const PRICE_TAG = priceTag(PRICE_TABLES);
110
+
105
111
  // Codex 세션 누적 토큰(tokens: input 은 캐시 제외, cacheRead, output)의 환산 비용. 가격표에 없는 모델이면 null.
106
112
  export function codexCost(model, t) {
107
113
  const p = lookup(OPENAI_PRICES, model);