@ereinha/opencode-enhanced-quotas 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.
Files changed (98) hide show
  1. package/README.md +333 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +42 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/constants.d.ts +13 -0
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +19 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/defaults.d.ts +3 -0
  11. package/dist/defaults.d.ts.map +1 -0
  12. package/dist/defaults.js +56 -0
  13. package/dist/defaults.js.map +1 -0
  14. package/dist/index.d.ts +7 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +449 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/interfaces.d.ts +210 -0
  19. package/dist/interfaces.d.ts.map +1 -0
  20. package/dist/interfaces.js +2 -0
  21. package/dist/interfaces.js.map +1 -0
  22. package/dist/logger.d.ts +15 -0
  23. package/dist/logger.d.ts.map +1 -0
  24. package/dist/logger.js +47 -0
  25. package/dist/logger.js.map +1 -0
  26. package/dist/plugin-state.d.ts +32 -0
  27. package/dist/plugin-state.d.ts.map +1 -0
  28. package/dist/plugin-state.js +81 -0
  29. package/dist/plugin-state.js.map +1 -0
  30. package/dist/providers/antigravity/auth.d.ts +12 -0
  31. package/dist/providers/antigravity/auth.d.ts.map +1 -0
  32. package/dist/providers/antigravity/auth.js +109 -0
  33. package/dist/providers/antigravity/auth.js.map +1 -0
  34. package/dist/providers/antigravity/index.d.ts +2 -0
  35. package/dist/providers/antigravity/index.d.ts.map +1 -0
  36. package/dist/providers/antigravity/index.js +2 -0
  37. package/dist/providers/antigravity/index.js.map +1 -0
  38. package/dist/providers/antigravity/provider.d.ts +34 -0
  39. package/dist/providers/antigravity/provider.d.ts.map +1 -0
  40. package/dist/providers/antigravity/provider.js +221 -0
  41. package/dist/providers/antigravity/provider.js.map +1 -0
  42. package/dist/providers/codex.d.ts +4 -0
  43. package/dist/providers/codex.d.ts.map +1 -0
  44. package/dist/providers/codex.js +233 -0
  45. package/dist/providers/codex.js.map +1 -0
  46. package/dist/providers/github.d.ts +4 -0
  47. package/dist/providers/github.d.ts.map +1 -0
  48. package/dist/providers/github.js +139 -0
  49. package/dist/providers/github.js.map +1 -0
  50. package/dist/quota-cache.d.ts +26 -0
  51. package/dist/quota-cache.d.ts.map +1 -0
  52. package/dist/quota-cache.js +107 -0
  53. package/dist/quota-cache.js.map +1 -0
  54. package/dist/registry.d.ts +3 -0
  55. package/dist/registry.d.ts.map +1 -0
  56. package/dist/registry.js +23 -0
  57. package/dist/registry.js.map +1 -0
  58. package/dist/services/aggregation-service.d.ts +34 -0
  59. package/dist/services/aggregation-service.d.ts.map +1 -0
  60. package/dist/services/aggregation-service.js +89 -0
  61. package/dist/services/aggregation-service.js.map +1 -0
  62. package/dist/services/config-loader.d.ts +32 -0
  63. package/dist/services/config-loader.d.ts.map +1 -0
  64. package/dist/services/config-loader.js +168 -0
  65. package/dist/services/config-loader.js.map +1 -0
  66. package/dist/services/history-service.d.ts +39 -0
  67. package/dist/services/history-service.d.ts.map +1 -0
  68. package/dist/services/history-service.js +207 -0
  69. package/dist/services/history-service.js.map +1 -0
  70. package/dist/services/prediction-engine.d.ts +51 -0
  71. package/dist/services/prediction-engine.d.ts.map +1 -0
  72. package/dist/services/prediction-engine.js +108 -0
  73. package/dist/services/prediction-engine.js.map +1 -0
  74. package/dist/services/quota-service.d.ts +42 -0
  75. package/dist/services/quota-service.d.ts.map +1 -0
  76. package/dist/services/quota-service.js +339 -0
  77. package/dist/services/quota-service.js.map +1 -0
  78. package/dist/ui/progress-bar.d.ts +20 -0
  79. package/dist/ui/progress-bar.d.ts.map +1 -0
  80. package/dist/ui/progress-bar.js +150 -0
  81. package/dist/ui/progress-bar.js.map +1 -0
  82. package/dist/ui/quota-table.d.ts +15 -0
  83. package/dist/ui/quota-table.d.ts.map +1 -0
  84. package/dist/ui/quota-table.js +137 -0
  85. package/dist/ui/quota-table.js.map +1 -0
  86. package/dist/utils/paths.d.ts +7 -0
  87. package/dist/utils/paths.d.ts.map +1 -0
  88. package/dist/utils/paths.js +37 -0
  89. package/dist/utils/paths.js.map +1 -0
  90. package/dist/utils/time.d.ts +3 -0
  91. package/dist/utils/time.d.ts.map +1 -0
  92. package/dist/utils/time.js +38 -0
  93. package/dist/utils/time.js.map +1 -0
  94. package/dist/utils/validation.d.ts +6 -0
  95. package/dist/utils/validation.d.ts.map +1 -0
  96. package/dist/utils/validation.js +66 -0
  97. package/dist/utils/validation.js.map +1 -0
  98. package/package.json +42 -0
