copilot-api-plus 1.0.56 → 1.0.58

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,24 +1,19 @@
1
1
  #!/usr/bin/env node
2
- import { n as ensurePaths, t as PATHS } from "./paths-BdbyVdad.js";
3
- import { t as state } from "./state-CRpaW-qc.js";
4
- import { c as githubHeaders, n as GITHUB_API_BASE_URL, o as copilotBaseUrl, s as copilotHeaders } from "./get-user-DOv07Myc.js";
5
- import { n as forwardError, t as HTTPError } from "./error-CvvAyU1E.js";
6
- import { a as cacheModels, c as isNullish, i as setupGitHubToken, l as sleep, n as refreshCopilotToken, o as cacheVSCodeVersion, r as setupCopilotToken, s as findModel, t as clearGithubToken } from "./token-D8U-wBLK.js";
7
- import { d as getValidAccessToken, g as rotateAccount, l as getCurrentProjectId, n as clearAntigravityAuth, o as getAntigravityAuthPath, r as disableCurrentAccount, s as getApiKey } from "./auth-D_mymhYC.js";
8
- import { n as getZenAuthPath, t as clearZenAuth } from "./auth-DIDShcrD.js";
9
- import { n as getAntigravityUsage, r as isThinkingModel, t as getAntigravityModels } from "./get-models-DhYpjJVG.js";
2
+ import { a as cacheModels, c as isNullish, d as ensurePaths, i as setupGitHubToken, l as sleep, n as refreshCopilotToken, o as cacheVSCodeVersion, r as setupCopilotToken, s as findModel, t as clearGithubToken, u as PATHS } from "./token-DmGYG1Z1.js";
3
+ import { c as githubHeaders, n as GITHUB_API_BASE_URL, o as copilotBaseUrl, s as copilotHeaders, u as state } from "./get-user-BxebJZB6.js";
4
+ import { n as forwardError, t as HTTPError } from "./error-u36czEGD.js";
10
5
  import { createRequire } from "node:module";
11
6
  import { defineCommand, runMain } from "citty";
12
7
  import consola from "consola";
13
8
  import fs from "node:fs/promises";
14
- import path from "node:path";
15
9
  import os from "node:os";
16
- import { getProxyForUrl } from "proxy-from-env";
17
- import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
10
+ import path from "node:path";
18
11
  import * as p from "@clack/prompts";
19
12
  import clipboard from "clipboardy";
20
13
  import { serve } from "srvx";
21
14
  import invariant from "tiny-invariant";
15
+ import { getProxyForUrl } from "proxy-from-env";
16
+ import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
22
17
  import { execSync } from "node:child_process";
23
18
  import process$1 from "node:process";
24
19
  import { Hono } from "hono";
@@ -30,376 +25,84 @@ import { events } from "fetch-event-stream";
30
25
  var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
31
26
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
32
27
  //#endregion
33
- //#region node_modules/dotenv/package.json
34
- var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
35
- module.exports = {
36
- "name": "dotenv",
37
- "version": "17.2.3",
38
- "description": "Loads environment variables from .env file",
39
- "main": "lib/main.js",
40
- "types": "lib/main.d.ts",
41
- "exports": {
42
- ".": {
43
- "types": "./lib/main.d.ts",
44
- "require": "./lib/main.js",
45
- "default": "./lib/main.js"
46
- },
47
- "./config": "./config.js",
48
- "./config.js": "./config.js",
49
- "./lib/env-options": "./lib/env-options.js",
50
- "./lib/env-options.js": "./lib/env-options.js",
51
- "./lib/cli-options": "./lib/cli-options.js",
52
- "./lib/cli-options.js": "./lib/cli-options.js",
53
- "./package.json": "./package.json"
54
- },
55
- "scripts": {
56
- "dts-check": "tsc --project tests/types/tsconfig.json",
57
- "lint": "standard",
58
- "pretest": "npm run lint && npm run dts-check",
59
- "test": "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
60
- "test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
61
- "prerelease": "npm test",
62
- "release": "standard-version"
63
- },
64
- "repository": {
65
- "type": "git",
66
- "url": "git://github.com/motdotla/dotenv.git"
67
- },
68
- "homepage": "https://github.com/motdotla/dotenv#readme",
69
- "funding": "https://dotenvx.com",
70
- "keywords": [
71
- "dotenv",
72
- "env",
73
- ".env",
74
- "environment",
75
- "variables",
76
- "config",
77
- "settings"
78
- ],
79
- "readmeFilename": "README.md",
80
- "license": "BSD-2-Clause",
81
- "devDependencies": {
82
- "@types/node": "^18.11.3",
83
- "decache": "^4.6.2",
84
- "sinon": "^14.0.1",
85
- "standard": "^17.0.0",
86
- "standard-version": "^9.5.0",
87
- "tap": "^19.2.0",
88
- "typescript": "^4.8.4"
89
- },
90
- "engines": { "node": ">=12" },
91
- "browser": { "fs": false }
92
- };
93
- }));
94
- //#endregion
95
- //#region node_modules/dotenv/lib/main.js
96
- var require_main = /* @__PURE__ */ __commonJSMin(((exports, module) => {
97
- const fs$1 = __require("fs");
98
- const path$1 = __require("path");
99
- const os$1 = __require("os");
100
- const crypto$1 = __require("crypto");
101
- const version = require_package().version;
102
- const TIPS = [
103
- "🔐 encrypt with Dotenvx: https://dotenvx.com",
104
- "🔐 prevent committing .env to code: https://dotenvx.com/precommit",
105
- "🔐 prevent building .env in docker: https://dotenvx.com/prebuild",
106
- "📡 add observability to secrets: https://dotenvx.com/ops",
107
- "👥 sync secrets across teammates & machines: https://dotenvx.com/ops",
108
- "🗂️ backup and recover secrets: https://dotenvx.com/ops",
109
- "✅ audit secrets and track compliance: https://dotenvx.com/ops",
110
- "🔄 add secrets lifecycle management: https://dotenvx.com/ops",
111
- "🔑 add access controls to secrets: https://dotenvx.com/ops",
112
- "🛠️ run anywhere with `dotenvx run -- yourcommand`",
113
- "⚙️ specify custom .env file path with { path: '/custom/path/.env' }",
114
- "⚙️ enable debug logging with { debug: true }",
115
- "⚙️ override existing env vars with { override: true }",
116
- "⚙️ suppress all logs with { quiet: true }",
117
- "⚙️ write to custom object with { processEnv: myObject }",
118
- "⚙️ load multiple .env files with { path: ['.env.local', '.env'] }"
119
- ];
120
- function _getRandomTip() {
121
- return TIPS[Math.floor(Math.random() * TIPS.length)];
122
- }
123
- function parseBoolean(value) {
124
- if (typeof value === "string") return ![
125
- "false",
126
- "0",
127
- "no",
128
- "off",
129
- ""
130
- ].includes(value.toLowerCase());
131
- return Boolean(value);
132
- }
133
- function supportsAnsi() {
134
- return process.stdout.isTTY;
135
- }
136
- function dim(text) {
137
- return supportsAnsi() ? `\x1b[2m${text}\x1b[0m` : text;
138
- }
139
- const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
140
- function parse(src) {
141
- const obj = {};
142
- let lines = src.toString();
143
- lines = lines.replace(/\r\n?/gm, "\n");
144
- let match;
145
- while ((match = LINE.exec(lines)) != null) {
146
- const key = match[1];
147
- let value = match[2] || "";
148
- value = value.trim();
149
- const maybeQuote = value[0];
150
- value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
151
- if (maybeQuote === "\"") {
152
- value = value.replace(/\\n/g, "\n");
153
- value = value.replace(/\\r/g, "\r");
154
- }
155
- obj[key] = value;
156
- }
157
- return obj;
28
+ //#region src/auth.ts
29
+ async function runAuth(options) {
30
+ if (options.verbose) {
31
+ consola.level = 5;
32
+ consola.info("Verbose logging enabled");
158
33
  }
159
- function _parseVault(options) {
160
- options = options || {};
161
- const vaultPath = _vaultPath(options);
162
- options.path = vaultPath;
163
- const result = DotenvModule.configDotenv(options);
164
- if (!result.parsed) {
165
- const err = /* @__PURE__ */ new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
166
- err.code = "MISSING_DATA";
167
- throw err;
168
- }
169
- const keys = _dotenvKey(options).split(",");
170
- const length = keys.length;
171
- let decrypted;
172
- for (let i = 0; i < length; i++) try {
173
- const attrs = _instructions(result, keys[i].trim());
174
- decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
175
- break;
176
- } catch (error) {
177
- if (i + 1 >= length) throw error;
34
+ state.showToken = options.showToken;
35
+ await ensurePaths();
36
+ await setupGitHubToken({ force: true });
37
+ consola.success("GitHub token written to", PATHS.GITHUB_TOKEN_PATH);
38
+ }
39
+ const auth = defineCommand({
40
+ meta: {
41
+ name: "auth",
42
+ description: "Run GitHub auth flow without running the server"
43
+ },
44
+ args: {
45
+ verbose: {
46
+ alias: "v",
47
+ type: "boolean",
48
+ default: false,
49
+ description: "Enable verbose logging"
50
+ },
51
+ "show-token": {
52
+ type: "boolean",
53
+ default: false,
54
+ description: "Show GitHub token on auth"
178
55
  }
179
- return DotenvModule.parse(decrypted);
180
- }
181
- function _warn(message) {
182
- console.error(`[dotenv@${version}][WARN] ${message}`);
183
- }
184
- function _debug(message) {
185
- console.log(`[dotenv@${version}][DEBUG] ${message}`);
186
- }
187
- function _log(message) {
188
- console.log(`[dotenv@${version}] ${message}`);
189
- }
190
- function _dotenvKey(options) {
191
- if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) return options.DOTENV_KEY;
192
- if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) return process.env.DOTENV_KEY;
193
- return "";
56
+ },
57
+ run({ args }) {
58
+ return runAuth({
59
+ verbose: args.verbose,
60
+ showToken: args["show-token"]
61
+ });
194
62
  }
195
- function _instructions(result, dotenvKey) {
196
- let uri;
63
+ });
64
+ //#endregion
65
+ //#region src/services/github/get-copilot-usage.ts
66
+ const getCopilotUsage = async () => {
67
+ const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, { headers: githubHeaders(state) });
68
+ if (!response.ok) throw new HTTPError("Failed to get Copilot usage", response);
69
+ return await response.json();
70
+ };
71
+ //#endregion
72
+ //#region src/check-usage.ts
73
+ const checkUsage = defineCommand({
74
+ meta: {
75
+ name: "check-usage",
76
+ description: "Show current GitHub Copilot usage/quota information"
77
+ },
78
+ async run() {
79
+ await ensurePaths();
80
+ await setupGitHubToken();
197
81
  try {
198
- uri = new URL(dotenvKey);
199
- } catch (error) {
200
- if (error.code === "ERR_INVALID_URL") {
201
- const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
202
- err.code = "INVALID_DOTENV_KEY";
203
- throw err;
82
+ const usage = await getCopilotUsage();
83
+ const premium = usage.quota_snapshots.premium_interactions;
84
+ const premiumTotal = premium.entitlement;
85
+ const premiumUsed = premiumTotal - premium.remaining;
86
+ const premiumPercentUsed = premiumTotal > 0 ? premiumUsed / premiumTotal * 100 : 0;
87
+ const premiumPercentRemaining = premium.percent_remaining;
88
+ function summarizeQuota(name, snap) {
89
+ if (!snap) return `${name}: N/A`;
90
+ const total = snap.entitlement;
91
+ const used = total - snap.remaining;
92
+ const percentUsed = total > 0 ? used / total * 100 : 0;
93
+ const percentRemaining = snap.percent_remaining;
94
+ return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
204
95
  }
205
- throw error;
206
- }
207
- const key = uri.password;
208
- if (!key) {
209
- const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing key part");
210
- err.code = "INVALID_DOTENV_KEY";
211
- throw err;
212
- }
213
- const environment = uri.searchParams.get("environment");
214
- if (!environment) {
215
- const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing environment part");
216
- err.code = "INVALID_DOTENV_KEY";
217
- throw err;
96
+ const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
97
+ const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
98
+ const completionsLine = summarizeQuota("Completions", usage.quota_snapshots.completions);
99
+ consola.box(`Copilot Usage (plan: ${usage.copilot_plan})\nQuota resets: ${usage.quota_reset_date}\n\nQuotas:\n ${premiumLine}\n ${chatLine}\n ${completionsLine}`);
100
+ } catch (err) {
101
+ consola.error("Failed to fetch Copilot usage:", err);
102
+ process.exit(1);
218
103
  }
219
- const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
220
- const ciphertext = result.parsed[environmentKey];
221
- if (!ciphertext) {
222
- const err = /* @__PURE__ */ new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
223
- err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
224
- throw err;
225
- }
226
- return {
227
- ciphertext,
228
- key
229
- };
230
- }
231
- function _vaultPath(options) {
232
- let possibleVaultPath = null;
233
- if (options && options.path && options.path.length > 0) if (Array.isArray(options.path)) {
234
- for (const filepath of options.path) if (fs$1.existsSync(filepath)) possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
235
- } else possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
236
- else possibleVaultPath = path$1.resolve(process.cwd(), ".env.vault");
237
- if (fs$1.existsSync(possibleVaultPath)) return possibleVaultPath;
238
- return null;
239
- }
240
- function _resolveHome(envPath) {
241
- return envPath[0] === "~" ? path$1.join(os$1.homedir(), envPath.slice(1)) : envPath;
242
- }
243
- function _configVault(options) {
244
- const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
245
- const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
246
- if (debug || !quiet) _log("Loading env from encrypted .env.vault");
247
- const parsed = DotenvModule._parseVault(options);
248
- let processEnv = process.env;
249
- if (options && options.processEnv != null) processEnv = options.processEnv;
250
- DotenvModule.populate(processEnv, parsed, options);
251
- return { parsed };
252
- }
253
- function configDotenv(options) {
254
- const dotenvPath = path$1.resolve(process.cwd(), ".env");
255
- let encoding = "utf8";
256
- let processEnv = process.env;
257
- if (options && options.processEnv != null) processEnv = options.processEnv;
258
- let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
259
- let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
260
- if (options && options.encoding) encoding = options.encoding;
261
- else if (debug) _debug("No encoding is specified. UTF-8 is used by default");
262
- let optionPaths = [dotenvPath];
263
- if (options && options.path) if (!Array.isArray(options.path)) optionPaths = [_resolveHome(options.path)];
264
- else {
265
- optionPaths = [];
266
- for (const filepath of options.path) optionPaths.push(_resolveHome(filepath));
267
- }
268
- let lastError;
269
- const parsedAll = {};
270
- for (const path of optionPaths) try {
271
- const parsed = DotenvModule.parse(fs$1.readFileSync(path, { encoding }));
272
- DotenvModule.populate(parsedAll, parsed, options);
273
- } catch (e) {
274
- if (debug) _debug(`Failed to load ${path} ${e.message}`);
275
- lastError = e;
276
- }
277
- const populated = DotenvModule.populate(processEnv, parsedAll, options);
278
- debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
279
- quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
280
- if (debug || !quiet) {
281
- const keysCount = Object.keys(populated).length;
282
- const shortPaths = [];
283
- for (const filePath of optionPaths) try {
284
- const relative = path$1.relative(process.cwd(), filePath);
285
- shortPaths.push(relative);
286
- } catch (e) {
287
- if (debug) _debug(`Failed to load ${filePath} ${e.message}`);
288
- lastError = e;
289
- }
290
- _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
291
- }
292
- if (lastError) return {
293
- parsed: parsedAll,
294
- error: lastError
295
- };
296
- else return { parsed: parsedAll };
297
- }
298
- function config(options) {
299
- if (_dotenvKey(options).length === 0) return DotenvModule.configDotenv(options);
300
- const vaultPath = _vaultPath(options);
301
- if (!vaultPath) {
302
- _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
303
- return DotenvModule.configDotenv(options);
304
- }
305
- return DotenvModule._configVault(options);
306
- }
307
- function decrypt(encrypted, keyStr) {
308
- const key = Buffer.from(keyStr.slice(-64), "hex");
309
- let ciphertext = Buffer.from(encrypted, "base64");
310
- const nonce = ciphertext.subarray(0, 12);
311
- const authTag = ciphertext.subarray(-16);
312
- ciphertext = ciphertext.subarray(12, -16);
313
- try {
314
- const aesgcm = crypto$1.createDecipheriv("aes-256-gcm", key, nonce);
315
- aesgcm.setAuthTag(authTag);
316
- return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
317
- } catch (error) {
318
- const isRange = error instanceof RangeError;
319
- const invalidKeyLength = error.message === "Invalid key length";
320
- const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
321
- if (isRange || invalidKeyLength) {
322
- const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
323
- err.code = "INVALID_DOTENV_KEY";
324
- throw err;
325
- } else if (decryptionFailed) {
326
- const err = /* @__PURE__ */ new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
327
- err.code = "DECRYPTION_FAILED";
328
- throw err;
329
- } else throw error;
330
- }
331
- }
332
- function populate(processEnv, parsed, options = {}) {
333
- const debug = Boolean(options && options.debug);
334
- const override = Boolean(options && options.override);
335
- const populated = {};
336
- if (typeof parsed !== "object") {
337
- const err = /* @__PURE__ */ new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
338
- err.code = "OBJECT_REQUIRED";
339
- throw err;
340
- }
341
- for (const key of Object.keys(parsed)) if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
342
- if (override === true) {
343
- processEnv[key] = parsed[key];
344
- populated[key] = parsed[key];
345
- }
346
- if (debug) if (override === true) _debug(`"${key}" is already defined and WAS overwritten`);
347
- else _debug(`"${key}" is already defined and was NOT overwritten`);
348
- } else {
349
- processEnv[key] = parsed[key];
350
- populated[key] = parsed[key];
351
- }
352
- return populated;
353
104
  }
354
- const DotenvModule = {
355
- configDotenv,
356
- _configVault,
357
- _parseVault,
358
- config,
359
- decrypt,
360
- parse,
361
- populate
362
- };
363
- module.exports.configDotenv = DotenvModule.configDotenv;
364
- module.exports._configVault = DotenvModule._configVault;
365
- module.exports._parseVault = DotenvModule._parseVault;
366
- module.exports.config = DotenvModule.config;
367
- module.exports.decrypt = DotenvModule.decrypt;
368
- module.exports.parse = DotenvModule.parse;
369
- module.exports.populate = DotenvModule.populate;
370
- module.exports = DotenvModule;
371
- }));
372
- //#endregion
373
- //#region node_modules/dotenv/lib/env-options.js
374
- var require_env_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
375
- const options = {};
376
- if (process.env.DOTENV_CONFIG_ENCODING != null) options.encoding = process.env.DOTENV_CONFIG_ENCODING;
377
- if (process.env.DOTENV_CONFIG_PATH != null) options.path = process.env.DOTENV_CONFIG_PATH;
378
- if (process.env.DOTENV_CONFIG_QUIET != null) options.quiet = process.env.DOTENV_CONFIG_QUIET;
379
- if (process.env.DOTENV_CONFIG_DEBUG != null) options.debug = process.env.DOTENV_CONFIG_DEBUG;
380
- if (process.env.DOTENV_CONFIG_OVERRIDE != null) options.override = process.env.DOTENV_CONFIG_OVERRIDE;
381
- if (process.env.DOTENV_CONFIG_DOTENV_KEY != null) options.DOTENV_KEY = process.env.DOTENV_CONFIG_DOTENV_KEY;
382
- module.exports = options;
383
- }));
384
- //#endregion
385
- //#region node_modules/dotenv/lib/cli-options.js
386
- var require_cli_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
387
- const re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/;
388
- module.exports = function optionMatcher(args) {
389
- const options = args.reduce(function(acc, cur) {
390
- const matches = cur.match(re);
391
- if (matches) acc[matches[1]] = matches[2];
392
- return acc;
393
- }, {});
394
- if (!("quiet" in options)) options.quiet = "true";
395
- return options;
396
- };
397
- }));
398
- //#endregion
399
- //#region node_modules/dotenv/config.js
400
- (function() {
401
- require_main().config(Object.assign({}, require_env_options(), require_cli_options()(process.argv)));
402
- })();
105
+ });
403
106
  //#endregion
