@slkiser/opencode-quota 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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/dist/data/modelsdev-pricing.min.json +504 -0
  4. package/dist/index.d.ts +10 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +15 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/lib/cache.d.ts +49 -0
  9. package/dist/lib/cache.d.ts.map +1 -0
  10. package/dist/lib/cache.js +127 -0
  11. package/dist/lib/cache.js.map +1 -0
  12. package/dist/lib/config.d.ts +30 -0
  13. package/dist/lib/config.d.ts.map +1 -0
  14. package/dist/lib/config.js +154 -0
  15. package/dist/lib/config.js.map +1 -0
  16. package/dist/lib/copilot.d.ts +25 -0
  17. package/dist/lib/copilot.d.ts.map +1 -0
  18. package/dist/lib/copilot.js +306 -0
  19. package/dist/lib/copilot.js.map +1 -0
  20. package/dist/lib/entries.d.ts +60 -0
  21. package/dist/lib/entries.d.ts.map +1 -0
  22. package/dist/lib/entries.js +8 -0
  23. package/dist/lib/entries.js.map +1 -0
  24. package/dist/lib/firmware.d.ts +15 -0
  25. package/dist/lib/firmware.d.ts.map +1 -0
  26. package/dist/lib/firmware.js +79 -0
  27. package/dist/lib/firmware.js.map +1 -0
  28. package/dist/lib/format.d.ts +16 -0
  29. package/dist/lib/format.d.ts.map +1 -0
  30. package/dist/lib/format.js +99 -0
  31. package/dist/lib/format.js.map +1 -0
  32. package/dist/lib/google-token-cache.d.ts +30 -0
  33. package/dist/lib/google-token-cache.d.ts.map +1 -0
  34. package/dist/lib/google-token-cache.js +100 -0
  35. package/dist/lib/google-token-cache.js.map +1 -0
  36. package/dist/lib/google.d.ts +43 -0
  37. package/dist/lib/google.d.ts.map +1 -0
  38. package/dist/lib/google.js +399 -0
  39. package/dist/lib/google.js.map +1 -0
  40. package/dist/lib/markdown-table.d.ts +8 -0
  41. package/dist/lib/markdown-table.d.ts.map +1 -0
  42. package/dist/lib/markdown-table.js +56 -0
  43. package/dist/lib/markdown-table.js.map +1 -0
  44. package/dist/lib/modelsdev-pricing.d.ts +23 -0
  45. package/dist/lib/modelsdev-pricing.d.ts.map +1 -0
  46. package/dist/lib/modelsdev-pricing.js +32 -0
  47. package/dist/lib/modelsdev-pricing.js.map +1 -0
  48. package/dist/lib/openai.d.ts +33 -0
  49. package/dist/lib/openai.d.ts.map +1 -0
  50. package/dist/lib/openai.js +162 -0
  51. package/dist/lib/openai.js.map +1 -0
  52. package/dist/lib/opencode-auth.d.ts +11 -0
  53. package/dist/lib/opencode-auth.d.ts.map +1 -0
  54. package/dist/lib/opencode-auth.js +27 -0
  55. package/dist/lib/opencode-auth.js.map +1 -0
  56. package/dist/lib/opencode-storage.d.ts +45 -0
  57. package/dist/lib/opencode-storage.d.ts.map +1 -0
  58. package/dist/lib/opencode-storage.js +120 -0
  59. package/dist/lib/opencode-storage.js.map +1 -0
  60. package/dist/lib/quota-command-format.d.ts +14 -0
  61. package/dist/lib/quota-command-format.d.ts.map +1 -0
  62. package/dist/lib/quota-command-format.js +122 -0
  63. package/dist/lib/quota-command-format.js.map +1 -0
  64. package/dist/lib/quota-stats-format.d.ts +9 -0
  65. package/dist/lib/quota-stats-format.d.ts.map +1 -0
  66. package/dist/lib/quota-stats-format.js +244 -0
  67. package/dist/lib/quota-stats-format.js.map +1 -0
  68. package/dist/lib/quota-stats.d.ts +71 -0
  69. package/dist/lib/quota-stats.d.ts.map +1 -0
  70. package/dist/lib/quota-stats.js +270 -0
  71. package/dist/lib/quota-stats.js.map +1 -0
  72. package/dist/lib/quota-status.d.ts +23 -0
  73. package/dist/lib/quota-status.d.ts.map +1 -0
  74. package/dist/lib/quota-status.js +112 -0
  75. package/dist/lib/quota-status.js.map +1 -0
  76. package/dist/lib/toast-format-grouped.d.ts +25 -0
  77. package/dist/lib/toast-format-grouped.d.ts.map +1 -0
  78. package/dist/lib/toast-format-grouped.js +123 -0
  79. package/dist/lib/toast-format-grouped.js.map +1 -0
  80. package/dist/lib/types.d.ts +218 -0
  81. package/dist/lib/types.d.ts.map +1 -0
  82. package/dist/lib/types.js +39 -0
  83. package/dist/lib/types.js.map +1 -0
  84. package/dist/plugin.d.ts +13 -0
  85. package/dist/plugin.d.ts.map +1 -0
  86. package/dist/plugin.js +633 -0
  87. package/dist/plugin.js.map +1 -0
  88. package/dist/providers/copilot.d.ts +8 -0
  89. package/dist/providers/copilot.d.ts.map +1 -0
  90. package/dist/providers/copilot.js +50 -0
  91. package/dist/providers/copilot.js.map +1 -0
  92. package/dist/providers/firmware.d.ts +6 -0
  93. package/dist/providers/firmware.d.ts.map +1 -0
  94. package/dist/providers/firmware.js +52 -0
  95. package/dist/providers/firmware.js.map +1 -0
  96. package/dist/providers/google-antigravity.d.ts +6 -0
  97. package/dist/providers/google-antigravity.d.ts.map +1 -0
  98. package/dist/providers/google-antigravity.js +77 -0
  99. package/dist/providers/google-antigravity.js.map +1 -0
  100. package/dist/providers/openai.d.ts +6 -0
  101. package/dist/providers/openai.d.ts.map +1 -0
  102. package/dist/providers/openai.js +106 -0
  103. package/dist/providers/openai.js.map +1 -0
  104. package/dist/providers/registry.d.ts +8 -0
  105. package/dist/providers/registry.d.ts.map +1 -0
  106. package/dist/providers/registry.js +14 -0
  107. package/dist/providers/registry.js.map +1 -0
  108. package/package.json +71 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-token-cache.d.ts","sourceRoot":"","sources":["../../src/lib/google-token-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqBD,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAUT;AA4CD,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CAO9C;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,2BAA2B,CAAC;CACpC,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhB;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3D"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Persistent access-token cache for Google Antigravity accounts.
