agy-cli-usage 0.4.1 → 0.4.2
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/CHANGELOG.md +7 -0
- package/README.ko.md +237 -0
- package/README.md +162 -52
- package/dist/src/main.js +19 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
* use plain v* tags in release-please ([#12](https://github.com/abruption/agy-cli-usage/issues/12)) ([74b648d](https://github.com/abruption/agy-cli-usage/commit/74b648df24967f71a43095a80e7340a6b5ac2e39)), closes [#9](https://github.com/abruption/agy-cli-usage/issues/9)
|
|
12
12
|
|
|
13
|
+
## [0.4.2](https://github.com/abruption/agy-cli-usage/compare/v0.4.1...v0.4.2) (2026-06-30)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* use canonical binary name agy-cli-usage in --help output ([#27](https://github.com/abruption/agy-cli-usage/issues/27)) ([384fa64](https://github.com/abruption/agy-cli-usage/commit/384fa64aedaef5249a99dc0c2acac9a136d2dcb4))
|
|
19
|
+
|
|
13
20
|
## [0.4.1](https://github.com/abruption/agy-cli-usage/compare/v0.4.0...v0.4.1) (2026-06-24)
|
|
14
21
|
|
|
15
22
|
|
package/README.ko.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# agy-cli-usage
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/agy-cli-usage)
|
|
6
|
+
[](https://www.npmjs.com/package/agy-cli-usage)
|
|
7
|
+
[](https://github.com/abruption/agy-cli-usage/actions/workflows/ci.yml)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](https://www.npmjs.com/package/agy-cli-usage)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
**Antigravity CLI(`agy`) 사용량·쿼타 모니터 (headless).**
|
|
13
|
+
|
|
14
|
+
`agy`의 `/usage` 패널 — 모델 그룹별 주간·5시간 한도, 잔여율, 리프레시 시각 — 을 **헤드리스로** 조회합니다. IDE 불필요, macOS · Linux · Windows · 헤드리스 서버 지원.
|
|
15
|
+
|
|
16
|
+
[English](README.md) · **한국어**
|
|
17
|
+
|
|
18
|
+
<sub><a href="https://github.com/skainguyen1412/antigravity-usage">skainguyen1412/antigravity-usage</a>에서 영감 — 그쪽은 Antigravity <b>IDE</b> 대상, 이 프로젝트는 <b>CLI</b>(<code>agy</code>) 대상입니다.</sub>
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
Models & Quota
|
|
26
|
+
Account: you@gmail.com
|
|
27
|
+
|
|
28
|
+
GEMINI MODELS
|
|
29
|
+
Weekly Limit
|
|
30
|
+
[██████████████████████████████████████████████░░░░] 91.72%
|
|
31
|
+
92% remaining · Refreshes in 73h 23m
|
|
32
|
+
Five Hour Limit
|
|
33
|
+
[███████████████████████████████████████████████░░░] 94.63%
|
|
34
|
+
95% remaining · Refreshes in 2h 2m
|
|
35
|
+
|
|
36
|
+
CLAUDE AND GPT MODELS
|
|
37
|
+
Weekly Limit
|
|
38
|
+
[█████████████████████████████████████████████████░] 97.78%
|
|
39
|
+
98% remaining · Refreshes in 26h 17m
|
|
40
|
+
Five Hour Limit
|
|
41
|
+
[██████████████████████████████████████████████████] Quota available
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# 사람을 위한 안내 (For Human)
|
|
47
|
+
|
|
48
|
+
## 개요
|
|
49
|
+
|
|
50
|
+
`agy-cli-usage`는 `agy`의 인터랙티브 `/usage` 슬래시 커맨드와 동일한 사용량·쿼타 정보를 일반 셸에서 보여줍니다 — 1회성, watch 모드, 또는 머신 리더블 JSON. 잔여 쿼타 확인, 상태바 연동, 대시보드 공급 등에 사용하세요.
|
|
51
|
+
|
|
52
|
+
## 왜 필요한가
|
|
53
|
+
|
|
54
|
+
`agy -p "<prompt>"`(헤드리스 모드)는 LLM 프롬프트 전용 경로라 `/usage` 같은 TUI 슬래시 커맨드를 렌더링하지 않습니다. 그래서 사용량을 자동화·폴링할 수 없습니다. 이 도구는 쿼타를 직접 읽어(필요 시 `agy`를 가상 터미널로 구동해) 그 공백을 메웁니다.
|
|
55
|
+
|
|
56
|
+
## 빠른 시작
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# 설치 없이 한 번 실행
|
|
60
|
+
npx agy-cli-usage
|
|
61
|
+
|
|
62
|
+
# 전역 설치 → 어디서나 `agy-cli-usage` (별칭 `agy-usage`)
|
|
63
|
+
npm install -g agy-cli-usage
|
|
64
|
+
agy-cli-usage
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
> 사전 조건: 같은 머신에서 `agy`에 로그인되어 있을 것, Node.js >= 18.
|
|
68
|
+
|
|
69
|
+
## 사용법
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
agy-cli-usage # /usage 와 동일한 패널 (1회성)
|
|
73
|
+
agy-cli-usage --json # 머신 리더블 JSON
|
|
74
|
+
agy-cli-usage --watch 60 # 60초 간격 자동 갱신 (5분 캐시 경유)
|
|
75
|
+
agy-cli-usage update [--check] # 자기 업데이트 (--check: 알림만)
|
|
76
|
+
agy-cli-usage --version # 버전 출력
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| 플래그 | 설명 |
|
|
80
|
+
|--------|------|
|
|
81
|
+
| `--json` | 정규화 JSON 출력 (스크립트/대시보드 연동) |
|
|
82
|
+
| `--watch [초]` | N초 간격 갱신 (기본 60) |
|
|
83
|
+
| `--source <auto\|api\|pty>` | 데이터 소스 (기본 `auto`: API → 실패 시 PTY) |
|
|
84
|
+
| `--channel <auto\|daily\|prod>` | Cloud Code 호스트 |
|
|
85
|
+
| `--no-cache` / `--refresh` | 5분 캐시 무시하고 강제 조회 |
|
|
86
|
+
| `-h`, `--help` | 도움말 |
|
|
87
|
+
| `-v`, `--version` | 버전 |
|
|
88
|
+
|
|
89
|
+
## 동작 방식
|
|
90
|
+
|
|
91
|
+
1. **직접 API (기본 · 빠름).** OS에서 `agy`의 OAuth 토큰을 읽어, `agy`가 시작 시 호출하는 것과 동일한 Cloud Code 내부 API를 직접 호출합니다.
|
|
92
|
+
- `POST /v1internal:loadCodeAssist` → `cloudaicompanionProject` 획득
|
|
93
|
+
- `POST /v1internal:retrieveUserQuotaSummary {project}` → 쿼타
|
|
94
|
+
- 만료 시 OAuth refresh 자동 처리.
|
|
95
|
+
2. **PTY 폴백 (안전망).** 토큰을 못 읽거나 내부 API가 바뀌면, `agy`를 가상 터미널로 띄워 `/usage`를 보내고 `@xterm/headless`로 화면을 재구성해 파싱합니다.
|
|
96
|
+
|
|
97
|
+
## 크로스플랫폼 자격증명
|
|
98
|
+
|
|
99
|
+
토큰은 `agy`가 저장한 위치에서 **읽기만** 합니다. 플랫폼별 자동 처리:
|
|
100
|
+
|
|
101
|
+
| OS / 환경 | 저장 위치 | 읽는 방법 |
|
|
102
|
+
|-----------|----------|----------|
|
|
103
|
+
| macOS | Keychain | `@napi-rs/keyring` (폴백 `security`) |
|
|
104
|
+
| Linux 데스크톱 | Secret Service | `@napi-rs/keyring` (폴백 `secret-tool`) |
|
|
105
|
+
| **Windows** | Credential Manager | 내장 `powershell.exe`로 Win32 `CredRead` 호출 |
|
|
106
|
+
| **헤드리스 Linux** | 토큰 파일 | `~/.gemini/antigravity-cli/antigravity-oauth-token` |
|
|
107
|
+
|
|
108
|
+
읽기 순서: `키링 → OS CLI → Windows credman → 토큰 파일 → PTY`. 파일 경로는 `AGY_OAUTH_TOKEN_FILE`로 override.
|
|
109
|
+
|
|
110
|
+
## HTTP 엔드포인트 (선택)
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
PORT=3007 npm run serve # GET /quota → 정규화 JSON (5분 캐시), GET /healthz
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
외부 대시보드/스크립트에서 `GET /quota`로 소비하거나, `agy-cli-usage --json`을 서브프로세스로 호출하세요.
|
|
117
|
+
|
|
118
|
+
## 개발 & 릴리스
|
|
119
|
+
|
|
120
|
+
TypeScript(strict, ESM)로 작성하고 `tsc`로 `dist/`에 컴파일합니다.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm run build # tsc → dist/ (컴파일된 JS + .d.ts)
|
|
124
|
+
npm run check # tsc --noEmit (타입 체크)
|
|
125
|
+
npm test # 빌드 후 node --test (자격증명·네트워크 불필요, 순수 로직)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- **CI**: push/PR마다 Ubuntu(Node 18/20/22) + macOS/Windows(Node 22)에서 테스트.
|
|
129
|
+
- **릴리스**: [release-please](https://github.com/googleapis/release-please) — Conventional Commits 기반 완전 자동화. main에 머지된 커밋으로 **Release PR**(버전 범프 + CHANGELOG)이 유지되고, 그 PR을 머지하면 태그·GitHub Release·`npm publish --provenance`가 자동 실행됩니다.
|
|
130
|
+
|
|
131
|
+
## 주의
|
|
132
|
+
|
|
133
|
+
- `v1internal:retrieveUserQuotaSummary`는 **비공개·비문서 내부 엔드포인트**입니다. 스키마/호스트가 예고 없이 바뀔 수 있으며, 그때의 안전망이 PTY 폴백입니다. 본인 계정의 사용량 조회 용도로만 사용하세요.
|
|
134
|
+
- 자격증명은 OS 저장소에서 **읽기만** 하며, refresh 토큰을 되쓰지 않아 `agy` 세션과 충돌하지 않습니다.
|
|
135
|
+
- 코드에 포함된 OAuth client_id/secret은 `agy` 바이너리의 **installed-app(public)** 값으로, [Google 문서](https://developers.google.com/identity/protocols/oauth2)상 기밀이 아닙니다. 사용자 식별은 각자의 키링 토큰으로 이뤄집니다.
|
|
136
|
+
|
|
137
|
+
## 라이선스
|
|
138
|
+
|
|
139
|
+
[MIT](LICENSE) © abruption
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
# 에이전트(AI)를 위한 안내 (For Agent)
|
|
144
|
+
|
|
145
|
+
> 프로그래밍적 사용을 위한 머신 지향 스펙. 안정적 계약: `--json` 스냅샷과 `GET /quota` 페이로드는 동일한 형태(`Snapshot`)를 공유합니다.
|
|
146
|
+
|
|
147
|
+
## TL;DR
|
|
148
|
+
|
|
149
|
+
- 바이너리: `agy-cli-usage` (별칭 `agy-usage`). Node >= 18. 같은 호스트에 `agy` 로그인 필요.
|
|
150
|
+
- 구조화 데이터: `agy-cli-usage --json` (stdout) 또는 `GET http://127.0.0.1:3007/quota`.
|
|
151
|
+
- `auto`의 소스 순서: 직접 API → PTY 폴백. 결과는 5분 캐시.
|
|
152
|
+
|
|
153
|
+
## 커맨드
|
|
154
|
+
|
|
155
|
+
| 호출 | 동작 |
|
|
156
|
+
|------|------|
|
|
157
|
+
| `agy-cli-usage` | 패널을 stdout에 렌더(휴먼 포맷). |
|
|
158
|
+
| `agy-cli-usage --json` | `Snapshot` JSON을 stdout에 출력 후 종료. |
|
|
159
|
+
| `agy-cli-usage --watch [초]` | `초`(최소 5, 기본 60)마다 화면 클리어 후 재렌더. 무한 실행. |
|
|
160
|
+
| `agy-cli-usage --source <auto\|api\|pty>` | `api`: API 전용(실패 시 throw). `pty`: PTY 전용(캐시 무시). `auto`: API→PTY. |
|
|
161
|
+
| `agy-cli-usage --channel <auto\|daily\|prod>` | Cloud Code 호스트 선택. `auto`는 `daily`→`prod` 순서. |
|
|
162
|
+
| `agy-cli-usage --no-cache` / `--refresh` | 강제 신규 조회(5분 캐시 스킵). |
|
|
163
|
+
| `agy-cli-usage update [--check]` | `npm i -g` 자가 업데이트. `--check`는 알림만. |
|
|
164
|
+
| `agy-cli-usage --version` / `-v` | 버전 문자열을 stdout에 출력. |
|
|
165
|
+
|
|
166
|
+
## JSON 출력 (`--json`) — 스키마
|
|
167
|
+
|
|
168
|
+
```jsonc
|
|
169
|
+
{
|
|
170
|
+
"account": "you@gmail.com | null",
|
|
171
|
+
"tier": "string | null",
|
|
172
|
+
"fetchedAt": "ISO-8601 타임스탬프",
|
|
173
|
+
"source": "api | pty",
|
|
174
|
+
"host": "cloud code host | null",
|
|
175
|
+
"note": "string | null",
|
|
176
|
+
"groups": [
|
|
177
|
+
{
|
|
178
|
+
"name": "GEMINI MODELS",
|
|
179
|
+
"models": "쉼표 구분 모델 목록 (빈 문자열 가능)",
|
|
180
|
+
"buckets": [
|
|
181
|
+
{
|
|
182
|
+
"kind": "weekly | 5h | <기타>",
|
|
183
|
+
"label": "Weekly Limit",
|
|
184
|
+
"remainingFraction": 0.9172, // 0..1, 미상이면 null
|
|
185
|
+
"usedFraction": 0.0828, // 1 - remainingFraction, 또는 null
|
|
186
|
+
"resetAt": "ISO-8601 | null",
|
|
187
|
+
"resetsInSeconds": 264180, // 정수 초, 또는 null
|
|
188
|
+
"available": false, // remainingFraction === 1 이면 true
|
|
189
|
+
"description": "string | null"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
파싱 시 참고:
|
|
198
|
+
- `remainingFraction`(잔여 비율 0–1)을 우선 사용. `available`이 `true`면 풀 쿼타로 간주(패널은 "Quota available" 표시).
|
|
199
|
+
- `resetsInSeconds`는 `fetchedAt` 기준 상대값, `resetAt`은 절대값. 둘 다 `null` 가능.
|
|
200
|
+
- `kind`는 인식 시 `weekly`/`5h`로 정규화, 아니면 원본 window/label 문자열.
|
|
201
|
+
|
|
202
|
+
## HTTP API (`npm run serve` / `dist/src/server.js`)
|
|
203
|
+
|
|
204
|
+
| 라우트 | 응답 |
|
|
205
|
+
|--------|------|
|
|
206
|
+
| `GET /quota` | `200` `Snapshot` JSON(`--json`과 동일 형태). `?refresh=1`은 캐시 우회. 실패 시 `502 {"error":...}`. 헤더: `Cache-Control: public, max-age=300`, `Access-Control-Allow-Origin: *`. |
|
|
207
|
+
| `GET /healthz` | `200 {"ok":true}` |
|
|
208
|
+
| (그 외) | `404 {"error":"not found"}` |
|
|
209
|
+
|
|
210
|
+
`HOST`(기본 `127.0.0.1`) : `PORT`(기본 `3007`)에 바인딩.
|
|
211
|
+
|
|
212
|
+
## 환경변수
|
|
213
|
+
|
|
214
|
+
| 변수 | 효과 |
|
|
215
|
+
|------|------|
|
|
216
|
+
| `AGY_OAUTH_TOKEN_FILE` | 토큰 파일 경로 override(헤드리스 폴백). |
|
|
217
|
+
| `AGY_BIN` | `agy` 바이너리 경로(PTY 소스). 없으면 `PATH`→`~/.local/bin` 순 탐색. |
|
|
218
|
+
| `XDG_CACHE_HOME` | 캐시 베이스 디렉토리(캐시는 `<base>/agy-usage/quota.json`, 기본 `~/.cache`). |
|
|
219
|
+
| `NO_COLOR` | 렌더 패널의 ANSI 색상 비활성화. |
|
|
220
|
+
| `PORT` / `HOST` | HTTP 서버 바인딩(서버 모드 한정). |
|
|
221
|
+
|
|
222
|
+
## 종료 코드 & 오류
|
|
223
|
+
|
|
224
|
+
- `0` — 성공.
|
|
225
|
+
- `1` — 모든 오류(예: 토큰을 못 읽고 PTY도 불가할 때 `CredentialError`). 오류 텍스트는 **stderr**로, 구조화 출력은 **stdout**으로 나가므로, stderr에 경고(`auto` 모드의 `[api failed: …] falling back to PTY` 알림 등)가 있어도 `--json` stdout은 안전하게 파싱 가능.
|
|
226
|
+
- `update`는 내부 `npm` 종료 코드를 반환.
|
|
227
|
+
|
|
228
|
+
## 데이터 소스 & 캐시
|
|
229
|
+
|
|
230
|
+
- **캐시**: `<XDG_CACHE_HOME|~/.cache>/agy-usage/quota.json`, TTL **5분**. `--watch`/폴링 시 업스트림 API 부하 회피. `source === 'pty'`이거나 캐시 비활성(`--no-cache`/`--refresh`, HTTP 라우트의 `?refresh=1`) 시 우회.
|
|
231
|
+
- **API 경로**는 토큰(키링/파일)을 읽어 `loadCodeAssist` → `retrieveUserQuotaSummary` 호출. **PTY 경로**는 `agy`를 구동(POSIX `python3 pty`, Windows `node-pty`)하며 환경에서 `agy` 실행 가능해야 함.
|
|
232
|
+
|
|
233
|
+
## 연동 노트
|
|
234
|
+
|
|
235
|
+
- 자동화 시 `--json`(서브프로세스) 또는 `GET /quota`(상시 서비스)를 호출. 둘 다 동일 캐시를 거치므로 고빈도 폴링도 안전.
|
|
236
|
+
- 휴먼 패널은 파싱하지 말 것 — ANSI 이스케이프 포함, 레이아웃 지향. `Snapshot` JSON이 안정적 계약.
|
|
237
|
+
- 이 도구는 자격증명을 **읽기만** 하며, `agy` 세션을 변경하거나 토큰을 되쓰지 않음.
|
package/README.md
CHANGED
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
**Headless usage & quota monitor for the Antigravity CLI (`agy`).**
|
|
13
13
|
|
|
14
|
-
`agy
|
|
14
|
+
Reads `agy`'s `/usage` panel — per–model-group weekly & 5-hour limits, remaining percentage, and refresh times — **headlessly**. No IDE required; works on macOS · Linux · Windows · headless servers.
|
|
15
|
+
|
|
16
|
+
**English** · [한국어](README.ko.md)
|
|
15
17
|
|
|
16
18
|
<sub>Inspired by <a href="https://github.com/skainguyen1412/antigravity-usage">skainguyen1412/antigravity-usage</a> — which targets the Antigravity <b>IDE</b>; this targets the <b>CLI</b> (<code>agy</code>).</sub>
|
|
17
19
|
|
|
@@ -39,89 +41,197 @@
|
|
|
39
41
|
[██████████████████████████████████████████████████] Quota available
|
|
40
42
|
```
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# For Human
|
|
47
|
+
|
|
48
|
+
## What it is
|
|
49
|
+
|
|
50
|
+
`agy-cli-usage` shows the same usage/quota information as `agy`'s interactive `/usage` slash command, but from a plain shell — one-shot, watch mode, or machine-readable JSON. Use it to keep an eye on your remaining quota, drive a status bar, or feed a dashboard.
|
|
51
|
+
|
|
52
|
+
## Why
|
|
53
|
+
|
|
54
|
+
`agy -p "<prompt>"` (headless mode) is a prompt-only path: it does not render TUI slash commands like `/usage`, so usage can't be polled or automated. This tool fills that gap by reading the quota directly (and falling back to driving `agy` in a pseudo-terminal when needed).
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
43
57
|
|
|
44
58
|
```bash
|
|
45
|
-
#
|
|
59
|
+
# Run once, no install
|
|
46
60
|
npx agy-cli-usage
|
|
47
61
|
|
|
48
|
-
#
|
|
62
|
+
# Install globally → `agy-cli-usage` (alias `agy-usage`) anywhere
|
|
49
63
|
npm install -g agy-cli-usage
|
|
50
64
|
agy-cli-usage
|
|
51
65
|
```
|
|
52
66
|
|
|
53
|
-
>
|
|
67
|
+
> Prerequisites: `agy` is logged in on the same machine, and Node.js >= 18.
|
|
54
68
|
|
|
55
|
-
##
|
|
69
|
+
## Usage
|
|
56
70
|
|
|
57
71
|
```bash
|
|
58
|
-
agy-cli-usage # /usage
|
|
59
|
-
agy-cli-usage --json #
|
|
60
|
-
agy-cli-usage --watch 60 #
|
|
61
|
-
agy-cli-usage update [--check] #
|
|
62
|
-
agy-cli-usage --version #
|
|
72
|
+
agy-cli-usage # the /usage panel (one-shot)
|
|
73
|
+
agy-cli-usage --json # machine-readable JSON
|
|
74
|
+
agy-cli-usage --watch 60 # auto-refresh every 60s (via the 5-min cache)
|
|
75
|
+
agy-cli-usage update [--check] # self-update (--check: report only)
|
|
76
|
+
agy-cli-usage --version # print version
|
|
63
77
|
```
|
|
64
78
|
|
|
65
|
-
|
|
|
66
|
-
|
|
67
|
-
| `--json` |
|
|
68
|
-
| `--watch [
|
|
69
|
-
| `--source <auto\|api\|pty>` |
|
|
70
|
-
| `--channel <auto\|daily\|prod>` | Cloud Code
|
|
71
|
-
| `--no-cache` / `--refresh` |
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
`agy -p "<prompt>"`(headless)는 LLM 프롬프트 전용이라 `/usage` 같은 TUI 슬래시 커맨드를 렌더링하지 않습니다. 그래서 사용량을 자동화·폴링할 수 없습니다. 이 도구는 그 공백을 메웁니다.
|
|
79
|
+
| Flag | Description |
|
|
80
|
+
|------|-------------|
|
|
81
|
+
| `--json` | Normalized JSON output (for scripts/dashboards) |
|
|
82
|
+
| `--watch [secs]` | Refresh every N seconds (default 60) |
|
|
83
|
+
| `--source <auto\|api\|pty>` | Data source (default `auto`: API → PTY on failure) |
|
|
84
|
+
| `--channel <auto\|daily\|prod>` | Cloud Code host |
|
|
85
|
+
| `--no-cache` / `--refresh` | Bypass the 5-minute cache |
|
|
86
|
+
| `-h`, `--help` | Show help |
|
|
87
|
+
| `-v`, `--version` | Show version |
|
|
76
88
|
|
|
77
|
-
##
|
|
89
|
+
## How it works
|
|
78
90
|
|
|
79
|
-
1.
|
|
80
|
-
- `POST /v1internal:loadCodeAssist` → `cloudaicompanionProject`
|
|
81
|
-
- `POST /v1internal:retrieveUserQuotaSummary {project}` →
|
|
82
|
-
-
|
|
83
|
-
2. **PTY
|
|
91
|
+
1. **Direct API (default · fast).** Reads `agy`'s OAuth token from the OS and calls the same internal Cloud Code API that `agy` calls on startup:
|
|
92
|
+
- `POST /v1internal:loadCodeAssist` → obtains `cloudaicompanionProject`
|
|
93
|
+
- `POST /v1internal:retrieveUserQuotaSummary {project}` → the quota
|
|
94
|
+
- Refreshes the OAuth token automatically when expired.
|
|
95
|
+
2. **PTY fallback (safety net).** If the token can't be read or the internal API changes, it launches `agy` in a pseudo-terminal, sends `/usage`, reconstructs the screen with `@xterm/headless`, and parses it.
|
|
84
96
|
|
|
85
|
-
##
|
|
97
|
+
## Cross-platform credentials
|
|
86
98
|
|
|
87
|
-
|
|
99
|
+
The token is **read only** from wherever `agy` stored it. Handled per platform automatically:
|
|
88
100
|
|
|
89
|
-
| OS /
|
|
90
|
-
|
|
91
|
-
| macOS | Keychain | `@napi-rs/keyring` (
|
|
92
|
-
| Linux
|
|
93
|
-
| **Windows** | Credential Manager |
|
|
94
|
-
|
|
|
101
|
+
| OS / environment | Storage | How it's read |
|
|
102
|
+
|------------------|---------|---------------|
|
|
103
|
+
| macOS | Keychain | `@napi-rs/keyring` (fallback `security`) |
|
|
104
|
+
| Linux desktop | Secret Service | `@napi-rs/keyring` (fallback `secret-tool`) |
|
|
105
|
+
| **Windows** | Credential Manager | Win32 `CredRead` via built-in `powershell.exe` |
|
|
106
|
+
| **Headless Linux** | token file | `~/.gemini/antigravity-cli/antigravity-oauth-token` |
|
|
95
107
|
|
|
96
|
-
|
|
108
|
+
Read order: `keyring → OS CLI → Windows credman → token file → PTY`. Override the file path with `AGY_OAUTH_TOKEN_FILE`.
|
|
97
109
|
|
|
98
|
-
##
|
|
110
|
+
## HTTP endpoint (optional)
|
|
99
111
|
|
|
100
112
|
```bash
|
|
101
|
-
PORT=3007 npm run serve # GET /quota →
|
|
113
|
+
PORT=3007 npm run serve # GET /quota → normalized JSON (5-min cache), GET /healthz
|
|
102
114
|
```
|
|
103
115
|
|
|
104
|
-
|
|
116
|
+
Consume `GET /quota` from an external dashboard/script, or call `agy-cli-usage --json` as a subprocess.
|
|
105
117
|
|
|
106
|
-
##
|
|
118
|
+
## Development & Release
|
|
107
119
|
|
|
108
|
-
TypeScript(strict, ESM)
|
|
120
|
+
Written in TypeScript (strict, ESM) and compiled to `dist/` with `tsc`.
|
|
109
121
|
|
|
110
122
|
```bash
|
|
111
|
-
npm run build # tsc → dist/ (
|
|
112
|
-
npm run check # tsc --noEmit (
|
|
113
|
-
npm test #
|
|
123
|
+
npm run build # tsc → dist/ (compiled JS + .d.ts)
|
|
124
|
+
npm run check # tsc --noEmit (type-check)
|
|
125
|
+
npm test # build, then node --test (no credentials/network; pure logic)
|
|
114
126
|
```
|
|
115
127
|
|
|
116
|
-
- **CI**: push/PR
|
|
117
|
-
- **Release**: [release-please](https://github.com/googleapis/release-please) —
|
|
128
|
+
- **CI**: every push/PR runs the test suite on Ubuntu (Node 18/20/22) + macOS/Windows (Node 22).
|
|
129
|
+
- **Release**: [release-please](https://github.com/googleapis/release-please) — fully automated from Conventional Commits. Merged commits keep a **Release PR** (version bump + CHANGELOG) up to date; merging that PR creates the tag + GitHub Release and runs `npm publish --provenance`.
|
|
118
130
|
|
|
119
|
-
##
|
|
131
|
+
## Caveats
|
|
120
132
|
|
|
121
|
-
- `v1internal:retrieveUserQuotaSummary
|
|
122
|
-
-
|
|
123
|
-
-
|
|
133
|
+
- `v1internal:retrieveUserQuotaSummary` is a **private, undocumented endpoint**. Its schema/host may change without notice; the PTY fallback is the safety net. Use it only to check your own account's usage.
|
|
134
|
+
- Credentials are **read-only** from the OS store; the refresh token is never written back, so it never conflicts with `agy`'s own session.
|
|
135
|
+
- The OAuth client_id/secret embedded in the code are `agy`'s **installed-app (public)** values — per [Google's docs](https://developers.google.com/identity/protocols/oauth2) these are not treated as secret. Per-user identity comes from your keyring token, not the client_id.
|
|
124
136
|
|
|
125
|
-
##
|
|
137
|
+
## License
|
|
126
138
|
|
|
127
139
|
[MIT](LICENSE) © abruption
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
# For Agent (AI)
|
|
144
|
+
|
|
145
|
+
> Machine-oriented spec for programmatic use. Stable contract: the `--json` snapshot and the `GET /quota` payload share the same shape (`Snapshot`).
|
|
146
|
+
|
|
147
|
+
## TL;DR
|
|
148
|
+
|
|
149
|
+
- Binary: `agy-cli-usage` (alias `agy-usage`). Node >= 18. Requires `agy` logged in on the same host.
|
|
150
|
+
- Get structured data: `agy-cli-usage --json` (stdout) or `GET http://127.0.0.1:3007/quota`.
|
|
151
|
+
- Source order in `auto`: direct API first, PTY fallback second. Results cached 5 minutes.
|
|
152
|
+
|
|
153
|
+
## Commands
|
|
154
|
+
|
|
155
|
+
| Invocation | Behavior |
|
|
156
|
+
|------------|----------|
|
|
157
|
+
| `agy-cli-usage` | Render the panel to stdout (human format). |
|
|
158
|
+
| `agy-cli-usage --json` | Print the `Snapshot` JSON to stdout, then exit. |
|
|
159
|
+
| `agy-cli-usage --watch [secs]` | Clear screen and re-render every `secs` (min 5, default 60). Runs forever. |
|
|
160
|
+
| `agy-cli-usage --source <auto\|api\|pty>` | `api`: API only (throws on failure). `pty`: PTY only (ignores cache). `auto`: API→PTY. |
|
|
161
|
+
| `agy-cli-usage --channel <auto\|daily\|prod>` | Cloud Code host selection. `auto` tries `daily` then `prod`. |
|
|
162
|
+
| `agy-cli-usage --no-cache` / `--refresh` | Force a fresh fetch (skip the 5-min cache). |
|
|
163
|
+
| `agy-cli-usage update [--check]` | Self-update via `npm i -g`. `--check` reports only. |
|
|
164
|
+
| `agy-cli-usage --version` / `-v` | Print version string to stdout. |
|
|
165
|
+
|
|
166
|
+
## JSON output (`--json`) — schema
|
|
167
|
+
|
|
168
|
+
```jsonc
|
|
169
|
+
{
|
|
170
|
+
"account": "you@gmail.com | null",
|
|
171
|
+
"tier": "string | null",
|
|
172
|
+
"fetchedAt": "ISO-8601 timestamp",
|
|
173
|
+
"source": "api | pty",
|
|
174
|
+
"host": "cloud code host | null",
|
|
175
|
+
"note": "string | null",
|
|
176
|
+
"groups": [
|
|
177
|
+
{
|
|
178
|
+
"name": "GEMINI MODELS",
|
|
179
|
+
"models": "comma-separated model list (may be empty)",
|
|
180
|
+
"buckets": [
|
|
181
|
+
{
|
|
182
|
+
"kind": "weekly | 5h | <other>",
|
|
183
|
+
"label": "Weekly Limit",
|
|
184
|
+
"remainingFraction": 0.9172, // 0..1, or null if unknown
|
|
185
|
+
"usedFraction": 0.0828, // 1 - remainingFraction, or null
|
|
186
|
+
"resetAt": "ISO-8601 | null",
|
|
187
|
+
"resetsInSeconds": 264180, // integer seconds, or null
|
|
188
|
+
"available": false, // true iff remainingFraction === 1
|
|
189
|
+
"description": "string | null"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Notes for parsing:
|
|
198
|
+
- Prefer `remainingFraction` (fraction remaining, 0–1). When `available` is `true`, treat as full quota (the panel shows "Quota available").
|
|
199
|
+
- `resetsInSeconds` is relative to `fetchedAt`; `resetAt` is absolute. Either may be `null`.
|
|
200
|
+
- `kind` is normalized to `weekly` / `5h` where recognized, otherwise the raw window/label string.
|
|
201
|
+
|
|
202
|
+
## HTTP API (`npm run serve` / `dist/src/server.js`)
|
|
203
|
+
|
|
204
|
+
| Route | Response |
|
|
205
|
+
|-------|----------|
|
|
206
|
+
| `GET /quota` | `200` `Snapshot` JSON (same shape as `--json`). `?refresh=1` bypasses cache. `502 {"error":...}` on failure. Headers: `Cache-Control: public, max-age=300`, `Access-Control-Allow-Origin: *`. |
|
|
207
|
+
| `GET /healthz` | `200 {"ok":true}` |
|
|
208
|
+
| (other) | `404 {"error":"not found"}` |
|
|
209
|
+
|
|
210
|
+
Binds `HOST` (default `127.0.0.1`) : `PORT` (default `3007`).
|
|
211
|
+
|
|
212
|
+
## Environment variables
|
|
213
|
+
|
|
214
|
+
| Variable | Effect |
|
|
215
|
+
|----------|--------|
|
|
216
|
+
| `AGY_OAUTH_TOKEN_FILE` | Override the token file path (headless fallback). |
|
|
217
|
+
| `AGY_BIN` | Path to the `agy` binary (PTY source). Else resolved from `PATH`, then `~/.local/bin`. |
|
|
218
|
+
| `XDG_CACHE_HOME` | Cache base dir (cache lives at `<base>/agy-usage/quota.json`; default `~/.cache`). |
|
|
219
|
+
| `NO_COLOR` | Disable ANSI color in the rendered panel. |
|
|
220
|
+
| `PORT` / `HOST` | HTTP server bind (server mode only). |
|
|
221
|
+
|
|
222
|
+
## Exit codes & errors
|
|
223
|
+
|
|
224
|
+
- `0` — success.
|
|
225
|
+
- `1` — any error (e.g. `CredentialError` when no token is readable and PTY is unavailable). Error text goes to **stderr**; structured output goes to **stdout**, so `--json` stdout is safe to parse even when stderr carries warnings (e.g. the `[api failed: …] falling back to PTY` notice in `auto` mode).
|
|
226
|
+
- `update` returns the underlying `npm` exit status.
|
|
227
|
+
|
|
228
|
+
## Data sources & cache
|
|
229
|
+
|
|
230
|
+
- **Cache**: `<XDG_CACHE_HOME|~/.cache>/agy-usage/quota.json`, TTL **5 minutes**. Avoids hammering the upstream API on `--watch`/polling. Bypassed when `source === 'pty'` or the cache is disabled (`--no-cache`/`--refresh`, or `?refresh=1` on the HTTP route).
|
|
231
|
+
- **API path** reads the token (keyring/file), then calls `loadCodeAssist` → `retrieveUserQuotaSummary`. **PTY path** drives `agy` (`python3 pty` on POSIX, `node-pty` on Windows) and needs `agy` runnable in the environment.
|
|
232
|
+
|
|
233
|
+
## Integration notes
|
|
234
|
+
|
|
235
|
+
- For automation, call `--json` (subprocess) or `GET /quota` (long-running service). Both go through the same cache, so high-frequency polling is safe.
|
|
236
|
+
- Do not parse the human panel; it contains ANSI escapes and is layout-oriented. The `Snapshot` JSON is the stable contract.
|
|
237
|
+
- The tool only **reads** credentials; it never mutates `agy`'s session or writes tokens back.
|
package/dist/src/main.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// agy-usage — Antigravity CLI (agy) usage/quota monitor.
|
|
2
|
+
// agy-cli-usage — Antigravity CLI (agy) usage/quota monitor.
|
|
3
3
|
//
|
|
4
4
|
// Usage:
|
|
5
|
-
// agy-usage one-shot panel (like agy's /usage)
|
|
6
|
-
// agy-usage --json machine-readable JSON
|
|
7
|
-
// agy-usage --watch [secs] refresh every N seconds (default 60)
|
|
8
|
-
// agy-usage --source api|pty|auto data source (default auto: api, fall back to pty)
|
|
9
|
-
// agy-usage --channel daily|prod Cloud Code host (default: auto-detect)
|
|
10
|
-
// agy-usage --no-cache bypass the 5-minute cache
|
|
11
|
-
// agy-usage --refresh force a fresh fetch (alias for --no-cache)
|
|
12
|
-
// agy-usage update [--check] self-update via npm
|
|
13
|
-
// agy-usage --version | -v print the installed version
|
|
5
|
+
// agy-cli-usage one-shot panel (like agy's /usage)
|
|
6
|
+
// agy-cli-usage --json machine-readable JSON
|
|
7
|
+
// agy-cli-usage --watch [secs] refresh every N seconds (default 60)
|
|
8
|
+
// agy-cli-usage --source api|pty|auto data source (default auto: api, fall back to pty)
|
|
9
|
+
// agy-cli-usage --channel daily|prod Cloud Code host (default: auto-detect)
|
|
10
|
+
// agy-cli-usage --no-cache bypass the 5-minute cache
|
|
11
|
+
// agy-cli-usage --refresh force a fresh fetch (alias for --no-cache)
|
|
12
|
+
// agy-cli-usage update [--check] self-update via npm
|
|
13
|
+
// agy-cli-usage --version | -v print the installed version
|
|
14
14
|
import { getAccessToken, CredentialError } from './credentials.js';
|
|
15
15
|
import { fetchQuotaSummary } from './api.js';
|
|
16
16
|
import { captureUsageViaPty } from './pty-fallback.js';
|
|
@@ -58,16 +58,16 @@ function parseArgs(argv) {
|
|
|
58
58
|
}
|
|
59
59
|
return o;
|
|
60
60
|
}
|
|
61
|
-
const HELP = `agy-usage — Antigravity CLI (agy) usage/quota monitor
|
|
61
|
+
const HELP = `agy-cli-usage — Antigravity CLI (agy) usage/quota monitor
|
|
62
62
|
|
|
63
|
-
agy-usage one-shot panel
|
|
64
|
-
agy-usage --json machine-readable JSON
|
|
65
|
-
agy-usage --watch [secs] auto-refresh (default 60s)
|
|
66
|
-
agy-usage --source <auto|api|pty>
|
|
67
|
-
agy-usage --channel <auto|daily|prod>
|
|
68
|
-
agy-usage --no-cache | --refresh
|
|
69
|
-
agy-usage update [--check] self-update via npm (--check: report only)
|
|
70
|
-
agy-usage --version | -v
|
|
63
|
+
agy-cli-usage one-shot panel
|
|
64
|
+
agy-cli-usage --json machine-readable JSON
|
|
65
|
+
agy-cli-usage --watch [secs] auto-refresh (default 60s)
|
|
66
|
+
agy-cli-usage --source <auto|api|pty>
|
|
67
|
+
agy-cli-usage --channel <auto|daily|prod>
|
|
68
|
+
agy-cli-usage --no-cache | --refresh
|
|
69
|
+
agy-cli-usage update [--check] self-update via npm (--check: report only)
|
|
70
|
+
agy-cli-usage --version | -v
|
|
71
71
|
`;
|
|
72
72
|
// --- cache -------------------------------------------------------------------
|
|
73
73
|
function readCache() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agy-cli-usage",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Headless usage/quota monitor for the Antigravity CLI (agy) — reads Cloud Code quota directly, with a PTY fallback. No IDE required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "dist/src/main.d.ts",
|