aiquota 0.2.0__tar.gz
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.
- aiquota-0.2.0/LICENSE +21 -0
- aiquota-0.2.0/PKG-INFO +376 -0
- aiquota-0.2.0/README.md +357 -0
- aiquota-0.2.0/aiquota/__init__.py +8 -0
- aiquota-0.2.0/aiquota/__main__.py +3 -0
- aiquota-0.2.0/aiquota/adapters/__init__.py +1 -0
- aiquota-0.2.0/aiquota/adapters/_http.py +61 -0
- aiquota-0.2.0/aiquota/adapters/browser_read.py +138 -0
- aiquota-0.2.0/aiquota/adapters/chatgpt.py +178 -0
- aiquota-0.2.0/aiquota/adapters/claude.py +246 -0
- aiquota-0.2.0/aiquota/adapters/copilot.py +140 -0
- aiquota-0.2.0/aiquota/adapters/elevenlabs.py +74 -0
- aiquota-0.2.0/aiquota/adapters/manual.py +74 -0
- aiquota-0.2.0/aiquota/adapters/openrouter.py +85 -0
- aiquota-0.2.0/aiquota/adapters/session_based.py +200 -0
- aiquota-0.2.0/aiquota/assets/logos.json +1 -0
- aiquota-0.2.0/aiquota/browser_login.py +368 -0
- aiquota-0.2.0/aiquota/catalog.py +199 -0
- aiquota-0.2.0/aiquota/cli.py +656 -0
- aiquota-0.2.0/aiquota/core.py +357 -0
- aiquota-0.2.0/aiquota/guidialog.py +277 -0
- aiquota-0.2.0/aiquota/guipick.py +339 -0
- aiquota-0.2.0/aiquota/install_widget.py +143 -0
- aiquota-0.2.0/aiquota/login_policy.py +110 -0
- aiquota-0.2.0/aiquota/oauth.py +144 -0
- aiquota-0.2.0/aiquota/picker.py +569 -0
- aiquota-0.2.0/aiquota/remove_ui.py +97 -0
- aiquota-0.2.0/aiquota/render.py +127 -0
- aiquota-0.2.0/aiquota/widgets/add_account.sh +13 -0
- aiquota-0.2.0/aiquota/widgets/aiquota.5m.sh +20 -0
- aiquota-0.2.0/aiquota/widgets/aiquota.jsx +564 -0
- aiquota-0.2.0/aiquota/widgets/aiquota_render.py +126 -0
- aiquota-0.2.0/aiquota.egg-info/PKG-INFO +376 -0
- aiquota-0.2.0/aiquota.egg-info/SOURCES.txt +38 -0
- aiquota-0.2.0/aiquota.egg-info/dependency_links.txt +1 -0
- aiquota-0.2.0/aiquota.egg-info/entry_points.txt +4 -0
- aiquota-0.2.0/aiquota.egg-info/top_level.txt +1 -0
- aiquota-0.2.0/pyproject.toml +36 -0
- aiquota-0.2.0/setup.cfg +4 -0
- aiquota-0.2.0/tests/test_aiquota.py +1331 -0
aiquota-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anuj Patel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aiquota-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aiquota
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: See how much of every AI subscription you've used, in one place.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/anujpatel06/aiquota
|
|
7
|
+
Project-URL: Issues, https://github.com/anujpatel06/aiquota/issues
|
|
8
|
+
Keywords: ai,quota,usage,claude,chatgpt,subscription,cli
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# aiquota
|
|
21
|
+
|
|
22
|
+
**See how much of every AI subscription you've used — in one place.**
|
|
23
|
+
|
|
24
|
+
Checking whether you're about to hit a limit means opening Claude's settings,
|
|
25
|
+
then ChatGPT's, then whatever else you pay for. `aiquota` puts every quota in
|
|
26
|
+
one widget, one menu bar item, and one command.
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<img src="docs/img/widget.png" width="440" alt="aiquota desktop widget showing Claude and ChatGPT usage">
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
$ aiquota
|
|
34
|
+
|
|
35
|
+
Claude [live]
|
|
36
|
+
5-hour session █████████░░░░░░░░░░░░░░░ 37.0% resets Wed 20:30
|
|
37
|
+
Weekly (all) █████░░░░░░░░░░░░░░░░░░░ 22.0% resets Mon 00:30
|
|
38
|
+
binding: five_hour · overage: rejected
|
|
39
|
+
|
|
40
|
+
ChatGPT ChatGPT (team) [live]
|
|
41
|
+
5-hour ███████████████░░░░░░░░░ 64.0% resets Wed 18:34
|
|
42
|
+
7-day ███████░░░░░░░░░░░░░░░░░ 28.0% resets Tue 11:39
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- **Sign in, don't paste keys.** Pick a platform and its own login page opens.
|
|
46
|
+
You choose the account; aiquota never sees a password.
|
|
47
|
+
- **No dependencies.** Pure Python stdlib, so `pip install` can't break.
|
|
48
|
+
- **Never invents a number.** Every card is tagged `live`, `manual`, or
|
|
49
|
+
`error`. If a provider exposes no counter, it says so instead of showing a
|
|
50
|
+
plausible percentage.
|
|
51
|
+
- **Respects provider terms.** Where a provider forbids third-party sign-in,
|
|
52
|
+
aiquota won't offer it — and tells you why, with a link to the policy.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv tool install aiquota # or: pipx install aiquota
|
|
60
|
+
aiquota install-widget # macOS: adds the menu bar + desktop widgets
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then click **+ Add an AI account** in the widget and sign in.
|
|
64
|
+
|
|
65
|
+
<details>
|
|
66
|
+
<summary>Other ways</summary>
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install aiquota # into the current environment
|
|
70
|
+
pip install git+https://github.com/anujpatel06/aiquota # latest main
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`uv tool` / `pipx` are recommended because they put `aiquota` on your PATH
|
|
74
|
+
without touching your project environments.
|
|
75
|
+
|
|
76
|
+
The widgets need one of these host apps — `install-widget` tells you which
|
|
77
|
+
is missing rather than failing quietly:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
brew install --cask swiftbar # menu bar
|
|
81
|
+
brew install --cask ubersicht # desktop
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Install just one with `aiquota install-widget menubar` or `… desktop`.
|
|
85
|
+
</details>
|
|
86
|
+
|
|
87
|
+
Python 3.8+, no dependencies. The CLI runs anywhere; the widgets are macOS
|
|
88
|
+
only, and `install-widget` says so instead of pretending on Linux.
|
|
89
|
+
|
|
90
|
+
## Quick start
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
aiquota link # see what's on your machine, choose what to track
|
|
94
|
+
aiquota # show everything
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`link` is the only way an account gets connected. It lists credentials it can
|
|
98
|
+
see — which account, from which file — and **links nothing until you pick one
|
|
99
|
+
and confirm**. Nothing is read or sent before that.
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
$ aiquota link
|
|
103
|
+
|
|
104
|
+
Add an AI account
|
|
105
|
+
|
|
106
|
+
Nothing is read until you choose it.
|
|
107
|
+
|
|
108
|
+
[1] ChatGPT / Codex ● live ✓ tracked
|
|
109
|
+
Codex/Work windows + credits (NOT general chat quota)
|
|
110
|
+
✓ found: Codex CLI login (auth_mode: chatgpt), account 2754df98…
|
|
111
|
+
|
|
112
|
+
[2] Claude ● live
|
|
113
|
+
Pro/Max 5-hour + weekly windows, reset times
|
|
114
|
+
needs: Claude Code login, or an OAuth token
|
|
115
|
+
|
|
116
|
+
[3] Cursor ◐ manual for now
|
|
117
|
+
Request quota is shown in-app; no documented API yet
|
|
118
|
+
|
|
119
|
+
[7] Gemini ○ manual
|
|
120
|
+
No consumer quota API; AI Studio shows API-tier limits only
|
|
121
|
+
|
|
122
|
+
... 16 platforms total ...
|
|
123
|
+
|
|
124
|
+
[17] Something else… ○ manual
|
|
125
|
+
any AI service not listed above
|
|
126
|
+
|
|
127
|
+
Add which? (number, or Enter to cancel):
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The badges are honest about what you'll actually get:
|
|
131
|
+
|
|
132
|
+
| Badge | Meaning |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `● live` | An adapter fetches real usage once you link a credential |
|
|
135
|
+
| `◐ manual for now` | An endpoint likely exists; no adapter written yet — PRs welcome |
|
|
136
|
+
| `○ manual` | No usage API exists; you enter the numbers |
|
|
137
|
+
|
|
138
|
+
Most AI platforms publish no consumer usage API at all. Listing them as
|
|
139
|
+
`manual` is deliberate — a browsable list of everything you pay for beats a
|
|
140
|
+
short list of only what can be automated.
|
|
141
|
+
|
|
142
|
+
Useful variants:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
aiquota link --list # just browse, change nothing
|
|
146
|
+
aiquota link cursor # jump straight to one platform
|
|
147
|
+
aiquota unlink chatgpt # stop using the credential, keep the service
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Adding accounts
|
|
151
|
+
|
|
152
|
+
Click **+ Add an AI account…** in the menu bar or desktop widget and a native
|
|
153
|
+
macOS list appears with every supported platform:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
● ChatGPT / Codex — live usage ✓ added
|
|
157
|
+
● Claude — live usage ✓ added
|
|
158
|
+
◐ Cursor — manual for now
|
|
159
|
+
◐ ElevenLabs — manual for now
|
|
160
|
+
◐ GitHub Copilot — manual for now
|
|
161
|
+
◐ OpenRouter — manual for now
|
|
162
|
+
○ Gemini — manual entry
|
|
163
|
+
○ Grok — manual entry
|
|
164
|
+
○ Higgsfield — manual entry
|
|
165
|
+
○ Midjourney — manual entry
|
|
166
|
+
○ Perplexity — manual entry
|
|
167
|
+
○ Runway — manual entry
|
|
168
|
+
○ Suno — manual entry
|
|
169
|
+
○ v0 / Lovable / Replit …
|
|
170
|
+
+ Something else…
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Pick one and it walks you through the rest. No terminal required — though
|
|
174
|
+
`aiquota link` gives the same flow in the shell if you prefer.
|
|
175
|
+
|
|
176
|
+
The badges say what you actually get:
|
|
177
|
+
|
|
178
|
+
| Badge | Meaning |
|
|
179
|
+
|---|---|
|
|
180
|
+
| `● live` | Real usage, fetched once you link a credential |
|
|
181
|
+
| `◐ manual for now` | An endpoint likely exists; no adapter yet — PRs welcome |
|
|
182
|
+
| `○ manual` | No usage API; you enter the numbers |
|
|
183
|
+
|
|
184
|
+
Most AI platforms publish no consumer usage API. Listing them as `manual` is
|
|
185
|
+
deliberate — seeing everything you pay for in one place beats seeing only the
|
|
186
|
+
two that can be automated.
|
|
187
|
+
|
|
188
|
+
## Usage
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
aiquota # status for everything (default command)
|
|
192
|
+
aiquota claude # just one service
|
|
193
|
+
aiquota --json # machine-readable
|
|
194
|
+
aiquota --compact # one line, for a status bar
|
|
195
|
+
aiquota --html ~/quota.html # write a widget
|
|
196
|
+
aiquota -r # bypass the cache
|
|
197
|
+
aiquota doctor # diagnose configuration problems
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Managing services
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
aiquota list # what you're tracking
|
|
204
|
+
aiquota add midjourney --adapter manual --plan "Standard"
|
|
205
|
+
aiquota set midjourney credits=120 credits_total=900
|
|
206
|
+
aiquota disable chatgpt # keep config, hide the card
|
|
207
|
+
aiquota enable chatgpt
|
|
208
|
+
aiquota remove midjourney # asks first
|
|
209
|
+
aiquota rm midjourney -y # don't ask
|
|
210
|
+
aiquota rm a b c -y # several at once
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`remove` also purges that service's cache entry, so a deleted card can't
|
|
214
|
+
reappear from stale data.
|
|
215
|
+
|
|
216
|
+
### Tracking a service with no API
|
|
217
|
+
|
|
218
|
+
Most AI subscriptions expose nothing. Track them anyway — no code required:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
aiquota add higgsfield --adapter manual --plan "Creator" \
|
|
222
|
+
--set credits=420 --set credits_total=1500 --set renews_on=2026-10-01
|
|
223
|
+
|
|
224
|
+
# or as a used/limit pair with your own unit
|
|
225
|
+
aiquota add notebooklm --adapter manual \
|
|
226
|
+
--set used=140 --set limit=900 --set unit_label="Notebooks"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
These render as `manual`, so you're never fooled into thinking a hand-typed
|
|
230
|
+
number was fetched live.
|
|
231
|
+
|
|
232
|
+
## Supported platforms
|
|
233
|
+
|
|
234
|
+
How you connect each one depends on what the provider allows.
|
|
235
|
+
|
|
236
|
+
### Sign in with your account
|
|
237
|
+
|
|
238
|
+
Click the platform, its own login page opens, you pick the account.
|
|
239
|
+
No API key, no password shown to aiquota.
|
|
240
|
+
|
|
241
|
+
<p align="center">
|
|
242
|
+
<img src="docs/img/picker.png" width="420" alt="Platform picker listing 16 AI services with logos and status">
|
|
243
|
+
</p>
|
|
244
|
+
|
|
245
|
+
| Platform | What you get |
|
|
246
|
+
|---|---|
|
|
247
|
+
| **Cursor** | Request quota for the billing period (sign in) |
|
|
248
|
+
| **Grok** | Subscription tier (sign in) |
|
|
249
|
+
| **Midjourney** | Fast GPU minutes (sign in) |
|
|
250
|
+
| **OpenRouter** | Credit balance and spend (official API) |
|
|
251
|
+
| **Perplexity** | Pro search quota (sign in) |
|
|
252
|
+
| **Runway** | Credit balance (sign in) |
|
|
253
|
+
| **Suno** | Song credits and renewal date (sign in) |
|
|
254
|
+
|
|
255
|
+
### Uses a credential you already have
|
|
256
|
+
|
|
257
|
+
These providers restrict third-party sign-in, so aiquota reads a
|
|
258
|
+
credential you created yourself — and asks first.
|
|
259
|
+
|
|
260
|
+
| Platform | Why not sign-in | Source |
|
|
261
|
+
|---|---|---|
|
|
262
|
+
| **ChatGPT / Codex** | Codex CLI's login is issued to Codex. | [developers.openai.com](https://developers.openai.com/codex/auth) |
|
|
263
|
+
| **Claude** | Anthropic restricts OAuth to Claude Code and its own applications. | [code.claude.com](https://code.claude.com/docs/en/legal-and-compliance) |
|
|
264
|
+
| **ElevenLabs** | No third-party OAuth; a user-created API key is the supported route. | [elevenlabs.io](https://elevenlabs.io/docs/api-reference/authentication) |
|
|
265
|
+
| **GitHub Copilot** | Reuses your existing `gh` CLI login, which you performed yourself. | [docs.github.com](https://docs.github.com/en/copilot) |
|
|
266
|
+
|
|
267
|
+
### Manual entry
|
|
268
|
+
|
|
269
|
+
No reachable usage endpoint — probed and confirmed, not assumed.
|
|
270
|
+
You enter the numbers and they're labelled `manual`.
|
|
271
|
+
|
|
272
|
+
**Gemini**, **Higgsfield**, **Lovable**, **Replit**, **v0**.
|
|
273
|
+
|
|
274
|
+
Anything not listed: choose "Something else…" in the picker.
|
|
275
|
+
|
|
276
|
+
If you know a real endpoint for a manual entry, that's the most
|
|
277
|
+
valuable PR you can send — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
278
|
+
### Important caveats
|
|
279
|
+
|
|
280
|
+
Read these before trusting a number.
|
|
281
|
+
|
|
282
|
+
- **Most of these endpoints are undocumented.** They are the ones each
|
|
283
|
+
vendor's own client calls, and they can change without notice. aiquota has no
|
|
284
|
+
affiliation with any provider listed.
|
|
285
|
+
- **Claude prefers a free read.** The adapter calls the read-only
|
|
286
|
+
`/api/oauth/usage` endpoint first. If your token lacks the `user:profile`
|
|
287
|
+
scope (tokens from `claude setup-token` do), it falls back to reading rate
|
|
288
|
+
headers from a 1-token Haiku call and says so in `read_via`. Results are
|
|
289
|
+
cached for 5 minutes — raise `--ttl` if you poll often.
|
|
290
|
+
- **ChatGPT covers the Codex/Work meter, not general chat.** Your normal
|
|
291
|
+
conversation quota has no reachable endpoint. Nothing here can show it.
|
|
292
|
+
- **ChatGPT Plus ≠ OpenAI API.** Separate products, separate billing. The
|
|
293
|
+
documented `/v1/usage` endpoints report API spend and know nothing about a
|
|
294
|
+
Plus subscription.
|
|
295
|
+
|
|
296
|
+
### Credentials
|
|
297
|
+
|
|
298
|
+
**aiquota never uses a credential you haven't linked.** Run `aiquota link` to
|
|
299
|
+
see what's available and choose. It will find logins belonging to other apps
|
|
300
|
+
(Claude Code, Codex CLI, Hermes) but will not touch them until you say so.
|
|
301
|
+
|
|
302
|
+
| Adapter | Can link from |
|
|
303
|
+
|---|---|
|
|
304
|
+
| `claude` | `AIQUOTA_CLAUDE_TOKEN` / `ANTHROPIC_TOKEN` env, `~/.claude/.credentials.json`, `~/.hermes/.env` |
|
|
305
|
+
| `chatgpt` | `AIQUOTA_CODEX_TOKEN` env, `~/.codex/auth.json` |
|
|
306
|
+
|
|
307
|
+
Env vars and tokens you put in the config are used directly — you set those
|
|
308
|
+
deliberately. Reading *another application's* credential file always requires
|
|
309
|
+
`link` (or `autodiscover=true`). Set `AIQUOTA_NO_AUTODISCOVER=1` to block it
|
|
310
|
+
entirely. Config lives at `~/.config/aiquota/config.json`, chmod `0600`.
|
|
311
|
+
|
|
312
|
+
## Writing an adapter
|
|
313
|
+
|
|
314
|
+
Drop a `.py` file in `~/.config/aiquota/adapters/` — no fork, no reinstall:
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
from aiquota import Adapter, Result, Window, register, LIVE
|
|
318
|
+
|
|
319
|
+
@register
|
|
320
|
+
class MyServiceAdapter(Adapter):
|
|
321
|
+
name = "myservice" # config key
|
|
322
|
+
service = "My Service" # display name
|
|
323
|
+
summary = "What this reads" # shown by `aiquota adapters`
|
|
324
|
+
setup = "Set MYSERVICE_TOKEN" # shown when unconfigured
|
|
325
|
+
|
|
326
|
+
def probe(self, conf):
|
|
327
|
+
return Result(
|
|
328
|
+
name=self.name, service=self.service, tier=LIVE,
|
|
329
|
+
windows=[Window(label="Monthly", used_pct=42.0,
|
|
330
|
+
resets_at="Nov 1")],
|
|
331
|
+
)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Then `aiquota add myservice`. The contract:
|
|
335
|
+
|
|
336
|
+
- **Never raise.** Catch your errors and return `tier=ERROR` with a readable
|
|
337
|
+
message. A broken adapter must not take down the whole run (there's a test
|
|
338
|
+
for this).
|
|
339
|
+
- **Be honest about `tier`** — `LIVE` only for numbers you actually fetched.
|
|
340
|
+
- **Declare `cost_note`** if probing spends quota or money.
|
|
341
|
+
|
|
342
|
+
PRs adding adapters are welcome.
|
|
343
|
+
|
|
344
|
+
## Scripting
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# warn when any window passes 80%
|
|
348
|
+
aiquota --exit-code --threshold 80 || notify-send "AI quota running low"
|
|
349
|
+
|
|
350
|
+
# tmux status bar
|
|
351
|
+
set -g status-right '#(aiquota --compact)'
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
`--json` gives you `{generated_at, services: [{name, service, plan, tier,
|
|
355
|
+
windows: [{label, used_pct, resets_at}], extra}]}`.
|
|
356
|
+
|
|
357
|
+
## Desktop widgets
|
|
358
|
+
|
|
359
|
+
Keep it on screen instead of typing a command:
|
|
360
|
+
|
|
361
|
+
- **Menu bar** (SwiftBar/xbar) — `AI 46%` at the top of the screen, over every app
|
|
362
|
+
- **Desktop** (Übersicht) — a panel drawn on the wallpaper
|
|
363
|
+
|
|
364
|
+
Both live in [`widgets/`](widgets/) with install steps.
|
|
365
|
+
|
|
366
|
+
## Development
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
python3 -m unittest discover -s tests -v # 31 tests, no network, ~0.2s
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Tests set `AIQUOTA_NO_AUTODISCOVER=1` so they never pick up real credentials.
|
|
373
|
+
|
|
374
|
+
## License
|
|
375
|
+
|
|
376
|
+
MIT
|