@nick3/copilot-api 1.3.3 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +25 -3
  2. package/dist/account-DhQb2A6q.js +17 -0
  3. package/dist/account-DhQb2A6q.js.map +1 -0
  4. package/dist/{accounts-manager-H7YGTVk8.js → accounts-manager-DjGzZIcp.js} +18 -569
  5. package/dist/accounts-manager-DjGzZIcp.js.map +1 -0
  6. package/dist/accounts-registry-c7rs5Ed9.js +180 -0
  7. package/dist/accounts-registry-c7rs5Ed9.js.map +1 -0
  8. package/dist/admin/assets/index-BB9SaCFS.js +57 -0
  9. package/dist/admin/assets/{index-D-pIr-q0.css → index-CvffOmW7.css} +1 -1
  10. package/dist/admin/index.html +2 -2
  11. package/dist/auth-CYJuRbDb.js +241 -0
  12. package/dist/auth-CYJuRbDb.js.map +1 -0
  13. package/dist/check-usage-CVF7i8yX.js +82 -0
  14. package/dist/check-usage-CVF7i8yX.js.map +1 -0
  15. package/dist/debug-hQJWwXtC.js +82 -0
  16. package/dist/debug-hQJWwXtC.js.map +1 -0
  17. package/dist/get-copilot-token-BwP_PxV5.js +13 -0
  18. package/dist/get-copilot-token-BwP_PxV5.js.map +1 -0
  19. package/dist/main.js +25 -735
  20. package/dist/main.js.map +1 -1
  21. package/dist/paths-DoT4SZ8f.js +49 -0
  22. package/dist/paths-DoT4SZ8f.js.map +1 -0
  23. package/dist/poll-access-token-CN92flJy.js +52 -0
  24. package/dist/poll-access-token-CN92flJy.js.map +1 -0
  25. package/dist/{server-BZhJgGbw.js → server-CM_0PrbK.js} +183 -7
  26. package/dist/server-CM_0PrbK.js.map +1 -0
  27. package/dist/start-KYMwXUvr.js +302 -0
  28. package/dist/start-KYMwXUvr.js.map +1 -0
  29. package/dist/utils-BUJfM1V2.js +335 -0
  30. package/dist/utils-BUJfM1V2.js.map +1 -0
  31. package/package.json +1 -1
  32. package/dist/accounts-manager-H7YGTVk8.js.map +0 -1
  33. package/dist/admin/assets/index-C9gbhsHu.js +0 -56
  34. package/dist/server-BZhJgGbw.js.map +0 -1
package/dist/main.js CHANGED
@@ -1,740 +1,29 @@
1
1
  #!/usr/bin/env node
2
- import { HTTPError, PATHS, accountsManager, addAccountToRegistry, cacheMacMachineId, cacheVSCodeVersion, cacheVsCodeSessionId, ensurePaths, getCopilotUsage, getGitHubUser, getModelRefreshIntervalMs, getOauthAppConfig, getOauthUrls, isFreeModelLoadBalancingEnabled, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, sleep, state } from "./accounts-manager-H7YGTVk8.js";
3
- import { defineCommand, runMain } from "citty";
4
- import consola from "consola";
5
- import fs from "node:fs/promises";
6
- import os from "node:os";
7
- import clipboard from "clipboardy";
8
- import { serve } from "srvx";
9
- import invariant from "tiny-invariant";
10
- import { getProxyForUrl } from "proxy-from-env";
11
- import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
12
- import { execSync } from "node:child_process";
13
- import process$1 from "node:process";
2
+ import { defineCommand, parseArgs, runMain } from "citty";
14
3
 
