copilot-api-plus 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -1,14 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import { PATHS, ensurePaths } from "./paths-Ch0ixSo2.js";
3
- import { state } from "./state-DAw5jMjc.js";
4
- import { GITHUB_API_BASE_URL, copilotBaseUrl, copilotHeaders, githubHeaders } from "./get-user-DgPgvnrS.js";
3
+ import { state } from "./state-CcLGr8VN.js";
4
+ import { GITHUB_API_BASE_URL, copilotBaseUrl, copilotHeaders, githubHeaders } from "./get-user-BFf5xJXg.js";
5
5
  import { HTTPError, forwardError } from "./error-CvU5otz-.js";
6
- import { cacheModels, cacheVSCodeVersion, clearGithubToken, isNullish, setupCopilotToken, setupGitHubToken, sleep } from "./token-DYeOMeid.js";
7
- import { clearZenAuth, getZenAuthPath } from "./auth-C5zV8JbW.js";
6
+ import { cacheModels, cacheVSCodeVersion, clearGithubToken, isNullish, setupCopilotToken, setupGitHubToken, sleep } from "./token-B8crDDoA.js";
7
+ import { clearAntigravityAuth, disableCurrentAccount, getAntigravityAuthPath, getValidAccessToken, rotateAccount } from "./auth-Cm_0h9bp.js";
8
+ import { clearZenAuth, getZenAuthPath } from "./auth-Cua-c0dq.js";
9
+ import { getAntigravityModels, isThinkingModel } from "./get-models-Bbb8B5jI.js";
8
10
  import { defineCommand, runMain } from "citty";
9
11
  import consola from "consola";
10
12
  import fs from "node:fs/promises";
11
13
  import os from "node:os";
14
+ import path from "node:path";
15
+ import * as p from "@clack/prompts";
12
16
  import clipboard from "clipboardy";
13
17
  import { serve } from "srvx";
14
18
  import invariant from "tiny-invariant";
