copilot-api-plus 1.0.31 → 1.0.33

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,24 @@
1
1
  #!/usr/bin/env node
2
- import { PATHS, ensurePaths } from "./paths-Ch0ixSo2.js";
2
+ import { PATHS, ensurePaths } from "./paths-CVYLp61D.js";
3
3
  import { state } from "./state-CcLGr8VN.js";
4
4
  import { GITHUB_API_BASE_URL, copilotBaseUrl, copilotHeaders, githubHeaders } from "./get-user-BzIEATcF.js";
5
5
  import { HTTPError, forwardError } from "./error-CvU5otz-.js";
6
- import { cacheModels, cacheVSCodeVersion, clearGithubToken, isNullish, setupCopilotToken, setupGitHubToken, sleep } from "./token-BUmQ_BcM.js";
7
- import { clearAntigravityAuth, disableCurrentAccount, getAntigravityAuthPath, getApiKey, getValidAccessToken, rotateAccount } from "./auth-y23hLerx.js";
8
- import { clearZenAuth, getZenAuthPath } from "./auth-OZNLGzjK.js";
9
- import { getAntigravityModels, getAntigravityUsage, isThinkingModel } from "./get-models-B5kAooWg.js";
6
+ import { cacheModels, cacheVSCodeVersion, clearGithubToken, isNullish, setupCopilotToken, setupGitHubToken, sleep } from "./token-ClgudjZm.js";
7
+ import { clearAntigravityAuth, disableCurrentAccount, getAntigravityAuthPath, getApiKey, getValidAccessToken, rotateAccount } from "./auth-CM_ilreU.js";
8
+ import { clearZenAuth, getZenAuthPath } from "./auth-T55-Bhoo.js";
9
+ import { getAntigravityModels, getAntigravityUsage, isThinkingModel } from "./get-models-DMdiCNoU.js";
10
10
  import { createRequire } from "node:module";
11
11
  import { defineCommand, runMain } from "citty";
12
12
  import consola from "consola";
13
13
  import fs from "node:fs/promises";
14
- import os from "node:os";
15
14
  import path from "node:path";
15
+ import os from "node:os";
16
+ import { getProxyForUrl } from "proxy-from-env";
17
+ import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
16
18
  import * as p from "@clack/prompts";
17
19
  import clipboard from "clipboardy";
18
20
  import { serve } from "srvx";
19
21
  import invariant from "tiny-invariant";
20
- import { getProxyForUrl } from "proxy-from-env";
21
- import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
22
22
  import { execSync } from "node:child_process";
23
23
  import process$1 from "node:process";
24
24
  import { Hono } from "hono";
@@ -35,951 +35,1076 @@ var __commonJS = (cb, mod) => function() {
35
35
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
36
36
 
37
37
  //#endregion
38
- //#region src/auth.ts
39
- async function runAuth(options$1) {
40
- if (options$1.verbose) {
41
- consola.level = 5;
42
- consola.info("Verbose logging enabled");
43
- }
44
- state.showToken = options$1.showToken;
45
- await ensurePaths();
46
- await setupGitHubToken({ force: true });
47
- consola.success("GitHub token written to", PATHS.GITHUB_TOKEN_PATH);
48
- }
49
- const auth = defineCommand({
50
- meta: {
51
- name: "auth",
52
- description: "Run GitHub auth flow without running the server"
53
- },
54
- args: {
55
- verbose: {
56
- alias: "v",
57
- type: "boolean",
58
- default: false,
59
- description: "Enable verbose logging"
38
+ //#region node_modules/dotenv/package.json
39
+ var require_package = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/package.json": ((exports, module) => {
40
+ module.exports = {
41
+ "name": "dotenv",
42
+ "version": "17.2.3",
43
+ "description": "Loads environment variables from .env file",
44
+ "main": "lib/main.js",
45
+ "types": "lib/main.d.ts",
46
+ "exports": {
47
+ ".": {
48
+ "types": "./lib/main.d.ts",
49
+ "require": "./lib/main.js",
50
+ "default": "./lib/main.js"
51
+ },
52
+ "./config": "./config.js",
53
+ "./config.js": "./config.js",
54
+ "./lib/env-options": "./lib/env-options.js",
55
+ "./lib/env-options.js": "./lib/env-options.js",
56
+ "./lib/cli-options": "./lib/cli-options.js",
57
+ "./lib/cli-options.js": "./lib/cli-options.js",
58
+ "./package.json": "./package.json"
60
59
  },
61
- "show-token": {
62
- type: "boolean",
63
- default: false,
64
- description: "Show GitHub token on auth"
65
- }
66
- },
67
- run({ args }) {
68
- return runAuth({
69
- verbose: args.verbose,
70
- showToken: args["show-token"]
71
- });
72
- }
73
- });
74
-
75
- //#endregion
76
- //#region src/services/github/get-copilot-usage.ts
77
- const getCopilotUsage = async () => {
78
- const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, { headers: githubHeaders(state) });
79
- if (!response.ok) throw new HTTPError("Failed to get Copilot usage", response);
80
- return await response.json();
81
- };
82
-
83
- //#endregion
84
- //#region src/check-usage.ts
85
- const checkUsage = defineCommand({
86
- meta: {
87
- name: "check-usage",
88
- description: "Show current GitHub Copilot usage/quota information"
89
- },
90
- async run() {
91
- await ensurePaths();
92
- await setupGitHubToken();
93
- try {
94
- const usage = await getCopilotUsage();
95
- const premium = usage.quota_snapshots.premium_interactions;
96
- const premiumTotal = premium.entitlement;
97
- const premiumUsed = premiumTotal - premium.remaining;
98
- const premiumPercentUsed = premiumTotal > 0 ? premiumUsed / premiumTotal * 100 : 0;
99
- const premiumPercentRemaining = premium.percent_remaining;
100
- function summarizeQuota(name, snap) {
101
- if (!snap) return `${name}: N/A`;
102
- const total = snap.entitlement;
103
- const used = total - snap.remaining;
104
- const percentUsed = total > 0 ? used / total * 100 : 0;
105
- const percentRemaining = snap.percent_remaining;
106
- return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
107
- }
108
- const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
109
- const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
110
- const completionsLine = summarizeQuota("Completions", usage.quota_snapshots.completions);
111
- consola.box(`Copilot Usage (plan: ${usage.copilot_plan})\nQuota resets: ${usage.quota_reset_date}\n\nQuotas:\n ${premiumLine}\n ${chatLine}\n ${completionsLine}`);
112
- } catch (err) {
113
- consola.error("Failed to fetch Copilot usage:", err);
114
- process.exit(1);
115
- }
116
- }
117
- });
60
+ "scripts": {
61
+ "dts-check": "tsc --project tests/types/tsconfig.json",
62
+ "lint": "standard",
63
+ "pretest": "npm run lint && npm run dts-check",
64
+ "test": "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
65
+ "test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
66
+ "prerelease": "npm test",
67
+ "release": "standard-version"
68
+ },
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "git://github.com/motdotla/dotenv.git"
72
+ },
73
+ "homepage": "https://github.com/motdotla/dotenv#readme",
74
+ "funding": "https://dotenvx.com",
75
+ "keywords": [
76
+ "dotenv",
77
+ "env",
78
+ ".env",
79
+ "environment",
80
+ "variables",
81
+ "config",
82
+ "settings"
83
+ ],
84
+ "readmeFilename": "README.md",
85
+ "license": "BSD-2-Clause",
86
+ "devDependencies": {
87
+ "@types/node": "^18.11.3",
88
+ "decache": "^4.6.2",
89
+ "sinon": "^14.0.1",
90
+ "standard": "^17.0.0",
91
+ "standard-version": "^9.5.0",
92
+ "tap": "^19.2.0",
93
+ "typescript": "^4.8.4"
94
+ },
95
+ "engines": { "node": ">=12" },
96
+ "browser": { "fs": false }
97
+ };
98
+ }) });
118
99
 
119
100
  //#endregion