15
- //#region src/lib/types/account.ts
16
- const ACCOUNT_TYPE_VALUES = [
17
- "individual",
18
- "business",
19
- "enterprise"
20
- ];
21
- function isAccountType(value) {
22
- return typeof value === "string" && ACCOUNT_TYPE_VALUES.includes(value);
23
- }
24
- function parseAccountType(value) {
25
- if (!isAccountType(value)) throw new Error(`Invalid account type: ${String(value)}. Valid values: ${ACCOUNT_TYPE_VALUES.join(", ")}`);
26
- return value;
27
- }
28
-
29
- //#endregion
30
- //#region src/services/github/get-device-code.ts
31
- async function getDeviceCode() {
32
- const { clientId, headers, scope } = getOauthAppConfig();
33
- const { deviceCodeUrl } = getOauthUrls();
34
- const response = await fetch(deviceCodeUrl, {
35
- method: "POST",
36
- headers,
37
- body: JSON.stringify({
38
- client_id: clientId,
39
- scope
40
- })
41
- });
42
- if (!response.ok) throw new HTTPError("Failed to get device code", response);
43
- return await response.json();
44
- }
45
-
46
- //#endregion
47
- //#region src/services/github/poll-access-token.ts
48
- async function pollAccessToken(deviceCode) {
49
- const { clientId, headers } = getOauthAppConfig();
50
- const { accessTokenUrl } = getOauthUrls();
51
- const sleepDuration = (deviceCode.interval + 1) * 1e3;
52
- consola.debug(`Polling access token with interval of ${sleepDuration}ms`);
53
- while (true) {
54
- const response = await fetch(accessTokenUrl, {
55
- method: "POST",
56
- headers,
57
- body: JSON.stringify({
58
- client_id: clientId,
59
- device_code: deviceCode.device_code,
60
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
61
- })
62
- });
63
- if (!response.ok) {
64
- await sleep(sleepDuration);
65
- consola.error("Failed to poll access token:", await response.text());
66
- continue;
67
- }
68
- const json = await response.json();
69
- consola.debug("Polling access token response:", json);
70
- const { access_token } = json;
71
- if (access_token) return access_token;
72
- else await sleep(sleepDuration);
73
- }
74
- }
75
-
76
- //#endregion
77
- //#region src/auth.ts
78
- /**
79
- * Fetch quota info for an account (used by auth ls -q)
80
- */
81
- async function fetchQuotaInfo(account) {
82
- try {
83
- const token = await loadAccountToken(account.id);
84
- if (!token) return " | Quota: (no token)";
85
- const premium = (await getCopilotUsage({
86
- githubToken: token,
87
- accountType: account.accountType
88
- })).quota_snapshots.premium_interactions;
89
- return premium.unlimited ? " | Quota: unlimited" : ` | Quota: ${premium.remaining}/${premium.entitlement}`;
90
- } catch (error) {
91
- consola.debug(`Failed to fetch quota for ${account.id}:`, error);
92
- return " | Quota: (failed to fetch)";
93
- }
94
- }
95
- /**
96
- * auth add - Add a new GitHub Copilot account
97
- */
98
- const authAdd = defineCommand({
99
- meta: {
100
- name: "add",
101
- description: "Add a new GitHub Copilot account"
102
- },
103
- args: {
104
- "account-type": {
105
- alias: "a",
106
- type: "string",
107
- default: "individual",
108
- description: "Account type (individual, business, enterprise)"
109
- },
110
- verbose: {
111
- alias: "v",
112
- type: "boolean",
113
- default: false,
114
- description: "Enable verbose logging"
115
- },
116
- "show-token": {
117
- type: "boolean",
118
- default: false,
119
- description: "Show GitHub token after auth"
120
- }
121
- },
122
- async run({ args }) {
123
- if (args.verbose) {
124
- consola.level = 5;
125
- consola.info("Verbose logging enabled");
126
- }
127
- state.showToken = args["show-token"];
128
- let accountType;
129
- try {
130
- accountType = parseAccountType(args["account-type"]);
131
- } catch (error) {
132
- consola.error(error instanceof Error ? error.message : String(error));
133
- process.exit(1);
134
- }
135
- await ensurePaths();
136
- consola.info("Starting GitHub device code authentication...");
137
- const deviceResponse = await getDeviceCode();
138
- consola.debug("Device code response:", deviceResponse);
139
- consola.info(`Please enter the code "${deviceResponse.user_code}" at ${deviceResponse.verification_uri}`);
140
- const token = await pollAccessToken(deviceResponse);
141
- if (state.showToken) consola.info("GitHub token:", token);
142
- const accountId = (await getGitHubUser({
143
- githubToken: token,
144
- accountType
145
- })).login;
146
- await saveAccountToken(accountId, token);
147
- const existingAccounts = await listAccountsFromRegistry();
148
- if (existingAccounts.some((acc) => acc.id === accountId)) {
149
- await saveRegistry({
150
- version: 1,
151
- accounts: existingAccounts
152
- });
153
- consola.success(`Account "${accountId}" already exists. Token has been updated.`);
154
- } else {
155
- await addAccountToRegistry({
156
- id: accountId,
157
- accountType,
158
- addedAt: Date.now()
159
- });
160
- consola.success(`Account "${accountId}" added successfully!`);
161
- }
162
- consola.info(`Account type: ${accountType}`);
163
- }
164
- });
165
- /**
166
- * auth ls - List all registered accounts
167
- */
168
- const authLs = defineCommand({
169
- meta: {
170
- name: "ls",
171
- description: "List all registered accounts"
172
- },
173
- args: {
174
- "show-quota": {
175
- alias: "q",
176
- type: "boolean",
177
- default: false,
178
- description: "Show quota information (requires API call)"
179
- },
180
- verbose: {
181
- alias: "v",
182
- type: "boolean",
183
- default: false,
184
- description: "Enable verbose logging"
185
- }
186
- },
187
- async run({ args }) {
188
- if (args.verbose) consola.level = 5;
189
- await ensurePaths();
190
- const accounts = await listAccountsFromRegistry();
191
- if (accounts.length === 0) {
192
- consola.info("No accounts registered. Use 'auth add' to add an account.");
193
- return;
194
- }
195
- consola.info(`Found ${accounts.length} account(s):\n`);
196
- for (const [i, account] of accounts.entries()) {
197
- const addedDate = new Date(account.addedAt).toLocaleString();
198
- const quotaInfo = args["show-quota"] ? await fetchQuotaInfo(account) : "";
199
- console.log(` ${i + 1}. ${account.id} (${account.accountType})${quotaInfo}`);
200
- console.log(` Added: ${addedDate}\n`);
201
- }
202
- }
203
- });
204
- /**
205
- * auth rm - Remove an account
206
- */
207
- const authRm = defineCommand({
208
- meta: {
209
- name: "rm",
210
- description: "Remove an account"
211
- },
212
- args: {
213
- target: {
214
- type: "positional",
215
- description: "Account ID or index (1-based)",
216
- required: true
217
- },
218
- force: {
219
- alias: "f",
220
- type: "boolean",
221
- default: false,
222
- description: "Skip confirmation prompt"
223
- },
224
- verbose: {
225
- alias: "v",
226
- type: "boolean",
227
- default: false,
228
- description: "Enable verbose logging"
229
- }
230
- },
231
- async run({ args }) {
232
- if (args.verbose) consola.level = 5;
233
- await ensurePaths();
234
- const target = args.target;
235
- const accounts = await listAccountsFromRegistry();
236
- if (accounts.length === 0) {
237
- consola.error("No accounts to remove.");
238
- return;
239
- }
240
- let accountToRemove;
241
- const index = Number.parseInt(target, 10);
242
- if (!Number.isNaN(index) && index >= 1 && index <= accounts.length) accountToRemove = {
243
- id: accounts[index - 1].id,
244
- index: index - 1
245
- };
246
- else {
247
- const foundIndex = accounts.findIndex((acc) => acc.id === target);
248
- if (foundIndex !== -1) accountToRemove = {
249
- id: accounts[foundIndex].id,
250
- index: foundIndex
251
- };
252
- }
253
- if (!accountToRemove) {
254
- consola.error(`Account "${target}" not found.`);
255
- consola.info("Use 'auth ls' to see available accounts.");
256
- return;
257
- }
258
- if (!args.force) {
259
- if (!await consola.prompt(`Are you sure you want to remove account "${accountToRemove.id}"?`, { type: "confirm" })) {
260
- consola.info("Cancelled.");
261
- return;
262
- }
263
- }
264
- await removeAccountToken(accountToRemove.id);
265
- await removeAccountFromRegistry(accountToRemove.id);
266
- consola.success(`Account "${accountToRemove.id}" removed.`);
267
- }
268
- });
269
- /**
270
- * Main auth command with subcommands
271
- */
272
- const auth = defineCommand({
273
- meta: {
274
- name: "auth",
275
- description: "Manage GitHub Copilot accounts"
276
- },
277
- subCommands: {
278
- add: authAdd,
279
- ls: authLs,
280
- rm: authRm
281
- },
282
- args: {
283
- "account-type": {
284
- alias: "a",
285
- type: "string",
286
- default: "individual",
287
- description: "Account type (individual, business, enterprise)"
288
- },
289
- verbose: {
290
- alias: "v",
291
- type: "boolean",
292
- default: false,
293
- description: "Enable verbose logging"
294
- },
295
- "show-token": {
296
- type: "boolean",
297
- default: false,
298
- description: "Show GitHub token after auth"
299
- }
300
- },
301
- async run(ctx) {
302
- const firstArg = ctx.rawArgs[0];
303
- if (!(firstArg === "add" || firstArg === "ls" || firstArg === "rm") && authAdd.run) await authAdd.run(ctx);
304
- }
305
- });
306
-
307
- //#endregion
308
- //#region src/lib/token.ts
309
- const readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8");
310
- const writeGithubToken = (token) => fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token);
311
- async function setupGitHubToken(options) {
312
- try {
313
- const githubToken = await readGithubToken();
314
- if (githubToken && !options?.force) {
315
- state.githubToken = githubToken;
316
- if (state.showToken) consola.info("GitHub token:", githubToken);
317
- await logUser();
318
- return;
319
- }
320
- consola.info("Not logged in, getting new access token");
321
- const response = await getDeviceCode();
322
- consola.debug("Device code response:", response);
323
- consola.info(`Please enter the code "${response.user_code}" in ${response.verification_uri}`);
324
- const token = await pollAccessToken(response);
325
- await writeGithubToken(token);
326
- state.githubToken = token;
327
- if (state.showToken) consola.info("GitHub token:", token);
328
- await logUser();
329
- } catch (error) {
330
- if (error instanceof HTTPError) {
331
- consola.error("Failed to get GitHub token:", await error.response.json());
332
- throw error;
333
- }
334
- consola.error("Failed to get GitHub token:", error);
335
- throw error;
336
- }
337
- }
338
- async function logUser() {
339
- const user = await getGitHubUser();
340
- consola.info(`Logged in as ${user.login}`);
341
- }
342
-
343
- //#endregion
344
- //#region src/check-usage.ts
345
- const checkUsage = defineCommand({
346
- meta: {
347
- name: "check-usage",
348
- description: "Show current GitHub Copilot usage/quota information"
349
- },
350
- async run() {
351
- await ensurePaths();
352
- await setupGitHubToken();
353
- try {
354
- const usage = await getCopilotUsage();
355
- const premium = usage.quota_snapshots.premium_interactions;
356
- const premiumTotal = premium.entitlement;
357
- const premiumUsed = premiumTotal - premium.remaining;
358
- const premiumPercentUsed = premiumTotal > 0 ? premiumUsed / premiumTotal * 100 : 0;
359
- const premiumPercentRemaining = premium.percent_remaining;
360
- function summarizeQuota(name, snap) {
361
- if (!snap) return `${name}: N/A`;
362
- const total = snap.entitlement;
363
- const used = total - snap.remaining;
364
- const percentUsed = total > 0 ? used / total * 100 : 0;
365
- const percentRemaining = snap.percent_remaining;
366
- return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`;
367
- }
368
- const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`;
369
- const chatLine = summarizeQuota("Chat", usage.quota_snapshots.chat);
370
- const completionsLine = summarizeQuota("Completions", usage.quota_snapshots.completions);
371
- consola.box(`Copilot Usage (plan: ${usage.copilot_plan})\nQuota resets: ${usage.quota_reset_date}\n\nQuotas:\n ${premiumLine}\n ${chatLine}\n ${completionsLine}`);
372
- } catch (err) {
373
- consola.error("Failed to fetch Copilot usage:", err);
374
- process.exit(1);
375
- }
376
- }
377
- });
378
-
379
- //#endregion
380
- //#region src/debug.ts
381
- async function getPackageVersion() {
382
- try {
383
- const packageJsonPath = new URL("../package.json", import.meta.url).pathname;
384
- return JSON.parse(await fs.readFile(packageJsonPath)).version;
385
- } catch {
386
- return "unknown";
387
- }
388
- }
389
- function getRuntimeInfo() {
390
- const isBun = typeof Bun !== "undefined";
391
- return {
392
- name: isBun ? "bun" : "node",
393
- version: isBun ? Bun.version : process.version.slice(1),
394
- platform: os.platform(),
395
- arch: os.arch()
396
- };
397
- }
398
- async function checkTokenExists() {
399
- try {
400
- if (!(await fs.stat(PATHS.GITHUB_TOKEN_PATH)).isFile()) return false;
401
- return (await fs.readFile(PATHS.GITHUB_TOKEN_PATH, "utf8")).trim().length > 0;
402
- } catch {
403
- return false;
404
- }
405
- }
406
- async function getDebugInfo() {
407
- const [version, tokenExists] = await Promise.all([getPackageVersion(), checkTokenExists()]);
408
- return {
409
- version,
410
- runtime: getRuntimeInfo(),
411
- paths: {
412
- APP_DIR: PATHS.APP_DIR,
413
- GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH
414
- },
415
- tokenExists
416
- };
417
- }
418
- function printDebugInfoPlain(info) {
419
- consola.info(`copilot-api debug
420
-
421
- Version: ${info.version}
422
- Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})
423
-
424
- Paths:
425
- - APP_DIR: ${info.paths.APP_DIR}
426
- - GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}
427
-
428
- Token exists: ${info.tokenExists ? "Yes" : "No"}`);
429
- }
430
- function printDebugInfoJson(info) {
431
- console.log(JSON.stringify(info, null, 2));
432
- }
433
- async function runDebug(options) {
434
- const debugInfo = await getDebugInfo();
435
- if (options.json) printDebugInfoJson(debugInfo);
436
- else printDebugInfoPlain(debugInfo);
437
- }
438
- const debug = defineCommand({
439
- meta: {
440
- name: "debug",
441
- description: "Print debug information about the application"
442
- },
443
- args: { json: {
444
- type: "boolean",
445
- default: false,
446
- description: "Output debug information as JSON"
447
- } },
448
- run({ args }) {
449
- return runDebug({ json: args.json });
450
- }
451
- });
452
-
453
- //#endregion
454
- //#region src/lib/proxy.ts
455
- function initProxyFromEnv() {
456
- if (typeof Bun !== "undefined") return;
457
- try {
458
- const direct = new Agent();
459
- const proxies = /* @__PURE__ */ new Map();
460
- setGlobalDispatcher({
461
- dispatch(options, handler) {
462
- try {
463
- const origin = typeof options.origin === "string" ? new URL(options.origin) : options.origin;
464
- const raw = getProxyForUrl(origin.toString());
465
- const proxyUrl = raw && raw.length > 0 ? raw : void 0;
466
- if (!proxyUrl) {
467
- consola.debug(`HTTP proxy bypass: ${origin.hostname}`);
468
- return direct.dispatch(options, handler);
469
- }
470
- let agent = proxies.get(proxyUrl);
471
- if (!agent) {
472
- agent = new ProxyAgent(proxyUrl);
473
- proxies.set(proxyUrl, agent);
474
- }
475
- let label = proxyUrl;
476
- try {
477
- const u = new URL(proxyUrl);
478
- label = `${u.protocol}//${u.host}`;
479
- } catch {}
480
- consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`);
481
- return agent.dispatch(options, handler);
482
- } catch {
483
- return direct.dispatch(options, handler);
484
- }
485
- },
486
- close() {
487
- return direct.close();
488
- },
489
- destroy() {
490
- return direct.destroy();
491
- }
492
- });
493
- consola.debug("HTTP proxy configured from environment (per-URL)");
494
- } catch (err) {
495
- consola.debug("Proxy setup skipped:", err);
496
- }
497
- }
498
-
499
- //#endregion
500
- //#region src/lib/shell.ts
501
- function getShell() {
502
- const { platform, ppid, env } = process$1;
503
- if (platform === "win32") {
504
- try {
505
- const command = `wmic process get ParentProcessId,Name | findstr "${ppid}"`;
506
- if (execSync(command, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
507
- } catch {
508
- return "cmd";
509
- }
510
- return "cmd";
511
- } else {
512
- const shellPath = env.SHELL;
513
- if (shellPath) {
514
- if (shellPath.endsWith("zsh")) return "zsh";
515
- if (shellPath.endsWith("fish")) return "fish";
516
- if (shellPath.endsWith("bash")) return "bash";
517
- }
518
- return "sh";
519
- }
520
- }
521
- /**
522
- * Generates a copy-pasteable script to set multiple environment variables
523
- * and run a subsequent command.
524
- * @param {EnvVars} envVars - An object of environment variables to set.
525
- * @param {string} commandToRun - The command to run after setting the variables.
526
- * @returns {string} The formatted script string.
527
- */
528
- function generateEnvScript(envVars, commandToRun = "") {
529
- const shell = getShell();
530
- const filteredEnvVars = Object.entries(envVars).filter(([, value]) => value !== void 0);
531
- let commandBlock;
532
- switch (shell) {
533
- case "powershell":
534
- commandBlock = filteredEnvVars.map(([key, value]) => `$env:${key} = ${value}`).join("; ");
535
- break;
536
- case "cmd":
537
- commandBlock = filteredEnvVars.map(([key, value]) => `set ${key}=${value}`).join(" & ");
538
- break;
539
- case "fish":
540
- commandBlock = filteredEnvVars.map(([key, value]) => `set -gx ${key} ${value}`).join("; ");
541
- break;
542
- default: {
543
- const assignments = filteredEnvVars.map(([key, value]) => `${key}=${value}`).join(" ");
544
- commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : "";
545
- break;
546
- }
547
- }
548
- if (commandBlock && commandToRun) return `${commandBlock}${shell === "cmd" ? " & " : " && "}${commandToRun}`;
549
- return commandBlock || commandToRun;
550
- }
551
-
552
- //#endregion
553
- //#region src/start.ts
554
- /**
555
- * Run the interactive authentication flow to add a new account.
556
- * Called automatically when no accounts are found.
557
- */
558
- async function runAuthFlow(accountType) {
559
- consola.warn("No accounts found. Starting authentication flow...");
560
- const deviceResponse = await getDeviceCode();
561
- consola.info(`Please enter the code "${deviceResponse.user_code}" at ${deviceResponse.verification_uri}`);
562
- const token = await pollAccessToken(deviceResponse);
563
- if (state.showToken) consola.info("GitHub token:", token);
564
- const accountId = (await getGitHubUser({
565
- githubToken: token,
566
- accountType
567
- })).login;
568
- await saveAccountToken(accountId, token);
569
- await addAccountToRegistry({
570
- id: accountId,
571
- accountType,
572
- addedAt: Date.now()
573
- });
574
- consola.success(`Account "${accountId}" added successfully!`);
575
- }
576
- async function runServer(options) {
577
- mergeConfigWithDefaults();
578
- accountsManager.setFreeModelLoadBalancingEnabled(isFreeModelLoadBalancingEnabled());
579
- accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
580
- if (options.proxyEnv) initProxyFromEnv();
581
- state.verbose = options.verbose;
582
- if (options.verbose) {
583
- consola.level = 5;
584
- consola.info("Verbose logging enabled");
585
- }
586
- state.accountType = options.accountType;
587
- if (options.accountType !== "individual") consola.info(`Using ${options.accountType} plan GitHub account`);
588
- state.manualApprove = options.manual;
589
- state.rateLimitSeconds = options.rateLimit;
590
- state.rateLimitWait = options.rateLimitWait;
591
- state.showToken = options.showToken;
592
- await ensurePaths();
593
- await cacheVSCodeVersion();
594
- cacheMacMachineId();
595
- cacheVsCodeSessionId();
596
- await accountsManager.initialize(state.vsCodeVersion);
597
- if (options.githubToken) {
598
- await accountsManager.setTemporaryAccount(options.githubToken, options.accountType);
599
- consola.info("Using provided GitHub token as temporary account");
600
- }
601
- if (!accountsManager.hasAccounts()) try {
602
- await runAuthFlow(options.accountType);
603
- accountsManager.shutdown();
604
- await accountsManager.initialize(state.vsCodeVersion);
605
- accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
606
- } catch (error) {
607
- consola.error("Failed to add account:", error);
608
- process.exit(1);
609
- }
610
- const models = accountsManager.getFirstAccountModels();
611
- consola.info(`Available models: \n${models?.data.map((model) => `- ${model.id}`).join("\n") ?? "(no models loaded)"}`);
612
- const serverUrl = `http://localhost:${options.port}`;
613
- if (options.claudeCode) {
614
- invariant(models, "Models should be loaded by now");
615
- const selectedModel = await consola.prompt("Select a model to use with Claude Code", {
616
- type: "select",
617
- options: models.data.map((model) => model.id)
618
- });
619
- const selectedSmallModel = await consola.prompt("Select a small model to use with Claude Code", {
620
- type: "select",
621
- options: models.data.map((model) => model.id)
622
- });
623
- const command = generateEnvScript({
624
- ANTHROPIC_BASE_URL: serverUrl,
625
- ANTHROPIC_AUTH_TOKEN: "dummy",
626
- ANTHROPIC_MODEL: selectedModel,
627
- ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,
628
- ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,
629
- ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,
630
- DISABLE_NON_ESSENTIAL_MODEL_CALLS: "1",
631
- CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1"
632
- }, "claude");
633
- try {
634
- clipboard.writeSync(command);
635
- consola.success("Copied Claude Code command to clipboard!");
636
- } catch {
637
- consola.warn("Failed to copy to clipboard. Here is the Claude Code command:");
638
- consola.log(command);
639
- }
640
- }
641
- consola.box(`🌐 Admin UI: ${serverUrl}/admin`);
642
- const { server } = await import("./server-BZhJgGbw.js");
643
- serve({
644
- fetch: server.fetch,
645
- port: options.port,
646
- bun: { idleTimeout: 0 }
647
- });
648
- }
649
- const start = defineCommand({
650
- meta: {
651
- name: "start",
652
- description: "Start the Copilot API server"
653
- },
654
- args: {
655
- port: {
656
- alias: "p",
657
- type: "string",
658
- default: "4141",
659
- description: "Port to listen on"
660
- },
661
- verbose: {
662
- alias: "v",
663
- type: "boolean",
664
- default: false,
665
- description: "Enable verbose logging"
666
- },
667
- "account-type": {
668
- alias: "a",
669
- type: "string",
670
- default: "individual",
671
- description: "Account type to use (individual, business, enterprise)"
672
- },
673
- manual: {
674
- type: "boolean",
675
- default: false,
676
- description: "Enable manual request approval"
677
- },
678
- "rate-limit": {
679
- alias: "r",
680
- type: "string",
681
- description: "Rate limit in seconds between requests"
682
- },
683
- wait: {
684
- alias: "w",
685
- type: "boolean",
686
- default: false,
687
- description: "Wait instead of error when rate limit is hit. Has no effect if rate limit is not set"
688
- },
689
- "github-token": {
690
- alias: "g",
691
- type: "string",
692
- description: "Provide GitHub token directly (must be generated using the `auth` subcommand)"
693
- },
694
- "claude-code": {
695
- alias: "c",
696
- type: "boolean",
697
- default: false,
698
- description: "Generate a command to launch Claude Code with Copilot API config"
699
- },
700
- "show-token": {
701
- type: "boolean",
702
- default: false,
703
- description: "Show GitHub and Copilot tokens on fetch and refresh"
704
- },
705
- "proxy-env": {
706
- type: "boolean",
707
- default: false,
708
- description: "Initialize proxy from environment variables"
709
- }
710
- },
711
- run({ args }) {
712
- const rateLimitRaw = args["rate-limit"];
713
- const rateLimit = rateLimitRaw === void 0 ? void 0 : Number.parseInt(rateLimitRaw, 10);
714
- let accountType;
715
- try {
716
- accountType = parseAccountType(args["account-type"]);
717
- } catch (error) {
718
- consola.error(error instanceof Error ? error.message : String(error));
719
- process.exit(1);
720
- }
721
- return runServer({
722
- port: Number.parseInt(args.port, 10),
723
- verbose: args.verbose,
724
- accountType,
725
- manual: args.manual,
726
- rateLimit,
727
- rateLimitWait: args.wait,
728
- githubToken: args["github-token"],
729
- claudeCode: args["claude-code"],
730
- showToken: args["show-token"],
731
- proxyEnv: args["proxy-env"]
732
- });
733
- }
734
- });
735
-
736
- //#endregion
737
4
  //#region src/main.ts
5
+ const cliArgs = {
6
+ "api-home": {
7
+ type: "string",
8
+ description: "Path to the API home directory."
9
+ },
10
+ "oauth-app": {
11
+ type: "string",
12
+ description: "OAuth app identifier."
13
+ },
14
+ "enterprise-url": {
15
+ type: "string",
16
+ description: "Enterprise URL for GitHub."
17
+ }
18
+ };
19
+ const args = parseArgs(process.argv, cliArgs);
20
+ if (typeof args["api-home"] === "string") process.env.COPILOT_API_HOME = args["api-home"];
21
+ if (typeof args["oauth-app"] === "string") process.env.COPILOT_API_OAUTH_APP = args["oauth-app"];
22
+ if (typeof args["enterprise-url"] === "string") process.env.COPILOT_API_ENTERPRISE_URL = args["enterprise-url"];
23
+ const { auth } = await import("./auth-CYJuRbDb.js");
24
+ const { checkUsage } = await import("./check-usage-CVF7i8yX.js");
25
+ const { debug } = await import("./debug-hQJWwXtC.js");
26
+ const { start } = await import("./start-KYMwXUvr.js");
738
27
  const main = defineCommand({
739
28
  meta: {
740
29
  name: "copilot-api",
@@ -745,7 +34,8 @@ const main = defineCommand({
745
34
  start,
746
35
  "check-usage": checkUsage,
747
36
  debug
748
- }
37
+ },
38
+ args: cliArgs
749
39
  });
750
40
  await runMain(main);
751
41