@@ -185,9 +189,11 @@ async function runLogout(options) {
185
189
  if (options.all) {
186
190
  await clearGithubToken();
187
191
  await clearZenAuth();
192
+ await clearAntigravityAuth();
188
193
  consola.success("Logged out from all services");
189
194
  consola.info(`GitHub token: ${PATHS.GITHUB_TOKEN_PATH}`);
190
195
  consola.info(`Zen API key: ${getZenAuthPath()}`);
196
+ consola.info(`Antigravity accounts: ${getAntigravityAuthPath()}`);
191
197
  return;
192
198
  }
193
199
  if (options.zen) {
@@ -196,26 +202,42 @@ async function runLogout(options) {
196
202
  consola.info(`Zen API key location: ${getZenAuthPath()}`);
197
203
  return;
198
204
  }
199
- const choice = await consola.prompt("Which credentials do you want to clear?", {
205
+ if (options.antigravity) {
206
+ await clearAntigravityAuth();
207
+ consola.success("Logged out from Google Antigravity");
208
+ consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
209
+ return;
210
+ }
211
+ switch (await consola.prompt("Which credentials do you want to clear?", {
200
212
  type: "select",
201
213
  options: [
202
214
  "GitHub Copilot token",
203
215
  "OpenCode Zen API key",
204
- "Both (all credentials)"
216
+ "Google Antigravity accounts",
217
+ "All credentials"
205
218
  ]
206
- });
207
- if (choice === "GitHub Copilot token") {
208
- await clearGithubToken();
209
- consola.success("Logged out from GitHub Copilot");
210
- consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
211
- } else if (choice === "OpenCode Zen API key") {
212
- await clearZenAuth();
213
- consola.success("Logged out from OpenCode Zen");
214
- consola.info(`Zen API key location: ${getZenAuthPath()}`);
215
- } else if (choice === "Both (all credentials)") {
216
- await clearGithubToken();
217
- await clearZenAuth();
218
- consola.success("Logged out from all services");
219
+ })) {
220
+ case "GitHub Copilot token":
221
+ await clearGithubToken();
222
+ consola.success("Logged out from GitHub Copilot");
223
+ consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
224
+ break;
225
+ case "OpenCode Zen API key":
226
+ await clearZenAuth();
227
+ consola.success("Logged out from OpenCode Zen");
228
+ consola.info(`Zen API key location: ${getZenAuthPath()}`);
229
+ break;
230
+ case "Google Antigravity accounts":
231
+ await clearAntigravityAuth();
232
+ consola.success("Logged out from Google Antigravity");
233
+ consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
234
+ break;
235
+ case "All credentials":
236
+ await clearGithubToken();
237
+ await clearZenAuth();
238
+ await clearAntigravityAuth();
239
+ consola.success("Logged out from all services");
240
+ break;
219
241
  }
220
242
  }
221
243
  const logout = defineCommand({
@@ -230,21 +252,259 @@ const logout = defineCommand({
230
252
  default: false,
231
253
  description: "Clear only OpenCode Zen API key"
232
254
  },
255
+ antigravity: {
256
+ type: "boolean",
257
+ default: false,
258
+ description: "Clear only Google Antigravity accounts"
259
+ },
233
260
  all: {
234
261
  alias: "a",
235
262
  type: "boolean",
236
263
  default: false,
237
- description: "Clear all credentials (GitHub and Zen)"
264
+ description: "Clear all credentials (GitHub, Zen, and Antigravity)"
238
265
  }
239
266
  },
240
267
  run({ args }) {
241
268
  return runLogout({
242
269
  zen: args.zen,
270
+ antigravity: args.antigravity,
243
271
  all: args.all
244
272
  });
245
273
  }
246
274
  });
247
275
 
276
+ //#endregion
277
+ //#region src/lib/config.ts
278
+ const CONFIG_FILENAME = "config.json";
279
+ /**
280
+ * Get the path to the config file
281
+ */
282
+ function getConfigPath() {
283
+ return path.join(PATHS.DATA_DIR, CONFIG_FILENAME);
284
+ }
285
+ /**
286
+ * Load configuration from file
287
+ */
288
+ async function loadConfig() {
289
+ try {
290
+ const configPath = getConfigPath();
291
+ const content = await fs.readFile(configPath, "utf-8");
292
+ return JSON.parse(content);
293
+ } catch {
294
+ return {};
295
+ }
296
+ }
297
+ /**
298
+ * Save configuration to file
299
+ */
300
+ async function saveConfig(config) {
301
+ const configPath = getConfigPath();
302
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
303
+ consola.debug(`Configuration saved to ${configPath}`);
304
+ }
305
+ /**
306
+ * Get proxy configuration
307
+ */
308
+ async function getProxyConfig() {
309
+ return (await loadConfig()).proxy;
310
+ }
311
+ /**
312
+ * Save proxy configuration
313
+ */
314
+ async function saveProxyConfig(proxyConfig) {
315
+ const config = await loadConfig();
316
+ config.proxy = proxyConfig;
317
+ await saveConfig(config);
318
+ }
319
+ /**
320
+ * Clear proxy configuration
321
+ */
322
+ async function clearProxyConfig() {
323
+ const config = await loadConfig();
324
+ delete config.proxy;
325
+ await saveConfig(config);
326
+ }
327
+ /**
328
+ * Apply saved proxy configuration to environment variables
329
+ * This should be called at startup to restore proxy settings
330
+ */
331
+ async function applyProxyConfig() {
332
+ const proxyConfig = await getProxyConfig();
333
+ if (!proxyConfig || !proxyConfig.enabled) return false;
334
+ if (proxyConfig.httpProxy) {
335
+ process.env.HTTP_PROXY = proxyConfig.httpProxy;
336
+ process.env.http_proxy = proxyConfig.httpProxy;
337
+ }
338
+ if (proxyConfig.httpsProxy) {
339
+ process.env.HTTPS_PROXY = proxyConfig.httpsProxy;
340
+ process.env.https_proxy = proxyConfig.httpsProxy;
341
+ }
342
+ if (proxyConfig.noProxy) {
343
+ process.env.NO_PROXY = proxyConfig.noProxy;
344
+ process.env.no_proxy = proxyConfig.noProxy;
345
+ }
346
+ consola.info("Proxy configuration loaded from saved settings");
347
+ if (proxyConfig.httpProxy) consola.info(` HTTP_PROXY: ${proxyConfig.httpProxy}`);
348
+ if (proxyConfig.httpsProxy) consola.info(` HTTPS_PROXY: ${proxyConfig.httpsProxy}`);
349
+ if (proxyConfig.noProxy) consola.info(` NO_PROXY: ${proxyConfig.noProxy}`);
350
+ return true;
351
+ }
352
+
353
+ //#endregion
354
+ //#region src/proxy-config.ts
355
+ const proxy = defineCommand({
356
+ meta: {
357
+ name: "proxy",
358
+ description: "Configure proxy settings (persistent)"
359
+ },
360
+ args: {
361
+ set: {
362
+ type: "boolean",
363
+ default: false,
364
+ description: "Set proxy configuration interactively"
365
+ },
366
+ enable: {
367
+ type: "boolean",
368
+ default: false,
369
+ description: "Enable saved proxy configuration"
370
+ },
371
+ disable: {
372
+ type: "boolean",
373
+ default: false,
374
+ description: "Disable proxy (keep settings)"
375
+ },
376
+ clear: {
377
+ type: "boolean",
378
+ default: false,
379
+ description: "Clear all proxy settings"
380
+ },
381
+ show: {
382
+ type: "boolean",
383
+ default: false,
384
+ description: "Show current proxy configuration"
385
+ },
386
+ "http-proxy": {
387
+ type: "string",
388
+ description: "HTTP proxy URL (e.g., http://proxy:8080)"
389
+ },
390
+ "https-proxy": {
391
+ type: "string",
392
+ description: "HTTPS proxy URL (e.g., http://proxy:8080)"
393
+ },
394
+ "no-proxy": {
395
+ type: "string",
396
+ description: "Comma-separated list of hosts to bypass proxy"
397
+ }
398
+ },
399
+ async run({ args }) {
400
+ await ensurePaths();
401
+ if (args.show || !args.set && !args.enable && !args.disable && !args.clear && !args["http-proxy"] && !args["https-proxy"]) {
402
+ const config = await getProxyConfig();
403
+ if (!config) {
404
+ consola.info("No proxy configuration saved.");
405
+ consola.info("");
406
+ consola.info("To configure proxy, use one of:");
407
+ consola.info(" copilot-api-plus proxy --set # Interactive setup");
408
+ consola.info(" copilot-api-plus proxy --http-proxy http://proxy:8080 # Direct set");
409
+ return;
410
+ }
411
+ consola.info("Current proxy configuration:");
412
+ consola.info(` Status: ${config.enabled ? "✅ Enabled" : "❌ Disabled"}`);
413
+ if (config.httpProxy) consola.info(` HTTP_PROXY: ${config.httpProxy}`);
414
+ if (config.httpsProxy) consola.info(` HTTPS_PROXY: ${config.httpsProxy}`);
415
+ if (config.noProxy) consola.info(` NO_PROXY: ${config.noProxy}`);
416
+ return;
417
+ }
418
+ if (args.clear) {
419
+ await clearProxyConfig();
420
+ consola.success("Proxy configuration cleared.");
421
+ return;
422
+ }
423
+ if (args.enable) {
424
+ const config = await getProxyConfig();
425
+ if (!config) {
426
+ consola.error("No proxy configuration saved. Use --set to configure first.");
427
+ return;
428
+ }
429
+ config.enabled = true;
430
+ await saveProxyConfig(config);
431
+ consola.success("Proxy enabled. It will be used on next server start.");
432
+ return;
433
+ }
434
+ if (args.disable) {
435
+ const config = await getProxyConfig();
436
+ if (!config) {
437
+ consola.info("No proxy configuration to disable.");
438
+ return;
439
+ }
440
+ config.enabled = false;
441
+ await saveProxyConfig(config);
442
+ consola.success("Proxy disabled. Settings are preserved.");
443
+ return;
444
+ }
445
+ if (args["http-proxy"] || args["https-proxy"]) {
446
+ const newConfig = {
447
+ enabled: true,
448
+ httpProxy: args["http-proxy"],
449
+ httpsProxy: args["https-proxy"] || args["http-proxy"],
450
+ noProxy: args["no-proxy"]
451
+ };
452
+ await saveProxyConfig(newConfig);
453
+ consola.success("Proxy configuration saved and enabled.");
454
+ consola.info(` HTTP_PROXY: ${newConfig.httpProxy || "(not set)"}`);
455
+ consola.info(` HTTPS_PROXY: ${newConfig.httpsProxy || "(not set)"}`);
456
+ if (newConfig.noProxy) consola.info(` NO_PROXY: ${newConfig.noProxy}`);
457
+ return;
458
+ }
459
+ if (args.set) {
460
+ p.intro("Proxy Configuration");
461
+ const existingConfig = await getProxyConfig();
462
+ const httpProxy = await p.text({
463
+ message: "HTTP Proxy URL",
464
+ placeholder: "http://proxy:8080",
465
+ initialValue: existingConfig?.httpProxy || ""
466
+ });
467
+ if (p.isCancel(httpProxy)) {
468
+ p.cancel("Configuration cancelled.");
469
+ return;
470
+ }
471
+ const httpsProxy = await p.text({
472
+ message: "HTTPS Proxy URL (leave empty to use HTTP proxy)",
473
+ placeholder: "http://proxy:8080",
474
+ initialValue: existingConfig?.httpsProxy || ""
475
+ });
476
+ if (p.isCancel(httpsProxy)) {
477
+ p.cancel("Configuration cancelled.");
478
+ return;
479
+ }
480
+ const noProxy = await p.text({
481
+ message: "No Proxy (comma-separated hosts to bypass)",
482
+ placeholder: "localhost,127.0.0.1,.local",
483
+ initialValue: existingConfig?.noProxy || ""
484
+ });
485
+ if (p.isCancel(noProxy)) {
486
+ p.cancel("Configuration cancelled.");
487
+ return;
488
+ }
489
+ const enable = await p.confirm({
490
+ message: "Enable proxy now?",
491
+ initialValue: true
492
+ });
493
+ if (p.isCancel(enable)) {
494
+ p.cancel("Configuration cancelled.");
495
+ return;
496
+ }
497
+ await saveProxyConfig({
498
+ enabled: enable,
499
+ httpProxy: httpProxy || void 0,
500
+ httpsProxy: httpsProxy || httpProxy || void 0,
501
+ noProxy: noProxy || void 0
502
+ });
503
+ p.outro(`Proxy configuration saved${enable ? " and enabled" : ""}.`);
504
+ }
505
+ }
506
+ });
507
+
248
508
  //#endregion
249
509
  //#region src/lib/proxy.ts
250
510
  function initProxyFromEnv() {
@@ -376,6 +636,700 @@ const apiKeyAuthMiddleware = async (c, next) => {
376
636
  await next();
377
637
  };
378
638
 
639
+ //#endregion
640
+ //#region src/services/antigravity/create-chat-completions.ts
641
+ const ANTIGRAVITY_API_HOST$1 = "daily-cloudcode-pa.sandbox.googleapis.com";
642
+ const ANTIGRAVITY_STREAM_URL$1 = `https://${ANTIGRAVITY_API_HOST$1}/v1internal:streamGenerateContent?alt=sse`;
643
+ const ANTIGRAVITY_NO_STREAM_URL$1 = `https://${ANTIGRAVITY_API_HOST$1}/v1internal:generateContent`;
644
+ const ANTIGRAVITY_USER_AGENT$1 = "antigravity/1.11.3 windows/amd64";
645
+ /**
646
+ * Convert OpenAI format messages to Antigravity format
647
+ */
648
+ function convertMessages$1(messages) {
649
+ const contents = [];
650
+ let systemInstruction = void 0;
651
+ for (const message of messages) {
652
+ if (message.role === "system") {
653
+ systemInstruction = {
654
+ role: "user",
655
+ parts: [{ text: typeof message.content === "string" ? message.content : message.content.map((c) => c.text || "").join("") }]
656
+ };
657
+ continue;
658
+ }
659
+ const role = message.role === "assistant" ? "model" : "user";
660
+ if (typeof message.content === "string") contents.push({
661
+ role,
662
+ parts: [{ text: message.content }]
663
+ });
664
+ else {
665
+ const parts = [];
666
+ for (const part of message.content) if (part.type === "text") parts.push({ text: part.text });
667
+ else if (part.type === "image_url" && part.image_url?.url) {
668
+ const url = part.image_url.url;
669
+ if (url.startsWith("data:")) {
670
+ const match = url.match(/^data:([^;]+);base64,(.+)$/);
671
+ if (match) parts.push({ inlineData: {
672
+ mimeType: match[1],
673
+ data: match[2]
674
+ } });
675
+ }
676
+ }
677
+ contents.push({
678
+ role,
679
+ parts
680
+ });
681
+ }
682
+ }
683
+ return {
684
+ contents,
685
+ systemInstruction
686
+ };
687
+ }
688
+ /**
689
+ * Convert tools to Antigravity format
690
+ */
691
+ function convertTools$1(tools) {
692
+ if (!tools || tools.length === 0) return;
693
+ return tools.map((tool) => {
694
+ const t = tool;
695
+ if (t.type === "function" && t.function) return { functionDeclarations: [{
696
+ name: t.function.name,
697
+ description: t.function.description || "",
698
+ parameters: t.function.parameters || {}
699
+ }] };
700
+ return tool;
701
+ });
702
+ }
703
+ /**
704
+ * Create chat completion with Antigravity
705
+ */
706
+ async function createAntigravityChatCompletion(request) {
707
+ const accessToken = await getValidAccessToken();
708
+ if (!accessToken) return new Response(JSON.stringify({ error: {
709
+ message: "No valid Antigravity access token available. Please run login first.",
710
+ type: "auth_error"
711
+ } }), {
712
+ status: 401,
713
+ headers: { "Content-Type": "application/json" }
714
+ });
715
+ const { contents, systemInstruction } = convertMessages$1(request.messages);
716
+ const tools = convertTools$1(request.tools);
717
+ const antigravityRequest = {
718
+ model: request.model,
719
+ contents,
720
+ generationConfig: {
721
+ temperature: request.temperature ?? 1,
722
+ topP: request.top_p ?? .85,
723
+ topK: request.top_k ?? 50,
724
+ maxOutputTokens: request.max_tokens ?? 8096
725
+ }
726
+ };
727
+ if (systemInstruction) antigravityRequest.systemInstruction = systemInstruction;
728
+ if (tools) antigravityRequest.tools = tools;
729
+ if (isThinkingModel(request.model)) antigravityRequest.generationConfig = {
730
+ ...antigravityRequest.generationConfig,
731
+ thinkingConfig: { includeThoughts: true }
732
+ };
733
+ const endpoint = request.stream ? ANTIGRAVITY_STREAM_URL$1 : ANTIGRAVITY_NO_STREAM_URL$1;
734
+ consola.debug(`Antigravity request to ${endpoint} with model ${request.model}`);
735
+ try {
736
+ const response = await fetch(endpoint, {
737
+ method: "POST",
738
+ headers: {
739
+ Host: ANTIGRAVITY_API_HOST$1,
740
+ "User-Agent": ANTIGRAVITY_USER_AGENT$1,
741
+ Authorization: `Bearer ${accessToken}`,
742
+ "Content-Type": "application/json",
743
+ "Accept-Encoding": "gzip"
744
+ },
745
+ body: JSON.stringify(antigravityRequest)
746
+ });
747
+ if (!response.ok) {
748
+ const errorText = await response.text();
749
+ consola.error(`Antigravity error: ${response.status} ${errorText}`);
750
+ if (response.status === 403) await disableCurrentAccount();
751
+ if (response.status === 429 || response.status === 503) await rotateAccount();
752
+ return new Response(JSON.stringify({ error: {
753
+ message: `Antigravity API error: ${response.status}`,
754
+ type: "api_error",
755
+ details: errorText
756
+ } }), {
757
+ status: response.status,
758
+ headers: { "Content-Type": "application/json" }
759
+ });
760
+ }
761
+ if (request.stream) return transformStreamResponse(response, request.model);
762
+ else return transformNonStreamResponse(response, request.model);
763
+ } catch (error) {
764
+ consola.error("Antigravity request error:", error);
765
+ return new Response(JSON.stringify({ error: {
766
+ message: `Request failed: ${error}`,
767
+ type: "request_error"
768
+ } }), {
769
+ status: 500,
770
+ headers: { "Content-Type": "application/json" }
771
+ });
772
+ }
773
+ }
774
+ /**
775
+ * Transform Antigravity stream response to OpenAI format
776
+ */
777
+ function transformStreamResponse(response, model) {
778
+ const reader = response.body?.getReader();
779
+ if (!reader) return new Response("No response body", { status: 500 });
780
+ const encoder = new TextEncoder();
781
+ const decoder = new TextDecoder();
782
+ const stream = new ReadableStream({ async start(controller) {
783
+ let buffer = "";
784
+ const requestId = `chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
785
+ try {
786
+ while (true) {
787
+ const { done, value } = await reader.read();
788
+ if (done) {
789
+ controller.enqueue(encoder.encode("data: [DONE]\n\n"));
790
+ controller.close();
791
+ break;
792
+ }
793
+ buffer += decoder.decode(value, { stream: true });
794
+ const lines = buffer.split("\n");
795
+ buffer = lines.pop() || "";
796
+ for (const line of lines) if (line.startsWith("data: ")) {
797
+ const data = line.slice(6).trim();
798
+ if (data === "[DONE]" || data === "") continue;
799
+ try {
800
+ const parsed = JSON.parse(data);
801
+ const candidate = (parsed.response?.candidates || parsed.candidates)?.[0];
802
+ const parts = candidate?.content?.parts || [];
803
+ for (const part of parts) {
804
+ if (part.thought && part.text) {
805
+ const chunk = {
806
+ id: requestId,
807
+ object: "chat.completion.chunk",
808
+ created: Math.floor(Date.now() / 1e3),
809
+ model,
810
+ choices: [{
811
+ index: 0,
812
+ delta: { reasoning_content: part.text },
813
+ finish_reason: null
814
+ }]
815
+ };
816
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
817
+ continue;
818
+ }
819
+ if (part.text) {
820
+ const chunk = {
821
+ id: requestId,
822
+ object: "chat.completion.chunk",
823
+ created: Math.floor(Date.now() / 1e3),
824
+ model,
825
+ choices: [{
826
+ index: 0,
827
+ delta: { content: part.text },
828
+ finish_reason: candidate?.finishReason === "STOP" ? "stop" : null
829
+ }]
830
+ };
831
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
832
+ }
833
+ if (part.functionCall) {
834
+ const chunk = {
835
+ id: requestId,
836
+ object: "chat.completion.chunk",
837
+ created: Math.floor(Date.now() / 1e3),
838
+ model,
839
+ choices: [{
840
+ index: 0,
841
+ delta: { tool_calls: [{
842
+ index: 0,
843
+ id: `call_${Date.now()}`,
844
+ type: "function",
845
+ function: {
846
+ name: part.functionCall.name,
847
+ arguments: JSON.stringify(part.functionCall.args)
848
+ }
849
+ }] },
850
+ finish_reason: null
851
+ }]
852
+ };
853
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
854
+ }
855
+ }
856
+ } catch {}
857
+ }
858
+ }
859
+ } catch (error) {
860
+ consola.error("Stream transform error:", error);
861
+ controller.error(error);
862
+ }
863
+ } });
864
+ return new Response(stream, { headers: {
865
+ "Content-Type": "text/event-stream",
866
+ "Cache-Control": "no-cache",
867
+ Connection: "keep-alive"
868
+ } });
869
+ }
870
+ /**
871
+ * Transform Antigravity non-stream response to OpenAI format
872
+ */
873
+ async function transformNonStreamResponse(response, model) {
874
+ const data = await response.json();
875
+ const candidate = data.candidates?.[0];
876
+ const parts = candidate?.content?.parts || [];
877
+ let content = "";
878
+ let reasoningContent = "";
879
+ const toolCalls = [];
880
+ for (const part of parts) {
881
+ if (part.thought && part.text) reasoningContent += part.text;
882
+ else if (part.text) content += part.text;
883
+ if (part.functionCall) toolCalls.push({
884
+ id: `call_${Date.now()}`,
885
+ type: "function",
886
+ function: {
887
+ name: part.functionCall.name,
888
+ arguments: JSON.stringify(part.functionCall.args)
889
+ }
890
+ });
891
+ }
892
+ const message = {
893
+ role: "assistant",
894
+ content: content || null
895
+ };
896
+ if (reasoningContent) message.reasoning_content = reasoningContent;
897
+ if (toolCalls.length > 0) message.tool_calls = toolCalls;
898
+ const openaiResponse = {
899
+ id: `chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
900
+ object: "chat.completion",
901
+ created: Math.floor(Date.now() / 1e3),
902
+ model,
903
+ choices: [{
904
+ index: 0,
905
+ message,
906
+ finish_reason: candidate?.finishReason === "STOP" ? "stop" : "stop"
907
+ }],
908
+ usage: {
909
+ prompt_tokens: data.usageMetadata?.promptTokenCount || 0,
910
+ completion_tokens: data.usageMetadata?.candidatesTokenCount || 0,
911
+ total_tokens: data.usageMetadata?.totalTokenCount || 0
912
+ }
913
+ };
914
+ return new Response(JSON.stringify(openaiResponse), { headers: { "Content-Type": "application/json" } });
915
+ }
916
+
917
+ //#endregion
918
+ //#region src/routes/antigravity/chat-completions/route.ts
919
+ const app$1 = new Hono();
920
+ app$1.post("/", async (c) => {
921
+ const body = await c.req.json();
922
+ const response = await createAntigravityChatCompletion(body);
923
+ const headers = new Headers(response.headers);
924
+ if (body.stream) return new Response(response.body, {
925
+ status: response.status,
926
+ headers
927
+ });
928
+ return new Response(await response.text(), {
929
+ status: response.status,
930
+ headers
931
+ });
932
+ });
933
+ const antigravityChatCompletionsRoute = app$1;
934
+
935
+ //#endregion
936
+ //#region src/services/antigravity/create-messages.ts
937
+ const ANTIGRAVITY_API_HOST = "daily-cloudcode-pa.sandbox.googleapis.com";
938
+ const ANTIGRAVITY_STREAM_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:streamGenerateContent?alt=sse`;
939
+ const ANTIGRAVITY_NO_STREAM_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:generateContent`;
940
+ const ANTIGRAVITY_USER_AGENT = "antigravity/1.11.3 windows/amd64";
941
+ /**
942
+ * Convert Anthropic messages to Antigravity format
943
+ */
944
+ function convertMessages(messages, system) {
945
+ const contents = [];
946
+ let systemInstruction = void 0;
947
+ if (system) systemInstruction = {
948
+ role: "user",
949
+ parts: [{ text: system }]
950
+ };
951
+ for (const message of messages) {
952
+ const role = message.role === "assistant" ? "model" : "user";
953
+ if (typeof message.content === "string") contents.push({
954
+ role,
955
+ parts: [{ text: message.content }]
956
+ });
957
+ else {
958
+ const parts = [];
959
+ for (const block of message.content) if (block.type === "text" && block.text) parts.push({ text: block.text });
960
+ else if (block.type === "image" && block.source) parts.push({ inlineData: {
961
+ mimeType: block.source.media_type,
962
+ data: block.source.data
963
+ } });
964
+ if (parts.length > 0) contents.push({
965
+ role,
966
+ parts
967
+ });
968
+ }
969
+ }
970
+ return {
971
+ contents,
972
+ systemInstruction
973
+ };
974
+ }
975
+ /**
976
+ * Convert tools to Antigravity format
977
+ */
978
+ function convertTools(tools) {
979
+ if (!tools || tools.length === 0) return;
980
+ return tools.map((tool) => {
981
+ const t = tool;
982
+ return { functionDeclarations: [{
983
+ name: t.name,
984
+ description: t.description || "",
985
+ parameters: t.input_schema || {}
986
+ }] };
987
+ });
988
+ }
989
+ /**
990
+ * Create Anthropic-compatible message response using Antigravity
991
+ */
992
+ async function createAntigravityMessages(request) {
993
+ const accessToken = await getValidAccessToken();
994
+ if (!accessToken) return new Response(JSON.stringify({
995
+ type: "error",
996
+ error: {
997
+ type: "authentication_error",
998
+ message: "No valid Antigravity access token available. Please run login first."
999
+ }
1000
+ }), {
1001
+ status: 401,
1002
+ headers: { "Content-Type": "application/json" }
1003
+ });
1004
+ const { contents, systemInstruction } = convertMessages(request.messages, request.system);
1005
+ const tools = convertTools(request.tools);
1006
+ const antigravityRequest = {
1007
+ model: request.model,
1008
+ contents,
1009
+ generationConfig: {
1010
+ temperature: request.temperature ?? 1,
1011
+ topP: request.top_p ?? .85,
1012
+ topK: request.top_k ?? 50,
1013
+ maxOutputTokens: request.max_tokens ?? 8096
1014
+ }
1015
+ };
1016
+ if (systemInstruction) antigravityRequest.systemInstruction = systemInstruction;
1017
+ if (tools) antigravityRequest.tools = tools;
1018
+ if (isThinkingModel(request.model)) antigravityRequest.generationConfig = {
1019
+ ...antigravityRequest.generationConfig,
1020
+ thinkingConfig: { includeThoughts: true }
1021
+ };
1022
+ const endpoint = request.stream ? ANTIGRAVITY_STREAM_URL : ANTIGRAVITY_NO_STREAM_URL;
1023
+ consola.debug(`Antigravity messages request to ${endpoint} with model ${request.model}`);
1024
+ try {
1025
+ const response = await fetch(endpoint, {
1026
+ method: "POST",
1027
+ headers: {
1028
+ Host: ANTIGRAVITY_API_HOST,
1029
+ "User-Agent": ANTIGRAVITY_USER_AGENT,
1030
+ Authorization: `Bearer ${accessToken}`,
1031
+ "Content-Type": "application/json",
1032
+ "Accept-Encoding": "gzip"
1033
+ },
1034
+ body: JSON.stringify(antigravityRequest)
1035
+ });
1036
+ if (!response.ok) {
1037
+ const errorText = await response.text();
1038
+ consola.error(`Antigravity error: ${response.status} ${errorText}`);
1039
+ if (response.status === 403) await disableCurrentAccount();
1040
+ if (response.status === 429 || response.status === 503) await rotateAccount();
1041
+ return new Response(JSON.stringify({
1042
+ type: "error",
1043
+ error: {
1044
+ type: "api_error",
1045
+ message: `Antigravity API error: ${response.status}`
1046
+ }
1047
+ }), {
1048
+ status: response.status,
1049
+ headers: { "Content-Type": "application/json" }
1050
+ });
1051
+ }
1052
+ if (request.stream) return transformStreamToAnthropic(response, request.model);
1053
+ else return transformNonStreamToAnthropic(response, request.model);
1054
+ } catch (error) {
1055
+ consola.error("Antigravity messages request error:", error);
1056
+ return new Response(JSON.stringify({
1057
+ type: "error",
1058
+ error: {
1059
+ type: "api_error",
1060
+ message: `Request failed: ${error}`
1061
+ }
1062
+ }), {
1063
+ status: 500,
1064
+ headers: { "Content-Type": "application/json" }
1065
+ });
1066
+ }
1067
+ }
1068
+ /**
1069
+ * Transform Antigravity stream response to Anthropic format
1070
+ */
1071
+ function transformStreamToAnthropic(response, model) {
1072
+ const reader = response.body?.getReader();
1073
+ if (!reader) return new Response("No response body", { status: 500 });
1074
+ const encoder = new TextEncoder();
1075
+ const decoder = new TextDecoder();
1076
+ const stream = new ReadableStream({ async start(controller) {
1077
+ let buffer = "";
1078
+ const messageId = `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
1079
+ let inputTokens = 0;
1080
+ let outputTokens = 0;
1081
+ let contentBlockIndex = 0;
1082
+ let thinkingBlockStarted = false;
1083
+ let textBlockStarted = false;
1084
+ const messageStart = {
1085
+ type: "message_start",
1086
+ message: {
1087
+ id: messageId,
1088
+ type: "message",
1089
+ role: "assistant",
1090
+ content: [],
1091
+ model,
1092
+ stop_reason: null,
1093
+ stop_sequence: null,
1094
+ usage: {
1095
+ input_tokens: 0,
1096
+ output_tokens: 0
1097
+ }
1098
+ }
1099
+ };
1100
+ controller.enqueue(encoder.encode(`event: message_start\ndata: ${JSON.stringify(messageStart)}\n\n`));
1101
+ try {
1102
+ while (true) {
1103
+ const { done, value } = await reader.read();
1104
+ if (done) {
1105
+ controller.enqueue(encoder.encode(`event: message_stop\ndata: ${JSON.stringify({ type: "message_stop" })}\n\n`));
1106
+ controller.close();
1107
+ break;
1108
+ }
1109
+ buffer += decoder.decode(value, { stream: true });
1110
+ const lines = buffer.split("\n");
1111
+ buffer = lines.pop() || "";
1112
+ for (const line of lines) if (line.startsWith("data: ")) {
1113
+ const data = line.slice(6).trim();
1114
+ if (data === "[DONE]" || data === "") continue;
1115
+ try {
1116
+ const parsed = JSON.parse(data);
1117
+ const candidate = (parsed.response?.candidates || parsed.candidates)?.[0];
1118
+ const parts = candidate?.content?.parts || [];
1119
+ const usage = parsed.response?.usageMetadata || parsed.usageMetadata;
1120
+ if (usage) {
1121
+ inputTokens = usage.promptTokenCount || inputTokens;
1122
+ outputTokens = usage.candidatesTokenCount || outputTokens;
1123
+ }
1124
+ for (const part of parts) {
1125
+ if (part.thought && part.text) {
1126
+ if (!thinkingBlockStarted) {
1127
+ const blockStart = {
1128
+ type: "content_block_start",
1129
+ index: contentBlockIndex,
1130
+ content_block: {
1131
+ type: "thinking",
1132
+ thinking: ""
1133
+ }
1134
+ };
1135
+ controller.enqueue(encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(blockStart)}\n\n`));
1136
+ thinkingBlockStarted = true;
1137
+ }
1138
+ const thinkingDelta = {
1139
+ type: "content_block_delta",
1140
+ index: contentBlockIndex,
1141
+ delta: {
1142
+ type: "thinking_delta",
1143
+ thinking: part.text
1144
+ }
1145
+ };
1146
+ controller.enqueue(encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(thinkingDelta)}\n\n`));
1147
+ continue;
1148
+ }
1149
+ if (part.text && !part.thought) {
1150
+ if (thinkingBlockStarted && !textBlockStarted) {
1151
+ const blockStop = {
1152
+ type: "content_block_stop",
1153
+ index: contentBlockIndex
1154
+ };
1155
+ controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(blockStop)}\n\n`));
1156
+ contentBlockIndex++;
1157
+ }
1158
+ if (!textBlockStarted) {
1159
+ const blockStart = {
1160
+ type: "content_block_start",
1161
+ index: contentBlockIndex,
1162
+ content_block: {
1163
+ type: "text",
1164
+ text: ""
1165
+ }
1166
+ };
1167
+ controller.enqueue(encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(blockStart)}\n\n`));
1168
+ textBlockStarted = true;
1169
+ }
1170
+ const textDelta = {
1171
+ type: "content_block_delta",
1172
+ index: contentBlockIndex,
1173
+ delta: {
1174
+ type: "text_delta",
1175
+ text: part.text
1176
+ }
1177
+ };
1178
+ controller.enqueue(encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(textDelta)}\n\n`));
1179
+ }
1180
+ if (part.functionCall) {
1181
+ if (textBlockStarted || thinkingBlockStarted) {
1182
+ const blockStop = {
1183
+ type: "content_block_stop",
1184
+ index: contentBlockIndex
1185
+ };
1186
+ controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(blockStop)}\n\n`));
1187
+ contentBlockIndex++;
1188
+ textBlockStarted = false;
1189
+ thinkingBlockStarted = false;
1190
+ }
1191
+ const toolBlockStart = {
1192
+ type: "content_block_start",
1193
+ index: contentBlockIndex,
1194
+ content_block: {
1195
+ type: "tool_use",
1196
+ id: `toolu_${Date.now()}`,
1197
+ name: part.functionCall.name,
1198
+ input: {}
1199
+ }
1200
+ };
1201
+ controller.enqueue(encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(toolBlockStart)}\n\n`));
1202
+ const toolDelta = {
1203
+ type: "content_block_delta",
1204
+ index: contentBlockIndex,
1205
+ delta: {
1206
+ type: "input_json_delta",
1207
+ partial_json: JSON.stringify(part.functionCall.args)
1208
+ }
1209
+ };
1210
+ controller.enqueue(encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(toolDelta)}\n\n`));
1211
+ const toolBlockStop = {
1212
+ type: "content_block_stop",
1213
+ index: contentBlockIndex
1214
+ };
1215
+ controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(toolBlockStop)}\n\n`));
1216
+ contentBlockIndex++;
1217
+ }
1218
+ }
1219
+ if (candidate?.finishReason === "STOP") {
1220
+ if (textBlockStarted || thinkingBlockStarted) {
1221
+ const blockStop = {
1222
+ type: "content_block_stop",
1223
+ index: contentBlockIndex
1224
+ };
1225
+ controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(blockStop)}\n\n`));
1226
+ }
1227
+ const messageDelta = {
1228
+ type: "message_delta",
1229
+ delta: {
1230
+ stop_reason: "end_turn",
1231
+ stop_sequence: null
1232
+ },
1233
+ usage: { output_tokens: outputTokens }
1234
+ };
1235
+ controller.enqueue(encoder.encode(`event: message_delta\ndata: ${JSON.stringify(messageDelta)}\n\n`));
1236
+ }
1237
+ } catch {}
1238
+ }
1239
+ }
1240
+ } catch (error) {
1241
+ consola.error("Stream transform error:", error);
1242
+ controller.error(error);
1243
+ }
1244
+ } });
1245
+ return new Response(stream, { headers: {
1246
+ "Content-Type": "text/event-stream",
1247
+ "Cache-Control": "no-cache",
1248
+ Connection: "keep-alive"
1249
+ } });
1250
+ }
1251
+ /**
1252
+ * Transform Antigravity non-stream response to Anthropic format
1253
+ */
1254
+ async function transformNonStreamToAnthropic(response, model) {
1255
+ const data = await response.json();
1256
+ const candidate = data.candidates?.[0];
1257
+ const parts = candidate?.content?.parts || [];
1258
+ const content = [];
1259
+ for (const part of parts) {
1260
+ if (part.thought && part.text) content.push({
1261
+ type: "thinking",
1262
+ thinking: part.text
1263
+ });
1264
+ else if (part.text) content.push({
1265
+ type: "text",
1266
+ text: part.text
1267
+ });
1268
+ if (part.functionCall) content.push({
1269
+ type: "tool_use",
1270
+ id: `toolu_${Date.now()}`,
1271
+ name: part.functionCall.name,
1272
+ input: part.functionCall.args
1273
+ });
1274
+ }
1275
+ const anthropicResponse = {
1276
+ id: `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
1277
+ type: "message",
1278
+ role: "assistant",
1279
+ content,
1280
+ model,
1281
+ stop_reason: candidate?.finishReason === "STOP" ? "end_turn" : "end_turn",
1282
+ stop_sequence: null,
1283
+ usage: {
1284
+ input_tokens: data.usageMetadata?.promptTokenCount || 0,
1285
+ output_tokens: data.usageMetadata?.candidatesTokenCount || 0
1286
+ }
1287
+ };
1288
+ return new Response(JSON.stringify(anthropicResponse), { headers: { "Content-Type": "application/json" } });
1289
+ }
1290
+
1291
+ //#endregion
1292
+ //#region src/routes/antigravity/messages/route.ts
1293
+ const antigravityMessagesRoute = new Hono();
1294
+ antigravityMessagesRoute.post("/", async (c) => {
1295
+ if (!state.antigravityMode) return c.json({ error: "Antigravity mode is not enabled. Start with --antigravity flag." }, 400);
1296
+ try {
1297
+ const body = await c.req.json();
1298
+ consola.debug("Antigravity message request:", body.model);
1299
+ const response = await createAntigravityMessages(body);
1300
+ if (body.stream) {
1301
+ const headers = new Headers();
1302
+ headers.set("Content-Type", "text/event-stream");
1303
+ headers.set("Cache-Control", "no-cache");
1304
+ headers.set("Connection", "keep-alive");
1305
+ return new Response(response.body, {
1306
+ status: response.status,
1307
+ headers
1308
+ });
1309
+ }
1310
+ const data = await response.json();
1311
+ return c.json(data);
1312
+ } catch (error) {
1313
+ consola.error("Antigravity message error:", error);
1314
+ return c.json({
1315
+ type: "error",
1316
+ error: {
1317
+ type: "antigravity_error",
1318
+ message: error instanceof Error ? error.message : "Unknown error"
1319
+ }
1320
+ }, 500);
1321
+ }
1322
+ });
1323
+
1324
+ //#endregion
1325
+ //#region src/routes/antigravity/models/route.ts
1326
+ const app = new Hono();
1327
+ app.get("/", async (c) => {
1328
+ const models = await getAntigravityModels();
1329
+ return c.json(models);
1330
+ });
1331
+ const antigravityModelsRoute = app;
1332
+
379
1333
  //#endregion