120
- //#region src/lib/config.ts
121
- const CONFIG_FILENAME = "config.json";
122
- /**
123
- * Get the path to the config file
124
- */
125
- function getConfigPath() {
126
- return path.join(PATHS.DATA_DIR, CONFIG_FILENAME);
127
- }
128
- /**
129
- * Load configuration from file
130
- */
131
- async function loadConfig() {
132
- try {
133
- const configPath = getConfigPath();
134
- const content = await fs.readFile(configPath);
135
- return JSON.parse(content);
136
- } catch {
137
- return {};
101
+ //#region node_modules/dotenv/lib/main.js
102
+ var require_main = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/lib/main.js": ((exports, module) => {
103
+ const fs$1 = __require("fs");
104
+ const path$1 = __require("path");
105
+ const os$1 = __require("os");
106
+ const crypto$1 = __require("crypto");
107
+ const version = require_package().version;
108
+ const TIPS = [
109
+ "🔐 encrypt with Dotenvx: https://dotenvx.com",
110
+ "🔐 prevent committing .env to code: https://dotenvx.com/precommit",
111
+ "🔐 prevent building .env in docker: https://dotenvx.com/prebuild",
112
+ "📡 add observability to secrets: https://dotenvx.com/ops",
113
+ "👥 sync secrets across teammates & machines: https://dotenvx.com/ops",
114
+ "🗂️ backup and recover secrets: https://dotenvx.com/ops",
115
+ "✅ audit secrets and track compliance: https://dotenvx.com/ops",
116
+ "🔄 add secrets lifecycle management: https://dotenvx.com/ops",
117
+ "🔑 add access controls to secrets: https://dotenvx.com/ops",
118
+ "🛠️ run anywhere with `dotenvx run -- yourcommand`",
119
+ "⚙️ specify custom .env file path with { path: '/custom/path/.env' }",
120
+ "⚙️ enable debug logging with { debug: true }",
121
+ "⚙️ override existing env vars with { override: true }",
122
+ "⚙️ suppress all logs with { quiet: true }",
123
+ "⚙️ write to custom object with { processEnv: myObject }",
124
+ "⚙️ load multiple .env files with { path: ['.env.local', '.env'] }"
125
+ ];
126
+ function _getRandomTip() {
127
+ return TIPS[Math.floor(Math.random() * TIPS.length)];
138
128
  }
139
- }
140
- /**
141
- * Save configuration to file
142
- */
143
- async function saveConfig(config$1) {
144
- const configPath = getConfigPath();
145
- await fs.writeFile(configPath, JSON.stringify(config$1, null, 2), "utf8");
146
- consola.debug(`Configuration saved to ${configPath}`);
147
- }
148
- /**
149
- * Get proxy configuration
150
- */
151
- async function getProxyConfig() {
152
- return (await loadConfig()).proxy;
153
- }
154
- /**
155
- * Save proxy configuration
156
- */
157
- async function saveProxyConfig(proxyConfig) {
158
- const config$1 = await loadConfig();
159
- config$1.proxy = proxyConfig;
160
- await saveConfig(config$1);
161
- }
162
- /**
163
- * Clear proxy configuration
164
- */
165
- async function clearProxyConfig() {
166
- const config$1 = await loadConfig();
167
- delete config$1.proxy;
168
- await saveConfig(config$1);
169
- }
170
- /**
171
- * Apply saved proxy configuration to environment variables
172
- * This should be called at startup to restore proxy settings
173
- */
174
- async function applyProxyConfig() {
175
- const proxyConfig = await getProxyConfig();
176
- if (!proxyConfig || !proxyConfig.enabled) return false;
177
- if (proxyConfig.httpProxy) {
178
- process.env.HTTP_PROXY = proxyConfig.httpProxy;
179
- process.env.http_proxy = proxyConfig.httpProxy;
129
+ function parseBoolean(value) {
130
+ if (typeof value === "string") return ![
131
+ "false",
132
+ "0",
133
+ "no",
134
+ "off",
135
+ ""
136
+ ].includes(value.toLowerCase());
137
+ return Boolean(value);
180
138
  }
181
- if (proxyConfig.httpsProxy) {
182
- process.env.HTTPS_PROXY = proxyConfig.httpsProxy;
183
- process.env.https_proxy = proxyConfig.httpsProxy;
139
+ function supportsAnsi() {
140
+ return process.stdout.isTTY;
184
141
  }
185
- if (proxyConfig.noProxy) {
186
- process.env.NO_PROXY = proxyConfig.noProxy;
187
- process.env.no_proxy = proxyConfig.noProxy;
142
+ function dim(text) {
143
+ return supportsAnsi() ? `\x1b[2m${text}\x1b[0m` : text;
188
144
  }
189
- consola.info("Proxy configuration loaded from saved settings");
190
- if (proxyConfig.httpProxy) consola.info(` HTTP_PROXY: ${proxyConfig.httpProxy}`);
191
- if (proxyConfig.httpsProxy) consola.info(` HTTPS_PROXY: ${proxyConfig.httpsProxy}`);
192
- if (proxyConfig.noProxy) consola.info(` NO_PROXY: ${proxyConfig.noProxy}`);
193
- return true;
194
- }
195
-
196
- //#endregion
197
- //#region src/debug.ts
198
- async function getPackageVersion() {
199
- try {
200
- const packageJsonPath = new URL("../package.json", import.meta.url).pathname;
201
- return JSON.parse(await fs.readFile(packageJsonPath)).version;
202
- } catch {
203
- return "unknown";
204
- }
205
- }
206
- function getRuntimeInfo() {
207
- const isBun = typeof Bun !== "undefined";
208
- return {
209
- name: isBun ? "bun" : "node",
210
- version: isBun ? Bun.version : process.version.slice(1),
211
- platform: os.platform(),
212
- arch: os.arch()
213
- };
214
- }
215
- async function checkTokenExists() {
216
- try {
217
- if (!(await fs.stat(PATHS.GITHUB_TOKEN_PATH)).isFile()) return false;
218
- return (await fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8")).trim().length > 0;
219
- } catch {
220
- return false;
221
- }
222
- }
223
- async function checkFileExists(path$2) {
224
- try {
225
- if (!(await fs.stat(path$2)).isFile()) return false;
226
- return (await fs.readFile(path$2, "utf8")).trim().length > 0;
227
- } catch {
228
- return false;
229
- }
230
- }
231
- async function getDebugInfo() {
232
- const zenAuthPath = getZenAuthPath();
233
- const antigravityAuthPath = getAntigravityAuthPath();
234
- const [version$1, githubExists, zenExists, antigravityExists, proxyConfig] = await Promise.all([
235
- getPackageVersion(),
236
- checkTokenExists(),
237
- checkFileExists(zenAuthPath),
238
- checkFileExists(antigravityAuthPath),
239
- getProxyConfig()
240
- ]);
241
- return {
242
- version: version$1,
243
- runtime: getRuntimeInfo(),
244
- paths: {
245
- APP_DIR: PATHS.APP_DIR,
246
- GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,
247
- ZEN_AUTH_PATH: zenAuthPath,
248
- ANTIGRAVITY_AUTH_PATH: antigravityAuthPath
249
- },
250
- credentials: {
251
- github: githubExists,
252
- zen: zenExists,
253
- antigravity: antigravityExists
254
- },
255
- proxy: proxyConfig
256
- };
257
- }
258
- function printDebugInfoPlain(info) {
259
- let proxyStatus = "Not configured";
260
- if (info.proxy) proxyStatus = info.proxy.enabled ? `Enabled (${info.proxy.httpProxy || info.proxy.httpsProxy})` : "Disabled";
261
- consola.info(`copilot-api-plus debug
262
-
263
- Version: ${info.version}
264
- Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})
265
-
266
- Paths:
267
- APP_DIR: ${info.paths.APP_DIR}
268
- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}
269
- ZEN_AUTH_PATH: ${info.paths.ZEN_AUTH_PATH}
270
- ANTIGRAVITY_AUTH_PATH: ${info.paths.ANTIGRAVITY_AUTH_PATH}
271
-
272
- Credentials:
273
- GitHub Copilot: ${info.credentials.github ? "✅ Configured" : "❌ Not configured"}
274
- OpenCode Zen: ${info.credentials.zen ? "✅ Configured" : "❌ Not configured"}
275
- Google Antigravity: ${info.credentials.antigravity ? "✅ Configured" : "❌ Not configured"}
276
-
277
- Proxy: ${proxyStatus}`);
278
- }
279
- function printDebugInfoJson(info) {
280
- console.log(JSON.stringify(info, null, 2));
281
- }
282
- async function runDebug(options$1) {
283
- const debugInfo = await getDebugInfo();
284
- if (options$1.json) printDebugInfoJson(debugInfo);
285
- else printDebugInfoPlain(debugInfo);
286
- }
287
- const debug = defineCommand({
288
- meta: {
289
- name: "debug",
290
- description: "Print debug information about the application"
291
- },
292
- args: { json: {
293
- type: "boolean",
294
- default: false,
295
- description: "Output debug information as JSON"
296
- } },
297
- run({ args }) {
298
- return runDebug({ json: args.json });
299
- }
300
- });
301
-
302
- //#endregion
303
- //#region src/logout.ts
304
- async function runLogout(options$1) {
305
- await ensurePaths();
306
- if (options$1.all) {
307
- await clearGithubToken();
308
- await clearZenAuth();
309
- await clearAntigravityAuth();
310
- consola.success("Logged out from all services");
311
- consola.info(`GitHub token: ${PATHS.GITHUB_TOKEN_PATH}`);
312
- consola.info(`Zen API key: ${getZenAuthPath()}`);
313
- consola.info(`Antigravity accounts: ${getAntigravityAuthPath()}`);
314
- return;
145
+ const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
146
+ function parse(src) {
147
+ const obj = {};
148
+ let lines = src.toString();
149
+ lines = lines.replace(/\r\n?/gm, "\n");
150
+ let match;
151
+ while ((match = LINE.exec(lines)) != null) {
152
+ const key = match[1];
153
+ let value = match[2] || "";
154
+ value = value.trim();
155
+ const maybeQuote = value[0];
156
+ value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
157
+ if (maybeQuote === "\"") {
158
+ value = value.replace(/\\n/g, "\n");
159
+ value = value.replace(/\\r/g, "\r");
160
+ }
161
+ obj[key] = value;
162
+ }
163
+ return obj;
315
164
  }
316
- if (options$1.github) {
317
- await clearGithubToken();
318
- consola.success("Logged out from GitHub Copilot");
319
- consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
320
- return;
165
+ function _parseVault(options$1) {
166
+ options$1 = options$1 || {};
167
+ const vaultPath = _vaultPath(options$1);
168
+ options$1.path = vaultPath;
169
+ const result = DotenvModule.configDotenv(options$1);
170
+ if (!result.parsed) {
171
+ const err = /* @__PURE__ */ new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
172
+ err.code = "MISSING_DATA";
173
+ throw err;
174
+ }
175
+ const keys = _dotenvKey(options$1).split(",");
176
+ const length = keys.length;
177
+ let decrypted;
178
+ for (let i = 0; i < length; i++) try {
179
+ const key = keys[i].trim();
180
+ const attrs = _instructions(result, key);
181
+ decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
182
+ break;
183
+ } catch (error) {
184
+ if (i + 1 >= length) throw error;
185
+ }
186
+ return DotenvModule.parse(decrypted);
321
187
  }
322
- if (options$1.zen) {
323
- await clearZenAuth();
324
- consola.success("Logged out from OpenCode Zen");
325
- consola.info(`Zen API key location: ${getZenAuthPath()}`);
326
- return;
188
+ function _warn(message) {
189
+ console.error(`[dotenv@${version}][WARN] ${message}`);
327
190
  }
328
- if (options$1.antigravity) {
329
- await clearAntigravityAuth();
330
- consola.success("Logged out from Google Antigravity");
331
- consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
332
- return;
191
+ function _debug(message) {
192
+ console.log(`[dotenv@${version}][DEBUG] ${message}`);
333
193
  }
334
- switch (await consola.prompt("Which credentials do you want to clear?", {
335
- type: "select",
336
- options: [
337
- "GitHub Copilot token",
338
- "OpenCode Zen API key",
339
- "Google Antigravity accounts",
340
- "All credentials"
341
- ]
342
- })) {
343
- case "GitHub Copilot token":
344
- await clearGithubToken();
345
- consola.success("Logged out from GitHub Copilot");
346
- consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
347
- break;
348
- case "OpenCode Zen API key":
349
- await clearZenAuth();
350
- consola.success("Logged out from OpenCode Zen");
351
- consola.info(`Zen API key location: ${getZenAuthPath()}`);
352
- break;
353
- case "Google Antigravity accounts":
354
- await clearAntigravityAuth();
355
- consola.success("Logged out from Google Antigravity");
356
- consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
357
- break;
358
- case "All credentials":
359
- await clearGithubToken();
360
- await clearZenAuth();
361
- await clearAntigravityAuth();
362
- consola.success("Logged out from all services");
363
- break;
194
+ function _log(message) {
195
+ console.log(`[dotenv@${version}] ${message}`);
364
196
  }
365
- }
366
- const logout = defineCommand({
367
- meta: {
368
- name: "logout",
369
- description: "Clear stored credentials and logout"
370
- },
371
- args: {
372
- github: {
373
- alias: "g",
374
- type: "boolean",
375
- default: false,
376
- description: "Clear only GitHub Copilot token"
377
- },
378
- zen: {
379
- alias: "z",
380
- type: "boolean",
381
- default: false,
382
- description: "Clear only OpenCode Zen API key"
383
- },
384
- antigravity: {
385
- type: "boolean",
386
- default: false,
387
- description: "Clear only Google Antigravity accounts"
388
- },
389
- all: {
390
- alias: "a",
391
- type: "boolean",
392
- default: false,
393
- description: "Clear all credentials (GitHub, Zen, and Antigravity)"
394
- }
395
- },
396
- run({ args }) {
397
- return runLogout({
398
- github: args.github,
399
- zen: args.zen,
400
- antigravity: args.antigravity,
401
- all: args.all
402
- });
197
+ function _dotenvKey(options$1) {
198
+ if (options$1 && options$1.DOTENV_KEY && options$1.DOTENV_KEY.length > 0) return options$1.DOTENV_KEY;
199
+ if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) return process.env.DOTENV_KEY;
200
+ return "";
403
201
  }
404
- });
405
-
406
- //#endregion
407
- //#region src/proxy-config.ts
408
- const proxy = defineCommand({
409
- meta: {
410
- name: "proxy",
411
- description: "Configure proxy settings (persistent)"
412
- },
413
- args: {
414
- set: {
415
- type: "boolean",
416
- default: false,
417
- description: "Set proxy configuration interactively"
418
- },
419
- enable: {
420
- type: "boolean",
421
- default: false,
422
- description: "Enable saved proxy configuration"
423
- },
424
- disable: {
425
- type: "boolean",
426
- default: false,
427
- description: "Disable proxy (keep settings)"
428
- },
429
- clear: {
430
- type: "boolean",
431
- default: false,
432
- description: "Clear all proxy settings"
433
- },
434
- show: {
435
- type: "boolean",
436
- default: false,
437
- description: "Show current proxy configuration"
438
- },
439
- "http-proxy": {
440
- type: "string",
441
- description: "HTTP proxy URL (e.g., http://proxy:8080)"
442
- },
443
- "https-proxy": {
444
- type: "string",
445
- description: "HTTPS proxy URL (e.g., http://proxy:8080)"
446
- },
447
- "no-proxy": {
448
- type: "string",
449
- description: "Comma-separated list of hosts to bypass proxy"
450
- }
451
- },
452
- async run({ args }) {
453
- await ensurePaths();
454
- if (args.show || !args.set && !args.enable && !args.disable && !args.clear && !args["http-proxy"] && !args["https-proxy"]) {
455
- const config$1 = await getProxyConfig();
456
- if (!config$1) {
457
- consola.info("No proxy configuration saved.");
458
- consola.info("");
459
- consola.info("To configure proxy, use one of:");
460
- consola.info(" copilot-api-plus proxy --set # Interactive setup");
461
- consola.info(" copilot-api-plus proxy --http-proxy http://proxy:8080 # Direct set");
462
- return;
202
+ function _instructions(result, dotenvKey) {
203
+ let uri;
204
+ try {
205
+ uri = new URL(dotenvKey);
206
+ } catch (error) {
207
+ if (error.code === "ERR_INVALID_URL") {
208
+ 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");
209
+ err.code = "INVALID_DOTENV_KEY";
210
+ throw err;
463
211
  }
464
- consola.info("Current proxy configuration:");
465
- consola.info(` Status: ${config$1.enabled ? "✅ Enabled" : "❌ Disabled"}`);
466
- if (config$1.httpProxy) consola.info(` HTTP_PROXY: ${config$1.httpProxy}`);
467
- if (config$1.httpsProxy) consola.info(` HTTPS_PROXY: ${config$1.httpsProxy}`);
468
- if (config$1.noProxy) consola.info(` NO_PROXY: ${config$1.noProxy}`);
469
- return;
212
+ throw error;
470
213
  }
471
- if (args.clear) {
472
- await clearProxyConfig();
473
- consola.success("Proxy configuration cleared.");
474
- return;
214
+ const key = uri.password;
215
+ if (!key) {
216
+ const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing key part");
217
+ err.code = "INVALID_DOTENV_KEY";
218
+ throw err;
475
219
  }
476
- if (args.enable) {
477
- const config$1 = await getProxyConfig();
478
- if (!config$1) {
479
- consola.error("No proxy configuration saved. Use --set to configure first.");
480
- return;
481
- }
482
- config$1.enabled = true;
483
- await saveProxyConfig(config$1);
484
- consola.success("Proxy enabled. It will be used on next server start.");
485
- return;
220
+ const environment = uri.searchParams.get("environment");
221
+ if (!environment) {
222
+ const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing environment part");
223
+ err.code = "INVALID_DOTENV_KEY";
224
+ throw err;
486
225
  }
487
- if (args.disable) {
488
- const config$1 = await getProxyConfig();
489
- if (!config$1) {
490
- consola.info("No proxy configuration to disable.");
491
- return;
492
- }
493
- config$1.enabled = false;
494
- await saveProxyConfig(config$1);
495
- consola.success("Proxy disabled. Settings are preserved.");
496
- return;
226
+ const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
227
+ const ciphertext = result.parsed[environmentKey];
228
+ if (!ciphertext) {
229
+ const err = /* @__PURE__ */ new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
230
+ err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
231
+ throw err;
497
232
  }
498
- if (args["http-proxy"] || args["https-proxy"]) {
499
- const newConfig = {
500
- enabled: true,
501
- httpProxy: args["http-proxy"],
502
- httpsProxy: args["https-proxy"] || args["http-proxy"],
503
- noProxy: args["no-proxy"]
504
- };
505
- await saveProxyConfig(newConfig);
506
- consola.success("Proxy configuration saved and enabled.");
507
- consola.info(` HTTP_PROXY: ${newConfig.httpProxy || "(not set)"}`);
508
- consola.info(` HTTPS_PROXY: ${newConfig.httpsProxy || "(not set)"}`);
509
- if (newConfig.noProxy) consola.info(` NO_PROXY: ${newConfig.noProxy}`);
510
- return;
233
+ return {
234
+ ciphertext,
235
+ key
236
+ };
237
+ }
238
+ function _vaultPath(options$1) {
239
+ let possibleVaultPath = null;
240
+ if (options$1 && options$1.path && options$1.path.length > 0) if (Array.isArray(options$1.path)) {
241
+ for (const filepath of options$1.path) if (fs$1.existsSync(filepath)) possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
242
+ } else possibleVaultPath = options$1.path.endsWith(".vault") ? options$1.path : `${options$1.path}.vault`;
243
+ else possibleVaultPath = path$1.resolve(process.cwd(), ".env.vault");
244
+ if (fs$1.existsSync(possibleVaultPath)) return possibleVaultPath;
245
+ return null;
246
+ }
247
+ function _resolveHome(envPath) {
248
+ return envPath[0] === "~" ? path$1.join(os$1.homedir(), envPath.slice(1)) : envPath;
249
+ }
250
+ function _configVault(options$1) {
251
+ const debug$1 = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options$1 && options$1.debug);
252
+ const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options$1 && options$1.quiet);
253
+ if (debug$1 || !quiet) _log("Loading env from encrypted .env.vault");
254
+ const parsed = DotenvModule._parseVault(options$1);
255
+ let processEnv = process.env;
256
+ if (options$1 && options$1.processEnv != null) processEnv = options$1.processEnv;
257
+ DotenvModule.populate(processEnv, parsed, options$1);
258
+ return { parsed };
259
+ }
260
+ function configDotenv(options$1) {
261
+ const dotenvPath = path$1.resolve(process.cwd(), ".env");
262
+ let encoding = "utf8";
263
+ let processEnv = process.env;
264
+ if (options$1 && options$1.processEnv != null) processEnv = options$1.processEnv;
265
+ let debug$1 = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options$1 && options$1.debug);
266
+ let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options$1 && options$1.quiet);
267
+ if (options$1 && options$1.encoding) encoding = options$1.encoding;
268
+ else if (debug$1) _debug("No encoding is specified. UTF-8 is used by default");
269
+ let optionPaths = [dotenvPath];
270
+ if (options$1 && options$1.path) if (!Array.isArray(options$1.path)) optionPaths = [_resolveHome(options$1.path)];
271
+ else {
272
+ optionPaths = [];
273
+ for (const filepath of options$1.path) optionPaths.push(_resolveHome(filepath));
511
274
  }
512
- if (args.set) {
513
- p.intro("Proxy Configuration");
514
- const existingConfig = await getProxyConfig();
515
- const httpProxy = await p.text({
516
- message: "HTTP Proxy URL",
517
- placeholder: "http://proxy:8080",
518
- initialValue: existingConfig?.httpProxy || ""
519
- });
520
- if (p.isCancel(httpProxy)) {
521
- p.cancel("Configuration cancelled.");
522
- return;
523
- }
524
- const httpsProxy = await p.text({
525
- message: "HTTPS Proxy URL (leave empty to use HTTP proxy)",
526
- placeholder: "http://proxy:8080",
527
- initialValue: existingConfig?.httpsProxy || ""
528
- });
529
- if (p.isCancel(httpsProxy)) {
530
- p.cancel("Configuration cancelled.");
531
- return;
532
- }
533
- const noProxy = await p.text({
534
- message: "No Proxy (comma-separated hosts to bypass)",
535
- placeholder: "localhost,127.0.0.1,.local",
536
- initialValue: existingConfig?.noProxy || ""
537
- });
538
- if (p.isCancel(noProxy)) {
539
- p.cancel("Configuration cancelled.");
540
- return;
275
+ let lastError;
276
+ const parsedAll = {};
277
+ for (const path$2 of optionPaths) try {
278
+ const parsed = DotenvModule.parse(fs$1.readFileSync(path$2, { encoding }));
279
+ DotenvModule.populate(parsedAll, parsed, options$1);
280
+ } catch (e) {
281
+ if (debug$1) _debug(`Failed to load ${path$2} ${e.message}`);
282
+ lastError = e;
283
+ }
284
+ const populated = DotenvModule.populate(processEnv, parsedAll, options$1);
285
+ debug$1 = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug$1);
286
+ quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
287
+ if (debug$1 || !quiet) {
288
+ const keysCount = Object.keys(populated).length;
289
+ const shortPaths = [];
290
+ for (const filePath of optionPaths) try {
291
+ const relative = path$1.relative(process.cwd(), filePath);
292
+ shortPaths.push(relative);
293
+ } catch (e) {
294
+ if (debug$1) _debug(`Failed to load ${filePath} ${e.message}`);
295
+ lastError = e;
541
296
  }
542
- const enable = await p.confirm({
543
- message: "Enable proxy now?",
544
- initialValue: true
545
- });
546
- if (p.isCancel(enable)) {
547
- p.cancel("Configuration cancelled.");
548
- return;
297
+ _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
298
+ }
299
+ if (lastError) return {
300
+ parsed: parsedAll,
301
+ error: lastError
302
+ };
303
+ else return { parsed: parsedAll };
304
+ }
305
+ function config(options$1) {
306
+ if (_dotenvKey(options$1).length === 0) return DotenvModule.configDotenv(options$1);
307
+ const vaultPath = _vaultPath(options$1);
308
+ if (!vaultPath) {
309
+ _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
310
+ return DotenvModule.configDotenv(options$1);
311
+ }
312
+ return DotenvModule._configVault(options$1);
313
+ }
314
+ function decrypt(encrypted, keyStr) {
315
+ const key = Buffer.from(keyStr.slice(-64), "hex");
316
+ let ciphertext = Buffer.from(encrypted, "base64");
317
+ const nonce = ciphertext.subarray(0, 12);
318
+ const authTag = ciphertext.subarray(-16);
319
+ ciphertext = ciphertext.subarray(12, -16);
320
+ try {
321
+ const aesgcm = crypto$1.createDecipheriv("aes-256-gcm", key, nonce);
322
+ aesgcm.setAuthTag(authTag);
323
+ return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
324
+ } catch (error) {
325
+ const isRange = error instanceof RangeError;
326
+ const invalidKeyLength = error.message === "Invalid key length";
327
+ const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
328
+ if (isRange || invalidKeyLength) {
329
+ const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
330
+ err.code = "INVALID_DOTENV_KEY";
331
+ throw err;
332
+ } else if (decryptionFailed) {
333
+ const err = /* @__PURE__ */ new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
334
+ err.code = "DECRYPTION_FAILED";
335
+ throw err;
336
+ } else throw error;
337
+ }
338
+ }
339
+ function populate(processEnv, parsed, options$1 = {}) {
340
+ const debug$1 = Boolean(options$1 && options$1.debug);
341
+ const override = Boolean(options$1 && options$1.override);
342
+ const populated = {};
343
+ if (typeof parsed !== "object") {
344
+ const err = /* @__PURE__ */ new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
345
+ err.code = "OBJECT_REQUIRED";
346
+ throw err;
347
+ }
348
+ for (const key of Object.keys(parsed)) if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
349
+ if (override === true) {
350
+ processEnv[key] = parsed[key];
351
+ populated[key] = parsed[key];
549
352
  }
550
- await saveProxyConfig({
551
- enabled: enable,
552
- httpProxy: httpProxy || void 0,
553
- httpsProxy: httpsProxy || httpProxy || void 0,
554
- noProxy: noProxy || void 0
555
- });
556
- p.outro(`Proxy configuration saved${enable ? " and enabled" : ""}.`);
353
+ if (debug$1) if (override === true) _debug(`"${key}" is already defined and WAS overwritten`);
354
+ else _debug(`"${key}" is already defined and was NOT overwritten`);
355
+ } else {
356
+ processEnv[key] = parsed[key];
357
+ populated[key] = parsed[key];
557
358
  }
359
+ return populated;
558
360
  }
559
- });
361
+ const DotenvModule = {
362
+ configDotenv,
363
+ _configVault,
364
+ _parseVault,
365
+ config,
366
+ decrypt,
367
+ parse,
368
+ populate
369
+ };
370
+ module.exports.configDotenv = DotenvModule.configDotenv;
371
+ module.exports._configVault = DotenvModule._configVault;
372
+ module.exports._parseVault = DotenvModule._parseVault;
373
+ module.exports.config = DotenvModule.config;
374
+ module.exports.decrypt = DotenvModule.decrypt;
375
+ module.exports.parse = DotenvModule.parse;
376
+ module.exports.populate = DotenvModule.populate;
377
+ module.exports = DotenvModule;
378
+ }) });
379
+
380
+ //#endregion
381
+ //#region node_modules/dotenv/lib/env-options.js
382
+ var require_env_options = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/lib/env-options.js": ((exports, module) => {
383
+ const options = {};
384
+ if (process.env.DOTENV_CONFIG_ENCODING != null) options.encoding = process.env.DOTENV_CONFIG_ENCODING;
385
+ if (process.env.DOTENV_CONFIG_PATH != null) options.path = process.env.DOTENV_CONFIG_PATH;
386
+ if (process.env.DOTENV_CONFIG_QUIET != null) options.quiet = process.env.DOTENV_CONFIG_QUIET;
387
+ if (process.env.DOTENV_CONFIG_DEBUG != null) options.debug = process.env.DOTENV_CONFIG_DEBUG;
388
+ if (process.env.DOTENV_CONFIG_OVERRIDE != null) options.override = process.env.DOTENV_CONFIG_OVERRIDE;
389
+ if (process.env.DOTENV_CONFIG_DOTENV_KEY != null) options.DOTENV_KEY = process.env.DOTENV_CONFIG_DOTENV_KEY;
390
+ module.exports = options;
391
+ }) });
560
392
 
561
393
  //#endregion
562
- //#region node_modules/dotenv/package.json
563
- var require_package = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/package.json": ((exports, module) => {
564
- module.exports = {
565
- "name": "dotenv",
566
- "version": "17.2.3",
567
- "description": "Loads environment variables from .env file",
568
- "main": "lib/main.js",
569
- "types": "lib/main.d.ts",
570
- "exports": {
571
- ".": {
572
- "types": "./lib/main.d.ts",
573
- "require": "./lib/main.js",
574
- "default": "./lib/main.js"
575
- },
576
- "./config": "./config.js",
577
- "./config.js": "./config.js",
578
- "./lib/env-options": "./lib/env-options.js",
579
- "./lib/env-options.js": "./lib/env-options.js",
580
- "./lib/cli-options": "./lib/cli-options.js",
581
- "./lib/cli-options.js": "./lib/cli-options.js",
582
- "./package.json": "./package.json"
583
- },
584
- "scripts": {
585
- "dts-check": "tsc --project tests/types/tsconfig.json",
586
- "lint": "standard",
587
- "pretest": "npm run lint && npm run dts-check",
588
- "test": "tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000",
589
- "test:coverage": "tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
590
- "prerelease": "npm test",
591
- "release": "standard-version"
592
- },
593
- "repository": {
594
- "type": "git",
595
- "url": "git://github.com/motdotla/dotenv.git"
596
- },
597
- "homepage": "https://github.com/motdotla/dotenv#readme",
598
- "funding": "https://dotenvx.com",
599
- "keywords": [
600
- "dotenv",
601
- "env",
602
- ".env",
603
- "environment",
604
- "variables",
605
- "config",
606
- "settings"
607
- ],
608
- "readmeFilename": "README.md",
609
- "license": "BSD-2-Clause",
610
- "devDependencies": {
611
- "@types/node": "^18.11.3",
612
- "decache": "^4.6.2",
613
- "sinon": "^14.0.1",
614
- "standard": "^17.0.0",
615
- "standard-version": "^9.5.0",
616
- "tap": "^19.2.0",
617
- "typescript": "^4.8.4"
618
- },
619
- "engines": { "node": ">=12" },
620
- "browser": { "fs": false }
394
+ //#region node_modules/dotenv/lib/cli-options.js
395
+ var require_cli_options = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/lib/cli-options.js": ((exports, module) => {
396
+ const re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/;
397
+ module.exports = function optionMatcher(args) {
398
+ const options$1 = args.reduce(function(acc, cur) {
399
+ const matches = cur.match(re);
400
+ if (matches) acc[matches[1]] = matches[2];
401
+ return acc;
402
+ }, {});
403
+ if (!("quiet" in options$1)) options$1.quiet = "true";
404
+ return options$1;
621
405
  };
622
406
  }) });
623
407
 
624
408
  //#endregion
625
- //#region node_modules/dotenv/lib/main.js
626
- var require_main = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/lib/main.js": ((exports, module) => {
627
- const fs$1 = __require("fs");
628
- const path$1 = __require("path");
629
- const os$1 = __require("os");
630
- const crypto$1 = __require("crypto");
631
- const version = require_package().version;
632
- const TIPS = [
633
- "🔐 encrypt with Dotenvx: https://dotenvx.com",
634
- "🔐 prevent committing .env to code: https://dotenvx.com/precommit",
635
- "🔐 prevent building .env in docker: https://dotenvx.com/prebuild",
636
- "📡 add observability to secrets: https://dotenvx.com/ops",
637
- "👥 sync secrets across teammates & machines: https://dotenvx.com/ops",
638
- "🗂️ backup and recover secrets: https://dotenvx.com/ops",
639
- "✅ audit secrets and track compliance: https://dotenvx.com/ops",
640
- "🔄 add secrets lifecycle management: https://dotenvx.com/ops",
641
- "🔑 add access controls to secrets: https://dotenvx.com/ops",
642
- "🛠️ run anywhere with `dotenvx run -- yourcommand`",
643
- "⚙️ specify custom .env file path with { path: '/custom/path/.env' }",
644
- "⚙️ enable debug logging with { debug: true }",
645
- "⚙️ override existing env vars with { override: true }",
646
- "⚙️ suppress all logs with { quiet: true }",
647
- "⚙️ write to custom object with { processEnv: myObject }",
648
- "⚙️ load multiple .env files with { path: ['.env.local', '.env'] }"
649
- ];
650
- function _getRandomTip() {
651
- return TIPS[Math.floor(Math.random() * TIPS.length)];
409
+ //#region node_modules/dotenv/config.js
410
+ (function() {
411
+ require_main().config(Object.assign({}, require_env_options(), require_cli_options()(process.argv)));
412
+ })();
413
+
414
+ //#endregion
415
+ //#region src/lib/config.ts
416
+ const CONFIG_FILENAME = "config.json";
417
+ /**
418
+ * Get the path to the config file
419
+ */
420
+ function getConfigPath() {
421
+ return path.join(PATHS.DATA_DIR, CONFIG_FILENAME);
422
+ }
423
+ /**
424
+ * Load configuration from file
425
+ */
426
+ async function loadConfig() {
427
+ try {
428
+ const configPath = getConfigPath();
429
+ const content = await fs.readFile(configPath);
430
+ return JSON.parse(content);
431
+ } catch {
432
+ return {};
652
433
  }
653
- function parseBoolean(value) {
654
- if (typeof value === "string") return ![
655
- "false",
656
- "0",
657
- "no",
658
- "off",
659
- ""
660
- ].includes(value.toLowerCase());
661
- return Boolean(value);
434
+ }
435
+ /**
436
+ * Save configuration to file
437
+ */
438
+ async function saveConfig(config$1) {
439
+ const configPath = getConfigPath();
440
+ await fs.writeFile(configPath, JSON.stringify(config$1, null, 2), "utf8");
441
+ consola.debug(`Configuration saved to ${configPath}`);
442
+ }
443
+ /**
444
+ * Get proxy configuration
445
+ */
446
+ async function getProxyConfig() {
447
+ return (await loadConfig()).proxy;
448
+ }
449
+ /**
450
+ * Save proxy configuration
451
+ */
452
+ async function saveProxyConfig(proxyConfig) {
453
+ const config$1 = await loadConfig();
454
+ config$1.proxy = proxyConfig;
455
+ await saveConfig(config$1);
456
+ }
457
+ /**
458
+ * Clear proxy configuration
459
+ */
460
+ async function clearProxyConfig() {
461
+ const config$1 = await loadConfig();
462
+ delete config$1.proxy;
463
+ await saveConfig(config$1);
464
+ }
465
+ /**
466
+ * Apply saved proxy configuration to environment variables
467
+ * This should be called at startup to restore proxy settings
468
+ */
469
+ async function applyProxyConfig() {
470
+ const proxyConfig = await getProxyConfig();
471
+ if (!proxyConfig || !proxyConfig.enabled) return false;
472
+ if (proxyConfig.httpProxy) {
473
+ process.env.HTTP_PROXY = proxyConfig.httpProxy;
474
+ process.env.http_proxy = proxyConfig.httpProxy;
662
475
  }
663
- function supportsAnsi() {
664
- return process.stdout.isTTY;
476
+ if (proxyConfig.httpsProxy) {
477
+ process.env.HTTPS_PROXY = proxyConfig.httpsProxy;
478
+ process.env.https_proxy = proxyConfig.httpsProxy;
479
+ }
480
+ if (proxyConfig.noProxy) {
481
+ process.env.NO_PROXY = proxyConfig.noProxy;
482
+ process.env.no_proxy = proxyConfig.noProxy;
483
+ }
484
+ consola.info("Proxy configuration loaded from saved settings");
485
+ if (proxyConfig.httpProxy) consola.info(` HTTP_PROXY: ${proxyConfig.httpProxy}`);
486
+ if (proxyConfig.httpsProxy) consola.info(` HTTPS_PROXY: ${proxyConfig.httpsProxy}`);
487
+ if (proxyConfig.noProxy) consola.info(` NO_PROXY: ${proxyConfig.noProxy}`);
488
+ return true;
489
+ }
490
+
491
+ //#endregion
492
+ //#region src/lib/proxy.ts
493
+ function initProxyFromEnv() {
494
+ if (typeof Bun !== "undefined") return;
495
+ try {
496
+ const direct = new Agent();
497
+ const proxies = /* @__PURE__ */ new Map();
498
+ setGlobalDispatcher({
499
+ dispatch(options$1, handler) {
500
+ try {
501
+ const origin = typeof options$1.origin === "string" ? new URL(options$1.origin) : options$1.origin;
502
+ const raw = getProxyForUrl(origin.toString());
503
+ const proxyUrl = raw && raw.length > 0 ? raw : void 0;
504
+ if (!proxyUrl) {
505
+ consola.debug(`HTTP proxy bypass: ${origin.hostname}`);
506
+ return direct.dispatch(options$1, handler);
507
+ }
508
+ let agent = proxies.get(proxyUrl);
509
+ if (!agent) {
510
+ agent = new ProxyAgent(proxyUrl);
511
+ proxies.set(proxyUrl, agent);
512
+ }
513
+ let label = proxyUrl;
514
+ try {
515
+ const u = new URL(proxyUrl);
516
+ label = `${u.protocol}//${u.host}`;
517
+ } catch {}
518
+ consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`);
519
+ return agent.dispatch(options$1, handler);
520
+ } catch {
521
+ return direct.dispatch(options$1, handler);
522
+ }
523
+ },
524
+ close() {
525
+ return direct.close();
526
+ },
527
+ destroy() {
528
+ return direct.destroy();
529
+ }
530
+ });
531
+ consola.debug("HTTP proxy configured from environment (per-URL)");
532
+ } catch (err) {
533
+ consola.debug("Proxy setup skipped:", err);
534
+ }
535
+ }
536
+
537
+ //#endregion
538
+ //#region src/antigravity.ts
539
+ /**
540
+ * Add a new Antigravity account via OAuth
541
+ */
542
+ async function addAccount() {
543
+ const { setupAntigravity, loadAntigravityAuth } = await import("./auth-B2lTFLSD.js");
544
+ const existingAuth = await loadAntigravityAuth();
545
+ if (existingAuth && existingAuth.accounts.length > 0) {
546
+ const enabledCount = existingAuth.accounts.filter((a) => a.enable).length;
547
+ consola.info(`Found ${existingAuth.accounts.length} existing accounts (${enabledCount} enabled)`);
548
+ }
549
+ await setupAntigravity();
550
+ }
551
+ /**
552
+ * List all Antigravity accounts
553
+ */
554
+ async function listAccounts() {
555
+ const { loadAntigravityAuth } = await import("./auth-B2lTFLSD.js");
556
+ const auth$1 = await loadAntigravityAuth();
557
+ if (!auth$1 || auth$1.accounts.length === 0) {
558
+ consola.info("No Antigravity accounts configured");
559
+ return;
560
+ }
561
+ consola.info(`\nAntigravity Accounts (${auth$1.accounts.length} total):`);
562
+ consola.info("=".repeat(50));
563
+ for (let i = 0; i < auth$1.accounts.length; i++) {
564
+ const account = auth$1.accounts[i];
565
+ const isCurrent = i === auth$1.currentIndex;
566
+ const status = account.enable ? "enabled" : "disabled";
567
+ const marker = isCurrent ? "→ " : " ";
568
+ const projectId = account.project_id || "unknown";
569
+ consola.info(`${marker}[${i}] Project: ${projectId} | Status: ${status}${isCurrent ? " (current)" : ""}`);
570
+ }
571
+ }
572
+ /**
573
+ * Remove an Antigravity account by index
574
+ */
575
+ async function removeAccount(index) {
576
+ const { loadAntigravityAuth, saveAntigravityAuth } = await import("./auth-B2lTFLSD.js");
577
+ const auth$1 = await loadAntigravityAuth();
578
+ if (!auth$1 || auth$1.accounts.length === 0) {
579
+ consola.error("No Antigravity accounts configured");
580
+ return;
665
581
  }
666
- function dim(text) {
667
- return supportsAnsi() ? `\x1b[2m${text}\x1b[0m` : text;
582
+ if (index < 0 || index >= auth$1.accounts.length) {
583
+ consola.error(`Invalid index. Must be between 0 and ${auth$1.accounts.length - 1}`);
584
+ return;
668
585
  }
669
- const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
670
- function parse(src) {
671
- const obj = {};
672
- let lines = src.toString();
673
- lines = lines.replace(/\r\n?/gm, "\n");
674
- let match;
675
- while ((match = LINE.exec(lines)) != null) {
676
- const key = match[1];
677
- let value = match[2] || "";
678
- value = value.trim();
679
- const maybeQuote = value[0];
680
- value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
681
- if (maybeQuote === "\"") {
682
- value = value.replace(/\\n/g, "\n");
683
- value = value.replace(/\\r/g, "\r");
586
+ const removed = auth$1.accounts.splice(index, 1)[0];
587
+ if (auth$1.currentIndex >= auth$1.accounts.length) auth$1.currentIndex = Math.max(0, auth$1.accounts.length - 1);
588
+ await saveAntigravityAuth(auth$1);
589
+ consola.success(`Removed account ${index} (Project: ${removed.project_id || "unknown"})`);
590
+ }
591
+ /**
592
+ * Clear all Antigravity accounts
593
+ */
594
+ async function clearAccounts() {
595
+ const { clearAntigravityAuth: clearAntigravityAuth$1 } = await import("./auth-B2lTFLSD.js");
596
+ if (await consola.prompt("Are you sure you want to remove all Antigravity accounts?", {
597
+ type: "confirm",
598
+ initial: false
599
+ })) await clearAntigravityAuth$1();
600
+ }
601
+ const antigravity = defineCommand({
602
+ meta: {
603
+ name: "antigravity",
604
+ description: "Manage Google Antigravity accounts"
605
+ },
606
+ subCommands: {
607
+ add: defineCommand({
608
+ meta: {
609
+ name: "add",
610
+ description: "Add a new Antigravity account via OAuth"
611
+ },
612
+ async run() {
613
+ await ensurePaths();
614
+ if (await applyProxyConfig()) initProxyFromEnv();
615
+ await addAccount();
684
616
  }
685
- obj[key] = value;
686
- }
687
- return obj;
617
+ }),
618
+ list: defineCommand({
619
+ meta: {
620
+ name: "list",
621
+ description: "List all Antigravity accounts"
622
+ },
623
+ async run() {
624
+ await ensurePaths();
625
+ await listAccounts();
626
+ }
627
+ }),
628
+ remove: defineCommand({
629
+ meta: {
630
+ name: "remove",
631
+ description: "Remove an Antigravity account by index"
632
+ },
633
+ args: { index: {
634
+ type: "positional",
635
+ description: "Account index to remove (use 'list' to see indexes)",
636
+ required: true
637
+ } },
638
+ async run({ args }) {
639
+ await ensurePaths();
640
+ const indexStr = String(args.index);
641
+ const index = Number.parseInt(indexStr, 10);
642
+ if (Number.isNaN(index)) {
643
+ consola.error("Index must be a number");
644
+ return;
645
+ }
646
+ await removeAccount(index);
647
+ }
648
+ }),
649
+ clear: defineCommand({
650
+ meta: {
651
+ name: "clear",
652
+ description: "Remove all Antigravity accounts"
653
+ },
654
+ async run() {
655
+ await ensurePaths();
656
+ await clearAccounts();
657
+ }
658
+ })
688
659
  }
689
- function _parseVault(options$1) {
690
- options$1 = options$1 || {};
691
- const vaultPath = _vaultPath(options$1);
692
- options$1.path = vaultPath;
693
- const result = DotenvModule.configDotenv(options$1);
694
- if (!result.parsed) {
695
- const err = /* @__PURE__ */ new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
696
- err.code = "MISSING_DATA";
697
- throw err;
660
+ });
661
+
662
+ //#endregion
663
+ //#region src/auth.ts
664
+ async function runAuth(options$1) {
665
+ if (options$1.verbose) {
666
+ consola.level = 5;
667
+ consola.info("Verbose logging enabled");
668
+ }
669
+ state.showToken = options$1.showToken;
670
+ await ensurePaths();
671
+ await setupGitHubToken({ force: true });
672
+ consola.success("GitHub token written to", PATHS.GITHUB_TOKEN_PATH);
673
+ }
674
+ const auth = defineCommand({
675
+ meta: {
676
+ name: "auth",
677
+ description: "Run GitHub auth flow without running the server"
678
+ },
679
+ args: {
680
+ verbose: {
681
+ alias: "v",
682
+ type: "boolean",
683
+ default: false,
684
+ description: "Enable verbose logging"
685
+ },
686
+ "show-token": {
687
+ type: "boolean",
688
+ default: false,
689
+ description: "Show GitHub token on auth"
698
690
  }
699
- const keys = _dotenvKey(options$1).split(",");
700
- const length = keys.length;
701
- let decrypted;
702
- for (let i = 0; i < length; i++) try {
703
- const key = keys[i].trim();
704
- const attrs = _instructions(result, key);
705
- decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
706
- break;
707
- } catch (error) {
708
- if (i + 1 >= length) throw error;
691
+ },
692
+ run({ args }) {
693
+ return runAuth({
694
+ verbose: args.verbose,
695
+ showToken: args["show-token"]
696
+ });
697
+ }
698
+ });
699
+
700
+ //#endregion
701
+ //#region src/services/github/get-copilot-usage.ts
702
+ const getCopilotUsage = async () => {
703
+ const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, { headers: githubHeaders(state) });
704
+ if (!response.ok) throw new HTTPError("Failed to get Copilot usage", response);
705
+ return await response.json();
706
+ };
707
+
708
+ //#endregion
709
+ //#region src/check-usage.ts
710
+ const checkUsage = defineCommand({
711
+ meta: {
712
+ name: "check-usage",
713
+ description: "Show current GitHub Copilot usage/quota information"
714
+ },
715
+ async run() {
716
+ await ensurePaths();
717
+ await setupGitHubToken();
718
+ try {
719
+ const usage = await getCopilotUsage();
720
+ const premium = usage.quota_snapshots.premium_interactions;
721
+ const premiumTotal = premium.entitlement;
722
+ const premiumUsed = premiumTotal - premium.remaining;
723
+ const premiumPercentUsed = premiumTotal > 0 ? premiumUsed / premiumTotal * 100 : 0;
724
+ const premiumPercentRemaining = premium.percent_remaining;
725
+ function summarizeQuota(name, snap) {
726
+ if (!snap) return `${name}: N/A`;
727
+ const total = snap.entitlement;
728
+ const used = total - snap.remaining;
729
+ const percentUsed = total > 0 ? used / total * 100 : 0;
730
+ const percentRemaining = snap.percent_remaining;
731
+ return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
732
+ }
733
+ const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
734
+ const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
735
+ const completionsLine = summarizeQuota("Completions", usage.quota_snapshots.completions);
736
+ consola.box(`Copilot Usage (plan: ${usage.copilot_plan})\nQuota resets: ${usage.quota_reset_date}\n\nQuotas:\n ${premiumLine}\n ${chatLine}\n ${completionsLine}`);
737
+ } catch (err) {
738
+ consola.error("Failed to fetch Copilot usage:", err);
739
+ process.exit(1);
709
740
  }
710
- return DotenvModule.parse(decrypted);
711
741
  }
712
- function _warn(message) {
713
- console.error(`[dotenv@${version}][WARN] ${message}`);
742
+ });
743
+
744
+ //#endregion
745
+ //#region src/debug.ts
746
+ async function getPackageVersion() {
747
+ try {
748
+ const packageJsonPath = new URL("../package.json", import.meta.url).pathname;
749
+ return JSON.parse(await fs.readFile(packageJsonPath)).version;
750
+ } catch {
751
+ return "unknown";
714
752
  }
715
- function _debug(message) {
716
- console.log(`[dotenv@${version}][DEBUG] ${message}`);
753
+ }
754
+ function getRuntimeInfo() {
755
+ const isBun = typeof Bun !== "undefined";
756
+ return {
757
+ name: isBun ? "bun" : "node",
758
+ version: isBun ? Bun.version : process.version.slice(1),
759
+ platform: os.platform(),
760
+ arch: os.arch()
761
+ };
762
+ }
763
+ async function checkTokenExists() {
764
+ try {
765
+ if (!(await fs.stat(PATHS.GITHUB_TOKEN_PATH)).isFile()) return false;
766
+ return (await fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8")).trim().length > 0;
767
+ } catch {
768
+ return false;
717
769
  }
718
- function _log(message) {
719
- console.log(`[dotenv@${version}] ${message}`);
770
+ }
771
+ async function checkFileExists(path$2) {
772
+ try {
773
+ if (!(await fs.stat(path$2)).isFile()) return false;
774
+ return (await fs.readFile(path$2, "utf8")).trim().length > 0;
775
+ } catch {
776
+ return false;
720
777
  }
721
- function _dotenvKey(options$1) {
722
- if (options$1 && options$1.DOTENV_KEY && options$1.DOTENV_KEY.length > 0) return options$1.DOTENV_KEY;
723
- if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) return process.env.DOTENV_KEY;
724
- return "";
778
+ }
779
+ async function getDebugInfo() {
780
+ const zenAuthPath = getZenAuthPath();
781
+ const antigravityAuthPath = getAntigravityAuthPath();
782
+ const [version$1, githubExists, zenExists, antigravityExists, proxyConfig] = await Promise.all([
783
+ getPackageVersion(),
784
+ checkTokenExists(),
785
+ checkFileExists(zenAuthPath),
786
+ checkFileExists(antigravityAuthPath),
787
+ getProxyConfig()
788
+ ]);
789
+ return {
790
+ version: version$1,
791
+ runtime: getRuntimeInfo(),
792
+ paths: {
793
+ APP_DIR: PATHS.APP_DIR,
794
+ GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,
795
+ ZEN_AUTH_PATH: zenAuthPath,
796
+ ANTIGRAVITY_AUTH_PATH: antigravityAuthPath
797
+ },
798
+ credentials: {
799
+ github: githubExists,
800
+ zen: zenExists,
801
+ antigravity: antigravityExists
802
+ },
803
+ proxy: proxyConfig
804
+ };
805
+ }
806
+ function printDebugInfoPlain(info) {
807
+ let proxyStatus = "Not configured";
808
+ if (info.proxy) proxyStatus = info.proxy.enabled ? `Enabled (${info.proxy.httpProxy || info.proxy.httpsProxy})` : "Disabled";
809
+ consola.info(`copilot-api-plus debug
810
+
811
+ Version: ${info.version}
812
+ Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})
813
+
814
+ Paths:
815
+ APP_DIR: ${info.paths.APP_DIR}
816
+ GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}
817
+ ZEN_AUTH_PATH: ${info.paths.ZEN_AUTH_PATH}
818
+ ANTIGRAVITY_AUTH_PATH: ${info.paths.ANTIGRAVITY_AUTH_PATH}
819
+
820
+ Credentials:
821
+ GitHub Copilot: ${info.credentials.github ? "✅ Configured" : "❌ Not configured"}
822
+ OpenCode Zen: ${info.credentials.zen ? "✅ Configured" : "❌ Not configured"}
823
+ Google Antigravity: ${info.credentials.antigravity ? "✅ Configured" : "❌ Not configured"}
824
+
825
+ Proxy: ${proxyStatus}`);
826
+ }
827
+ function printDebugInfoJson(info) {
828
+ console.log(JSON.stringify(info, null, 2));
829
+ }
830
+ async function runDebug(options$1) {
831
+ const debugInfo = await getDebugInfo();
832
+ if (options$1.json) printDebugInfoJson(debugInfo);
833
+ else printDebugInfoPlain(debugInfo);
834
+ }
835
+ const debug = defineCommand({
836
+ meta: {
837
+ name: "debug",
838
+ description: "Print debug information about the application"
839
+ },
840
+ args: { json: {
841
+ type: "boolean",
842
+ default: false,
843
+ description: "Output debug information as JSON"
844
+ } },
845
+ run({ args }) {
846
+ return runDebug({ json: args.json });
847
+ }
848
+ });
849
+
850
+ //#endregion
851
+ //#region src/logout.ts
852
+ async function runLogout(options$1) {
853
+ await ensurePaths();
854
+ if (options$1.all) {
855
+ await clearGithubToken();
856
+ await clearZenAuth();
857
+ await clearAntigravityAuth();
858
+ consola.success("Logged out from all services");
859
+ consola.info(`GitHub token: ${PATHS.GITHUB_TOKEN_PATH}`);
860
+ consola.info(`Zen API key: ${getZenAuthPath()}`);
861
+ consola.info(`Antigravity accounts: ${getAntigravityAuthPath()}`);
862
+ return;
725
863
  }
726
- function _instructions(result, dotenvKey) {
727
- let uri;
728
- try {
729
- uri = new URL(dotenvKey);
730
- } catch (error) {
731
- if (error.code === "ERR_INVALID_URL") {
732
- 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");
733
- err.code = "INVALID_DOTENV_KEY";
734
- throw err;
735
- }
736
- throw error;
737
- }
738
- const key = uri.password;
739
- if (!key) {
740
- const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing key part");
741
- err.code = "INVALID_DOTENV_KEY";
742
- throw err;
743
- }
744
- const environment = uri.searchParams.get("environment");
745
- if (!environment) {
746
- const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: Missing environment part");
747
- err.code = "INVALID_DOTENV_KEY";
748
- throw err;
749
- }
750
- const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
751
- const ciphertext = result.parsed[environmentKey];
752
- if (!ciphertext) {
753
- const err = /* @__PURE__ */ new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
754
- err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
755
- throw err;
756
- }
757
- return {
758
- ciphertext,
759
- key
760
- };
864
+ if (options$1.github) {
865
+ await clearGithubToken();
866
+ consola.success("Logged out from GitHub Copilot");
867
+ consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
868
+ return;
761
869
  }
762
- function _vaultPath(options$1) {
763
- let possibleVaultPath = null;
764
- if (options$1 && options$1.path && options$1.path.length > 0) if (Array.isArray(options$1.path)) {
765
- for (const filepath of options$1.path) if (fs$1.existsSync(filepath)) possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
766
- } else possibleVaultPath = options$1.path.endsWith(".vault") ? options$1.path : `${options$1.path}.vault`;
767
- else possibleVaultPath = path$1.resolve(process.cwd(), ".env.vault");
768
- if (fs$1.existsSync(possibleVaultPath)) return possibleVaultPath;
769
- return null;
870
+ if (options$1.zen) {
871
+ await clearZenAuth();
872
+ consola.success("Logged out from OpenCode Zen");
873
+ consola.info(`Zen API key location: ${getZenAuthPath()}`);
874
+ return;
770
875
  }
771
- function _resolveHome(envPath) {
772
- return envPath[0] === "~" ? path$1.join(os$1.homedir(), envPath.slice(1)) : envPath;
876
+ if (options$1.antigravity) {
877
+ await clearAntigravityAuth();
878
+ consola.success("Logged out from Google Antigravity");
879
+ consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
880
+ return;
773
881
  }
774
- function _configVault(options$1) {
775
- const debug$1 = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options$1 && options$1.debug);
776
- const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options$1 && options$1.quiet);
777
- if (debug$1 || !quiet) _log("Loading env from encrypted .env.vault");
778
- const parsed = DotenvModule._parseVault(options$1);
779
- let processEnv = process.env;
780
- if (options$1 && options$1.processEnv != null) processEnv = options$1.processEnv;
781
- DotenvModule.populate(processEnv, parsed, options$1);
782
- return { parsed };
882
+ switch (await consola.prompt("Which credentials do you want to clear?", {
883
+ type: "select",
884
+ options: [
885
+ "GitHub Copilot token",
886
+ "OpenCode Zen API key",
887
+ "Google Antigravity accounts",
888
+ "All credentials"
889
+ ]
890
+ })) {
891
+ case "GitHub Copilot token":
892
+ await clearGithubToken();
893
+ consola.success("Logged out from GitHub Copilot");
894
+ consola.info(`Token file location: ${PATHS.GITHUB_TOKEN_PATH}`);
895
+ break;
896
+ case "OpenCode Zen API key":
897
+ await clearZenAuth();
898
+ consola.success("Logged out from OpenCode Zen");
899
+ consola.info(`Zen API key location: ${getZenAuthPath()}`);
900
+ break;
901
+ case "Google Antigravity accounts":
902
+ await clearAntigravityAuth();
903
+ consola.success("Logged out from Google Antigravity");
904
+ consola.info(`Antigravity accounts location: ${getAntigravityAuthPath()}`);
905
+ break;
906
+ case "All credentials":
907
+ await clearGithubToken();
908
+ await clearZenAuth();
909
+ await clearAntigravityAuth();
910
+ consola.success("Logged out from all services");
911
+ break;
783
912
  }
784
- function configDotenv(options$1) {
785
- const dotenvPath = path$1.resolve(process.cwd(), ".env");
786
- let encoding = "utf8";
787
- let processEnv = process.env;
788
- if (options$1 && options$1.processEnv != null) processEnv = options$1.processEnv;
789
- let debug$1 = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options$1 && options$1.debug);
790
- let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options$1 && options$1.quiet);
791
- if (options$1 && options$1.encoding) encoding = options$1.encoding;
792
- else if (debug$1) _debug("No encoding is specified. UTF-8 is used by default");
793
- let optionPaths = [dotenvPath];
794
- if (options$1 && options$1.path) if (!Array.isArray(options$1.path)) optionPaths = [_resolveHome(options$1.path)];
795
- else {
796
- optionPaths = [];
797
- for (const filepath of options$1.path) optionPaths.push(_resolveHome(filepath));
913
+ }
914
+ const logout = defineCommand({
915
+ meta: {
916
+ name: "logout",
917
+ description: "Clear stored credentials and logout"
918
+ },
919
+ args: {
920
+ github: {
921
+ alias: "g",
922
+ type: "boolean",
923
+ default: false,
924
+ description: "Clear only GitHub Copilot token"
925
+ },
926
+ zen: {
927
+ alias: "z",
928
+ type: "boolean",
929
+ default: false,
930
+ description: "Clear only OpenCode Zen API key"
931
+ },
932
+ antigravity: {
933
+ type: "boolean",
934
+ default: false,
935
+ description: "Clear only Google Antigravity accounts"
936
+ },
937
+ all: {
938
+ alias: "a",
939
+ type: "boolean",
940
+ default: false,
941
+ description: "Clear all credentials (GitHub, Zen, and Antigravity)"
798
942
  }
799
- let lastError;
800
- const parsedAll = {};
801
- for (const path$2 of optionPaths) try {
802
- const parsed = DotenvModule.parse(fs$1.readFileSync(path$2, { encoding }));
803
- DotenvModule.populate(parsedAll, parsed, options$1);
804
- } catch (e) {
805
- if (debug$1) _debug(`Failed to load ${path$2} ${e.message}`);
806
- lastError = e;
943
+ },
944
+ run({ args }) {
945
+ return runLogout({
946
+ github: args.github,
947
+ zen: args.zen,
948
+ antigravity: args.antigravity,
949
+ all: args.all
950
+ });
951
+ }
952
+ });
953
+
954
+ //#endregion
955
+ //#region src/proxy-config.ts
956
+ const proxy = defineCommand({
957
+ meta: {
958
+ name: "proxy",
959
+ description: "Configure proxy settings (persistent)"
960
+ },
961
+ args: {
962
+ set: {
963
+ type: "boolean",
964
+ default: false,
965
+ description: "Set proxy configuration interactively"
966
+ },
967
+ enable: {
968
+ type: "boolean",
969
+ default: false,
970
+ description: "Enable saved proxy configuration"
971
+ },
972
+ disable: {
973
+ type: "boolean",
974
+ default: false,
975
+ description: "Disable proxy (keep settings)"
976
+ },
977
+ clear: {
978
+ type: "boolean",
979
+ default: false,
980
+ description: "Clear all proxy settings"
981
+ },
982
+ show: {
983
+ type: "boolean",
984
+ default: false,
985
+ description: "Show current proxy configuration"
986
+ },
987
+ "http-proxy": {
988
+ type: "string",
989
+ description: "HTTP proxy URL (e.g., http://proxy:8080)"
990
+ },
991
+ "https-proxy": {
992
+ type: "string",
993
+ description: "HTTPS proxy URL (e.g., http://proxy:8080)"
994
+ },
995
+ "no-proxy": {
996
+ type: "string",
997
+ description: "Comma-separated list of hosts to bypass proxy"
807
998
  }
808
- const populated = DotenvModule.populate(processEnv, parsedAll, options$1);
809
- debug$1 = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug$1);
810
- quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
811
- if (debug$1 || !quiet) {
812
- const keysCount = Object.keys(populated).length;
813
- const shortPaths = [];
814
- for (const filePath of optionPaths) try {
815
- const relative = path$1.relative(process.cwd(), filePath);
816
- shortPaths.push(relative);
817
- } catch (e) {
818
- if (debug$1) _debug(`Failed to load ${filePath} ${e.message}`);
819
- lastError = e;
999
+ },
1000
+ async run({ args }) {
1001
+ await ensurePaths();
1002
+ if (args.show || !args.set && !args.enable && !args.disable && !args.clear && !args["http-proxy"] && !args["https-proxy"]) {
1003
+ const config$1 = await getProxyConfig();
1004
+ if (!config$1) {
1005
+ consola.info("No proxy configuration saved.");
1006
+ consola.info("");
1007
+ consola.info("To configure proxy, use one of:");
1008
+ consola.info(" copilot-api-plus proxy --set # Interactive setup");
1009
+ consola.info(" copilot-api-plus proxy --http-proxy http://proxy:8080 # Direct set");
1010
+ return;
820
1011
  }
821
- _log(`injecting env (${keysCount}) from ${shortPaths.join(",")} ${dim(`-- tip: ${_getRandomTip()}`)}`);
822
- }
823
- if (lastError) return {
824
- parsed: parsedAll,
825
- error: lastError
826
- };
827
- else return { parsed: parsedAll };
828
- }
829
- function config(options$1) {
830
- if (_dotenvKey(options$1).length === 0) return DotenvModule.configDotenv(options$1);
831
- const vaultPath = _vaultPath(options$1);
832
- if (!vaultPath) {
833
- _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
834
- return DotenvModule.configDotenv(options$1);
1012
+ consola.info("Current proxy configuration:");
1013
+ consola.info(` Status: ${config$1.enabled ? "✅ Enabled" : "❌ Disabled"}`);
1014
+ if (config$1.httpProxy) consola.info(` HTTP_PROXY: ${config$1.httpProxy}`);
1015
+ if (config$1.httpsProxy) consola.info(` HTTPS_PROXY: ${config$1.httpsProxy}`);
1016
+ if (config$1.noProxy) consola.info(` NO_PROXY: ${config$1.noProxy}`);
1017
+ return;
835
1018
  }
836
- return DotenvModule._configVault(options$1);
837
- }
838
- function decrypt(encrypted, keyStr) {
839
- const key = Buffer.from(keyStr.slice(-64), "hex");
840
- let ciphertext = Buffer.from(encrypted, "base64");
841
- const nonce = ciphertext.subarray(0, 12);
842
- const authTag = ciphertext.subarray(-16);
843
- ciphertext = ciphertext.subarray(12, -16);
844
- try {
845
- const aesgcm = crypto$1.createDecipheriv("aes-256-gcm", key, nonce);
846
- aesgcm.setAuthTag(authTag);
847
- return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
848
- } catch (error) {
849
- const isRange = error instanceof RangeError;
850
- const invalidKeyLength = error.message === "Invalid key length";
851
- const decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
852
- if (isRange || invalidKeyLength) {
853
- const err = /* @__PURE__ */ new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
854
- err.code = "INVALID_DOTENV_KEY";
855
- throw err;
856
- } else if (decryptionFailed) {
857
- const err = /* @__PURE__ */ new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
858
- err.code = "DECRYPTION_FAILED";
859
- throw err;
860
- } else throw error;
1019
+ if (args.clear) {
1020
+ await clearProxyConfig();
1021
+ consola.success("Proxy configuration cleared.");
1022
+ return;
861
1023
  }
862
- }
863
- function populate(processEnv, parsed, options$1 = {}) {
864
- const debug$1 = Boolean(options$1 && options$1.debug);
865
- const override = Boolean(options$1 && options$1.override);
866
- const populated = {};
867
- if (typeof parsed !== "object") {
868
- const err = /* @__PURE__ */ new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
869
- err.code = "OBJECT_REQUIRED";
870
- throw err;
1024
+ if (args.enable) {
1025
+ const config$1 = await getProxyConfig();
1026
+ if (!config$1) {
1027
+ consola.error("No proxy configuration saved. Use --set to configure first.");
1028
+ return;
1029
+ }
1030
+ config$1.enabled = true;
1031
+ await saveProxyConfig(config$1);
1032
+ consola.success("Proxy enabled. It will be used on next server start.");
1033
+ return;
871
1034
  }
872
- for (const key of Object.keys(parsed)) if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
873
- if (override === true) {
874
- processEnv[key] = parsed[key];
875
- populated[key] = parsed[key];
1035
+ if (args.disable) {
1036
+ const config$1 = await getProxyConfig();
1037
+ if (!config$1) {
1038
+ consola.info("No proxy configuration to disable.");
1039
+ return;
876
1040
  }
877
- if (debug$1) if (override === true) _debug(`"${key}" is already defined and WAS overwritten`);
878
- else _debug(`"${key}" is already defined and was NOT overwritten`);
879
- } else {
880
- processEnv[key] = parsed[key];
881
- populated[key] = parsed[key];
1041
+ config$1.enabled = false;
1042
+ await saveProxyConfig(config$1);
1043
+ consola.success("Proxy disabled. Settings are preserved.");
1044
+ return;
882
1045
  }
883
- return populated;
884
- }
885
- const DotenvModule = {
886
- configDotenv,
887
- _configVault,
888
- _parseVault,
889
- config,
890
- decrypt,
891
- parse,
892
- populate
893
- };
894
- module.exports.configDotenv = DotenvModule.configDotenv;
895
- module.exports._configVault = DotenvModule._configVault;
896
- module.exports._parseVault = DotenvModule._parseVault;
897
- module.exports.config = DotenvModule.config;
898
- module.exports.decrypt = DotenvModule.decrypt;
899
- module.exports.parse = DotenvModule.parse;
900
- module.exports.populate = DotenvModule.populate;
901
- module.exports = DotenvModule;
902
- }) });
903
-
904
- //#endregion
905
- //#region node_modules/dotenv/lib/env-options.js
906
- var require_env_options = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/lib/env-options.js": ((exports, module) => {
907
- const options = {};
908
- if (process.env.DOTENV_CONFIG_ENCODING != null) options.encoding = process.env.DOTENV_CONFIG_ENCODING;
909
- if (process.env.DOTENV_CONFIG_PATH != null) options.path = process.env.DOTENV_CONFIG_PATH;
910
- if (process.env.DOTENV_CONFIG_QUIET != null) options.quiet = process.env.DOTENV_CONFIG_QUIET;
911
- if (process.env.DOTENV_CONFIG_DEBUG != null) options.debug = process.env.DOTENV_CONFIG_DEBUG;
912
- if (process.env.DOTENV_CONFIG_OVERRIDE != null) options.override = process.env.DOTENV_CONFIG_OVERRIDE;
913
- if (process.env.DOTENV_CONFIG_DOTENV_KEY != null) options.DOTENV_KEY = process.env.DOTENV_CONFIG_DOTENV_KEY;
914
- module.exports = options;
915
- }) });
916
-
917
- //#endregion
918
- //#region node_modules/dotenv/lib/cli-options.js
919
- var require_cli_options = /* @__PURE__ */ __commonJS({ "node_modules/dotenv/lib/cli-options.js": ((exports, module) => {
920
- const re = /^dotenv_config_(encoding|path|quiet|debug|override|DOTENV_KEY)=(.+)$/;
921
- module.exports = function optionMatcher(args) {
922
- const options$1 = args.reduce(function(acc, cur) {
923
- const matches = cur.match(re);
924
- if (matches) acc[matches[1]] = matches[2];
925
- return acc;
926
- }, {});
927
- if (!("quiet" in options$1)) options$1.quiet = "true";
928
- return options$1;
929
- };
930
- }) });
931
-
932
- //#endregion
933
- //#region node_modules/dotenv/config.js
934
- (function() {
935
- require_main().config(Object.assign({}, require_env_options(), require_cli_options()(process.argv)));
936
- })();
937
-
938
- //#endregion
939
- //#region src/lib/proxy.ts
940
- function initProxyFromEnv() {
941
- if (typeof Bun !== "undefined") return;
942
- try {
943
- const direct = new Agent();
944
- const proxies = /* @__PURE__ */ new Map();
945
- setGlobalDispatcher({
946
- dispatch(options$1, handler) {
947
- try {
948
- const origin = typeof options$1.origin === "string" ? new URL(options$1.origin) : options$1.origin;
949
- const raw = getProxyForUrl(origin.toString());
950
- const proxyUrl = raw && raw.length > 0 ? raw : void 0;
951
- if (!proxyUrl) {
952
- consola.debug(`HTTP proxy bypass: ${origin.hostname}`);
953
- return direct.dispatch(options$1, handler);
954
- }
955
- let agent = proxies.get(proxyUrl);
956
- if (!agent) {
957
- agent = new ProxyAgent(proxyUrl);
958
- proxies.set(proxyUrl, agent);
959
- }
960
- let label = proxyUrl;
961
- try {
962
- const u = new URL(proxyUrl);
963
- label = `${u.protocol}//${u.host}`;
964
- } catch {}
965
- consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`);
966
- return agent.dispatch(options$1, handler);
967
- } catch {
968
- return direct.dispatch(options$1, handler);
969
- }
970
- },
971
- close() {
972
- return direct.close();
973
- },
974
- destroy() {
975
- return direct.destroy();
1046
+ if (args["http-proxy"] || args["https-proxy"]) {
1047
+ const newConfig = {
1048
+ enabled: true,
1049
+ httpProxy: args["http-proxy"],
1050
+ httpsProxy: args["https-proxy"] || args["http-proxy"],
1051
+ noProxy: args["no-proxy"]
1052
+ };
1053
+ await saveProxyConfig(newConfig);
1054
+ consola.success("Proxy configuration saved and enabled.");
1055
+ consola.info(` HTTP_PROXY: ${newConfig.httpProxy || "(not set)"}`);
1056
+ consola.info(` HTTPS_PROXY: ${newConfig.httpsProxy || "(not set)"}`);
1057
+ if (newConfig.noProxy) consola.info(` NO_PROXY: ${newConfig.noProxy}`);
1058
+ return;
1059
+ }
1060
+ if (args.set) {
1061
+ p.intro("Proxy Configuration");
1062
+ const existingConfig = await getProxyConfig();
1063
+ const httpProxy = await p.text({
1064
+ message: "HTTP Proxy URL",
1065
+ placeholder: "http://proxy:8080",
1066
+ initialValue: existingConfig?.httpProxy || ""
1067
+ });
1068
+ if (p.isCancel(httpProxy)) {
1069
+ p.cancel("Configuration cancelled.");
1070
+ return;
976
1071
  }
977
- });
978
- consola.debug("HTTP proxy configured from environment (per-URL)");
979
- } catch (err) {
980
- consola.debug("Proxy setup skipped:", err);
1072
+ const httpsProxy = await p.text({
1073
+ message: "HTTPS Proxy URL (leave empty to use HTTP proxy)",
1074
+ placeholder: "http://proxy:8080",
1075
+ initialValue: existingConfig?.httpsProxy || ""
1076
+ });
1077
+ if (p.isCancel(httpsProxy)) {
1078
+ p.cancel("Configuration cancelled.");
1079
+ return;
1080
+ }
1081
+ const noProxy = await p.text({
1082
+ message: "No Proxy (comma-separated hosts to bypass)",
1083
+ placeholder: "localhost,127.0.0.1,.local",
1084
+ initialValue: existingConfig?.noProxy || ""
1085
+ });
1086
+ if (p.isCancel(noProxy)) {
1087
+ p.cancel("Configuration cancelled.");
1088
+ return;
1089
+ }
1090
+ const enable = await p.confirm({
1091
+ message: "Enable proxy now?",
1092
+ initialValue: true
1093
+ });
1094
+ if (p.isCancel(enable)) {
1095
+ p.cancel("Configuration cancelled.");
1096
+ return;
1097
+ }
1098
+ await saveProxyConfig({
1099
+ enabled: enable,
1100
+ httpProxy: httpProxy || void 0,
1101
+ httpsProxy: httpsProxy || httpProxy || void 0,
1102
+ noProxy: noProxy || void 0
1103
+ });
1104
+ p.outro(`Proxy configuration saved${enable ? " and enabled" : ""}.`);
1105
+ }
981
1106
  }
982
- }
1107
+ });
983
1108
 
984
1109
  //#endregion
985
1110
  //#region src/lib/shell.ts
@@ -2037,30 +2162,66 @@ function createErrorResponse(type, message, status) {
2037
2162
  * Create Anthropic-compatible message response using Antigravity
2038
2163
  * Note: Both Gemini and Claude models use the same endpoint and Gemini-style format
2039
2164
  */
2165
+ const MAX_RETRIES = 5;
2040
2166
  async function createAntigravityMessages(request) {
2041
- const accessToken = await getValidAccessToken();
2042
- if (!accessToken) return createErrorResponse("authentication_error", "No valid Antigravity access token available. Please run login first.", 401);
2043
2167
  const endpoint = request.stream ? ANTIGRAVITY_STREAM_URL : ANTIGRAVITY_NO_STREAM_URL;
2044
2168
  const body = buildGeminiRequest(request);
2045
- consola.debug(`Antigravity messages request to ${endpoint} with model ${request.model}`);
2046
- try {
2047
- const response = await fetch(endpoint, {
2048
- method: "POST",
2049
- headers: {
2050
- Host: ANTIGRAVITY_API_HOST,
2051
- "User-Agent": ANTIGRAVITY_USER_AGENT,
2052
- Authorization: `Bearer ${accessToken}`,
2053
- "Content-Type": "application/json",
2054
- "Accept-Encoding": "gzip"
2055
- },
2056
- body: JSON.stringify(body)
2057
- });
2058
- if (!response.ok) return await handleApiError(response);
2059
- return request.stream ? transformStreamResponse(response, request.model) : await transformNonStreamResponse(response, request.model);
2060
- } catch (error) {
2061
- consola.error("Antigravity messages request error:", error);
2062
- return createErrorResponse("api_error", `Request failed: ${String(error)}`, 500);
2169
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
2170
+ const accessToken = await getValidAccessToken();
2171
+ if (!accessToken) return createErrorResponse("authentication_error", "No valid Antigravity access token available. Please run login first.", 401);
2172
+ consola.debug(`Antigravity request to ${endpoint} (attempt ${attempt + 1}/${MAX_RETRIES + 1})`);
2173
+ try {
2174
+ const response = await fetch(endpoint, {
2175
+ method: "POST",
2176
+ headers: {
2177
+ Host: ANTIGRAVITY_API_HOST,
2178
+ "User-Agent": ANTIGRAVITY_USER_AGENT,
2179
+ Authorization: `Bearer ${accessToken}`,
2180
+ "Content-Type": "application/json",
2181
+ "Accept-Encoding": "gzip"
2182
+ },
2183
+ body: JSON.stringify(body)
2184
+ });
2185
+ if (response.ok) return request.stream ? transformStreamResponse(response, request.model) : await transformNonStreamResponse(response, request.model);
2186
+ const errorResult = await handleApiError(response);
2187
+ if (errorResult.shouldRetry && attempt < MAX_RETRIES) {
2188
+ consola.info(`Rate limited, retrying in ${errorResult.retryDelayMs}ms...`);
2189
+ await sleep(errorResult.retryDelayMs);
2190
+ continue;
2191
+ }
2192
+ return errorResult.response;
2193
+ } catch (error) {
2194
+ consola.error("Antigravity messages request error:", error);
2195
+ if (attempt < MAX_RETRIES) {
2196
+ await sleep(500);
2197
+ continue;
2198
+ }
2199
+ return createErrorResponse("api_error", `Request failed: ${String(error)}`, 500);
2200
+ }
2063
2201
  }
2202
+ return createErrorResponse("api_error", "Max retries exceeded", 429);
2203
+ }
2204
+ /**
2205
+ * Parse retry delay from error response
2206
+ */
2207
+ function parseRetryDelay(errorText) {
2208
+ try {
2209
+ const details = JSON.parse(errorText).error?.details ?? [];
2210
+ for (const detail of details) {
2211
+ if (detail["@type"]?.includes("RetryInfo") && detail.retryDelay) {
2212
+ const match = /(\d+(?:\.\d+)?)s/.exec(detail.retryDelay);
2213
+ if (match) return Math.ceil(Number.parseFloat(match[1]) * 1e3);
2214
+ }
2215
+ if (detail.quotaResetDelay) {
2216
+ const match = /(\d+(?:\.\d+)?)(?:ms|s)/.exec(detail.quotaResetDelay);
2217
+ if (match) {
2218
+ const value = Number.parseFloat(match[1]);
2219
+ return detail.quotaResetDelay.includes("ms") ? Math.ceil(value) : Math.ceil(value * 1e3);
2220
+ }
2221
+ }
2222
+ }
2223
+ } catch {}
2224
+ return 500;
2064
2225
  }
2065
2226
  /**
2066
2227
  * Handle API error response
@@ -2069,8 +2230,19 @@ async function handleApiError(response) {
2069
2230
  const errorText = await response.text();
2070
2231
  consola.error(`Antigravity error: ${response.status} ${errorText}`);
2071
2232
  if (response.status === 403) await disableCurrentAccount();
2072
- if (response.status === 429 || response.status === 503) await rotateAccount();
2073
- return createErrorResponse("api_error", `Antigravity API error: ${response.status}`, response.status);
2233
+ if (response.status === 429 || response.status === 503) {
2234
+ await rotateAccount();
2235
+ return {
2236
+ shouldRetry: true,
2237
+ retryDelayMs: parseRetryDelay(errorText),
2238
+ response: createErrorResponse("api_error", `Antigravity API error: ${response.status}`, response.status)
2239
+ };
2240
+ }
2241
+ return {
2242
+ shouldRetry: false,
2243
+ retryDelayMs: 0,
2244
+ response: createErrorResponse("api_error", `Antigravity API error: ${response.status}`, response.status)
2245
+ };
2074
2246
  }
2075
2247
  /**
2076
2248
  * Emit SSE event to controller based on stream event type
@@ -3354,7 +3526,7 @@ async function runServer(options$1) {
3354
3526
  state.zenApiKey = options$1.zenApiKey;
3355
3527
  consola.info("Using provided Zen API key");
3356
3528
  } else {
3357
- const { setupZenApiKey, loadZenAuth } = await import("./auth-wHA1Oitm.js");
3529
+ const { setupZenApiKey, loadZenAuth } = await import("./auth-CCwbOOQN.js");
3358
3530
  const existingAuth = await loadZenAuth();
3359
3531
  if (existingAuth) {
3360
3532
  state.zenApiKey = existingAuth.apiKey;
@@ -3367,7 +3539,7 @@ async function runServer(options$1) {
3367
3539
  } else if (options$1.antigravity) {
3368
3540
  consola.info("Google Antigravity mode enabled");
3369
3541
  state.antigravityMode = true;
3370
- const { loadAntigravityAuth, setupAntigravity, getCurrentAccount, hasApiKey, getApiKey: getApiKey$1, setOAuthCredentials } = await import("./auth-Ijg_vdBM.js");
3542
+ const { loadAntigravityAuth, setupAntigravity, getCurrentAccount, hasApiKey, getApiKey: getApiKey$1, setOAuthCredentials } = await import("./auth-B2lTFLSD.js");
3371
3543
  if (options$1.antigravityClientId && options$1.antigravityClientSecret) {
3372
3544
  setOAuthCredentials(options$1.antigravityClientId, options$1.antigravityClientSecret);
3373
3545
  consola.info("Using provided OAuth credentials from CLI");
@@ -3396,7 +3568,7 @@ async function runServer(options$1) {
3396
3568
  }
3397
3569
  if (!await getCurrentAccount() && !hasApiKey()) throw new Error("No enabled Antigravity accounts available");
3398
3570
  }
3399
- const { getAntigravityModels: getAntigravityModels$1 } = await import("./get-models-D9Mg0iWy.js");
3571
+ const { getAntigravityModels: getAntigravityModels$1 } = await import("./get-models-CmDpYUV-.js");
3400
3572
  const models = await getAntigravityModels$1();
3401
3573
  state.antigravityModels = models;
3402
3574
  consola.info(`Available Antigravity models: \n${models.data.map((model) => `- ${model.id}`).join("\n")}`);
@@ -3420,7 +3592,7 @@ async function runServer(options$1) {
3420
3592
  const { HTTPError: HTTPError$1 } = await import("./error-CsShqJjE.js");
3421
3593
  if (error instanceof HTTPError$1 && error.response.status === 401) {
3422
3594
  consola.error("Failed to get Copilot token - GitHub token may be invalid or Copilot access revoked");
3423
- const { clearGithubToken: clearGithubToken$1 } = await import("./token-DhdRMuOy.js");
3595
+ const { clearGithubToken: clearGithubToken$1 } = await import("./token-sYqHiHEd.js");
3424
3596
  await clearGithubToken$1();
3425
3597
  consola.info("Please restart to re-authenticate");
3426
3598
  }
@@ -3592,6 +3764,7 @@ const main = defineCommand({
3592
3764
  description: "A wrapper around GitHub Copilot API to make it OpenAI/Anthropic compatible. Fork with bug fixes and improvements."
3593
3765
  },
3594
3766
  subCommands: {
3767
+ antigravity,
3595
3768
  auth,
3596
3769
  start,
3597
3770
  "check-usage": checkUsage,