3
+ *
4
+ * Why:
5
+ * - Antigravity quota is multi-account; each account needs its own access token.
6
+ * - Refreshing on every toast is noisy and increases timeout risk.
7
+ * - We persist access tokens so restarts don't force immediate refresh.
8
+ */
9
+ import { readFile, writeFile, mkdir } from "fs/promises";
10
+ import { homedir } from "os";
11
+ import { dirname, join } from "path";
12
+ import { createHash } from "crypto";
13
+ const CACHE_VERSION = 1;
14
+ let memCache = null;
15
+ let loadPromise = null;
16
+ function getCacheBaseDir() {
17
+ const home = homedir();
18
+ if (process.platform === "win32") {
19
+ return process.env.LOCALAPPDATA || join(home, "AppData", "Local");
20
+ }
21
+ return process.env.XDG_CACHE_HOME || join(home, ".cache");
22
+ }
23
+ export function getGoogleTokenCachePath() {
24
+ return join(getCacheBaseDir(), "opencode-quota", "google-access-tokens.json");
25
+ }
26
+ export function makeAccountCacheKey(params) {
27
+ const emailPart = (params.email ?? "").trim().toLowerCase();
28
+ const hash = createHash("sha256")
29
+ .update(params.refreshToken)
30
+ .update("\n")
31
+ .update(params.projectId)
32
+ .digest("hex")
33
+ .slice(0, 16);
34
+ // Keep a human hint without making it sensitive.
35
+ return `${emailPart}::${params.projectId}::${hash}`;
36
+ }
37
+ async function loadFromDisk(path) {
38
+ try {
39
+ const raw = await readFile(path, "utf-8");
40
+ const parsed = JSON.parse(raw);
41
+ if (!parsed || typeof parsed !== "object")
42
+ throw new Error("invalid");
43
+ const file = parsed;
44
+ if (file.version !== CACHE_VERSION || typeof file.tokens !== "object" || !file.tokens) {
45
+ throw new Error("invalid");
46
+ }
47
+ return {
48
+ version: CACHE_VERSION,
49
+ updatedAt: typeof file.updatedAt === "number" ? file.updatedAt : Date.now(),
50
+ tokens: file.tokens,
51
+ };
52
+ }
53
+ catch {
54
+ return { version: CACHE_VERSION, updatedAt: Date.now(), tokens: {} };
55
+ }
56
+ }
57
+ async function ensureLoaded() {
58
+ if (memCache)
59
+ return memCache;
60
+ if (loadPromise)
61
+ return loadPromise;
62
+ const path = getGoogleTokenCachePath();
63
+ loadPromise = (async () => {
64
+ const file = await loadFromDisk(path);
65
+ memCache = file;
66
+ loadPromise = null;
67
+ return file;
68
+ })();
69
+ return loadPromise;
70
+ }
71
+ async function persist() {
72
+ if (!memCache)
73
+ return;
74
+ const path = getGoogleTokenCachePath();
75
+ const dir = dirname(path);
76
+ await mkdir(dir, { recursive: true });
77
+ await writeFile(path, JSON.stringify(memCache, null, 2), "utf-8");
78
+ }
79
+ export async function getCachedAccessToken(params) {
80
+ const cache = await ensureLoaded();
81
+ const entry = cache.tokens[params.key];
82
+ if (!entry)
83
+ return null;
84
+ if (typeof entry.expiresAt !== "number")
85
+ return null;
86
+ if (entry.expiresAt <= Date.now() + params.skewMs)
87
+ return null;
88
+ return entry;
89
+ }
90
+ export async function setCachedAccessToken(params) {
91
+ const cache = await ensureLoaded();
92
+ cache.tokens[params.key] = params.entry;
93
+ cache.updatedAt = Date.now();
94
+ await persist();
95
+ }
96
+ export async function clearGoogleTokenCache() {
97
+ memCache = { version: CACHE_VERSION, updatedAt: Date.now(), tokens: {} };
98
+ await persist();
99
+ }
100
+ //# sourceMappingURL=google-token-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-token-cache.js","sourceRoot":"","sources":["../../src/lib/google-token-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Google Antigravity quota fetcher
3
+ *
4
+ * Uses OpenCode's antigravity-accounts.json at ~/.config/opencode/antigravity-accounts.json.
5
+ * Requires the user to have opencode-antigravity-auth installed and logged in.
6
+ */
7
+ import type { AntigravityAccount, GoogleModelId, GoogleResult } from "./types.js";
8
+ export declare function getAntigravityAccountsCandidatePaths(): string[];
9
+ export declare function pickAntigravityAccountsPath(): string;
10
+ /**
11
+ * Read Antigravity accounts from storage
12
+ */
13
+ export declare function readAntigravityAccounts(): Promise<AntigravityAccount[] | null>;
14
+ export declare function hasAntigravityAccountsConfigured(): Promise<boolean>;
15
+ export declare function refreshGoogleTokensForAllAccounts(params?: {
16
+ skewMs?: number;
17
+ force?: boolean;
18
+ }): Promise<null | {
19
+ total: number;
20
+ successCount: number;
21
+ failures: Array<{
22
+ email?: string;
23
+ error: string;
24
+ }>;
25
+ }>;
26
+ /**
27
+ * Query Google Antigravity quota for ALL accounts
28
+ *
29
+ * Reads accounts from ~/.config/opencode/antigravity-accounts.json.
30
+ * Refreshes access tokens and fetches quota for all accounts in parallel.
31
+ *
32
+ * @param modelIds - Model IDs to fetch quota for
33
+ * @returns Quota result with all models and any errors, or null if not configured
34
+ */
35
+ export declare function queryGoogleQuota(modelIds: GoogleModelId[]): Promise<GoogleResult>;
36
+ /**
37
+ * Format Google quota for toast display
38
+ *
39
+ * @param result - Google quota result
40
+ * @returns Formatted string like "G3Pro 100% * G3Flash 100% * Claude 0%" or null
41
+ */
42
+ export declare function formatGoogleQuota(result: GoogleResult): string | null;
43
+ //# sourceMappingURL=google.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/lib/google.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,KAAK,EACV,kBAAkB,EAKlB,aAAa,EAEb,YAAY,EACb,MAAM,YAAY,CAAC;AA4BpB,wBAAgB,oCAAoC,IAAI,MAAM,EAAE,CAwB/D;AAED,wBAAgB,2BAA2B,IAAI,MAAM,CAMpD;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,CAmBpF;AAED,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,OAAO,CAAC,CAGzE;AAsHD,wBAAsB,iCAAiC,CAAC,MAAM,CAAC,EAAE;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CACP,IAAI,GACJ;IACE,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD,CACJ,CAmCA;AA+KD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAsCvF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAcrE"}
@@ -0,0 +1,399 @@
1
+ /**
2
+ * Google Antigravity quota fetcher
3
+ *
4
+ * Uses OpenCode's antigravity-accounts.json at ~/.config/opencode/antigravity-accounts.json.
5
+ * Requires the user to have opencode-antigravity-auth installed and logged in.
6
+ */
7
+ import { readFile } from "fs/promises";
8
+ import { homedir } from "os";
9
+ import { join } from "path";
10
+ import { existsSync } from "fs";
11
+ import { ANTIGRAVITY_CLIENT_ID as GOOGLE_CLIENT_ID, ANTIGRAVITY_CLIENT_SECRET as GOOGLE_CLIENT_SECRET, } from "opencode-antigravity-auth/dist/src/constants.js";
12
+ import { REQUEST_TIMEOUT_MS, GOOGLE_MODEL_KEYS } from "./types.js";
13
+ import { getCachedAccessToken, makeAccountCacheKey, setCachedAccessToken, } from "./google-token-cache.js";
14
+ // =============================================================================
15
+ // Constants
16
+ // =============================================================================
17
+ const GOOGLE_QUOTA_API_URL = "https://cloudcode-pa.googleapis.com/v1internal:fetchAvailableModels";
18
+ const USER_AGENT = "antigravity/1.11.9 darwin/arm64";
19
+ const GOOGLE_TOKEN_REFRESH_URL = "https://oauth2.googleapis.com/token";
20
+ // Network timeouts tuned for reliability.
21
+ const GOOGLE_TOKEN_TIMEOUT_MS = 8000;
22
+ const GOOGLE_QUOTA_TIMEOUT_MS = 6000;
23
+ // Multi-account fetching concurrency (reliability > speed).
24
+ const GOOGLE_ACCOUNTS_CONCURRENCY = 3;
25
+ // =============================================================================
26
+ // Helpers
27
+ // =============================================================================
28
+ export function getAntigravityAccountsCandidatePaths() {
29
+ const home = homedir();
30
+ const isWindows = process.platform === "win32";
31
+ // Match common storage resolution used by opencode-antigravity-auth variants.
32
+ // - Config: $XDG_CONFIG_HOME/opencode (or ~/.config/opencode)
33
+ // - Data: $XDG_DATA_HOME/opencode (or ~/.local/share/opencode)
34
+ // - Windows: %APPDATA%/opencode (configBase), dataBase==configBase
35
+ const configBaseDir = isWindows
36
+ ? process.env.APPDATA || join(home, "AppData", "Roaming")
37
+ : process.env.XDG_CONFIG_HOME || join(home, ".config");
38
+ const xdgDataBase = isWindows
39
+ ? configBaseDir
40
+ : process.env.XDG_DATA_HOME || join(home, ".local", "share");
41
+ const candidates = [
42
+ join(configBaseDir, "opencode", "antigravity-accounts.json"),
43
+ join(xdgDataBase, "opencode", "antigravity-accounts.json"),
44
+ ];
45
+ // Unique + stable order.
46
+ return Array.from(new Set(candidates));
47
+ }
48
+ export function pickAntigravityAccountsPath() {
49
+ for (const p of getAntigravityAccountsCandidatePaths()) {
50
+ if (existsSync(p))
51
+ return p;
52
+ }
53
+ // Default to the first candidate for error/debug messaging.
54
+ return getAntigravityAccountsCandidatePaths()[0];
55
+ }
56
+ /**
57
+ * Read Antigravity accounts from storage
58
+ */
59
+ export async function readAntigravityAccounts() {
60
+ for (const path of getAntigravityAccountsCandidatePaths()) {
61
+ try {
62
+ const content = await readFile(path, "utf-8");
63
+ const file = JSON.parse(content);
64
+ if (!file.accounts || file.accounts.length === 0) {
65
+ continue;
66
+ }
67
+ // Filter to accounts with refresh tokens
68
+ const validAccounts = file.accounts.filter((account) => account.refreshToken);
69
+ return validAccounts.length > 0 ? validAccounts : null;
70
+ }
71
+ catch {
72
+ // try next candidate
73
+ }
74
+ }
75
+ return null;
76
+ }
77
+ export async function hasAntigravityAccountsConfigured() {
78
+ const accounts = await readAntigravityAccounts();
79
+ return !!accounts && accounts.length > 0;
80
+ }
81
+ async function mapWithConcurrency(params) {
82
+ const n = Math.max(1, Math.trunc(params.concurrency));
83
+ const results = new Array(params.items.length);
84
+ let nextIndex = 0;
85
+ const workers = Array.from({ length: Math.min(n, params.items.length) }, async () => {
86
+ while (true) {
87
+ const idx = nextIndex++;
88
+ if (idx >= params.items.length)
89
+ return;
90
+ results[idx] = await params.fn(params.items[idx], idx);
91
+ }
92
+ });
93
+ await Promise.all(workers);
94
+ return results;
95
+ }
96
+ /**
97
+ * Refresh Google access token
98
+ */
99
+ async function refreshAccessToken(refreshToken, timeoutMs = GOOGLE_TOKEN_TIMEOUT_MS) {
100
+ try {
101
+ const params = new URLSearchParams({
102
+ client_id: GOOGLE_CLIENT_ID,
103
+ client_secret: GOOGLE_CLIENT_SECRET,
104
+ refresh_token: refreshToken,
105
+ grant_type: "refresh_token",
106
+ });
107
+ const response = await fetchWithTimeout(GOOGLE_TOKEN_REFRESH_URL, {
108
+ method: "POST",
109
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
110
+ body: params,
111
+ }, timeoutMs);
112
+ if (!response.ok) {
113
+ // Try to extract error code from response
114
+ try {
115
+ const errorData = (await response.json());
116
+ if (errorData.error === "invalid_grant") {
117
+ return { error: "Token revoked" };
118
+ }
119
+ return {
120
+ error: errorData.error_description || `HTTP ${response.status}`,
121
+ };
122
+ }
123
+ catch {
124
+ return { error: `HTTP ${response.status}` };
125
+ }
126
+ }
127
+ const data = (await response.json());
128
+ return {
129
+ accessToken: data.access_token,
130
+ expiresIn: data.expires_in,
131
+ };
132
+ }
133
+ catch (err) {
134
+ if (err instanceof Error && err.message.includes("timeout")) {
135
+ return { error: "Token refresh timeout" };
136
+ }
137
+ return { error: "Token refresh failed" };
138
+ }
139
+ }
140
+ async function refreshAccessTokenWithCache(params) {
141
+ const skewMs = params.skewMs ?? 2 * 60_000;
142
+ const key = makeAccountCacheKey({
143
+ refreshToken: params.refreshToken,
144
+ projectId: params.projectId,
145
+ email: params.email,
146
+ });
147
+ if (!params.force) {
148
+ const cached = await getCachedAccessToken({ key, skewMs });
149
+ if (cached)
150
+ return { accessToken: cached.accessToken };
151
+ }
152
+ const refreshed = await refreshAccessToken(params.refreshToken);
153
+ if ("error" in refreshed)
154
+ return refreshed;
155
+ await setCachedAccessToken({
156
+ key,
157
+ entry: {
158
+ accessToken: refreshed.accessToken,
159
+ expiresAt: Date.now() + Math.max(1, refreshed.expiresIn) * 1000,
160
+ projectId: params.projectId,
161
+ email: params.email,
162
+ },
163
+ });
164
+ return { accessToken: refreshed.accessToken };
165
+ }
166
+ export async function refreshGoogleTokensForAllAccounts(params) {
167
+ const accounts = await readAntigravityAccounts();
168
+ if (!accounts || accounts.length === 0)
169
+ return null;
170
+ const valid = accounts.filter((a) => !!a.refreshToken);
171
+ if (valid.length === 0)
172
+ return null;
173
+ const results = await mapWithConcurrency({
174
+ items: valid,
175
+ concurrency: GOOGLE_ACCOUNTS_CONCURRENCY,
176
+ fn: async (account) => {
177
+ const email = account.email;
178
+ const projectId = getProjectId(account);
179
+ if (!projectId)
180
+ return { ok: false, email, error: "No projectId" };
181
+ const token = await refreshAccessTokenWithCache({
182
+ refreshToken: account.refreshToken,
183
+ projectId,
184
+ email,
185
+ skewMs: params?.skewMs,
186
+ force: params?.force,
187
+ });
188
+ if ("error" in token)
189
+ return { ok: false, email, error: token.error };
190
+ return { ok: true, email };
191
+ },
192
+ });
193
+ const failures = results.filter((r) => !r.ok).map((r) => ({ email: r.email, error: r.error }));
194
+ const successCount = results.filter((r) => r.ok).length;
195
+ return {
196
+ total: valid.length,
197
+ successCount,
198
+ failures,
199
+ };
200
+ }
201
+ /**
202
+ * Fetch with timeout
203
+ */
204
+ async function fetchWithTimeout(url, options, timeoutMs = REQUEST_TIMEOUT_MS) {
205
+ const controller = new AbortController();
206
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
207
+ try {
208
+ const response = await fetch(url, {
209
+ ...options,
210
+ signal: controller.signal,
211
+ });
212
+ return response;
213
+ }
214
+ catch (err) {
215
+ if (err instanceof Error && err.name === "AbortError") {
216
+ throw new Error(`Request timeout after ${Math.round(timeoutMs / 1000)}s`);
217
+ }
218
+ throw err;
219
+ }
220
+ finally {
221
+ clearTimeout(timeoutId);
222
+ }
223
+ }
224
+ /**
225
+ * Fetch quota from Google API
226
+ */
227
+ async function fetchGoogleQuota(accessToken, projectId, timeoutMs = GOOGLE_QUOTA_TIMEOUT_MS) {
228
+ const response = await fetchWithTimeout(GOOGLE_QUOTA_API_URL, {
229
+ method: "POST",
230
+ headers: {
231
+ "Content-Type": "application/json",
232
+ Authorization: `Bearer ${accessToken}`,
233
+ "User-Agent": USER_AGENT,
234
+ },
235
+ body: JSON.stringify({ project: projectId }),
236
+ }, timeoutMs);
237
+ if (!response.ok) {
238
+ if (response.status === 401 || response.status === 403) {
239
+ throw new Error(`Google API auth error: ${response.status}`);
240
+ }
241
+ throw new Error(`Google API error: ${response.status}`);
242
+ }
243
+ return response.json();
244
+ }
245
+ /**
246
+ * Extract model quotas from API response
247
+ */
248
+ function extractModelQuotas(data, modelIds, accountEmail) {
249
+ const quotas = [];
250
+ for (const modelId of modelIds) {
251
+ const modelConfig = GOOGLE_MODEL_KEYS[modelId];
252
+ if (!modelConfig)
253
+ continue;
254
+ let modelInfo = data.models[modelConfig.key];
255
+ // Try alternate key if primary not found
256
+ if (!modelInfo && modelConfig.altKey) {
257
+ modelInfo = data.models[modelConfig.altKey];
258
+ }
259
+ if (modelInfo) {
260
+ const remainingFraction = modelInfo.quotaInfo?.remainingFraction ?? 0;
261
+ quotas.push({
262
+ modelId,
263
+ displayName: modelConfig.display,
264
+ percentRemaining: Math.round(remainingFraction * 100),
265
+ resetTimeIso: modelInfo.quotaInfo?.resetTime,
266
+ accountEmail,
267
+ });
268
+ }
269
+ }
270
+ return quotas;
271
+ }
272
+ /**
273
+ * Fetch quota for a single account
274
+ */
275
+ function getProjectId(account) {
276
+ return account.projectId || account.projectID || account.managedProjectId;
277
+ }
278
+ // NOTE: This plugin treats Google Antigravity as truly multi-account.
279
+ // Each account gets its own access token derived from its refresh token.
280
+ async function fetchAccountQuotaWithAntigravityRefresh(params) {
281
+ const email = params.account.email || "Unknown";
282
+ const projectId = getProjectId(params.account);
283
+ if (!projectId) {
284
+ return { success: false, error: "No projectId", accountEmail: email };
285
+ }
286
+ try {
287
+ const tokenResult = await refreshAccessTokenWithCache({
288
+ refreshToken: params.account.refreshToken,
289
+ projectId,
290
+ email,
291
+ });
292
+ if ("error" in tokenResult)
293
+ return { success: false, error: tokenResult.error, accountEmail: email };
294
+ let data;
295
+ try {
296
+ data = await fetchGoogleQuota(tokenResult.accessToken, projectId);
297
+ }
298
+ catch (err) {
299
+ // One auth retry: refresh token then retry quota call.
300
+ if (err instanceof Error && err.message.includes("auth error")) {
301
+ const retryToken = await refreshAccessToken(params.account.refreshToken);
302
+ if ("error" in retryToken) {
303
+ return { success: false, error: retryToken.error, accountEmail: email };
304
+ }
305
+ await setCachedAccessToken({
306
+ key: makeAccountCacheKey({ refreshToken: params.account.refreshToken, projectId, email }),
307
+ entry: {
308
+ accessToken: retryToken.accessToken,
309
+ expiresAt: Date.now() + Math.max(1, retryToken.expiresIn) * 1000,
310
+ projectId,
311
+ email,
312
+ },
313
+ });
314
+ data = await fetchGoogleQuota(retryToken.accessToken, projectId);
315
+ }
316
+ else {
317
+ throw err;
318
+ }
319
+ }
320
+ const models = extractModelQuotas(data, params.modelIds, email);
321
+ return { success: true, models, accountEmail: email };
322
+ }
323
+ catch (err) {
324
+ if (err instanceof Error && err.message.includes("timeout")) {
325
+ return { success: false, error: "API timeout", accountEmail: email };
326
+ }
327
+ return {
328
+ success: false,
329
+ error: err instanceof Error ? err.message : String(err),
330
+ accountEmail: email,
331
+ };
332
+ }
333
+ }
334
+ // =============================================================================
335
+ // Export
336
+ // =============================================================================
337
+ /**
338
+ * Query Google Antigravity quota for ALL accounts
339
+ *
340
+ * Reads accounts from ~/.config/opencode/antigravity-accounts.json.
341
+ * Refreshes access tokens and fetches quota for all accounts in parallel.
342
+ *
343
+ * @param modelIds - Model IDs to fetch quota for
344
+ * @returns Quota result with all models and any errors, or null if not configured
345
+ */
346
+ export async function queryGoogleQuota(modelIds) {
347
+ const accounts = await readAntigravityAccounts();
348
+ if (!accounts || accounts.length === 0) {
349
+ return null;
350
+ }
351
+ // Query accounts with bounded concurrency (reliability > speed).
352
+ const results = await mapWithConcurrency({
353
+ items: accounts,
354
+ concurrency: GOOGLE_ACCOUNTS_CONCURRENCY,
355
+ fn: async (account) => fetchAccountQuotaWithAntigravityRefresh({ account, modelIds }),
356
+ });
357
+ // Collect all successful models and errors
358
+ const allModels = [];
359
+ const errors = [];
360
+ for (const result of results) {
361
+ if (result.success && result.models && result.models.length > 0) {
362
+ allModels.push(...result.models);
363
+ }
364
+ else if (!result.success && result.error && result.accountEmail) {
365
+ errors.push({ email: result.accountEmail, error: result.error });
366
+ }
367
+ }
368
+ // Return combined result
369
+ if (allModels.length === 0 && errors.length === 0) {
370
+ return {
371
+ success: false,
372
+ error: "No quota data available",
373
+ };
374
+ }
375
+ return {
376
+ success: true,
377
+ models: allModels,
378
+ errors: errors.length > 0 ? errors : undefined,
379
+ };
380
+ }
381
+ /**
382
+ * Format Google quota for toast display
383
+ *
384
+ * @param result - Google quota result
385
+ * @returns Formatted string like "G3Pro 100% * G3Flash 100% * Claude 0%" or null
386
+ */
387
+ export function formatGoogleQuota(result) {
388
+ if (!result) {
389
+ return null;
390
+ }
391
+ if (!result.success) {
392
+ return null;
393
+ }
394
+ if (result.models.length === 0) {
395
+ return null;
396
+ }
397
+ return result.models.map((m) => `${m.displayName} ${m.percentRemaining}%`).join(" \u2022 ");
398
+ }
399
+ //# sourceMappingURL=google.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/lib/google.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEhC,OAAO,EACL,qBAAqB,IAAI,gBAAgB,EACzC,yBAAyB,IAAI,oBAAoB,GAClD,MAAM,iDAAiD,CAAC;AAYzD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF,MAAM,oBAAoB,GAAG,qEAAqE,CAAC;AACnG,MAAM,UAAU,GAAG,iCAAiC,CAAC;AAErD,MAAM,wBAAwB,GAAG,qCAAqC,CAAC;AAEvE,0CAA0C;AAC1C,MAAM,uBAAuB,GAAG,IAAI,CAAC;AACrC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAErC,4DAA4D;AAC5D,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAEtC,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,MAAM,UAAU,oCAAoC;IAClD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAE/C,8EAA8E;IAC9E,8DAA8D;IAC9D,+DAA+D;IAC/D,mEAAmE;IAEnE,MAAM,aAAa,GAAG,SAAS;QAC7B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC;QACzD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAEzD,MAAM,WAAW,GAAG,SAAS;QAC3B,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE/D,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,2BAA2B,CAAC;QAC5D,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,2BAA2B,CAAC;KAC3D,CAAC;IAEF,yBAAyB;IACzB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,KAAK,MAAM,CAAC,IAAI,oCAAoC,EAAE,EAAE,CAAC;QACvD,IAAI,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,4DAA4D;IAC5D,OAAO,oCAAoC,EAAE,CAAC,CAAC,CAAE,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAC3C,KAAK,MAAM,IAAI,IAAI,oCAAoC,EAAE,EAAE,CAAC;QAC1D,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;YAE5D,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjD,SAAS;YACX,CAAC;YAED,yCAAyC;YACzC,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YAC9E,OAAO,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gCAAgC;IACpD,MAAM,QAAQ,GAAG,MAAM,uBAAuB,EAAE,CAAC;IACjD,OAAO,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAO,MAIvC;IACC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,IAAI,KAAK,CAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAClF,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;YACxB,IAAI,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM;gBAAE,OAAO;YACvC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAE,EAAE,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAC/B,YAAoB,EACpB,YAAoB,uBAAuB;IAE3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,SAAS,EAAE,gBAAgB;YAC3B,aAAa,EAAE,oBAAoB;YACnC,aAAa,EAAE,YAAY;YAC3B,UAAU,EAAE,eAAe;SAC5B,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACrC,wBAAwB,EACxB;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,MAAM;SACb,EACD,SAAS,CACV,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,0CAA0C;YAC1C,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGvC,CAAC;gBACF,IAAI,SAAS,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;oBACxC,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;gBACpC,CAAC;gBACD,OAAO;oBACL,KAAK,EAAE,SAAS,CAAC,iBAAiB,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE;iBAChE,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,KAAK,EAAE,QAAQ,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC9C,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGlC,CAAC;QAEF,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,YAAY;YAC9B,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5D,OAAO,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;QAC5C,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,2BAA2B,CAAC,MAM1C;IACC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC;IAC3C,MAAM,GAAG,GAAG,mBAAmB,CAAC;QAC9B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3D,IAAI,MAAM;YAAE,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAChE,IAAI,OAAO,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAE3C,MAAM,oBAAoB,CAAC;QACzB,GAAG;QACH,KAAK,EAAE;YACL,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,IAAI;YAC/D,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB;KACF,CAAC,CAAC;IAEH,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CAAC,MAGvD;IAQC,MAAM,QAAQ,GAAG,MAAM,uBAAuB,EAAE,CAAC;IACjD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IACvD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC;QACvC,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE,2BAA2B;QACxC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACpB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YAC5B,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YACxC,IAAI,CAAC,SAAS;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAc,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;YAE5E,MAAM,KAAK,GAAG,MAAM,2BAA2B,CAAC;gBAC9C,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,SAAS;gBACT,KAAK;gBACL,MAAM,EAAE,MAAM,EAAE,MAAM;gBACtB,KAAK,EAAE,MAAM,EAAE,KAAK;aACrB,CAAC,CAAC;YACH,IAAI,OAAO,IAAI,KAAK;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAc,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC/E,OAAO,EAAE,EAAE,EAAE,IAAa,EAAE,KAAK,EAAE,CAAC;QACtC,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC/F,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;IAExD,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,YAAY;QACZ,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAC7B,GAAW,EACX,OAAoB,EACpB,YAAoB,kBAAkB;IAEtC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAElE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,GAAG,OAAO;YACV,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAC7B,WAAmB,EACnB,SAAiB,EACjB,YAAoB,uBAAuB;IAE3C,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACrC,oBAAoB,EACpB;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,WAAW,EAAE;YACtC,YAAY,EAAE,UAAU;SACzB;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;KAC7C,EACD,SAAS,CACV,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAkC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CACzB,IAAyB,EACzB,QAAyB,EACzB,YAAqB;IAErB,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,CAAC,WAAW;YAAE,SAAS;QAE3B,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAE7C,yCAAyC;QACzC,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;YACrC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,iBAAiB,GAAG,SAAS,CAAC,SAAS,EAAE,iBAAiB,IAAI,CAAC,CAAC;YACtE,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO;gBACP,WAAW,EAAE,WAAW,CAAC,OAAO;gBAChC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,GAAG,CAAC;gBACrD,YAAY,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS;gBAC5C,YAAY;aACb,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,OAA2B;IAC/C,OAAO,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;AAC5E,CAAC;AAED,sEAAsE;AACtE,yEAAyE;AAEzE,KAAK,UAAU,uCAAuC,CAAC,MAGtD;IAMC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC;IAChD,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAE/C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACxE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,2BAA2B,CAAC;YACpD,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY;YACzC,SAAS;YACT,KAAK;SACN,CAAC,CAAC;QAEH,IAAI,OAAO,IAAI,WAAW;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QAErG,IAAI,IAAyB,CAAC;QAC9B,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,uDAAuD;YACvD,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC/D,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;gBACzE,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;oBAC1B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;gBAC1E,CAAC;gBACD,MAAM,oBAAoB,CAAC;oBACzB,GAAG,EAAE,mBAAmB,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;oBACzF,KAAK,EAAE;wBACL,WAAW,EAAE,UAAU,CAAC,WAAW;wBACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI;wBAChE,SAAS;wBACT,KAAK;qBACN;iBACF,CAAC,CAAC;gBACH,IAAI,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YACnE,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAEhE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QACvE,CAAC;QACD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;YACvD,YAAY,EAAE,KAAK;SACpB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,SAAS;AACT,gFAAgF;AAEhF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAyB;IAC9D,MAAM,QAAQ,GAAG,MAAM,uBAAuB,EAAE,CAAC;IACjD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iEAAiE;IACjE,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC;QACvC,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,2BAA2B;QACxC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,uCAAuC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;KACtF,CAAC,CAAC;IAEH,2CAA2C;IAC3C,MAAM,SAAS,GAAuB,EAAE,CAAC;IACzC,MAAM,MAAM,GAAyB,EAAE,CAAC;IAExC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChE,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;aAAM,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,yBAAyB;SACjC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;KAC1B,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC9F,CAAC"}
@@ -0,0 +1,8 @@
1
+ type Align = "left" | "right" | "center";
2
+ export declare function renderMarkdownTable(params: {
3
+ headers: string[];
4
+ rows: string[][];
5
+ aligns?: Align[];
6
+ }): string;
7
+ export {};
8
+ //# sourceMappingURL=markdown-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-table.d.ts","sourceRoot":"","sources":["../../src/lib/markdown-table.ts"],"names":[],"mappings":"AAAA,KAAK,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAqBzC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB,GAAG,MAAM,CAsCT"}
@@ -0,0 +1,56 @@
1
+ function padCell(text, width, align) {
2
+ const s = text ?? "";
3
+ const len = s.length;
4
+ if (len >= width)
5
+ return s;
6
+ const pad = width - len;
7
+ if (align === "right")
8
+ return " ".repeat(pad) + s;
9
+ if (align === "center") {
10
+ const left = Math.floor(pad / 2);
11
+ const right = pad - left;
12
+ return " ".repeat(left) + s + " ".repeat(right);
13
+ }
14
+ return s + " ".repeat(pad);
15
+ }
16
+ function escapeCell(text) {
17
+ // Keep this conservative: tool output should be plain ascii.
18
+ return (text ?? "").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
19
+ }
20
+ export function renderMarkdownTable(params) {
21
+ const aligns = params.aligns ?? params.headers.map(() => "left");
22
+ const colCount = params.headers.length;
23
+ const safeRows = params.rows.map((r) => {
24
+ const out = [];
25
+ for (let i = 0; i < colCount; i++)
26
+ out.push(escapeCell(r[i] ?? ""));
27
+ return out;
28
+ });
29
+ const headerCells = params.headers.map((h) => escapeCell(h));
30
+ const widths = headerCells.map((h) => Math.max(3, h.length));
31
+ for (const row of safeRows) {
32
+ for (let i = 0; i < colCount; i++) {
33
+ widths[i] = Math.max(widths[i], (row[i] ?? "").length);
34
+ }
35
+ }
36
+ const fmtRow = (cells) => `| ${cells
37
+ .map((c, i) => padCell(c, widths[i], aligns[i] ?? "left"))
38
+ .join(" | ")} |`;
39
+ const sep = `| ${widths
40
+ .map((w, i) => {
41
+ const a = aligns[i] ?? "left";
42
+ if (a === "right")
43
+ return "-".repeat(Math.max(3, w - 1)) + ":";
44
+ if (a === "center")
45
+ return ":" + "-".repeat(Math.max(3, w - 2)) + ":";
46
+ return "-".repeat(Math.max(3, w));
47
+ })
48
+ .join(" | ")} |`;
49
+ const lines = [];
50
+ lines.push(fmtRow(headerCells));
51
+ lines.push(sep);
52
+ for (const row of safeRows)
53
+ lines.push(fmtRow(row));
54
+ return lines.join("\n");
55
+ }
56
+ //# sourceMappingURL=markdown-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-table.js","sourceRoot":"","sources":["../../src/lib/markdown-table.ts"],"names":[],"mappings":"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"}