380
1334
  //#region src/lib/approval.ts
381
1335
  const awaitApproval = async () => {
@@ -1312,7 +2266,7 @@ zenModelRoutes.get("/", async (c) => {
1312
2266
  if (!state.zenMode || !state.zenApiKey) return c.json({ error: "Zen mode is not enabled. Start with --zen flag." }, 400);
1313
2267
  try {
1314
2268
  if (state.zenModels) return c.json(state.zenModels);
1315
- const { getZenModels } = await import("./get-models-Hlxa1hWY.js");
2269
+ const { getZenModels } = await import("./get-models-DJfPj_Rg.js");
1316
2270
  const models = await getZenModels();
1317
2271
  state.zenModels = models;
1318
2272
  return c.json(models);
@@ -1332,33 +2286,41 @@ server.use(logger());
1332
2286
  server.use(cors());
1333
2287
  server.use(apiKeyAuthMiddleware);
1334
2288
  server.get("/", (c) => c.text("Server running"));
1335
- server.route("/chat/completions", new Hono().all("/*", async (c, next) => {
2289
+ server.route("/chat/completions", new Hono().all("/*", async (c, _next) => {
1336
2290
  if (state.zenMode) return zenCompletionRoutes.fetch(c.req.raw, c.env);
2291
+ if (state.antigravityMode) return antigravityChatCompletionsRoute.fetch(c.req.raw, c.env);
1337
2292
  return completionRoutes.fetch(c.req.raw, c.env);
1338
2293
  }));
1339
- server.route("/models", new Hono().all("/*", async (c, next) => {
2294
+ server.route("/models", new Hono().all("/*", async (c, _next) => {
1340
2295
  if (state.zenMode) return zenModelRoutes.fetch(c.req.raw, c.env);
2296
+ if (state.antigravityMode) return antigravityModelsRoute.fetch(c.req.raw, c.env);
1341
2297
  return modelRoutes.fetch(c.req.raw, c.env);
1342
2298
  }));
1343
2299
  server.route("/embeddings", embeddingRoutes);
1344
2300
  server.route("/usage", usageRoute);
1345
2301
  server.route("/token", tokenRoute);
1346
- server.route("/v1/chat/completions", new Hono().all("/*", async (c, next) => {
2302
+ server.route("/v1/chat/completions", new Hono().all("/*", async (c, _next) => {
1347
2303
  if (state.zenMode) return zenCompletionRoutes.fetch(c.req.raw, c.env);
2304
+ if (state.antigravityMode) return antigravityChatCompletionsRoute.fetch(c.req.raw, c.env);
1348
2305
  return completionRoutes.fetch(c.req.raw, c.env);
1349
2306
  }));
1350
- server.route("/v1/models", new Hono().all("/*", async (c, next) => {
2307
+ server.route("/v1/models", new Hono().all("/*", async (c, _next) => {
1351
2308
  if (state.zenMode) return zenModelRoutes.fetch(c.req.raw, c.env);
2309
+ if (state.antigravityMode) return antigravityModelsRoute.fetch(c.req.raw, c.env);
1352
2310
  return modelRoutes.fetch(c.req.raw, c.env);
1353
2311
  }));
1354
2312
  server.route("/v1/embeddings", embeddingRoutes);
1355
- server.route("/v1/messages", new Hono().all("/*", async (c, next) => {
2313
+ server.route("/v1/messages", new Hono().all("/*", async (c, _next) => {
1356
2314
  if (state.zenMode) return zenMessageRoutes.fetch(c.req.raw, c.env);
2315
+ if (state.antigravityMode) return antigravityMessagesRoute.fetch(c.req.raw, c.env);
1357
2316
  return messageRoutes.fetch(c.req.raw, c.env);
1358
2317
  }));
1359
2318
  server.route("/zen/v1/chat/completions", zenCompletionRoutes);
1360
2319
  server.route("/zen/v1/models", zenModelRoutes);
1361
2320
  server.route("/zen/v1/messages", zenMessageRoutes);
2321
+ server.route("/antigravity/v1/chat/completions", antigravityChatCompletionsRoute);
2322
+ server.route("/antigravity/v1/models", antigravityModelsRoute);
2323
+ server.route("/antigravity/v1/messages", antigravityMessagesRoute);
1362
2324
 
1363
2325
  //#endregion
1364
2326
  //#region src/start.ts
@@ -1386,7 +2348,9 @@ server.route("/zen/v1/messages", zenMessageRoutes);
1386
2348
  * - zenApiKey: OpenCode Zen API key (optional; if omitted will prompt for setup)
1387
2349
  */
1388
2350
  async function runServer(options) {
2351
+ const savedProxyApplied = await applyProxyConfig();
1389
2352
  if (options.proxyEnv) initProxyFromEnv();
2353
+ else if (savedProxyApplied) initProxyFromEnv();
1390
2354
  if (options.verbose) {
1391
2355
  consola.level = 5;
1392
2356
  consola.info("Verbose logging enabled");
@@ -1407,23 +2371,40 @@ async function runServer(options) {
1407
2371
  state.zenApiKey = options.zenApiKey;
1408
2372
  consola.info("Using provided Zen API key");
1409
2373
  } else {
1410
- const { setupZenApiKey, loadZenAuth } = await import("./auth-KlL1W4gV.js");
2374
+ const { setupZenApiKey, loadZenAuth } = await import("./auth-BO-mwvoU.js");
1411
2375
  const existingAuth = await loadZenAuth();
1412
2376
  if (existingAuth) {
1413
2377
  state.zenApiKey = existingAuth.apiKey;
1414
2378
  consola.info("Using existing Zen API key");
1415
2379
  } else state.zenApiKey = await setupZenApiKey();
1416
2380
  }
1417
- const { cacheZenModels } = await import("./get-models-Hlxa1hWY.js");
2381
+ const { cacheZenModels } = await import("./get-models-DJfPj_Rg.js");
1418
2382
  await cacheZenModels();
1419
2383
  consola.info(`Available Zen models: \n${state.zenModels?.data.map((model) => `- ${model.id}`).join("\n")}`);
2384
+ } else if (options.antigravity) {
2385
+ consola.info("Google Antigravity mode enabled");
2386
+ state.antigravityMode = true;
2387
+ const { loadAntigravityAuth, setupAntigravity, getCurrentAccount } = await import("./auth-D2wtETTq.js");
2388
+ const existingAuth = await loadAntigravityAuth();
2389
+ if (!existingAuth || existingAuth.accounts.length === 0) {
2390
+ consola.warn("No Antigravity accounts found");
2391
+ await setupAntigravity();
2392
+ } else {
2393
+ const enabledCount = existingAuth.accounts.filter((a) => a.enable).length;
2394
+ consola.info(`Found ${existingAuth.accounts.length} Antigravity accounts (${enabledCount} enabled)`);
2395
+ }
2396
+ if (!await getCurrentAccount()) throw new Error("No enabled Antigravity accounts available");
2397
+ const { getAntigravityModels: getAntigravityModels$1 } = await import("./get-models-Dq2ZDU9m.js");
2398
+ const models = await getAntigravityModels$1();
2399
+ state.antigravityModels = models;
2400
+ consola.info(`Available Antigravity models: \n${models.data.map((model) => `- ${model.id}`).join("\n")}`);
1420
2401
  } else {
1421
2402
  await cacheVSCodeVersion();
1422
2403
  if (options.githubToken) {
1423
2404
  state.githubToken = options.githubToken;
1424
2405
  consola.info("Using provided GitHub token");
1425
2406
  try {
1426
- const { getGitHubUser } = await import("./get-user-M3sQS0U8.js");
2407
+ const { getGitHubUser } = await import("./get-user-hpkh0FzZ.js");
1427
2408
  const user = await getGitHubUser();
1428
2409
  consola.info(`Logged in as ${user.login}`);
1429
2410
  } catch (error) {
@@ -1437,7 +2418,7 @@ async function runServer(options) {
1437
2418
  const { HTTPError: HTTPError$1 } = await import("./error-CsShqJjE.js");
1438
2419
  if (error instanceof HTTPError$1 && error.response.status === 401) {
1439
2420
  consola.error("Failed to get Copilot token - GitHub token may be invalid or Copilot access revoked");
1440
- const { clearGithubToken: clearGithubToken$1 } = await import("./token-BssxOyqn.js");
2421
+ const { clearGithubToken: clearGithubToken$1 } = await import("./token-DS09XjQ5.js");
1441
2422
  await clearGithubToken$1();
1442
2423
  consola.info("Please restart to re-authenticate");
1443
2424
  }
@@ -1448,7 +2429,7 @@ async function runServer(options) {
1448
2429
  }
1449
2430
  const serverUrl = `http://localhost:${options.port}`;
1450
2431
  if (options.claudeCode) {
1451
- const models = state.zenMode ? state.zenModels : state.models;
2432
+ const models = state.zenMode ? state.zenModels : state.antigravityMode ? state.antigravityModels : state.models;
1452
2433
  invariant(models, "Models should be loaded by now");
1453
2434
  const selectedModel = await consola.prompt("Select a model to use with Claude Code", {
1454
2435
  type: "select",
@@ -1556,6 +2537,11 @@ const start = defineCommand({
1556
2537
  "zen-api-key": {
1557
2538
  type: "string",
1558
2539
  description: "OpenCode Zen API key (get from https://opencode.ai/zen)"
2540
+ },
2541
+ antigravity: {
2542
+ type: "boolean",
2543
+ default: false,
2544
+ description: "Enable Google Antigravity mode (proxy to Antigravity instead of GitHub Copilot)"
1559
2545
  }
1560
2546
  },
1561
2547
  run({ args }) {
@@ -1577,7 +2563,8 @@ const start = defineCommand({
1577
2563
  proxyEnv: args["proxy-env"],
1578
2564
  apiKeys,
1579
2565
  zen: args.zen,
1580
- zenApiKey: args["zen-api-key"]
2566
+ zenApiKey: args["zen-api-key"],
2567
+ antigravity: args.antigravity
1581
2568
  });
1582
2569
  }
1583
2570
  });
@@ -1594,7 +2581,8 @@ const main = defineCommand({
1594
2581
  start,
1595
2582
  "check-usage": checkUsage,
1596
2583
  debug,
1597
- logout
2584
+ logout,
2585
+ proxy
1598
2586
  }
1599
2587
  });
1600
2588
  await runMain(main);