@metyatech/ai-quota 0.9.3 → 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/README.md +19 -57
- package/dist/claude.d.ts +1 -1
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +42 -16
- package/dist/claude.js.map +1 -1
- package/dist/cli.js +13 -38
- package/dist/cli.js.map +1 -1
- package/dist/codex.d.ts +4 -12
- package/dist/codex.d.ts.map +1 -1
- package/dist/codex.js +92 -177
- package/dist/codex.js.map +1 -1
- package/dist/copilot.d.ts.map +1 -1
- package/dist/copilot.js +16 -4
- package/dist/copilot.js.map +1 -1
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/gemini.d.ts +2 -9
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +130 -94
- package/dist/gemini.js.map +1 -1
- package/dist/human-output.d.ts +16 -0
- package/dist/human-output.d.ts.map +1 -0
- package/dist/human-output.js +247 -0
- package/dist/human-output.js.map +1 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +61 -39
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +1 -1
- package/dist/types.d.ts +1 -17
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/amazon-q.d.ts +0 -63
- package/dist/amazon-q.d.ts.map +0 -1
- package/dist/amazon-q.js +0 -114
- package/dist/amazon-q.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @metyatech/ai-quota
|
|
2
2
|
|
|
3
|
-
AI agent quota/rate-limit fetching library for Claude, Gemini, Copilot,
|
|
3
|
+
AI agent quota/rate-limit fetching library for Claude, Gemini, Copilot, and Codex.
|
|
4
4
|
|
|
5
5
|
This package extracts the **quota fetching** layer from agent-runner so it can be reused
|
|
6
6
|
independently. Gate/ramp evaluation logic (e.g. `evaluateUsageGate`) is intentionally kept
|
|
@@ -22,7 +22,6 @@ npx @metyatech/ai-quota
|
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
ai-quota [agent] Show quota for all agents, or a single named agent
|
|
25
|
-
ai-quota record [agent] Record usage for agents with local tracking (e.g. amazon-q)
|
|
26
25
|
ai-quota --json Machine-readable JSON output
|
|
27
26
|
ai-quota --mcp Start as an MCP server
|
|
28
27
|
ai-quota --quiet Suppress non-error output (useful in scripts)
|
|
@@ -31,7 +30,7 @@ ai-quota --help Show usage information
|
|
|
31
30
|
ai-quota --version Show version
|
|
32
31
|
```
|
|
33
32
|
|
|
34
|
-
Supported agent names: `claude`, `gemini`, `copilot`, `
|
|
33
|
+
Supported agent names: `claude`, `gemini`, `copilot`, `codex`
|
|
35
34
|
|
|
36
35
|
### Usage Examples
|
|
37
36
|
|
|
@@ -40,11 +39,6 @@ Supported agent names: `claude`, `gemini`, `copilot`, `amazon-q`, `codex`
|
|
|
40
39
|
ai-quota
|
|
41
40
|
```
|
|
42
41
|
|
|
43
|
-
**Record Amazon Q usage (+1 request):**
|
|
44
|
-
```bash
|
|
45
|
-
ai-quota record amazon-q
|
|
46
|
-
```
|
|
47
|
-
|
|
48
42
|
## Model Context Protocol (MCP)
|
|
49
43
|
|
|
50
44
|
`ai-quota` can act as an MCP server, allowing AI agents (like Claude Desktop) to check your
|
|
@@ -83,13 +77,13 @@ without needing to explicitly call a tool.
|
|
|
83
77
|
### Human-readable output example
|
|
84
78
|
|
|
85
79
|
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
AGENT STATUS LIMIT DETAILS
|
|
81
|
+
----------- --------- ----- ---------------------------------------------------------------
|
|
82
|
+
claude CAN_USE 5h 5h: 8% used (reset in 1h 39m), 7d: 22% used (reset in 5d 20h 39m)
|
|
83
|
+
gemini/pro CAN_USE pro 4% used (reset in 14h 14m)
|
|
84
|
+
gemini/flash CAN_USE flash 40% used (reset in 14h 18m)
|
|
85
|
+
copilot LOW_QUOTA - 72% used (reset in 9d 11h)
|
|
86
|
+
codex CAN_USE 5h 5h: 65% used (reset in 3h), 7d: 21% used (reset in 6d)
|
|
93
87
|
```
|
|
94
88
|
|
|
95
89
|
### JSON output example
|
|
@@ -100,11 +94,10 @@ ai-quota --json
|
|
|
100
94
|
|
|
101
95
|
```json
|
|
102
96
|
{
|
|
103
|
-
"claude": { "
|
|
104
|
-
"gemini": { "
|
|
105
|
-
"copilot": { "
|
|
106
|
-
"
|
|
107
|
-
"codex": { "usedPercent": 65, "resetsAt": "2026-02-19T14:50:56Z", "fiveHour": { ... }, "weekly": { ... } }
|
|
97
|
+
"claude": { "status": "ok", "reason": null, "error": null, "data": { ... }, "display": "5h: 8% used (...)" },
|
|
98
|
+
"gemini": { "status": "ok", "reason": null, "error": null, "data": { ... }, "display": "pro: 4% used (...)" },
|
|
99
|
+
"copilot": { "status": "ok", "reason": null, "error": null, "data": { ... }, "display": "72% used (...)" },
|
|
100
|
+
"codex": { "status": "ok", "reason": null, "error": null, "data": { ... }, "display": "5h: 65% used (...)" }
|
|
108
101
|
}
|
|
109
102
|
```
|
|
110
103
|
|
|
@@ -115,8 +108,7 @@ ai-quota --json
|
|
|
115
108
|
| Claude | `~/.claude/.credentials.json` |
|
|
116
109
|
| Gemini | `~/.gemini/oauth_creds.json` |
|
|
117
110
|
| Copilot | `GITHUB_TOKEN` env var, `gh auth token` CLI, or `hosts.yml` |
|
|
118
|
-
|
|
|
119
|
-
| Codex | `~/.codex/sessions/` JSONL files, or `~/.codex/auth.json` |
|
|
111
|
+
| Codex | `~/.codex/auth.json` |
|
|
120
112
|
|
|
121
113
|
Exit code is `0` on success. Exit code `1` if any agent fetch fails.
|
|
122
114
|
|
|
@@ -155,15 +147,7 @@ console.log(results.gemini.display); // "skipped"
|
|
|
155
147
|
| Claude | `~/.claude/.credentials.json` | REST (Anthropic OAuth) |
|
|
156
148
|
| Gemini | `~/.gemini/oauth_creds.json` | REST (Google OAuth) |
|
|
157
149
|
| Copilot | GitHub token (caller-provided) | REST (GitHub API) |
|
|
158
|
-
|
|
|
159
|
-
| Codex | JSONL session files / ChatGPT backend API | Local files + REST |
|
|
160
|
-
|
|
161
|
-
> **Amazon Q limitation:** Amazon Q Developer (free tier) does not provide a public API for
|
|
162
|
-
> querying usage or quota programmatically as of February 2026. There is no official AWS SDK
|
|
163
|
-
> method, REST endpoint, or CLI command that returns the number of agentic requests consumed
|
|
164
|
-
> against the monthly free-tier limit for Builder ID users. This library uses a local JSON
|
|
165
|
-
> counter file as the best available approach. Call `recordAmazonQUsage` after each Amazon Q
|
|
166
|
-
> invocation to keep the counter accurate.
|
|
150
|
+
| Codex | `~/.codex/auth.json` | REST (ChatGPT internal) |
|
|
167
151
|
|
|
168
152
|
## Requirements
|
|
169
153
|
|
|
@@ -226,37 +210,15 @@ Options:
|
|
|
226
210
|
| `apiBaseUrl` | `string` | `https://api.github.com` | Override GitHub API base URL |
|
|
227
211
|
| `apiVersion` | `string` | `2025-05-01` | GitHub API version header |
|
|
228
212
|
|
|
229
|
-
### Amazon Q
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
import {
|
|
233
|
-
fetchAmazonQRateLimits,
|
|
234
|
-
recordAmazonQUsage,
|
|
235
|
-
resolveAmazonQUsageStatePath
|
|
236
|
-
} from "@metyatech/ai-quota";
|
|
237
|
-
|
|
238
|
-
const statePath = resolveAmazonQUsageStatePath("/path/to/workdir");
|
|
239
|
-
|
|
240
|
-
// After each Amazon Q invocation:
|
|
241
|
-
recordAmazonQUsage(statePath);
|
|
242
|
-
|
|
243
|
-
// Check current quota:
|
|
244
|
-
const snapshot = fetchAmazonQRateLimits(statePath, 50 /* monthly limit */);
|
|
245
|
-
console.log("Used:", snapshot.used, "/", snapshot.limit);
|
|
246
|
-
console.log("Remaining:", snapshot.percentRemaining, "%");
|
|
247
|
-
```
|
|
248
|
-
|
|
249
213
|
### Codex
|
|
250
214
|
|
|
251
215
|
```typescript
|
|
252
216
|
import { fetchCodexRateLimits, rateLimitSnapshotToStatus } from "@metyatech/ai-quota";
|
|
253
217
|
|
|
254
218
|
const snapshot = await fetchCodexRateLimits({ codexHome: "~/.codex" });
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
console.log("Weekly % left:", weekly?.percentLeft);
|
|
259
|
-
}
|
|
219
|
+
const status = rateLimitSnapshotToStatus(snapshot);
|
|
220
|
+
const weekly = status?.windows.find((w) => w.key === "weekly");
|
|
221
|
+
console.log("Weekly % left:", weekly?.percentLeft);
|
|
260
222
|
```
|
|
261
223
|
|
|
262
224
|
Options for `fetchCodexRateLimits`:
|
|
@@ -264,7 +226,7 @@ Options for `fetchCodexRateLimits`:
|
|
|
264
226
|
| Option | Type | Default | Description |
|
|
265
227
|
| ---------------- | ---------- | ---------- | ------------------------------------ |
|
|
266
228
|
| `codexHome` | `string` | `~/.codex` | Path to the Codex home directory |
|
|
267
|
-
| `timeoutSeconds` | `number` | `20` | HTTP API
|
|
229
|
+
| `timeoutSeconds` | `number` | `20` | HTTP API request timeout in seconds |
|
|
268
230
|
| `timingSink` | `function` | none | Callback for per-phase timing (ms) |
|
|
269
231
|
|
|
270
232
|
## Dev commands
|
package/dist/claude.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export type { ClaudeUsageData, ClaudeUsageBucket } from "./types.js";
|
|
|
10
10
|
* @returns A promise resolving to ClaudeUsageData or null if credentials are
|
|
11
11
|
* missing, expired, or the API request fails.
|
|
12
12
|
*/
|
|
13
|
-
export declare function fetchClaudeRateLimits(timeoutMs?: number): Promise<ClaudeUsageData
|
|
13
|
+
export declare function fetchClaudeRateLimits(timeoutMs?: number): Promise<ClaudeUsageData>;
|
|
14
14
|
//# sourceMappingURL=claude.d.ts.map
|
package/dist/claude.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGlD,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA2CrE;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,GAAE,MAAa,GACvB,OAAO,CAAC,eAAe,CAAC,CAuF1B"}
|
package/dist/claude.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { QuotaFetchError } from "./errors.js";
|
|
3
4
|
function getClaudeConfigDir() {
|
|
4
5
|
const home = process.env.USERPROFILE ?? process.env.HOME ?? "";
|
|
5
6
|
return path.join(home, ".claude");
|
|
@@ -7,10 +8,19 @@ function getClaudeConfigDir() {
|
|
|
7
8
|
function readClaudeCredentials() {
|
|
8
9
|
const credsPath = path.join(getClaudeConfigDir(), ".credentials.json");
|
|
9
10
|
try {
|
|
10
|
-
if (!fs.existsSync(credsPath))
|
|
11
|
-
|
|
11
|
+
if (!fs.existsSync(credsPath)) {
|
|
12
|
+
throw new QuotaFetchError("no_credentials", `Claude credentials not found at ${credsPath}`);
|
|
13
|
+
}
|
|
12
14
|
const raw = fs.readFileSync(credsPath, "utf8");
|
|
13
|
-
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = JSON.parse(raw);
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
throw new QuotaFetchError("parse_error", `Failed to parse Claude credentials at ${credsPath}`, {
|
|
21
|
+
cause: e
|
|
22
|
+
});
|
|
23
|
+
}
|
|
14
24
|
if (!parsed || typeof parsed !== "object")
|
|
15
25
|
return null;
|
|
16
26
|
const record = parsed;
|
|
@@ -28,8 +38,10 @@ function readClaudeCredentials() {
|
|
|
28
38
|
return null;
|
|
29
39
|
return { accessToken, expiresAt };
|
|
30
40
|
}
|
|
31
|
-
catch {
|
|
32
|
-
|
|
41
|
+
catch (e) {
|
|
42
|
+
if (e instanceof QuotaFetchError)
|
|
43
|
+
throw e;
|
|
44
|
+
throw new QuotaFetchError("api_error", "Failed to read Claude credentials.", { cause: e });
|
|
33
45
|
}
|
|
34
46
|
}
|
|
35
47
|
/**
|
|
@@ -45,11 +57,13 @@ function readClaudeCredentials() {
|
|
|
45
57
|
export async function fetchClaudeRateLimits(timeoutMs = 5000) {
|
|
46
58
|
try {
|
|
47
59
|
const creds = readClaudeCredentials();
|
|
48
|
-
if (!creds)
|
|
49
|
-
|
|
60
|
+
if (!creds) {
|
|
61
|
+
throw new QuotaFetchError("no_credentials", "Claude credentials missing.");
|
|
62
|
+
}
|
|
50
63
|
// Check token expiry with 5-minute buffer
|
|
51
|
-
if (Date.now() + 300_000 >= creds.expiresAt)
|
|
52
|
-
|
|
64
|
+
if (Date.now() + 300_000 >= creds.expiresAt) {
|
|
65
|
+
throw new QuotaFetchError("token_expired", "Claude access token is expired.");
|
|
66
|
+
}
|
|
53
67
|
const controller = new AbortController();
|
|
54
68
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
55
69
|
let res;
|
|
@@ -64,14 +78,23 @@ export async function fetchClaudeRateLimits(timeoutMs = 5000) {
|
|
|
64
78
|
signal: controller.signal
|
|
65
79
|
});
|
|
66
80
|
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
83
|
+
throw new QuotaFetchError("timeout", "Claude usage request timed out.", { cause: e });
|
|
84
|
+
}
|
|
85
|
+
throw new QuotaFetchError("network_error", "Claude usage request failed.", { cause: e });
|
|
86
|
+
}
|
|
67
87
|
finally {
|
|
68
88
|
clearTimeout(timer);
|
|
69
89
|
}
|
|
70
|
-
if (!res.ok)
|
|
71
|
-
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
const reason = res.status === 401 || res.status === 403 ? "auth_failed" : "api_error";
|
|
92
|
+
throw new QuotaFetchError(reason, `Claude usage request failed (${res.status} ${res.statusText}).`, { httpStatus: res.status });
|
|
93
|
+
}
|
|
72
94
|
const data = (await res.json());
|
|
73
|
-
if (!data || typeof data !== "object")
|
|
74
|
-
|
|
95
|
+
if (!data || typeof data !== "object") {
|
|
96
|
+
throw new QuotaFetchError("parse_error", "Claude usage response was not a JSON object.");
|
|
97
|
+
}
|
|
75
98
|
const record = data;
|
|
76
99
|
const parseBucket = (val) => {
|
|
77
100
|
if (!val || typeof val !== "object")
|
|
@@ -95,15 +118,18 @@ export async function fetchClaudeRateLimits(timeoutMs = 5000) {
|
|
|
95
118
|
const utilization = typeof e.utilization === "number" && Number.isFinite(e.utilization) ? e.utilization : 0;
|
|
96
119
|
return { is_enabled, monthly_limit, used_credits, utilization };
|
|
97
120
|
};
|
|
98
|
-
|
|
121
|
+
const out = {
|
|
99
122
|
five_hour: parseBucket(record.five_hour),
|
|
100
123
|
seven_day: parseBucket(record.seven_day),
|
|
101
124
|
seven_day_sonnet: parseBucket(record.seven_day_sonnet),
|
|
102
125
|
extra_usage: parseExtraUsage(record.extra_usage)
|
|
103
126
|
};
|
|
127
|
+
return out;
|
|
104
128
|
}
|
|
105
|
-
catch {
|
|
106
|
-
|
|
129
|
+
catch (e) {
|
|
130
|
+
if (e instanceof QuotaFetchError)
|
|
131
|
+
throw e;
|
|
132
|
+
throw new QuotaFetchError("unknown", "Claude usage fetch failed.", { cause: e });
|
|
107
133
|
}
|
|
108
134
|
}
|
|
109
135
|
//# sourceMappingURL=claude.js.map
|
package/dist/claude.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -2,19 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* ai-quota CLI
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import os from "node:os";
|
|
7
|
-
import { fetchAllRateLimits, runMcpServer, SUPPORTED_AGENTS, agentToSdkKey, recordAmazonQUsage, resolveAmazonQUsageStatePath } from "./index.js";
|
|
5
|
+
import { fetchAllRateLimits, runMcpServer, SUPPORTED_AGENTS, agentToSdkKey } from "./index.js";
|
|
8
6
|
import { getVersion } from "./utils.js";
|
|
9
|
-
|
|
10
|
-
function padName(name) {
|
|
11
|
-
return (name + ":").padEnd(11);
|
|
12
|
-
}
|
|
7
|
+
import { buildHumanRows, formatHumanTable } from "./human-output.js";
|
|
13
8
|
function showHelp() {
|
|
14
9
|
process.stdout.write(`ai-quota v${getVersion()}\n\n` +
|
|
15
10
|
"Usage:\n" +
|
|
16
11
|
" ai-quota [agent] Show quota for all agents, or a specific agent\n" +
|
|
17
|
-
" ai-quota record [agent] Record usage for agents that require local tracking (e.g. amazon-q)\n" +
|
|
18
12
|
" ai-quota --json Output machine-readable JSON\n" +
|
|
19
13
|
" ai-quota --mcp Start as an MCP server\n" +
|
|
20
14
|
" ai-quota --quiet Suppress non-error output\n" +
|
|
@@ -22,25 +16,8 @@ function showHelp() {
|
|
|
22
16
|
" ai-quota --help Show this help message\n" +
|
|
23
17
|
" ai-quota --version Show version\n\n" +
|
|
24
18
|
"Agents: " + SUPPORTED_AGENTS.join(", ") + "\n" +
|
|
25
|
-
"Output:
|
|
26
|
-
"Note:
|
|
27
|
-
}
|
|
28
|
-
async function handleRecord(args) {
|
|
29
|
-
const target = args[0];
|
|
30
|
-
if (!target) {
|
|
31
|
-
process.stderr.write("Error: 'record' requires an agent name (e.g. 'ai-quota record amazon-q')\n");
|
|
32
|
-
process.exitCode = 1;
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (target === "amazon-q") {
|
|
36
|
-
const statePath = resolveAmazonQUsageStatePath(os.homedir());
|
|
37
|
-
const newState = recordAmazonQUsage(statePath);
|
|
38
|
-
process.stdout.write(`Recorded usage for ${target}. Current total: ${newState.used} for ${newState.periodKey}\n`);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
process.stderr.write(`Error: Agent '${target}' does not support manual usage recording.\n`);
|
|
42
|
-
process.exitCode = 1;
|
|
43
|
-
}
|
|
19
|
+
"Output: table with AGENT, STATUS, LIMIT, DETAILS\n" +
|
|
20
|
+
"Note: Use --json for scripts.\n");
|
|
44
21
|
}
|
|
45
22
|
async function main() {
|
|
46
23
|
const args = process.argv.slice(2);
|
|
@@ -52,11 +29,6 @@ async function main() {
|
|
|
52
29
|
process.stdout.write(`${getVersion()}\n`);
|
|
53
30
|
return;
|
|
54
31
|
}
|
|
55
|
-
// Handle 'record' subcommand
|
|
56
|
-
if (args[0] === "record") {
|
|
57
|
-
await handleRecord(args.slice(1));
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
32
|
if (args.includes("--mcp")) {
|
|
61
33
|
await runMcpServer();
|
|
62
34
|
return;
|
|
@@ -81,15 +53,18 @@ async function main() {
|
|
|
81
53
|
if (res.status === "error")
|
|
82
54
|
anyError = true;
|
|
83
55
|
if (jsonMode) {
|
|
84
|
-
outputJson[agent] =
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
56
|
+
outputJson[agent] = {
|
|
57
|
+
status: res.status,
|
|
58
|
+
reason: res.reason,
|
|
59
|
+
error: res.error,
|
|
60
|
+
data: res.data,
|
|
61
|
+
display: res.display
|
|
62
|
+
};
|
|
88
63
|
}
|
|
89
64
|
}
|
|
90
65
|
if (!jsonMode && !quiet) {
|
|
91
|
-
const
|
|
92
|
-
process.stdout.write(
|
|
66
|
+
const rows = buildHumanRows(allResults, { agents: agentsToDisplay, now: new Date() });
|
|
67
|
+
process.stdout.write(formatHumanTable(rows) + "\n");
|
|
93
68
|
}
|
|
94
69
|
if (jsonMode && !quiet) {
|
|
95
70
|
process.stdout.write(JSON.stringify(outputJson, null, 2) + "\n");
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/codex.d.ts
CHANGED
|
@@ -19,21 +19,13 @@ export type FetchCodexRateLimitsOptions = {
|
|
|
19
19
|
timingSink?: (phase: string, durationMs: number) => void;
|
|
20
20
|
};
|
|
21
21
|
/**
|
|
22
|
-
* Converts a raw `RateLimitSnapshot`
|
|
23
|
-
* API) into a structured `CodexStatus` with labelled usage windows.
|
|
22
|
+
* Converts a raw `RateLimitSnapshot` into a structured `CodexStatus` with labelled usage windows.
|
|
24
23
|
*/
|
|
25
24
|
export declare function rateLimitSnapshotToStatus(snapshot: RateLimitSnapshot, now?: Date): CodexStatus | null;
|
|
26
25
|
/**
|
|
27
|
-
* Fetches Codex (ChatGPT) rate limit data.
|
|
26
|
+
* Fetches Codex (ChatGPT) rate limit data from the remote ChatGPT backend API.
|
|
28
27
|
*
|
|
29
|
-
*
|
|
30
|
-
* 1. Reads the most recent JSONL session file from `~/.codex/sessions/`.
|
|
31
|
-
* This is the fastest method and handles both modern and legacy log formats.
|
|
32
|
-
* 2. If no session data is found, it attempts to call the ChatGPT backend API
|
|
33
|
-
* using the access token found in `~/.codex/auth.json`.
|
|
34
|
-
*
|
|
35
|
-
* @param options - Configuration for file paths and timeouts
|
|
36
|
-
* @returns A promise resolving to a RateLimitSnapshot or null if no source is available
|
|
28
|
+
* Reads credentials from `~/.codex/auth.json` and calls the `/backend-api/wham/usage` endpoint.
|
|
37
29
|
*/
|
|
38
|
-
export declare function fetchCodexRateLimits(options?: FetchCodexRateLimitsOptions): Promise<RateLimitSnapshot
|
|
30
|
+
export declare function fetchCodexRateLimits(options?: FetchCodexRateLimitsOptions): Promise<RateLimitSnapshot>;
|
|
39
31
|
//# sourceMappingURL=codex.d.ts.map
|
package/dist/codex.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../src/codex.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAmB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../src/codex.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAmB,MAAM,YAAY,CAAC;AAGrE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,cAAc,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D,CAAC;AAoDF;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,GAAG,GAAE,IAAiB,GACrB,WAAW,GAAG,IAAI,CAkEpB;AA2ID;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,iBAAiB,CAAC,CAI5B"}
|