when-does-my-quota-refresh 1.0.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/LICENSE +21 -0
- package/README.md +704 -0
- package/dist/auth-S43EEJYA.js +12 -0
- package/dist/auth-S43EEJYA.js.map +1 -0
- package/dist/chunk-YZVX5QIP.js +487 -0
- package/dist/chunk-YZVX5QIP.js.map +1 -0
- package/dist/cli/index.js +2329 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/sdk/index.d.ts +350 -0
- package/dist/sdk/index.js +1804 -0
- package/dist/sdk/index.js.map +1 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 when-does-my-quota-refresh contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
# when-does-my-quota-refresh
|
|
2
|
+
|
|
3
|
+
**Cross-platform CLI + SDK for tracking Antigravity AI model quotas across all your accounts.**
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
╔══════════════════════════════════════════════════════════════╗
|
|
7
|
+
║ when-does-my-quota-refresh — Full Dashboard 14:32:07 ║
|
|
8
|
+
╠══════════════════════════════════════════════════════════════╣
|
|
9
|
+
║ 📧 user@gmail.com (Personal — Ultra) ● Active ║
|
|
10
|
+
║ ┌─ Gemini Models ───────────────────────────────────────┐ ║
|
|
11
|
+
║ │ 5-Hour [██████████████░░░░░░░░░░░░░░░░] 72% 2h31m │ ║
|
|
12
|
+
║ │ Weekly [████████████████████████░░░░░░░] 85% 3d12h │ ║
|
|
13
|
+
║ └────────────────────────────────────────────────────────┘ ║
|
|
14
|
+
║ ┌─ Claude + GPT Models ──────────────────────────────────┐ ║
|
|
15
|
+
║ │ 5-Hour [████████████████░░░░░░░░░░░░░░] 56% 2h31m │ ║
|
|
16
|
+
║ │ Weekly [████████████████████████████░░░] 93% 3d12h │ ║
|
|
17
|
+
║ └────────────────────────────────────────────────────────┘ ║
|
|
18
|
+
║ 📈 Recent ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁▂▃▄▅▆▇█▇▆▅▄▃ ║
|
|
19
|
+
╚══════════════════════════════════════════════════════════════╝
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
- [Why when-does-my-quota-refresh?](#why-when-does-my-quota-refresh)
|
|
27
|
+
- [Quick Start](#quick-start)
|
|
28
|
+
- [Installation](#installation)
|
|
29
|
+
- [Commands Reference](#commands-reference)
|
|
30
|
+
- [SDK Usage](#sdk-usage)
|
|
31
|
+
- [Data Sources](#data-sources)
|
|
32
|
+
- [Configuration](#configuration)
|
|
33
|
+
- [Plugin System](#plugin-system)
|
|
34
|
+
- [Platform Support](#platform-support)
|
|
35
|
+
- [Development](#development)
|
|
36
|
+
- [Testing](#testing)
|
|
37
|
+
- [Contributing](#contributing)
|
|
38
|
+
- [License](#license)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Why when-does-my-quota-refresh?
|
|
43
|
+
|
|
44
|
+
**antigravity-usage** (the original tool) has significant shortcomings:
|
|
45
|
+
|
|
46
|
+
| | antigravity-usage | when-does-my-quota-refresh |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| Windows support | ❌ Broken | ✅ Full support |
|
|
49
|
+
| Data completeness | ❌ 5-hour session only | ✅ 5-hour + weekly limits |
|
|
50
|
+
| SDK / library use | ❌ CLI only | ✅ Import as library |
|
|
51
|
+
| Plugin system | ❌ None | ✅ Extensible |
|
|
52
|
+
| Usage history | ❌ None | ✅ SQLite-backed trends |
|
|
53
|
+
| Development | ❌ Stalled (6+ months) | ✅ Active |
|
|
54
|
+
|
|
55
|
+
**when-does-my-quota-refresh** provides:
|
|
56
|
+
|
|
57
|
+
- ✅ **Cross-platform** — Windows, macOS, and Linux
|
|
58
|
+
- ✅ **Complete quota data** — both 5-hour and weekly limits for all model groups
|
|
59
|
+
- ✅ **Full dashboard** — `aq --full` for a complete overview
|
|
60
|
+
- ✅ **SDK-first** — import as a library in your own tools
|
|
61
|
+
- ✅ **Plugin system** — notifications, webhooks, and community plugins
|
|
62
|
+
- ✅ **Usage history** — track and visualize quota trends over time
|
|
63
|
+
- ✅ **Smart auto-wakeup** — maximize daily quota usage via system scheduler
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Quick Start
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Install globally
|
|
71
|
+
npm install -g when-does-my-quota-refresh
|
|
72
|
+
|
|
73
|
+
# Check quota (uses local IDE connection — no login needed)
|
|
74
|
+
aq
|
|
75
|
+
|
|
76
|
+
# Full dashboard with all accounts
|
|
77
|
+
aq --full
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
> **No login required** for the default mode. when-does-my-quota-refresh connects directly to Antigravity's language server running in your IDE.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
### npm (recommended)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install -g when-does-my-quota-refresh
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### From source
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/your-username/when-does-my-quota-refresh.git
|
|
96
|
+
cd when-does-my-quota-refresh
|
|
97
|
+
npm install
|
|
98
|
+
npm run build
|
|
99
|
+
npm link
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Verify installation
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
aq --version
|
|
106
|
+
aq doctor
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Commands Reference
|
|
112
|
+
|
|
113
|
+
### Default Command (no subcommand)
|
|
114
|
+
|
|
115
|
+
| Command | Description |
|
|
116
|
+
|---------|-------------|
|
|
117
|
+
| `aq` | Show compact quota for the active account |
|
|
118
|
+
| `aq --full` | Show full dashboard with all accounts, groups, and sparklines |
|
|
119
|
+
| `aq --full --watch` | Live-refreshing full dashboard (30s interval) |
|
|
120
|
+
| `aq --json` | Output default command as JSON |
|
|
121
|
+
| `aq --verbose` | Enable debug logging |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### `aq quota` — Display Current Quota
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
aq quota # Compact view for active account
|
|
129
|
+
aq quota --all # Side-by-side comparison of all accounts
|
|
130
|
+
aq quota --refresh # Force fresh fetch (bypass cache)
|
|
131
|
+
aq quota --method local # Force a specific data source (local, cli, oauth)
|
|
132
|
+
aq quota --json # Machine-readable JSON output
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Options:**
|
|
136
|
+
|
|
137
|
+
| Flag | Description |
|
|
138
|
+
|------|-------------|
|
|
139
|
+
| `-a, --all` | Fetch and display all accounts side-by-side |
|
|
140
|
+
| `-r, --refresh` | Skip cache, fetch fresh data |
|
|
141
|
+
| `-m, --method <method>` | Force a specific data source |
|
|
142
|
+
| `--json` | Output as JSON |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### `aq accounts` — Manage Accounts
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
aq accounts list # List all configured accounts
|
|
150
|
+
aq accounts add # Login a new Google account (browser flow)
|
|
151
|
+
aq accounts add --manual # Manual login (headless/SSH — shows URL)
|
|
152
|
+
aq accounts switch <email> # Set the active account
|
|
153
|
+
aq accounts remove <email> # Remove an account (with confirmation)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Subcommands:**
|
|
157
|
+
|
|
158
|
+
| Subcommand | Description |
|
|
159
|
+
|------------|-------------|
|
|
160
|
+
| `list` | List all managed accounts with status |
|
|
161
|
+
| `add` | Start OAuth login flow for a new Google account |
|
|
162
|
+
| `add --manual` | Get a URL for manual login (for headless environments) |
|
|
163
|
+
| `switch <email>` | Set a different account as active |
|
|
164
|
+
| `remove <email>` | Remove an account (prompts for confirmation) |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### `aq history` — Usage History & Analytics
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
aq history # Last 7 days for active account
|
|
172
|
+
aq history --days 30 # Last 30 days
|
|
173
|
+
aq history --email user@gmail.com # Specific account
|
|
174
|
+
aq history --group gemini # Filter: gemini, claude, or all
|
|
175
|
+
aq history --compare # Compare all accounts
|
|
176
|
+
aq history --json # Machine-readable output
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Options:**
|
|
180
|
+
|
|
181
|
+
| Flag | Description |
|
|
182
|
+
|------|-------------|
|
|
183
|
+
| `-e, --email <email>` | Account to show (default: active account) |
|
|
184
|
+
| `-d, --days <days>` | Number of days (default: 7) |
|
|
185
|
+
| `--group <group>` | Filter: `gemini`, `claude`, or `all` (default: `all`) |
|
|
186
|
+
| `--compare` | Show side-by-side comparison of all accounts |
|
|
187
|
+
| `--json` | Output as JSON |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### `aq wakeup` — Auto-Trigger Quota Refresh
|
|
192
|
+
|
|
193
|
+
Automatically trigger quota refreshes to maximize your daily usage limits. Uses your system's native scheduler (cron on macOS/Linux, Task Scheduler on Windows).
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
aq wakeup config # Interactive setup
|
|
197
|
+
aq wakeup install # Install to system scheduler
|
|
198
|
+
aq wakeup uninstall # Remove from system scheduler
|
|
199
|
+
aq wakeup status # Check if wakeup is installed
|
|
200
|
+
aq wakeup test # Manually test the wakeup trigger
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Subcommands:**
|
|
204
|
+
|
|
205
|
+
| Subcommand | Description |
|
|
206
|
+
|------------|-------------|
|
|
207
|
+
| `config` | Interactive wizard to configure trigger mode, schedule, and accounts |
|
|
208
|
+
| `install` | Register the wakeup job with the system scheduler |
|
|
209
|
+
| `uninstall` | Remove the wakeup job from the system scheduler |
|
|
210
|
+
| `status` | Show current wakeup configuration and scheduler status |
|
|
211
|
+
| `test` | Manually trigger a quota refresh to verify it works |
|
|
212
|
+
|
|
213
|
+
**Trigger Modes:**
|
|
214
|
+
|
|
215
|
+
| Mode | Description |
|
|
216
|
+
|------|-------------|
|
|
217
|
+
| `smart` | Trigger when quota resets are detected (Recommended) |
|
|
218
|
+
| `interval` | Trigger every N hours |
|
|
219
|
+
| `daily` | Trigger at specific times of day |
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### `aq watch` — Real-Time Monitoring
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
aq watch start # Start monitoring (foreground)
|
|
227
|
+
aq watch start --interval 30 # Custom poll interval (seconds)
|
|
228
|
+
aq watch status # Check daemon status
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### `aq doctor` — Diagnose Setup Issues
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
aq doctor
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Runs a comprehensive health check:
|
|
240
|
+
|
|
241
|
+
- Platform and Node.js version
|
|
242
|
+
- Config directory and file
|
|
243
|
+
- Account configuration and token validity
|
|
244
|
+
- Antigravity process detection
|
|
245
|
+
- Live quota fetch test
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
### `aq config` — Manage Settings
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
aq config show # Display all configuration
|
|
253
|
+
aq config set <key> <value> # Update a setting
|
|
254
|
+
aq config get <key> # Read a single setting
|
|
255
|
+
aq config path # Show config directory path
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Common settings:**
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
aq config set defaultMode oauth # Change default data source
|
|
262
|
+
aq config set cacheTtlMs 300000 # Cache TTL: 5 minutes
|
|
263
|
+
aq config set notifications false # Disable desktop notifications
|
|
264
|
+
aq config set daemon.pollIntervalMs 30000 # Watch interval: 30 seconds
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Supported config keys:**
|
|
268
|
+
|
|
269
|
+
| Key | Type | Default | Description |
|
|
270
|
+
|-----|------|---------|-------------|
|
|
271
|
+
| `defaultMode` | `string` | `local` | Default data source (`local`, `cli`, `oauth`) |
|
|
272
|
+
| `cacheTtlMs` | `number` | `300000` | Cache time-to-live in milliseconds |
|
|
273
|
+
| `refreshIntervalMs` | `number` | `300000` | Auto-refresh interval |
|
|
274
|
+
| `notifications` | `boolean` | `true` | Desktop notifications |
|
|
275
|
+
| `plugins` | `string[]` | `[]` | Installed plugin names |
|
|
276
|
+
| `wakeupModels` | `string[]` | `[...]` | Models to track in wakeup |
|
|
277
|
+
| `wakeupAccounts` | `string[]` | `[]` | Accounts for wakeup (empty = all) |
|
|
278
|
+
| `daemon.pollIntervalMs` | `number` | `60000` | Watch mode poll interval |
|
|
279
|
+
| `daemon.enabled` | `boolean` | `false` | Enable background daemon |
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### `aq plugin` — Plugin Management
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
aq plugin list # List installed plugins
|
|
287
|
+
aq plugin install <name> # Install a plugin
|
|
288
|
+
aq plugin remove <name> # Remove a plugin
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### Global Flags
|
|
294
|
+
|
|
295
|
+
| Flag | Description |
|
|
296
|
+
|------|-------------|
|
|
297
|
+
| `-V, --version` | Show version number |
|
|
298
|
+
| `-h, --help` | Show help |
|
|
299
|
+
| `--verbose` | Enable debug output |
|
|
300
|
+
| `--json` | Output as JSON (where applicable) |
|
|
301
|
+
| `--full` | Show full dashboard |
|
|
302
|
+
| `--no-history` | Skip history sparkline in full dashboard |
|
|
303
|
+
| `--watch` | Auto-refresh mode (with `--full`) |
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## SDK Usage
|
|
308
|
+
|
|
309
|
+
when-does-my-quota-refresh ships as an importable SDK for building your own tools and extensions.
|
|
310
|
+
|
|
311
|
+
### Installation
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
npm install when-does-my-quota-refresh
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Basic Usage
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { createClient } from 'when-does-my-quota-refresh'
|
|
321
|
+
|
|
322
|
+
const client = createClient()
|
|
323
|
+
|
|
324
|
+
// Fetch quota for active account
|
|
325
|
+
const snapshot = await client.fetchQuota()
|
|
326
|
+
console.log(snapshot.groups)
|
|
327
|
+
// => [{ displayName: 'Gemini Models', buckets: [...] }, ...]
|
|
328
|
+
|
|
329
|
+
// Fetch all accounts
|
|
330
|
+
const snapshots = await client.fetchQuota({ allAccounts: true })
|
|
331
|
+
for (const s of snapshots) {
|
|
332
|
+
console.log(`${s.email}: ${s.groups.length} groups`)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Force refresh (bypass cache)
|
|
336
|
+
const fresh = await client.fetchQuota({ refresh: true })
|
|
337
|
+
|
|
338
|
+
// Force a specific data source
|
|
339
|
+
const fromLocal = await client.fetchQuota({ source: 'local' })
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Full Dashboard
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
const { snapshots, history, dailySummary } = await client.getFullDashboard()
|
|
346
|
+
|
|
347
|
+
// snapshots: QuotaSnapshot[] — current state for each account
|
|
348
|
+
// history: Record<string, UsageRecord[]> — recent readings per account
|
|
349
|
+
// dailySummary: Record<string, DailySummary[]> — aggregated daily stats
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Usage History
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// Last 30 days for a specific account
|
|
356
|
+
const history = client.getHistory('user@gmail.com', 30)
|
|
357
|
+
|
|
358
|
+
// Daily summary
|
|
359
|
+
const summary = client.getDailySummary('user@gmail.com', 7)
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Types
|
|
363
|
+
|
|
364
|
+
All types are exported for TypeScript consumers:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
import type {
|
|
368
|
+
QuotaSnapshot,
|
|
369
|
+
QuotaGroup,
|
|
370
|
+
QuotaBucket,
|
|
371
|
+
PromptCreditsInfo,
|
|
372
|
+
DataSource,
|
|
373
|
+
ModelQuotaInfo,
|
|
374
|
+
AccountInfo,
|
|
375
|
+
Plugin,
|
|
376
|
+
UsageRecord,
|
|
377
|
+
ClientOptions,
|
|
378
|
+
} from 'when-does-my-quota-refresh'
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Error Handling
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
import {
|
|
385
|
+
SourceUnavailableError,
|
|
386
|
+
AuthError,
|
|
387
|
+
QuotaFetchError,
|
|
388
|
+
} from 'when-does-my-quota-refresh'
|
|
389
|
+
|
|
390
|
+
try {
|
|
391
|
+
const snapshot = await client.fetchQuota()
|
|
392
|
+
} catch (err) {
|
|
393
|
+
if (err instanceof SourceUnavailableError) {
|
|
394
|
+
console.log(`Source ${err.message} is not available`)
|
|
395
|
+
} else if (err instanceof AuthError) {
|
|
396
|
+
console.log('Authentication failed — run `aq accounts add`')
|
|
397
|
+
} else if (err instanceof QuotaFetchError) {
|
|
398
|
+
console.log(`Fetch failed: ${err.message}`)
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Configuration
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
import { loadConfig, saveConfig, getConfigDirPath } from 'when-does-my-quota-refresh'
|
|
407
|
+
|
|
408
|
+
// Read current config
|
|
409
|
+
const config = loadConfig()
|
|
410
|
+
|
|
411
|
+
// Update and save
|
|
412
|
+
config.cacheTtlMs = 10 * 60 * 1000 // 10 minutes
|
|
413
|
+
saveConfig(config)
|
|
414
|
+
|
|
415
|
+
// Find where config is stored
|
|
416
|
+
console.log(getConfigDirPath())
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Data Sources
|
|
422
|
+
|
|
423
|
+
when-does-my-quota-refresh uses a smart fallback chain to fetch quota data:
|
|
424
|
+
|
|
425
|
+
### 1. Local (highest priority)
|
|
426
|
+
|
|
427
|
+
Connects directly to Antigravity's language server running in your IDE (VS Code, Cursor, etc.). This is the **default and recommended** source — no login required.
|
|
428
|
+
|
|
429
|
+
**How it works:**
|
|
430
|
+
1. Detects running Antigravity processes on your system
|
|
431
|
+
2. Discovers the language server's local port
|
|
432
|
+
3. Sends an HTTP request to fetch quota data
|
|
433
|
+
|
|
434
|
+
### 2. CLI Bridge
|
|
435
|
+
|
|
436
|
+
Uses the `agy` CLI's embedded HTTPS server. Useful when the local connection isn't available.
|
|
437
|
+
|
|
438
|
+
### 3. OAuth (Google Cloud Code API)
|
|
439
|
+
|
|
440
|
+
Fetches quota data via Google's Cloud Code API using OAuth2 tokens. Requires account login via `aq accounts add`.
|
|
441
|
+
|
|
442
|
+
**When to use:**
|
|
443
|
+
- Running on a remote server without IDE access
|
|
444
|
+
- Need historical data from the cloud
|
|
445
|
+
- Local/CLI sources are unavailable
|
|
446
|
+
|
|
447
|
+
### Source Selection
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
# Auto-select best source (default)
|
|
451
|
+
aq quota
|
|
452
|
+
|
|
453
|
+
# Force specific source
|
|
454
|
+
aq quota --method local
|
|
455
|
+
aq quota --method oauth
|
|
456
|
+
|
|
457
|
+
# Bypass cache
|
|
458
|
+
aq quota --refresh
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Configuration
|
|
464
|
+
|
|
465
|
+
Configuration is stored in your platform's standard location:
|
|
466
|
+
|
|
467
|
+
| Platform | Path |
|
|
468
|
+
|----------|------|
|
|
469
|
+
| **macOS** | `~/Library/Application Support/when-does-my-quota-refresh/` |
|
|
470
|
+
| **Linux** | `~/.config/when-does-my-quota-refresh/` |
|
|
471
|
+
| **Windows** | `%APPDATA%/when-does-my-quota-refresh/` |
|
|
472
|
+
|
|
473
|
+
### Config File
|
|
474
|
+
|
|
475
|
+
Located at `<config-dir>/config.json`:
|
|
476
|
+
|
|
477
|
+
```json
|
|
478
|
+
{
|
|
479
|
+
"defaultMode": "local",
|
|
480
|
+
"cacheTtlMs": 300000,
|
|
481
|
+
"refreshIntervalMs": 300000,
|
|
482
|
+
"wakeupModels": ["claude-sonnet-4-5", "gemini-3-flash", "gemini-3-pro-low"],
|
|
483
|
+
"wakeupAccounts": [],
|
|
484
|
+
"notifications": true,
|
|
485
|
+
"plugins": [],
|
|
486
|
+
"daemon": {
|
|
487
|
+
"pollIntervalMs": 60000,
|
|
488
|
+
"enabled": false
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Data Directory
|
|
494
|
+
|
|
495
|
+
Usage history and snapshots are stored in `<config-dir>/data/` using SQLite (`better-sqlite3`).
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## Plugin System
|
|
500
|
+
|
|
501
|
+
when-does-my-quota-refresh has a built-in plugin system for extending functionality.
|
|
502
|
+
|
|
503
|
+
### Built-in Plugins
|
|
504
|
+
|
|
505
|
+
| Plugin | Description |
|
|
506
|
+
|--------|-------------|
|
|
507
|
+
| `notifications` | Desktop notifications when quota drops below threshold |
|
|
508
|
+
| `webhook` | Send quota updates to a webhook URL |
|
|
509
|
+
|
|
510
|
+
### Creating a Plugin
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
import type { Plugin } from 'when-does-my-quota-refresh'
|
|
514
|
+
|
|
515
|
+
const myPlugin: Plugin = {
|
|
516
|
+
name: 'my-plugin',
|
|
517
|
+
version: '1.0.0',
|
|
518
|
+
|
|
519
|
+
// Called when plugin loads
|
|
520
|
+
onInit: async (ctx) => {
|
|
521
|
+
ctx.log('Plugin initialized')
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
// Called on every quota update
|
|
525
|
+
onQuotaUpdate: async (snapshot, ctx) => {
|
|
526
|
+
ctx.log(`Quota updated for ${snapshot.email}`)
|
|
527
|
+
ctx.notify('Quota Update', `${snapshot.groups.length} groups`)
|
|
528
|
+
},
|
|
529
|
+
|
|
530
|
+
// Called when any bucket drops below threshold
|
|
531
|
+
onQuotaLow: async (group, bucket, remaining, ctx) => {
|
|
532
|
+
ctx.notify('Low Quota!', `${group} ${bucket}: ${remaining * 100}% remaining`)
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
// Called when a bucket resets
|
|
536
|
+
onReset: async (group, nextReset, ctx) => {
|
|
537
|
+
ctx.log(`${group} resets at ${nextReset.toISOString()}`)
|
|
538
|
+
},
|
|
539
|
+
|
|
540
|
+
// Called when plugin unloads
|
|
541
|
+
onDestroy: async () => {
|
|
542
|
+
// Cleanup
|
|
543
|
+
},
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export default myPlugin
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Plugin Hooks
|
|
550
|
+
|
|
551
|
+
| Hook | When | Parameters |
|
|
552
|
+
|------|------|------------|
|
|
553
|
+
| `onInit` | Plugin loaded | `ctx: PluginContext` |
|
|
554
|
+
| `onQuotaUpdate` | Quota data fetched | `snapshot, ctx` |
|
|
555
|
+
| `onQuotaLow` | Bucket below threshold | `group, bucket, remaining, ctx` |
|
|
556
|
+
| `onReset` | Bucket resets | `group, nextReset, ctx` |
|
|
557
|
+
| `onDestroy` | Plugin unloaded | — |
|
|
558
|
+
|
|
559
|
+
### Plugin Context
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
interface PluginContext {
|
|
563
|
+
/** Show a desktop notification */
|
|
564
|
+
notify(title: string, message: string): void
|
|
565
|
+
/** Log a debug message */
|
|
566
|
+
log(message: string): void
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Platform Support
|
|
573
|
+
|
|
574
|
+
### Windows
|
|
575
|
+
|
|
576
|
+
when-does-my-quota-refresh provides full Windows support, unlike antigravity-usage:
|
|
577
|
+
|
|
578
|
+
- **Process detection** — `wmic` + PowerShell + `netstat`
|
|
579
|
+
- **Port discovery** — `Get-NetTCPConnection` + command-line flag extraction
|
|
580
|
+
- **System scheduler** — Windows Task Scheduler (via `schtasks`)
|
|
581
|
+
- **All commands** — full dashboard, watch, wakeup, history, etc.
|
|
582
|
+
|
|
583
|
+
### macOS & Linux
|
|
584
|
+
|
|
585
|
+
- **Process detection** — `ps` + `/proc` filesystem
|
|
586
|
+
- **Port discovery** — `lsof` / `/proc/net/tcp`
|
|
587
|
+
- **System scheduler** — `crontab`
|
|
588
|
+
- **Full feature support**
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## Development
|
|
593
|
+
|
|
594
|
+
### Prerequisites
|
|
595
|
+
|
|
596
|
+
- Node.js >= 18
|
|
597
|
+
- npm >= 9
|
|
598
|
+
|
|
599
|
+
### Getting Started
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
git clone https://github.com/your-username/when-does-my-quota-refresh.git
|
|
603
|
+
cd when-does-my-quota-refresh
|
|
604
|
+
npm install
|
|
605
|
+
npm run dev -- quota # Run CLI in development mode
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### Scripts
|
|
609
|
+
|
|
610
|
+
| Command | Description |
|
|
611
|
+
|---------|-------------|
|
|
612
|
+
| `npm run build` | Build SDK + CLI with tsup |
|
|
613
|
+
| `npm run dev` | Run CLI via tsx (no build step) |
|
|
614
|
+
| `npm test` | Run test suite |
|
|
615
|
+
| `npm run test:watch` | Run tests in watch mode |
|
|
616
|
+
| `npm run typecheck` | Type-check without emitting |
|
|
617
|
+
|
|
618
|
+
### Build Output
|
|
619
|
+
|
|
620
|
+
The build produces:
|
|
621
|
+
|
|
622
|
+
```
|
|
623
|
+
dist/
|
|
624
|
+
├── cli/
|
|
625
|
+
│ ├── index.js # CLI entry point (with shebang)
|
|
626
|
+
│ └── index.js.map
|
|
627
|
+
├── sdk/
|
|
628
|
+
│ ├── index.js # SDK entry point (importable)
|
|
629
|
+
│ ├── index.d.ts # TypeScript declarations
|
|
630
|
+
│ └── index.js.map
|
|
631
|
+
├── auth-*.js # OAuth chunk
|
|
632
|
+
├── auth-*.js.map
|
|
633
|
+
├── chunk-*.js # Shared chunks
|
|
634
|
+
└── chunk-*.js.map
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## Testing
|
|
640
|
+
|
|
641
|
+
### Running Tests
|
|
642
|
+
|
|
643
|
+
```bash
|
|
644
|
+
# Run all tests
|
|
645
|
+
npm test
|
|
646
|
+
|
|
647
|
+
# Watch mode (re-runs on file changes)
|
|
648
|
+
npm run test:watch
|
|
649
|
+
|
|
650
|
+
# Run a specific test file
|
|
651
|
+
npx vitest run tests/sdk/cache.test.ts
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### Test Structure
|
|
655
|
+
|
|
656
|
+
```
|
|
657
|
+
tests/
|
|
658
|
+
├── sdk/
|
|
659
|
+
│ ├── cache.test.ts # Cache behavior tests
|
|
660
|
+
│ └── types.test.ts # Type validation tests
|
|
661
|
+
└── sources/
|
|
662
|
+
└── local/
|
|
663
|
+
├── parser.test.ts # Response parser tests
|
|
664
|
+
└── process-detector.test.ts # Process detection tests
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### Writing Tests
|
|
668
|
+
|
|
669
|
+
Tests use [Vitest](https://vitest.dev/) with globals enabled:
|
|
670
|
+
|
|
671
|
+
```typescript
|
|
672
|
+
import { describe, it, expect } from 'vitest'
|
|
673
|
+
|
|
674
|
+
describe('MyFeature', () => {
|
|
675
|
+
it('should do something', () => {
|
|
676
|
+
expect(result).toBe(expected)
|
|
677
|
+
})
|
|
678
|
+
})
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Testing Before Publishing
|
|
682
|
+
|
|
683
|
+
See [docs/PUBLISHING.md](docs/PUBLISHING.md) for a complete guide on testing before npm publish.
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## Contributing
|
|
688
|
+
|
|
689
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide.
|
|
690
|
+
|
|
691
|
+
**Quick version:**
|
|
692
|
+
|
|
693
|
+
1. Fork and clone the repo
|
|
694
|
+
2. Install dependencies: `npm install`
|
|
695
|
+
3. Create a feature branch: `git checkout -b feat/my-feature`
|
|
696
|
+
4. Make changes + add tests
|
|
697
|
+
5. Verify: `npm run typecheck && npm test && npm run build`
|
|
698
|
+
6. Commit and open a PR
|
|
699
|
+
|
|
700
|
+
---
|
|
701
|
+
|
|
702
|
+
## License
|
|
703
|
+
|
|
704
|
+
[MIT](LICENSE) — see the LICENSE file for details.
|