@@ -0,0 +1,221 @@
1
+ import { formatRelativeTime } from "../../utils/time";
2
+ import { getCloudCredentials } from "./auth";
3
+ import { logger } from "../../logger";
4
+ const CLOUDCODE_ENDPOINTS = [
5
+ "https://daily-cloudcode-pa.sandbox.googleapis.com",
6
+ "https://autopush-cloudcode-pa.sandbox.googleapis.com",
7
+ "https://cloudcode-pa.googleapis.com",
8
+ ];
9
+ const CLOUDCODE_HEADERS = {
10
+ "Content-Type": "application/json",
11
+ "User-Agent": "antigravity/1.11.5 windows/amd64",
12
+ "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
13
+ "Client-Metadata": '{"ideType":"IDE_UNSPECIFIED","platform":"PLATFORM_UNSPECIFIED","pluginType":"GEMINI"}',
14
+ };
15
+ const DEFAULT_INDICATORS = [
16
+ { threshold: 0.2, symbol: "!" },
17
+ { threshold: 0.05, symbol: "!!" },
18
+ ];
19
+ function getIndicatorSymbol(fraction, indicators = DEFAULT_INDICATORS) {
20
+ if (indicators.length === 0)
21
+ return "";
22
+ const sorted = [...indicators].sort((a, b) => a.threshold - b.threshold);
23
+ for (const indicator of sorted) {
24
+ if (fraction <= indicator.threshold) {
25
+ return ` ${indicator.symbol}`;
26
+ }
27
+ }
28
+ return "";
29
+ }
30
+ async function fetchAvailableModels(accessToken, projectId, debugEnabled) {
31
+ const payload = projectId ? { project: projectId } : {};
32
+ let lastError = null;
33
+ const headers = {
34
+ ...CLOUDCODE_HEADERS,
35
+ Authorization: `Bearer ${accessToken}`,
36
+ };
37
+ for (const endpoint of CLOUDCODE_ENDPOINTS) {
38
+ try {
39
+ const url = `${endpoint}/v1internal:fetchAvailableModels`;
40
+ const controller = new AbortController();
41
+ const timeoutId = setTimeout(() => controller.abort(), 10000);
42
+ try {
43
+ if (debugEnabled) {
44
+ logger.debug("antigravity:request", {
45
+ endpoint,
46
+ url,
47
+ hasProjectId: !!projectId,
48
+ });
49
+ }
50
+ const response = await fetch(url, {
51
+ method: "POST",
52
+ headers,
53
+ body: JSON.stringify(payload),
54
+ signal: controller.signal,
55
+ });
56
+ if (debugEnabled) {
57
+ logger.debug("antigravity:response_meta", {
58
+ endpoint,
59
+ status: response.status,
60
+ ok: response.ok,
61
+ contentType: response.headers.get("content-type"),
62
+ });
63
+ }
64
+ if (response.status === 401) {
65
+ throw new Error("Authorization expired or invalid.");
66
+ }
67
+ if (response.status === 403) {
68
+ throw new Error("Access forbidden (403). Check your account permissions.");
69
+ }
70
+ if (!response.ok) {
71
+ const text = await response.text();
72
+ if (debugEnabled) {
73
+ logger.debug("antigravity:error_body", {
74
+ endpoint,
75
+ status: response.status,
76
+ bodyPreview: text.slice(0, 2000),
77
+ });
78
+ }
79
+ throw new Error(`Cloud Code API error ${response.status}: ${text.slice(0, 200)}`);
80
+ }
81
+ const json = (await response.json());
82
+ const modelCount = Object.keys(json.models || {}).length;
83
+ if (debugEnabled) {
84
+ logger.debug("antigravity:fetch_success", { modelCount });
85
+ }
86
+ if (debugEnabled) {
87
+ const sampleKeys = Object.keys(json.models || {}).slice(0, 8);
88
+ const sanitizedSample = {};
89
+ for (const key of sampleKeys) {
90
+ sanitizedSample[key] = json.models?.[key];
91
+ }
92
+ logger.debug("antigravity:raw_response_sample", {
93
+ modelCount,
94
+ sampleKeys,
95
+ sample: sanitizedSample,
96
+ });
97
+ }
98
+ return json;
99
+ }
100
+ finally {
101
+ clearTimeout(timeoutId);
102
+ }
103
+ }
104
+ catch (error) {
105
+ lastError =
106
+ error instanceof Error ? error : new Error(String(error));
107
+ if (lastError.message.includes("Authorization") ||
108
+ lastError.message.includes("forbidden") ||
109
+ lastError.message.includes("invalid_grant")) {
110
+ throw lastError;
111
+ }
112
+ }
113
+ }
114
+ throw lastError || new Error("All Cloud Code API endpoints failed");
115
+ }
116
+ export async function fetchCloudQuota(accessToken, projectId, debugEnabled = false) {
117
+ if (!accessToken) {
118
+ throw new Error("Access token is required for cloud quota fetching");
119
+ }
120
+ const response = await fetchAvailableModels(accessToken, projectId, debugEnabled);
121
+ const models = [];
122
+ if (response.models) {
123
+ for (const [modelKey, info] of Object.entries(response.models)) {
124
+ if (!info.quotaInfo)
125
+ continue;
126
+ models.push({
127
+ modelName: info.model || modelKey,
128
+ label: info.displayName || modelKey,
129
+ quotaInfo: {
130
+ remainingFraction: info.quotaInfo.remainingFraction ?? 0,
131
+ resetTime: info.quotaInfo.resetTime,
132
+ },
133
+ });
134
+ }
135
+ }
136
+ return {
137
+ account: {
138
+ projectId,
139
+ },
140
+ models,
141
+ timestamp: Date.now(),
142
+ };
143
+ }
144
+ /**
145
+ * Creates the Antigravity provider that returns flat, raw quota data.
146
+ * Grouping and aggregation is handled by the service layer via AggregatedGroups.
147
+ */
148
+ export function createAntigravityProvider(config = {}) {
149
+ return {
150
+ id: "antigravity",
151
+ async fetchQuota() {
152
+ const debugEnabled = !!config.debug;
153
+ logger.debug("provider:antigravity:fetch_start", {
154
+ configDebug: config.debug,
155
+ });
156
+ // Fetch cloud credentials (Google OAuth)
157
+ let credentials;
158
+ try {
159
+ credentials = await getCloudCredentials();
160
+ if (debugEnabled) {
161
+ logger.debug("provider:antigravity:auth_ok", {
162
+ projectId: credentials.projectId,
163
+ });
164
+ }
165
+ }
166
+ catch (e) {
167
+ logger.error("provider:antigravity:auth_failed", e);
168
+ throw e;
169
+ }
170
+ // Fetch live quota from Antigravity Cloud API
171
+ const cloudResult = await fetchCloudQuota(credentials.accessToken, credentials.projectId, debugEnabled);
172
+ if (debugEnabled) {
173
+ logger.debug("provider:antigravity:cloud_ok", {
174
+ modelCount: cloudResult.models.length,
175
+ });
176
+ }
177
+ // Return flat list of all models with quota info
178
+ const entries = [];
179
+ for (const model of cloudResult.models) {
180
+ if (!model.quotaInfo ||
181
+ typeof model.quotaInfo.remainingFraction !== "number") {
182
+ continue;
183
+ }
184
+ const label = model.label || model.modelName || "";
185
+ // Filter out internal/miscellaneous quotas (e.g. "chat 12345", "rev123")
186
+ const lowerLabel = label.toLowerCase();
187
+ if (/^chat \d+/.test(lowerLabel) || lowerLabel.startsWith("rev")) {
188
+ continue;
189
+ }
190
+ const remainingFraction = model.quotaInfo.remainingFraction;
191
+ const usedPercent = Math.max(0, Math.min(100, (1 - remainingFraction) * 100));
192
+ // Generate stable raw ID from model name
193
+ const rawId = `ag-raw-${label
194
+ .toLowerCase()
195
+ .replace(/[^a-z0-9]+/g, "-")
196
+ .replace(/^-|-$/g, "")}`;
197
+ const indicator = getIndicatorSymbol(remainingFraction, config.indicators);
198
+ let reset;
199
+ if (model.quotaInfo.resetTime) {
200
+ reset = `resets in ${formatRelativeTime(new Date(model.quotaInfo.resetTime))}`;
201
+ }
202
+ entries.push({
203
+ id: rawId,
204
+ providerName: `Antigravity ${label}`,
205
+ used: usedPercent,
206
+ limit: 100,
207
+ unit: "%",
208
+ reset,
209
+ info: indicator.trim() || undefined,
210
+ });
211
+ }
212
+ if (debugEnabled) {
213
+ logger.debug("provider:antigravity:fetch_ok", {
214
+ count: entries.length,
215
+ });
216
+ }
217
+ return entries;
218
+ },
219
+ };
220
+ }
221
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/providers/antigravity/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type IQuotaProvider, type QuotaData } from "../interfaces";
2
+ export declare function extractCodexQuota(payload: unknown): QuotaData[];
3
+ export declare function createCodexProvider(): IQuotaProvider;
4
+ //# sourceMappingURL=codex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/providers/codex.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAkPpE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,CAoC/D;AAED,wBAAgB,mBAAmB,IAAI,cAAc,CAqCpD"}
@@ -0,0 +1,233 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { AUTH_FILE } from "../utils/paths";
3
+ import { logger } from "../logger";
4
+ const DEFAULT_BASE_URL = "https://chatgpt.com/backend-api";
5
+ const REQUEST_TIMEOUT_MS = 15_000;
6
+ const MAX_ERROR_BODY_CHARS = 2_000;
7
+ async function readAuthFile() {
8
+ try {
9
+ const authPath = AUTH_FILE();
10
+ const raw = await readFile(authPath, "utf8");
11
+ const parsed = JSON.parse(raw);
12
+ return parsed;
13
+ }
14
+ catch (e) {
15
+ logger.debug("provider:codex:auth_read_failed", { authPath: AUTH_FILE(), error: e });
16
+ return null;
17
+ }
18
+ }
19
+ function pickOauthAuth(auth) {
20
+ const preferred = ["opencode", "codex", "openai"];
21
+ for (const providerID of preferred) {
22
+ const info = auth[providerID];
23
+ if (info?.type === "oauth") {
24
+ return {
25
+ providerID,
26
+ access: info.access,
27
+ enterpriseUrl: info.enterpriseUrl,
28
+ };
29
+ }
30
+ }
31
+ for (const [providerID, info] of Object.entries(auth)) {
32
+ if (info.type === "oauth") {
33
+ return {
34
+ providerID,
35
+ access: info.access,
36
+ enterpriseUrl: info.enterpriseUrl,
37
+ };
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ function buildUsageUrl(baseUrl) {
43
+ const trimmed = baseUrl.replace(/\/+$/, "");
44
+ if (trimmed.includes("/backend-api")) {
45
+ return `${trimmed}/wham/usage`;
46
+ }
47
+ return `${trimmed}/api/codex/usage`;
48
+ }
49
+ async function fetchQuotaPayload(accessToken, baseUrl) {
50
+ const url = buildUsageUrl(baseUrl);
51
+ const controller = new AbortController();
52
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
53
+ try {
54
+ const response = await fetch(url, {
55
+ headers: {
56
+ Authorization: `Bearer ${accessToken}`,
57
+ },
58
+ signal: controller.signal,
59
+ });
60
+ const bodyText = await response.text();
61
+ let payload = null;
62
+ try {
63
+ payload = JSON.parse(bodyText);
64
+ }
65
+ catch {
66
+ payload = bodyText;
67
+ }
68
+ if (!response.ok) {
69
+ const error = new Error(`quota request failed (${response.status})`);
70
+ error.cause = {
71
+ status: response.status,
72
+ bodyText: bodyText.slice(0, MAX_ERROR_BODY_CHARS),
73
+ };
74
+ throw error;
75
+ }
76
+ return payload;
77
+ }
78
+ finally {
79
+ clearTimeout(timeout);
80
+ }
81
+ }
82
+ function isObject(value) {
83
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
84
+ }
85
+ function toNumber(value) {
86
+ if (typeof value === "number" && Number.isFinite(value)) {
87
+ return value;
88
+ }
89
+ if (typeof value === "string") {
90
+ const parsed = Number.parseFloat(value);
91
+ if (Number.isFinite(parsed))
92
+ return parsed;
93
+ }
94
+ return null;
95
+ }
96
+ function describeWindow(windowSeconds) {
97
+ if (!windowSeconds || windowSeconds <= 0)
98
+ return null;
99
+ const minutes = Math.round(windowSeconds / 60);
100
+ if (minutes >= 60 && minutes % 60 === 0) {
101
+ const hours = minutes / 60;
102
+ return `${hours}h window`;
103
+ }
104
+ return `${minutes}m window`;
105
+ }
106
+ function formatRelativeSeconds(seconds) {
107
+ if (seconds <= 0)
108
+ return "now";
109
+ const minutes = Math.floor(seconds / 60);
110
+ const hours = Math.floor(minutes / 60);
111
+ const remainingMinutes = minutes % 60;
112
+ if (hours > 0) {
113
+ return `${hours}h ${remainingMinutes}m`;
114
+ }
115
+ return `${minutes}m`;
116
+ }
117
+ function parseRateLimitWindow(id, label, snapshot) {
118
+ const usedPercent = toNumber(snapshot.used_percent);
119
+ if (usedPercent === null)
120
+ return null;
121
+ // Window info
122
+ let window;
123
+ const windowSeconds = toNumber(snapshot.limit_window_seconds);
124
+ const windowLabel = describeWindow(windowSeconds);
125
+ if (windowLabel)
126
+ window = windowLabel;
127
+ // Reset info
128
+ let reset;
129
+ const resetAfter = toNumber(snapshot.reset_after_seconds);
130
+ const resetAt = toNumber(snapshot.reset_at);
131
+ if (resetAfter !== null) {
132
+ reset = `resets in ${formatRelativeSeconds(resetAfter)}`;
133
+ }
134
+ else if (resetAt !== null) {
135
+ reset = `resets at ${new Date(resetAt * 1000).toLocaleTimeString()}`;
136
+ }
137
+ return {
138
+ id: `codex-${id}`,
139
+ providerName: `Codex ${label}`,
140
+ used: Math.max(0, Math.min(100, usedPercent)),
141
+ limit: 100,
142
+ unit: "%",
143
+ window,
144
+ reset,
145
+ };
146
+ }
147
+ function parseCredits(credits) {
148
+ const base = {
149
+ id: "codex-credits",
150
+ providerName: "Codex Credits",
151
+ unit: "credits",
152
+ };
153
+ if (credits.unlimited) {
154
+ return {
155
+ ...base,
156
+ used: 0,
157
+ limit: null,
158
+ info: "unlimited",
159
+ };
160
+ }
161
+ const balance = toNumber(credits.balance ?? null);
162
+ if (balance === null)
163
+ return null;
164
+ return {
165
+ ...base,
166
+ used: balance,
167
+ limit: null,
168
+ info: "balance",
169
+ };
170
+ }
171
+ export function extractCodexQuota(payload) {
172
+ if (!isObject(payload))
173
+ return [];
174
+ const rateLimitCandidate = payload["rate_limit"];
175
+ const rateLimit = isObject(rateLimitCandidate) ? rateLimitCandidate : null;
176
+ const entries = [];
177
+ if (rateLimit) {
178
+ const primary = isObject(rateLimit.primary_window)
179
+ ? rateLimit.primary_window
180
+ : null;
181
+ const secondary = isObject(rateLimit.secondary_window)
182
+ ? rateLimit.secondary_window
183
+ : null;
184
+ if (primary) {
185
+ const entry = parseRateLimitWindow("primary", "Primary", primary);
186
+ if (entry)
187
+ entries.push(entry);
188
+ }
189
+ if (secondary) {
190
+ const entry = parseRateLimitWindow("secondary", "Secondary", secondary);
191
+ if (entry)
192
+ entries.push(entry);
193
+ }
194
+ }
195
+ const creditsCandidate = payload["credits"];
196
+ const credits = isObject(creditsCandidate) ? creditsCandidate : null;
197
+ if (credits) {
198
+ const creditEntry = parseCredits(credits);
199
+ if (creditEntry)
200
+ entries.push(creditEntry);
201
+ }
202
+ return entries;
203
+ }
204
+ export function createCodexProvider() {
205
+ return {
206
+ id: "codex",
207
+ async fetchQuota() {
208
+ logger.debug("provider:codex:fetch_start", { authPath: AUTH_FILE() });
209
+ const auth = await readAuthFile();
210
+ if (!auth) {
211
+ logger.debug("provider:codex:no_auth", { authPath: AUTH_FILE() });
212
+ throw new Error("Codex auth.json not found");
213
+ }
214
+ const oauth = pickOauthAuth(auth);
215
+ if (!oauth) {
216
+ logger.debug("provider:codex:no_oauth", { availableProviders: Object.keys(auth) });
217
+ throw new Error("Codex OAuth credentials missing");
218
+ }
219
+ const baseUrl = process.env.OPENCODE_CODEX_BASE_URL ??
220
+ oauth.enterpriseUrl ??
221
+ DEFAULT_BASE_URL;
222
+ logger.debug("provider:codex:request", { providerID: oauth.providerID, baseUrl, url: buildUsageUrl(baseUrl) });
223
+ const payload = await fetchQuotaPayload(oauth.access, baseUrl);
224
+ const entries = extractCodexQuota(payload);
225
+ logger.debug("provider:codex:parse", { count: entries.length });
226
+ if (entries.length === 0) {
227
+ throw new Error("Codex quota payload did not include rate limits");
228
+ }
229
+ return entries;
230
+ },
231
+ };
232
+ }
233
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/providers/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGnC,MAAM,gBAAgB,GAAG,iCAAiC,CAAC;AAC3D,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAsDnC,KAAK,UAAU,YAAY;IACvB,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAC;QAC3C,OAAO,MAAM,CAAC;IAClB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,IAAc;IACnC,MAAM,SAAS,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAClD,KAAK,MAAM,UAAU,IAAI,SAAS,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9B,IAAI,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,OAAO;gBACL,UAAU;gBACV,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,aAAa,EAAE,IAAI,CAAC,aAAa;aAClC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,OAAO;gBACL,UAAU;gBACV,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,aAAa,EAAE,IAAI,CAAC,aAAa;aAClC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACrC,OAAO,GAAG,OAAO,aAAa,CAAC;IACjC,CAAC;IACD,OAAO,GAAG,OAAO,kBAAkB,CAAC;AACtC,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,WAAmB,EACnB,OAAe;IAEf,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,kBAAkB,CAAC,CAAC;IACzE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,WAAW,EAAE;aACvC;YACD,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,QAAQ,CAAC;QACrB,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,yBAAyB,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YACrE,KAAK,CAAC,KAAK,GAAG;gBACZ,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC;aAClD,CAAC;YACF,MAAM,KAAK,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;IAC7C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,aAA4B;IAClD,IAAI,CAAC,aAAa,IAAI,aAAa,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,EAAE,CAAC,CAAC;IAC/C,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,GAAG,EAAE,CAAC;QAC3B,OAAO,GAAG,KAAK,UAAU,CAAC;IAC5B,CAAC;IACD,OAAO,GAAG,OAAO,UAAU,CAAC;AAC9B,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe;IAC5C,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACvC,MAAM,gBAAgB,GAAG,OAAO,GAAG,EAAE,CAAC;IACtC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,GAAG,KAAK,KAAK,gBAAgB,GAAG,CAAC;IAC1C,CAAC;IACD,OAAO,GAAG,OAAO,GAAG,CAAC;AACvB,CAAC;AAED,SAAS,oBAAoB,CAC3B,EAAU,EACV,KAAa,EACb,QAAiC;IAEjC,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,WAAW,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEtC,cAAc;IACd,IAAI,MAA0B,CAAC;IAC/B,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IAClD,IAAI,WAAW;QAAE,MAAM,GAAG,WAAW,CAAC;IAEtC,aAAa;IACb,IAAI,KAAyB,CAAC;IAC9B,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,KAAK,GAAG,aAAa,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC;IAC3D,CAAC;SAAM,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC5B,KAAK,GAAG,aAAa,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,kBAAkB,EAAE,EAAE,CAAC;IACvE,CAAC;IAED,OAAO;QACL,EAAE,EAAE,SAAS,EAAE,EAAE;QACjB,YAAY,EAAE,SAAS,KAAK,EAAE;QAC9B,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC7C,KAAK,EAAE,GAAG;QACV,IAAI,EAAE,GAAG;QACT,MAAM;QACN,KAAK;KACN,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,OAA4B;IAChD,MAAM,IAAI,GAAG;QACX,EAAE,EAAE,eAAe;QACnB,YAAY,EAAE,eAAe;QAC7B,IAAI,EAAE,SAAS;KAChB,CAAC;IAEF,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO;YACL,GAAG,IAAI;YACP,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,WAAW;SAClB,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAElC,OAAO;QACL,GAAG,IAAI;QACP,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,SAAS;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,MAAM,kBAAkB,GAAI,OAAmC,CAAC,YAAY,CAAC,CAAC;IAC9E,MAAM,SAAS,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC;IAE3E,MAAM,OAAO,GAAgB,EAAE,CAAC;IAEhC,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,cAAc,CAAC;YAChD,CAAC,CAAE,SAAS,CAAC,cAA0C;YACvD,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC,gBAAgB,CAAC;YACpD,CAAC,CAAE,SAAS,CAAC,gBAA4C;YACzD,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,oBAAoB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YAClE,IAAI,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;YACxE,IAAI,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,MAAM,gBAAgB,GAAI,OAAmC,CAAC,SAAS,CAAC,CAAC;IACzE,MAAM,OAAO,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;IAErE,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,WAAW,GAAG,YAAY,CAAC,OAA8B,CAAC,CAAC;QACjE,IAAI,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,EAAE,EAAE,OAAO;QACX,KAAK,CAAC,UAAU;YACd,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;YAEtE,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAC;YAClC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;gBAClE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YACjD,CAAC;YAEH,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,EAAE,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACnF,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACrD,CAAC;YAED,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,uBAAuB;gBACnC,KAAK,CAAC,aAAa;gBACnB,gBAAgB,CAAC;YAEjB,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAEjH,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC/D,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAE3C,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAEhE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;YACrE,CAAC;YAED,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type IQuotaProvider, type QuotaData } from "../interfaces";
2
+ export declare function parseGithubUsage(data: unknown, sku: string | null, apiWarning?: string | null): QuotaData[];
3
+ export declare function createGithubProvider(): IQuotaProvider;
4
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAsDpE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,CAoD3G;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAiDrD"}
@@ -0,0 +1,139 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { AUTH_FILE, getConfigDirectory } from "../utils/paths";
3
+ import { join } from "node:path";
4
+ const AUTH_PATH_LOCAL = AUTH_FILE();
5
+ const AUTH_PATH_CONFIG = join(getConfigDirectory(), "auth.json");
6
+ async function readAuthFile() {
7
+ for (const path of [AUTH_PATH_LOCAL, AUTH_PATH_CONFIG]) {
8
+ try {
9
+ const raw = await readFile(path, "utf8");
10
+ return JSON.parse(raw);
11
+ }
12
+ catch {
13
+ continue;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ function parseTokenSku(token) {
19
+ const parts = token.split(";");
20
+ for (const part of parts) {
21
+ if (part.startsWith("sku=")) {
22
+ return part.split("=")[1];
23
+ }
24
+ }
25
+ return null;
26
+ }
27
+ function getNextMonthStart() {
28
+ const now = new Date();
29
+ const nextMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, 0, 0, 0));
30
+ return nextMonth;
31
+ }
32
+ function formatTimeUntil(target) {
33
+ const diff = target.getTime() - Date.now();
34
+ if (diff <= 0)
35
+ return "soon";
36
+ const days = Math.floor(diff / (1000 * 60 * 60 * 24));
37
+ const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
38
+ if (days > 0)
39
+ return `${days}d ${hours}h`;
40
+ return `${hours}h`;
41
+ }
42
+ export function parseGithubUsage(data, sku, apiWarning) {
43
+ // free_engaged_oss_quota is actually a "pro" equivalent for OSS maintainers
44
+ const isFreeLimited = sku?.includes("free") && !sku?.includes("oss");
45
+ const now = new Date();
46
+ const resetTime = getNextMonthStart();
47
+ const resetStr = `resets in ${formatTimeUntil(resetTime)}`;
48
+ let usedSuggestions = 0;
49
+ let limit = isFreeLimited ? 2000 : null;
50
+ let unit = "suggestions";
51
+ if (Array.isArray(data) && data.length > 0) {
52
+ const currentMonthUsage = data.filter((day) => {
53
+ if (!day || typeof day !== "object")
54
+ return false;
55
+ const dayRecord = day;
56
+ const dayValue = dayRecord["day"];
57
+ if (typeof dayValue !== "string")
58
+ return false;
59
+ const dayDate = new Date(dayValue);
60
+ return dayDate.getUTCMonth() === now.getUTCMonth() && dayDate.getUTCFullYear() === now.getUTCFullYear();
61
+ });
62
+ usedSuggestions = currentMonthUsage.reduce((acc, day) => {
63
+ if (!day || typeof day !== "object")
64
+ return acc;
65
+ const dayRecord = day;
66
+ const suggestions = typeof dayRecord["total_suggestions_count"] === "number" ? dayRecord["total_suggestions_count"] : 0;
67
+ const chat = typeof dayRecord["total_chat_count"] === "number" ? dayRecord["total_chat_count"] : 0;
68
+ return acc + suggestions + chat;
69
+ }, 0);
70
+ }
71
+ const infoParts = [];
72
+ if (isFreeLimited)
73
+ infoParts.push("Free Plan");
74
+ else if (sku)
75
+ infoParts.push("Pro Plan");
76
+ if (apiWarning) {
77
+ infoParts.push("Service Currently Unavailable (API Deprecated)");
78
+ }
79
+ return [
80
+ {
81
+ id: "github-copilot",
82
+ providerName: "GitHub Copilot",
83
+ used: usedSuggestions,
84
+ limit: limit,
85
+ unit: unit,
86
+ reset: resetStr,
87
+ window: "Monthly",
88
+ info: infoParts.join(" | "),
89
+ }
90
+ ];
91
+ }
92
+ export function createGithubProvider() {
93
+ return {
94
+ id: "github-copilot",
95
+ async fetchQuota() {
96
+ const auth = await readAuthFile();
97
+ if (!auth) {
98
+ throw new Error("Opencode auth.json not found");
99
+ }
100
+ const info = auth["github-copilot"] || auth["github"];
101
+ if (!info || !info.access) {
102
+ throw new Error("GitHub Copilot credentials missing");
103
+ }
104
+ const sku = parseTokenSku(info.access);
105
+ // Note: GitHub does not currently support a user-level Copilot usage
106
+ // endpoint for individual accounts. The legacy/beta endpoints were
107
+ // deprecated (and may return 404). We still attempt the call, but we
108
+ // surface failures as provider metadata so users can diagnose.
109
+ let data = null;
110
+ let apiWarning = null;
111
+ try {
112
+ const response = await fetch("https://api.github.com/user/copilot/usage", {
113
+ headers: {
114
+ Authorization: `Bearer ${info.access}`,
115
+ "X-GitHub-Api-Version": "2022-11-28",
116
+ Accept: "application/vnd.github+json",
117
+ },
118
+ });
119
+ if (!response.ok) {
120
+ if (response.status === 404) {
121
+ apiWarning = "404";
122
+ }
123
+ else {
124
+ const body = await response.text();
125
+ apiWarning = `${response.status}: ${body.slice(0, 50)}`;
126
+ }
127
+ }
128
+ else {
129
+ data = (await response.json());
130
+ }
131
+ }
132
+ catch (error) {
133
+ apiWarning = "Request Failed";
134
+ }
135
+ return parseGithubUsage(data, sku, apiWarning);
136
+ },
137
+ };
138
+ }
139
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"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"}