@metyatech/ai-quota 0.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/dist/gemini.js ADDED
@@ -0,0 +1,235 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ const ENV_GEMINI_OAUTH_CLIENT_ID = "AGENT_RUNNER_GEMINI_OAUTH_CLIENT_ID";
5
+ const ENV_GEMINI_OAUTH_CLIENT_SECRET = "AGENT_RUNNER_GEMINI_OAUTH_CLIENT_SECRET";
6
+ let cachedGeminiOauthClientInfo = null;
7
+ function getClientIdFromIdToken(idToken) {
8
+ if (typeof idToken !== "string")
9
+ return undefined;
10
+ const parts = idToken.split(".");
11
+ if (parts.length !== 3)
12
+ return undefined;
13
+ try {
14
+ const payloadJson = Buffer.from(parts[1], "base64url").toString("utf8");
15
+ const payload = JSON.parse(payloadJson);
16
+ if (typeof payload?.aud === "string" && payload.aud.length > 0)
17
+ return payload.aud;
18
+ if (typeof payload?.azp === "string" && payload.azp.length > 0)
19
+ return payload.azp;
20
+ return undefined;
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ }
26
+ function readGeminiOauthClientInfoFromEnv() {
27
+ const clientId = process.env[ENV_GEMINI_OAUTH_CLIENT_ID];
28
+ const clientSecret = process.env[ENV_GEMINI_OAUTH_CLIENT_SECRET];
29
+ if (!clientId && !clientSecret)
30
+ return null;
31
+ return {
32
+ clientId: typeof clientId === "string" && clientId.length > 0 ? clientId : undefined,
33
+ clientSecret: typeof clientSecret === "string" && clientSecret.length > 0 ? clientSecret : undefined,
34
+ source: "env"
35
+ };
36
+ }
37
+ function extractOauthConstantsFromJs(content) {
38
+ const clientIdMatch = content.match(/const\s+OAUTH_CLIENT_ID\s*=\s*['"]([^'"]+)['"]/);
39
+ const clientSecretMatch = content.match(/const\s+OAUTH_CLIENT_SECRET\s*=\s*['"]([^'"]+)['"]/);
40
+ const clientId = clientIdMatch?.[1];
41
+ const clientSecret = clientSecretMatch?.[1];
42
+ if (!clientId && !clientSecret)
43
+ return null;
44
+ return {
45
+ clientId,
46
+ clientSecret,
47
+ source: "gemini-cli"
48
+ };
49
+ }
50
+ function tryReadGeminiCliOauthClientInfoFromWellKnownPaths() {
51
+ const candidates = [];
52
+ if (process.platform === "win32") {
53
+ const appData = process.env.APPDATA;
54
+ if (appData) {
55
+ const npmGlobal = path.join(appData, "npm", "node_modules");
56
+ candidates.push(path.join(npmGlobal, "@google", "gemini-cli", "node_modules", "@google", "gemini-cli-core", "dist", "src", "code_assist", "oauth2.js"), path.join(npmGlobal, "@google", "gemini-cli-core", "dist", "src", "code_assist", "oauth2.js"));
57
+ }
58
+ }
59
+ for (const filePath of candidates) {
60
+ try {
61
+ if (!fs.existsSync(filePath))
62
+ continue;
63
+ const content = fs.readFileSync(filePath, "utf8");
64
+ const extracted = extractOauthConstantsFromJs(content);
65
+ if (extracted)
66
+ return extracted;
67
+ }
68
+ catch {
69
+ // ignore and continue
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ function getGeminiOauthClientInfo() {
75
+ if (cachedGeminiOauthClientInfo)
76
+ return cachedGeminiOauthClientInfo;
77
+ cachedGeminiOauthClientInfo =
78
+ readGeminiOauthClientInfoFromEnv() ?? tryReadGeminiCliOauthClientInfoFromWellKnownPaths();
79
+ return cachedGeminiOauthClientInfo;
80
+ }
81
+ async function refreshAccessToken(options) {
82
+ const params = new URLSearchParams();
83
+ params.set("client_id", options.clientId);
84
+ params.set("client_secret", options.clientSecret);
85
+ params.set("refresh_token", options.refreshToken);
86
+ params.set("grant_type", "refresh_token");
87
+ const res = await fetch("https://oauth2.googleapis.com/token", {
88
+ method: "POST",
89
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
90
+ body: params.toString()
91
+ });
92
+ if (!res.ok) {
93
+ throw new Error(`Failed to refresh Google access token: ${res.status} ${await res.text()}`);
94
+ }
95
+ const data = (await res.json());
96
+ if (typeof data?.access_token !== "string" || data.access_token.length === 0) {
97
+ throw new Error("Google token refresh response missing access_token.");
98
+ }
99
+ const expiryDate = typeof data?.expires_in === "number"
100
+ ? Date.now() + Math.max(0, data.expires_in) * 1000
101
+ : undefined;
102
+ return { accessToken: data.access_token, expiryDate };
103
+ }
104
+ async function getCredentials() {
105
+ const credsPath = path.join(os.homedir(), ".gemini", "oauth_creds.json");
106
+ if (!fs.existsSync(credsPath)) {
107
+ throw new Error(`Gemini OAuth credentials not found at ${credsPath}`);
108
+ }
109
+ const raw = fs.readFileSync(credsPath, "utf8");
110
+ const creds = JSON.parse(raw);
111
+ let accessToken = creds.access_token;
112
+ const now = Date.now();
113
+ // Buffer of 5 minutes
114
+ if (!accessToken ||
115
+ (typeof creds.expiry_date === "number" && creds.expiry_date < now + 300000)) {
116
+ if (creds.refresh_token) {
117
+ const discovered = getGeminiOauthClientInfo();
118
+ const clientId = getClientIdFromIdToken(creds.id_token) ??
119
+ discovered?.clientId ??
120
+ (typeof creds.client_id === "string" && creds.client_id.length > 0
121
+ ? creds.client_id
122
+ : undefined);
123
+ const clientSecret = discovered?.clientSecret ??
124
+ (typeof creds.client_secret === "string" && creds.client_secret.length > 0
125
+ ? creds.client_secret
126
+ : undefined);
127
+ if (!clientId) {
128
+ throw new Error(`Gemini OAuth refresh requires a client ID; set ${ENV_GEMINI_OAUTH_CLIENT_ID} or install Gemini CLI.`);
129
+ }
130
+ if (!clientSecret) {
131
+ throw new Error(`Gemini OAuth refresh requires a client secret; set ${ENV_GEMINI_OAUTH_CLIENT_SECRET} or install Gemini CLI.`);
132
+ }
133
+ const refreshed = await refreshAccessToken({
134
+ refreshToken: creds.refresh_token,
135
+ clientId,
136
+ clientSecret
137
+ });
138
+ accessToken = refreshed.accessToken;
139
+ try {
140
+ creds.access_token = accessToken;
141
+ if (typeof refreshed.expiryDate === "number") {
142
+ creds.expiry_date = refreshed.expiryDate;
143
+ }
144
+ fs.writeFileSync(credsPath, JSON.stringify(creds, null, 2), "utf8");
145
+ }
146
+ catch {
147
+ // Best-effort: keep the refreshed token in memory even if persisting fails.
148
+ }
149
+ }
150
+ else {
151
+ throw new Error("Gemini access token expired and no refresh token available.");
152
+ }
153
+ }
154
+ return { accessToken: accessToken };
155
+ }
156
+ /**
157
+ * Fetches Gemini quota usage from the Cloud Code Assist API.
158
+ *
159
+ * Reads OAuth credentials from `~/.gemini/oauth_creds.json` and automatically
160
+ * refreshes the access token when needed. Returns null on any error.
161
+ *
162
+ * The environment variables `AGENT_RUNNER_GEMINI_OAUTH_CLIENT_ID` and
163
+ * `AGENT_RUNNER_GEMINI_OAUTH_CLIENT_SECRET` can override the OAuth client
164
+ * credentials when the Gemini CLI is not installed.
165
+ */
166
+ export async function fetchGeminiRateLimits() {
167
+ try {
168
+ const { accessToken } = await getCredentials();
169
+ // 1. Load Code Assist to get the project ID
170
+ const loadRes = await fetch("https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist", {
171
+ method: "POST",
172
+ headers: {
173
+ Authorization: `Bearer ${accessToken}`,
174
+ "Content-Type": "application/json",
175
+ "User-Agent": "ai-quota"
176
+ },
177
+ body: JSON.stringify({
178
+ metadata: {
179
+ ideType: "GEMINI_CLI",
180
+ platform: process.platform === "win32" ? "WINDOWS_AMD64" : "LINUX_AMD64"
181
+ }
182
+ })
183
+ });
184
+ if (!loadRes.ok) {
185
+ throw new Error(`loadCodeAssist failed: ${loadRes.status} ${await loadRes.text()}`);
186
+ }
187
+ const loadData = (await loadRes.json());
188
+ const projectId = loadData.cloudaicompanionProject;
189
+ if (!projectId) {
190
+ throw new Error("No cloudaicompanionProject found in loadCodeAssist response.");
191
+ }
192
+ // 2. Retrieve User Quota
193
+ const quotaRes = await fetch("https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota", {
194
+ method: "POST",
195
+ headers: {
196
+ Authorization: `Bearer ${accessToken}`,
197
+ "Content-Type": "application/json",
198
+ "User-Agent": "ai-quota"
199
+ },
200
+ body: JSON.stringify({ project: projectId })
201
+ });
202
+ if (!quotaRes.ok) {
203
+ throw new Error(`retrieveUserQuota failed: ${quotaRes.status} ${await quotaRes.text()}`);
204
+ }
205
+ const quotaData = (await quotaRes.json());
206
+ const usage = {};
207
+ if (Array.isArray(quotaData.buckets)) {
208
+ for (const bucket of quotaData.buckets) {
209
+ const modelId = bucket.modelId;
210
+ if (modelId === "gemini-3-pro-preview" || modelId === "gemini-3-flash-preview") {
211
+ // remainingFraction is usually between 0.0 and 1.0.
212
+ // Keep fractional precision so tiny consumption (<0.5%) does not get rounded away.
213
+ const remainingFraction = typeof bucket.remainingFraction === "number" &&
214
+ Number.isFinite(bucket.remainingFraction)
215
+ ? Math.min(Math.max(bucket.remainingFraction, 0), 1)
216
+ : 1.0;
217
+ const limit = 100; // percentage scale
218
+ const usedRaw = (1.0 - remainingFraction) * 100;
219
+ const used = Math.round(usedRaw * 1_000_000) / 1_000_000;
220
+ usage[modelId] = {
221
+ limit,
222
+ usage: used,
223
+ resetAt: bucket.resetTime ? new Date(bucket.resetTime) : new Date(Date.now() + 3600000)
224
+ };
225
+ }
226
+ }
227
+ }
228
+ return usage;
229
+ }
230
+ catch (error) {
231
+ console.error("Error fetching Gemini usage:", error);
232
+ return null;
233
+ }
234
+ }
235
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../src/gemini.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @metyatech/ai-quota
3
+ *
4
+ * Quota / rate-limit fetching for Claude, Gemini, Copilot, Amazon Q, and Codex.
5
+ * Only fetching is provided here — gate/ramp evaluation logic stays in the caller.
6
+ */
7
+ export type { RateLimitWindow, RateLimitSnapshot } from "./types.js";
8
+ export type { ClaudeUsageData, ClaudeUsageBucket } from "./types.js";
9
+ export type { GeminiUsage, GeminiModelUsage } from "./types.js";
10
+ export type { CopilotUsage } from "./types.js";
11
+ export type { AmazonQUsageSnapshot } from "./types.js";
12
+ export { fetchClaudeRateLimits } from "./claude.js";
13
+ export { fetchGeminiRateLimits } from "./gemini.js";
14
+ export { fetchCopilotRateLimits, parseCopilotUserInfo, parseCopilotQuotaHeader } from "./copilot.js";
15
+ export type { FetchCopilotRateLimitsOptions } from "./copilot.js";
16
+ export { fetchAmazonQRateLimits, recordAmazonQUsage, loadAmazonQUsageState, saveAmazonQUsageState, resolveAmazonQUsageStatePath } from "./amazon-q.js";
17
+ export { fetchCodexRateLimits, rateLimitSnapshotToStatus } from "./codex.js";
18
+ export type { CodexStatus, UsageWindow, UsageWindowKey, FetchCodexRateLimitsOptions } from "./codex.js";
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACrE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,EACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,6BAA6B,EAAE,MAAM,cAAc,CAAC;AAGlE,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,4BAA4B,EAC7B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACd,2BAA2B,EAC5B,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @metyatech/ai-quota
3
+ *
4
+ * Quota / rate-limit fetching for Claude, Gemini, Copilot, Amazon Q, and Codex.
5
+ * Only fetching is provided here — gate/ramp evaluation logic stays in the caller.
6
+ */
7
+ // Claude
8
+ export { fetchClaudeRateLimits } from "./claude.js";
9
+ // Gemini
10
+ export { fetchGeminiRateLimits } from "./gemini.js";
11
+ // Copilot
12
+ export { fetchCopilotRateLimits, parseCopilotUserInfo, parseCopilotQuotaHeader } from "./copilot.js";
13
+ // Amazon Q
14
+ export { fetchAmazonQRateLimits, recordAmazonQUsage, loadAmazonQUsageState, saveAmazonQUsageState, resolveAmazonQUsageStatePath } from "./amazon-q.js";
15
+ // Codex
16
+ export { fetchCodexRateLimits, rateLimitSnapshotToStatus } from "./codex.js";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,SAAS;AACT,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,SAAS;AACT,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,UAAU;AACV,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,EACxB,MAAM,cAAc,CAAC;AAGtB,WAAW;AACX,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,4BAA4B,EAC7B,MAAM,eAAe,CAAC;AAEvB,QAAQ;AACR,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,YAAY,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Shared types for @metyatech/ai-quota.
3
+ *
4
+ * These types are intentionally kept compatible with the agent-runner
5
+ * usage types so that migration from local files to this package is
6
+ * a drop-in replacement.
7
+ */
8
+ export type RateLimitWindow = {
9
+ usedPercent?: number;
10
+ used_percent?: number;
11
+ windowDurationMins?: number | null;
12
+ window_minutes?: number | null;
13
+ windowMinutes?: number | null;
14
+ resetsAt?: number | null;
15
+ resets_at?: number | null;
16
+ };
17
+ export type RateLimitSnapshot = {
18
+ primary?: RateLimitWindow | null;
19
+ secondary?: RateLimitWindow | null;
20
+ credits?: unknown;
21
+ planType?: string | null;
22
+ plan_type?: string | null;
23
+ };
24
+ export type ClaudeUsageBucket = {
25
+ utilization: number;
26
+ resets_at: string;
27
+ };
28
+ export type ClaudeUsageData = {
29
+ five_hour: ClaudeUsageBucket | null;
30
+ seven_day: ClaudeUsageBucket | null;
31
+ seven_day_sonnet: ClaudeUsageBucket | null;
32
+ extra_usage: {
33
+ is_enabled: boolean;
34
+ monthly_limit: number | null;
35
+ used_credits: number;
36
+ utilization: number;
37
+ } | null;
38
+ };
39
+ export type GeminiModelUsage = {
40
+ limit: number;
41
+ usage: number;
42
+ resetAt: Date;
43
+ };
44
+ export type GeminiUsage = {
45
+ "gemini-3-pro-preview"?: GeminiModelUsage;
46
+ "gemini-3-flash-preview"?: GeminiModelUsage;
47
+ };
48
+ export type CopilotUsage = {
49
+ percentRemaining: number;
50
+ resetAt: Date;
51
+ entitlement: number;
52
+ overageUsed: number;
53
+ overageEnabled: boolean;
54
+ source: "user" | "header";
55
+ raw: unknown;
56
+ };
57
+ export type AmazonQUsageSnapshot = {
58
+ used: number;
59
+ limit: number;
60
+ percentRemaining: number;
61
+ resetAt: Date;
62
+ periodKey: string;
63
+ };
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,MAAM,eAAe,GAAG;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAMF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC3C,WAAW,EAAE;QACX,UAAU,EAAE,OAAO,CAAC;QACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB,GAAG,IAAI,CAAC;CACV,CAAC;AAMF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,sBAAsB,CAAC,EAAE,gBAAgB,CAAC;IAC1C,wBAAwB,CAAC,EAAE,gBAAgB,CAAC;CAC7C,CAAC;AAMF,MAAM,MAAM,YAAY,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,IAAI,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAMF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared types for @metyatech/ai-quota.
3
+ *
4
+ * These types are intentionally kept compatible with the agent-runner
5
+ * usage types so that migration from local files to this package is
6
+ * a drop-in replacement.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@metyatech/ai-quota",
3
+ "version": "0.2.0",
4
+ "description": "AI agent quota/rate-limit fetching library and CLI for Claude, Gemini, Copilot, Amazon Q, and Codex",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "ai-quota": "./dist/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/metyatech/ai-quota.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/metyatech/ai-quota/issues"
30
+ },
31
+ "homepage": "https://github.com/metyatech/ai-quota",
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json && node scripts/add-shebang.mjs",
37
+ "test": "vitest run",
38
+ "lint": "eslint . && tsc -p tsconfig.json --noEmit",
39
+ "format": "prettier --write .",
40
+ "format:check": "prettier --check .",
41
+ "verify": "npm run lint && npm test && npm run build"
42
+ },
43
+ "devDependencies": {
44
+ "@eslint/js": "^9.13.0",
45
+ "@types/node": "^22.10.0",
46
+ "@typescript-eslint/eslint-plugin": "^8.17.0",
47
+ "@typescript-eslint/parser": "^8.17.0",
48
+ "eslint": "^9.13.0",
49
+ "prettier": "^3.4.0",
50
+ "typescript": "^5.7.0",
51
+ "vitest": "^1.6.0"
52
+ }
53
+ }