@jeffreycao/copilot-api 2.7.1 → 2.7.2
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/auth-C3_rHdk6.js +2 -0
- package/dist/{auth-2VWfdcpq.js → auth-DC-EO-eb.js} +68 -26
- package/dist/auth-DC-EO-eb.js.map +1 -0
- package/dist/{config-B2OaAnpL.js → config-DIDLVXMU.js} +24 -6
- package/dist/config-DIDLVXMU.js.map +1 -0
- package/dist/{config-store-CARrUljo.js → config-store-CMgB1mCV.js} +2 -1
- package/dist/config-store-CMgB1mCV.js.map +1 -0
- package/dist/{copilot-runtime-B7T_EuGD.js → copilot-runtime-CRTYwDWy.js} +3 -3
- package/dist/{copilot-runtime-B7T_EuGD.js.map → copilot-runtime-CRTYwDWy.js.map} +1 -1
- package/dist/{debug-CcfAczV9.js → debug-B0URJ4gT.js} +3 -3
- package/dist/{debug-CcfAczV9.js.map → debug-B0URJ4gT.js.map} +1 -1
- package/dist/{github-copilot-provider-DlQZgaCT.js → github-copilot-provider-CLEAHyT-.js} +2 -2
- package/dist/{github-copilot-provider-DlQZgaCT.js.map → github-copilot-provider-CLEAHyT-.js.map} +1 -1
- package/dist/main.js +6 -6
- package/dist/{mcp-Byz9h_xz.js → mcp-CuZyqwi8.js} +2 -2
- package/dist/{mcp-Byz9h_xz.js.map → mcp-CuZyqwi8.js.map} +1 -1
- package/dist/mcp-server-BH-SFdCD.js +2 -0
- package/dist/{mcp-server-D6uKVzo6.js → mcp-server-CKEydKaf.js} +2 -2
- package/dist/{mcp-server-D6uKVzo6.js.map → mcp-server-CKEydKaf.js.map} +1 -1
- package/dist/{provider-DktH3jcC.js → provider-C2Hs8Dua.js} +2 -2
- package/dist/{provider-DktH3jcC.js.map → provider-C2Hs8Dua.js.map} +1 -1
- package/dist/{provider-management-z3m7cUkp.js → provider-management-BjU3aJnC.js} +3 -3
- package/dist/{provider-management-z3m7cUkp.js.map → provider-management-BjU3aJnC.js.map} +1 -1
- package/dist/{server-BYG25POu.js → server-DbkseGH6.js} +96 -24
- package/dist/server-DbkseGH6.js.map +1 -0
- package/dist/{start-v0WnZYEn.js → start-C_Svr70X.js} +8 -8
- package/dist/{start-v0WnZYEn.js.map → start-C_Svr70X.js.map} +1 -1
- package/dist/{token-Cx07G8-R.js → token-BjzzuPSb.js} +604 -334
- package/dist/token-BjzzuPSb.js.map +1 -0
- package/package.json +1 -1
- package/dist/auth-2VWfdcpq.js.map +0 -1
- package/dist/auth-DFH2l7hT.js +0 -2
- package/dist/config-B2OaAnpL.js.map +0 -1
- package/dist/config-store-CARrUljo.js.map +0 -1
- package/dist/mcp-server-ouCaZXlw.js +0 -2
- package/dist/server-BYG25POu.js.map +0 -1
- package/dist/token-Cx07G8-R.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as writeFileAtomically, _ as readEditableConfigFromDisk, c as getConfig, h as isResponsesApiWebSocketEnabled, u as getUpstreamTransportConfig, x as PATHS } from "./config-store-
|
|
2
|
-
import { c as setProviderConfig, n as getRawProviderConfig } from "./config-
|
|
3
|
-
import { a as UpstreamHeadersTimeoutError, i as HTTPError, n as assertGitHubCopilotEnabled, o as UpstreamStreamInactivityTimeoutError } from "./github-copilot-provider-
|
|
1
|
+
import { C as writeFileAtomically, _ as readEditableConfigFromDisk, c as getConfig, h as isResponsesApiWebSocketEnabled, u as getUpstreamTransportConfig, x as PATHS } from "./config-store-CMgB1mCV.js";
|
|
2
|
+
import { c as setProviderConfig, n as getRawProviderConfig } from "./config-DIDLVXMU.js";
|
|
3
|
+
import { a as UpstreamHeadersTimeoutError, i as HTTPError, n as assertGitHubCopilotEnabled, o as UpstreamStreamInactivityTimeoutError } from "./github-copilot-provider-CLEAHyT-.js";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
6
6
|
import path from "node:path";
|
|
@@ -11,6 +11,7 @@ import { WebSocket } from "undici";
|
|
|
11
11
|
import { events } from "fetch-event-stream";
|
|
12
12
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
13
13
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
14
|
+
import { z } from "zod";
|
|
14
15
|
import { exec } from "node:child_process";
|
|
15
16
|
//#region src/lib/internal-headers.ts
|
|
16
17
|
const FULL_MODEL_CATALOG_HEADER = "x-full-model-catalog";
|
|
@@ -980,13 +981,13 @@ function shouldIncludeHeader(headerName) {
|
|
|
980
981
|
const CALLBACK_HOST = "127.0.0.1";
|
|
981
982
|
const CALLBACK_PORT = 1455;
|
|
982
983
|
const CALLBACK_PATH = "/auth/callback";
|
|
983
|
-
const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
984
|
+
const CLIENT_ID$1 = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
984
985
|
const AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
|
|
985
986
|
const TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
986
987
|
const REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
987
|
-
const SCOPE = "openid profile email offline_access";
|
|
988
|
+
const SCOPE$1 = "openid profile email offline_access";
|
|
988
989
|
const JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
989
|
-
const REFRESH_BUFFER_MS = 6e4;
|
|
990
|
+
const REFRESH_BUFFER_MS$1 = 6e4;
|
|
990
991
|
const CALLBACK_TIMEOUT_MS = 12e4;
|
|
991
992
|
const REFRESH_TIMEOUT_MS = 3e4;
|
|
992
993
|
var CodexOAuthError = class extends Error {
|
|
@@ -1048,7 +1049,7 @@ function decodeJwt(accessToken) {
|
|
|
1048
1049
|
return null;
|
|
1049
1050
|
}
|
|
1050
1051
|
}
|
|
1051
|
-
function getAccountId(accessToken) {
|
|
1052
|
+
function getAccountId$1(accessToken) {
|
|
1052
1053
|
const payload = decodeJwt(accessToken);
|
|
1053
1054
|
if (!payload) return null;
|
|
1054
1055
|
const authPayload = payload[JWT_CLAIM_PATH];
|
|
@@ -1122,7 +1123,7 @@ async function exchangeAuthorizationCode(code, verifier, signal) {
|
|
|
1122
1123
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1123
1124
|
body: new URLSearchParams({
|
|
1124
1125
|
grant_type: "authorization_code",
|
|
1125
|
-
client_id: CLIENT_ID,
|
|
1126
|
+
client_id: CLIENT_ID$1,
|
|
1126
1127
|
code,
|
|
1127
1128
|
code_verifier: verifier,
|
|
1128
1129
|
redirect_uri: REDIRECT_URI
|
|
@@ -1152,7 +1153,7 @@ async function refreshAccessToken(refreshToken, options = {}) {
|
|
|
1152
1153
|
body: new URLSearchParams({
|
|
1153
1154
|
grant_type: "refresh_token",
|
|
1154
1155
|
refresh_token: refreshToken,
|
|
1155
|
-
client_id: CLIENT_ID
|
|
1156
|
+
client_id: CLIENT_ID$1
|
|
1156
1157
|
}),
|
|
1157
1158
|
signal
|
|
1158
1159
|
});
|
|
@@ -1177,9 +1178,9 @@ async function createAuthorizationFlow() {
|
|
|
1177
1178
|
const state = createState();
|
|
1178
1179
|
const url = new URL(AUTHORIZE_URL);
|
|
1179
1180
|
url.searchParams.set("response_type", "code");
|
|
1180
|
-
url.searchParams.set("client_id", CLIENT_ID);
|
|
1181
|
+
url.searchParams.set("client_id", CLIENT_ID$1);
|
|
1181
1182
|
url.searchParams.set("redirect_uri", REDIRECT_URI);
|
|
1182
|
-
url.searchParams.set("scope", SCOPE);
|
|
1183
|
+
url.searchParams.set("scope", SCOPE$1);
|
|
1183
1184
|
url.searchParams.set("code_challenge", challenge);
|
|
1184
1185
|
url.searchParams.set("code_challenge_method", "S256");
|
|
1185
1186
|
url.searchParams.set("state", state);
|
|
@@ -1295,7 +1296,7 @@ async function loginCodex(options) {
|
|
|
1295
1296
|
if (!code) throw callbackError ?? /* @__PURE__ */ new Error("Missing Codex authorization code");
|
|
1296
1297
|
const tokenResult = await exchangeAuthorizationCode(code, verifier, options.signal);
|
|
1297
1298
|
options.signal?.throwIfAborted();
|
|
1298
|
-
const accountId = getAccountId(tokenResult.accessToken);
|
|
1299
|
+
const accountId = getAccountId$1(tokenResult.accessToken);
|
|
1299
1300
|
if (!accountId) throw new Error("Failed to extract Codex account id from access token");
|
|
1300
1301
|
return {
|
|
1301
1302
|
accessToken: tokenResult.accessToken,
|
|
@@ -1306,17 +1307,590 @@ async function loginCodex(options) {
|
|
|
1306
1307
|
}
|
|
1307
1308
|
async function refreshCodexCredentials(credentials, options = {}) {
|
|
1308
1309
|
const tokenResult = await refreshAccessToken(credentials.refreshToken, options);
|
|
1309
|
-
const accountId = getAccountId(tokenResult.accessToken);
|
|
1310
|
+
const accountId = getAccountId$1(tokenResult.accessToken);
|
|
1310
1311
|
if (!accountId) throw new Error("Failed to extract Codex account id from access token");
|
|
1311
1312
|
return {
|
|
1312
|
-
accessToken: tokenResult.accessToken,
|
|
1313
|
-
refreshToken: tokenResult.refreshToken,
|
|
1314
|
-
expiresAt: tokenResult.expiresAt,
|
|
1315
|
-
accountId
|
|
1313
|
+
accessToken: tokenResult.accessToken,
|
|
1314
|
+
refreshToken: tokenResult.refreshToken,
|
|
1315
|
+
expiresAt: tokenResult.expiresAt,
|
|
1316
|
+
accountId
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
function isCodexCredentialsExpired(credentials, now = Date.now()) {
|
|
1320
|
+
return credentials.expiresAt <= now + REFRESH_BUFFER_MS$1;
|
|
1321
|
+
}
|
|
1322
|
+
//#endregion
|
|
1323
|
+
//#region src/lib/oauth/xai.ts
|
|
1324
|
+
const XAI_API_BASE_URL = "https://api.x.ai";
|
|
1325
|
+
const CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
|
|
1326
|
+
const ISSUER = "https://auth.x.ai/oauth2";
|
|
1327
|
+
const SCOPE = "openid profile email offline_access grok-cli:access api:access";
|
|
1328
|
+
const REQUEST_TIMEOUT_MS = 3e4;
|
|
1329
|
+
const POLLING_SAFETY_MARGIN_MS = 3e3;
|
|
1330
|
+
const REFRESH_BUFFER_MS = 6e4;
|
|
1331
|
+
const tokenSchema = z.object({
|
|
1332
|
+
access_token: z.string().trim().min(1),
|
|
1333
|
+
refresh_token: z.string().trim().min(1).optional(),
|
|
1334
|
+
id_token: z.string().optional(),
|
|
1335
|
+
expires_in: z.number().finite().optional()
|
|
1336
|
+
});
|
|
1337
|
+
const deviceSchema = z.object({
|
|
1338
|
+
device_code: z.string().min(1),
|
|
1339
|
+
user_code: z.string().min(1),
|
|
1340
|
+
verification_uri: z.url({ protocol: /^https$/u }),
|
|
1341
|
+
verification_uri_complete: z.url({ protocol: /^https$/u }).optional(),
|
|
1342
|
+
expires_in: z.number().finite().optional(),
|
|
1343
|
+
interval: z.number().finite().optional()
|
|
1344
|
+
});
|
|
1345
|
+
const errorSchema = z.object({ error: z.string().optional() });
|
|
1346
|
+
var XaiOAuthError = class extends Error {
|
|
1347
|
+
reason;
|
|
1348
|
+
constructor(reason) {
|
|
1349
|
+
super(reason === "authorization_expired" ? "xAI device code expired. Please sign in again." : "xAI device authorization was denied.");
|
|
1350
|
+
this.name = "XaiOAuthError";
|
|
1351
|
+
this.reason = reason;
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
function positiveSeconds(value, fallback) {
|
|
1355
|
+
return value !== void 0 && value > 0 ? value : fallback;
|
|
1356
|
+
}
|
|
1357
|
+
function tokenCredentials(tokens, currentRefreshToken) {
|
|
1358
|
+
const refreshToken = tokens.refresh_token ?? currentRefreshToken;
|
|
1359
|
+
if (!refreshToken) throw new Error("xAI token response is missing refresh_token");
|
|
1360
|
+
let expiresAt = Date.now() + positiveSeconds(tokens.expires_in, 3600) * 1e3;
|
|
1361
|
+
if (!tokens.expires_in || tokens.expires_in <= 0) try {
|
|
1362
|
+
const payload = JSON.parse(Buffer.from(tokens.access_token.split(".")[1], "base64url").toString("utf8"));
|
|
1363
|
+
const claims = z.object({ exp: z.number().finite().positive() }).safeParse(payload);
|
|
1364
|
+
if (claims.success) expiresAt = claims.data.exp * 1e3;
|
|
1365
|
+
} catch {}
|
|
1366
|
+
return {
|
|
1367
|
+
accessToken: tokens.access_token,
|
|
1368
|
+
refreshToken,
|
|
1369
|
+
expiresAt
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
function tokenAccountId(token) {
|
|
1373
|
+
if (!token) return void 0;
|
|
1374
|
+
try {
|
|
1375
|
+
const payload = JSON.parse(Buffer.from(token.split(".")[1], "base64url").toString("utf8"));
|
|
1376
|
+
const claims = z.object({ sub: z.string().trim().min(1) }).safeParse(payload);
|
|
1377
|
+
return claims.success ? claims.data.sub : void 0;
|
|
1378
|
+
} catch {
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
async function getAccountId(tokens, signal, dependencies) {
|
|
1383
|
+
const accountId = tokenAccountId(tokens.id_token) ?? tokenAccountId(tokens.access_token);
|
|
1384
|
+
if (accountId) return accountId;
|
|
1385
|
+
const response = await (dependencies.fetcher ?? fetch)(`${ISSUER}/userinfo`, {
|
|
1386
|
+
headers: {
|
|
1387
|
+
Authorization: `Bearer ${tokens.access_token}`,
|
|
1388
|
+
Accept: "application/json"
|
|
1389
|
+
},
|
|
1390
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(REQUEST_TIMEOUT_MS)])
|
|
1391
|
+
});
|
|
1392
|
+
if (!response.ok) throw requestError(response, await readOAuthError(response));
|
|
1393
|
+
const user = z.object({ sub: z.string().trim().min(1) }).parse(await response.json());
|
|
1394
|
+
signal.throwIfAborted();
|
|
1395
|
+
return user.sub;
|
|
1396
|
+
}
|
|
1397
|
+
async function send(endpoint, body, options = {}, dependencies = {}) {
|
|
1398
|
+
const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
1399
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
1400
|
+
const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
|
|
1401
|
+
try {
|
|
1402
|
+
return await (dependencies.fetcher ?? fetch)(`${ISSUER}/${endpoint}`, {
|
|
1403
|
+
method: "POST",
|
|
1404
|
+
headers: {
|
|
1405
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1406
|
+
Accept: "application/json",
|
|
1407
|
+
"User-Agent": "copilot-api"
|
|
1408
|
+
},
|
|
1409
|
+
body: new URLSearchParams(body),
|
|
1410
|
+
signal
|
|
1411
|
+
});
|
|
1412
|
+
} catch (error) {
|
|
1413
|
+
options.signal?.throwIfAborted();
|
|
1414
|
+
if (timeout.aborted) throw new Error(`xAI authorization request timed out after ${timeoutMs}ms`, { cause: error });
|
|
1415
|
+
throw error;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
async function readOAuthError(response) {
|
|
1419
|
+
const payload = await response.json().catch(() => null);
|
|
1420
|
+
const parsed = errorSchema.safeParse(payload);
|
|
1421
|
+
return parsed.success ? parsed.data.error : void 0;
|
|
1422
|
+
}
|
|
1423
|
+
function requestError(response, error) {
|
|
1424
|
+
const detail = error && /^[a-z_]+$/u.test(error) ? `: ${error}` : "";
|
|
1425
|
+
return /* @__PURE__ */ new Error(`xAI authorization request failed (${response.status})${detail}`);
|
|
1426
|
+
}
|
|
1427
|
+
async function loginXai(options, dependencies = {}) {
|
|
1428
|
+
options.signal?.throwIfAborted();
|
|
1429
|
+
const response = await send("device/code", {
|
|
1430
|
+
client_id: CLIENT_ID,
|
|
1431
|
+
scope: SCOPE,
|
|
1432
|
+
referrer: "opencode"
|
|
1433
|
+
}, options, dependencies);
|
|
1434
|
+
if (!response.ok) throw requestError(response, await readOAuthError(response));
|
|
1435
|
+
const device = deviceSchema.parse(await response.json());
|
|
1436
|
+
options.signal?.throwIfAborted();
|
|
1437
|
+
const lifetimeMs = positiveSeconds(device.expires_in, 300) * 1e3;
|
|
1438
|
+
const expiresAt = Date.now() + lifetimeMs;
|
|
1439
|
+
const timeout = AbortSignal.timeout(lifetimeMs);
|
|
1440
|
+
const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
|
|
1441
|
+
options.onAuth({
|
|
1442
|
+
url: device.verification_uri_complete ?? device.verification_uri,
|
|
1443
|
+
verificationUri: device.verification_uri,
|
|
1444
|
+
userCode: device.user_code,
|
|
1445
|
+
expiresAt
|
|
1446
|
+
});
|
|
1447
|
+
let intervalMs = Math.max(positiveSeconds(device.interval, 5) * 1e3, 1e3);
|
|
1448
|
+
const sleep = dependencies.sleep ?? ((ms, abortSignal) => setTimeout$1(ms, void 0, { signal: abortSignal }));
|
|
1449
|
+
try {
|
|
1450
|
+
for (;;) {
|
|
1451
|
+
signal.throwIfAborted();
|
|
1452
|
+
const tokenResponse = await send("token", {
|
|
1453
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
1454
|
+
client_id: CLIENT_ID,
|
|
1455
|
+
device_code: device.device_code
|
|
1456
|
+
}, { signal }, dependencies);
|
|
1457
|
+
signal.throwIfAborted();
|
|
1458
|
+
if (tokenResponse.ok) {
|
|
1459
|
+
const tokens = tokenSchema.parse(await tokenResponse.json());
|
|
1460
|
+
signal.throwIfAborted();
|
|
1461
|
+
const credentials = tokenCredentials(tokens);
|
|
1462
|
+
const accountId = await getAccountId(tokens, signal, dependencies);
|
|
1463
|
+
signal.throwIfAborted();
|
|
1464
|
+
return {
|
|
1465
|
+
...credentials,
|
|
1466
|
+
accountId
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
const error = await readOAuthError(tokenResponse);
|
|
1470
|
+
if (error === "authorization_pending" || error === "slow_down") {
|
|
1471
|
+
if (error === "slow_down") intervalMs += 5e3;
|
|
1472
|
+
await sleep(intervalMs + POLLING_SAFETY_MARGIN_MS, signal);
|
|
1473
|
+
continue;
|
|
1474
|
+
}
|
|
1475
|
+
if (error === "access_denied" || error === "authorization_denied") throw new XaiOAuthError("authorization_denied");
|
|
1476
|
+
if (error === "expired_token") throw new XaiOAuthError("authorization_expired");
|
|
1477
|
+
throw requestError(tokenResponse, error);
|
|
1478
|
+
}
|
|
1479
|
+
} catch (error) {
|
|
1480
|
+
options.signal?.throwIfAborted();
|
|
1481
|
+
if (timeout.aborted) throw new XaiOAuthError("authorization_expired");
|
|
1482
|
+
throw error;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
async function refreshXaiCredentials(credentials, options = {}, dependencies = {}) {
|
|
1486
|
+
const response = await send("token", {
|
|
1487
|
+
grant_type: "refresh_token",
|
|
1488
|
+
refresh_token: credentials.refreshToken,
|
|
1489
|
+
client_id: CLIENT_ID
|
|
1490
|
+
}, options, dependencies);
|
|
1491
|
+
if (!response.ok) throw requestError(response, await readOAuthError(response));
|
|
1492
|
+
const tokens = tokenSchema.parse(await response.json());
|
|
1493
|
+
const refreshedAccountId = tokenAccountId(tokens.id_token) ?? tokenAccountId(tokens.access_token);
|
|
1494
|
+
if (refreshedAccountId && refreshedAccountId !== credentials.accountId) throw new Error("xAI token refresh returned a different account");
|
|
1495
|
+
return {
|
|
1496
|
+
...tokenCredentials(tokens, credentials.refreshToken),
|
|
1497
|
+
accountId: credentials.accountId
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
function isXaiCredentialsExpired(credentials, now = Date.now()) {
|
|
1501
|
+
return credentials.expiresAt <= now + REFRESH_BUFFER_MS;
|
|
1502
|
+
}
|
|
1503
|
+
const CODEX_CREDENTIAL_LOCK_RETRY_MS = 10;
|
|
1504
|
+
const CODEX_CREDENTIAL_LOCK_TIMEOUT_MS = 1e4;
|
|
1505
|
+
const CODEX_CREDENTIAL_LOCK_STALE_MS = 6e4;
|
|
1506
|
+
function isNodeError(error) {
|
|
1507
|
+
return error instanceof Error && "code" in error;
|
|
1508
|
+
}
|
|
1509
|
+
function normalizeCodexAccountSelector(value) {
|
|
1510
|
+
return value.trim().toLowerCase();
|
|
1511
|
+
}
|
|
1512
|
+
function parseCodexCredentialLockMetadata(value) {
|
|
1513
|
+
try {
|
|
1514
|
+
const candidate = JSON.parse(value);
|
|
1515
|
+
if (typeof candidate.createdAt !== "number" || !Number.isFinite(candidate.createdAt) || typeof candidate.owner !== "string" || typeof candidate.pid !== "number" || !Number.isSafeInteger(candidate.pid) || candidate.pid <= 0) return null;
|
|
1516
|
+
return {
|
|
1517
|
+
createdAt: candidate.createdAt,
|
|
1518
|
+
owner: candidate.owner,
|
|
1519
|
+
pid: candidate.pid
|
|
1520
|
+
};
|
|
1521
|
+
} catch {
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
function isProcessAlive(pid) {
|
|
1526
|
+
try {
|
|
1527
|
+
process.kill(pid, 0);
|
|
1528
|
+
return true;
|
|
1529
|
+
} catch (error) {
|
|
1530
|
+
return !(isNodeError(error) && error.code === "ESRCH");
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
async function isCodexCredentialLockContention(error, lockPath) {
|
|
1534
|
+
if (isNodeError(error) && error.code === "EEXIST") return true;
|
|
1535
|
+
if (process.platform !== "win32" || !isNodeError(error) || error.code !== "EACCES" && error.code !== "EPERM") return false;
|
|
1536
|
+
try {
|
|
1537
|
+
await fs.stat(lockPath);
|
|
1538
|
+
return true;
|
|
1539
|
+
} catch (statError) {
|
|
1540
|
+
if (isNodeError(statError) && statError.code === "ENOENT") return true;
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
async function removeStaleCodexCredentialLock(lockPath) {
|
|
1545
|
+
let content;
|
|
1546
|
+
let modifiedAt;
|
|
1547
|
+
try {
|
|
1548
|
+
const [lockContent, stats] = await Promise.all([fs.readFile(lockPath, "utf8"), fs.stat(lockPath)]);
|
|
1549
|
+
content = lockContent;
|
|
1550
|
+
modifiedAt = stats.mtimeMs;
|
|
1551
|
+
} catch (error) {
|
|
1552
|
+
if (isNodeError(error) && error.code === "ENOENT" || await isCodexCredentialLockContention(error, lockPath)) return;
|
|
1553
|
+
throw error;
|
|
1554
|
+
}
|
|
1555
|
+
const metadata = parseCodexCredentialLockMetadata(content);
|
|
1556
|
+
if (Date.now() - (metadata?.createdAt ?? modifiedAt) < CODEX_CREDENTIAL_LOCK_STALE_MS && (!metadata || isProcessAlive(metadata.pid))) return;
|
|
1557
|
+
try {
|
|
1558
|
+
if (await fs.readFile(lockPath, "utf8") !== content) return;
|
|
1559
|
+
await fs.unlink(lockPath);
|
|
1560
|
+
} catch (error) {
|
|
1561
|
+
if (isNodeError(error) && error.code === "ENOENT" || await isCodexCredentialLockContention(error, lockPath)) return;
|
|
1562
|
+
throw error;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
async function acquireCodexCredentialLock(lockPath = `${PATHS.CODEX_CREDENTIAL_PATH}.lock`) {
|
|
1566
|
+
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
|
1567
|
+
const startedAt = Date.now();
|
|
1568
|
+
while (true) {
|
|
1569
|
+
const metadata = {
|
|
1570
|
+
createdAt: Date.now(),
|
|
1571
|
+
owner: `${process.pid}-${randomBytes(8).toString("hex")}`,
|
|
1572
|
+
pid: process.pid
|
|
1573
|
+
};
|
|
1574
|
+
const content = `${JSON.stringify(metadata)}\n`;
|
|
1575
|
+
try {
|
|
1576
|
+
const fileHandle = await fs.open(lockPath, "wx", 384);
|
|
1577
|
+
try {
|
|
1578
|
+
await fileHandle.writeFile(content, "utf8");
|
|
1579
|
+
await fileHandle.sync();
|
|
1580
|
+
} catch (error) {
|
|
1581
|
+
await fileHandle.close().catch(() => {});
|
|
1582
|
+
await fs.unlink(lockPath).catch(() => {});
|
|
1583
|
+
throw error;
|
|
1584
|
+
}
|
|
1585
|
+
return {
|
|
1586
|
+
content,
|
|
1587
|
+
fileHandle,
|
|
1588
|
+
lockPath
|
|
1589
|
+
};
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
if (!await isCodexCredentialLockContention(error, lockPath)) throw error;
|
|
1592
|
+
}
|
|
1593
|
+
await removeStaleCodexCredentialLock(lockPath);
|
|
1594
|
+
if (Date.now() - startedAt >= CODEX_CREDENTIAL_LOCK_TIMEOUT_MS) throw new Error(`Timed out waiting for Codex credential store lock: ${lockPath}`);
|
|
1595
|
+
await setTimeout$1(CODEX_CREDENTIAL_LOCK_RETRY_MS);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
async function releaseCodexCredentialLock(lock) {
|
|
1599
|
+
await lock.fileHandle.close();
|
|
1600
|
+
try {
|
|
1601
|
+
if (await fs.readFile(lock.lockPath, "utf8") !== lock.content) return;
|
|
1602
|
+
await fs.unlink(lock.lockPath);
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
if (!(isNodeError(error) && error.code === "ENOENT")) throw error;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
async function withCodexCredentialLock(operation, lockPath) {
|
|
1608
|
+
const lock = await acquireCodexCredentialLock(lockPath);
|
|
1609
|
+
let result;
|
|
1610
|
+
try {
|
|
1611
|
+
result = await operation();
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
await releaseCodexCredentialLock(lock).catch(() => {});
|
|
1614
|
+
throw error;
|
|
1615
|
+
}
|
|
1616
|
+
await releaseCodexCredentialLock(lock);
|
|
1617
|
+
return result;
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Serializes operations that must keep Codex account selection in config.json
|
|
1621
|
+
* consistent with the credential store. Credential writes retain their own
|
|
1622
|
+
* narrower lock so refreshes can run without changing the selected account.
|
|
1623
|
+
*/
|
|
1624
|
+
function withCodexAccountMutationLock(operation) {
|
|
1625
|
+
return withCodexCredentialLock(operation, `${PATHS.CODEX_CREDENTIAL_PATH}.accounts.lock`);
|
|
1626
|
+
}
|
|
1627
|
+
function withCredentialFileLock(credentialPath, operation) {
|
|
1628
|
+
return withCodexCredentialLock(operation, `${credentialPath}.lock`);
|
|
1629
|
+
}
|
|
1630
|
+
async function readOptionalFile(filePath) {
|
|
1631
|
+
try {
|
|
1632
|
+
return await fs.readFile(filePath, "utf8");
|
|
1633
|
+
} catch (error) {
|
|
1634
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
1635
|
+
throw error;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
function writeProtectedFile(filePath, content) {
|
|
1639
|
+
return Promise.resolve().then(() => writeFileAtomically(filePath, content));
|
|
1640
|
+
}
|
|
1641
|
+
function normalizeCodexCredentials(credentials) {
|
|
1642
|
+
if (!credentials || typeof credentials !== "object") return null;
|
|
1643
|
+
const candidate = credentials;
|
|
1644
|
+
if (typeof candidate.accessToken !== "string" || !candidate.accessToken.trim() || typeof candidate.refreshToken !== "string" || !candidate.refreshToken.trim() || typeof candidate.expiresAt !== "number" || !Number.isFinite(candidate.expiresAt) || typeof candidate.accountId !== "string" || !candidate.accountId.trim()) return null;
|
|
1645
|
+
return {
|
|
1646
|
+
accessToken: candidate.accessToken,
|
|
1647
|
+
refreshToken: candidate.refreshToken,
|
|
1648
|
+
expiresAt: candidate.expiresAt,
|
|
1649
|
+
accountId: candidate.accountId
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
function normalizeCodexStoredAccount(account) {
|
|
1653
|
+
const credentials = normalizeCodexCredentials(account);
|
|
1654
|
+
if (!credentials) return null;
|
|
1655
|
+
const aliasValue = account.alias;
|
|
1656
|
+
if (aliasValue !== void 0 && typeof aliasValue !== "string") return null;
|
|
1657
|
+
const alias = aliasValue?.trim();
|
|
1658
|
+
return {
|
|
1659
|
+
...credentials,
|
|
1660
|
+
...alias ? { alias } : {}
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
function normalizeCodexCredentialStore(value) {
|
|
1664
|
+
const legacyCredentials = normalizeCodexCredentials(value);
|
|
1665
|
+
if (legacyCredentials) return {
|
|
1666
|
+
version: 1,
|
|
1667
|
+
accounts: [legacyCredentials]
|
|
1668
|
+
};
|
|
1669
|
+
if (!value || typeof value !== "object") return null;
|
|
1670
|
+
const candidate = value;
|
|
1671
|
+
if (candidate.version !== 1 || !Array.isArray(candidate.accounts)) return null;
|
|
1672
|
+
if (candidate.accounts.length > 3) return null;
|
|
1673
|
+
const accounts = [];
|
|
1674
|
+
const accountIds = /* @__PURE__ */ new Set();
|
|
1675
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
1676
|
+
for (const value of candidate.accounts) {
|
|
1677
|
+
const account = normalizeCodexStoredAccount(value);
|
|
1678
|
+
if (!account || accountIds.has(account.accountId)) return null;
|
|
1679
|
+
const normalizedAlias = account.alias ? normalizeCodexAccountSelector(account.alias) : void 0;
|
|
1680
|
+
if (normalizedAlias && aliases.has(normalizedAlias)) return null;
|
|
1681
|
+
accounts.push(account);
|
|
1682
|
+
accountIds.add(account.accountId);
|
|
1683
|
+
if (normalizedAlias) aliases.add(normalizedAlias);
|
|
1684
|
+
}
|
|
1685
|
+
return {
|
|
1686
|
+
version: 1,
|
|
1687
|
+
accounts: accounts.map((account, index) => {
|
|
1688
|
+
const alias = account.alias;
|
|
1689
|
+
if (!alias || !accounts.some((candidate, candidateIndex) => candidateIndex !== index && normalizeCodexAccountSelector(candidate.accountId) === normalizeCodexAccountSelector(alias))) return account;
|
|
1690
|
+
const { alias: _alias, ...credentials } = account;
|
|
1691
|
+
return credentials;
|
|
1692
|
+
})
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
async function writeCodexCredentialStoreUnlocked(store, credentialPath = PATHS.CODEX_CREDENTIAL_PATH) {
|
|
1696
|
+
await writeProtectedFile(credentialPath, `${JSON.stringify(store, null, 2)}\n`);
|
|
1697
|
+
}
|
|
1698
|
+
async function readGitHubToken() {
|
|
1699
|
+
return (await readOptionalFile(PATHS.GITHUB_TOKEN_PATH))?.trim() || null;
|
|
1700
|
+
}
|
|
1701
|
+
const GITHUB_TOKEN_ENV = "COPILOT_API_GITHUB_TOKEN";
|
|
1702
|
+
function readGitHubTokenFromEnv() {
|
|
1703
|
+
return process.env["COPILOT_API_GITHUB_TOKEN"]?.trim() || void 0;
|
|
1704
|
+
}
|
|
1705
|
+
async function writeGitHubToken(token) {
|
|
1706
|
+
await writeProtectedFile(PATHS.GITHUB_TOKEN_PATH, token.trim());
|
|
1707
|
+
}
|
|
1708
|
+
function createOAuthCredentialStore(providerLabel, credentialPath) {
|
|
1709
|
+
async function readStore() {
|
|
1710
|
+
const raw = await readOptionalFile(credentialPath());
|
|
1711
|
+
if (!raw?.trim()) return null;
|
|
1712
|
+
let parsed;
|
|
1713
|
+
try {
|
|
1714
|
+
parsed = JSON.parse(raw);
|
|
1715
|
+
} catch (error) {
|
|
1716
|
+
throw new Error(`${providerLabel} credentials file is not valid JSON: ${credentialPath()}`, { cause: error });
|
|
1717
|
+
}
|
|
1718
|
+
const store = normalizeCodexCredentialStore(parsed);
|
|
1719
|
+
if (!store) throw new Error(`${providerLabel} credentials file is missing required fields: ${credentialPath()}`);
|
|
1720
|
+
return store;
|
|
1721
|
+
}
|
|
1722
|
+
async function readCredentials(accountId) {
|
|
1723
|
+
const store = await readStore();
|
|
1724
|
+
if (!store || store.accounts.length === 0) return null;
|
|
1725
|
+
const normalizedAccountId = accountId?.trim();
|
|
1726
|
+
if (normalizedAccountId) return store.accounts.find((account) => account.accountId === normalizedAccountId) ?? null;
|
|
1727
|
+
if (store.accounts.length > 1) throw new Error(`Multiple ${providerLabel} accounts found but no account is selected`);
|
|
1728
|
+
return store.accounts[0];
|
|
1729
|
+
}
|
|
1730
|
+
async function writeCredentials(credentials, options = {}) {
|
|
1731
|
+
const normalizedCredentials = normalizeCodexCredentials(credentials);
|
|
1732
|
+
if (!normalizedCredentials) throw new Error(`${providerLabel} credentials are missing required fields`);
|
|
1733
|
+
await withCredentialFileLock(credentialPath(), async () => {
|
|
1734
|
+
const store = await readStore() ?? {
|
|
1735
|
+
version: 1,
|
|
1736
|
+
accounts: []
|
|
1737
|
+
};
|
|
1738
|
+
const accountIdSelector = normalizeCodexAccountSelector(normalizedCredentials.accountId);
|
|
1739
|
+
const existingIndex = store.accounts.findIndex((account) => account.accountId === normalizedCredentials.accountId);
|
|
1740
|
+
if (existingIndex < 0 && options.insertIfMissing === false) return;
|
|
1741
|
+
const existingRefreshToken = store.accounts[existingIndex]?.refreshToken;
|
|
1742
|
+
if (options.expectedRefreshToken !== void 0 && existingRefreshToken !== options.expectedRefreshToken && existingRefreshToken !== normalizedCredentials.refreshToken) return;
|
|
1743
|
+
if (existingIndex < 0 && store.accounts.some((account) => normalizeCodexAccountSelector(account.accountId) === accountIdSelector)) throw new Error(`${providerLabel} account id '${normalizedCredentials.accountId}' is already in use`);
|
|
1744
|
+
if (existingIndex < 0 && store.accounts.length >= 3) throw new Error(`${providerLabel} supports at most 3 accounts`);
|
|
1745
|
+
if (store.accounts.some((account, index) => index !== existingIndex && account.alias && normalizeCodexAccountSelector(account.alias) === accountIdSelector)) throw new Error(`${providerLabel} account id '${normalizedCredentials.accountId}' conflicts with another account alias`);
|
|
1746
|
+
const alias = options.alias?.trim();
|
|
1747
|
+
if (alias) {
|
|
1748
|
+
const aliasSelector = normalizeCodexAccountSelector(alias);
|
|
1749
|
+
if (store.accounts.some((account, index) => index !== existingIndex && account.alias && normalizeCodexAccountSelector(account.alias) === aliasSelector)) throw new Error(`${providerLabel} account alias '${alias}' is already in use`);
|
|
1750
|
+
if (store.accounts.some((account, index) => index !== existingIndex && normalizeCodexAccountSelector(account.accountId) === aliasSelector)) throw new Error(`${providerLabel} account alias '${alias}' conflicts with another account id`);
|
|
1751
|
+
}
|
|
1752
|
+
const existingAccount = existingIndex >= 0 ? store.accounts[existingIndex] : void 0;
|
|
1753
|
+
const nextAccount = {
|
|
1754
|
+
...normalizedCredentials,
|
|
1755
|
+
...alias ? { alias } : existingAccount?.alias ? { alias: existingAccount.alias } : {}
|
|
1756
|
+
};
|
|
1757
|
+
const accounts = [...store.accounts];
|
|
1758
|
+
if (existingIndex >= 0) accounts[existingIndex] = nextAccount;
|
|
1759
|
+
else accounts.push(nextAccount);
|
|
1760
|
+
await writeCodexCredentialStoreUnlocked({
|
|
1761
|
+
version: 1,
|
|
1762
|
+
accounts
|
|
1763
|
+
}, credentialPath());
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
async function removeCredentials(accountId) {
|
|
1767
|
+
const normalizedAccountId = accountId.trim();
|
|
1768
|
+
if (!normalizedAccountId) throw new Error(`${providerLabel} account id must be a non-empty string`);
|
|
1769
|
+
return await withCredentialFileLock(credentialPath(), async () => {
|
|
1770
|
+
const store = await readStore();
|
|
1771
|
+
const index = store?.accounts.findIndex((account) => account.accountId === normalizedAccountId) ?? -1;
|
|
1772
|
+
if (!store || index < 0) throw new Error(`${providerLabel} account '${normalizedAccountId}' was not found`);
|
|
1773
|
+
const removedAccount = store.accounts[index];
|
|
1774
|
+
await writeCodexCredentialStoreUnlocked({
|
|
1775
|
+
version: 1,
|
|
1776
|
+
accounts: store.accounts.filter((_account, accountIndex) => accountIndex !== index)
|
|
1777
|
+
}, credentialPath());
|
|
1778
|
+
return removedAccount;
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
return {
|
|
1782
|
+
readStore,
|
|
1783
|
+
readCredentials,
|
|
1784
|
+
writeCredentials,
|
|
1785
|
+
removeCredentials
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
const codexCredentialStore = createOAuthCredentialStore("Codex", () => PATHS.CODEX_CREDENTIAL_PATH);
|
|
1789
|
+
const readCodexCredentialStore = codexCredentialStore.readStore;
|
|
1790
|
+
codexCredentialStore.readCredentials;
|
|
1791
|
+
const writeCodexCredentials = codexCredentialStore.writeCredentials;
|
|
1792
|
+
codexCredentialStore.removeCredentials;
|
|
1793
|
+
//#endregion
|
|
1794
|
+
//#region src/lib/oauth-accounts.ts
|
|
1795
|
+
function createOAuthAccountManager(options) {
|
|
1796
|
+
const store = createOAuthCredentialStore(options.label, options.credentialPath);
|
|
1797
|
+
const withMutationLock = (operation) => withCredentialFileLock(`${options.credentialPath()}.accounts`, operation);
|
|
1798
|
+
const activeId = (accounts) => readEditableConfigFromDisk().providers?.[options.provider]?.accountId?.trim() || (accounts.length === 1 ? accounts[0].accountId : void 0);
|
|
1799
|
+
const summarize = (account, active) => ({
|
|
1800
|
+
accountId: account.accountId,
|
|
1801
|
+
...account.alias ? { alias: account.alias } : {},
|
|
1802
|
+
active
|
|
1803
|
+
});
|
|
1804
|
+
async function findAccount(selector) {
|
|
1805
|
+
const normalized = selector.trim();
|
|
1806
|
+
if (!normalized) throw new Error(`${options.label} account selector must be a non-empty string`);
|
|
1807
|
+
const accounts = (await store.readStore())?.accounts ?? [];
|
|
1808
|
+
const account = accounts.find((candidate) => candidate.accountId === normalized) ?? accounts.find((candidate) => candidate.alias?.toLowerCase() === normalized.toLowerCase());
|
|
1809
|
+
if (!account) throw new Error(`${options.label} account '${normalized}' was not found`);
|
|
1810
|
+
return {
|
|
1811
|
+
account,
|
|
1812
|
+
accounts
|
|
1813
|
+
};
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
store,
|
|
1817
|
+
withMutationLock,
|
|
1818
|
+
list: () => withMutationLock(async () => {
|
|
1819
|
+
const accounts = (await store.readStore())?.accounts ?? [];
|
|
1820
|
+
const active = activeId(accounts);
|
|
1821
|
+
return accounts.map((account) => summarize(account, account.accountId === active));
|
|
1822
|
+
}),
|
|
1823
|
+
select: (selector) => withMutationLock(async () => {
|
|
1824
|
+
const { account } = await findAccount(selector);
|
|
1825
|
+
options.selectAccount(account.accountId);
|
|
1826
|
+
return summarize(account, true);
|
|
1827
|
+
}),
|
|
1828
|
+
remove: (selector) => withMutationLock(async () => {
|
|
1829
|
+
const { account, accounts } = await findAccount(selector);
|
|
1830
|
+
if (account.accountId === activeId(accounts)) throw new Error(`${options.label} account '${account.accountId}' is currently in use; switch to another account before removing it`);
|
|
1831
|
+
const removed = await store.removeCredentials(account.accountId);
|
|
1832
|
+
return summarize(removed, false);
|
|
1833
|
+
})
|
|
1316
1834
|
};
|
|
1317
1835
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1836
|
+
//#endregion
|
|
1837
|
+
//#region src/lib/xai-token.ts
|
|
1838
|
+
function syncXaiProviderConfig(accountId, enable = false) {
|
|
1839
|
+
const { apiKey: _apiKey, modelsDevProviderId: _catalog, ...existing } = readEditableConfigFromDisk().providers?.xai ?? {};
|
|
1840
|
+
setProviderConfig("xai", {
|
|
1841
|
+
...existing,
|
|
1842
|
+
type: "openai-responses",
|
|
1843
|
+
enabled: enable ? true : existing.enabled,
|
|
1844
|
+
baseUrl: XAI_API_BASE_URL,
|
|
1845
|
+
authType: "oauth2",
|
|
1846
|
+
accountId,
|
|
1847
|
+
pricingCurrency: "USD"
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
const xaiAccounts = createOAuthAccountManager({
|
|
1851
|
+
provider: "xai",
|
|
1852
|
+
label: "xAI",
|
|
1853
|
+
credentialPath: () => PATHS.XAI_CREDENTIAL_PATH,
|
|
1854
|
+
selectAccount: (accountId) => syncXaiProviderConfig(accountId)
|
|
1855
|
+
});
|
|
1856
|
+
const getXaiAccounts = xaiAccounts.list;
|
|
1857
|
+
const selectXaiAccount = xaiAccounts.select;
|
|
1858
|
+
const removeXaiAccount = xaiAccounts.remove;
|
|
1859
|
+
async function readXaiCredentials(accountId = getRawProviderConfig("xai")?.accountId) {
|
|
1860
|
+
return await xaiAccounts.store.readCredentials(accountId);
|
|
1861
|
+
}
|
|
1862
|
+
function persistXaiCredentials(credentials, options = {}) {
|
|
1863
|
+
return xaiAccounts.withMutationLock(async () => {
|
|
1864
|
+
await xaiAccounts.store.writeCredentials(credentials, { alias: options.alias });
|
|
1865
|
+
syncXaiProviderConfig(credentials.accountId, true);
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
const refreshInFlight = /* @__PURE__ */ new Map();
|
|
1869
|
+
const pendingPersistence = /* @__PURE__ */ new Map();
|
|
1870
|
+
async function getXaiAccessToken() {
|
|
1871
|
+
const credentials = await readXaiCredentials();
|
|
1872
|
+
if (!credentials || !isXaiCredentialsExpired(credentials)) return credentials?.accessToken ?? null;
|
|
1873
|
+
const key = `${credentials.accountId}:${credentials.refreshToken}`;
|
|
1874
|
+
const inFlight = refreshInFlight.get(key);
|
|
1875
|
+
if (inFlight) return await inFlight;
|
|
1876
|
+
const refresh = withCredentialFileLock(`${PATHS.XAI_CREDENTIAL_PATH}.refresh`, async () => {
|
|
1877
|
+
const current = await readXaiCredentials(credentials.accountId);
|
|
1878
|
+
if (!current) return null;
|
|
1879
|
+
if (!isXaiCredentialsExpired(current)) return current.accessToken;
|
|
1880
|
+
const currentKey = `${current.accountId}:${current.refreshToken}`;
|
|
1881
|
+
const refreshed = pendingPersistence.get(currentKey) ?? await refreshXaiCredentials(current);
|
|
1882
|
+
pendingPersistence.set(currentKey, refreshed);
|
|
1883
|
+
await xaiAccounts.store.writeCredentials(refreshed, {
|
|
1884
|
+
insertIfMissing: false,
|
|
1885
|
+
expectedRefreshToken: current.refreshToken
|
|
1886
|
+
});
|
|
1887
|
+
pendingPersistence.delete(currentKey);
|
|
1888
|
+
return (await readXaiCredentials(credentials.accountId))?.accessToken ?? null;
|
|
1889
|
+
}).finally(() => {
|
|
1890
|
+
refreshInFlight.delete(key);
|
|
1891
|
+
});
|
|
1892
|
+
refreshInFlight.set(key, refresh);
|
|
1893
|
+
return await refresh;
|
|
1320
1894
|
}
|
|
1321
1895
|
//#endregion
|
|
1322
1896
|
//#region src/lib/request-auth.ts
|
|
@@ -1643,272 +2217,6 @@ const GITHUB_BASE_URL = "https://github.com";
|
|
|
1643
2217
|
const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
|
|
1644
2218
|
const GITHUB_APP_SCOPES = ["read:user"].join(" ");
|
|
1645
2219
|
const OPENCODE_GITHUB_CLIENT_ID = "Ov23li8tweQw6odWQebz";
|
|
1646
|
-
const CODEX_CREDENTIAL_LOCK_RETRY_MS = 10;
|
|
1647
|
-
const CODEX_CREDENTIAL_LOCK_TIMEOUT_MS = 1e4;
|
|
1648
|
-
const CODEX_CREDENTIAL_LOCK_STALE_MS = 6e4;
|
|
1649
|
-
function isNodeError(error) {
|
|
1650
|
-
return error instanceof Error && "code" in error;
|
|
1651
|
-
}
|
|
1652
|
-
function normalizeCodexAccountSelector(value) {
|
|
1653
|
-
return value.trim().toLowerCase();
|
|
1654
|
-
}
|
|
1655
|
-
function parseCodexCredentialLockMetadata(value) {
|
|
1656
|
-
try {
|
|
1657
|
-
const candidate = JSON.parse(value);
|
|
1658
|
-
if (typeof candidate.createdAt !== "number" || !Number.isFinite(candidate.createdAt) || typeof candidate.owner !== "string" || typeof candidate.pid !== "number" || !Number.isSafeInteger(candidate.pid) || candidate.pid <= 0) return null;
|
|
1659
|
-
return {
|
|
1660
|
-
createdAt: candidate.createdAt,
|
|
1661
|
-
owner: candidate.owner,
|
|
1662
|
-
pid: candidate.pid
|
|
1663
|
-
};
|
|
1664
|
-
} catch {
|
|
1665
|
-
return null;
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
function isProcessAlive(pid) {
|
|
1669
|
-
try {
|
|
1670
|
-
process.kill(pid, 0);
|
|
1671
|
-
return true;
|
|
1672
|
-
} catch (error) {
|
|
1673
|
-
return !(isNodeError(error) && error.code === "ESRCH");
|
|
1674
|
-
}
|
|
1675
|
-
}
|
|
1676
|
-
async function isCodexCredentialLockContention(error, lockPath) {
|
|
1677
|
-
if (isNodeError(error) && error.code === "EEXIST") return true;
|
|
1678
|
-
if (process.platform !== "win32" || !isNodeError(error) || error.code !== "EACCES" && error.code !== "EPERM") return false;
|
|
1679
|
-
try {
|
|
1680
|
-
await fs.stat(lockPath);
|
|
1681
|
-
return true;
|
|
1682
|
-
} catch (statError) {
|
|
1683
|
-
if (isNodeError(statError) && statError.code === "ENOENT") return true;
|
|
1684
|
-
return false;
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
async function removeStaleCodexCredentialLock(lockPath) {
|
|
1688
|
-
let content;
|
|
1689
|
-
let modifiedAt;
|
|
1690
|
-
try {
|
|
1691
|
-
const [lockContent, stats] = await Promise.all([fs.readFile(lockPath, "utf8"), fs.stat(lockPath)]);
|
|
1692
|
-
content = lockContent;
|
|
1693
|
-
modifiedAt = stats.mtimeMs;
|
|
1694
|
-
} catch (error) {
|
|
1695
|
-
if (isNodeError(error) && error.code === "ENOENT") return;
|
|
1696
|
-
throw error;
|
|
1697
|
-
}
|
|
1698
|
-
const metadata = parseCodexCredentialLockMetadata(content);
|
|
1699
|
-
if (Date.now() - (metadata?.createdAt ?? modifiedAt) < CODEX_CREDENTIAL_LOCK_STALE_MS && (!metadata || isProcessAlive(metadata.pid))) return;
|
|
1700
|
-
try {
|
|
1701
|
-
if (await fs.readFile(lockPath, "utf8") !== content) return;
|
|
1702
|
-
await fs.unlink(lockPath);
|
|
1703
|
-
} catch (error) {
|
|
1704
|
-
if (isNodeError(error) && error.code === "ENOENT") return;
|
|
1705
|
-
throw error;
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
async function acquireCodexCredentialLock(lockPath = `${PATHS.CODEX_CREDENTIAL_PATH}.lock`) {
|
|
1709
|
-
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
|
1710
|
-
const startedAt = Date.now();
|
|
1711
|
-
while (true) {
|
|
1712
|
-
const metadata = {
|
|
1713
|
-
createdAt: Date.now(),
|
|
1714
|
-
owner: `${process.pid}-${randomBytes(8).toString("hex")}`,
|
|
1715
|
-
pid: process.pid
|
|
1716
|
-
};
|
|
1717
|
-
const content = `${JSON.stringify(metadata)}\n`;
|
|
1718
|
-
try {
|
|
1719
|
-
const fileHandle = await fs.open(lockPath, "wx", 384);
|
|
1720
|
-
try {
|
|
1721
|
-
await fileHandle.writeFile(content, "utf8");
|
|
1722
|
-
await fileHandle.sync();
|
|
1723
|
-
} catch (error) {
|
|
1724
|
-
await fileHandle.close().catch(() => {});
|
|
1725
|
-
await fs.unlink(lockPath).catch(() => {});
|
|
1726
|
-
throw error;
|
|
1727
|
-
}
|
|
1728
|
-
return {
|
|
1729
|
-
content,
|
|
1730
|
-
fileHandle,
|
|
1731
|
-
lockPath
|
|
1732
|
-
};
|
|
1733
|
-
} catch (error) {
|
|
1734
|
-
if (!await isCodexCredentialLockContention(error, lockPath)) throw error;
|
|
1735
|
-
}
|
|
1736
|
-
await removeStaleCodexCredentialLock(lockPath);
|
|
1737
|
-
if (Date.now() - startedAt >= CODEX_CREDENTIAL_LOCK_TIMEOUT_MS) throw new Error(`Timed out waiting for Codex credential store lock: ${lockPath}`);
|
|
1738
|
-
await setTimeout$1(CODEX_CREDENTIAL_LOCK_RETRY_MS);
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
async function releaseCodexCredentialLock(lock) {
|
|
1742
|
-
await lock.fileHandle.close();
|
|
1743
|
-
try {
|
|
1744
|
-
if (await fs.readFile(lock.lockPath, "utf8") !== lock.content) return;
|
|
1745
|
-
await fs.unlink(lock.lockPath);
|
|
1746
|
-
} catch (error) {
|
|
1747
|
-
if (!(isNodeError(error) && error.code === "ENOENT")) throw error;
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
async function withCodexCredentialLock(operation, lockPath) {
|
|
1751
|
-
const lock = await acquireCodexCredentialLock(lockPath);
|
|
1752
|
-
let result;
|
|
1753
|
-
try {
|
|
1754
|
-
result = await operation();
|
|
1755
|
-
} catch (error) {
|
|
1756
|
-
await releaseCodexCredentialLock(lock).catch(() => {});
|
|
1757
|
-
throw error;
|
|
1758
|
-
}
|
|
1759
|
-
await releaseCodexCredentialLock(lock);
|
|
1760
|
-
return result;
|
|
1761
|
-
}
|
|
1762
|
-
/**
|
|
1763
|
-
* Serializes operations that must keep Codex account selection in config.json
|
|
1764
|
-
* consistent with the credential store. Credential writes retain their own
|
|
1765
|
-
* narrower lock so refreshes can run without changing the selected account.
|
|
1766
|
-
*/
|
|
1767
|
-
function withCodexAccountMutationLock(operation) {
|
|
1768
|
-
return withCodexCredentialLock(operation, `${PATHS.CODEX_CREDENTIAL_PATH}.accounts.lock`);
|
|
1769
|
-
}
|
|
1770
|
-
async function readOptionalFile(filePath) {
|
|
1771
|
-
try {
|
|
1772
|
-
return await fs.readFile(filePath, "utf8");
|
|
1773
|
-
} catch (error) {
|
|
1774
|
-
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
1775
|
-
throw error;
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
function writeProtectedFile(filePath, content) {
|
|
1779
|
-
return Promise.resolve().then(() => writeFileAtomically(filePath, content));
|
|
1780
|
-
}
|
|
1781
|
-
function normalizeCodexCredentials(credentials) {
|
|
1782
|
-
if (!credentials || typeof credentials !== "object") return null;
|
|
1783
|
-
const candidate = credentials;
|
|
1784
|
-
if (typeof candidate.accessToken !== "string" || typeof candidate.refreshToken !== "string" || typeof candidate.expiresAt !== "number" || typeof candidate.accountId !== "string") return null;
|
|
1785
|
-
return {
|
|
1786
|
-
accessToken: candidate.accessToken,
|
|
1787
|
-
refreshToken: candidate.refreshToken,
|
|
1788
|
-
expiresAt: candidate.expiresAt,
|
|
1789
|
-
accountId: candidate.accountId
|
|
1790
|
-
};
|
|
1791
|
-
}
|
|
1792
|
-
function normalizeCodexStoredAccount(account) {
|
|
1793
|
-
const credentials = normalizeCodexCredentials(account);
|
|
1794
|
-
if (!credentials) return null;
|
|
1795
|
-
const aliasValue = account.alias;
|
|
1796
|
-
if (aliasValue !== void 0 && typeof aliasValue !== "string") return null;
|
|
1797
|
-
const alias = aliasValue?.trim();
|
|
1798
|
-
return {
|
|
1799
|
-
...credentials,
|
|
1800
|
-
...alias ? { alias } : {}
|
|
1801
|
-
};
|
|
1802
|
-
}
|
|
1803
|
-
function normalizeCodexCredentialStore(value) {
|
|
1804
|
-
const legacyCredentials = normalizeCodexCredentials(value);
|
|
1805
|
-
if (legacyCredentials) return {
|
|
1806
|
-
version: 1,
|
|
1807
|
-
accounts: [legacyCredentials]
|
|
1808
|
-
};
|
|
1809
|
-
if (!value || typeof value !== "object") return null;
|
|
1810
|
-
const candidate = value;
|
|
1811
|
-
if (candidate.version !== 1 || !Array.isArray(candidate.accounts)) return null;
|
|
1812
|
-
if (candidate.accounts.length > 3) return null;
|
|
1813
|
-
const accounts = [];
|
|
1814
|
-
const accountIds = /* @__PURE__ */ new Set();
|
|
1815
|
-
const aliases = /* @__PURE__ */ new Set();
|
|
1816
|
-
for (const value of candidate.accounts) {
|
|
1817
|
-
const account = normalizeCodexStoredAccount(value);
|
|
1818
|
-
if (!account || accountIds.has(account.accountId)) return null;
|
|
1819
|
-
const normalizedAlias = account.alias ? normalizeCodexAccountSelector(account.alias) : void 0;
|
|
1820
|
-
if (normalizedAlias && aliases.has(normalizedAlias)) return null;
|
|
1821
|
-
accounts.push(account);
|
|
1822
|
-
accountIds.add(account.accountId);
|
|
1823
|
-
if (normalizedAlias) aliases.add(normalizedAlias);
|
|
1824
|
-
}
|
|
1825
|
-
return {
|
|
1826
|
-
version: 1,
|
|
1827
|
-
accounts: accounts.map((account, index) => {
|
|
1828
|
-
const alias = account.alias;
|
|
1829
|
-
if (!alias || !accounts.some((candidate, candidateIndex) => candidateIndex !== index && normalizeCodexAccountSelector(candidate.accountId) === normalizeCodexAccountSelector(alias))) return account;
|
|
1830
|
-
const { alias: _alias, ...credentials } = account;
|
|
1831
|
-
return credentials;
|
|
1832
|
-
})
|
|
1833
|
-
};
|
|
1834
|
-
}
|
|
1835
|
-
async function writeCodexCredentialStoreUnlocked(store) {
|
|
1836
|
-
await writeProtectedFile(PATHS.CODEX_CREDENTIAL_PATH, `${JSON.stringify(store, null, 2)}\n`);
|
|
1837
|
-
}
|
|
1838
|
-
async function readGitHubToken() {
|
|
1839
|
-
return (await readOptionalFile(PATHS.GITHUB_TOKEN_PATH))?.trim() || null;
|
|
1840
|
-
}
|
|
1841
|
-
const GITHUB_TOKEN_ENV = "COPILOT_API_GITHUB_TOKEN";
|
|
1842
|
-
function readGitHubTokenFromEnv() {
|
|
1843
|
-
return process.env["COPILOT_API_GITHUB_TOKEN"]?.trim() || void 0;
|
|
1844
|
-
}
|
|
1845
|
-
async function writeGitHubToken(token) {
|
|
1846
|
-
await writeProtectedFile(PATHS.GITHUB_TOKEN_PATH, token.trim());
|
|
1847
|
-
}
|
|
1848
|
-
async function readCodexCredentialStore() {
|
|
1849
|
-
const raw = await readOptionalFile(PATHS.CODEX_CREDENTIAL_PATH);
|
|
1850
|
-
if (!raw?.trim()) return null;
|
|
1851
|
-
let parsed;
|
|
1852
|
-
try {
|
|
1853
|
-
parsed = JSON.parse(raw);
|
|
1854
|
-
} catch (error) {
|
|
1855
|
-
throw new Error(`Codex credentials file is not valid JSON: ${PATHS.CODEX_CREDENTIAL_PATH}`, { cause: error });
|
|
1856
|
-
}
|
|
1857
|
-
const store = normalizeCodexCredentialStore(parsed);
|
|
1858
|
-
if (!store) throw new Error(`Codex credentials file is missing required fields: ${PATHS.CODEX_CREDENTIAL_PATH}`);
|
|
1859
|
-
return store;
|
|
1860
|
-
}
|
|
1861
|
-
async function writeCodexCredentials(credentials, options = {}) {
|
|
1862
|
-
const normalizedCredentials = normalizeCodexCredentials(credentials);
|
|
1863
|
-
if (!normalizedCredentials) throw new Error("Codex credentials are missing required fields");
|
|
1864
|
-
await withCodexCredentialLock(async () => {
|
|
1865
|
-
const store = await readCodexCredentialStore() ?? {
|
|
1866
|
-
version: 1,
|
|
1867
|
-
accounts: []
|
|
1868
|
-
};
|
|
1869
|
-
const accountIdSelector = normalizeCodexAccountSelector(normalizedCredentials.accountId);
|
|
1870
|
-
const existingIndex = store.accounts.findIndex((account) => account.accountId === normalizedCredentials.accountId);
|
|
1871
|
-
if (existingIndex < 0 && options.insertIfMissing === false) return;
|
|
1872
|
-
const existingRefreshToken = store.accounts[existingIndex]?.refreshToken;
|
|
1873
|
-
if (options.expectedRefreshToken !== void 0 && existingRefreshToken !== options.expectedRefreshToken && existingRefreshToken !== normalizedCredentials.refreshToken) return;
|
|
1874
|
-
if (existingIndex < 0 && store.accounts.some((account) => normalizeCodexAccountSelector(account.accountId) === accountIdSelector)) throw new Error(`Codex account id '${normalizedCredentials.accountId}' is already in use`);
|
|
1875
|
-
if (existingIndex < 0 && store.accounts.length >= 3) throw new Error(`Codex supports at most 3 accounts`);
|
|
1876
|
-
if (store.accounts.some((account, index) => index !== existingIndex && account.alias && normalizeCodexAccountSelector(account.alias) === accountIdSelector)) throw new Error(`Codex account id '${normalizedCredentials.accountId}' conflicts with another account alias`);
|
|
1877
|
-
const alias = options.alias?.trim();
|
|
1878
|
-
if (alias) {
|
|
1879
|
-
const aliasSelector = normalizeCodexAccountSelector(alias);
|
|
1880
|
-
if (store.accounts.some((account, index) => index !== existingIndex && account.alias && normalizeCodexAccountSelector(account.alias) === aliasSelector)) throw new Error(`Codex account alias '${alias}' is already in use`);
|
|
1881
|
-
if (store.accounts.some((account, index) => index !== existingIndex && normalizeCodexAccountSelector(account.accountId) === aliasSelector)) throw new Error(`Codex account alias '${alias}' conflicts with another account id`);
|
|
1882
|
-
}
|
|
1883
|
-
const existingAccount = existingIndex >= 0 ? store.accounts[existingIndex] : void 0;
|
|
1884
|
-
const nextAccount = {
|
|
1885
|
-
...normalizedCredentials,
|
|
1886
|
-
...alias ? { alias } : existingAccount?.alias ? { alias: existingAccount.alias } : {}
|
|
1887
|
-
};
|
|
1888
|
-
const accounts = [...store.accounts];
|
|
1889
|
-
if (existingIndex >= 0) accounts[existingIndex] = nextAccount;
|
|
1890
|
-
else accounts.push(nextAccount);
|
|
1891
|
-
await writeCodexCredentialStoreUnlocked({
|
|
1892
|
-
version: 1,
|
|
1893
|
-
accounts
|
|
1894
|
-
});
|
|
1895
|
-
});
|
|
1896
|
-
}
|
|
1897
|
-
async function removeCodexCredentials(accountId) {
|
|
1898
|
-
const normalizedAccountId = accountId.trim();
|
|
1899
|
-
if (!normalizedAccountId) throw new Error("Codex account id must be a non-empty string");
|
|
1900
|
-
return await withCodexCredentialLock(async () => {
|
|
1901
|
-
const store = await readCodexCredentialStore();
|
|
1902
|
-
const index = store?.accounts.findIndex((account) => account.accountId === normalizedAccountId) ?? -1;
|
|
1903
|
-
if (!store || index < 0) throw new Error(`Codex account '${normalizedAccountId}' was not found`);
|
|
1904
|
-
const removedAccount = store.accounts[index];
|
|
1905
|
-
await writeCodexCredentialStoreUnlocked({
|
|
1906
|
-
version: 1,
|
|
1907
|
-
accounts: store.accounts.filter((_account, accountIndex) => accountIndex !== index)
|
|
1908
|
-
});
|
|
1909
|
-
return removedAccount;
|
|
1910
|
-
});
|
|
1911
|
-
}
|
|
1912
2220
|
//#endregion
|
|
1913
2221
|
//#region src/services/github/get-copilot-token.ts
|
|
1914
2222
|
const getCopilotToken = async () => {
|
|
@@ -2168,53 +2476,15 @@ function syncCodexProviderConfig(options) {
|
|
|
2168
2476
|
function getConfiguredCodexAccountId() {
|
|
2169
2477
|
return getRawProviderConfig("codex")?.accountId?.trim() || void 0;
|
|
2170
2478
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
return normalizedSelector;
|
|
2181
|
-
}
|
|
2182
|
-
function findCodexAccount(accounts, selector) {
|
|
2183
|
-
return accounts.find((candidate) => candidate.accountId === selector) ?? accounts.find((candidate) => candidate.alias?.toLowerCase() === selector.toLowerCase());
|
|
2184
|
-
}
|
|
2185
|
-
function toCodexAccountSummary(account, active) {
|
|
2186
|
-
return {
|
|
2187
|
-
accountId: account.accountId,
|
|
2188
|
-
...account.alias ? { alias: account.alias } : {},
|
|
2189
|
-
active
|
|
2190
|
-
};
|
|
2191
|
-
}
|
|
2192
|
-
async function getCodexAccounts() {
|
|
2193
|
-
return await withCodexAccountMutationLock(async () => {
|
|
2194
|
-
const accounts = (await readCodexCredentialStore())?.accounts ?? [];
|
|
2195
|
-
const activeAccountId = resolveActiveCodexAccountId(accounts, getPersistedCodexAccountId());
|
|
2196
|
-
return accounts.map((account) => toCodexAccountSummary(account, account.accountId === activeAccountId));
|
|
2197
|
-
});
|
|
2198
|
-
}
|
|
2199
|
-
async function selectCodexAccount(selector) {
|
|
2200
|
-
return await withCodexAccountMutationLock(async () => {
|
|
2201
|
-
const normalizedSelector = normalizeCodexSelector(selector);
|
|
2202
|
-
const account = findCodexAccount((await readCodexCredentialStore())?.accounts ?? [], normalizedSelector);
|
|
2203
|
-
if (!account) throw new Error(`Codex account '${normalizedSelector}' was not found`);
|
|
2204
|
-
syncCodexProviderConfig({ accountId: account.accountId });
|
|
2205
|
-
return toCodexAccountSummary(account, true);
|
|
2206
|
-
});
|
|
2207
|
-
}
|
|
2208
|
-
async function removeCodexAccount(selector) {
|
|
2209
|
-
return await withCodexAccountMutationLock(async () => {
|
|
2210
|
-
const normalizedSelector = normalizeCodexSelector(selector);
|
|
2211
|
-
const accounts = (await readCodexCredentialStore())?.accounts ?? [];
|
|
2212
|
-
const account = findCodexAccount(accounts, normalizedSelector);
|
|
2213
|
-
if (!account) throw new Error(`Codex account '${normalizedSelector}' was not found`);
|
|
2214
|
-
if (account.accountId === resolveActiveCodexAccountId(accounts, getPersistedCodexAccountId())) throw new Error(`Codex account '${account.accountId}' is currently in use; switch to another account before removing it`);
|
|
2215
|
-
return toCodexAccountSummary(await removeCodexCredentials(account.accountId), false);
|
|
2216
|
-
});
|
|
2217
|
-
}
|
|
2479
|
+
const codexAccounts = createOAuthAccountManager({
|
|
2480
|
+
provider: "codex",
|
|
2481
|
+
label: "Codex",
|
|
2482
|
+
credentialPath: () => PATHS.CODEX_CREDENTIAL_PATH,
|
|
2483
|
+
selectAccount: (accountId) => syncCodexProviderConfig({ accountId })
|
|
2484
|
+
});
|
|
2485
|
+
const getCodexAccounts = codexAccounts.list;
|
|
2486
|
+
const selectCodexAccount = codexAccounts.select;
|
|
2487
|
+
const removeCodexAccount = codexAccounts.remove;
|
|
2218
2488
|
async function persistCodexCredentials(credentials, options = {}) {
|
|
2219
2489
|
const generation = options.runtimeGeneration ?? codexRuntimeGeneration;
|
|
2220
2490
|
const persist = async () => {
|
|
@@ -2470,6 +2740,6 @@ async function logUser(dependencies = defaultCopilotTokenDependencies) {
|
|
|
2470
2740
|
state.tokenBasedBilling = copilotUser.token_based_billing;
|
|
2471
2741
|
}
|
|
2472
2742
|
//#endregion
|
|
2473
|
-
export {
|
|
2743
|
+
export { createResponsesHttpEventStream as $, compactSystemPromptStarts as A, selectXaiAccount as B, prepareForCompact as C, compactAutoContinuePromptStarts as D, initOpencodeVersion as E, getMissingApiKeysMessage as F, loginCodex as G, readGitHubToken as H, getXaiAccessToken as I, forwardCodexResponses as J, CODEX_API_BASE_URL as K, getXaiAccounts as L, createAuthMiddleware as M, getConfiguredAdminApiKeys as N, compactMessageSections as O, getConfiguredApiKeys as P, fetchUpstreamWithLifecycle as Q, persistXaiCredentials as R, copilotWebSocketHeaders as S, prepareMessageProxyHeaders as T, readGitHubTokenFromEnv as U, GITHUB_TOKEN_ENV as V, loginXai as W, requestContext as X, generateTraceId as Y, resolveTraceId as Z, parseUserIdMetadata as _, removeCodexAccount as a, state as at, copilotHeaders as b, setupCopilotToken as c, generateRequestIdFromPayload as d, createResponsesSafeStream as et, getRootSessionId as f, isResponsesStream as g, isNullish as h, persistCodexCredentials as i, createWebSocketUrl as it, compactTextOnlyGuard as j, compactSummaryPromptStart as k, setupGitHubToken as l, isAsyncIterable as m, invalidateCodexRuntime as n, getResponsesStreamTerminalDisposition as nt, selectCodexAccount as o, FULL_MODEL_CATALOG_HEADER as ot, getUUID as p, buildCodexRequestHeaders as q, logUser as r, createPooledWebSocketStream as rt, setupCodexToken as s, stripInternalRequestHeaders as st, getCodexAccounts as t, encodePoolKeyPart as tt, stopCopilotRefreshLoop as u, getCopilotUsage as v, prepareInteractionHeaders as w, copilotModelsHeaders as x, copilotBaseUrl as y, removeXaiAccount as z };
|
|
2474
2744
|
|
|
2475
|
-
//# sourceMappingURL=token-
|
|
2745
|
+
//# sourceMappingURL=token-BjzzuPSb.js.map
|