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.
Files changed (40) hide show
  1. aiquota-0.2.0/LICENSE +21 -0
  2. aiquota-0.2.0/PKG-INFO +376 -0
  3. aiquota-0.2.0/README.md +357 -0
  4. aiquota-0.2.0/aiquota/__init__.py +8 -0
  5. aiquota-0.2.0/aiquota/__main__.py +3 -0
  6. aiquota-0.2.0/aiquota/adapters/__init__.py +1 -0
  7. aiquota-0.2.0/aiquota/adapters/_http.py +61 -0
  8. aiquota-0.2.0/aiquota/adapters/browser_read.py +138 -0
  9. aiquota-0.2.0/aiquota/adapters/chatgpt.py +178 -0
  10. aiquota-0.2.0/aiquota/adapters/claude.py +246 -0
  11. aiquota-0.2.0/aiquota/adapters/copilot.py +140 -0
  12. aiquota-0.2.0/aiquota/adapters/elevenlabs.py +74 -0
  13. aiquota-0.2.0/aiquota/adapters/manual.py +74 -0
  14. aiquota-0.2.0/aiquota/adapters/openrouter.py +85 -0
  15. aiquota-0.2.0/aiquota/adapters/session_based.py +200 -0
  16. aiquota-0.2.0/aiquota/assets/logos.json +1 -0
  17. aiquota-0.2.0/aiquota/browser_login.py +368 -0
  18. aiquota-0.2.0/aiquota/catalog.py +199 -0
  19. aiquota-0.2.0/aiquota/cli.py +656 -0
  20. aiquota-0.2.0/aiquota/core.py +357 -0
  21. aiquota-0.2.0/aiquota/guidialog.py +277 -0
  22. aiquota-0.2.0/aiquota/guipick.py +339 -0
  23. aiquota-0.2.0/aiquota/install_widget.py +143 -0
  24. aiquota-0.2.0/aiquota/login_policy.py +110 -0
  25. aiquota-0.2.0/aiquota/oauth.py +144 -0
  26. aiquota-0.2.0/aiquota/picker.py +569 -0
  27. aiquota-0.2.0/aiquota/remove_ui.py +97 -0
  28. aiquota-0.2.0/aiquota/render.py +127 -0
  29. aiquota-0.2.0/aiquota/widgets/add_account.sh +13 -0
  30. aiquota-0.2.0/aiquota/widgets/aiquota.5m.sh +20 -0
  31. aiquota-0.2.0/aiquota/widgets/aiquota.jsx +564 -0
  32. aiquota-0.2.0/aiquota/widgets/aiquota_render.py +126 -0
  33. aiquota-0.2.0/aiquota.egg-info/PKG-INFO +376 -0
  34. aiquota-0.2.0/aiquota.egg-info/SOURCES.txt +38 -0
  35. aiquota-0.2.0/aiquota.egg-info/dependency_links.txt +1 -0
  36. aiquota-0.2.0/aiquota.egg-info/entry_points.txt +4 -0
  37. aiquota-0.2.0/aiquota.egg-info/top_level.txt +1 -0
  38. aiquota-0.2.0/pyproject.toml +36 -0
  39. aiquota-0.2.0/setup.cfg +4 -0
  40. 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