axusage 3.1.0 → 3.2.0
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 +78 -194
- package/dist/adapters/claude.js +9 -8
- package/dist/adapters/coalesce-claude-usage-response.js +5 -7
- package/dist/adapters/{chatgpt.d.ts → codex.d.ts} +1 -1
- package/dist/adapters/{chatgpt.js → codex.js} +5 -5
- package/dist/adapters/copilot.d.ts +7 -0
- package/dist/adapters/copilot.js +58 -0
- package/dist/adapters/{parse-chatgpt-usage.d.ts → parse-codex-usage.d.ts} +3 -3
- package/dist/adapters/parse-copilot-usage.d.ts +15 -0
- package/dist/adapters/parse-copilot-usage.js +61 -0
- package/dist/cli.js +3 -21
- package/dist/commands/auth-setup-command.d.ts +1 -2
- package/dist/commands/auth-setup-command.js +44 -67
- package/dist/commands/auth-status-command.js +18 -38
- package/dist/commands/fetch-service-usage.d.ts +0 -1
- package/dist/commands/fetch-service-usage.js +1 -2
- package/dist/commands/run-auth-setup.d.ts +0 -10
- package/dist/commands/run-auth-setup.js +3 -80
- package/dist/commands/usage-command.d.ts +2 -7
- package/dist/commands/usage-command.js +7 -39
- package/dist/config/credential-sources.d.ts +3 -11
- package/dist/config/credential-sources.js +1 -1
- package/dist/services/get-service-access-token.d.ts +3 -3
- package/dist/services/get-service-access-token.js +11 -11
- package/dist/services/service-adapter-registry.d.ts +2 -2
- package/dist/services/service-adapter-registry.js +4 -4
- package/dist/services/supported-service.d.ts +6 -2
- package/dist/services/supported-service.js +2 -6
- package/dist/types/{chatgpt.d.ts → codex.d.ts} +4 -4
- package/dist/types/{chatgpt.js → codex.js} +6 -6
- package/dist/types/copilot.d.ts +14 -0
- package/dist/types/copilot.js +21 -0
- package/dist/utils/check-cli-dependency.d.ts +2 -4
- package/dist/utils/check-cli-dependency.js +7 -4
- package/dist/utils/copilot-gh-token.d.ts +1 -0
- package/dist/utils/copilot-gh-token.js +38 -0
- package/dist/utils/validate-root-options.d.ts +0 -3
- package/dist/utils/validate-root-options.js +2 -6
- package/package.json +15 -19
- package/dist/adapters/github-copilot.d.ts +0 -6
- package/dist/adapters/github-copilot.js +0 -57
- package/dist/adapters/parse-github-copilot-usage.d.ts +0 -23
- package/dist/adapters/parse-github-copilot-usage.js +0 -78
- package/dist/commands/auth-clear-command.d.ts +0 -7
- package/dist/commands/auth-clear-command.js +0 -84
- package/dist/commands/fetch-service-usage-with-reauth.d.ts +0 -7
- package/dist/commands/fetch-service-usage-with-reauth.js +0 -45
- package/dist/services/app-paths.d.ts +0 -9
- package/dist/services/app-paths.js +0 -39
- package/dist/services/auth-storage-path.d.ts +0 -3
- package/dist/services/auth-storage-path.js +0 -7
- package/dist/services/auth-timeouts.d.ts +0 -4
- package/dist/services/auth-timeouts.js +0 -4
- package/dist/services/browser-auth-manager.d.ts +0 -49
- package/dist/services/browser-auth-manager.js +0 -113
- package/dist/services/create-auth-context.d.ts +0 -8
- package/dist/services/create-auth-context.js +0 -35
- package/dist/services/do-setup-auth.d.ts +0 -3
- package/dist/services/do-setup-auth.js +0 -19
- package/dist/services/fetch-json-with-context.d.ts +0 -5
- package/dist/services/fetch-json-with-context.js +0 -37
- package/dist/services/launch-chromium.d.ts +0 -6
- package/dist/services/launch-chromium.js +0 -20
- package/dist/services/persist-storage-state.d.ts +0 -6
- package/dist/services/persist-storage-state.js +0 -16
- package/dist/services/request-service.d.ts +0 -3
- package/dist/services/request-service.js +0 -4
- package/dist/services/service-auth-configs.d.ts +0 -15
- package/dist/services/service-auth-configs.js +0 -26
- package/dist/services/setup-auth-flow.d.ts +0 -3
- package/dist/services/setup-auth-flow.js +0 -67
- package/dist/services/shared-browser-auth-manager.d.ts +0 -4
- package/dist/services/shared-browser-auth-manager.js +0 -87
- package/dist/services/verify-session.d.ts +0 -2
- package/dist/services/verify-session.js +0 -27
- package/dist/services/wait-for-login.d.ts +0 -6
- package/dist/services/wait-for-login.js +0 -115
- package/dist/types/github-copilot.d.ts +0 -21
- package/dist/types/github-copilot.js +0 -27
- package/dist/utils/resolve-prompt-capability.d.ts +0 -1
- package/dist/utils/resolve-prompt-capability.js +0 -3
- package/dist/utils/write-atomic-json.d.ts +0 -1
- package/dist/utils/write-atomic-json.js +0 -56
- /package/dist/adapters/{parse-chatgpt-usage.js → parse-codex-usage.js} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# axusage
|
|
2
2
|
|
|
3
|
-
Monitor
|
|
3
|
+
Monitor API usage across Claude, ChatGPT, GitHub Copilot, and Gemini from a single CLI.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -8,127 +8,72 @@ Monitor AI usage across Claude, ChatGPT, GitHub Copilot, and Gemini from a singl
|
|
|
8
8
|
# Install globally
|
|
9
9
|
npm install -g axusage
|
|
10
10
|
|
|
11
|
-
#
|
|
11
|
+
# One-time authentication per provider
|
|
12
12
|
claude
|
|
13
13
|
codex
|
|
14
14
|
gemini
|
|
15
|
-
|
|
15
|
+
gh auth login
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# Optional: print service-specific auth instructions
|
|
18
|
+
axusage --auth-setup copilot
|
|
19
|
+
|
|
20
|
+
# Check auth status
|
|
18
21
|
axusage --auth-status
|
|
19
|
-
# For CLI-auth services, this reports CLI availability; use the CLI to confirm login.
|
|
20
22
|
|
|
21
|
-
# Fetch usage
|
|
23
|
+
# Fetch usage for all services
|
|
22
24
|
axusage
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
## Requirements
|
|
26
28
|
|
|
27
|
-
- `claude` CLI (Claude auth)
|
|
28
|
-
- `codex` CLI (ChatGPT auth)
|
|
29
|
-
- `gemini` CLI (Gemini auth)
|
|
30
|
-
-
|
|
29
|
+
- `claude` CLI (Claude auth) - `npm install -g @anthropic-ai/claude-code`
|
|
30
|
+
- `codex` CLI (ChatGPT auth) - `npm install -g @openai/codex`
|
|
31
|
+
- `gemini` CLI (Gemini auth) - `npm install -g @google/gemini-cli`
|
|
32
|
+
- `gh` CLI (GitHub Copilot auth) - `https://cli.github.com/` or `brew install gh`
|
|
31
33
|
|
|
32
34
|
### Custom Paths
|
|
33
35
|
|
|
34
|
-
If
|
|
36
|
+
If CLIs are not on your `PATH`, override binary paths:
|
|
35
37
|
|
|
36
38
|
```bash
|
|
37
39
|
export AXUSAGE_CLAUDE_PATH=/path/to/claude
|
|
38
40
|
export AXUSAGE_CODEX_PATH=/path/to/codex
|
|
39
41
|
export AXUSAGE_GEMINI_PATH=/path/to/gemini
|
|
42
|
+
export AXUSAGE_GH_PATH=/path/to/gh
|
|
40
43
|
|
|
41
|
-
# Optional:
|
|
44
|
+
# Optional: dependency check timeout (milliseconds, default: 5000)
|
|
42
45
|
export AXUSAGE_CLI_TIMEOUT_MS=5000
|
|
43
46
|
```
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
export PLAYWRIGHT_BROWSERS_PATH=/path/to/playwright-browsers
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Exit Codes
|
|
52
|
-
|
|
53
|
-
- `0`: success
|
|
54
|
-
- `1`: errors, including partial failures
|
|
48
|
+
`AXUSAGE_GH_PATH` is also used as a Copilot fallback when resolving a token
|
|
49
|
+
via `gh auth token`.
|
|
55
50
|
|
|
56
51
|
## Authentication
|
|
57
52
|
|
|
58
|
-
|
|
59
|
-
Copilot uses browser-based authentication for persistent, long-lived sessions.
|
|
60
|
-
|
|
61
|
-
**Setup (one-time per service):**
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
# Set up authentication for each service
|
|
65
|
-
claude
|
|
66
|
-
codex
|
|
67
|
-
gemini
|
|
68
|
-
axusage --auth-setup github-copilot --interactive
|
|
69
|
-
|
|
70
|
-
# Check authentication status
|
|
71
|
-
axusage --auth-status
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
`--auth-status` reports browser-auth status for GitHub Copilot and CLI availability
|
|
75
|
-
for Claude/ChatGPT/Gemini. Use `claude`, `codex`, or `gemini` to confirm CLI login.
|
|
76
|
-
|
|
77
|
-
When you run `axusage --auth-setup github-copilot --interactive`, a browser window will open.
|
|
78
|
-
Simply log in to GitHub as you normally would. Your authentication will be
|
|
79
|
-
saved and automatically used for future requests.
|
|
80
|
-
|
|
81
|
-
**Authenticated sessions directory (via [`env-paths`](https://github.com/sindresorhus/env-paths)):**
|
|
82
|
-
|
|
83
|
-
- Linux: `~/.local/share/axusage/browser-contexts/` (or `$XDG_DATA_HOME/axusage/browser-contexts/`)
|
|
84
|
-
- macOS: `~/Library/Application Support/axusage/browser-contexts/`
|
|
85
|
-
- Windows: `%LOCALAPPDATA%\axusage\Data\browser-contexts\`
|
|
53
|
+
Authentication is managed by provider CLIs for all services.
|
|
86
54
|
|
|
87
|
-
|
|
55
|
+
- Claude: `claude`
|
|
56
|
+
- ChatGPT: `codex`
|
|
57
|
+
- Gemini: `gemini`
|
|
58
|
+
- GitHub Copilot: `gh auth login`
|
|
88
59
|
|
|
89
|
-
|
|
90
|
-
>
|
|
91
|
-
> - Linux/macOS: `mkdir -p ~/.local/share/axusage/ && cp -r ~/.local/share/agent-usage/* ~/.local/share/axusage/`
|
|
92
|
-
> - Windows: Copy from `%LOCALAPPDATA%\agent-usage\` to `%LOCALAPPDATA%\axusage\`
|
|
93
|
-
|
|
94
|
-
Security notes:
|
|
95
|
-
|
|
96
|
-
- Files in this directory contain sensitive session data. They are created with owner-only permissions (0600 for files, 0700 for the directory) where possible.
|
|
97
|
-
- To revoke access for GitHub Copilot, clear saved browser auth:
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
axusage --auth-clear github-copilot --interactive
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
This moves the saved browser files to your system Trash/Recycle Bin (recoverable).
|
|
104
|
-
|
|
105
|
-
Use `--force` to skip confirmation in scripts.
|
|
106
|
-
|
|
107
|
-
Browser installation:
|
|
108
|
-
|
|
109
|
-
- Playwright Chromium is installed automatically on `pnpm install` via a postinstall script. If this fails in your environment, install manually:
|
|
60
|
+
Use:
|
|
110
61
|
|
|
111
62
|
```bash
|
|
112
|
-
|
|
63
|
+
axusage --auth-setup <service>
|
|
113
64
|
```
|
|
114
65
|
|
|
115
|
-
|
|
66
|
+
to print the correct command for a given service.
|
|
116
67
|
|
|
117
|
-
|
|
68
|
+
Check auth status with:
|
|
118
69
|
|
|
119
70
|
```bash
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
pnpm add -g axusage # Reinstall to run postinstall
|
|
71
|
+
axusage --auth-status
|
|
72
|
+
axusage --auth-status claude
|
|
123
73
|
```
|
|
124
74
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
pnpm add -g axusage
|
|
129
|
-
PLAYWRIGHT_BIN="$(pnpm root -g)/axusage/node_modules/.bin/playwright"
|
|
130
|
-
"$PLAYWRIGHT_BIN" install chromium --with-deps
|
|
131
|
-
```
|
|
75
|
+
`--auth-status` checks whether each service is authenticated and reports the
|
|
76
|
+
detected auth method. It does not validate API token freshness.
|
|
132
77
|
|
|
133
78
|
## Usage
|
|
134
79
|
|
|
@@ -136,165 +81,104 @@ PLAYWRIGHT_BIN="$(pnpm root -g)/axusage/node_modules/.bin/playwright"
|
|
|
136
81
|
# Query all services
|
|
137
82
|
axusage
|
|
138
83
|
|
|
139
|
-
#
|
|
140
|
-
axusage --interactive
|
|
141
|
-
|
|
142
|
-
# Single service
|
|
84
|
+
# Query a single service
|
|
143
85
|
axusage --service claude
|
|
144
|
-
axusage
|
|
145
|
-
axusage
|
|
86
|
+
axusage -s codex
|
|
87
|
+
axusage -s copilot
|
|
146
88
|
|
|
147
|
-
#
|
|
148
|
-
axusage --format
|
|
149
|
-
axusage --
|
|
89
|
+
# Output formats
|
|
90
|
+
axusage --format text
|
|
91
|
+
axusage --format tsv
|
|
92
|
+
axusage --format json
|
|
93
|
+
axusage --format prometheus
|
|
150
94
|
|
|
151
|
-
#
|
|
152
|
-
axusage --
|
|
95
|
+
# Auth utilities
|
|
96
|
+
axusage --auth-setup claude
|
|
97
|
+
axusage --auth-status
|
|
153
98
|
|
|
154
99
|
# Disable color output
|
|
155
100
|
axusage --no-color
|
|
156
101
|
```
|
|
157
102
|
|
|
103
|
+
### Exit Codes
|
|
104
|
+
|
|
105
|
+
- `0`: Success
|
|
106
|
+
- `1`: One or more failures (including partial failures)
|
|
107
|
+
|
|
108
|
+
## Credential Sources
|
|
109
|
+
|
|
110
|
+
Credential source config is read from:
|
|
111
|
+
|
|
112
|
+
- Config file path shown in `axusage --help`
|
|
113
|
+
- `AXUSAGE_SOURCES` environment variable (JSON), which overrides file config
|
|
114
|
+
|
|
158
115
|
## Examples
|
|
159
116
|
|
|
160
117
|
### Extract service and utilization (TSV + awk)
|
|
161
118
|
|
|
162
119
|
```bash
|
|
163
|
-
axusage --format
|
|
120
|
+
axusage --format tsv | tail -n +2 | awk -F'\t' '{print $1, $4"%"}'
|
|
164
121
|
```
|
|
165
122
|
|
|
166
123
|
### Count windows by service (TSV + cut/sort/uniq)
|
|
167
124
|
|
|
168
125
|
```bash
|
|
169
|
-
axusage --format
|
|
126
|
+
axusage --format tsv | tail -n +2 | cut -f1 | sort | uniq -c
|
|
170
127
|
```
|
|
171
128
|
|
|
172
129
|
### Filter by utilization threshold (TSV + awk)
|
|
173
130
|
|
|
174
131
|
```bash
|
|
175
|
-
axusage --format
|
|
132
|
+
axusage --format tsv | tail -n +2 | awk -F'\t' '$4 > 50 {print $1, $3, $4"%"}'
|
|
176
133
|
```
|
|
177
134
|
|
|
178
135
|
### Extract utilization as JSON (JSON + jq)
|
|
179
136
|
|
|
180
137
|
```bash
|
|
181
|
-
axusage --format
|
|
138
|
+
axusage --format json \
|
|
182
139
|
| jq -r '(.results? // .) | (if type=="array" then . else [.] end) | .[] | .windows[] | [.name, (.utilization|tostring)] | @tsv'
|
|
183
140
|
```
|
|
184
141
|
|
|
185
142
|
## Output
|
|
186
143
|
|
|
187
|
-
Human-readable
|
|
144
|
+
Human-readable output includes:
|
|
188
145
|
|
|
189
|
-
- Utilization percentage per window
|
|
146
|
+
- Utilization percentage per window
|
|
190
147
|
- Usage rate vs expected rate
|
|
191
148
|
- Reset times
|
|
192
|
-
- Color coding:
|
|
193
|
-
|
|
194
|
-
JSON format returns structured data for programmatic use.
|
|
195
|
-
|
|
196
|
-
## Agent Rule
|
|
149
|
+
- Color coding: on track / over budget / significantly over
|
|
197
150
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
```markdown
|
|
201
|
-
# Rule: `axusage` Usage
|
|
202
|
-
|
|
203
|
-
Run `npx -y axusage --help` to learn available options.
|
|
204
|
-
|
|
205
|
-
Use `axusage` when you need a quick, scriptable snapshot of API usage across Claude, ChatGPT, GitHub Copilot, and Gemini. It standardizes output (text, JSON, Prometheus) so you can alert, dashboard, or pipe it into other Unix tools.
|
|
206
|
-
```
|
|
151
|
+
JSON output provides structured data for automation.
|
|
152
|
+
Prometheus output emits text metrics suitable for scraping.
|
|
207
153
|
|
|
208
154
|
## Troubleshooting
|
|
209
155
|
|
|
210
|
-
###
|
|
211
|
-
|
|
212
|
-
- The CLI shows a countdown while waiting for login.
|
|
213
|
-
- If you have completed login, press Enter in the terminal to continue.
|
|
214
|
-
- If it still fails, run `axusage --auth-clear <service> --interactive` and retry.
|
|
215
|
-
|
|
216
|
-
### "No saved authentication" error
|
|
217
|
-
|
|
218
|
-
- Check which services are authenticated: `axusage --auth-status`.
|
|
219
|
-
- For GitHub Copilot, set up the missing service: `axusage --auth-setup <service> --interactive`.
|
|
220
|
-
- For Claude/ChatGPT/Gemini, run the provider CLI to authenticate.
|
|
221
|
-
|
|
222
|
-
### Sessions expire
|
|
223
|
-
|
|
224
|
-
- Browser sessions can expire based on provider policy. Re-run `axusage --auth-setup <service> --interactive` for the affected service when you see authentication errors.
|
|
156
|
+
### "Required dependency '... not found'"
|
|
225
157
|
|
|
226
|
-
|
|
158
|
+
Install the missing CLI or set the corresponding override env var (for example, `AXUSAGE_GH_PATH`).
|
|
227
159
|
|
|
228
|
-
|
|
160
|
+
### Authentication errors (401 / unauthorized / no saved authentication)
|
|
229
161
|
|
|
230
|
-
|
|
162
|
+
1. Run `axusage --auth-status` to see which services are not authenticated.
|
|
163
|
+
2. Re-authenticate in the provider CLI (`claude`, `codex`, `gemini`, `gh auth login`).
|
|
164
|
+
3. Retry `axusage`.
|
|
231
165
|
|
|
232
|
-
|
|
233
|
-
auth for GitHub Copilot:
|
|
166
|
+
### Partial failures
|
|
234
167
|
|
|
235
|
-
|
|
236
|
-
npm install -g axusage
|
|
168
|
+
`axusage` exits with code `1` if any service fails, even when other services succeed. Check warnings in stderr for the failed service(s).
|
|
237
169
|
|
|
238
|
-
|
|
239
|
-
codex
|
|
240
|
-
gemini
|
|
241
|
-
axusage --auth-setup github-copilot --interactive
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
2. Confirm the workstation has valid sessions:
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
axusage --auth-status
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
For CLI-auth services, run `claude`, `codex`, or `gemini` to confirm login.
|
|
251
|
-
|
|
252
|
-
3. Package the saved contexts so they can be transferred. Set `CONTEXT_DIR` to the path for your platform (see the table above):
|
|
253
|
-
|
|
254
|
-
```bash
|
|
255
|
-
CONTEXT_DIR="$HOME/.local/share/axusage/browser-contexts" # Linux default; adjust on macOS/Windows
|
|
256
|
-
tar czf axusage-contexts.tgz -C "$(dirname "$CONTEXT_DIR")" "$(basename "$CONTEXT_DIR")"
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
Archive structure: `browser-contexts/github-copilot-auth.json` plus matching
|
|
260
|
-
`github-copilot-auth.meta.json` (CLI-auth services do not use browser contexts).
|
|
261
|
-
|
|
262
|
-
### 2. Transfer the browser contexts to the Linux server
|
|
263
|
-
|
|
264
|
-
1. Copy the archive to the server with `scp` (replace `user@server` with your login):
|
|
265
|
-
|
|
266
|
-
```bash
|
|
267
|
-
scp axusage-contexts.tgz user@server:~/
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
2. On the server, create the target directory if it does not already exist, unpack the archive, and lock down the permissions:
|
|
271
|
-
|
|
272
|
-
```bash
|
|
273
|
-
ssh user@server
|
|
274
|
-
CONTEXT_DIR="$HOME/.local/share/axusage/browser-contexts" # Linux default; adjust per platform
|
|
275
|
-
AXUSAGE_DIR="$(dirname "$CONTEXT_DIR")"
|
|
276
|
-
mkdir -p "$CONTEXT_DIR"
|
|
277
|
-
tar xzf ~/axusage-contexts.tgz -C "$AXUSAGE_DIR"
|
|
278
|
-
# Directories 700, files 600
|
|
279
|
-
find "$AXUSAGE_DIR" -type d -exec chmod 700 {} +
|
|
280
|
-
find "$CONTEXT_DIR" -type f -exec chmod 600 {} +
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
3. Verify that the sessions are available on the server:
|
|
170
|
+
## Agent Rule
|
|
284
171
|
|
|
285
|
-
|
|
286
|
-
axusage --auth-status
|
|
287
|
-
```
|
|
172
|
+
Add to your `CLAUDE.md` or `AGENTS.md`:
|
|
288
173
|
|
|
289
|
-
|
|
174
|
+
```markdown
|
|
175
|
+
# Rule: `axusage` Usage
|
|
290
176
|
|
|
291
|
-
|
|
177
|
+
Run `npx -y axusage --help` to learn available options.
|
|
292
178
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
- If you transfer browser contexts between machines, ensure the target system is secure and permissions are restricted to the intended user.
|
|
296
|
-
- The CLI stores authentication data in the platform-specific directories listed above; protect that directory to prevent unauthorized access.
|
|
179
|
+
Use `axusage` when you need a quick, scriptable snapshot of API usage across Claude, ChatGPT, GitHub Copilot, and Gemini. It standardizes output (text, JSON, Prometheus) so you can alert, dashboard, or pipe it into other Unix tools.
|
|
180
|
+
```
|
|
297
181
|
|
|
298
182
|
## Development
|
|
299
183
|
|
|
300
|
-
For local development in this repository, `pnpm run start` triggers a clean rebuild before executing the CLI. Use `
|
|
184
|
+
For local development in this repository, `pnpm run start` triggers a clean rebuild before executing the CLI. Use `node bin/axusage` only when `dist/` is already up to date. End users installing globally should run the `axusage` binary directly.
|
package/dist/adapters/claude.js
CHANGED
|
@@ -51,12 +51,15 @@ export const claudeAdapter = {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
try {
|
|
54
|
-
const response = await
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
const [response, planType] = await Promise.all([
|
|
55
|
+
fetch(USAGE_API_URL, {
|
|
56
|
+
headers: {
|
|
57
|
+
Authorization: `Bearer ${accessToken}`,
|
|
58
|
+
"anthropic-beta": ANTHROPIC_BETA_HEADER,
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
fetchPlanType(accessToken),
|
|
62
|
+
]);
|
|
60
63
|
if (!response.ok) {
|
|
61
64
|
const errorText = await response.text().catch(() => "");
|
|
62
65
|
return {
|
|
@@ -76,8 +79,6 @@ export const claudeAdapter = {
|
|
|
76
79
|
error: new ApiError(`Invalid response format: ${parseResult.error.message}`, undefined, data),
|
|
77
80
|
};
|
|
78
81
|
}
|
|
79
|
-
// Fetch plan type (best effort, don't fail if unavailable)
|
|
80
|
-
const planType = await fetchPlanType(accessToken);
|
|
81
82
|
const usageData = toServiceUsageData(parseResult.data);
|
|
82
83
|
return {
|
|
83
84
|
ok: true,
|
|
@@ -47,12 +47,15 @@ const resolveUtilization = (candidate) => {
|
|
|
47
47
|
return candidate.utilization;
|
|
48
48
|
return candidate.percentage ?? candidate.percent ?? 0;
|
|
49
49
|
};
|
|
50
|
-
const selectMetric = (candidates, matchers) => {
|
|
50
|
+
const selectMetric = (candidates, matchers, exclude = []) => {
|
|
51
51
|
for (const candidate of candidates) {
|
|
52
52
|
const label = normalizeLabel(candidate);
|
|
53
53
|
if (!label)
|
|
54
54
|
continue;
|
|
55
55
|
const tokens = tokenizeLabel(label);
|
|
56
|
+
const hasExcludedToken = exclude.some((ex) => tokens.has(ex) || label.includes(ex));
|
|
57
|
+
if (hasExcludedToken)
|
|
58
|
+
continue;
|
|
56
59
|
const matches = matchers.includes(label) ||
|
|
57
60
|
matchers.some((matcher) => tokens.has(matcher));
|
|
58
61
|
if (!matches)
|
|
@@ -88,12 +91,7 @@ export function coalesceClaudeUsageResponse(data) {
|
|
|
88
91
|
"5",
|
|
89
92
|
"5hour",
|
|
90
93
|
]);
|
|
91
|
-
const sevenDay = selectMetric(candidates, [
|
|
92
|
-
"seven_day",
|
|
93
|
-
"seven",
|
|
94
|
-
"7",
|
|
95
|
-
"week",
|
|
96
|
-
]);
|
|
94
|
+
const sevenDay = selectMetric(candidates, ["seven_day", "seven", "7", "week"], ["opus", "sonnet", "oauth"]);
|
|
97
95
|
const sevenDayOpus = selectMetric(candidates, ["seven_day_opus", "opus"]);
|
|
98
96
|
const sevenDaySonnet = selectMetric(candidates, [
|
|
99
97
|
"seven_day_sonnet",
|
|
@@ -5,4 +5,4 @@ import type { ServiceAdapter } from "../types/domain.js";
|
|
|
5
5
|
* Uses the OAuth token from Codex CLI's credential store (~/.codex/auth.json)
|
|
6
6
|
* to make direct API calls to ChatGPT's usage endpoint.
|
|
7
7
|
*/
|
|
8
|
-
export declare const
|
|
8
|
+
export declare const codexAdapter: ServiceAdapter;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ApiError } from "../types/domain.js";
|
|
2
2
|
import { getServiceAccessToken } from "../services/get-service-access-token.js";
|
|
3
|
-
import {
|
|
4
|
-
import { toServiceUsageData } from "./parse-
|
|
3
|
+
import { CodexUsageResponse as CodexUsageResponseSchema } from "../types/codex.js";
|
|
4
|
+
import { toServiceUsageData } from "./parse-codex-usage.js";
|
|
5
5
|
const API_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
6
6
|
/**
|
|
7
7
|
* ChatGPT service adapter using direct API access.
|
|
@@ -9,10 +9,10 @@ const API_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
|
9
9
|
* Uses the OAuth token from Codex CLI's credential store (~/.codex/auth.json)
|
|
10
10
|
* to make direct API calls to ChatGPT's usage endpoint.
|
|
11
11
|
*/
|
|
12
|
-
export const
|
|
12
|
+
export const codexAdapter = {
|
|
13
13
|
name: "ChatGPT",
|
|
14
14
|
async fetchUsage() {
|
|
15
|
-
const accessToken = await getServiceAccessToken("
|
|
15
|
+
const accessToken = await getServiceAccessToken("codex");
|
|
16
16
|
if (!accessToken) {
|
|
17
17
|
return {
|
|
18
18
|
ok: false,
|
|
@@ -33,7 +33,7 @@ export const chatGPTAdapter = {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
const data = await response.json();
|
|
36
|
-
const parseResult =
|
|
36
|
+
const parseResult = CodexUsageResponseSchema.safeParse(data);
|
|
37
37
|
if (!parseResult.success) {
|
|
38
38
|
return {
|
|
39
39
|
ok: false,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ServiceAdapter } from "../types/domain.js";
|
|
2
|
+
/**
|
|
3
|
+
* GitHub Copilot service adapter using token-based API access.
|
|
4
|
+
*
|
|
5
|
+
* Credentials resolved via getServiceAccessToken (vault, local axauth, gh CLI).
|
|
6
|
+
*/
|
|
7
|
+
export declare const copilotAdapter: ServiceAdapter;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ApiError } from "../types/domain.js";
|
|
2
|
+
import { CopilotUsageResponse as CopilotUsageResponseSchema } from "../types/copilot.js";
|
|
3
|
+
import { toServiceUsageData } from "./parse-copilot-usage.js";
|
|
4
|
+
import { getServiceAccessToken } from "../services/get-service-access-token.js";
|
|
5
|
+
// Internal/undocumented GitHub API used by VS Code, JetBrains, and other
|
|
6
|
+
// first-party Copilot integrations. May change without notice.
|
|
7
|
+
const API_URL = "https://api.github.com/copilot_internal/user";
|
|
8
|
+
/**
|
|
9
|
+
* GitHub Copilot service adapter using token-based API access.
|
|
10
|
+
*
|
|
11
|
+
* Credentials resolved via getServiceAccessToken (vault, local axauth, gh CLI).
|
|
12
|
+
*/
|
|
13
|
+
export const copilotAdapter = {
|
|
14
|
+
name: "GitHub Copilot",
|
|
15
|
+
async fetchUsage() {
|
|
16
|
+
const accessToken = await getServiceAccessToken("copilot");
|
|
17
|
+
if (!accessToken) {
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
error: new ApiError("No GitHub Copilot credentials found. Run 'gh auth login' to authenticate."),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(API_URL, {
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${accessToken}`,
|
|
27
|
+
Accept: "application/json",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
const errorText = await response.text().catch(() => "");
|
|
32
|
+
return {
|
|
33
|
+
ok: false,
|
|
34
|
+
error: new ApiError(`GitHub Copilot API request failed: ${String(response.status)} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`, response.status),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
const parseResult = CopilotUsageResponseSchema.safeParse(data);
|
|
39
|
+
if (!parseResult.success) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
error: new ApiError(`Invalid response format: ${parseResult.error.message}`, undefined, data),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
value: toServiceUsageData(parseResult.data),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
error: new ApiError(`Failed to fetch GitHub Copilot usage: ${message}`),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ServiceUsageData } from "../types/domain.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { CodexUsageResponse, CodexRateLimitWindow } from "../types/codex.js";
|
|
3
3
|
/**
|
|
4
4
|
* Converts a ChatGPT rate limit window to common usage window
|
|
5
5
|
*/
|
|
6
|
-
export declare function toUsageWindow(name: string, window:
|
|
6
|
+
export declare function toUsageWindow(name: string, window: CodexRateLimitWindow): {
|
|
7
7
|
name: string;
|
|
8
8
|
utilization: number;
|
|
9
9
|
resetsAt: Date;
|
|
@@ -12,4 +12,4 @@ export declare function toUsageWindow(name: string, window: ChatGPTRateLimitWind
|
|
|
12
12
|
/**
|
|
13
13
|
* Converts ChatGPT response to common domain model
|
|
14
14
|
*/
|
|
15
|
-
export declare function toServiceUsageData(response:
|
|
15
|
+
export declare function toServiceUsageData(response: CodexUsageResponse): ServiceUsageData;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ServiceUsageData } from "../types/domain.js";
|
|
2
|
+
import type { CopilotUsageResponse } from "../types/copilot.js";
|
|
3
|
+
/**
|
|
4
|
+
* Calculates monthly period duration ending at the reset date.
|
|
5
|
+
*
|
|
6
|
+
* Determines the period start by going back one month from the reset
|
|
7
|
+
* date and clamping the day to the last valid day of that previous
|
|
8
|
+
* month. This handles edge cases like Jan 31 → Feb 28/29 where the
|
|
9
|
+
* target month has fewer days than the reset date's day component.
|
|
10
|
+
*/
|
|
11
|
+
export declare function calculatePeriodDuration(resetDate: Date): number;
|
|
12
|
+
/**
|
|
13
|
+
* Converts GitHub Copilot API response to common domain model.
|
|
14
|
+
*/
|
|
15
|
+
export declare function toServiceUsageData(response: CopilotUsageResponse): ServiceUsageData;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
2
|
+
/**
|
|
3
|
+
* Calculates monthly period duration ending at the reset date.
|
|
4
|
+
*
|
|
5
|
+
* Determines the period start by going back one month from the reset
|
|
6
|
+
* date and clamping the day to the last valid day of that previous
|
|
7
|
+
* month. This handles edge cases like Jan 31 → Feb 28/29 where the
|
|
8
|
+
* target month has fewer days than the reset date's day component.
|
|
9
|
+
*/
|
|
10
|
+
export function calculatePeriodDuration(resetDate) {
|
|
11
|
+
const periodEnd = resetDate.getTime();
|
|
12
|
+
const year = resetDate.getUTCFullYear();
|
|
13
|
+
const month = resetDate.getUTCMonth();
|
|
14
|
+
const day = resetDate.getUTCDate();
|
|
15
|
+
const firstOfCurrentMonth = Date.UTC(year, month, 1, 0, 0, 0);
|
|
16
|
+
const lastPreviousMonthDate = new Date(firstOfCurrentMonth - MS_PER_DAY);
|
|
17
|
+
const lastPreviousMonthDay = lastPreviousMonthDate.getUTCDate();
|
|
18
|
+
const previousMonth = lastPreviousMonthDate.getUTCMonth();
|
|
19
|
+
const previousYear = lastPreviousMonthDate.getUTCFullYear();
|
|
20
|
+
const targetDay = Math.min(day, lastPreviousMonthDay);
|
|
21
|
+
const periodStart = Date.UTC(previousYear, previousMonth, targetDay, resetDate.getUTCHours(), resetDate.getUTCMinutes(), resetDate.getUTCSeconds(), resetDate.getUTCMilliseconds());
|
|
22
|
+
return Math.max(periodEnd - periodStart, 0);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Converts GitHub Copilot API response to common domain model.
|
|
26
|
+
*/
|
|
27
|
+
export function toServiceUsageData(response) {
|
|
28
|
+
const { premium_interactions } = response.quota_snapshots;
|
|
29
|
+
if (premium_interactions.unlimited) {
|
|
30
|
+
return {
|
|
31
|
+
service: "GitHub Copilot",
|
|
32
|
+
planType: response.copilot_plan,
|
|
33
|
+
windows: [
|
|
34
|
+
{
|
|
35
|
+
name: "Monthly Premium Interactions",
|
|
36
|
+
utilization: 0,
|
|
37
|
+
resetsAt: undefined,
|
|
38
|
+
periodDurationMs: 0,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const resetDate = new Date(response.quota_reset_date_utc);
|
|
44
|
+
const periodDurationMs = calculatePeriodDuration(resetDate);
|
|
45
|
+
const used = premium_interactions.entitlement - premium_interactions.remaining;
|
|
46
|
+
const utilization = premium_interactions.entitlement === 0
|
|
47
|
+
? 0
|
|
48
|
+
: (used / premium_interactions.entitlement) * 100;
|
|
49
|
+
return {
|
|
50
|
+
service: "GitHub Copilot",
|
|
51
|
+
planType: response.copilot_plan,
|
|
52
|
+
windows: [
|
|
53
|
+
{
|
|
54
|
+
name: "Monthly Premium Interactions",
|
|
55
|
+
utilization: Math.round(utilization * 100) / 100,
|
|
56
|
+
resetsAt: resetDate,
|
|
57
|
+
periodDurationMs,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|