404
107
  //#region src/lib/config.ts
405
108
  /**
@@ -481,296 +184,36 @@ async function applyProxyConfig() {
481
184
  return true;
482
185
  }
483
186
  //#endregion
484
- //#region src/lib/proxy.ts
485
- function initProxyFromEnv() {
486
- if (typeof Bun !== "undefined") return;
187
+ //#region src/debug.ts
188
+ async function getPackageVersion() {
487
189
  try {
488
- const direct = new Agent();
489
- const proxies = /* @__PURE__ */ new Map();
490
- setGlobalDispatcher({
491
- dispatch(options, handler) {
492
- try {
493
- const origin = typeof options.origin === "string" ? new URL(options.origin) : options.origin;
494
- const raw = getProxyForUrl(origin.toString());
495
- const proxyUrl = raw && raw.length > 0 ? raw : void 0;
496
- if (!proxyUrl) {
497
- consola.debug(`HTTP proxy bypass: ${origin.hostname}`);
498
- return direct.dispatch(options, handler);
499
- }
500
- let agent = proxies.get(proxyUrl);
501
- if (!agent) {
502
- agent = new ProxyAgent(proxyUrl);
503
- proxies.set(proxyUrl, agent);
504
- }
505
- let label = proxyUrl;
506
- try {
507
- const u = new URL(proxyUrl);
508
- label = `${u.protocol}//${u.host}`;
509
- } catch {}
510
- consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`);
511
- return agent.dispatch(options, handler);
512
- } catch {
513
- return direct.dispatch(options, handler);
514
- }
515
- },
516
- close() {
517
- return direct.close();
518
- },
519
- destroy() {
520
- return direct.destroy();
521
- }
522
- });
523
- consola.debug("HTTP proxy configured from environment (per-URL)");
524
- } catch (err) {
525
- consola.debug("Proxy setup skipped:", err);
526
- }
527
- }
528
- //#endregion
529
- //#region src/antigravity.ts
530
- /**
531
- * Add a new Antigravity account via OAuth
532
- */
533
- async function addAccount() {
534
- const { setupAntigravity, loadAntigravityAuth } = await import("./auth-DreFwlx2.js");
535
- const existingAuth = await loadAntigravityAuth();
536
- if (existingAuth && existingAuth.accounts.length > 0) {
537
- const enabledCount = existingAuth.accounts.filter((a) => a.enable).length;
538
- consola.info(`Found ${existingAuth.accounts.length} existing accounts (${enabledCount} enabled)`);
190
+ const packageJsonPath = new URL("../package.json", import.meta.url).pathname;
191
+ return JSON.parse(await fs.readFile(packageJsonPath)).version;
192
+ } catch {
193
+ return "unknown";
539
194
  }
540
- await setupAntigravity();
541
195
  }
542
- /**
543
- * List all Antigravity accounts
544
- */
545
- async function listAccounts() {
546
- const { loadAntigravityAuth } = await import("./auth-DreFwlx2.js");
547
- const auth = await loadAntigravityAuth();
548
- if (!auth || auth.accounts.length === 0) {
549
- consola.info("No Antigravity accounts configured");
550
- return;
551
- }
552
- consola.info(`\nAntigravity Accounts (${auth.accounts.length} total):`);
553
- consola.info("=".repeat(50));
554
- for (let i = 0; i < auth.accounts.length; i++) {
555
- const account = auth.accounts[i];
556
- const isCurrent = i === auth.currentIndex;
557
- const status = account.enable ? "enabled" : "disabled";
558
- const marker = isCurrent ? "→ " : " ";
559
- const projectId = account.project_id || "unknown";
560
- consola.info(`${marker}[${i}] Project: ${projectId} | Status: ${status}${isCurrent ? " (current)" : ""}`);
561
- }
196
+ function getRuntimeInfo() {
197
+ const isBun = typeof Bun !== "undefined";
198
+ return {
199
+ name: isBun ? "bun" : "node",
200
+ version: isBun ? Bun.version : process.version.slice(1),
201
+ platform: os.platform(),
202
+ arch: os.arch()
203
+ };
562
204
  }
563
- /**
564
- * Remove an Antigravity account by index
565
- */
566
- async function removeAccount(index) {
567
- const { loadAntigravityAuth, saveAntigravityAuth } = await import("./auth-DreFwlx2.js");
568
- const auth = await loadAntigravityAuth();
569
- if (!auth || auth.accounts.length === 0) {
570
- consola.error("No Antigravity accounts configured");
571
- return;
572
- }
573
- if (index < 0 || index >= auth.accounts.length) {
574
- consola.error(`Invalid index. Must be between 0 and ${auth.accounts.length - 1}`);
575
- return;
576
- }
577
- const removed = auth.accounts.splice(index, 1)[0];
578
- if (auth.currentIndex >= auth.accounts.length) auth.currentIndex = Math.max(0, auth.accounts.length - 1);
579
- await saveAntigravityAuth(auth);
580
- consola.success(`Removed account ${index} (Project: ${removed.project_id || "unknown"})`);
581
- }
582
- /**
583
- * Clear all Antigravity accounts
584
- */
585
- async function clearAccounts() {
586
- const { clearAntigravityAuth } = await import("./auth-DreFwlx2.js");
587
- if (await consola.prompt("Are you sure you want to remove all Antigravity accounts?", {
588
- type: "confirm",
589
- initial: false
590
- })) await clearAntigravityAuth();
591
- }
592
- const antigravity = defineCommand({
593
- meta: {
594
- name: "antigravity",
595
- description: "Manage Google Antigravity accounts"
596
- },
597
- subCommands: {
598
- add: defineCommand({
599
- meta: {
600
- name: "add",
601
- description: "Add a new Antigravity account via OAuth"
602
- },
603
- async run() {
604
- await ensurePaths();
605
- if (await applyProxyConfig()) initProxyFromEnv();
606
- await addAccount();
607
- }
608
- }),
609
- list: defineCommand({
610
- meta: {
611
- name: "list",
612
- description: "List all Antigravity accounts"
613
- },
614
- async run() {
615
- await ensurePaths();
616
- await listAccounts();
617
- }
618
- }),
619
- remove: defineCommand({
620
- meta: {
621
- name: "remove",
622
- description: "Remove an Antigravity account by index"
623
- },
624
- args: { index: {
625
- type: "positional",
626
- description: "Account index to remove (use 'list' to see indexes)",
627
- required: true
628
- } },
629
- async run({ args }) {
630
- await ensurePaths();
631
- const indexStr = String(args.index);
632
- const index = Number.parseInt(indexStr, 10);
633
- if (Number.isNaN(index)) {
634
- consola.error("Index must be a number");
635
- return;
636
- }
637
- await removeAccount(index);
638
- }
639
- }),
640
- clear: defineCommand({
641
- meta: {
642
- name: "clear",
643
- description: "Remove all Antigravity accounts"
644
- },
645
- async run() {
646
- await ensurePaths();
647
- await clearAccounts();
648
- }
649
- })
650
- }
651
- });
652
- //#endregion
653
- //#region src/auth.ts
654
- async function runAuth(options) {
655
- if (options.verbose) {
656
- consola.level = 5;
657
- consola.info("Verbose logging enabled");
658
- }
659
- state.showToken = options.showToken;
660
- await ensurePaths();
661
- await setupGitHubToken({ force: true });
662
- consola.success("GitHub token written to", PATHS.GITHUB_TOKEN_PATH);
663
- }
664
- const auth = defineCommand({
665
- meta: {
666
- name: "auth",
667
- description: "Run GitHub auth flow without running the server"
668
- },
669
- args: {
670
- verbose: {
671
- alias: "v",
672
- type: "boolean",
673
- default: false,
674
- description: "Enable verbose logging"
675
- },
676
- "show-token": {
677
- type: "boolean",
678
- default: false,
679
- description: "Show GitHub token on auth"
680
- }
681
- },
682
- run({ args }) {
683
- return runAuth({
684
- verbose: args.verbose,
685
- showToken: args["show-token"]
686
- });
687
- }
688
- });
689
- //#endregion
690
- //#region src/services/github/get-copilot-usage.ts
691
- const getCopilotUsage = async () => {
692
- const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, { headers: githubHeaders(state) });
693
- if (!response.ok) throw new HTTPError("Failed to get Copilot usage", response);
694
- return await response.json();
695
- };
696
- //#endregion
697
- //#region src/check-usage.ts
698
- const checkUsage = defineCommand({
699
- meta: {
700
- name: "check-usage",
701
- description: "Show current GitHub Copilot usage/quota information"
702
- },
703
- async run() {
704
- await ensurePaths();
705
- await setupGitHubToken();
706
- try {
707
- const usage = await getCopilotUsage();
708
- const premium = usage.quota_snapshots.premium_interactions;
709
- const premiumTotal = premium.entitlement;
710
- const premiumUsed = premiumTotal - premium.remaining;
711
- const premiumPercentUsed = premiumTotal > 0 ? premiumUsed / premiumTotal * 100 : 0;
712
- const premiumPercentRemaining = premium.percent_remaining;
713
- function summarizeQuota(name, snap) {
714
- if (!snap) return `${name}: N/A`;
715
- const total = snap.entitlement;
716
- const used = total - snap.remaining;
717
- const percentUsed = total > 0 ? used / total * 100 : 0;
718
- const percentRemaining = snap.percent_remaining;
719
- return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
720
- }
721
- const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
722
- const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
723
- const completionsLine = summarizeQuota("Completions", usage.quota_snapshots.completions);
724
- consola.box(`Copilot Usage (plan: ${usage.copilot_plan})\nQuota resets: ${usage.quota_reset_date}\n\nQuotas:\n ${premiumLine}\n ${chatLine}\n ${completionsLine}`);
725
- } catch (err) {
726
- consola.error("Failed to fetch Copilot usage:", err);
727
- process.exit(1);
728
- }
729
- }
730
- });
731
- //#endregion
732
- //#region src/debug.ts
733
- async function getPackageVersion() {
734
- try {
735
- const packageJsonPath = new URL("../package.json", import.meta.url).pathname;
736
- return JSON.parse(await fs.readFile(packageJsonPath)).version;
737
- } catch {
738
- return "unknown";
739
- }
740
- }
741
- function getRuntimeInfo() {
742
- const isBun = typeof Bun !== "undefined";
743
- return {
744
- name: isBun ? "bun" : "node",
745
- version: isBun ? Bun.version : process.version.slice(1),
746
- platform: os.platform(),
747
- arch: os.arch()
748
- };
749
- }
750
- async function checkTokenExists() {
751
- try {
752
- if (!(await fs.stat(PATHS.GITHUB_TOKEN_PATH)).isFile()) return false;
753
- return (await fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8")).trim().length > 0;
754
- } catch {
755
- return false;
756
- }
757
- }
758
- async function checkFileExists(path) {
759
- try {
760
- if (!(await fs.stat(path)).isFile()) return false;
761
- return (await fs.readFile(path, "utf8")).trim().length > 0;
762
- } catch {
763
- return false;
205
+ async function checkTokenExists() {
206
+ try {
207
+ if (!(await fs.stat(PATHS.GITHUB_TOKEN_PATH)).isFile()) return false;
208
+ return (await fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8")).trim().length > 0;
209
+ } catch {
210
+ return false;
764
211
  }
765
212
  }
766
213
  async function getDebugInfo() {
767
- const zenAuthPath = getZenAuthPath();
768
- const antigravityAuthPath = getAntigravityAuthPath();
769
- const [version, githubExists, zenExists, antigravityExists, proxyConfig] = await Promise.all([
214
+ const [version, githubExists, proxyConfig] = await Promise.all([
770
215
  getPackageVersion(),
771
216
  checkTokenExists(),
772
- checkFileExists(zenAuthPath),
773
- checkFileExists(antigravityAuthPath),
774
217
  getProxyConfig()
775
218
  ]);
776
219
  return {
@@ -778,15 +221,9 @@ async function getDebugInfo() {
778
221
  runtime: getRuntimeInfo(),
779
222
  paths: {
780
223
  APP_DIR: PATHS.APP_DIR,
781
- GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,
782
- ZEN_AUTH_PATH: zenAuthPath,
783
- ANTIGRAVITY_AUTH_PATH: antigravityAuthPath
784
- },
785
- credentials: {
786
- github: githubExists,
787
- zen: zenExists,
788
- antigravity: antigravityExists
224
+ GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH
789
225
  },
226
+ credentials: { github: githubExists },
790
227
  proxy: proxyConfig
791
228
  };
792
229
  }
@@ -801,13 +238,9 @@ Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform}
801
238
  Paths:
802
239
  APP_DIR: ${info.paths.APP_DIR}
803
240
  GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}
804
- ZEN_AUTH_PATH: ${info.paths.ZEN_AUTH_PATH}
805
- ANTIGRAVITY_AUTH_PATH: ${info.paths.ANTIGRAVITY_AUTH_PATH}
806
241
 
807
242
  Credentials:
808
243
  GitHub Copilot: ${info.credentials.github ? "✅ Configured" : "❌ Not configured"}
809
- OpenCode Zen: ${info.credentials.zen ? "✅ Configured" : "❌ Not configured"}
810
- Google Antigravity: ${info.credentials.antigravity ? "✅ Configured" : "❌ Not configured"}
811
244
 
812
245
  Proxy: ${proxyStatus}`);
813
246
  }
@@ -837,65 +270,15 @@ const debug = defineCommand({
837
270
  //#region src/logout.ts
838
271
  async function runLogout(options) {
839
272
  await ensurePaths();
840
- if (options.all) {
841
- await clearGithubToken();
842
- await clearZenAuth();
843
- await clearAntigravityAuth();
844
- consola.success("Logged out from all services");
845
- consola.info(`GitHub token: ${PATHS.GITHUB_TOKEN_PATH}`);
846
- consola.info(`Zen API key: ${getZenAuthPath()}`);
847
- consola.info(`Antigravity accounts: ${getAntigravityAuthPath()}`);
848
- return;
849
- }
850
- if (options.github) {
273
+ if (options.all || options.github) {
851
274
  await clearGithubToken();
852
275
  consola.success("Logged out from GitHub Copilot");
853
276
  consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
854
277
  return;
855
278
  }
856
- if (options.zen) {
857
- await clearZenAuth();
858
- consola.success("Logged out from OpenCode Zen");
859
- consola.info(`Zen API key location: ${getZenAuthPath()}`);
860
- return;
861
- }
862
- if (options.antigravity) {
863
- await clearAntigravityAuth();
864
- consola.success("Logged out from Google Antigravity");
865
- consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
866
- return;
867
- }
868
- switch (await consola.prompt("Which credentials do you want to clear?", {
869
- type: "select",
870
- options: [
871
- "GitHub Copilot token",
872
- "OpenCode Zen API key",
873
- "Google Antigravity accounts",
874
- "All credentials"
875
- ]
876
- })) {
877
- case "GitHub Copilot token":
878
- await clearGithubToken();
879
- consola.success("Logged out from GitHub Copilot");
880
- consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
881
- break;
882
- case "OpenCode Zen API key":
883
- await clearZenAuth();
884
- consola.success("Logged out from OpenCode Zen");
885
- consola.info(`Zen API key location: ${getZenAuthPath()}`);
886
- break;
887
- case "Google Antigravity accounts":
888
- await clearAntigravityAuth();
889
- consola.success("Logged out from Google Antigravity");
890
- consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
891
- break;
892
- case "All credentials":
893
- await clearGithubToken();
894
- await clearZenAuth();
895
- await clearAntigravityAuth();
896
- consola.success("Logged out from all services");
897
- break;
898
- }
279
+ await clearGithubToken();
280
+ consola.success("Logged out from GitHub Copilot");
281
+ consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
899
282
  }
900
283
  const logout = defineCommand({
901
284
  meta: {
@@ -907,31 +290,18 @@ const logout = defineCommand({
907
290
  alias: "g",
908
291
  type: "boolean",
909
292
  default: false,
910
- description: "Clear only GitHub Copilot token"
911
- },
912
- zen: {
913
- alias: "z",
914
- type: "boolean",
915
- default: false,
916
- description: "Clear only OpenCode Zen API key"
917
- },
918
- antigravity: {
919
- type: "boolean",
920
- default: false,
921
- description: "Clear only Google Antigravity accounts"
293
+ description: "Clear GitHub Copilot token"
922
294
  },
923
295
  all: {
924
296
  alias: "a",
925
297
  type: "boolean",
926
298
  default: false,
927
- description: "Clear all credentials (GitHub, Zen, and Antigravity)"
299
+ description: "Clear all credentials"
928
300
  }
929
301
  },
930
302
  run({ args }) {
931
303
  return runLogout({
932
304
  github: args.github,
933
- zen: args.zen,
934
- antigravity: args.antigravity,
935
305
  all: args.all
936
306
  });
937
307
  }
@@ -1095,1473 +465,559 @@ const proxy = defineCommand({
1095
465
  }
1096
466
  });
1097
467
  //#endregion
1098
- //#region src/lib/shell.ts
1099
- function getShell() {
1100
- const { platform, ppid, env } = process$1;
1101
- if (platform === "win32") {
1102
- try {
1103
- if (execSync(`wmic process get ParentProcessId,Name | findstr "${ppid}"`, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
1104
- } catch {
1105
- return "cmd";
1106
- }
1107
- return "cmd";
1108
- } else {
1109
- const shellPath = env.SHELL;
1110
- if (shellPath) {
1111
- if (shellPath.endsWith("zsh")) return "zsh";
1112
- if (shellPath.endsWith("fish")) return "fish";
1113
- if (shellPath.endsWith("bash")) return "bash";
1114
- }
1115
- return "sh";
1116
- }
1117
- }
1118
- /**
1119
- * Generates a copy-pasteable script to set multiple environment variables
1120
- * and run a subsequent command.
1121
- * @param {EnvVars} envVars - An object of environment variables to set.
1122
- * @param {string} commandToRun - The command to run after setting the variables.
1123
- * @returns {string} The formatted script string.
1124
- */
1125
- function generateEnvScript(envVars, commandToRun = "") {
1126
- const shell = getShell();
1127
- const filteredEnvVars = Object.entries(envVars).filter(([, value]) => value !== void 0);
1128
- let commandBlock;
1129
- switch (shell) {
1130
- case "powershell":
1131
- commandBlock = filteredEnvVars.map(([key, value]) => `$env:${key} = ${value}`).join("; ");
1132
- break;
1133
- case "cmd":
1134
- commandBlock = filteredEnvVars.map(([key, value]) => `set ${key}=${value}`).join(" & ");
1135
- break;
1136
- case "fish":
1137
- commandBlock = filteredEnvVars.map(([key, value]) => `set -gx ${key} ${value}`).join("; ");
1138
- break;
1139
- default: {
1140
- const assignments = filteredEnvVars.map(([key, value]) => `${key}=${value}`).join(" ");
1141
- commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : "";
1142
- break;
1143
- }
1144
- }
1145
- if (commandBlock && commandToRun) return `${commandBlock}${shell === "cmd" ? " & " : " && "}${commandToRun}`;
1146
- return commandBlock || commandToRun;
1147
- }
1148
- //#endregion
1149
- //#region src/lib/api-key-auth.ts
1150
- /**
1151
- * Retrieve an API key from the incoming request.
1152
- *
1153
- * Checks common locations where clients supply keys (Authorization Bearer header, `x-api-key` header, or `apiKey` query parameter) and returns the first one found.
1154
- *
1155
- * @returns The extracted API key, or `undefined` if no key is present.
1156
- */
1157
- function extractApiKey(c) {
1158
- const authHeader = c.req.header("authorization");
1159
- if (authHeader?.startsWith("Bearer ")) return authHeader.slice(7);
1160
- const anthropicKey = c.req.header("x-api-key");
1161
- if (anthropicKey) return anthropicKey;
1162
- const queryKey = c.req.query("apiKey");
1163
- if (queryKey) return queryKey;
1164
- }
1165
- /**
1166
- * API key authentication middleware
1167
- * Validates that the request contains a valid API key if API keys are configured
1168
- */
1169
- const apiKeyAuthMiddleware = async (c, next) => {
1170
- if (!state.apiKeys || state.apiKeys.length === 0) {
1171
- await next();
1172
- return;
1173
- }
1174
- const providedKey = extractApiKey(c);
1175
- if (!providedKey) throw new HTTPException(401, { message: "API key required. Please provide a valid API key in the Authorization header (Bearer token) or x-api-key header." });
1176
- if (!state.apiKeys.includes(providedKey)) throw new HTTPException(401, { message: "Invalid API key. Please provide a valid API key." });
1177
- await next();
1178
- };
1179
- //#endregion
1180
- //#region src/lib/model-logger.ts
1181
- /**
1182
- * Get timestamp string in format HH:mm:ss
1183
- */
1184
- function getTime() {
1185
- return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
1186
- }
1187
- /**
1188
- * Format duration in human readable format
1189
- */
1190
- function formatDuration(ms) {
1191
- if (ms < 1e3) return `${ms}ms`;
1192
- return `${(ms / 1e3).toFixed(1)}s`;
1193
- }
1194
- /**
1195
- * Extract model name from request body
1196
- */
1197
- async function extractModel(c) {
1198
- try {
1199
- return (await c.req.raw.clone().json()).model;
1200
- } catch {
1201
- return;
1202
- }
1203
- }
1204
- /**
1205
- * Custom logger middleware that shows model name before timestamp
1206
- *
1207
- * Output format:
1208
- * [model] HH:mm:ss <-- METHOD /path
1209
- * [model] HH:mm:ss --> METHOD /path STATUS DURATION
1210
- */
1211
- function modelLogger() {
1212
- return async (c, next) => {
1213
- const method = c.req.method;
1214
- const fullPath = `${c.req.path}${c.req.raw.url.includes("?") ? `?${c.req.raw.url.split("?")[1]}` : ""}`;
1215
- let model;
1216
- if (method === "POST" && c.req.header("content-type")?.includes("json")) model = await extractModel(c);
1217
- const modelPrefix = model ? `[${model}] ` : "";
1218
- const startTime = getTime();
1219
- console.log(`${modelPrefix}${startTime} <-- ${method} ${fullPath}`);
1220
- const start = Date.now();
1221
- await next();
1222
- const duration = Date.now() - start;
1223
- const endTime = getTime();
1224
- console.log(`${modelPrefix}${endTime} --> ${method} ${fullPath} ${c.res.status} ${formatDuration(duration)}`);
468
+ //#region node_modules/dotenv/package.json
469
+ var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
470
+ module.exports = {
471
+ "name": "dotenv",
472
+ "version": "17.2.3",
473
+ "description": "Loads environment variables from .env file",
474
+ "main": "lib/main.js",
475
+ "types": "lib/main.d.ts",
476
+ "exports": {
477
+ ".": {
478
+ "types": "./lib/main.d.ts",
479
+ "require": "./lib/main.js",
480
+ "default": "./lib/main.js"
481
+ },
482
+ "./config": "./config.js",
483
+ "./config.js": "./config.js",
484
+ "./lib/env-options": "./lib/env-options.js",
485
+ "./lib/env-options.js": "./lib/env-options.js",
486
+ "./lib/cli-options": "./lib/cli-options.js",
487
+ "./lib/cli-options.js": "./lib/cli-options.js",
488
+ "./package.json": "./package.json"
489
+ },
490
+ "scripts": {
491
+ "dts-check": "tsc --project tests/types/tsconfig.json",
492
+ "lint": "standard",
493
+ "pretest": "npm run lint && npm run dts-check",
494
+ "test": "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
495
+ "test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
496
+ "prerelease": "npm test",
497
+ "release": "standard-version"
498
+ },
499
+ "repository": {
500
+ "type": "git",
501
+ "url": "git://github.com/motdotla/dotenv.git"
502
+ },
503
+ "homepage": "https://github.com/motdotla/dotenv#readme",
504
+ "funding": "https://dotenvx.com",
505
+ "keywords": [
506
+ "dotenv",
507
+ "env",
508
+ ".env",
509
+ "environment",
510
+ "variables",
511
+ "config",
512
+ "settings"
513
+ ],
514
+ "readmeFilename": "README.md",
515
+ "license": "BSD-2-Clause",
516
+ "devDependencies": {
517
+ "@types/node": "^18.11.3",
518
+ "decache": "^4.6.2",
519
+ "sinon": "^14.0.1",
520
+ "standard": "^17.0.0",
521
+ "standard-version": "^9.5.0",
522
+ "tap": "^19.2.0",
523
+ "typescript": "^4.8.4"
524
+ },
525
+ "engines": { "node": ">=12" },
526
+ "browser": { "fs": false }
1225
527
  };
1226
- }
528
+ }));
1227
529
  //#endregion
1228
- //#region src/services/antigravity/stream-parser.ts
1229
- /**
1230
- * Create initial stream state
1231
- */
1232
- function createStreamState() {
1233
- return {
1234
- buffer: "",
1235
- inputTokens: 0,
1236
- outputTokens: 0,
1237
- contentBlockIndex: 0,
1238
- thinkingBlockStarted: false,
1239
- textBlockStarted: false
1240
- };
1241
- }
1242
- /**
1243
- * Parse a single SSE line and return the JSON data if valid
1244
- */
1245
- function parseSSELine(line) {
1246
- if (!line.startsWith("data: ")) return null;
1247
- const data = line.slice(6).trim();
1248
- if (data === "[DONE]" || data === "") return null;
1249
- try {
1250
- return JSON.parse(data);
1251
- } catch {
1252
- return null;
1253
- }
1254
- }
1255
- /**
1256
- * Extract candidates and usage from parsed data
1257
- */
1258
- function extractFromData(data) {
1259
- return {
1260
- candidates: data.response?.candidates || data.candidates || [],
1261
- usage: data.response?.usageMetadata || data.usageMetadata
1262
- };
1263
- }
1264
- /**
1265
- * Process a single part and emit events
1266
- */
1267
- function processPart(part, state, emit) {
1268
- if (part.thought && part.text) {
1269
- processThinkingPart(part.text, state, emit);
1270
- return;
1271
- }
1272
- if (part.text && !part.thought) {
1273
- processTextPart(part.text, state, emit);
1274
- return;
1275
- }
1276
- if (part.functionCall) processToolPart(part.functionCall, state, emit);
1277
- }
1278
- /**
1279
- * Process thinking content
1280
- */
1281
- function processThinkingPart(text, state, emit) {
1282
- if (!state.thinkingBlockStarted) {
1283
- emit({
1284
- type: "thinking_start",
1285
- index: state.contentBlockIndex
1286
- });
1287
- state.thinkingBlockStarted = true;
1288
- }
1289
- emit({
1290
- type: "thinking_delta",
1291
- index: state.contentBlockIndex,
1292
- text
1293
- });
1294
- }
1295
- /**
1296
- * Process text content
1297
- */
1298
- function processTextPart(text, state, emit) {
1299
- if (state.thinkingBlockStarted && !state.textBlockStarted) {
1300
- emit({
1301
- type: "thinking_stop",
1302
- index: state.contentBlockIndex
1303
- });
1304
- state.contentBlockIndex++;
1305
- state.thinkingBlockStarted = false;
530
+ //#region node_modules/dotenv/lib/main.js
531
+ var require_main = /* @__PURE__ */ __commonJSMin(((exports, module) => {
532
+ const fs$1 = __require("fs");
533
+ const path$1 = __require("path");
534
+ const os$1 = __require("os");
535
+ const crypto = __require("crypto");
536
+ const version = require_package().version;
537
+ const TIPS = [
538
+ "🔐 encrypt with Dotenvx: https://dotenvx.com",
539
+ "🔐 prevent committing .env to code: https://dotenvx.com/precommit",
540
+ "🔐 prevent building .env in docker: https://dotenvx.com/prebuild",
541
+ "📡 add observability to secrets: https://dotenvx.com/ops",
542
+ "👥 sync secrets across teammates & machines: https://dotenvx.com/ops",
543
+ "🗂️ backup and recover secrets: https://dotenvx.com/ops",
544
+ "✅ audit secrets and track compliance: https://dotenvx.com/ops",
545
+ "🔄 add secrets lifecycle management: https://dotenvx.com/ops",
546
+ "🔑 add access controls to secrets: https://dotenvx.com/ops",
547
+ "🛠️ run anywhere with `dotenvx run -- yourcommand`",
548
+ "⚙️ specify custom .env file path with { path: '/custom/path/.env' }",
549
+ "⚙️ enable debug logging with { debug: true }",
550
+ "⚙️ override existing env vars with { override: true }",
551
+ "⚙️ suppress all logs with { quiet: true }",
552
+ "⚙️ write to custom object with { processEnv: myObject }",
553
+ "⚙️ load multiple .env files with { path: ['.env.local', '.env'] }"
554
+ ];
555
+ function _getRandomTip() {
556
+ return TIPS[Math.floor(Math.random() * TIPS.length)];
1306
557
  }
1307
- if (!state.textBlockStarted) {
1308
- emit({
1309
- type: "text_start",
1310
- index: state.contentBlockIndex
1311
- });
1312
- state.textBlockStarted = true;
558
+ function parseBoolean(value) {
559
+ if (typeof value === "string") return ![
560
+ "false",
561
+ "0",
562
+ "no",
563
+ "off",
564
+ ""
565
+ ].includes(value.toLowerCase());
566
+ return Boolean(value);
1313
567
  }
1314
- emit({
1315
- type: "text_delta",
1316
- index: state.contentBlockIndex,
1317
- text
1318
- });
1319
- }
1320
- /**
1321
- * Process tool/function call
1322
- */
1323
- function processToolPart(functionCall, state, emit) {
1324
- if (state.textBlockStarted) {
1325
- emit({
1326
- type: "text_stop",
1327
- index: state.contentBlockIndex
1328
- });
1329
- state.contentBlockIndex++;
1330
- state.textBlockStarted = false;
1331
- } else if (state.thinkingBlockStarted) {
1332
- emit({
1333
- type: "thinking_stop",
1334
- index: state.contentBlockIndex
1335
- });
1336
- state.contentBlockIndex++;
1337
- state.thinkingBlockStarted = false;
568
+ function supportsAnsi() {
569
+ return process.stdout.isTTY;
1338
570
  }
1339
- emit({
1340
- type: "tool_use",
1341
- index: state.contentBlockIndex,
1342
- name: functionCall.name,
1343
- args: functionCall.args
1344
- });
1345
- state.contentBlockIndex++;
1346
- }
1347
- /**
1348
- * Handle finish reason and close open blocks
1349
- */
1350
- function handleFinish(state, emit) {
1351
- if (state.textBlockStarted) {
1352
- emit({
1353
- type: "text_stop",
1354
- index: state.contentBlockIndex
1355
- });
1356
- state.textBlockStarted = false;
1357
- } else if (state.thinkingBlockStarted) {
1358
- emit({
1359
- type: "thinking_stop",
1360
- index: state.contentBlockIndex
1361
- });
1362
- state.thinkingBlockStarted = false;
571
+ function dim(text) {
572
+ return supportsAnsi() ? `\x1b[2m${text}\x1b[0m` : text;
1363
573
  }
1364
- emit({
1365
- type: "usage",
1366
- inputTokens: state.inputTokens,
1367
- outputTokens: state.outputTokens
1368
- });
1369
- emit({
1370
- type: "finish",
1371
- stopReason: "end_turn"
1372
- });
1373
- }
1374
- /**
1375
- * Process chunk and update buffer, returning complete lines
1376
- */
1377
- function processChunk(chunk, state) {
1378
- state.buffer += chunk;
1379
- const lines = state.buffer.split("\n");
1380
- state.buffer = lines.pop() || "";
1381
- return lines;
1382
- }
1383
- //#endregion
1384
- //#region src/services/antigravity/create-chat-completions.ts
1385
- /**
1386
- * Google Antigravity Chat Completions
1387
- *
1388
- * Proxy chat completion requests to Google Antigravity API or standard Gemini API.
1389
- * Supports two authentication methods:
1390
- * - API Key: Uses standard Gemini API (generativelanguage.googleapis.com)
1391
- * - OAuth: Uses Antigravity private API (daily-cloudcode-pa.sandbox.googleapis.com)
1392
- *
1393
- * Based on: https://github.com/liuw1535/antigravity2api-nodejs
1394
- */
1395
- const ANTIGRAVITY_API_HOST = "daily-cloudcode-pa.sandbox.googleapis.com";
1396
- const ANTIGRAVITY_STREAM_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:streamGenerateContent?alt=sse`;
1397
- const ANTIGRAVITY_NO_STREAM_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:generateContent`;
1398
- const ANTIGRAVITY_USER_AGENT$1 = "antigravity/1.11.3 windows/amd64";
1399
- const GEMINI_API_HOST = "generativelanguage.googleapis.com";
1400
- const getGeminiStreamUrl = (model, apiKey) => `https://${GEMINI_API_HOST}/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${apiKey}`;
1401
- const getGeminiNoStreamUrl = (model, apiKey) => `https://${GEMINI_API_HOST}/v1beta/models/${model}:generateContent?key=${apiKey}`;
1402
- /**
1403
- * Convert OpenAI format messages to Antigravity format
1404
- */
1405
- function convertMessages$1(messages) {
1406
- const contents = [];
1407
- let systemInstruction;
1408
- for (const message of messages) {
1409
- if (message.role === "system") {
1410
- systemInstruction = buildSystemInstruction(message.content);
1411
- continue;
574
+ const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
575
+ function parse(src) {
576
+ const obj = {};
577
+ let lines = src.toString();
578
+ lines = lines.replace(/\r\n?/gm, "\n");
579
+ let match;
580
+ while ((match = LINE.exec(lines)) != null) {
581
+ const key = match[1];
582
+ let value = match[2] || "";
583
+ value = value.trim();
584
+ const maybeQuote = value[0];
585
+ value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
586
+ if (maybeQuote === "\"") {
587
+ value = value.replace(/\\n/g, "\n");
588
+ value = value.replace(/\\r/g, "\r");
589
+ }
590
+ obj[key] = value;
1412
591
  }
1413
- const role = message.role === "assistant" ? "model" : "user";
1414
- const parts = buildMessageParts(message.content);
1415
- contents.push({
1416
- role,
1417
- parts
1418
- });
1419
- }
1420
- return {
1421
- contents,
1422
- systemInstruction
1423
- };
1424
- }
1425
- /**
1426
- * Build system instruction from content
1427
- */
1428
- function buildSystemInstruction(content) {
1429
- return { parts: [{ text: typeof content === "string" ? content : content.map((c) => c.text || "").join("") }] };
1430
- }
1431
- /**
1432
- * Build message parts from content
1433
- */
1434
- function buildMessageParts(content) {
1435
- if (typeof content === "string") return [{ text: content }];
1436
- const parts = [];
1437
- for (const part of content) if (part.type === "text") parts.push({ text: part.text });
1438
- else if (part.type === "image_url" && part.image_url?.url) {
1439
- const imageData = parseBase64Image(part.image_url.url);
1440
- if (imageData) parts.push({ inlineData: imageData });
592
+ return obj;
1441
593
  }
1442
- return parts;
1443
- }
1444
- /**
1445
- * Parse base64 image URL
1446
- */
1447
- function parseBase64Image(url) {
1448
- if (!url.startsWith("data:")) return null;
1449
- const match = url.match(/^data:([^;]+);base64,(.+)$/);
1450
- if (!match) return null;
1451
- return {
1452
- mimeType: match[1],
1453
- data: match[2]
1454
- };
1455
- }
1456
- const GEMINI_ALLOWED_FIELDS$1 = new Set([
1457
- "type",
1458
- "description",
1459
- "properties",
1460
- "required",
1461
- "items",
1462
- "enum",
1463
- "nullable"
1464
- ]);
1465
- /**
1466
- * Convert type value to Gemini format
1467
- * Handles both string and array types (for nullable)
1468
- */
1469
- function convertTypeValue$1(value) {
1470
- if (typeof value === "string") return { type: value.toUpperCase() };
1471
- if (Array.isArray(value)) {
1472
- const nonNullType = value.find((t) => typeof t === "string" && t !== "null");
1473
- if (nonNullType) return {
1474
- type: nonNullType.toUpperCase(),
1475
- nullable: true
1476
- };
594
+ function _parseVault(options) {
595
+ options = options || {};
596
+ const vaultPath = _vaultPath(options);
597
+ options.path = vaultPath;
598
+ const result = DotenvModule.configDotenv(options);
599
+ if (!result.parsed) {
600
+ const err = /* @__PURE__ */ new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
601
+ err.code = "MISSING_DATA";
602
+ throw err;
603
+ }
604
+ const keys = _dotenvKey(options).split(",");
605
+ const length = keys.length;
606
+ let decrypted;
607
+ for (let i = 0; i < length; i++) try {
608
+ const attrs = _instructions(result, keys[i].trim());
609
+ decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
610
+ break;
611
+ } catch (error) {
612
+ if (i + 1 >= length) throw error;
613
+ }
614
+ return DotenvModule.parse(decrypted);
1477
615
  }
1478
- return null;
1479
- }
1480
- /**
1481
- * Clean properties object recursively
1482
- */
1483
- function cleanProperties$1(props) {
1484
- const cleanedProps = {};
1485
- for (const [propKey, propValue] of Object.entries(props)) cleanedProps[propKey] = cleanJsonSchema$1(propValue);
1486
- return cleanedProps;
1487
- }
1488
- /**
1489
- * Clean and convert JSON schema to Gemini format
1490
- * - Removes unsupported fields like $schema, additionalProperties
1491
- * - Converts type values to uppercase (string -> STRING)
1492
- * - Ensures properties format is correct for Google API
1493
- */
1494
- function cleanJsonSchema$1(schema) {
1495
- if (!schema || typeof schema !== "object") return schema;
1496
- if (Array.isArray(schema)) return schema.map((item) => cleanJsonSchema$1(item));
1497
- const obj = schema;
1498
- const cleaned = {};
1499
- for (const [key, value] of Object.entries(obj)) {
1500
- if (!GEMINI_ALLOWED_FIELDS$1.has(key)) continue;
1501
- if (key === "type") {
1502
- const result = convertTypeValue$1(value);
1503
- if (result) {
1504
- cleaned.type = result.type;
1505
- if (result.nullable) cleaned.nullable = true;
1506
- }
1507
- } else if (key === "properties" && typeof value === "object" && value) cleaned.properties = cleanProperties$1(value);
1508
- else if (typeof value === "object" && value !== null) cleaned[key] = cleanJsonSchema$1(value);
1509
- else cleaned[key] = value;
616
+ function _warn(message) {
617
+ console.error(`[dotenv@${version}][WARN] ${message}`);
1510
618
  }
1511
- return cleaned;
1512
- }
1513
- /**
1514
- * Convert tools to Antigravity format
1515
- * All tools should be in a single object with functionDeclarations array
1516
- */
1517
- function convertTools$1(tools) {
1518
- if (!tools || tools.length === 0) return void 0;
1519
- const functionDeclarations = [];
1520
- for (const tool of tools) {
1521
- const t = tool;
1522
- if (t.type === "function" && t.function) functionDeclarations.push({
1523
- name: t.function.name,
1524
- description: t.function.description || "",
1525
- parameters: cleanJsonSchema$1(t.function.parameters) || {}
1526
- });
619
+ function _debug(message) {
620
+ console.log(`[dotenv@${version}][DEBUG] ${message}`);
1527
621
  }
1528
- if (functionDeclarations.length === 0) return void 0;
1529
- return [{ functionDeclarations }];
1530
- }
1531
- /**
1532
- * Build standard Gemini API request body (for API Key authentication)
1533
- */
1534
- function buildStandardGeminiRequestBody(request) {
1535
- const { contents, systemInstruction } = convertMessages$1(request.messages);
1536
- const tools = convertTools$1(request.tools);
1537
- const body = {
1538
- contents,
1539
- generationConfig: {
1540
- temperature: request.temperature ?? 1,
1541
- topP: request.top_p ?? .85,
1542
- topK: request.top_k ?? 50,
1543
- maxOutputTokens: request.max_tokens ?? 8096
1544
- }
1545
- };
1546
- if (systemInstruction) body.systemInstruction = systemInstruction;
1547
- if (tools) body.tools = tools;
1548
- if (isThinkingModel(request.model)) body.generationConfig = {
1549
- ...body.generationConfig,
1550
- thinkingConfig: { includeThoughts: true }
1551
- };
1552
- return body;
1553
- }
1554
- /**
1555
- * Build Antigravity request body
1556
- * The Antigravity API expects a specific nested structure with request object
1557
- */
1558
- function buildAntigravityRequestBody(request) {
1559
- const innerRequest = buildStandardGeminiRequestBody(request);
1560
- return {
1561
- model: request.model,
1562
- userAgent: "antigravity",
1563
- requestId: `agent-${crypto.randomUUID()}`,
1564
- request: innerRequest
1565
- };
1566
- }
1567
- /**
1568
- * Create error response
1569
- */
1570
- function createErrorResponse$1(message, type, status, details) {
1571
- const error = {
1572
- message,
1573
- type
1574
- };
1575
- if (details) error.details = details;
1576
- return new Response(JSON.stringify({ error }), {
1577
- status,
1578
- headers: { "Content-Type": "application/json" }
1579
- });
1580
- }
1581
- /**
1582
- * Create chat completion with Antigravity or standard Gemini API
1583
- * Priority: API Key > OAuth
1584
- */
1585
- async function createAntigravityChatCompletion(request) {
1586
- const apiKey = getApiKey();
1587
- if (apiKey) return await createWithApiKey(request, apiKey);
1588
- const accessToken = await getValidAccessToken();
1589
- if (!accessToken) return createErrorResponse$1("No valid authentication available. Please set GEMINI_API_KEY environment variable or run OAuth login.", "auth_error", 401);
1590
- return await createWithOAuth(request, accessToken);
1591
- }
1592
- /**
1593
- * Create chat completion using API Key (standard Gemini API)
1594
- */
1595
- async function createWithApiKey(request, apiKey) {
1596
- const endpoint = request.stream ? getGeminiStreamUrl(request.model, apiKey) : getGeminiNoStreamUrl(request.model, apiKey);
1597
- const body = buildStandardGeminiRequestBody(request);
1598
- consola.debug(`Gemini API request with model ${request.model}`);
1599
- try {
1600
- const response = await fetch(endpoint, {
1601
- method: "POST",
1602
- headers: { "Content-Type": "application/json" },
1603
- body: JSON.stringify(body)
1604
- });
1605
- if (!response.ok) return await handleApiError$1(response);
1606
- return request.stream ? transformStreamResponse$1(response, request.model) : await transformNonStreamResponse$1(response, request.model);
1607
- } catch (error) {
1608
- consola.error("Gemini API request error:", error);
1609
- return createErrorResponse$1(`Request failed: ${String(error)}`, "request_error", 500);
622
+ function _log(message) {
623
+ console.log(`[dotenv@${version}] ${message}`);
1610
624
  }
1611
- }
1612
- /**
1613
- * Create chat completion using OAuth (Antigravity private API)
1614
- * Note: Both Gemini and Claude models use the same endpoint and Gemini-style format
1615
- */
1616
- async function createWithOAuth(request, accessToken) {
1617
- const endpoint = request.stream ? ANTIGRAVITY_STREAM_URL : ANTIGRAVITY_NO_STREAM_URL;
1618
- const body = buildAntigravityRequestBody(request);
1619
- consola.debug(`Antigravity request to ${endpoint} with model ${request.model}`);
1620
- try {
1621
- const response = await fetch(endpoint, {
1622
- method: "POST",
1623
- headers: {
1624
- Host: ANTIGRAVITY_API_HOST,
1625
- "User-Agent": ANTIGRAVITY_USER_AGENT$1,
1626
- Authorization: `Bearer ${accessToken}`,
1627
- "Content-Type": "application/json",
1628
- "Accept-Encoding": "gzip"
1629
- },
1630
- body: JSON.stringify(body)
1631
- });
1632
- if (!response.ok) return await handleApiError$1(response);
1633
- return request.stream ? transformStreamResponse$1(response, request.model) : await transformNonStreamResponse$1(response, request.model);
1634
- } catch (error) {
1635
- consola.error("Antigravity request error:", error);
1636
- return createErrorResponse$1(`Request failed: ${String(error)}`, "request_error", 500);
625
+ function _dotenvKey(options) {
626
+ if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) return options.DOTENV_KEY;
627
+ if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) return process.env.DOTENV_KEY;
628
+ return "";
1637
629
  }
1638
- }
1639
- /**
1640
- * Handle API error response
1641
- */
1642
- async function handleApiError$1(response) {
1643
- const errorText = await response.text();
1644
- consola.error(`Antigravity error: ${response.status} ${errorText}`);
1645
- if (response.status === 403) await disableCurrentAccount();
1646
- if (response.status === 429 || response.status === 503) await rotateAccount();
1647
- return createErrorResponse$1(`Antigravity API error: ${response.status}`, "api_error", response.status, errorText);
1648
- }
1649
- /**
1650
- * Generate request ID
1651
- */
1652
- function generateRequestId() {
1653
- return `chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
1654
- }
1655
- /**
1656
- * Transform Antigravity stream response to OpenAI format
1657
- */
1658
- function transformStreamResponse$1(response, model) {
1659
- const reader = response.body?.getReader();
1660
- if (!reader) return new Response("No response body", { status: 500 });
1661
- const encoder = new TextEncoder();
1662
- const decoder = new TextDecoder();
1663
- const requestId = generateRequestId();
1664
- const stream = new ReadableStream({ async start(controller) {
1665
- const state = createStreamState();
630
+ function _instructions(result, dotenvKey) {
631
+ let uri;
1666
632
  try {
1667
- await processOpenAIStream(reader, decoder, state, controller, encoder, requestId, model);
1668
- controller.enqueue(encoder.encode("data: [DONE]\n\n"));
1669
- controller.close();
633
+ uri = new URL(dotenvKey);
1670
634
  } catch (error) {
1671
- consola.error("Stream transform error:", error);
1672
- controller.error(error);
1673
- }
1674
- } });
1675
- return new Response(stream, { headers: {
1676
- "Content-Type": "text/event-stream",
1677
- "Cache-Control": "no-cache",
1678
- Connection: "keep-alive"
1679
- } });
1680
- }
1681
- /**
1682
- * Process stream and emit OpenAI format chunks
1683
- */
1684
- async function processOpenAIStream(reader, decoder, state, controller, encoder, requestId, model) {
1685
- while (true) {
1686
- const { done, value } = await reader.read();
1687
- if (done) break;
1688
- const lines = processChunk(decoder.decode(value, { stream: true }), state);
1689
- for (const line of lines) {
1690
- const data = parseSSELine(line);
1691
- if (!data) continue;
1692
- const { candidates } = extractFromData(data);
1693
- const candidate = candidates[0];
1694
- const parts = candidate?.content?.parts ?? [];
1695
- for (const part of parts) {
1696
- const chunkData = buildOpenAIChunk(part, requestId, model, candidate?.finishReason);
1697
- if (chunkData) controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunkData)}\n\n`));
635
+ if (error.code === "ERR_INVALID_URL") {
636
+ const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
637
+ err.code = "INVALID_DOTENV_KEY";
638
+ throw err;
1698
639
  }
640
+ throw error;
1699
641
  }
1700
- }
1701
- }
1702
- /**
1703
- * Build OpenAI format chunk from part
1704
- */
1705
- function buildOpenAIChunk(part, requestId, model, finishReason) {
1706
- const baseChunk = {
1707
- id: requestId,
1708
- object: "chat.completion.chunk",
1709
- created: Math.floor(Date.now() / 1e3),
1710
- model
1711
- };
1712
- if (part.thought && part.text) return {
1713
- ...baseChunk,
1714
- choices: [{
1715
- index: 0,
1716
- delta: { reasoning_content: part.text },
1717
- finish_reason: null
1718
- }]
1719
- };
1720
- if (part.text && !part.thought) return {
1721
- ...baseChunk,
1722
- choices: [{
1723
- index: 0,
1724
- delta: { content: part.text },
1725
- finish_reason: finishReason === "STOP" ? "stop" : null
1726
- }]
1727
- };
1728
- if (part.functionCall) return {
1729
- ...baseChunk,
1730
- choices: [{
1731
- index: 0,
1732
- delta: { tool_calls: [{
1733
- index: 0,
1734
- id: `call_${Date.now()}`,
1735
- type: "function",
1736
- function: {
1737
- name: part.functionCall.name,
1738
- arguments: JSON.stringify(part.functionCall.args)
1739
- }
1740
- }] },
1741
- finish_reason: null
1742
- }]
1743
- };
1744
- return null;
1745
- }
1746
- /**
1747
- * Transform Antigravity non-stream response to OpenAI format
1748
- */
1749
- async function transformNonStreamResponse$1(response, model) {
1750
- const rawData = await response.json();
1751
- const data = rawData.response ?? rawData;
1752
- const { content, reasoningContent, toolCalls } = extractNonStreamContent((data.candidates?.[0])?.content?.parts ?? []);
1753
- const message = {
1754
- role: "assistant",
1755
- content: content || null
1756
- };
1757
- if (reasoningContent) message.reasoning_content = reasoningContent;
1758
- if (toolCalls.length > 0) message.tool_calls = toolCalls;
1759
- const openaiResponse = {
1760
- id: generateRequestId(),
1761
- object: "chat.completion",
1762
- created: Math.floor(Date.now() / 1e3),
1763
- model,
1764
- choices: [{
1765
- index: 0,
1766
- message,
1767
- finish_reason: "stop"
1768
- }],
1769
- usage: {
1770
- prompt_tokens: data.usageMetadata?.promptTokenCount ?? 0,
1771
- completion_tokens: data.usageMetadata?.candidatesTokenCount ?? 0,
1772
- total_tokens: data.usageMetadata?.totalTokenCount ?? 0
642
+ const key = uri.password;
643
+ if (!key) {
644
+ const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing key part");
645
+ err.code = "INVALID_DOTENV_KEY";
646
+ throw err;
1773
647
  }
1774
- };
1775
- return new Response(JSON.stringify(openaiResponse), { headers: { "Content-Type": "application/json" } });
1776
- }
1777
- /**
1778
- * Extract content from non-stream response parts
1779
- */
1780
- function extractNonStreamContent(parts) {
1781
- let content = "";
1782
- let reasoningContent = "";
1783
- const toolCalls = [];
1784
- for (const part of parts) {
1785
- if (part.thought && part.text) reasoningContent += part.text;
1786
- else if (part.text) content += part.text;
1787
- if (part.functionCall) toolCalls.push({
1788
- id: `call_${Date.now()}`,
1789
- type: "function",
1790
- function: {
1791
- name: part.functionCall.name,
1792
- arguments: JSON.stringify(part.functionCall.args)
1793
- }
1794
- });
648
+ const environment = uri.searchParams.get("environment");
649
+ if (!environment) {
650
+ const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing environment part");
651
+ err.code = "INVALID_DOTENV_KEY";
652
+ throw err;
653
+ }
654
+ const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
655
+ const ciphertext = result.parsed[environmentKey];
656
+ if (!ciphertext) {
657
+ const err = /* @__PURE__ */ new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
658
+ err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
659
+ throw err;
660
+ }
661
+ return {
662
+ ciphertext,
663
+ key
664
+ };
1795
665
  }
1796
- return {
1797
- content,
1798
- reasoningContent,
1799
- toolCalls
1800
- };
1801
- }
1802
- //#endregion
1803
- //#region src/routes/antigravity/chat-completions/route.ts
1804
- /**
1805
- * Antigravity Chat Completions Route
1806
- *
1807
- * OpenAI-compatible chat completions endpoint for Antigravity.
1808
- */
1809
- const app$1 = new Hono();
1810
- app$1.post("/", async (c) => {
1811
- const body = await c.req.json();
1812
- const response = await createAntigravityChatCompletion(body);
1813
- const headers = new Headers(response.headers);
1814
- if (body.stream) return new Response(response.body, {
1815
- status: response.status,
1816
- headers
1817
- });
1818
- return new Response(await response.text(), {
1819
- status: response.status,
1820
- headers
1821
- });
1822
- });
1823
- const antigravityChatCompletionsRoute = app$1;
1824
- //#endregion
1825
- //#region src/lib/request-queue.ts
1826
- var RequestQueue = class {
1827
- queue = [];
1828
- activeCount = 0;
1829
- maxConcurrent;
1830
- minDelayMs;
1831
- lastRequestTime = 0;
1832
- constructor(maxConcurrent = 2, minDelayMs = 300) {
1833
- this.maxConcurrent = maxConcurrent;
1834
- this.minDelayMs = minDelayMs;
666
+ function _vaultPath(options) {
667
+ let possibleVaultPath = null;
668
+ if (options && options.path && options.path.length > 0) if (Array.isArray(options.path)) {
669
+ for (const filepath of options.path) if (fs$1.existsSync(filepath)) possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
670
+ } else possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
671
+ else possibleVaultPath = path$1.resolve(process.cwd(), ".env.vault");
672
+ if (fs$1.existsSync(possibleVaultPath)) return possibleVaultPath;
673
+ return null;
1835
674
  }
1836
- async enqueue(execute) {
1837
- return new Promise((resolve, reject) => {
1838
- this.queue.push({
1839
- execute,
1840
- resolve,
1841
- reject
1842
- });
1843
- this.processQueue();
1844
- });
675
+ function _resolveHome(envPath) {
676
+ return envPath[0] === "~" ? path$1.join(os$1.homedir(), envPath.slice(1)) : envPath;
1845
677
  }
1846
- async processQueue() {
1847
- if (this.activeCount >= this.maxConcurrent || this.queue.length === 0) return;
1848
- const request = this.queue.shift();
1849
- if (!request) return;
1850
- this.activeCount++;
1851
- const elapsed = Date.now() - this.lastRequestTime;
1852
- if (elapsed < this.minDelayMs) await new Promise((r) => setTimeout(r, this.minDelayMs - elapsed));
1853
- this.lastRequestTime = Date.now();
1854
- try {
1855
- const result = await request.execute();
1856
- request.resolve(result);
1857
- } catch (error) {
1858
- request.reject(error);
1859
- } finally {
1860
- this.activeCount--;
1861
- this.processQueue();
1862
- }
678
+ function _configVault(options) {
679
+ const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
680
+ const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
681
+ if (debug || !quiet) _log("Loading env from encrypted .env.vault");
682
+ const parsed = DotenvModule._parseVault(options);
683
+ let processEnv = process.env;
684
+ if (options && options.processEnv != null) processEnv = options.processEnv;
685
+ DotenvModule.populate(processEnv, parsed, options);
686
+ return { parsed };
1863
687
  }
1864
- };
1865
- const antigravityQueue = new RequestQueue(2, 500);
1866
- //#endregion
1867
- //#region src/services/antigravity/anthropic-events.ts
1868
- /**
1869
- * Anthropic SSE Event Builder
1870
- *
1871
- * Builds Anthropic-compatible SSE events for streaming responses.
1872
- * Extracted for better code organization and reusability.
1873
- */
1874
- const encoder = new TextEncoder();
1875
- /**
1876
- * Create message_start event
1877
- */
1878
- function createMessageStart(messageId, model) {
1879
- const event = {
1880
- type: "message_start",
1881
- message: {
1882
- id: messageId,
1883
- type: "message",
1884
- role: "assistant",
1885
- content: [],
1886
- model,
1887
- stop_reason: null,
1888
- stop_sequence: null,
1889
- usage: {
1890
- input_tokens: 0,
1891
- output_tokens: 0
1892
- }
688
+ function configDotenv(options) {
689
+ const dotenvPath = path$1.resolve(process.cwd(), ".env");
690
+ let encoding = "utf8";
691
+ let processEnv = process.env;
692
+ if (options && options.processEnv != null) processEnv = options.processEnv;
693
+ let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
694
+ let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
695
+ if (options && options.encoding) encoding = options.encoding;
696
+ else if (debug) _debug("No encoding is specified. UTF-8 is used by default");
697
+ let optionPaths = [dotenvPath];
698
+ if (options && options.path) if (!Array.isArray(options.path)) optionPaths = [_resolveHome(options.path)];
699
+ else {
700
+ optionPaths = [];
701
+ for (const filepath of options.path) optionPaths.push(_resolveHome(filepath));
1893
702
  }
1894
- };
1895
- return encoder.encode(`event: message_start\ndata: ${JSON.stringify(event)}\n\n`);
1896
- }
1897
- /**
1898
- * Create message_stop event
1899
- */
1900
- function createMessageStop() {
1901
- return encoder.encode(`event: message_stop\ndata: ${JSON.stringify({ type: "message_stop" })}\n\n`);
1902
- }
1903
- /**
1904
- * Create content_block_start event for thinking
1905
- */
1906
- function createThinkingBlockStart(index) {
1907
- const event = {
1908
- type: "content_block_start",
1909
- index,
1910
- content_block: {
1911
- type: "thinking",
1912
- thinking: ""
703
+ let lastError;
704
+ const parsedAll = {};
705
+ for (const path of optionPaths) try {
706
+ const parsed = DotenvModule.parse(fs$1.readFileSync(path, { encoding }));
707
+ DotenvModule.populate(parsedAll, parsed, options);
708
+ } catch (e) {
709
+ if (debug) _debug(`Failed to load ${path} ${e.message}`);
710
+ lastError = e;
1913
711
  }
1914
- };
1915
- return encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(event)}\n\n`);
1916
- }
1917
- /**
1918
- * Create content_block_delta event for thinking
1919
- */
1920
- function createThinkingDelta(index, text) {
1921
- const event = {
1922
- type: "content_block_delta",
1923
- index,
1924
- delta: {
1925
- type: "thinking_delta",
1926
- thinking: text
712
+ const populated = DotenvModule.populate(processEnv, parsedAll, options);
713
+ debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
714
+ quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
715
+ if (debug || !quiet) {
716
+ const keysCount = Object.keys(populated).length;
717
+ const shortPaths = [];
718
+ for (const filePath of optionPaths) try {
719
+ const relative = path$1.relative(process.cwd(), filePath);
720
+ shortPaths.push(relative);
721
+ } catch (e) {
722
+ if (debug) _debug(`Failed to load ${filePath} ${e.message}`);
723
+ lastError = e;
724
+ }
725
+ _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
1927
726
  }
1928
- };
1929
- return encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(event)}\n\n`);
1930
- }
1931
- /**
1932
- * Create content_block_start event for text
1933
- */
1934
- function createTextBlockStart(index) {
1935
- const event = {
1936
- type: "content_block_start",
1937
- index,
1938
- content_block: {
1939
- type: "text",
1940
- text: ""
727
+ if (lastError) return {
728
+ parsed: parsedAll,
729
+ error: lastError
730
+ };
731
+ else return { parsed: parsedAll };
732
+ }
733
+ function config(options) {
734
+ if (_dotenvKey(options).length === 0) return DotenvModule.configDotenv(options);
735
+ const vaultPath = _vaultPath(options);
736
+ if (!vaultPath) {
737
+ _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
738
+ return DotenvModule.configDotenv(options);
1941
739
  }
1942
- };
1943
- return encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(event)}\n\n`);
1944
- }
1945
- /**
1946
- * Create content_block_delta event for text
1947
- */
1948
- function createTextDelta(index, text) {
1949
- const event = {
1950
- type: "content_block_delta",
1951
- index,
1952
- delta: {
1953
- type: "text_delta",
1954
- text
740
+ return DotenvModule._configVault(options);
741
+ }
742
+ function decrypt(encrypted, keyStr) {
743
+ const key = Buffer.from(keyStr.slice(-64), "hex");
744
+ let ciphertext = Buffer.from(encrypted, "base64");
745
+ const nonce = ciphertext.subarray(0, 12);
746
+ const authTag = ciphertext.subarray(-16);
747
+ ciphertext = ciphertext.subarray(12, -16);
748
+ try {
749
+ const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
750
+ aesgcm.setAuthTag(authTag);
751
+ return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
752
+ } catch (error) {
753
+ const isRange = error instanceof RangeError;
754
+ const invalidKeyLength = error.message === "Invalid key length";
755
+ const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
756
+ if (isRange || invalidKeyLength) {
757
+ const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
758
+ err.code = "INVALID_DOTENV_KEY";
759
+ throw err;
760
+ } else if (decryptionFailed) {
761
+ const err = /* @__PURE__ */ new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
762
+ err.code = "DECRYPTION_FAILED";
763
+ throw err;
764
+ } else throw error;
1955
765
  }
1956
- };
1957
- return encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(event)}\n\n`);
1958
- }
1959
- /**
1960
- * Create content_block_stop event
1961
- */
1962
- function createBlockStop(index) {
1963
- const event = {
1964
- type: "content_block_stop",
1965
- index
1966
- };
1967
- return encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(event)}\n\n`);
1968
- }
1969
- /**
1970
- * Create content_block_start event for tool_use
1971
- */
1972
- function createToolBlockStart(index, toolId, name) {
1973
- const event = {
1974
- type: "content_block_start",
1975
- index,
1976
- content_block: {
1977
- type: "tool_use",
1978
- id: toolId,
1979
- name,
1980
- input: {}
766
+ }
767
+ function populate(processEnv, parsed, options = {}) {
768
+ const debug = Boolean(options && options.debug);
769
+ const override = Boolean(options && options.override);
770
+ const populated = {};
771
+ if (typeof parsed !== "object") {
772
+ const err = /* @__PURE__ */ new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
773
+ err.code = "OBJECT_REQUIRED";
774
+ throw err;
1981
775
  }
1982
- };
1983
- return encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(event)}\n\n`);
1984
- }
1985
- /**
1986
- * Create content_block_delta event for tool input
1987
- */
1988
- function createToolDelta(index, args) {
1989
- const event = {
1990
- type: "content_block_delta",
1991
- index,
1992
- delta: {
1993
- type: "input_json_delta",
1994
- partial_json: JSON.stringify(args)
776
+ for (const key of Object.keys(parsed)) if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
777
+ if (override === true) {
778
+ processEnv[key] = parsed[key];
779
+ populated[key] = parsed[key];
780
+ }
781
+ if (debug) if (override === true) _debug(`"${key}" is already defined and WAS overwritten`);
782
+ else _debug(`"${key}" is already defined and was NOT overwritten`);
783
+ } else {
784
+ processEnv[key] = parsed[key];
785
+ populated[key] = parsed[key];
1995
786
  }
787
+ return populated;
788
+ }
789
+ const DotenvModule = {
790
+ configDotenv,
791
+ _configVault,
792
+ _parseVault,
793
+ config,
794
+ decrypt,
795
+ parse,
796
+ populate
1996
797
  };
1997
- return encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(event)}\n\n`);
1998
- }
1999
- /**
2000
- * Create message_delta event with stop reason and usage
2001
- */
2002
- function createMessageDelta(stopReason, outputTokens) {
2003
- const event = {
2004
- type: "message_delta",
2005
- delta: {
2006
- stop_reason: stopReason,
2007
- stop_sequence: null
2008
- },
2009
- usage: { output_tokens: outputTokens }
2010
- };
2011
- return encoder.encode(`event: message_delta\ndata: ${JSON.stringify(event)}\n\n`);
2012
- }
2013
- /**
2014
- * Generate a unique message ID
2015
- */
2016
- function generateMessageId() {
2017
- return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
2018
- }
2019
- /**
2020
- * Generate a unique tool ID
2021
- */
2022
- function generateToolId() {
2023
- return `toolu_${Date.now()}`;
2024
- }
798
+ module.exports.configDotenv = DotenvModule.configDotenv;
799
+ module.exports._configVault = DotenvModule._configVault;
800
+ module.exports._parseVault = DotenvModule._parseVault;
801
+ module.exports.config = DotenvModule.config;
802
+ module.exports.decrypt = DotenvModule.decrypt;
803
+ module.exports.parse = DotenvModule.parse;
804
+ module.exports.populate = DotenvModule.populate;
805
+ module.exports = DotenvModule;
806
+ }));
2025
807
  //#endregion
2026
- //#region src/services/antigravity/create-messages.ts
2027
- /**
2028
- * Google Antigravity Messages API
2029
- *
2030
- * Converts Anthropic Messages API format to Antigravity format.
2031
- * This enables Claude Code to use Antigravity as backend.
2032
- *
2033
- * Based on: https://github.com/liuw1535/antigravity2api-nodejs
2034
- */
2035
- const ANTIGRAVITY_ENDPOINTS = ["daily-cloudcode-pa.sandbox.googleapis.com", "cloudcode-pa.googleapis.com"];
2036
- let currentEndpointIndex = 0;
2037
- function getStreamUrl(host) {
2038
- return `https://${host}/v1internal:streamGenerateContent?alt=sse`;
2039
- }
2040
- function getNoStreamUrl(host) {
2041
- return `https://${host}/v1internal:generateContent`;
2042
- }
2043
- function getCurrentHost() {
2044
- return ANTIGRAVITY_ENDPOINTS[currentEndpointIndex];
2045
- }
2046
- function rotateEndpoint() {
2047
- const oldIndex = currentEndpointIndex;
2048
- currentEndpointIndex = (currentEndpointIndex + 1) % ANTIGRAVITY_ENDPOINTS.length;
2049
- consola.info(`Rotating endpoint: ${ANTIGRAVITY_ENDPOINTS[oldIndex]} → ${ANTIGRAVITY_ENDPOINTS[currentEndpointIndex]}`);
2050
- }
2051
- const ANTIGRAVITY_USER_AGENT = "antigravity/1.11.3 windows/amd64";
2052
- const rateLimitTracker = {};
2053
- function getModelFamily(model) {
2054
- if (model.includes("claude")) return "claude";
2055
- if (model.includes("gemini")) return "gemini";
2056
- return "other";
2057
- }
2058
- function trackRateLimit(model) {
2059
- const family = getModelFamily(model);
2060
- if (!rateLimitTracker[family]) rateLimitTracker[family] = {
2061
- lastLimitTime: 0,
2062
- consecutiveErrors: 0
2063
- };
2064
- rateLimitTracker[family].lastLimitTime = Date.now();
2065
- rateLimitTracker[family].consecutiveErrors++;
2066
- }
2067
- function clearRateLimitTracker(model) {
2068
- const family = getModelFamily(model);
2069
- if (rateLimitTracker[family]) rateLimitTracker[family].consecutiveErrors = 0;
2070
- }
2071
- function getBackoffDelay(model, baseDelay) {
2072
- const info = rateLimitTracker[getModelFamily(model)];
2073
- if (!info) return baseDelay;
2074
- const multiplier = Math.min(Math.pow(2, info.consecutiveErrors - 1), 60);
2075
- return Math.min(baseDelay * multiplier, 3e4);
2076
- }
2077
- /**
2078
- * Extract text from system content (can be string or array)
2079
- */
2080
- function extractSystemText(system) {
2081
- if (typeof system === "string") return system;
2082
- return system.filter((block) => block.type === "text" && block.text).map((block) => block.text).join("\n\n");
2083
- }
2084
- /**
2085
- * Convert Anthropic messages to Antigravity format
2086
- */
2087
- function convertMessages(messages, system) {
2088
- const contents = [];
2089
- let systemInstruction;
2090
- if (system) {
2091
- const systemText = extractSystemText(system);
2092
- if (systemText) systemInstruction = { parts: [{ text: systemText }] };
2093
- }
2094
- for (const message of messages) {
2095
- const role = message.role === "assistant" ? "model" : "user";
2096
- const parts = buildParts(message.content);
2097
- if (parts.length > 0) contents.push({
2098
- role,
2099
- parts
2100
- });
2101
- }
2102
- return {
2103
- contents,
2104
- systemInstruction
808
+ //#region node_modules/dotenv/lib/env-options.js
809
+ var require_env_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
810
+ const options = {};
811
+ if (process.env.DOTENV_CONFIG_ENCODING != null) options.encoding = process.env.DOTENV_CONFIG_ENCODING;
812
+ if (process.env.DOTENV_CONFIG_PATH != null) options.path = process.env.DOTENV_CONFIG_PATH;
813
+ if (process.env.DOTENV_CONFIG_QUIET != null) options.quiet = process.env.DOTENV_CONFIG_QUIET;
814
+ if (process.env.DOTENV_CONFIG_DEBUG != null) options.debug = process.env.DOTENV_CONFIG_DEBUG;
815
+ if (process.env.DOTENV_CONFIG_OVERRIDE != null) options.override = process.env.DOTENV_CONFIG_OVERRIDE;
816
+ if (process.env.DOTENV_CONFIG_DOTENV_KEY != null) options.DOTENV_KEY = process.env.DOTENV_CONFIG_DOTENV_KEY;
817
+ module.exports = options;
818
+ }));
819
+ //#endregion
820
+ //#region node_modules/dotenv/lib/cli-options.js
821
+ var require_cli_options = /* @__PURE__ */ __commonJSMin(((exports, module) => {
822
+ const re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/;
823
+ module.exports = function optionMatcher(args) {
824
+ const options = args.reduce(function(acc, cur) {
825
+ const matches = cur.match(re);
826
+ if (matches) acc[matches[1]] = matches[2];
827
+ return acc;
828
+ }, {});
829
+ if (!("quiet" in options)) options.quiet = "true";
830
+ return options;
2105
831
  };
2106
- }
2107
- /**
2108
- * Build parts array from message content
2109
- */
2110
- function buildParts(content) {
2111
- if (typeof content === "string") return [{ text: content }];
2112
- const parts = [];
2113
- for (const block of content) if (block.type === "text" && block.text) parts.push({ text: block.text });
2114
- else if (block.type === "image" && block.source) parts.push({ inlineData: {
2115
- mimeType: block.source.media_type,
2116
- data: block.source.data
2117
- } });
2118
- return parts;
2119
- }
2120
- const GEMINI_ALLOWED_FIELDS = new Set([
2121
- "type",
2122
- "description",
2123
- "properties",
2124
- "required",
2125
- "items",
2126
- "enum",
2127
- "nullable"
2128
- ]);
2129
- /**
2130
- * Convert type value to Gemini format
2131
- * Handles both string and array types (for nullable)
2132
- */
2133
- function convertTypeValue(value) {
2134
- if (typeof value === "string") return { type: value.toUpperCase() };
2135
- if (Array.isArray(value)) {
2136
- const nonNullType = value.find((t) => typeof t === "string" && t !== "null");
2137
- if (nonNullType) return {
2138
- type: nonNullType.toUpperCase(),
2139
- nullable: true
832
+ }));
833
+ //#endregion
834
+ //#region node_modules/dotenv/config.js
835
+ (function() {
836
+ require_main().config(Object.assign({}, require_env_options(), require_cli_options()(process.argv)));
837
+ })();
838
+ //#endregion
839
+ //#region src/lib/proxy.ts
840
+ function initProxyFromEnv() {
841
+ if (typeof Bun !== "undefined") return;
842
+ try {
843
+ const agentOptions = {
844
+ keepAliveTimeout: 3e4,
845
+ keepAliveMaxTimeout: 6e4,
846
+ connect: { timeout: 15e3 }
2140
847
  };
2141
- }
2142
- return null;
2143
- }
2144
- /**
2145
- * Clean properties object recursively
2146
- */
2147
- function cleanProperties(props) {
2148
- const cleanedProps = {};
2149
- for (const [propKey, propValue] of Object.entries(props)) cleanedProps[propKey] = cleanJsonSchema(propValue);
2150
- return cleanedProps;
2151
- }
2152
- /**
2153
- * Clean and convert JSON schema to Gemini format
2154
- * - Removes unsupported fields like $schema, additionalProperties
2155
- * - Converts type values to uppercase (string -> STRING)
2156
- * - Ensures properties format is correct for Google API
2157
- */
2158
- function cleanJsonSchema(schema) {
2159
- if (!schema || typeof schema !== "object") return schema;
2160
- if (Array.isArray(schema)) return schema.map((item) => cleanJsonSchema(item));
2161
- const obj = schema;
2162
- const cleaned = {};
2163
- for (const [key, value] of Object.entries(obj)) {
2164
- if (!GEMINI_ALLOWED_FIELDS.has(key)) continue;
2165
- if (key === "type") {
2166
- const result = convertTypeValue(value);
2167
- if (result) {
2168
- cleaned.type = result.type;
2169
- if (result.nullable) cleaned.nullable = true;
848
+ const direct = new Agent(agentOptions);
849
+ const proxies = /* @__PURE__ */ new Map();
850
+ setGlobalDispatcher({
851
+ dispatch(options, handler) {
852
+ try {
853
+ const origin = typeof options.origin === "string" ? new URL(options.origin) : options.origin;
854
+ const raw = getProxyForUrl(origin.toString());
855
+ const proxyUrl = raw && raw.length > 0 ? raw : void 0;
856
+ if (!proxyUrl) {
857
+ consola.debug(`HTTP proxy bypass: ${origin.hostname}`);
858
+ return direct.dispatch(options, handler);
859
+ }
860
+ let agent = proxies.get(proxyUrl);
861
+ if (!agent) {
862
+ agent = new ProxyAgent({
863
+ uri: proxyUrl,
864
+ ...agentOptions
865
+ });
866
+ proxies.set(proxyUrl, agent);
867
+ }
868
+ let label = proxyUrl;
869
+ try {
870
+ const u = new URL(proxyUrl);
871
+ label = `${u.protocol}//${u.host}`;
872
+ } catch {}
873
+ consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`);
874
+ return agent.dispatch(options, handler);
875
+ } catch {
876
+ return direct.dispatch(options, handler);
877
+ }
878
+ },
879
+ close() {
880
+ return direct.close();
881
+ },
882
+ destroy() {
883
+ return direct.destroy();
2170
884
  }
2171
- } else if (key === "properties" && typeof value === "object" && value) cleaned.properties = cleanProperties(value);
2172
- else if (typeof value === "object" && value !== null) cleaned[key] = cleanJsonSchema(value);
2173
- else cleaned[key] = value;
2174
- }
2175
- return cleaned;
2176
- }
2177
- /**
2178
- * Convert tools to Antigravity format
2179
- * All tools should be in a single object with functionDeclarations array
2180
- */
2181
- function convertTools(tools) {
2182
- if (!tools || tools.length === 0) return void 0;
2183
- const functionDeclarations = [];
2184
- for (const tool of tools) {
2185
- const t = tool;
2186
- functionDeclarations.push({
2187
- name: t.name,
2188
- description: t.description || "",
2189
- parameters: cleanJsonSchema(t.input_schema) || {}
2190
885
  });
886
+ consola.debug("HTTP proxy configured from environment (per-URL)");
887
+ } catch (err) {
888
+ consola.debug("Proxy setup skipped:", err);
2191
889
  }
2192
- return [{ functionDeclarations }];
2193
- }
2194
- /**
2195
- * Build Antigravity request body
2196
- * The Antigravity API expects a specific nested structure with request object
2197
- */
2198
- function buildGeminiRequest(request, projectId) {
2199
- const { contents, systemInstruction } = convertMessages(request.messages, request.system);
2200
- const tools = convertTools(request.tools);
2201
- const innerRequest = {
2202
- contents,
2203
- generationConfig: {
2204
- temperature: request.temperature ?? 1,
2205
- topP: request.top_p ?? .85,
2206
- topK: request.top_k ?? 50,
2207
- maxOutputTokens: request.max_tokens ?? 8096
2208
- }
2209
- };
2210
- if (systemInstruction) innerRequest.systemInstruction = systemInstruction;
2211
- if (tools) innerRequest.tools = tools;
2212
- if (isThinkingModel(request.model)) innerRequest.generationConfig = {
2213
- ...innerRequest.generationConfig,
2214
- thinkingConfig: { includeThoughts: true }
2215
- };
2216
- const result = {
2217
- model: request.model,
2218
- userAgent: "antigravity",
2219
- requestId: `agent-${crypto.randomUUID()}`,
2220
- request: innerRequest
2221
- };
2222
- if (projectId) result.project = projectId;
2223
- return result;
2224
- }
2225
- /**
2226
- * Create error response
2227
- */
2228
- function createErrorResponse(type, message, status) {
2229
- return new Response(JSON.stringify({
2230
- type: "error",
2231
- error: {
2232
- type,
2233
- message
2234
- }
2235
- }), {
2236
- status,
2237
- headers: { "Content-Type": "application/json" }
2238
- });
2239
890
  }
2240
- /**
2241
- * Create Anthropic-compatible message response using Antigravity
2242
- * Note: Both Gemini and Claude models use the same endpoint and Gemini-style format
2243
- *
2244
- * Features:
2245
- * - Endpoint fallback (daily → prod)
2246
- * - Per-model-family rate limit tracking
2247
- * - Exponential backoff for consecutive errors
2248
- * - Smart retry for short delays (≤5s on same endpoint)
2249
- */
2250
- const MAX_RETRIES$3 = 5;
2251
- const MAX_ENDPOINT_RETRIES = 2;
2252
- async function executeAntigravityRequest(request) {
2253
- const body = buildGeminiRequest(request, await getCurrentProjectId());
2254
- let endpointRetries = 0;
2255
- for (let attempt = 0; attempt <= MAX_RETRIES$3; attempt++) {
2256
- const host = getCurrentHost();
2257
- const endpoint = request.stream ? getStreamUrl(host) : getNoStreamUrl(host);
2258
- const accessToken = await getValidAccessToken();
2259
- if (!accessToken) return createErrorResponse("authentication_error", "No valid Antigravity access token available.", 401);
891
+ //#endregion
892
+ //#region src/lib/shell.ts
893
+ function getShell() {
894
+ const { platform, ppid, env } = process$1;
895
+ if (platform === "win32") {
2260
896
  try {
2261
- const response = await fetch(endpoint, {
2262
- method: "POST",
2263
- headers: {
2264
- Host: host,
2265
- "User-Agent": ANTIGRAVITY_USER_AGENT,
2266
- Authorization: `Bearer ${accessToken}`,
2267
- "Content-Type": "application/json",
2268
- "Accept-Encoding": "gzip"
2269
- },
2270
- body: JSON.stringify(body)
2271
- });
2272
- if (response.ok) {
2273
- clearRateLimitTracker(request.model);
2274
- return request.stream ? transformStreamResponse(response, request.model) : await transformNonStreamResponse(response, request.model);
2275
- }
2276
- const errorResult = await handleApiError(response, request.model);
2277
- if (errorResult.shouldRetry && attempt < MAX_RETRIES$3) {
2278
- trackRateLimit(request.model);
2279
- const backoffDelay = getBackoffDelay(request.model, errorResult.retryDelayMs);
2280
- if (backoffDelay <= 5e3 || endpointRetries >= MAX_ENDPOINT_RETRIES) {
2281
- consola.info(`Rate limited, retrying in ${backoffDelay}ms (attempt ${attempt + 1}/${MAX_RETRIES$3})`);
2282
- await sleep(backoffDelay);
2283
- } else {
2284
- rotateEndpoint();
2285
- endpointRetries++;
2286
- consola.info(`Switching endpoint, retrying in ${errorResult.retryDelayMs}ms`);
2287
- await sleep(errorResult.retryDelayMs);
2288
- }
2289
- continue;
2290
- }
2291
- return errorResult.response;
2292
- } catch (error) {
2293
- consola.error("Antigravity request error:", error);
2294
- if (attempt < MAX_RETRIES$3) {
2295
- if (endpointRetries < MAX_ENDPOINT_RETRIES) {
2296
- rotateEndpoint();
2297
- endpointRetries++;
2298
- }
2299
- await sleep(500);
2300
- continue;
2301
- }
2302
- return createErrorResponse("api_error", `Request failed: ${String(error)}`, 500);
897
+ if (execSync(`wmic process get ParentProcessId,Name | findstr "${ppid}"`, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
898
+ } catch {
899
+ return "cmd";
2303
900
  }
2304
- }
2305
- return createErrorResponse("api_error", "Max retries exceeded", 429);
2306
- }
2307
- async function createAntigravityMessages(request) {
2308
- return antigravityQueue.enqueue(() => executeAntigravityRequest(request));
2309
- }
2310
- /**
2311
- * Parse retry delay from error response
2312
- * Supports multiple formats:
2313
- * - RetryInfo.retryDelay: "3.5s"
2314
- * - quotaResetDelay: "3000ms" or "3s"
2315
- * - message: "Your quota will reset after 3s"
2316
- */
2317
- function parseRetryDelay$3(errorText) {
2318
- try {
2319
- const errorData = JSON.parse(errorText);
2320
- const details = errorData.error?.details ?? [];
2321
- for (const detail of details) {
2322
- if (detail["@type"]?.includes("RetryInfo") && detail.retryDelay) {
2323
- const match = /(\d+(?:\.\d+)?)s/.exec(detail.retryDelay);
2324
- if (match) return Math.ceil(Number.parseFloat(match[1]) * 1e3);
2325
- }
2326
- if (detail.quotaResetDelay) {
2327
- const match = /(\d+(?:\.\d+)?)(?:ms|s)/.exec(detail.quotaResetDelay);
2328
- if (match) {
2329
- const value = Number.parseFloat(match[1]);
2330
- return detail.quotaResetDelay.includes("ms") ? Math.ceil(value) : Math.ceil(value * 1e3);
2331
- }
2332
- }
901
+ return "cmd";
902
+ } else {
903
+ const shellPath = env.SHELL;
904
+ if (shellPath) {
905
+ if (shellPath.endsWith("zsh")) return "zsh";
906
+ if (shellPath.endsWith("fish")) return "fish";
907
+ if (shellPath.endsWith("bash")) return "bash";
2333
908
  }
2334
- const message = errorData.error?.message ?? "";
2335
- const resetMatch = /quota will reset after (\d+(?:\.\d+)?)s/i.exec(message);
2336
- if (resetMatch) return Math.ceil(Number.parseFloat(resetMatch[1]) * 1e3);
2337
- } catch {}
2338
- return 500;
2339
- }
2340
- /**
2341
- * Handle API error response
2342
- */
2343
- async function handleApiError(response, _model) {
2344
- const errorText = await response.text();
2345
- consola.error(`Antigravity error: ${response.status} ${errorText}`);
2346
- if (response.status === 403) await disableCurrentAccount();
2347
- if (response.status === 429 || response.status === 503) {
2348
- await rotateAccount();
2349
- return {
2350
- shouldRetry: true,
2351
- retryDelayMs: parseRetryDelay$3(errorText),
2352
- response: createErrorResponse("api_error", `Antigravity API error: ${response.status}`, response.status)
2353
- };
909
+ return "sh";
2354
910
  }
2355
- return {
2356
- shouldRetry: false,
2357
- retryDelayMs: 0,
2358
- response: createErrorResponse("api_error", `Antigravity API error: ${response.status}`, response.status)
2359
- };
2360
911
  }
2361
912
  /**
2362
- * Emit SSE event to controller based on stream event type
913
+ * Generates a copy-pasteable script to set multiple environment variables
914
+ * and run a subsequent command.
915
+ * @param {EnvVars} envVars - An object of environment variables to set.
916
+ * @param {string} commandToRun - The command to run after setting the variables.
917
+ * @returns {string} The formatted script string.
2363
918
  */
2364
- function emitSSEEvent(event, controller, state) {
2365
- switch (event.type) {
2366
- case "thinking_start":
2367
- controller.enqueue(createThinkingBlockStart(event.index));
2368
- break;
2369
- case "thinking_delta":
2370
- controller.enqueue(createThinkingDelta(event.index, event.text));
2371
- break;
2372
- case "thinking_stop":
2373
- controller.enqueue(createBlockStop(event.index));
2374
- break;
2375
- case "text_start":
2376
- controller.enqueue(createTextBlockStart(event.index));
2377
- break;
2378
- case "text_delta":
2379
- controller.enqueue(createTextDelta(event.index, event.text));
2380
- break;
2381
- case "text_stop":
2382
- controller.enqueue(createBlockStop(event.index));
919
+ function generateEnvScript(envVars, commandToRun = "") {
920
+ const shell = getShell();
921
+ const filteredEnvVars = Object.entries(envVars).filter(([, value]) => value !== void 0);
922
+ let commandBlock;
923
+ switch (shell) {
924
+ case "powershell":
925
+ commandBlock = filteredEnvVars.map(([key, value]) => `$env:${key} = ${value}`).join("; ");
2383
926
  break;
2384
- case "tool_use":
2385
- emitToolUseEvents(event, controller);
927
+ case "cmd":
928
+ commandBlock = filteredEnvVars.map(([key, value]) => `set ${key}=${value}`).join(" & ");
2386
929
  break;
2387
- case "usage":
2388
- state.inputTokens = event.inputTokens;
2389
- state.outputTokens = event.outputTokens;
930
+ case "fish":
931
+ commandBlock = filteredEnvVars.map(([key, value]) => `set -gx ${key} ${value}`).join("; ");
2390
932
  break;
2391
- case "finish":
2392
- controller.enqueue(createMessageDelta(event.stopReason, state.outputTokens));
933
+ default: {
934
+ const assignments = filteredEnvVars.map(([key, value]) => `${key}=${value}`).join(" ");
935
+ commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : "";
2393
936
  break;
2394
- }
2395
- }
2396
- /**
2397
- * Emit tool use events
2398
- */
2399
- function emitToolUseEvents(event, controller) {
2400
- const toolId = generateToolId();
2401
- controller.enqueue(createToolBlockStart(event.index, toolId, event.name));
2402
- controller.enqueue(createToolDelta(event.index, event.args));
2403
- controller.enqueue(createBlockStop(event.index));
2404
- }
2405
- /**
2406
- * Transform Antigravity stream response to Anthropic format
2407
- */
2408
- function transformStreamResponse(response, model) {
2409
- const reader = response.body?.getReader();
2410
- if (!reader) return new Response("No response body", { status: 500 });
2411
- const decoder = new TextDecoder();
2412
- const messageId = generateMessageId();
2413
- const stream = new ReadableStream({ async start(controller) {
2414
- const state = createStreamState();
2415
- controller.enqueue(createMessageStart(messageId, model));
2416
- try {
2417
- await processStream(reader, decoder, state, controller);
2418
- controller.enqueue(createMessageStop());
2419
- controller.close();
2420
- } catch (error) {
2421
- consola.error("Stream transform error:", error);
2422
- controller.error(error);
2423
937
  }
2424
- } });
2425
- return new Response(stream, { headers: {
2426
- "Content-Type": "text/event-stream",
2427
- "Cache-Control": "no-cache",
2428
- Connection: "keep-alive"
2429
- } });
938
+ }
939
+ if (commandBlock && commandToRun) return `${commandBlock}${shell === "cmd" ? " & " : " && "}${commandToRun}`;
940
+ return commandBlock || commandToRun;
2430
941
  }
942
+ //#endregion
943
+ //#region src/lib/api-key-auth.ts
2431
944
  /**
2432
- * Process candidate parts and handle finish
945
+ * Retrieve an API key from the incoming request.
946
+ *
947
+ * Checks common locations where clients supply keys (Authorization Bearer header, `x-api-key` header, or `apiKey` query parameter) and returns the first one found.
948
+ *
949
+ * @returns The extracted API key, or `undefined` if no key is present.
2433
950
  */
2434
- function processCandidate(candidate, state, emit) {
2435
- const parts = candidate?.content?.parts ?? [];
2436
- for (const part of parts) processPart(part, state, emit);
2437
- if (candidate?.finishReason === "STOP") {
2438
- handleFinish(state, emit);
2439
- return true;
2440
- }
2441
- return false;
951
+ function extractApiKey(c) {
952
+ const authHeader = c.req.header("authorization");
953
+ if (authHeader?.startsWith("Bearer ")) return authHeader.slice(7);
954
+ const anthropicKey = c.req.header("x-api-key");
955
+ if (anthropicKey) return anthropicKey;
956
+ const queryKey = c.req.query("apiKey");
957
+ if (queryKey) return queryKey;
2442
958
  }
2443
959
  /**
2444
- * Process the stream and emit events
960
+ * API key authentication middleware
961
+ * Validates that the request contains a valid API key if API keys are configured
2445
962
  */
2446
- async function processStream(reader, decoder, state, controller) {
2447
- const emit = (event) => emitSSEEvent(event, controller, state);
2448
- let finished = false;
2449
- while (!finished) {
2450
- const { done, value } = await reader.read();
2451
- if (done) break;
2452
- const lines = processChunk(decoder.decode(value, { stream: true }), state);
2453
- for (const line of lines) {
2454
- if (finished) break;
2455
- const data = parseSSELine(line);
2456
- if (!data) continue;
2457
- const { candidates, usage } = extractFromData(data);
2458
- if (usage) {
2459
- state.inputTokens = usage.promptTokenCount ?? state.inputTokens;
2460
- state.outputTokens = usage.candidatesTokenCount ?? state.outputTokens;
2461
- }
2462
- if (candidates[0] && processCandidate(candidates[0], state, emit)) {
2463
- finished = true;
2464
- break;
2465
- }
2466
- }
963
+ const apiKeyAuthMiddleware = async (c, next) => {
964
+ if (!state.apiKeys || state.apiKeys.length === 0) {
965
+ await next();
966
+ return;
2467
967
  }
2468
- }
968
+ const providedKey = extractApiKey(c);
969
+ if (!providedKey) throw new HTTPException(401, { message: "API key required. Please provide a valid API key in the Authorization header (Bearer token) or x-api-key header." });
970
+ if (!state.apiKeys.includes(providedKey)) throw new HTTPException(401, { message: "Invalid API key. Please provide a valid API key." });
971
+ await next();
972
+ };
973
+ //#endregion
974
+ //#region src/lib/model-logger.ts
2469
975
  /**
2470
- * Transform Antigravity non-stream response to Anthropic format
976
+ * Get timestamp string in format HH:mm:ss
2471
977
  */
2472
- async function transformNonStreamResponse(response, model) {
2473
- const rawData = await response.json();
2474
- const data = rawData.response ?? rawData;
2475
- const content = buildNonStreamContent((data.candidates?.[0])?.content?.parts ?? []);
2476
- const anthropicResponse = {
2477
- id: generateMessageId(),
2478
- type: "message",
2479
- role: "assistant",
2480
- content,
2481
- model,
2482
- stop_reason: "end_turn",
2483
- stop_sequence: null,
2484
- usage: {
2485
- input_tokens: data.usageMetadata?.promptTokenCount ?? 0,
2486
- output_tokens: data.usageMetadata?.candidatesTokenCount ?? 0
2487
- }
2488
- };
2489
- return new Response(JSON.stringify(anthropicResponse), { headers: { "Content-Type": "application/json" } });
978
+ function getTime() {
979
+ return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
2490
980
  }
2491
981
  /**
2492
- * Build content array for non-stream response
982
+ * Format duration in human readable format
2493
983
  */
2494
- function buildNonStreamContent(parts) {
2495
- const content = [];
2496
- for (const part of parts) {
2497
- if (part.thought && part.text) content.push({
2498
- type: "thinking",
2499
- thinking: part.text
2500
- });
2501
- else if (part.text) content.push({
2502
- type: "text",
2503
- text: part.text
2504
- });
2505
- if (part.functionCall) content.push({
2506
- type: "tool_use",
2507
- id: generateToolId(),
2508
- name: part.functionCall.name,
2509
- input: part.functionCall.args
2510
- });
2511
- }
2512
- return content;
984
+ function formatDuration(ms) {
985
+ if (ms < 1e3) return `${ms}ms`;
986
+ return `${(ms / 1e3).toFixed(1)}s`;
2513
987
  }
2514
- //#endregion
2515
- //#region src/routes/antigravity/messages/route.ts
2516
988
  /**
2517
- * Antigravity Messages Route
2518
- *
2519
- * Anthropic-compatible messages endpoint for Antigravity.
2520
- * This enables Claude Code to use Antigravity as backend.
989
+ * Extract model name from request body
2521
990
  */
2522
- const antigravityMessagesRoute = new Hono();
2523
- antigravityMessagesRoute.post("/", async (c) => {
2524
- if (!state.antigravityMode) return c.json({ error: "Antigravity mode is not enabled. Start with --antigravity flag." }, 400);
991
+ async function extractModel(c) {
2525
992
  try {
2526
- const body = await c.req.json();
2527
- consola.debug("Antigravity message request:", body.model);
2528
- const response = await createAntigravityMessages(body);
2529
- if (body.stream) {
2530
- const headers = new Headers();
2531
- headers.set("Content-Type", "text/event-stream");
2532
- headers.set("Cache-Control", "no-cache");
2533
- headers.set("Connection", "keep-alive");
2534
- return new Response(response.body, {
2535
- status: response.status,
2536
- headers
2537
- });
2538
- }
2539
- const data = await response.json();
2540
- return c.json(data);
2541
- } catch (error) {
2542
- consola.error("Antigravity message error:", error);
2543
- return c.json({
2544
- type: "error",
2545
- error: {
2546
- type: "antigravity_error",
2547
- message: error instanceof Error ? error.message : "Unknown error"
2548
- }
2549
- }, 500);
993
+ return (await c.req.raw.clone().json()).model;
994
+ } catch {
995
+ return;
2550
996
  }
2551
- });
2552
- //#endregion
2553
- //#region src/routes/antigravity/models/route.ts
997
+ }
2554
998
  /**
2555
- * Antigravity Models Route
999
+ * Custom logger middleware that shows model name before timestamp
2556
1000
  *
2557
- * OpenAI-compatible models endpoint for Antigravity.
1001
+ * Output format:
1002
+ * [model] HH:mm:ss <-- METHOD /path
1003
+ * [model] HH:mm:ss --> METHOD /path STATUS DURATION
2558
1004
  */
2559
- const app = new Hono();
2560
- app.get("/", async (c) => {
2561
- const models = await getAntigravityModels();
2562
- return c.json(models);
2563
- });
2564
- const antigravityModelsRoute = app;
1005
+ function modelLogger() {
1006
+ return async (c, next) => {
1007
+ const method = c.req.method;
1008
+ const fullPath = `${c.req.path}${c.req.raw.url.includes("?") ? `?${c.req.raw.url.split("?")[1]}` : ""}`;
1009
+ let model;
1010
+ if (method === "POST" && c.req.header("content-type")?.includes("json")) model = await extractModel(c);
1011
+ const modelPrefix = model ? `[${model}] ` : "";
1012
+ const startTime = getTime();
1013
+ console.log(`${modelPrefix}${startTime} <-- ${method} ${fullPath}`);
1014
+ const start = Date.now();
1015
+ await next();
1016
+ const duration = Date.now() - start;
1017
+ const endTime = getTime();
1018
+ console.log(`${modelPrefix}${endTime} --> ${method} ${fullPath} ${c.res.status} ${formatDuration(duration)}`);
1019
+ };
1020
+ }
2565
1021
  //#endregion
2566
1022
  //#region src/lib/approval.ts
2567
1023
  const awaitApproval = async () => {
@@ -3379,446 +1835,34 @@ tokenRoute.get("/", (c) => {
3379
1835
  const usageRoute = new Hono();
3380
1836
  usageRoute.get("/", async (c) => {
3381
1837
  try {
3382
- if (state.antigravityMode) {
3383
- const usage = await getAntigravityUsage();
3384
- return c.json(usage);
3385
- }
3386
- if (state.zenMode) return c.json({
3387
- error: "Usage statistics not available for Zen mode",
3388
- message: "Please check your usage at https://console.opencode.ai",
3389
- mode: "zen"
3390
- }, 200);
3391
1838
  const usage = await getCopilotUsage();
3392
1839
  return c.json(usage);
3393
1840
  } catch (error) {
3394
1841
  consola.error("Error fetching usage:", error);
3395
- if (state.antigravityMode) return c.json({ error: "Failed to fetch Antigravity usage" }, 500);
3396
- if (state.zenMode) return c.json({ error: "Failed to fetch Zen usage" }, 500);
3397
1842
  return c.json({ error: "Failed to fetch Copilot usage" }, 500);
3398
1843
  }
3399
1844
  });
3400
1845
  //#endregion
3401
- //#region src/services/zen/create-chat-completions.ts
3402
- /**
3403
- * OpenCode Zen Chat Completions Proxy
3404
- *
3405
- * Proxies chat completion requests to OpenCode Zen API.
3406
- */
3407
- const MAX_RETRIES$2 = 5;
3408
- const DEFAULT_RETRY_DELAY$2 = 500;
3409
- /**
3410
- * Parse retry delay from error response
3411
- */
3412
- function parseRetryDelay$2(response, errorText) {
3413
- const retryAfter = response.headers.get("Retry-After");
3414
- if (retryAfter) {
3415
- const seconds = Number.parseInt(retryAfter, 10);
3416
- if (!Number.isNaN(seconds)) return seconds * 1e3;
3417
- }
3418
- try {
3419
- const errorData = JSON.parse(errorText);
3420
- if (errorData.error?.retry_after) return errorData.error.retry_after * 1e3;
3421
- } catch {}
3422
- return DEFAULT_RETRY_DELAY$2;
3423
- }
3424
- /**
3425
- * Create chat completions via OpenCode Zen
3426
- */
3427
- async function createZenChatCompletions(request, signal) {
3428
- const apiKey = state.zenApiKey;
3429
- if (!apiKey) throw new Error("Zen API key not configured");
3430
- consola.debug(`Zen chat completions request for model: ${request.model}`);
3431
- for (let attempt = 0; attempt <= MAX_RETRIES$2; attempt++) try {
3432
- const response = await fetch("https://opencode.ai/zen/v1/chat/completions", {
3433
- method: "POST",
3434
- headers: {
3435
- "Content-Type": "application/json",
3436
- Authorization: `Bearer ${apiKey}`
3437
- },
3438
- body: JSON.stringify(request),
3439
- signal
3440
- });
3441
- if (response.ok) return response;
3442
- const errorText = await response.text();
3443
- if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES$2) {
3444
- const retryDelay = parseRetryDelay$2(response, errorText);
3445
- consola.info(`Zen rate limited (${response.status}), retrying in ${retryDelay}ms...`);
3446
- await sleep(retryDelay);
3447
- continue;
3448
- }
3449
- consola.error(`Zen API error: ${response.status} ${errorText}`);
3450
- throw new Error(`Zen API error: ${response.status} ${errorText}`);
3451
- } catch (error) {
3452
- if (error instanceof Error && error.name === "AbortError") throw error;
3453
- if (attempt < MAX_RETRIES$2) {
3454
- consola.warn(`Zen request failed, retrying... (${attempt + 1})`);
3455
- await sleep(DEFAULT_RETRY_DELAY$2);
3456
- continue;
3457
- }
3458
- throw error;
3459
- }
3460
- throw new Error("Max retries exceeded");
3461
- }
3462
- //#endregion
3463
- //#region src/routes/zen/chat-completions/route.ts
3464
- /**
3465
- * OpenCode Zen Chat Completions Route
3466
- *
3467
- * Proxies OpenAI-format chat completion requests to Zen.
3468
- */
3469
- const zenCompletionRoutes = new Hono();
3470
- zenCompletionRoutes.post("/", async (c) => {
3471
- if (!state.zenMode || !state.zenApiKey) return c.json({ error: "Zen mode is not enabled. Start with --zen flag." }, 400);
3472
- try {
3473
- const body = await c.req.json();
3474
- consola.debug("Zen chat completion request:", body.model);
3475
- const response = await createZenChatCompletions(body);
3476
- if (body.stream) {
3477
- const headers = new Headers();
3478
- headers.set("Content-Type", "text/event-stream");
3479
- headers.set("Cache-Control", "no-cache");
3480
- headers.set("Connection", "keep-alive");
3481
- return new Response(response.body, {
3482
- status: response.status,
3483
- headers
3484
- });
3485
- }
3486
- const data = await response.json();
3487
- return c.json(data);
3488
- } catch (error) {
3489
- consola.error("Zen chat completion error:", error);
3490
- return c.json({ error: {
3491
- message: error instanceof Error ? error.message : "Unknown error",
3492
- type: "zen_error"
3493
- } }, 500);
3494
- }
3495
- });
3496
- //#endregion
3497
- //#region src/services/zen/create-messages.ts
3498
- /**
3499
- * OpenCode Zen Messages Proxy
3500
- *
3501
- * Proxies Anthropic-format message requests to OpenCode Zen API.
3502
- */
3503
- const MAX_RETRIES$1 = 5;
3504
- const DEFAULT_RETRY_DELAY$1 = 500;
3505
- /**
3506
- * Parse retry delay from error response headers or body
3507
- */
3508
- function parseRetryDelay$1(response, errorText) {
3509
- const retryAfter = response.headers.get("Retry-After");
3510
- if (retryAfter) {
3511
- const seconds = Number.parseInt(retryAfter, 10);
3512
- if (!Number.isNaN(seconds)) return seconds * 1e3;
3513
- }
3514
- try {
3515
- const errorData = JSON.parse(errorText);
3516
- if (errorData.error?.retry_after) return errorData.error.retry_after * 1e3;
3517
- } catch {}
3518
- return DEFAULT_RETRY_DELAY$1;
3519
- }
3520
- /**
3521
- * Create messages via OpenCode Zen (Anthropic format)
3522
- */
3523
- async function createZenMessages(request, signal) {
3524
- const apiKey = state.zenApiKey;
3525
- if (!apiKey) throw new Error("Zen API key not configured");
3526
- consola.debug(`Zen messages request for model: ${request.model}`);
3527
- for (let attempt = 0; attempt <= MAX_RETRIES$1; attempt++) try {
3528
- const response = await fetch("https://opencode.ai/zen/v1/messages", {
3529
- method: "POST",
3530
- headers: {
3531
- "Content-Type": "application/json",
3532
- "x-api-key": apiKey,
3533
- "anthropic-version": "2023-06-01"
3534
- },
3535
- body: JSON.stringify(request),
3536
- signal
3537
- });
3538
- if (response.ok) return response;
3539
- const errorText = await response.text();
3540
- if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES$1) {
3541
- const retryDelay = parseRetryDelay$1(response, errorText);
3542
- consola.info(`Zen rate limited (${response.status}), retrying in ${retryDelay}ms...`);
3543
- await sleep(retryDelay);
3544
- continue;
3545
- }
3546
- consola.error(`Zen Messages API error: ${response.status} ${errorText}`);
3547
- throw new Error(`Zen Messages API error: ${response.status} ${errorText}`);
3548
- } catch (error) {
3549
- if (error instanceof Error && error.name === "AbortError") throw error;
3550
- if (attempt < MAX_RETRIES$1) {
3551
- consola.warn(`Zen request failed, retrying... (${attempt + 1})`);
3552
- await sleep(DEFAULT_RETRY_DELAY$1);
3553
- continue;
3554
- }
3555
- throw error;
3556
- }
3557
- throw new Error("Max retries exceeded");
3558
- }
3559
- //#endregion
3560
- //#region src/routes/zen/messages/route.ts
3561
- /**
3562
- * OpenCode Zen Messages Route
3563
- *
3564
- * Proxies Anthropic-format message requests to Zen.
3565
- * This enables Claude Code to use Zen as backend.
3566
- */
3567
- const zenMessageRoutes = new Hono();
3568
- zenMessageRoutes.post("/", async (c) => {
3569
- if (!state.zenMode || !state.zenApiKey) return c.json({ error: "Zen mode is not enabled. Start with --zen flag." }, 400);
3570
- try {
3571
- const body = await c.req.json();
3572
- consola.debug("Zen message request:", body.model);
3573
- const response = await createZenMessages(body);
3574
- if (body.stream) {
3575
- const headers = new Headers();
3576
- headers.set("Content-Type", "text/event-stream");
3577
- headers.set("Cache-Control", "no-cache");
3578
- headers.set("Connection", "keep-alive");
3579
- return new Response(response.body, {
3580
- status: response.status,
3581
- headers
3582
- });
3583
- }
3584
- const data = await response.json();
3585
- return c.json(data);
3586
- } catch (error) {
3587
- consola.error("Zen message error:", error);
3588
- return c.json({
3589
- type: "error",
3590
- error: {
3591
- type: "zen_error",
3592
- message: error instanceof Error ? error.message : "Unknown error"
3593
- }
3594
- }, 500);
3595
- }
3596
- });
3597
- //#endregion
3598
- //#region src/routes/zen/models/route.ts
3599
- /**
3600
- * OpenCode Zen Models Route
3601
- *
3602
- * Returns available models from Zen.
3603
- */
3604
- const zenModelRoutes = new Hono();
3605
- zenModelRoutes.get("/", async (c) => {
3606
- if (!state.zenMode || !state.zenApiKey) return c.json({ error: "Zen mode is not enabled. Start with --zen flag." }, 400);
3607
- try {
3608
- if (state.zenModels) return c.json(state.zenModels);
3609
- const { getZenModels } = await import("./get-models-onnSXkNI.js");
3610
- const models = await getZenModels();
3611
- state.zenModels = models;
3612
- return c.json(models);
3613
- } catch (error) {
3614
- consola.error("Zen models error:", error);
3615
- return c.json({ error: {
3616
- message: error instanceof Error ? error.message : "Unknown error",
3617
- type: "zen_error"
3618
- } }, 500);
3619
- }
3620
- });
3621
- //#endregion
3622
- //#region src/services/zen/create-responses.ts
3623
- /**
3624
- * OpenCode Zen Responses Proxy
3625
- *
3626
- * Proxies OpenAI Responses API requests to OpenCode Zen.
3627
- * Used for GPT-5 series models with stateful, agentic tool-use.
3628
- */
3629
- const MAX_RETRIES = 5;
3630
- const DEFAULT_RETRY_DELAY = 500;
3631
- /**
3632
- * Parse retry delay from error response
3633
- */
3634
- function parseRetryDelay(response, errorText) {
3635
- const retryAfter = response.headers.get("Retry-After");
3636
- if (retryAfter) {
3637
- const seconds = Number.parseInt(retryAfter, 10);
3638
- if (!Number.isNaN(seconds)) return seconds * 1e3;
3639
- }
3640
- try {
3641
- const errorData = JSON.parse(errorText);
3642
- if (errorData.error?.retry_after) return errorData.error.retry_after * 1e3;
3643
- } catch {}
3644
- return DEFAULT_RETRY_DELAY;
3645
- }
3646
- /**
3647
- * Create responses via OpenCode Zen (OpenAI Responses API format)
3648
- */
3649
- async function createZenResponses(request, signal) {
3650
- const apiKey = state.zenApiKey;
3651
- if (!apiKey) throw new Error("Zen API key not configured");
3652
- consola.debug(`Zen responses request for model: ${request.model}`);
3653
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) try {
3654
- const response = await fetch("https://opencode.ai/zen/v1/responses", {
3655
- method: "POST",
3656
- headers: {
3657
- "Content-Type": "application/json",
3658
- Authorization: `Bearer ${apiKey}`
3659
- },
3660
- body: JSON.stringify(request),
3661
- signal
3662
- });
3663
- if (response.ok) return response;
3664
- const errorText = await response.text();
3665
- if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {
3666
- const retryDelay = parseRetryDelay(response, errorText);
3667
- consola.info(`Zen rate limited (${response.status}), retrying in ${retryDelay}ms...`);
3668
- await sleep(retryDelay);
3669
- continue;
3670
- }
3671
- consola.error(`Zen Responses API error: ${response.status} ${errorText}`);
3672
- throw new Error(`Zen Responses API error: ${response.status} ${errorText}`);
3673
- } catch (error) {
3674
- if (error instanceof Error && error.name === "AbortError") throw error;
3675
- if (attempt < MAX_RETRIES) {
3676
- consola.warn(`Zen request failed, retrying... (${attempt + 1})`);
3677
- await sleep(DEFAULT_RETRY_DELAY);
3678
- continue;
3679
- }
3680
- throw error;
3681
- }
3682
- throw new Error("Max retries exceeded");
3683
- }
3684
- //#endregion
3685
- //#region src/routes/zen/responses/route.ts
3686
- /**
3687
- * OpenCode Zen Responses Route
3688
- *
3689
- * Proxies OpenAI Responses API requests to Zen.
3690
- * Used for GPT-5 series models.
3691
- */
3692
- const zenResponsesRoutes = new Hono();
3693
- zenResponsesRoutes.post("/", async (c) => {
3694
- if (!state.zenMode || !state.zenApiKey) return c.json({ error: "Zen mode is not enabled. Start with --zen flag." }, 400);
3695
- try {
3696
- const body = await c.req.json();
3697
- consola.debug("Zen responses request:", body.model);
3698
- const response = await createZenResponses(body);
3699
- if (body.stream) {
3700
- const headers = new Headers();
3701
- headers.set("Content-Type", "text/event-stream");
3702
- headers.set("Cache-Control", "no-cache");
3703
- headers.set("Connection", "keep-alive");
3704
- return new Response(response.body, {
3705
- status: response.status,
3706
- headers
3707
- });
3708
- }
3709
- const data = await response.json();
3710
- return c.json(data);
3711
- } catch (error) {
3712
- consola.error("Zen responses error:", error);
3713
- return c.json({ error: {
3714
- message: error instanceof Error ? error.message : "Unknown error",
3715
- type: "zen_error"
3716
- } }, 500);
3717
- }
3718
- });
3719
- //#endregion
3720
1846
  //#region src/server.ts
3721
1847
  const server = new Hono();
3722
1848
  server.use(modelLogger());
3723
1849
  server.use(cors());
3724
1850
  server.use(apiKeyAuthMiddleware);
3725
1851
  server.get("/", (c) => c.text("Server running"));
3726
- function createSubRequest(c, basePath) {
3727
- const url = new URL(c.req.url);
3728
- url.pathname = url.pathname.slice(basePath.length) || "/";
3729
- return new Request(url.toString(), c.req.raw);
3730
- }
3731
- server.all("/chat/completions/*", async (c) => {
3732
- const req = createSubRequest(c, "/chat/completions");
3733
- if (state.zenMode) return zenCompletionRoutes.fetch(req, c.env);
3734
- if (state.antigravityMode) return antigravityChatCompletionsRoute.fetch(req, c.env);
3735
- return completionRoutes.fetch(req, c.env);
3736
- });
3737
- server.all("/chat/completions", async (c) => {
3738
- const req = createSubRequest(c, "/chat/completions");
3739
- if (state.zenMode) return zenCompletionRoutes.fetch(req, c.env);
3740
- if (state.antigravityMode) return antigravityChatCompletionsRoute.fetch(req, c.env);
3741
- return completionRoutes.fetch(req, c.env);
3742
- });
3743
- server.all("/models/*", async (c) => {
3744
- const req = createSubRequest(c, "/models");
3745
- if (state.zenMode) return zenModelRoutes.fetch(req, c.env);
3746
- if (state.antigravityMode) return antigravityModelsRoute.fetch(req, c.env);
3747
- return modelRoutes.fetch(req, c.env);
3748
- });
3749
- server.all("/models", async (c) => {
3750
- const req = createSubRequest(c, "/models");
3751
- if (state.zenMode) return zenModelRoutes.fetch(req, c.env);
3752
- if (state.antigravityMode) return antigravityModelsRoute.fetch(req, c.env);
3753
- return modelRoutes.fetch(req, c.env);
3754
- });
1852
+ server.route("/chat/completions", completionRoutes);
1853
+ server.route("/models", modelRoutes);
3755
1854
  server.route("/embeddings", embeddingRoutes);
3756
1855
  server.route("/usage", usageRoute);
3757
1856
  server.route("/token", tokenRoute);
3758
- server.all("/v1/chat/completions/*", async (c) => {
3759
- const req = createSubRequest(c, "/v1/chat/completions");
3760
- if (state.zenMode) return zenCompletionRoutes.fetch(req, c.env);
3761
- if (state.antigravityMode) return antigravityChatCompletionsRoute.fetch(req, c.env);
3762
- return completionRoutes.fetch(req, c.env);
3763
- });
3764
- server.all("/v1/chat/completions", async (c) => {
3765
- const req = createSubRequest(c, "/v1/chat/completions");
3766
- if (state.zenMode) return zenCompletionRoutes.fetch(req, c.env);
3767
- if (state.antigravityMode) return antigravityChatCompletionsRoute.fetch(req, c.env);
3768
- return completionRoutes.fetch(req, c.env);
3769
- });
3770
- server.all("/v1/models/*", async (c) => {
3771
- const req = createSubRequest(c, "/v1/models");
3772
- if (state.zenMode) return zenModelRoutes.fetch(req, c.env);
3773
- if (state.antigravityMode) return antigravityModelsRoute.fetch(req, c.env);
3774
- return modelRoutes.fetch(req, c.env);
3775
- });
3776
- server.all("/v1/models", async (c) => {
3777
- const req = createSubRequest(c, "/v1/models");
3778
- if (state.zenMode) return zenModelRoutes.fetch(req, c.env);
3779
- if (state.antigravityMode) return antigravityModelsRoute.fetch(req, c.env);
3780
- return modelRoutes.fetch(req, c.env);
3781
- });
1857
+ server.route("/v1/chat/completions", completionRoutes);
1858
+ server.route("/v1/models", modelRoutes);
3782
1859
  server.route("/v1/embeddings", embeddingRoutes);
3783
- server.all("/v1/messages/*", async (c) => {
3784
- const req = createSubRequest(c, "/v1/messages");
3785
- if (state.zenMode) return zenMessageRoutes.fetch(req, c.env);
3786
- if (state.antigravityMode) return antigravityMessagesRoute.fetch(req, c.env);
3787
- return messageRoutes.fetch(req, c.env);
3788
- });
3789
- server.all("/v1/messages", async (c) => {
3790
- const req = createSubRequest(c, "/v1/messages");
3791
- if (state.zenMode) return zenMessageRoutes.fetch(req, c.env);
3792
- if (state.antigravityMode) return antigravityMessagesRoute.fetch(req, c.env);
3793
- return messageRoutes.fetch(req, c.env);
3794
- });
3795
- server.all("/v1/responses/*", async (c) => {
3796
- const req = createSubRequest(c, "/v1/responses");
3797
- if (state.zenMode) return zenResponsesRoutes.fetch(req, c.env);
3798
- return c.json({ error: "Responses API requires Zen mode" }, 400);
3799
- });
3800
- server.all("/v1/responses", async (c) => {
3801
- const req = createSubRequest(c, "/v1/responses");
3802
- if (state.zenMode) return zenResponsesRoutes.fetch(req, c.env);
3803
- return c.json({ error: "Responses API requires Zen mode" }, 400);
3804
- });
3805
- server.route("/zen/v1/chat/completions", zenCompletionRoutes);
3806
- server.route("/zen/v1/models", zenModelRoutes);
3807
- server.route("/zen/v1/messages", zenMessageRoutes);
3808
- server.route("/zen/v1/responses", zenResponsesRoutes);
3809
- server.route("/antigravity/v1/chat/completions", antigravityChatCompletionsRoute);
3810
- server.route("/antigravity/v1/models", antigravityModelsRoute);
3811
- server.route("/antigravity/v1/messages", antigravityMessagesRoute);
1860
+ server.route("/v1/messages", messageRoutes);
3812
1861
  //#endregion
3813
1862
  //#region src/start.ts
3814
1863
  /**
3815
1864
  * Start and configure the Copilot API server according to the provided options.
3816
1865
  *
3817
- * Configures proxy and logging, initializes global state and credentials, ensures
3818
- * required paths and model data are cached, optionally generates a Claude Code
3819
- * launch command (and attempts to copy it to the clipboard), prints a usage
3820
- * viewer URL, and begins serving HTTP requests on the specified port.
3821
- *
3822
1866
  * @param options - Server startup options:
3823
1867
  * - port: Port number to listen on
3824
1868
  * - verbose: Enable verbose logging
@@ -3831,11 +1875,6 @@ server.route("/antigravity/v1/messages", antigravityMessagesRoute);
3831
1875
  * - showToken: Expose GitHub/Copilot tokens in responses for debugging
3832
1876
  * - proxyEnv: Initialize proxy settings from environment variables
3833
1877
  * - apiKeys: Optional list of API keys to enable API key authentication
3834
- * - zen: Enable OpenCode Zen mode (proxy to Zen instead of GitHub Copilot)
3835
- * - zenApiKey: OpenCode Zen API key (optional; if omitted will prompt for setup)
3836
- * - antigravity: Enable Google Antigravity mode
3837
- * - antigravityClientId: Google OAuth Client ID (optional; overrides env/default)
3838
- * - antigravityClientSecret: Google OAuth Client Secret (optional; overrides env/default)
3839
1878
  */
3840
1879
  async function runServer(options) {
3841
1880
  const savedProxyApplied = await applyProxyConfig();
@@ -3854,94 +1893,36 @@ async function runServer(options) {
3854
1893
  state.apiKeys = options.apiKeys;
3855
1894
  if (state.apiKeys && state.apiKeys.length > 0) consola.info(`API key authentication enabled with ${state.apiKeys.length} key(s)`);
3856
1895
  await ensurePaths();
3857
- if (options.zen) {
3858
- consola.info("OpenCode Zen mode enabled");
3859
- state.zenMode = true;
3860
- if (options.zenApiKey) {
3861
- state.zenApiKey = options.zenApiKey;
3862
- consola.info("Using provided Zen API key");
3863
- } else {
3864
- const { setupZenApiKey, loadZenAuth } = await import("./auth-g7psLP1B.js");
3865
- const existingAuth = await loadZenAuth();
3866
- if (existingAuth) {
3867
- state.zenApiKey = existingAuth.apiKey;
3868
- consola.info("Using existing Zen API key");
3869
- } else state.zenApiKey = await setupZenApiKey();
3870
- }
3871
- const { cacheZenModels } = await import("./get-models-onnSXkNI.js");
3872
- await cacheZenModels();
3873
- consola.info(`Available Zen models: \n${state.zenModels?.data.map((model) => `- ${model.id}`).join("\n")}`);
3874
- } else if (options.antigravity) {
3875
- consola.info("Google Antigravity mode enabled");
3876
- state.antigravityMode = true;
3877
- const { loadAntigravityAuth, setupAntigravity, getCurrentAccount, hasApiKey, getApiKey, setOAuthCredentials } = await import("./auth-DreFwlx2.js");
3878
- if (options.antigravityClientId && options.antigravityClientSecret) {
3879
- setOAuthCredentials(options.antigravityClientId, options.antigravityClientSecret);
3880
- consola.info("Using provided OAuth credentials from CLI");
3881
- }
3882
- if (hasApiKey()) {
3883
- consola.info("Using Gemini API Key for authentication (from GEMINI_API_KEY)");
3884
- consola.info(`API Key: ${getApiKey()?.slice(0, 10) ?? ""}...`);
3885
- } else {
3886
- const existingAuth = await loadAntigravityAuth();
3887
- if (!existingAuth || existingAuth.accounts.length === 0) {
3888
- consola.warn("No Antigravity accounts found and no GEMINI_API_KEY set");
3889
- consola.info("");
3890
- consola.info("You can authenticate using one of these methods:");
3891
- consola.info("");
3892
- consola.info("Method 1: API Key (Recommended - Simplest)");
3893
- consola.info(" Set environment variable: GEMINI_API_KEY=your_api_key");
3894
- consola.info(" Get your API key from: https://aistudio.google.com/apikey");
3895
- consola.info("");
3896
- consola.info("Method 2: OAuth (Current setup)");
3897
- consola.info(" Will proceed with OAuth login flow...");
3898
- consola.info("");
3899
- await setupAntigravity();
3900
- } else {
3901
- const enabledCount = existingAuth.accounts.filter((a) => a.enable).length;
3902
- consola.info(`Found ${existingAuth.accounts.length} Antigravity accounts (${enabledCount} enabled)`);
3903
- }
3904
- if (!await getCurrentAccount() && !hasApiKey()) throw new Error("No enabled Antigravity accounts available");
3905
- }
3906
- const { getAntigravityModels } = await import("./get-models-PKzVxQmq.js");
3907
- const models = await getAntigravityModels();
3908
- state.antigravityModels = models;
3909
- consola.info(`Available Antigravity models: \n${models.data.map((model) => `- ${model.id}`).join("\n")}`);
3910
- } else {
3911
- await cacheVSCodeVersion();
3912
- if (options.githubToken) {
3913
- state.githubToken = options.githubToken;
3914
- consola.info("Using provided GitHub token");
3915
- try {
3916
- const { getGitHubUser } = await import("./get-user-CGhBmkXO.js");
3917
- const user = await getGitHubUser();
3918
- consola.info(`Logged in as ${user.login}`);
3919
- } catch (error) {
3920
- consola.error("Provided GitHub token is invalid");
3921
- throw error;
3922
- }
3923
- } else await setupGitHubToken();
1896
+ await cacheVSCodeVersion();
1897
+ if (options.githubToken) {
1898
+ state.githubToken = options.githubToken;
1899
+ consola.info("Using provided GitHub token");
3924
1900
  try {
3925
- await setupCopilotToken();
1901
+ const { getGitHubUser } = await import("./get-user-D2HfoqjP.js");
1902
+ const user = await getGitHubUser();
1903
+ consola.info(`Logged in as ${user.login}`);
3926
1904
  } catch (error) {
3927
- const { HTTPError } = await import("./error-Djpro28X.js");
3928
- if (error instanceof HTTPError && error.response.status === 401) {
3929
- consola.error("Failed to get Copilot token - GitHub token may be invalid or Copilot access revoked");
3930
- const { clearGithubToken } = await import("./token-CoKq3Guw.js");
3931
- await clearGithubToken();
3932
- consola.info("Please restart to re-authenticate");
3933
- }
1905
+ consola.error("Provided GitHub token is invalid");
3934
1906
  throw error;
3935
1907
  }
3936
- await cacheModels();
3937
- consola.info(`Available models: \n${state.models?.data.map((model) => `- ${model.id}`).join("\n")}`);
1908
+ } else await setupGitHubToken();
1909
+ try {
1910
+ await setupCopilotToken();
1911
+ } catch (error) {
1912
+ const { HTTPError } = await import("./error-BfWAfRit.js");
1913
+ if (error instanceof HTTPError && error.response.status === 401) {
1914
+ consola.error("Failed to get Copilot token - GitHub token may be invalid or Copilot access revoked");
1915
+ const { clearGithubToken } = await import("./token-DT9ko4dY.js");
1916
+ await clearGithubToken();
1917
+ consola.info("Please restart to re-authenticate");
1918
+ }
1919
+ throw error;
3938
1920
  }
1921
+ await cacheModels();
1922
+ consola.info(`Available models: \n${state.models?.data.map((model) => `- ${model.id}`).join("\n")}`);
3939
1923
  const serverUrl = `http://localhost:${options.port}`;
3940
1924
  if (options.claudeCode) {
3941
- let modelList;
3942
- if (state.zenMode) modelList = state.zenModels?.data;
3943
- else if (state.antigravityMode) modelList = state.antigravityModels?.data;
3944
- else modelList = state.models?.data;
1925
+ const modelList = state.models?.data;
3945
1926
  invariant(modelList, "Models should be loaded by now");
3946
1927
  const selectedModel = await consola.prompt("Select a model to use with Claude Code", {
3947
1928
  type: "select",
@@ -3983,7 +1964,6 @@ await runMain(defineCommand({
3983
1964
  description: "A wrapper around GitHub Copilot API to make it OpenAI/Anthropic compatible. Fork with bug fixes and improvements."
3984
1965
  },
3985
1966
  subCommands: {
3986
- antigravity,
3987
1967
  auth,
3988
1968
  start: defineCommand({
3989
1969
  meta: {
@@ -4049,29 +2029,6 @@ await runMain(defineCommand({
4049
2029
  "api-key": {
4050
2030
  type: "string",
4051
2031
  description: "API keys for authentication"
4052
- },
4053
- zen: {
4054
- alias: "z",
4055
- type: "boolean",
4056
- default: false,
4057
- description: "Enable OpenCode Zen mode (proxy to Zen instead of GitHub Copilot)"
4058
- },
4059
- "zen-api-key": {
4060
- type: "string",
4061
- description: "OpenCode Zen API key (get from https://opencode.ai/zen)"
4062
- },
4063
- antigravity: {
4064
- type: "boolean",
4065
- default: false,
4066
- description: "Enable Google Antigravity mode (proxy to Antigravity instead of GitHub Copilot)"
4067
- },
4068
- "antigravity-client-id": {
4069
- type: "string",
4070
- description: "Google OAuth Client ID for Antigravity (create at https://console.cloud.google.com/apis/credentials)"
4071
- },
4072
- "antigravity-client-secret": {
4073
- type: "string",
4074
- description: "Google OAuth Client Secret for Antigravity"
4075
2032
  }
4076
2033
  },
4077
2034
  run({ args }) {
@@ -4091,12 +2048,7 @@ await runMain(defineCommand({
4091
2048
  claudeCode: args["claude-code"],
4092
2049
  showToken: args["show-token"],
4093
2050
  proxyEnv: args["proxy-env"],
4094
- apiKeys,
4095
- zen: args.zen,
4096
- zenApiKey: args["zen-api-key"],
4097
- antigravity: args.antigravity,
4098
- antigravityClientId: args["antigravity-client-id"],
4099
- antigravityClientSecret: args["antigravity-client-secret"]
2051
+ apiKeys
4100
2052
  });
4101
2053
  }
4102
2054
  }),