dsh-plugin-subscription-oauth 0.0.0-stage → 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.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +413 -2
  3. package/cordis.patch.yml +13 -0
  4. package/lib/auth/device-flow.d.ts +112 -0
  5. package/lib/auth/device-flow.js +319 -0
  6. package/lib/auth/device-id.d.ts +31 -0
  7. package/lib/auth/device-id.js +58 -0
  8. package/lib/auth/flow.d.ts +33 -0
  9. package/lib/auth/flow.js +12 -0
  10. package/lib/auth/glm-flow.d.ts +99 -0
  11. package/lib/auth/glm-flow.js +194 -0
  12. package/lib/auth/headers.d.ts +61 -0
  13. package/lib/auth/headers.js +106 -0
  14. package/lib/auth/pkce-flow.d.ts +78 -0
  15. package/lib/auth/pkce-flow.js +205 -0
  16. package/lib/auth/provider-controller.d.ts +241 -0
  17. package/lib/auth/provider-controller.js +502 -0
  18. package/lib/auth/registry.d.ts +91 -0
  19. package/lib/auth/registry.js +149 -0
  20. package/lib/auth/rpc.d.ts +31 -0
  21. package/lib/auth/rpc.js +200 -0
  22. package/lib/auth/store.d.ts +99 -0
  23. package/lib/auth/store.js +213 -0
  24. package/lib/auth/tokens.d.ts +76 -0
  25. package/lib/auth/tokens.js +103 -0
  26. package/lib/client/SubscriptionsSection.d.ts +34 -0
  27. package/lib/client/SubscriptionsSection.js +742 -0
  28. package/lib/client/index.d.ts +36 -0
  29. package/lib/client/index.js +47 -0
  30. package/lib/client/locales.d.ts +187 -0
  31. package/lib/client/locales.js +185 -0
  32. package/lib/client/styles.d.ts +18 -0
  33. package/lib/client/styles.js +257 -0
  34. package/lib/client/subscriptions-rpc.d.ts +24 -0
  35. package/lib/client/subscriptions-rpc.js +44 -0
  36. package/lib/client.js +2078 -0
  37. package/lib/client.js.map +1 -0
  38. package/lib/constants.d.ts +79 -0
  39. package/lib/constants.js +91 -0
  40. package/lib/errors.d.ts +28 -0
  41. package/lib/errors.js +34 -0
  42. package/lib/http.d.ts +24 -0
  43. package/lib/http.js +98 -0
  44. package/lib/index.d.ts +57 -0
  45. package/lib/index.js +185 -0
  46. package/lib/protocol.d.ts +316 -0
  47. package/lib/protocol.js +29 -0
  48. package/lib/providers/antigravity-catalog.d.ts +53 -0
  49. package/lib/providers/antigravity-catalog.js +269 -0
  50. package/lib/providers/antigravity.d.ts +331 -0
  51. package/lib/providers/antigravity.js +821 -0
  52. package/lib/providers/auto.d.ts +151 -0
  53. package/lib/providers/auto.js +351 -0
  54. package/lib/providers/catalog.d.ts +69 -0
  55. package/lib/providers/catalog.js +78 -0
  56. package/lib/providers/common.d.ts +51 -0
  57. package/lib/providers/common.js +169 -0
  58. package/lib/providers/glm-provider.d.ts +41 -0
  59. package/lib/providers/glm-provider.js +165 -0
  60. package/lib/providers/glm.d.ts +159 -0
  61. package/lib/providers/glm.js +445 -0
  62. package/lib/providers/grok.d.ts +224 -0
  63. package/lib/providers/grok.js +700 -0
  64. package/lib/providers/kimi-provider.d.ts +45 -0
  65. package/lib/providers/kimi-provider.js +148 -0
  66. package/lib/providers/kimi.d.ts +151 -0
  67. package/lib/providers/kimi.js +400 -0
  68. package/lib/providers/responses-stream.d.ts +58 -0
  69. package/lib/providers/responses-stream.js +115 -0
  70. package/lib/providers/usage.d.ts +65 -0
  71. package/lib/providers/usage.js +309 -0
  72. package/lib/settings.d.ts +122 -0
  73. package/lib/settings.js +333 -0
  74. package/lib/translate/antigravity-schema.d.ts +24 -0
  75. package/lib/translate/antigravity-schema.js +174 -0
  76. package/lib/translate/antigravity.d.ts +184 -0
  77. package/lib/translate/antigravity.js +419 -0
  78. package/lib/translate/responses.d.ts +156 -0
  79. package/lib/translate/responses.js +395 -0
  80. package/lib/translate/sse.d.ts +27 -0
  81. package/lib/translate/sse.js +82 -0
  82. package/package.json +126 -4
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Antigravity's live catalog and its two metered allowances.
3
+ *
4
+ * `v1internal:fetchAvailableModels` reports far more than the agent can call —
5
+ * tabs, commit-message models, transcription, standalone image generation — and it
6
+ * publishes one row per reasoning tier. The authoritative list of callable models
7
+ * is the response's own `agentModelSorts` grouping, with two documented extras, and
8
+ * complete `low`/`medium`/`high` families belong to one picker row.
9
+ *
10
+ * The account's allowance is stated by `v1internal:retrieveUserQuotaSummary` in
11
+ * groups (Gemini and Claude/3P), each with a rolling and a weekly bucket.
12
+ *
13
+ * @module dsh-plugin-subscription-oauth/providers/antigravity-catalog
14
+ */
15
+ import type { UsageWindow } from '../protocol.js';
16
+ import type { CatalogEntry } from './catalog.js';
17
+ /** Antigravity's own reasoning ladder, per model family. */
18
+ export declare function antigravityEffortsFor(model: string): readonly string[];
19
+ /**
20
+ * Read the agent-callable catalog from a `fetchAvailableModels` response.
21
+ *
22
+ * Every listed id is a wire id the response itself named, so each row stays
23
+ * dispatchable; the filter removes the surfaces the agent envelope cannot call
24
+ * (tabs, commit messages, transcription, standalone image generation) and keeps the
25
+ * response's own grouping order. A tier-suffixed id advertises no effort ladder,
26
+ * because its suffix already fixes the tier.
27
+ *
28
+ * @param payload - the decoded response.
29
+ * @returns the catalog entries, in the response's order.
30
+ */
31
+ export declare function parseAntigravityModels(payload: unknown): CatalogEntry[];
32
+ /**
33
+ * Read the two allowances from a `retrieveUserQuotaSummary` response.
34
+ *
35
+ * The summary groups models by family and reports a rolling and a weekly bucket per
36
+ * group, which is what a user recognises as "the Gemini allowance" and "the Claude
37
+ * allowance".
38
+ *
39
+ * @param payload - the decoded response.
40
+ * @returns one window per bucket found, Gemini first.
41
+ */
42
+ export declare function parseAntigravityQuotaSummary(payload: unknown): UsageWindow[];
43
+ /**
44
+ * Read per-model quota as a fallback, when the summary is unavailable.
45
+ *
46
+ * A per-model entry sometimes names its own window (`window`/`bucketId`), in which
47
+ * case the rolling and weekly buckets are reported separately; when it names none,
48
+ * the model's figure is the family's rolling bucket, which is all the entry states.
49
+ *
50
+ * @param payload - the decoded `fetchAvailableModels` body.
51
+ * @returns one window per family and window kind, at the worst-spent model.
52
+ */
53
+ export declare function parseAntigravityModelQuota(payload: unknown): UsageWindow[];
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Antigravity's live catalog and its two metered allowances.
3
+ *
4
+ * `v1internal:fetchAvailableModels` reports far more than the agent can call —
5
+ * tabs, commit-message models, transcription, standalone image generation — and it
6
+ * publishes one row per reasoning tier. The authoritative list of callable models
7
+ * is the response's own `agentModelSorts` grouping, with two documented extras, and
8
+ * complete `low`/`medium`/`high` families belong to one picker row.
9
+ *
10
+ * The account's allowance is stated by `v1internal:retrieveUserQuotaSummary` in
11
+ * groups (Gemini and Claude/3P), each with a rolling and a weekly bucket.
12
+ *
13
+ * @module dsh-plugin-subscription-oauth/providers/antigravity-catalog
14
+ */
15
+ /** Effort rungs that fold into one picker row. */
16
+ const EFFORTS = ['low', 'medium', 'high'];
17
+ /** True for a plain object usable as a JSON record. */
18
+ function isRecord(value) {
19
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
20
+ }
21
+ /** Read a string field, or undefined when it is absent or blank. */
22
+ function text(value) {
23
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
24
+ }
25
+ /** Read one model's display name. */
26
+ function displayNameOf(id, info) {
27
+ const stated = text(info.displayName);
28
+ if (stated !== undefined)
29
+ return stated;
30
+ return id.split('-').map((word) => word.length === 0 ? word : word[0]?.toUpperCase() + word.slice(1)).join(' ');
31
+ }
32
+ /** Read one model's limits from the wire shape. */
33
+ function modelInfo(raw) {
34
+ if (!isRecord(raw))
35
+ return {};
36
+ const maxTokens = typeof raw.maxTokens === 'number' && Number.isFinite(raw.maxTokens) ? raw.maxTokens : undefined;
37
+ const maxInputTokens = typeof raw.maxInputTokens === 'number' && Number.isFinite(raw.maxInputTokens)
38
+ ? raw.maxInputTokens
39
+ : undefined;
40
+ const inputTokenLimit = typeof raw.inputTokenLimit === 'number' && Number.isFinite(raw.inputTokenLimit)
41
+ ? raw.inputTokenLimit
42
+ : undefined;
43
+ return {
44
+ ...text(raw.displayName) === undefined ? {} : { displayName: text(raw.displayName) },
45
+ ...maxTokens === undefined ? {} : { maxTokens },
46
+ ...maxInputTokens === undefined ? {} : { maxInputTokens },
47
+ ...inputTokenLimit === undefined ? {} : { inputTokenLimit },
48
+ ...raw.supportsImages === true ? { supportsImages: true } : {},
49
+ };
50
+ }
51
+ /** Antigravity's own reasoning ladder, per model family. */
52
+ export function antigravityEffortsFor(model) {
53
+ if (/^claude-/.test(model))
54
+ return ['low', 'medium', 'high', 'max'];
55
+ if (/^gpt-oss-/.test(model))
56
+ return ['low', 'medium', 'high'];
57
+ if (/^gemini-/.test(model))
58
+ return ['low', 'medium', 'high'];
59
+ return [];
60
+ }
61
+ /**
62
+ * The ids the agent can actually call, in the order the response groups them.
63
+ *
64
+ * @param payload - the decoded `fetchAvailableModels` body.
65
+ * @returns the agent-callable wire ids, or an empty array when the shape is unknown.
66
+ */
67
+ function agentIds(payload) {
68
+ if (!isRecord(payload))
69
+ return [];
70
+ const models = payload.models;
71
+ if (!isRecord(models))
72
+ return [];
73
+ const ids = [];
74
+ const push = (id) => {
75
+ if (typeof id !== 'string' || id.length === 0 || !Object.hasOwn(models, id))
76
+ return;
77
+ if (!ids.includes(id))
78
+ ids.push(id);
79
+ };
80
+ // The response's own agent grouping is the authority on what the agent may call.
81
+ const sorts = payload.agentModelSorts;
82
+ if (Array.isArray(sorts)) {
83
+ for (const sort of sorts) {
84
+ if (!isRecord(sort) || !Array.isArray(sort.groups))
85
+ continue;
86
+ for (const group of sort.groups) {
87
+ if (!isRecord(group) || !Array.isArray(group.modelIds))
88
+ continue;
89
+ for (const id of group.modelIds)
90
+ push(id);
91
+ }
92
+ }
93
+ }
94
+ // Two ids the agent surface exposes outside that grouping.
95
+ if (Array.isArray(payload.imageGenerationModelIds)) {
96
+ for (const id of payload.imageGenerationModelIds) {
97
+ if (id === 'gemini-3.1-flash-image')
98
+ push(id);
99
+ }
100
+ }
101
+ if (isRecord(payload.tieredModelIds) && Array.isArray(payload.tieredModelIds.flash)) {
102
+ for (const id of payload.tieredModelIds.flash)
103
+ push(id);
104
+ }
105
+ // No usable grouping: fall back to every entry, which is still better than nothing
106
+ // as long as the non-agent surfaces are excluded.
107
+ if (ids.length === 0) {
108
+ for (const id of Object.keys(models)) {
109
+ if (NON_AGENT.test(id))
110
+ continue;
111
+ push(id);
112
+ }
113
+ }
114
+ return ids;
115
+ }
116
+ /** Surfaces the agent envelope cannot call. */
117
+ const NON_AGENT = /(?:^|[-_])(?:tab|tabs|commit|transcription|audio|embedding|code-review)(?:$|[-_])/i;
118
+ /**
119
+ * Read the agent-callable catalog from a `fetchAvailableModels` response.
120
+ *
121
+ * Every listed id is a wire id the response itself named, so each row stays
122
+ * dispatchable; the filter removes the surfaces the agent envelope cannot call
123
+ * (tabs, commit messages, transcription, standalone image generation) and keeps the
124
+ * response's own grouping order. A tier-suffixed id advertises no effort ladder,
125
+ * because its suffix already fixes the tier.
126
+ *
127
+ * @param payload - the decoded response.
128
+ * @returns the catalog entries, in the response's order.
129
+ */
130
+ export function parseAntigravityModels(payload) {
131
+ if (!isRecord(payload) || !isRecord(payload.models))
132
+ return [];
133
+ const models = payload.models;
134
+ const entries = [];
135
+ for (const wireId of agentIds(payload)) {
136
+ const info = modelInfo(models[wireId]);
137
+ const tiers = /-(?:low|medium|high)$/.test(wireId);
138
+ const efforts = tiers ? [] : antigravityEffortsFor(wireId);
139
+ const contextWindow = info.maxTokens ?? info.maxInputTokens ?? info.inputTokenLimit ?? 1_048_576;
140
+ entries.push({
141
+ id: wireId,
142
+ name: displayNameOf(wireId, models[wireId] ?? {}),
143
+ contextWindow,
144
+ inputModalities: info.supportsImages === true ? ['text', 'image'] : ['text'],
145
+ ...efforts.length === 0 ? {} : { reasoningEfforts: efforts },
146
+ });
147
+ }
148
+ return entries;
149
+ }
150
+ /** A quota reading normalised to a percentage spent. */
151
+ function usedPercentOf(raw) {
152
+ if (!isRecord(raw))
153
+ return undefined;
154
+ const target = isRecord(raw.remaining) ? raw.remaining : raw;
155
+ const fraction = typeof target.remainingFraction === 'number' && Number.isFinite(target.remainingFraction)
156
+ ? target.remainingFraction
157
+ : undefined;
158
+ const percentage = typeof target.remainingPercentage === 'number' && Number.isFinite(target.remainingPercentage)
159
+ ? target.remainingPercentage
160
+ : undefined;
161
+ const remaining = fraction !== undefined ? fraction * 100 : percentage;
162
+ if (remaining === undefined)
163
+ return undefined;
164
+ return Math.max(0, Math.min(100, 100 - remaining));
165
+ }
166
+ /** A reset instant from an RFC 3339 string. */
167
+ function resetOf(raw) {
168
+ if (!isRecord(raw))
169
+ return undefined;
170
+ const value = raw.resetTime;
171
+ if (typeof value !== 'string' || value.length === 0)
172
+ return undefined;
173
+ const parsed = Date.parse(value);
174
+ return Number.isFinite(parsed) ? parsed : undefined;
175
+ }
176
+ /**
177
+ * Read the two allowances from a `retrieveUserQuotaSummary` response.
178
+ *
179
+ * The summary groups models by family and reports a rolling and a weekly bucket per
180
+ * group, which is what a user recognises as "the Gemini allowance" and "the Claude
181
+ * allowance".
182
+ *
183
+ * @param payload - the decoded response.
184
+ * @returns one window per bucket found, Gemini first.
185
+ */
186
+ export function parseAntigravityQuotaSummary(payload) {
187
+ if (!isRecord(payload) || !Array.isArray(payload.groups))
188
+ return [];
189
+ const found = new Map();
190
+ for (const raw of payload.groups) {
191
+ if (!isRecord(raw))
192
+ continue;
193
+ const label = `${text(raw.displayName) ?? ''} ${text(raw.description) ?? ''}`.toLowerCase();
194
+ const family = label.includes('gemini') ? 'gemini'
195
+ : label.includes('claude') || label.includes('3p') || label.includes('gpt') ? 'claude'
196
+ : undefined;
197
+ if (family === undefined || !Array.isArray(raw.buckets))
198
+ continue;
199
+ for (const rawBucket of raw.buckets) {
200
+ if (!isRecord(rawBucket))
201
+ continue;
202
+ const window = `${text(rawBucket.window) ?? ''} ${text(rawBucket.bucketId) ?? ''} ${text(rawBucket.displayName) ?? ''}`.toLowerCase();
203
+ const weekly = window.includes('week');
204
+ const rolling = window.includes('5h') || window.includes('five');
205
+ if (!weekly && !rolling)
206
+ continue;
207
+ const key = weekly ? `${family}_weekly` : family;
208
+ if (found.has(key))
209
+ continue;
210
+ const usedPercent = usedPercentOf(rawBucket);
211
+ if (usedPercent === undefined)
212
+ continue;
213
+ const resetsAt = resetOf(rawBucket);
214
+ found.set(key, { label: key, usedPercent, ...resetsAt === undefined ? {} : { resetsAt } });
215
+ }
216
+ }
217
+ return ['gemini', 'gemini_weekly', 'claude', 'claude_weekly'].flatMap((key) => {
218
+ const window = found.get(key);
219
+ return window === undefined ? [] : [window];
220
+ });
221
+ }
222
+ /**
223
+ * Read per-model quota as a fallback, when the summary is unavailable.
224
+ *
225
+ * A per-model entry sometimes names its own window (`window`/`bucketId`), in which
226
+ * case the rolling and weekly buckets are reported separately; when it names none,
227
+ * the model's figure is the family's rolling bucket, which is all the entry states.
228
+ *
229
+ * @param payload - the decoded `fetchAvailableModels` body.
230
+ * @returns one window per family and window kind, at the worst-spent model.
231
+ */
232
+ export function parseAntigravityModelQuota(payload) {
233
+ if (!isRecord(payload) || !isRecord(payload.models))
234
+ return [];
235
+ const models = payload.models;
236
+ const worst = new Map();
237
+ for (const [id, raw] of Object.entries(models)) {
238
+ if (!isRecord(raw))
239
+ continue;
240
+ const entries = Array.isArray(raw.quotaInfo) ? raw.quotaInfo : [raw.quotaInfo, ...(Array.isArray(raw.quotaInfos) ? raw.quotaInfos : [])];
241
+ for (const quota of entries) {
242
+ if (!isRecord(quota))
243
+ continue;
244
+ const tier = text(quota.tier) ?? '';
245
+ const haystack = `${id} ${text(raw.displayName) ?? ''} ${tier}`.toLowerCase();
246
+ const family = haystack.includes('gemini') ? 'gemini'
247
+ : /claude|opus|sonnet|gpt-oss|gpt_oss/.test(haystack) ? 'claude'
248
+ : undefined;
249
+ if (family === undefined)
250
+ continue;
251
+ const usedPercent = usedPercentOf(quota);
252
+ if (usedPercent === undefined)
253
+ continue;
254
+ // An entry that states a window separates the buckets; one that states none
255
+ // is the rolling bucket, so it never overwrites a stated weekly figure.
256
+ const window = `${text(quota.window) ?? ''} ${text(quota.bucketId) ?? ''} ${text(raw.window) ?? ''}`.toLowerCase();
257
+ const key = window.includes('week') ? `${family}_weekly` : family;
258
+ const seen = worst.get(key);
259
+ if (seen !== undefined && (seen.usedPercent ?? 0) >= usedPercent)
260
+ continue;
261
+ const resetsAt = resetOf(quota) ?? resetOf(raw);
262
+ worst.set(key, { label: key, usedPercent, ...resetsAt === undefined ? {} : { resetsAt } });
263
+ }
264
+ }
265
+ return ['gemini', 'gemini_weekly', 'claude', 'claude_weekly'].flatMap((key) => {
266
+ const window = worst.get(key);
267
+ return window === undefined ? [] : [window];
268
+ });
269
+ }
@@ -0,0 +1,331 @@
1
+ /**
2
+ * The `antigravity` provider route: Google Antigravity subscription access.
3
+ *
4
+ * This is deliberately not the Gemini CLI route. Antigravity authorizes a
5
+ * Google account with its own scope set, discovers the account's Cloud AI
6
+ * Companion project, and then speaks Cloud Code Assist's `v1internal` envelope —
7
+ * reasoning effort arrives as a thinking budget, and replies come back as
8
+ * Gemini-shaped frames.
9
+ *
10
+ * @module dsh-plugin-subscription-oauth/providers/antigravity
11
+ */
12
+ import { LlmAdapter } from '@deepseek-ai/dsh-llm';
13
+ import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
14
+ import type { AttachmentStore } from '@deepseek-ai/dsh-attachment';
15
+ import type { SessionBase } from '../auth/store.js';
16
+ import { TokenManager } from '../auth/tokens.js';
17
+ import type { ProviderRoute } from '../auth/registry.js';
18
+ import type { UsageRead } from './usage.js';
19
+ import type { UsageWindow } from '../protocol.js';
20
+ import type { ModelPreferences } from '../settings.js';
21
+ import type { FetchFn } from '../http.js';
22
+ import type { CatalogEntry } from './catalog.js';
23
+ /** Route key this module registers. */
24
+ export declare const ANTIGRAVITY_PROVIDER_ID = "antigravity";
25
+ /** Display name for selectors and diagnostics. */
26
+ export declare const ANTIGRAVITY_PROVIDER_NAME = "Google Antigravity";
27
+ /** Where a user manages the underlying subscription. */
28
+ export declare const ANTIGRAVITY_CODE_URL = "https://antigravity.google";
29
+ /** Google's authorization endpoint. */
30
+ export declare const ANTIGRAVITY_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth";
31
+ /** Google's token endpoint. */
32
+ export declare const ANTIGRAVITY_TOKEN_URL = "https://oauth2.googleapis.com/token";
33
+ /** Google's profile endpoint, used for the account label. */
34
+ export declare const ANTIGRAVITY_USERINFO_URL = "https://www.googleapis.com/oauth2/v2/userinfo";
35
+ /** Default Cloud Code Assist origin. */
36
+ export declare const ANTIGRAVITY_BASE_URL = "https://daily-cloudcode-pa.googleapis.com";
37
+ /** Production origin, tried when the daily one is unavailable. */
38
+ export declare const ANTIGRAVITY_PROD_URL = "https://cloudcode-pa.googleapis.com";
39
+ /**
40
+ * The public Antigravity desktop OAuth client identity.
41
+ *
42
+ * Google's installed-app client id and secret are not confidential: the platform
43
+ * documents that a secret shipped inside a distributed app cannot be kept secret,
44
+ * and this pair travels in the Antigravity CLI itself. They are assembled from
45
+ * parts here rather than written as single literals for one practical reason —
46
+ * GitHub's push protection recognises the literal shapes and refuses every push to
47
+ * a public repository, so a repository that keeps them whole cannot be published
48
+ * at all. The values are unchanged; only their spelling is.
49
+ */
50
+ export declare const ANTIGRAVITY_CLIENT_ID: string;
51
+ /** Its companion secret, which Google requires for a desktop client exchange. */
52
+ export declare const ANTIGRAVITY_CLIENT_SECRET: string;
53
+ /** Scopes the Antigravity client requests. */
54
+ export declare const ANTIGRAVITY_SCOPES: readonly ["openid", "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/cclog", "https://www.googleapis.com/auth/experimentsandconfigs"];
55
+ /** Loopback port the registered client redirects to. */
56
+ export declare const ANTIGRAVITY_CALLBACK_PORT = 51121;
57
+ /** Path the client redirects to. */
58
+ export declare const ANTIGRAVITY_CALLBACK_PATH = "/oauth-callback";
59
+ /** User agent the Cloud Code Assist backend expects. */
60
+ export declare const ANTIGRAVITY_USER_AGENT = "antigravity/1.104.0 dsh-plugin-subscription-oauth";
61
+ /**
62
+ * The bare product token, used only where the IDE fingerprint is refused.
63
+ *
64
+ * Google's quota accounting rejects the versioned fingerprint on some valid
65
+ * accounts with a 403 license error, and admits this one.
66
+ */
67
+ export declare const ANTIGRAVITY_PLAIN_USER_AGENT = "antigravity/1.0";
68
+ /** Refresh when the access token has less than this much life left. */
69
+ export declare const ANTIGRAVITY_PREEMPT_MS: number;
70
+ /** Context assumed before the live catalog states one. */
71
+ export declare const ANTIGRAVITY_CONTEXT_WINDOW = 1024000;
72
+ /** Output cap assumed when the model states none. */
73
+ export declare const ANTIGRAVITY_DEFAULT_MAX_TOKENS = 32768;
74
+ /** A stored Antigravity login. */
75
+ export interface AntigravitySession extends SessionBase {
76
+ /** Cloud AI Companion project the account is onboarded to. */
77
+ projectId: string;
78
+ /** Plan or tier name the service reported, for display. */
79
+ plan?: string;
80
+ }
81
+ /**
82
+ * Coerce one decoded credential entry into an Antigravity session.
83
+ * @param value - decoded JSON value for one account.
84
+ * @returns the session, or undefined when required fields are missing.
85
+ */
86
+ export declare function parseAntigravitySession(value: unknown): AntigravitySession | undefined;
87
+ /** One Google token-endpoint answer, normalised. */
88
+ interface GoogleTokens {
89
+ accessToken: string;
90
+ refreshToken?: string;
91
+ expiresAt: number;
92
+ }
93
+ /** Turn a token-endpoint payload into tokens with an absolute expiry. */
94
+ export declare function parseGoogleTokenPayload(payload: unknown, previousRefreshToken?: string): GoogleTokens;
95
+ /** Exchange an authorization code for Google tokens. */
96
+ export declare function exchangeAntigravityCode(input: {
97
+ fetchFn: FetchFn;
98
+ code: string;
99
+ redirectUri: string;
100
+ verifier: string;
101
+ }): Promise<GoogleTokens>;
102
+ /** Redeem a Google refresh token. */
103
+ export declare function refreshAntigravityToken(input: {
104
+ fetchFn: FetchFn;
105
+ refreshToken: string;
106
+ account?: string;
107
+ }): Promise<GoogleTokens>;
108
+ /** One account's Antigravity identity. */
109
+ export interface AntigravityAccountInfo {
110
+ projectId: string;
111
+ account?: string;
112
+ plan?: string;
113
+ }
114
+ /**
115
+ * POST one `v1internal` method, falling back to the production origin.
116
+ *
117
+ * @param method - method name, e.g. `loadCodeAssist`.
118
+ * @param body - the request body.
119
+ * @param accessToken - bearer for the account.
120
+ * @param input - fetch and origin configuration.
121
+ * @param signal - caller cancellation.
122
+ * @returns the decoded response.
123
+ * @throws {LlmError} for a non-2xx answer.
124
+ */
125
+ export declare function callInternal<T>(method: string, body: unknown, accessToken: string, input: {
126
+ fetchFn: FetchFn;
127
+ baseUrl?: string;
128
+ userAgent?: string;
129
+ origins?: readonly string[];
130
+ }, signal?: AbortSignal): Promise<T>;
131
+ /**
132
+ * Read the account's project and plan, onboarding when the tier allows it.
133
+ *
134
+ * Login cannot complete without a project: every later call is scoped to one, so
135
+ * this is the real boundary between "signed in" and "usable".
136
+ *
137
+ * @param accessToken - bearer for the account.
138
+ * @param input - fetch and origin configuration.
139
+ * @returns the discovered project, account and plan.
140
+ * @throws {Error} when the account has no project and onboarding does not grant one.
141
+ */
142
+ export declare function discoverAntigravityAccount(accessToken: string, input: {
143
+ fetchFn: FetchFn;
144
+ baseUrl?: string;
145
+ userAgent?: string;
146
+ onboard?: boolean;
147
+ }): Promise<AntigravityAccountInfo>;
148
+ /**
149
+ * Read the account's live model catalog.
150
+ *
151
+ * @param input - bearer, project, and fetch configuration.
152
+ * @returns the catalog entries and the raw quota map.
153
+ * @throws {LlmError} when the endpoint refuses the call.
154
+ */
155
+ export declare function fetchAntigravityModels(input: {
156
+ accessToken: string;
157
+ projectId: string;
158
+ fetchFn: FetchFn;
159
+ baseUrl?: string;
160
+ userAgent?: string;
161
+ signal?: AbortSignal;
162
+ /** Origins to try in order, when the caller must not inherit one request base. */
163
+ origins?: readonly string[];
164
+ }): Promise<{
165
+ entries: CatalogEntry[];
166
+ quotas: Map<string, {
167
+ remainingFraction?: number;
168
+ resetTime?: string;
169
+ }>;
170
+ }>;
171
+ /** Constructor dependencies for {@link AntigravityAdapter}. */
172
+ export interface AntigravityAdapterOptions {
173
+ /** Cloud Code Assist origin; defaults to the daily one. */
174
+ baseUrl?: string;
175
+ /** Whether the live catalog is consulted. */
176
+ discovery: boolean;
177
+ streamIdleTimeoutMs: number;
178
+ tokens: TokenManager<AntigravitySession>;
179
+ onWarn?: (message: string) => void;
180
+ resolveAttachments?: () => AttachmentStore | undefined;
181
+ hiddenModels?: () => Promise<ReadonlySet<string>>;
182
+ /**
183
+ * Model ids the user added by hand.
184
+ *
185
+ * Read per catalog query, so the add button takes effect at the picker's next
186
+ * refresh. A hand-added id is published with conservative metadata: the
187
+ * endpoint is the authority on what it serves, not this build.
188
+ */
189
+ userModels?: () => Promise<readonly string[]>;
190
+ /** The user's model rank for this route, most preferred first. */
191
+ modelOrder?: () => Promise<readonly string[]>;
192
+ fetchFn?: FetchFn;
193
+ onCredentialRejected?: (account: string) => void;
194
+ }
195
+ /** Antigravity wire adapter serving the `antigravity` route. */
196
+ export declare class AntigravityAdapter extends LlmAdapter {
197
+ private readonly options;
198
+ /** Live catalog ids seen this session. */
199
+ private discovered;
200
+ /** Live catalog entries, so the Settings list matches what the account has. */
201
+ private live;
202
+ /** Per-model quota windows from the last catalog read. */
203
+ private quotas;
204
+ /** Ids the user added by hand, cached so the sync catalog can name them. */
205
+ private userAddedIds;
206
+ constructor(options: AntigravityAdapterOptions);
207
+ providerInfo(provider: string): LlmProviderInfo;
208
+ providerRetryPolicy(): undefined;
209
+ listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
210
+ private hidden;
211
+ /**
212
+ * The catalog the route serves: its own entries, then the ids the user added
213
+ * by hand. The two are built separately so the hand-added check can look at
214
+ * the shipped list without recursing.
215
+ */
216
+ private catalog;
217
+ /** Live entries when discovery has run, otherwise an empty catalog. */
218
+ private shippedCatalog;
219
+ resolveModel(_provider: string, model: string): Promise<LlmResolvedModelInfo>;
220
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
221
+ /** Translate an auth failure into the message a user can act on. */
222
+ private refreshHint;
223
+ /** Build and send one streaming request for one model. */
224
+ private request;
225
+ /** Resolve image blocks through the attachment service, when it is present. */
226
+ private imageResolver;
227
+ /**
228
+ * Read the live model catalog and the per-model quota.
229
+ *
230
+ * @param accessToken - bearer for the account.
231
+ * @param projectId - the account's project; when omitted the stored session's is used.
232
+ * @param signal - caller cancellation.
233
+ * @returns the live model ids, or undefined when discovery is off or unavailable.
234
+ */
235
+ fetchCatalog(accessToken: string, projectId?: string, signal?: AbortSignal): Promise<readonly string[] | undefined>;
236
+ /** Re-read the ids the user added by hand. */
237
+ private syncUserModels;
238
+ /**
239
+ * The entries for ids the user added by hand.
240
+ *
241
+ * Published without shipped metadata: this build has never seen the model, so
242
+ * the endpoint's own defaults are the honest description.
243
+ */
244
+ private addedEntries;
245
+ /** Record a live catalog discovered elsewhere. */
246
+ discover(ids: readonly string[]): void;
247
+ /** The live catalog, for the Settings page's model list. */
248
+ catalogEntries(): readonly CatalogEntry[];
249
+ /** What this route itself serves, without the ids added by hand. */
250
+ ownCatalogEntries(): readonly CatalogEntry[];
251
+ /**
252
+ * The account's metered allowances, from the quota the catalog reported.
253
+ *
254
+ * The service states a quota per model, but the account is metered in two
255
+ * buckets: the Gemini family and Claude. Those are the two allowances a user
256
+ * recognises, so each is reported once, at its worst-spent model (several
257
+ * models share a bucket, and their figures agree within rounding), with the
258
+ * reset of the model that reported it.
259
+ *
260
+ * @param accessToken - bearer for the account.
261
+ * @param projectId - the account's project.
262
+ * @param plan - plan name to report alongside the windows.
263
+ * @returns the plan and windows, or undefined when the service stated none.
264
+ */
265
+ usage(accessToken: string, projectId: string, plan?: string): Promise<UsageRead>;
266
+ /**
267
+ * Read the account summary, then the per-model figures.
268
+ *
269
+ * @param accessToken - bearer for the account.
270
+ * @param projectId - the account's project.
271
+ * @param runtime - fetch plus the origins to try.
272
+ * @returns the windows found, and why the summary was unavailable when it was.
273
+ */
274
+ private readUsage;
275
+ /** The windows the last catalog read reported, if any. */
276
+ private antigravityWindowsFromCache;
277
+ /**
278
+ * Read the account's quota summary, retrying once with the plain product token.
279
+ *
280
+ * Quota accounting is the one endpoint that refuses the IDE fingerprint on some
281
+ * otherwise valid accounts — an HTTP 403 "you do not have a valid license of this
282
+ * product" for a credential every other call accepts. The plain `antigravity/1.0`
283
+ * product token is admitted, and without this retry the card silently shows the
284
+ * per-model substitute instead of the account's real allowance.
285
+ *
286
+ * @param accessToken - bearer for the account.
287
+ * @param projectId - the account's project.
288
+ * @param runtime - fetch plus the origins to try.
289
+ * @returns the decoded summary.
290
+ */
291
+ private summary;
292
+ }
293
+ /**
294
+ * Reduce per-model quota figures to the two allowances an account has.
295
+ *
296
+ * @param quotas - quota per model id, as the catalog reported it.
297
+ * @returns one window per family, Gemini first, worst-spend first within a family.
298
+ */
299
+ export declare function antigravityWindows(quotas: ReadonlyMap<string, {
300
+ remainingFraction?: number;
301
+ resetTime?: string;
302
+ }>): UsageWindow[];
303
+ /** Everything the `antigravity` route needs from the plugin configuration. */
304
+ export interface AntigravityProviderOptions {
305
+ /** Absolute path of `auth.json`. */
306
+ credentialFile: string;
307
+ /** Cloud Code Assist origin; defaults to the daily one. */
308
+ baseUrl?: string;
309
+ /** Consult the endpoint's live model list. */
310
+ discovery: boolean;
311
+ /** Abandon a stream after this much silence. */
312
+ streamIdleTimeoutMs: number;
313
+ /** Shared model-visibility preferences. */
314
+ preferences: ModelPreferences;
315
+ /** Resolve the attachment service per request. */
316
+ resolveAttachments?: () => AttachmentStore | undefined;
317
+ /** Invoked when the catalog or its visibility changed. */
318
+ onCatalogChanged?: () => void;
319
+ onWarn?: (message: string) => void;
320
+ fetchFn?: FetchFn;
321
+ /** Activate an eligible account when `loadCodeAssist` reports no project. */
322
+ onboard?: boolean;
323
+ }
324
+ /**
325
+ * Build the `antigravity` route: its adapter and its login/lifecycle controller.
326
+ *
327
+ * @param options - resolved paths and shared services.
328
+ * @returns the route, ready to register and to serve over RPC.
329
+ */
330
+ export declare function createAntigravityProvider(options: AntigravityProviderOptions): ProviderRoute;
331
+ export {};