agent-shim 8.15.0 → 8.16.0
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/README.md +4 -2
- package/dist/cli.cjs +928 -203
- package/dist/index.cjs +376 -46
- package/dist/index.mjs +365 -45
- package/dist/types/index.d.ts +182 -38
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -14464,7 +14464,7 @@ var require_client = __commonJS({
|
|
|
14464
14464
|
"use strict";
|
|
14465
14465
|
var assert2 = require("node:assert");
|
|
14466
14466
|
var net3 = require("node:net");
|
|
14467
|
-
var
|
|
14467
|
+
var http7 = require("node:http");
|
|
14468
14468
|
var util = require_util2();
|
|
14469
14469
|
var { ClientStats } = require_stats();
|
|
14470
14470
|
var { channels } = require_diagnostics();
|
|
@@ -14522,7 +14522,7 @@ var require_client = __commonJS({
|
|
|
14522
14522
|
var connectH1 = require_client_h1();
|
|
14523
14523
|
var connectH2 = require_client_h2();
|
|
14524
14524
|
var kClosedResolve = /* @__PURE__ */ Symbol("kClosedResolve");
|
|
14525
|
-
var getDefaultNodeMaxHeaderSize =
|
|
14525
|
+
var getDefaultNodeMaxHeaderSize = http7 && http7.maxHeaderSize && Number.isInteger(http7.maxHeaderSize) && http7.maxHeaderSize > 0 ? () => http7.maxHeaderSize : () => {
|
|
14526
14526
|
throw new InvalidArgumentError2("http module not available or http.maxHeaderSize invalid");
|
|
14527
14527
|
};
|
|
14528
14528
|
var noop = () => {
|
|
@@ -55242,6 +55242,8 @@ var ProviderEnvSchema = external_exports.record(external_exports.string().min(1)
|
|
|
55242
55242
|
var PROVIDER_KINDS = ["http", "codex"];
|
|
55243
55243
|
var CODEX_TIERS = ["fable", "opus", "sonnet", "haiku"];
|
|
55244
55244
|
var CODEX_EFFORTS = ["none", "low", "medium", "high"];
|
|
55245
|
+
var CODEX_LOGINS = ["codex-cli", "chatgpt-sign-in"];
|
|
55246
|
+
var CODEX_DEFAULT_LOGIN = "codex-cli";
|
|
55245
55247
|
var CODEX_DEFAULT_MODEL = "gpt-5.6-sol";
|
|
55246
55248
|
var CODEX_DEFAULT_TIER_MODELS = Object.freeze({
|
|
55247
55249
|
fable: "gpt-5.6-sol",
|
|
@@ -55261,7 +55263,9 @@ var CodexProviderConfigSchema = external_exports.strictObject({
|
|
|
55261
55263
|
haiku: external_exports.string().min(1).optional()
|
|
55262
55264
|
}).optional(),
|
|
55263
55265
|
/** The reasoning effort used when the request's own `output_config.effort` is not one the backend accepts. */
|
|
55264
|
-
effort: external_exports.enum(CODEX_EFFORTS).optional()
|
|
55266
|
+
effort: external_exports.enum(CODEX_EFFORTS).optional(),
|
|
55267
|
+
/** Which login the upstream call is made with; see `CODEX_LOGINS`. */
|
|
55268
|
+
login: external_exports.enum(CODEX_LOGINS).optional()
|
|
55265
55269
|
});
|
|
55266
55270
|
var HttpProviderSchema = external_exports.strictObject({
|
|
55267
55271
|
$schema: external_exports.string().optional(),
|
|
@@ -60278,6 +60282,7 @@ function buildLayoutPaths(root) {
|
|
|
60278
60282
|
frontdoorCaCertFile: import_node_path19.default.join(root, "frontdoor", "ca", "ca.pem"),
|
|
60279
60283
|
frontdoorCaKeyFile: import_node_path19.default.join(root, "frontdoor", "ca", "ca.key"),
|
|
60280
60284
|
frontdoorCaBundlesDir: import_node_path19.default.join(root, "frontdoor", "ca", "bundles"),
|
|
60285
|
+
chatgptSignInFile: import_node_path19.default.join(root, "codex", "chatgpt-sign-in.json"),
|
|
60281
60286
|
frontdoorStateFile: import_node_path19.default.join(root, "frontdoor", "state.json"),
|
|
60282
60287
|
frontdoorLockFile: import_node_path19.default.join(root, "frontdoor", "start.lock"),
|
|
60283
60288
|
frontdoorControlTokenFile: import_node_path19.default.join(root, "frontdoor", "control-token"),
|
|
@@ -61744,7 +61749,7 @@ function registerIdentityCommand(program2, deps) {
|
|
|
61744
61749
|
// package.json
|
|
61745
61750
|
var package_default = {
|
|
61746
61751
|
name: "agent-shim",
|
|
61747
|
-
version: "8.
|
|
61752
|
+
version: "8.16.0",
|
|
61748
61753
|
description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
61749
61754
|
license: "MIT",
|
|
61750
61755
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -63484,7 +63489,7 @@ var ProviderKindMismatchError = class extends UsageError {
|
|
|
63484
63489
|
}
|
|
63485
63490
|
};
|
|
63486
63491
|
function isEmptyCodexConfig(config2) {
|
|
63487
|
-
return config2 === void 0 || config2.defaultModel === void 0 && config2.effort === void 0 && (config2.models === void 0 || Object.keys(config2.models).length === 0);
|
|
63492
|
+
return config2 === void 0 || config2.defaultModel === void 0 && config2.effort === void 0 && config2.login === void 0 && (config2.models === void 0 || Object.keys(config2.models).length === 0);
|
|
63488
63493
|
}
|
|
63489
63494
|
function addProvider(paths, name, input2) {
|
|
63490
63495
|
if (providerExists(paths, name)) {
|
|
@@ -64121,7 +64126,7 @@ function registerCheckCommand(program2, deps) {
|
|
|
64121
64126
|
}
|
|
64122
64127
|
|
|
64123
64128
|
// src/codex/commands.ts
|
|
64124
|
-
var
|
|
64129
|
+
var import_node_crypto9 = require("node:crypto");
|
|
64125
64130
|
var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
64126
64131
|
var import_node_os6 = __toESM(require("node:os"), 1);
|
|
64127
64132
|
var import_node_path31 = __toESM(require("node:path"), 1);
|
|
@@ -64272,8 +64277,273 @@ function createCodexAuthStore(authPath, ports) {
|
|
|
64272
64277
|
};
|
|
64273
64278
|
}
|
|
64274
64279
|
|
|
64275
|
-
// src/codex/
|
|
64280
|
+
// src/codex/siwc.ts
|
|
64276
64281
|
var import_node_crypto6 = require("node:crypto");
|
|
64282
|
+
var SIWC_AUTHORIZE_URL = "https://auth.openai.com/api/accounts/authorize";
|
|
64283
|
+
var SIWC_TOKEN_URL = "https://auth.openai.com/api/accounts/oauth/token";
|
|
64284
|
+
var SIWC_REVOKE_URL = "https://auth.openai.com/api/accounts/oauth/revoke";
|
|
64285
|
+
var SIWC_ISSUER = "https://auth.openai.com";
|
|
64286
|
+
var SIWC_JWKS_URL = "https://auth.openai.com/.well-known/jwks.json";
|
|
64287
|
+
var SIWC_DYNAMIC_CLIENT_ID = "dynamic_agent_client";
|
|
64288
|
+
var SIWC_RESOURCE = "https://api.openai.com/v1";
|
|
64289
|
+
var SIWC_RESPONSES_URL = `${SIWC_RESOURCE}/responses`;
|
|
64290
|
+
var SIWC_SCOPES = ["openid", "profile", "email", "offline_access", "resource.invoke", "chatgpt.tokens.use.direct"];
|
|
64291
|
+
var SIWC_PLAN_SCOPE = "chatgpt.tokens.use.direct";
|
|
64292
|
+
var SIWC_CALLBACK_PORT = 1455;
|
|
64293
|
+
var SIWC_CALLBACK_PATH = "/auth/callback";
|
|
64294
|
+
var SIWC_RANDOM_BYTES = 32;
|
|
64295
|
+
var MS_PER_SECOND4 = 1e3;
|
|
64296
|
+
var ID_TOKEN_ALGORITHM = "RS256";
|
|
64297
|
+
var SiwcError = class extends Error {
|
|
64298
|
+
constructor(message) {
|
|
64299
|
+
super(message);
|
|
64300
|
+
this.name = "SiwcError";
|
|
64301
|
+
}
|
|
64302
|
+
};
|
|
64303
|
+
var SiwcInvalidGrantError = class extends SiwcError {
|
|
64304
|
+
constructor(message) {
|
|
64305
|
+
super(message);
|
|
64306
|
+
this.name = "SiwcInvalidGrantError";
|
|
64307
|
+
}
|
|
64308
|
+
};
|
|
64309
|
+
function base64Url(bytes) {
|
|
64310
|
+
return Buffer.from(bytes).toString("base64url");
|
|
64311
|
+
}
|
|
64312
|
+
function newPkce(randomBytes4) {
|
|
64313
|
+
const verifier = base64Url(randomBytes4(SIWC_RANDOM_BYTES));
|
|
64314
|
+
return { verifier, challenge: (0, import_node_crypto6.createHash)("sha256").update(verifier).digest("base64url") };
|
|
64315
|
+
}
|
|
64316
|
+
function newOpaqueValue(randomBytes4) {
|
|
64317
|
+
return base64Url(randomBytes4(SIWC_RANDOM_BYTES));
|
|
64318
|
+
}
|
|
64319
|
+
function buildAuthorizeUrl(request7) {
|
|
64320
|
+
const url2 = new URL(SIWC_AUTHORIZE_URL);
|
|
64321
|
+
const params = url2.searchParams;
|
|
64322
|
+
params.set("client_id", request7.clientId ?? SIWC_DYNAMIC_CLIENT_ID);
|
|
64323
|
+
if (request7.clientId === void 0) {
|
|
64324
|
+
params.set("agent_name_hint", request7.agentName);
|
|
64325
|
+
}
|
|
64326
|
+
if (request7.returning !== void 0) {
|
|
64327
|
+
params.set("id_token_hint", request7.returning.idToken);
|
|
64328
|
+
if (request7.returning.loginHint !== void 0) {
|
|
64329
|
+
params.set("login_hint", request7.returning.loginHint);
|
|
64330
|
+
}
|
|
64331
|
+
}
|
|
64332
|
+
params.set("response_type", "code");
|
|
64333
|
+
params.set("redirect_uri", request7.redirectUri);
|
|
64334
|
+
params.set("scope", SIWC_SCOPES.join(" "));
|
|
64335
|
+
params.set("resource", SIWC_RESOURCE);
|
|
64336
|
+
params.set("state", request7.state);
|
|
64337
|
+
params.set("nonce", request7.nonce);
|
|
64338
|
+
params.set("code_challenge_method", "S256");
|
|
64339
|
+
params.set("code_challenge", request7.challenge);
|
|
64340
|
+
return url2.toString();
|
|
64341
|
+
}
|
|
64342
|
+
function parseCallback(url2, expectedState) {
|
|
64343
|
+
const params = url2.searchParams;
|
|
64344
|
+
const error62 = params.get("error");
|
|
64345
|
+
if (error62 !== null) {
|
|
64346
|
+
throw new SiwcError(`the sign-in was refused: ${error62}${params.has("error_description") ? ` (${params.get("error_description") ?? ""})` : ""}`);
|
|
64347
|
+
}
|
|
64348
|
+
if (params.get("state") !== expectedState) {
|
|
64349
|
+
throw new SiwcError("the sign-in callback's state did not match the request, so it was discarded");
|
|
64350
|
+
}
|
|
64351
|
+
const code = params.get("code");
|
|
64352
|
+
if (code === null || code === "") {
|
|
64353
|
+
throw new SiwcError("the sign-in callback carried no authorization code");
|
|
64354
|
+
}
|
|
64355
|
+
const scope = params.get("scope");
|
|
64356
|
+
return { code, clientId: params.get("client_id") ?? void 0, scopes: scope === null ? [] : scope.split(" ").filter((part) => part !== "") };
|
|
64357
|
+
}
|
|
64358
|
+
var TokenResponseSchema = external_exports.looseObject({
|
|
64359
|
+
access_token: external_exports.string().min(1),
|
|
64360
|
+
refresh_token: external_exports.string().min(1).optional(),
|
|
64361
|
+
id_token: external_exports.string().min(1).optional(),
|
|
64362
|
+
expires_in: external_exports.number().positive(),
|
|
64363
|
+
scope: external_exports.string().optional()
|
|
64364
|
+
});
|
|
64365
|
+
var ERROR_BODY_CHARS = 300;
|
|
64366
|
+
var TOKEN_CALL_TIMEOUT_MS = 3e4;
|
|
64367
|
+
async function postToken(ports, form, what) {
|
|
64368
|
+
const response = await ports.fetch(SIWC_TOKEN_URL, {
|
|
64369
|
+
method: "POST",
|
|
64370
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
64371
|
+
body: new URLSearchParams({ ...form, resource: SIWC_RESOURCE }).toString(),
|
|
64372
|
+
signal: AbortSignal.timeout(TOKEN_CALL_TIMEOUT_MS)
|
|
64373
|
+
});
|
|
64374
|
+
if (!response.ok) {
|
|
64375
|
+
const detail = (await response.text()).slice(0, ERROR_BODY_CHARS);
|
|
64376
|
+
const message = `the ${what} failed with HTTP ${String(response.status)}: ${detail}`;
|
|
64377
|
+
throw /"error"\s*:\s*"invalid_grant"/.test(detail) ? new SiwcInvalidGrantError(message) : new SiwcError(message);
|
|
64378
|
+
}
|
|
64379
|
+
const parsed = TokenResponseSchema.safeParse(await response.json());
|
|
64380
|
+
if (!parsed.success) {
|
|
64381
|
+
throw new SiwcError(`the ${what} answered without an access token and a lifetime`);
|
|
64382
|
+
}
|
|
64383
|
+
return parsed.data;
|
|
64384
|
+
}
|
|
64385
|
+
function grantTokens(ports, answer) {
|
|
64386
|
+
return {
|
|
64387
|
+
accessToken: answer.access_token,
|
|
64388
|
+
refreshToken: answer.refresh_token,
|
|
64389
|
+
idToken: answer.id_token,
|
|
64390
|
+
scopes: answer.scope === void 0 ? void 0 : answer.scope.split(" ").filter((part) => part !== ""),
|
|
64391
|
+
expiresAt: ports.now().getTime() + answer.expires_in * MS_PER_SECOND4
|
|
64392
|
+
};
|
|
64393
|
+
}
|
|
64394
|
+
async function exchangeCode(ports, request7) {
|
|
64395
|
+
return grantTokens(
|
|
64396
|
+
ports,
|
|
64397
|
+
await postToken(ports, { grant_type: "authorization_code", client_id: request7.clientId, code: request7.code, code_verifier: request7.verifier, redirect_uri: request7.redirectUri }, "authorisation code exchange")
|
|
64398
|
+
);
|
|
64399
|
+
}
|
|
64400
|
+
async function refreshTokens(ports, request7) {
|
|
64401
|
+
return grantTokens(ports, await postToken(ports, { grant_type: "refresh_token", client_id: request7.clientId, refresh_token: request7.refreshToken }, "token refresh"));
|
|
64402
|
+
}
|
|
64403
|
+
var JwtHeaderSchema = external_exports.looseObject({ alg: external_exports.string(), kid: external_exports.string().optional() });
|
|
64404
|
+
var IdTokenClaimsSchema = external_exports.looseObject({
|
|
64405
|
+
iss: external_exports.string(),
|
|
64406
|
+
sub: external_exports.string().min(1),
|
|
64407
|
+
aud: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]),
|
|
64408
|
+
exp: external_exports.number(),
|
|
64409
|
+
nonce: external_exports.string().optional(),
|
|
64410
|
+
email: external_exports.string().optional()
|
|
64411
|
+
});
|
|
64412
|
+
var JwksSchema = external_exports.object({ keys: external_exports.array(external_exports.looseObject({ kid: external_exports.string().optional(), kty: external_exports.string() })) });
|
|
64413
|
+
function decodeSegment(segment) {
|
|
64414
|
+
if (segment === void 0) {
|
|
64415
|
+
throw new SiwcError("the ID token is not a three-part JWT");
|
|
64416
|
+
}
|
|
64417
|
+
try {
|
|
64418
|
+
const parsed = JSON.parse(Buffer.from(segment, "base64url").toString("utf8"));
|
|
64419
|
+
return parsed;
|
|
64420
|
+
} catch {
|
|
64421
|
+
throw new SiwcError("the ID token has an unreadable segment");
|
|
64422
|
+
}
|
|
64423
|
+
}
|
|
64424
|
+
async function verifyIdToken(ports, idToken, expected) {
|
|
64425
|
+
const [headerSegment, payloadSegment, signatureSegment, ...rest] = idToken.split(".");
|
|
64426
|
+
if (rest.length > 0 || headerSegment === void 0 || payloadSegment === void 0 || signatureSegment === void 0) {
|
|
64427
|
+
throw new SiwcError("the ID token is not a three-part JWT");
|
|
64428
|
+
}
|
|
64429
|
+
const header = JwtHeaderSchema.parse(decodeSegment(headerSegment));
|
|
64430
|
+
if (header.alg !== ID_TOKEN_ALGORITHM) {
|
|
64431
|
+
throw new SiwcError(`the ID token is signed with ${header.alg}, and only ${ID_TOKEN_ALGORITHM} is accepted`);
|
|
64432
|
+
}
|
|
64433
|
+
const response = await ports.fetch(SIWC_JWKS_URL, { method: "GET", headers: {}, signal: AbortSignal.timeout(TOKEN_CALL_TIMEOUT_MS) });
|
|
64434
|
+
if (!response.ok) {
|
|
64435
|
+
throw new SiwcError(`the issuer's key set could not be fetched (HTTP ${String(response.status)})`);
|
|
64436
|
+
}
|
|
64437
|
+
const jwk = JwksSchema.parse(await response.json()).keys.find((key) => key.kty === "RSA" && (header.kid === void 0 || key.kid === header.kid));
|
|
64438
|
+
if (jwk === void 0) {
|
|
64439
|
+
throw new SiwcError("the issuer's key set has no key for the ID token's signature");
|
|
64440
|
+
}
|
|
64441
|
+
const signed = Buffer.from(`${headerSegment}.${payloadSegment}`);
|
|
64442
|
+
if (!(0, import_node_crypto6.verify)("sha256", signed, (0, import_node_crypto6.createPublicKey)({ key: jwk, format: "jwk" }), Buffer.from(signatureSegment, "base64url"))) {
|
|
64443
|
+
throw new SiwcError("the ID token's signature did not verify");
|
|
64444
|
+
}
|
|
64445
|
+
const claims = IdTokenClaimsSchema.parse(decodeSegment(payloadSegment));
|
|
64446
|
+
if (claims.iss !== SIWC_ISSUER) {
|
|
64447
|
+
throw new SiwcError(`the ID token was issued by ${claims.iss}, not ${SIWC_ISSUER}`);
|
|
64448
|
+
}
|
|
64449
|
+
if (!(Array.isArray(claims.aud) ? claims.aud : [claims.aud]).includes(expected.clientId)) {
|
|
64450
|
+
throw new SiwcError("the ID token was issued for a different client");
|
|
64451
|
+
}
|
|
64452
|
+
if (claims.exp * MS_PER_SECOND4 <= ports.now().getTime()) {
|
|
64453
|
+
throw new SiwcError("the ID token has already expired");
|
|
64454
|
+
}
|
|
64455
|
+
if (expected.nonce !== void 0 && claims.nonce !== expected.nonce) {
|
|
64456
|
+
throw new SiwcError("the ID token's nonce did not match the request");
|
|
64457
|
+
}
|
|
64458
|
+
return { sub: claims.sub, email: claims.email };
|
|
64459
|
+
}
|
|
64460
|
+
|
|
64461
|
+
// src/codex/siwcLogin.ts
|
|
64462
|
+
var SIWC_AGENT_NAME = "agent-shim";
|
|
64463
|
+
var SIWC_LOGIN_TIMEOUT_MS = 3e5;
|
|
64464
|
+
async function runSiwcLogin(ports, options) {
|
|
64465
|
+
const existing = ports.store.read();
|
|
64466
|
+
const returning = existing?.grant;
|
|
64467
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
64468
|
+
const clientId = ports.store.read()?.registeredClientId ?? returning?.clientId;
|
|
64469
|
+
try {
|
|
64470
|
+
return await authorizeOnce(ports, options, clientId, attempt === 0 ? returning : void 0);
|
|
64471
|
+
} catch (error62) {
|
|
64472
|
+
if (!(error62 instanceof SiwcInvalidGrantError) || attempt > 0) {
|
|
64473
|
+
throw error62;
|
|
64474
|
+
}
|
|
64475
|
+
ports.print("OpenAI did not accept the first code, which is expected once after registering: authorising again with the registration it issued.");
|
|
64476
|
+
}
|
|
64477
|
+
}
|
|
64478
|
+
}
|
|
64479
|
+
async function authorizeOnce(ports, options, savedClientId, returning) {
|
|
64480
|
+
const pkce = newPkce(ports.siwc.randomBytes);
|
|
64481
|
+
const state = newOpaqueValue(ports.siwc.randomBytes);
|
|
64482
|
+
const nonce = newOpaqueValue(ports.siwc.randomBytes);
|
|
64483
|
+
const redirectUri = `http://127.0.0.1:${String(SIWC_CALLBACK_PORT)}${SIWC_CALLBACK_PATH}`;
|
|
64484
|
+
const url2 = buildAuthorizeUrl({
|
|
64485
|
+
clientId: savedClientId,
|
|
64486
|
+
agentName: SIWC_AGENT_NAME,
|
|
64487
|
+
redirectUri,
|
|
64488
|
+
state,
|
|
64489
|
+
nonce,
|
|
64490
|
+
challenge: pkce.challenge,
|
|
64491
|
+
...returning === void 0 ? {} : { returning: { idToken: returning.idToken, loginHint: returning.email } }
|
|
64492
|
+
});
|
|
64493
|
+
const listener = await ports.listen(SIWC_CALLBACK_PORT, state);
|
|
64494
|
+
try {
|
|
64495
|
+
ports.print(`Sign in at: ${url2}`);
|
|
64496
|
+
if (options.open) {
|
|
64497
|
+
ports.openBrowser(url2);
|
|
64498
|
+
}
|
|
64499
|
+
const callback = parseCallback(await listener.waitForCallback(AbortSignal.timeout(SIWC_LOGIN_TIMEOUT_MS)), state);
|
|
64500
|
+
const clientId = callback.clientId ?? savedClientId;
|
|
64501
|
+
if (clientId === void 0) {
|
|
64502
|
+
throw new SiwcError("the sign-in callback carried no client id and none was stored from an earlier sign-in");
|
|
64503
|
+
}
|
|
64504
|
+
const grantBefore = ports.store.read()?.grant;
|
|
64505
|
+
ports.store.write({ registeredClientId: clientId, ...grantBefore === void 0 ? {} : { grant: grantBefore } });
|
|
64506
|
+
const tokens = await exchangeCode(ports.siwc, { clientId, code: callback.code, verifier: pkce.verifier, redirectUri });
|
|
64507
|
+
if (tokens.refreshToken === void 0 || tokens.idToken === void 0) {
|
|
64508
|
+
throw new SiwcError("the token endpoint did not return a refresh token and an ID token, so the sign-in cannot be kept");
|
|
64509
|
+
}
|
|
64510
|
+
const scopes = tokens.scopes ?? callback.scopes;
|
|
64511
|
+
if (!scopes.includes(SIWC_PLAN_SCOPE)) {
|
|
64512
|
+
throw new SiwcError("the sign-in was not granted permission to use your ChatGPT plan: run the login again and allow it");
|
|
64513
|
+
}
|
|
64514
|
+
const identity = await verifyIdToken(ports.siwc, tokens.idToken, { clientId, nonce });
|
|
64515
|
+
ports.store.write({
|
|
64516
|
+
registeredClientId: clientId,
|
|
64517
|
+
grant: { clientId, sub: identity.sub, ...identity.email === void 0 ? {} : { email: identity.email }, idToken: tokens.idToken, accessToken: tokens.accessToken, refreshToken: tokens.refreshToken, scopes, expiresAt: tokens.expiresAt }
|
|
64518
|
+
});
|
|
64519
|
+
return { email: identity.email, sub: identity.sub };
|
|
64520
|
+
} finally {
|
|
64521
|
+
listener.close();
|
|
64522
|
+
}
|
|
64523
|
+
}
|
|
64524
|
+
var REVOKE_TIMEOUT_MS = 3e4;
|
|
64525
|
+
async function runSiwcLogout(ports) {
|
|
64526
|
+
const file2 = ports.store.read();
|
|
64527
|
+
if (file2?.grant === void 0) {
|
|
64528
|
+
return { hadGrant: false, revoked: false };
|
|
64529
|
+
}
|
|
64530
|
+
const revoked = await ports.siwc.fetch(SIWC_REVOKE_URL, {
|
|
64531
|
+
method: "POST",
|
|
64532
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
64533
|
+
body: new URLSearchParams({ token: file2.grant.refreshToken, token_type_hint: "refresh_token", client_id: file2.grant.clientId }).toString(),
|
|
64534
|
+
signal: AbortSignal.timeout(REVOKE_TIMEOUT_MS)
|
|
64535
|
+
}).then(
|
|
64536
|
+
(response) => response.ok,
|
|
64537
|
+
() => false
|
|
64538
|
+
);
|
|
64539
|
+
ports.store.write({ registeredClientId: file2.grant.clientId });
|
|
64540
|
+
return { hadGrant: true, revoked };
|
|
64541
|
+
}
|
|
64542
|
+
|
|
64543
|
+
// src/codex/siwcPorts.ts
|
|
64544
|
+
var import_node_child_process4 = require("node:child_process");
|
|
64545
|
+
var import_node_crypto7 = require("node:crypto");
|
|
64546
|
+
var import_node_http = __toESM(require("node:http"), 1);
|
|
64277
64547
|
|
|
64278
64548
|
// src/codex/http.ts
|
|
64279
64549
|
var HTTP_STATUS = {
|
|
@@ -64291,7 +64561,157 @@ var HTTP_STATUS = {
|
|
|
64291
64561
|
badGateway: 502
|
|
64292
64562
|
};
|
|
64293
64563
|
|
|
64564
|
+
// src/codex/siwcPorts.ts
|
|
64565
|
+
function realSiwcPorts(fetch3) {
|
|
64566
|
+
return { fetch: fetch3, randomBytes: (size) => (0, import_node_crypto7.randomBytes)(size), now: () => /* @__PURE__ */ new Date() };
|
|
64567
|
+
}
|
|
64568
|
+
var CALLBACK_PAGE = "<!doctype html><meta charset=utf-8><title>Signed in</title><p>You can close this tab and return to the terminal.</p>";
|
|
64569
|
+
async function listenForCallback(port, state) {
|
|
64570
|
+
let deliver;
|
|
64571
|
+
const arrived = new Promise((resolve) => {
|
|
64572
|
+
deliver = resolve;
|
|
64573
|
+
});
|
|
64574
|
+
const server = import_node_http.default.createServer((request7, response) => {
|
|
64575
|
+
const url2 = new URL(request7.url ?? "/", `http://127.0.0.1:${String(port)}`);
|
|
64576
|
+
if (request7.method !== "GET" || url2.pathname !== SIWC_CALLBACK_PATH || url2.searchParams.getAll("state").length !== 1 || url2.searchParams.get("state") !== state) {
|
|
64577
|
+
response.writeHead(HTTP_STATUS.notFound).end("Not found");
|
|
64578
|
+
return;
|
|
64579
|
+
}
|
|
64580
|
+
response.writeHead(HTTP_STATUS.ok, { "Content-Type": "text/html; charset=utf-8" });
|
|
64581
|
+
response.end(CALLBACK_PAGE);
|
|
64582
|
+
deliver?.(url2);
|
|
64583
|
+
});
|
|
64584
|
+
await new Promise((resolve, reject) => {
|
|
64585
|
+
server.once("error", (error62) => {
|
|
64586
|
+
reject(error62.code === "EADDRINUSE" ? new Error(`port ${String(port)} is in use (another sign-in, such as \`codex login\`, may be running): finish or stop it and try again`) : error62);
|
|
64587
|
+
});
|
|
64588
|
+
server.listen(port, "127.0.0.1", () => {
|
|
64589
|
+
resolve();
|
|
64590
|
+
});
|
|
64591
|
+
});
|
|
64592
|
+
return {
|
|
64593
|
+
waitForCallback: async (signal) => await Promise.race([
|
|
64594
|
+
arrived,
|
|
64595
|
+
new Promise((_resolve, reject) => {
|
|
64596
|
+
signal.addEventListener("abort", () => {
|
|
64597
|
+
reject(new Error("timed out waiting for the browser sign-in to finish"));
|
|
64598
|
+
});
|
|
64599
|
+
})
|
|
64600
|
+
]),
|
|
64601
|
+
close: () => {
|
|
64602
|
+
server.close();
|
|
64603
|
+
server.closeAllConnections();
|
|
64604
|
+
}
|
|
64605
|
+
};
|
|
64606
|
+
}
|
|
64607
|
+
function openInBrowser(url2) {
|
|
64608
|
+
const command = process.platform === "darwin" ? { file: "open", args: [url2] } : process.platform === "win32" ? { file: "cmd", args: ["/c", "start", "", url2] } : { file: "xdg-open", args: [url2] };
|
|
64609
|
+
(0, import_node_child_process4.spawn)(command.file, command.args, { detached: true, stdio: "ignore" }).unref();
|
|
64610
|
+
}
|
|
64611
|
+
|
|
64612
|
+
// src/codex/siwcStore.ts
|
|
64613
|
+
var SiwcGrantSchema = external_exports.strictObject({
|
|
64614
|
+
clientId: external_exports.string().min(1),
|
|
64615
|
+
sub: external_exports.string().min(1),
|
|
64616
|
+
email: external_exports.string().optional(),
|
|
64617
|
+
idToken: external_exports.string().min(1),
|
|
64618
|
+
accessToken: external_exports.string().min(1),
|
|
64619
|
+
refreshToken: external_exports.string().min(1),
|
|
64620
|
+
scopes: external_exports.array(external_exports.string()).readonly(),
|
|
64621
|
+
/** When the access token stops working, in milliseconds since the epoch. */
|
|
64622
|
+
expiresAt: external_exports.number()
|
|
64623
|
+
});
|
|
64624
|
+
var SiwcFileSchema = external_exports.strictObject({ registeredClientId: external_exports.string().min(1).optional(), grant: SiwcGrantSchema.optional() });
|
|
64625
|
+
var SIWC_REFRESH_MARGIN_MS = 6e4;
|
|
64626
|
+
function parseSiwcFile(raw, filePath) {
|
|
64627
|
+
let json2;
|
|
64628
|
+
try {
|
|
64629
|
+
json2 = JSON.parse(raw);
|
|
64630
|
+
} catch {
|
|
64631
|
+
throw new CodexAuthError(`${filePath} is not valid JSON: run \`agent-shim codex login\` again`);
|
|
64632
|
+
}
|
|
64633
|
+
const parsed = SiwcFileSchema.safeParse(json2);
|
|
64634
|
+
if (!parsed.success) {
|
|
64635
|
+
throw new CodexAuthError(`${filePath} is not a Sign in with ChatGPT file: run \`agent-shim codex login\` again`);
|
|
64636
|
+
}
|
|
64637
|
+
return parsed.data;
|
|
64638
|
+
}
|
|
64639
|
+
function grantFrom(previous, tokens) {
|
|
64640
|
+
return {
|
|
64641
|
+
...previous,
|
|
64642
|
+
accessToken: tokens.accessToken,
|
|
64643
|
+
refreshToken: tokens.refreshToken ?? previous.refreshToken,
|
|
64644
|
+
idToken: tokens.idToken ?? previous.idToken,
|
|
64645
|
+
scopes: tokens.scopes ?? previous.scopes,
|
|
64646
|
+
expiresAt: tokens.expiresAt
|
|
64647
|
+
};
|
|
64648
|
+
}
|
|
64649
|
+
function createSiwcStore(filePath, ports) {
|
|
64650
|
+
let cached2;
|
|
64651
|
+
let inFlight;
|
|
64652
|
+
const read = () => {
|
|
64653
|
+
const raw = ports.fs.read(filePath);
|
|
64654
|
+
return raw === void 0 ? void 0 : parseSiwcFile(raw, filePath);
|
|
64655
|
+
};
|
|
64656
|
+
const write = (file2) => {
|
|
64657
|
+
const temp = `${filePath}.${ports.tempSuffix}.tmp`;
|
|
64658
|
+
ports.fs.writePrivate(temp, `${JSON.stringify(file2, null, 2)}
|
|
64659
|
+
`);
|
|
64660
|
+
ports.fs.rename(temp, filePath);
|
|
64661
|
+
cached2 = file2.grant;
|
|
64662
|
+
};
|
|
64663
|
+
const loadSignedIn = () => {
|
|
64664
|
+
const file2 = read();
|
|
64665
|
+
if (file2?.grant === void 0) {
|
|
64666
|
+
throw new CodexAuthError(`no Sign in with ChatGPT login at ${filePath}: run \`agent-shim codex login\` first`);
|
|
64667
|
+
}
|
|
64668
|
+
if (!file2.grant.scopes.includes(SIWC_PLAN_SCOPE)) {
|
|
64669
|
+
throw new CodexAuthError(`the Sign in with ChatGPT login at ${filePath} was not granted permission to use your ChatGPT plan: run \`agent-shim codex login\` again and allow it`);
|
|
64670
|
+
}
|
|
64671
|
+
return { file: file2, grant: file2.grant };
|
|
64672
|
+
};
|
|
64673
|
+
const credentialsOf2 = (grant) => ({ accessToken: grant.accessToken, accountId: void 0 });
|
|
64674
|
+
const doRefresh = async (rejected) => {
|
|
64675
|
+
const { file: file2, grant } = loadSignedIn();
|
|
64676
|
+
if (rejected !== void 0 && grant.accessToken !== rejected) {
|
|
64677
|
+
cached2 = grant;
|
|
64678
|
+
return credentialsOf2(grant);
|
|
64679
|
+
}
|
|
64680
|
+
let tokens;
|
|
64681
|
+
try {
|
|
64682
|
+
tokens = await refreshTokens(ports.siwc, { clientId: grant.clientId, refreshToken: grant.refreshToken });
|
|
64683
|
+
} catch (error62) {
|
|
64684
|
+
if (error62 instanceof SiwcError) {
|
|
64685
|
+
throw new CodexAuthError(`${error62.message}: run \`agent-shim codex login\` again if the login was revoked`);
|
|
64686
|
+
}
|
|
64687
|
+
throw error62;
|
|
64688
|
+
}
|
|
64689
|
+
const next = grantFrom(grant, tokens);
|
|
64690
|
+
write({ ...file2, grant: next });
|
|
64691
|
+
return credentialsOf2(next);
|
|
64692
|
+
};
|
|
64693
|
+
const refreshOnce = async (rejected) => await (inFlight ??= doRefresh(rejected).finally(() => {
|
|
64694
|
+
inFlight = void 0;
|
|
64695
|
+
}));
|
|
64696
|
+
return {
|
|
64697
|
+
read,
|
|
64698
|
+
write,
|
|
64699
|
+
auth: {
|
|
64700
|
+
current: async () => {
|
|
64701
|
+
const grant = cached2 ?? loadSignedIn().grant;
|
|
64702
|
+
cached2 = grant;
|
|
64703
|
+
if (grant.expiresAt - SIWC_REFRESH_MARGIN_MS <= ports.siwc.now().getTime()) {
|
|
64704
|
+
return await refreshOnce(void 0);
|
|
64705
|
+
}
|
|
64706
|
+
return credentialsOf2(grant);
|
|
64707
|
+
},
|
|
64708
|
+
refresh: async (rejected) => await refreshOnce(rejected)
|
|
64709
|
+
}
|
|
64710
|
+
};
|
|
64711
|
+
}
|
|
64712
|
+
|
|
64294
64713
|
// src/codex/upstream.ts
|
|
64714
|
+
var import_node_crypto8 = require("node:crypto");
|
|
64295
64715
|
var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
64296
64716
|
var CODEX_UPSTREAM_TIMEOUT_MS = 3e5;
|
|
64297
64717
|
var CODEX_HEADERS_TIMEOUT_MS = 15e3;
|
|
@@ -64327,12 +64747,17 @@ function sessionIdFor(userId, randomId) {
|
|
|
64327
64747
|
if (userId === void 0 || userId === "") {
|
|
64328
64748
|
return randomId();
|
|
64329
64749
|
}
|
|
64330
|
-
const hex3 = (0,
|
|
64750
|
+
const hex3 = (0, import_node_crypto8.createHash)("sha256").update(`agent-shim codex session
|
|
64331
64751
|
${userId}`).digest("hex");
|
|
64332
64752
|
let next = 0;
|
|
64333
64753
|
return UUID_TEMPLATE.replace(/x/g, () => hex3.charAt(next++));
|
|
64334
64754
|
}
|
|
64335
|
-
|
|
64755
|
+
var CODEX_BACKEND_TARGET = { url: CODEX_RESPONSES_URL, headers: codexBackendHeaders };
|
|
64756
|
+
var RESPONSES_API_TARGET = {
|
|
64757
|
+
url: SIWC_RESPONSES_URL,
|
|
64758
|
+
headers: (credentials) => ({ "Content-Type": "application/json", Accept: "text/event-stream", Authorization: `Bearer ${credentials.accessToken}` })
|
|
64759
|
+
};
|
|
64760
|
+
function codexBackendHeaders(credentials, sessionId) {
|
|
64336
64761
|
return {
|
|
64337
64762
|
"Content-Type": "application/json",
|
|
64338
64763
|
Accept: "text/event-stream",
|
|
@@ -64344,11 +64769,11 @@ function headersFor(credentials, sessionId) {
|
|
|
64344
64769
|
};
|
|
64345
64770
|
}
|
|
64346
64771
|
async function callCodex(ports, request7, sessionId, signal) {
|
|
64347
|
-
const
|
|
64772
|
+
const target = ports.target ?? CODEX_BACKEND_TARGET;
|
|
64348
64773
|
const body = JSON.stringify(request7);
|
|
64349
|
-
const send = async (credentials2) => await fetchUntilHeaders(ports.fetch, ports.timers,
|
|
64774
|
+
const send = async (credentials2) => await fetchUntilHeaders(ports.fetch, ports.timers, target.url, {
|
|
64350
64775
|
method: "POST",
|
|
64351
|
-
headers:
|
|
64776
|
+
headers: target.headers(credentials2, sessionId),
|
|
64352
64777
|
body,
|
|
64353
64778
|
signal: AbortSignal.any([signal, AbortSignal.timeout(CODEX_UPSTREAM_TIMEOUT_MS)])
|
|
64354
64779
|
});
|
|
@@ -64384,6 +64809,7 @@ var realCodexAuthFs = {
|
|
|
64384
64809
|
}
|
|
64385
64810
|
},
|
|
64386
64811
|
writePrivate: (filePath, contents) => {
|
|
64812
|
+
import_node_fs11.default.mkdirSync(import_node_path31.default.dirname(filePath), { recursive: true });
|
|
64387
64813
|
import_node_fs11.default.writeFileSync(filePath, contents, { encoding: "utf8", mode: PRIVATE_FILE_MODE });
|
|
64388
64814
|
import_node_fs11.default.chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
64389
64815
|
},
|
|
@@ -64403,17 +64829,22 @@ function writeUsageSnapshot(log, snapshot) {
|
|
|
64403
64829
|
log(`usage snapshot write failed: ${error62 instanceof Error ? error62.message : String(error62)}`);
|
|
64404
64830
|
}
|
|
64405
64831
|
}
|
|
64406
|
-
function createCodexRoutePorts(log) {
|
|
64832
|
+
function createCodexRoutePorts(log, signInFile) {
|
|
64407
64833
|
const agent = createUpstreamAgent();
|
|
64408
64834
|
const upstreamFetch = createUpstreamFetch(agent);
|
|
64835
|
+
const tempSuffix = `${String(process.pid)}.${(0, import_node_crypto9.randomUUID)()}`;
|
|
64409
64836
|
const auth = createCodexAuthStore(import_node_path31.default.join(codexHome(process.env, import_node_os6.default.homedir()), "auth.json"), {
|
|
64410
64837
|
fs: realCodexAuthFs,
|
|
64411
64838
|
fetch: upstreamFetch,
|
|
64412
64839
|
now: () => /* @__PURE__ */ new Date(),
|
|
64413
|
-
tempSuffix
|
|
64840
|
+
tempSuffix
|
|
64414
64841
|
});
|
|
64842
|
+
const signIn = createSiwcStore(signInFile, { fs: realCodexAuthFs, siwc: realSiwcPorts(upstreamFetch), tempSuffix });
|
|
64415
64843
|
return {
|
|
64416
|
-
|
|
64844
|
+
upstreams: {
|
|
64845
|
+
"codex-cli": { fetch: upstreamFetch, auth, timers: realTimers, randomId: import_node_crypto9.randomUUID },
|
|
64846
|
+
"chatgpt-sign-in": { fetch: upstreamFetch, auth: signIn.auth, timers: realTimers, randomId: import_node_crypto9.randomUUID, target: RESPONSES_API_TARGET }
|
|
64847
|
+
},
|
|
64417
64848
|
writeUsageSnapshot: (snapshot) => {
|
|
64418
64849
|
writeUsageSnapshot(log, snapshot);
|
|
64419
64850
|
},
|
|
@@ -64421,6 +64852,18 @@ function createCodexRoutePorts(log) {
|
|
|
64421
64852
|
log
|
|
64422
64853
|
};
|
|
64423
64854
|
}
|
|
64855
|
+
function readSignInStatus(fsPort, filePath) {
|
|
64856
|
+
const raw = fsPort.readFileUtf8(filePath);
|
|
64857
|
+
if (raw === void 0) {
|
|
64858
|
+
return { state: "none" };
|
|
64859
|
+
}
|
|
64860
|
+
try {
|
|
64861
|
+
const file2 = parseSiwcFile(raw, filePath);
|
|
64862
|
+
return file2.grant === void 0 ? { state: "none" } : { state: "signed-in", email: file2.grant.email, planScope: file2.grant.scopes.includes(SIWC_PLAN_SCOPE), accessTokenExpiresAt: file2.grant.expiresAt };
|
|
64863
|
+
} catch (error62) {
|
|
64864
|
+
return { state: "unreadable", message: error62 instanceof Error ? error62.message : String(error62) };
|
|
64865
|
+
}
|
|
64866
|
+
}
|
|
64424
64867
|
function codexProviderNames(fsPort, providersDir) {
|
|
64425
64868
|
return readAllProviders(fsPort, providersDir).filter((entry) => isCodexProvider(entry.provider)).map((entry) => entry.name).sort();
|
|
64426
64869
|
}
|
|
@@ -64431,12 +64874,22 @@ function collectCodexStatus(fsPort, paths, isRunning) {
|
|
|
64431
64874
|
supervisorAlive: state.supervisorPid !== void 0 && isRunning(state.supervisorPid),
|
|
64432
64875
|
sessions: listFrontDoorSessions(fsPort, paths.frontdoorSessionsDir).map((session) => ({ ...session, alive: isRunning(session.pid) })),
|
|
64433
64876
|
codexProviders: codexProviderNames(fsPort, paths.providersDir),
|
|
64877
|
+
signIn: readSignInStatus(fsPort, paths.chatgptSignInFile),
|
|
64434
64878
|
usageSnapshotPath: codexUsageSnapshotPath(),
|
|
64435
64879
|
usageSnapshotExists: fsPort.readFileUtf8(codexUsageSnapshotPath()) !== void 0,
|
|
64436
64880
|
logPath: paths.frontdoorLogPath,
|
|
64437
64881
|
logExists: fsPort.readFileUtf8(paths.frontdoorLogPath) !== void 0
|
|
64438
64882
|
};
|
|
64439
64883
|
}
|
|
64884
|
+
function formatSignIn(signIn) {
|
|
64885
|
+
if (signIn.state === "none") {
|
|
64886
|
+
return "chatgpt sign-in: not signed in (run `agent-shim codex login`)";
|
|
64887
|
+
}
|
|
64888
|
+
if (signIn.state === "unreadable") {
|
|
64889
|
+
return `chatgpt sign-in: ${signIn.message}`;
|
|
64890
|
+
}
|
|
64891
|
+
return `chatgpt sign-in: signed in${signIn.email === void 0 ? "" : ` as ${signIn.email}`}${signIn.planScope ? "" : ", WITHOUT permission to use your ChatGPT plan (run `agent-shim codex login` again and allow it)"}`;
|
|
64892
|
+
}
|
|
64440
64893
|
function formatCodexStatus(status) {
|
|
64441
64894
|
const lines = [];
|
|
64442
64895
|
lines.push(
|
|
@@ -64457,10 +64910,24 @@ function formatCodexStatus(status) {
|
|
|
64457
64910
|
if (status.frontDoor.lastError !== void 0) {
|
|
64458
64911
|
lines.push(`last error: ${status.frontDoor.lastError}`);
|
|
64459
64912
|
}
|
|
64913
|
+
lines.push(formatSignIn(status.signIn));
|
|
64460
64914
|
lines.push(`usage snapshot: ${status.usageSnapshotPath}${status.usageSnapshotExists ? "" : " (not created yet)"}`);
|
|
64461
64915
|
lines.push(`daemon log: ${status.logPath}${status.logExists ? "" : " (not created yet)"}`);
|
|
64462
64916
|
return lines;
|
|
64463
64917
|
}
|
|
64918
|
+
function realSiwcLoginPorts(paths) {
|
|
64919
|
+
const siwc = realSiwcPorts(createUpstreamFetch(createUpstreamAgent()));
|
|
64920
|
+
const store = createSiwcStore(paths.chatgptSignInFile, { fs: realCodexAuthFs, siwc, tempSuffix: `${String(process.pid)}.${(0, import_node_crypto9.randomUUID)()}` });
|
|
64921
|
+
return {
|
|
64922
|
+
store,
|
|
64923
|
+
siwc,
|
|
64924
|
+
listen: listenForCallback,
|
|
64925
|
+
openBrowser: openInBrowser,
|
|
64926
|
+
print: (line) => {
|
|
64927
|
+
console.log(line);
|
|
64928
|
+
}
|
|
64929
|
+
};
|
|
64930
|
+
}
|
|
64464
64931
|
function registerCodexCommand(program2, deps) {
|
|
64465
64932
|
const { paths } = deps;
|
|
64466
64933
|
const codex = withExamples(program2.command("codex").description("Inspect the codex translation the front-door daemon serves for codex providers."), ["agent-shim codex status"]);
|
|
@@ -64477,10 +64944,38 @@ function registerCodexCommand(program2, deps) {
|
|
|
64477
64944
|
}),
|
|
64478
64945
|
["agent-shim codex status", "agent-shim codex status --json"]
|
|
64479
64946
|
);
|
|
64947
|
+
withExamples(
|
|
64948
|
+
codex.command("login").description("Sign in with ChatGPT so a codex provider with `codex.login` set to `chatgpt-sign-in` can spend your ChatGPT plan on OpenAI's public Responses API. Opens your browser.").option("--no-open", "Print the sign-in address instead of opening the browser.").option("--json", "Print the result as JSON.").action(async (options) => {
|
|
64949
|
+
const ports = realSiwcLoginPorts(paths);
|
|
64950
|
+
const result = await runSiwcLogin(options.json === true ? { ...ports, print: () => void 0 } : ports, { open: options.open });
|
|
64951
|
+
if (options.json === true) {
|
|
64952
|
+
printJson({ action: "login", email: result.email ?? null, sub: result.sub });
|
|
64953
|
+
return;
|
|
64954
|
+
}
|
|
64955
|
+
console.log(`Signed in${result.email === void 0 ? "" : ` as ${result.email}`}. Set "codex": { "login": "chatgpt-sign-in" } on a codex provider to use it.`);
|
|
64956
|
+
}),
|
|
64957
|
+
["agent-shim codex login", "agent-shim codex login --no-open"]
|
|
64958
|
+
);
|
|
64959
|
+
withExamples(
|
|
64960
|
+
codex.command("logout").description("Revoke the Sign in with ChatGPT login and remove it from this machine.").option("--json", "Print the result as JSON.").action(async (options) => {
|
|
64961
|
+
const ports = realSiwcLoginPorts(paths);
|
|
64962
|
+
const result = await runSiwcLogout(ports);
|
|
64963
|
+
if (options.json === true) {
|
|
64964
|
+
printJson({ action: "logout", ...result });
|
|
64965
|
+
return;
|
|
64966
|
+
}
|
|
64967
|
+
if (!result.hadGrant) {
|
|
64968
|
+
console.log("Not signed in.");
|
|
64969
|
+
return;
|
|
64970
|
+
}
|
|
64971
|
+
console.log(result.revoked ? "Signed out and revoked the login at OpenAI." : "Signed out here, but OpenAI could not be told to revoke the login: revoke it in ChatGPT settings.");
|
|
64972
|
+
}),
|
|
64973
|
+
["agent-shim codex logout"]
|
|
64974
|
+
);
|
|
64480
64975
|
}
|
|
64481
64976
|
|
|
64482
64977
|
// src/frontdoor/commands.ts
|
|
64483
|
-
var
|
|
64978
|
+
var import_node_crypto14 = require("node:crypto");
|
|
64484
64979
|
var import_node_path36 = __toESM(require("node:path"), 1);
|
|
64485
64980
|
var import_node_fs13 = __toESM(require("node:fs"), 1);
|
|
64486
64981
|
|
|
@@ -64585,7 +65080,7 @@ function createDoorPipelines(deps) {
|
|
|
64585
65080
|
}
|
|
64586
65081
|
|
|
64587
65082
|
// src/frontdoor/capability.ts
|
|
64588
|
-
var
|
|
65083
|
+
var import_node_crypto10 = require("node:crypto");
|
|
64589
65084
|
var CONNECT_PROXY_USER = "agent-shim";
|
|
64590
65085
|
var CONNECT_PROXY_REALM = "agent-shim front door";
|
|
64591
65086
|
var BASIC_SCHEME = "basic";
|
|
@@ -64607,13 +65102,13 @@ function capabilityFromProxyAuthorization(value2) {
|
|
|
64607
65102
|
return password === "" ? void 0 : password;
|
|
64608
65103
|
}
|
|
64609
65104
|
function digest(token) {
|
|
64610
|
-
return (0,
|
|
65105
|
+
return (0, import_node_crypto10.createHash)("sha256").update(token, "utf8").digest();
|
|
64611
65106
|
}
|
|
64612
65107
|
function isLiveCapability(presented, live) {
|
|
64613
65108
|
const presentedDigest = digest(presented);
|
|
64614
65109
|
let matched = false;
|
|
64615
65110
|
for (const token of live) {
|
|
64616
|
-
const equal = (0,
|
|
65111
|
+
const equal = (0, import_node_crypto10.timingSafeEqual)(presentedDigest, digest(token));
|
|
64617
65112
|
matched = equal || matched;
|
|
64618
65113
|
}
|
|
64619
65114
|
return matched;
|
|
@@ -64757,11 +65252,11 @@ function createFileCapture(file2, now = () => /* @__PURE__ */ new Date()) {
|
|
|
64757
65252
|
}
|
|
64758
65253
|
|
|
64759
65254
|
// src/frontdoor/connect.ts
|
|
64760
|
-
var
|
|
65255
|
+
var import_node_crypto12 = require("node:crypto");
|
|
64761
65256
|
var fs13 = __toESM(require("node:fs"), 1);
|
|
64762
65257
|
|
|
64763
65258
|
// src/frontdoor/x509.ts
|
|
64764
|
-
var
|
|
65259
|
+
var import_node_crypto11 = require("node:crypto");
|
|
64765
65260
|
var import_node_net = __toESM(require("node:net"), 1);
|
|
64766
65261
|
var TAG_BOOLEAN = 1;
|
|
64767
65262
|
var TAG_INTEGER = 2;
|
|
@@ -64797,7 +65292,7 @@ var HIGH_BIT = 128;
|
|
|
64797
65292
|
var BASE_128_PAYLOAD_MASK = 127;
|
|
64798
65293
|
var FIRST_ARC_WEIGHT = 40;
|
|
64799
65294
|
var SHORT_FORM_MAX_LENGTH = 127;
|
|
64800
|
-
var
|
|
65295
|
+
var MS_PER_SECOND5 = 1e3;
|
|
64801
65296
|
var UTC_TIME_LAST_YEAR = 2049;
|
|
64802
65297
|
var YEAR_DIGITS = 4;
|
|
64803
65298
|
var TWO_DIGIT_YEAR_DIGITS = 2;
|
|
@@ -64856,7 +65351,7 @@ function wholeBitString(content) {
|
|
|
64856
65351
|
return tlv(TAG_BIT_STRING, Buffer.concat([Buffer.from([0]), content]));
|
|
64857
65352
|
}
|
|
64858
65353
|
function time3(instant) {
|
|
64859
|
-
const iso = new Date(Math.floor(instant.getTime() /
|
|
65354
|
+
const iso = new Date(Math.floor(instant.getTime() / MS_PER_SECOND5) * MS_PER_SECOND5).toISOString();
|
|
64860
65355
|
const compact = `${iso.replace(/[-:T]/g, "").slice(0, COMPACT_TIME_DIGITS)}Z`;
|
|
64861
65356
|
if (instant.getUTCFullYear() > UTC_TIME_LAST_YEAR) {
|
|
64862
65357
|
return tlv(TAG_GENERALIZED_TIME, Buffer.from(compact, "ascii"));
|
|
@@ -64913,7 +65408,7 @@ function ipBytes(address) {
|
|
|
64913
65408
|
return bytes;
|
|
64914
65409
|
}
|
|
64915
65410
|
function keyIdentifier(publicKey) {
|
|
64916
|
-
return (0,
|
|
65411
|
+
return (0, import_node_crypto11.createHash)("sha1").update(publicKey.export({ type: "pkcs1", format: "der" })).digest();
|
|
64917
65412
|
}
|
|
64918
65413
|
function readElement(buffer, offset) {
|
|
64919
65414
|
const tag = buffer[offset];
|
|
@@ -64959,7 +65454,7 @@ ${body.join("\n")}
|
|
|
64959
65454
|
`;
|
|
64960
65455
|
}
|
|
64961
65456
|
function randomSerial() {
|
|
64962
|
-
const bytes = (0,
|
|
65457
|
+
const bytes = (0, import_node_crypto11.randomBytes)(SERIAL_NUMBER_BYTES);
|
|
64963
65458
|
bytes[0] = (bytes[0] ?? 0) & BASE_128_PAYLOAD_MASK | HIGH_BIT >> 1;
|
|
64964
65459
|
return bytes;
|
|
64965
65460
|
}
|
|
@@ -64974,7 +65469,7 @@ function assemble(spec) {
|
|
|
64974
65469
|
spec.subjectPublicKey.export({ type: "spki", format: "der" }),
|
|
64975
65470
|
tlv(TAG_EXTENSIONS, sequence(...spec.extensions))
|
|
64976
65471
|
);
|
|
64977
|
-
const signature = (0,
|
|
65472
|
+
const signature = (0, import_node_crypto11.sign)("sha256", tbs, spec.signingKey);
|
|
64978
65473
|
return sequence(tbs, SIGNATURE_ALGORITHM, wholeBitString(signature));
|
|
64979
65474
|
}
|
|
64980
65475
|
function subjectKeyIdentifierExtension(publicKey) {
|
|
@@ -64984,7 +65479,7 @@ function basicConstraintsExtension(isCa) {
|
|
|
64984
65479
|
return extension(OID_BASIC_CONSTRAINTS, true, sequence(...isCa ? [boolean4(true)] : []));
|
|
64985
65480
|
}
|
|
64986
65481
|
function rsaKeyPair() {
|
|
64987
|
-
return (0,
|
|
65482
|
+
return (0, import_node_crypto11.generateKeyPairSync)("rsa", { modulusLength: RSA_MODULUS_BITS });
|
|
64988
65483
|
}
|
|
64989
65484
|
function keyPem(privateKey) {
|
|
64990
65485
|
return privateKey.export({ type: "pkcs8", format: "pem" });
|
|
@@ -65008,8 +65503,8 @@ function issueLeafCertificate(ca, names, notBefore, notAfter) {
|
|
|
65008
65503
|
if (commonName === void 0) {
|
|
65009
65504
|
throw new Error("a leaf certificate needs at least one name");
|
|
65010
65505
|
}
|
|
65011
|
-
const caCertificate = new
|
|
65012
|
-
const caPrivateKey = (0,
|
|
65506
|
+
const caCertificate = new import_node_crypto11.X509Certificate(ca.certPem);
|
|
65507
|
+
const caPrivateKey = (0, import_node_crypto11.createPrivateKey)(ca.keyPem);
|
|
65013
65508
|
const { publicKey, privateKey } = rsaKeyPair();
|
|
65014
65509
|
const generalNames = names.map((name) => import_node_net.default.isIP(name) === 0 ? tlv(TAG_GENERAL_NAME_DNS, Buffer.from(name, "ascii")) : tlv(TAG_GENERAL_NAME_IP, ipBytes(name)));
|
|
65015
65510
|
const der = assemble({
|
|
@@ -65106,22 +65601,22 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
65106
65601
|
};
|
|
65107
65602
|
writeFrontDoorState(fs19, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
|
|
65108
65603
|
const previousSticky = lastPort;
|
|
65109
|
-
let
|
|
65604
|
+
let http7;
|
|
65110
65605
|
try {
|
|
65111
|
-
|
|
65606
|
+
http7 = await ports.startProviderListener(lastPort);
|
|
65112
65607
|
} catch (error62) {
|
|
65113
65608
|
return fail(`could not start the provider listener: ${error62 instanceof Error ? error62.message : String(error62)}`);
|
|
65114
65609
|
}
|
|
65115
|
-
if (previousSticky !== void 0 &&
|
|
65116
|
-
ports.log(`agent-shim frontdoor supervisor: sticky port ${String(previousSticky)} was occupied; moving to ${String(
|
|
65610
|
+
if (previousSticky !== void 0 && http7.port !== previousSticky) {
|
|
65611
|
+
ports.log(`agent-shim frontdoor supervisor: sticky port ${String(previousSticky)} was occupied; moving to ${String(http7.port)} (sessions launched against the old port are stale until they relaunch)`);
|
|
65117
65612
|
}
|
|
65118
|
-
lastPort =
|
|
65613
|
+
lastPort = http7.port;
|
|
65119
65614
|
const previousStickyConnect = lastConnectPort;
|
|
65120
65615
|
let connect3;
|
|
65121
65616
|
try {
|
|
65122
65617
|
connect3 = await ports.startConnectListener(lastConnectPort);
|
|
65123
65618
|
} catch (error62) {
|
|
65124
|
-
await
|
|
65619
|
+
await http7.close();
|
|
65125
65620
|
return fail(`could not start the CONNECT surface: ${error62 instanceof Error ? error62.message : String(error62)}`);
|
|
65126
65621
|
}
|
|
65127
65622
|
if (previousStickyConnect !== void 0 && connect3.port !== previousStickyConnect) {
|
|
@@ -65134,16 +65629,16 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
65134
65629
|
direct = await ports.startDirectListener(lastDirectPort);
|
|
65135
65630
|
} catch (error62) {
|
|
65136
65631
|
await connect3.close();
|
|
65137
|
-
await
|
|
65632
|
+
await http7.close();
|
|
65138
65633
|
return fail(`could not start the direct listener: ${error62 instanceof Error ? error62.message : String(error62)}`);
|
|
65139
65634
|
}
|
|
65140
65635
|
if (previousStickyDirect !== void 0 && direct.port !== previousStickyDirect) {
|
|
65141
65636
|
ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom must be restarted to admit the new address)`);
|
|
65142
65637
|
}
|
|
65143
65638
|
lastDirectPort = direct.port;
|
|
65144
|
-
writeFrontDoorState(fs19, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port:
|
|
65639
|
+
writeFrontDoorState(fs19, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http7.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
|
|
65145
65640
|
fs19.removeRecursive(paths.frontdoorLockFile);
|
|
65146
|
-
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(
|
|
65641
|
+
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http7.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
|
|
65147
65642
|
let idleSince;
|
|
65148
65643
|
let ticks = 0;
|
|
65149
65644
|
for (; ; ) {
|
|
@@ -65151,14 +65646,17 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
65151
65646
|
return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
|
|
65152
65647
|
}
|
|
65153
65648
|
ticks += 1;
|
|
65154
|
-
|
|
65155
|
-
|
|
65649
|
+
const listed = listFrontDoorSessions(fs19, paths.frontdoorSessionsDir);
|
|
65650
|
+
const pruned = pruneDeadFrontDoorSessions(fs19, paths.frontdoorSessionsDir, ports.isRunning);
|
|
65651
|
+
ports.observeLaunchRegistry(listed, pruned);
|
|
65652
|
+
const prunedPids = new Set(pruned);
|
|
65653
|
+
if (listed.filter((session) => !prunedPids.has(session.pid)).length === 0) {
|
|
65156
65654
|
idleSince ??= ports.now();
|
|
65157
65655
|
if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE2) {
|
|
65158
65656
|
ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
|
|
65159
65657
|
await direct.close();
|
|
65160
65658
|
await connect3.close();
|
|
65161
|
-
await
|
|
65659
|
+
await http7.close();
|
|
65162
65660
|
ports.closeRcStreamHub();
|
|
65163
65661
|
writeFrontDoorState(fs19, paths.frontdoorStateFile, sticky());
|
|
65164
65662
|
return 0;
|
|
@@ -65274,8 +65772,8 @@ function ensureCa(store, generate) {
|
|
|
65274
65772
|
}
|
|
65275
65773
|
function caParses(ca) {
|
|
65276
65774
|
try {
|
|
65277
|
-
new
|
|
65278
|
-
(0,
|
|
65775
|
+
new import_node_crypto12.X509Certificate(ca.certPem);
|
|
65776
|
+
(0, import_node_crypto12.createPrivateKey)(ca.keyPem);
|
|
65279
65777
|
return true;
|
|
65280
65778
|
} catch {
|
|
65281
65779
|
return false;
|
|
@@ -65563,13 +66061,13 @@ function realConnectCertStore(paths) {
|
|
|
65563
66061
|
|
|
65564
66062
|
// src/frontdoor/connectEffects.ts
|
|
65565
66063
|
var import_node_dns = __toESM(require("node:dns"), 1);
|
|
65566
|
-
var
|
|
66064
|
+
var http3 = __toESM(require("node:http"), 1);
|
|
65567
66065
|
var https3 = __toESM(require("node:https"), 1);
|
|
65568
66066
|
var net2 = __toESM(require("node:net"), 1);
|
|
65569
66067
|
var tls = __toESM(require("node:tls"), 1);
|
|
65570
66068
|
|
|
65571
66069
|
// src/frontdoor/server.ts
|
|
65572
|
-
var
|
|
66070
|
+
var import_node_http2 = __toESM(require("node:http"), 1);
|
|
65573
66071
|
var import_node_https = __toESM(require("node:https"), 1);
|
|
65574
66072
|
|
|
65575
66073
|
// src/frontdoor/rcControl.ts
|
|
@@ -66646,7 +67144,7 @@ function createFrontDoorServer(pipeline, log, tls2, control, api) {
|
|
|
66646
67144
|
});
|
|
66647
67145
|
};
|
|
66648
67146
|
if (tls2 === void 0) {
|
|
66649
|
-
return
|
|
67147
|
+
return import_node_http2.default.createServer(handler);
|
|
66650
67148
|
}
|
|
66651
67149
|
const server = import_node_https.default.createServer({ key: tls2.keyPem, cert: tls2.certPem }, handler);
|
|
66652
67150
|
server.on("tlsClientError", (_error, socket) => {
|
|
@@ -66661,7 +67159,7 @@ async function frontDoorHealthy(port, ca) {
|
|
|
66661
67159
|
resolve(response.statusCode === HTTP_STATUS.ok);
|
|
66662
67160
|
};
|
|
66663
67161
|
const options = { host: "127.0.0.1", port, path: "/healthz", agent: false, timeout: HEALTH_TIMEOUT_MS };
|
|
66664
|
-
const request7 = ca === void 0 ?
|
|
67162
|
+
const request7 = ca === void 0 ? import_node_http2.default.get(options, onResponse) : import_node_https.default.get({ ...options, ca: [ca] }, onResponse);
|
|
66665
67163
|
request7.on("timeout", () => {
|
|
66666
67164
|
request7.destroy();
|
|
66667
67165
|
});
|
|
@@ -66816,7 +67314,7 @@ async function reservedDial(target, ports) {
|
|
|
66816
67314
|
function requestServername(options, fallback) {
|
|
66817
67315
|
return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
|
|
66818
67316
|
}
|
|
66819
|
-
var ExemptHttpAgent = class extends
|
|
67317
|
+
var ExemptHttpAgent = class extends http3.Agent {
|
|
66820
67318
|
constructor(ports = DOOR_SOURCE_PORTS) {
|
|
66821
67319
|
super();
|
|
66822
67320
|
this.ports = ports;
|
|
@@ -67087,7 +67585,7 @@ function realConnectEffects(ports = DOOR_SOURCE_PORTS) {
|
|
|
67087
67585
|
};
|
|
67088
67586
|
},
|
|
67089
67587
|
createHttpSession: (handler, onUpgrade) => {
|
|
67090
|
-
const server =
|
|
67588
|
+
const server = http3.createServer(handler);
|
|
67091
67589
|
server.on("clientError", (_error, socket) => {
|
|
67092
67590
|
socket.destroy();
|
|
67093
67591
|
});
|
|
@@ -67157,7 +67655,7 @@ function realConnectEffects(ports = DOOR_SOURCE_PORTS) {
|
|
|
67157
67655
|
}
|
|
67158
67656
|
upstreamResponse.pipe(response);
|
|
67159
67657
|
};
|
|
67160
|
-
const upstream = target.tls ? https3.request(options, onUpstreamResponse) :
|
|
67658
|
+
const upstream = target.tls ? https3.request(options, onUpstreamResponse) : http3.request(options, onUpstreamResponse);
|
|
67161
67659
|
upstream.on("error", (error62) => {
|
|
67162
67660
|
if (response.headersSent) {
|
|
67163
67661
|
response.destroy(error62);
|
|
@@ -67282,7 +67780,21 @@ function cacheClause(cacheEnv, owner, block2) {
|
|
|
67282
67780
|
const state = describeCachedCredential({ port: cacheEnv.port, platform: cacheEnv.platform, owner, cache: block2.cache, nowMs: cacheEnv.now() });
|
|
67283
67781
|
return { text: `; ${formatCachedCredentialState(state)}`, unreadable: state.status === "unreadable" };
|
|
67284
67782
|
}
|
|
67285
|
-
function
|
|
67783
|
+
function signInProblem(signIn) {
|
|
67784
|
+
if (signIn.raw === void 0) {
|
|
67785
|
+
return "nobody is signed in: run `agent-shim codex login`.";
|
|
67786
|
+
}
|
|
67787
|
+
try {
|
|
67788
|
+
const grant = parseSiwcFile(signIn.raw, signIn.path).grant;
|
|
67789
|
+
if (grant === void 0) {
|
|
67790
|
+
return "nobody is signed in: run `agent-shim codex login`.";
|
|
67791
|
+
}
|
|
67792
|
+
return grant.scopes.includes(SIWC_PLAN_SCOPE) ? void 0 : "the login was not given permission to use your ChatGPT plan: run `agent-shim codex login` again and allow it.";
|
|
67793
|
+
} catch (error62) {
|
|
67794
|
+
return error62 instanceof Error ? error62.message : String(error62);
|
|
67795
|
+
}
|
|
67796
|
+
}
|
|
67797
|
+
function pushProvider(push, entry, cacheEnv, signIn) {
|
|
67286
67798
|
if (entry.raw === void 0) {
|
|
67287
67799
|
push("provider", "fail", `${entry.path} is missing.`, entry.name);
|
|
67288
67800
|
return;
|
|
@@ -67309,6 +67821,12 @@ function pushProvider(push, entry, cacheEnv) {
|
|
|
67309
67821
|
if (validated2.data.env?.ENABLE_TOOL_SEARCH === void 0) {
|
|
67310
67822
|
push("provider", "warn", `${entry.name} does not set ENABLE_TOOL_SEARCH: a session on this provider loads MCP tools upfront rather than deferring them, because its base URL is the front door, which Claude Code treats as a non-first-party host. Set ENABLE_TOOL_SEARCH in the provider's env block to restore deferred loading, when the upstream backend supports the tool_reference payloads it sends.`, entry.name);
|
|
67311
67823
|
}
|
|
67824
|
+
if (signIn !== void 0 && isCodexProvider(validated2.data) && validated2.data.codex?.login === "chatgpt-sign-in") {
|
|
67825
|
+
const problem = signInProblem(signIn);
|
|
67826
|
+
if (problem !== void 0) {
|
|
67827
|
+
push("provider", "warn", `${entry.name} uses the Sign in with ChatGPT login, but ${problem}`, entry.name);
|
|
67828
|
+
}
|
|
67829
|
+
}
|
|
67312
67830
|
}
|
|
67313
67831
|
function pushLegacyName(push, params) {
|
|
67314
67832
|
const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
|
|
@@ -67433,7 +67951,7 @@ function runDoctor(params) {
|
|
|
67433
67951
|
return poolName === void 0 ? validIdentityNames.has(selector) : poolName in pools;
|
|
67434
67952
|
};
|
|
67435
67953
|
for (const entry of params.providers) {
|
|
67436
|
-
pushProvider(push, entry, params.credentialCache);
|
|
67954
|
+
pushProvider(push, entry, params.credentialCache, params.chatgptSignIn);
|
|
67437
67955
|
}
|
|
67438
67956
|
if (params.platform !== "darwin" || params.run === void 0) {
|
|
67439
67957
|
push("keychain", "pass", "Skipped (not macOS).");
|
|
@@ -67675,6 +68193,7 @@ function collectDoctorReport(params) {
|
|
|
67675
68193
|
const report = runDoctor({
|
|
67676
68194
|
env: params.env,
|
|
67677
68195
|
credentialCache: realCredentialCacheEnv(paths),
|
|
68196
|
+
chatgptSignIn: { path: paths.chatgptSignInFile, raw: realFsPort.readFileUtf8(paths.chatgptSignInFile) },
|
|
67678
68197
|
installedClaudeVersions: realInstalledClaudeVersions(),
|
|
67679
68198
|
identities,
|
|
67680
68199
|
configProfiles,
|
|
@@ -68870,6 +69389,56 @@ var DoctorRunOutputSchema = external_exports.strictObject({
|
|
|
68870
69389
|
findings: external_exports.readonly(external_exports.array(DoctorFindingSchema))
|
|
68871
69390
|
});
|
|
68872
69391
|
|
|
69392
|
+
// node_modules/.pnpm/@orpc+contract@1.15.4/node_modules/@orpc/contract/dist/shared/contract.D_dZrO__.mjs
|
|
69393
|
+
var ValidationError = class extends Error {
|
|
69394
|
+
issues;
|
|
69395
|
+
data;
|
|
69396
|
+
constructor(options) {
|
|
69397
|
+
super(options.message, options);
|
|
69398
|
+
this.issues = options.issues;
|
|
69399
|
+
this.data = options.data;
|
|
69400
|
+
}
|
|
69401
|
+
};
|
|
69402
|
+
function mergeErrorMap(errorMap1, errorMap2) {
|
|
69403
|
+
return { ...errorMap1, ...errorMap2 };
|
|
69404
|
+
}
|
|
69405
|
+
async function validateORPCError(map3, error62) {
|
|
69406
|
+
const { code, status, message, data, cause, defined } = error62;
|
|
69407
|
+
const config2 = map3?.[error62.code];
|
|
69408
|
+
if (!config2 || fallbackORPCErrorStatus(error62.code, config2.status) !== error62.status) {
|
|
69409
|
+
return defined ? new ORPCError(code, { defined: false, status, message, data, cause }) : error62;
|
|
69410
|
+
}
|
|
69411
|
+
if (!config2.data) {
|
|
69412
|
+
return defined ? error62 : new ORPCError(code, { defined: true, status, message, data, cause });
|
|
69413
|
+
}
|
|
69414
|
+
const validated2 = await config2.data["~standard"].validate(error62.data);
|
|
69415
|
+
if (validated2.issues) {
|
|
69416
|
+
return defined ? new ORPCError(code, { defined: false, status, message, data, cause }) : error62;
|
|
69417
|
+
}
|
|
69418
|
+
return new ORPCError(code, { defined: true, status, message, data: validated2.value, cause });
|
|
69419
|
+
}
|
|
69420
|
+
var ContractProcedure = class {
|
|
69421
|
+
/**
|
|
69422
|
+
* This property holds the defined options for the contract procedure.
|
|
69423
|
+
*/
|
|
69424
|
+
"~orpc";
|
|
69425
|
+
constructor(def) {
|
|
69426
|
+
if (def.route?.successStatus && isORPCErrorStatus(def.route.successStatus)) {
|
|
69427
|
+
throw new Error("[ContractProcedure] Invalid successStatus.");
|
|
69428
|
+
}
|
|
69429
|
+
if (Object.values(def.errorMap).some((val) => val && val.status && !isORPCErrorStatus(val.status))) {
|
|
69430
|
+
throw new Error("[ContractProcedure] Invalid error status code.");
|
|
69431
|
+
}
|
|
69432
|
+
this["~orpc"] = def;
|
|
69433
|
+
}
|
|
69434
|
+
};
|
|
69435
|
+
function isContractProcedure(item) {
|
|
69436
|
+
if (item instanceof ContractProcedure) {
|
|
69437
|
+
return true;
|
|
69438
|
+
}
|
|
69439
|
+
return (typeof item === "object" || typeof item === "function") && item !== null && "~orpc" in item && typeof item["~orpc"] === "object" && item["~orpc"] !== null && "errorMap" in item["~orpc"] && "route" in item["~orpc"] && "meta" in item["~orpc"];
|
|
69440
|
+
}
|
|
69441
|
+
|
|
68873
69442
|
// node_modules/.pnpm/@orpc+standard-server-fetch@1.15.4/node_modules/@orpc/standard-server-fetch/dist/index.mjs
|
|
68874
69443
|
function toEventIterator(stream, options = {}) {
|
|
68875
69444
|
const eventStream = stream?.pipeThrough(new TextDecoderStream()).pipeThrough(new EventDecoderStream());
|
|
@@ -69581,93 +70150,6 @@ var StandardRPCLink = class extends StandardLink {
|
|
|
69581
70150
|
}
|
|
69582
70151
|
};
|
|
69583
70152
|
|
|
69584
|
-
// node_modules/.pnpm/@orpc+client@1.15.4/node_modules/@orpc/client/dist/adapters/fetch/index.mjs
|
|
69585
|
-
var CompositeLinkFetchPlugin = class extends CompositeStandardLinkPlugin {
|
|
69586
|
-
initRuntimeAdapter(options) {
|
|
69587
|
-
for (const plugin of this.plugins) {
|
|
69588
|
-
plugin.initRuntimeAdapter?.(options);
|
|
69589
|
-
}
|
|
69590
|
-
}
|
|
69591
|
-
};
|
|
69592
|
-
var LinkFetchClient = class {
|
|
69593
|
-
fetch;
|
|
69594
|
-
toFetchRequestOptions;
|
|
69595
|
-
adapterInterceptors;
|
|
69596
|
-
constructor(options) {
|
|
69597
|
-
const plugin = new CompositeLinkFetchPlugin(options.plugins);
|
|
69598
|
-
plugin.initRuntimeAdapter(options);
|
|
69599
|
-
this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
69600
|
-
this.toFetchRequestOptions = options;
|
|
69601
|
-
this.adapterInterceptors = toArray(options.adapterInterceptors);
|
|
69602
|
-
}
|
|
69603
|
-
async call(standardRequest, options, path44, input2) {
|
|
69604
|
-
const request7 = toFetchRequest(standardRequest, this.toFetchRequestOptions);
|
|
69605
|
-
const fetchResponse = await intercept(
|
|
69606
|
-
this.adapterInterceptors,
|
|
69607
|
-
{ ...options, request: request7, path: path44, input: input2, init: { redirect: "manual" } },
|
|
69608
|
-
({ request: request22, path: path210, input: input22, init, ...options2 }) => this.fetch(request22, init, options2, path210, input22)
|
|
69609
|
-
);
|
|
69610
|
-
const lazyResponse = toStandardLazyResponse(fetchResponse, { signal: request7.signal });
|
|
69611
|
-
return lazyResponse;
|
|
69612
|
-
}
|
|
69613
|
-
};
|
|
69614
|
-
var RPCLink = class extends StandardRPCLink {
|
|
69615
|
-
constructor(options) {
|
|
69616
|
-
const linkClient = new LinkFetchClient(options);
|
|
69617
|
-
super(linkClient, options);
|
|
69618
|
-
}
|
|
69619
|
-
};
|
|
69620
|
-
|
|
69621
|
-
// node_modules/.pnpm/@orpc+contract@1.15.4/node_modules/@orpc/contract/dist/shared/contract.D_dZrO__.mjs
|
|
69622
|
-
var ValidationError = class extends Error {
|
|
69623
|
-
issues;
|
|
69624
|
-
data;
|
|
69625
|
-
constructor(options) {
|
|
69626
|
-
super(options.message, options);
|
|
69627
|
-
this.issues = options.issues;
|
|
69628
|
-
this.data = options.data;
|
|
69629
|
-
}
|
|
69630
|
-
};
|
|
69631
|
-
function mergeErrorMap(errorMap1, errorMap2) {
|
|
69632
|
-
return { ...errorMap1, ...errorMap2 };
|
|
69633
|
-
}
|
|
69634
|
-
async function validateORPCError(map3, error62) {
|
|
69635
|
-
const { code, status, message, data, cause, defined } = error62;
|
|
69636
|
-
const config2 = map3?.[error62.code];
|
|
69637
|
-
if (!config2 || fallbackORPCErrorStatus(error62.code, config2.status) !== error62.status) {
|
|
69638
|
-
return defined ? new ORPCError(code, { defined: false, status, message, data, cause }) : error62;
|
|
69639
|
-
}
|
|
69640
|
-
if (!config2.data) {
|
|
69641
|
-
return defined ? error62 : new ORPCError(code, { defined: true, status, message, data, cause });
|
|
69642
|
-
}
|
|
69643
|
-
const validated2 = await config2.data["~standard"].validate(error62.data);
|
|
69644
|
-
if (validated2.issues) {
|
|
69645
|
-
return defined ? new ORPCError(code, { defined: false, status, message, data, cause }) : error62;
|
|
69646
|
-
}
|
|
69647
|
-
return new ORPCError(code, { defined: true, status, message, data: validated2.value, cause });
|
|
69648
|
-
}
|
|
69649
|
-
var ContractProcedure = class {
|
|
69650
|
-
/**
|
|
69651
|
-
* This property holds the defined options for the contract procedure.
|
|
69652
|
-
*/
|
|
69653
|
-
"~orpc";
|
|
69654
|
-
constructor(def) {
|
|
69655
|
-
if (def.route?.successStatus && isORPCErrorStatus(def.route.successStatus)) {
|
|
69656
|
-
throw new Error("[ContractProcedure] Invalid successStatus.");
|
|
69657
|
-
}
|
|
69658
|
-
if (Object.values(def.errorMap).some((val) => val && val.status && !isORPCErrorStatus(val.status))) {
|
|
69659
|
-
throw new Error("[ContractProcedure] Invalid error status code.");
|
|
69660
|
-
}
|
|
69661
|
-
this["~orpc"] = def;
|
|
69662
|
-
}
|
|
69663
|
-
};
|
|
69664
|
-
function isContractProcedure(item) {
|
|
69665
|
-
if (item instanceof ContractProcedure) {
|
|
69666
|
-
return true;
|
|
69667
|
-
}
|
|
69668
|
-
return (typeof item === "object" || typeof item === "function") && item !== null && "~orpc" in item && typeof item["~orpc"] === "object" && item["~orpc"] !== null && "errorMap" in item["~orpc"] && "route" in item["~orpc"] && "meta" in item["~orpc"];
|
|
69669
|
-
}
|
|
69670
|
-
|
|
69671
70153
|
// node_modules/.pnpm/@orpc+contract@1.15.4/node_modules/@orpc/contract/dist/index.mjs
|
|
69672
70154
|
function mergeMeta(meta1, meta22) {
|
|
69673
70155
|
return { ...meta1, ...meta22 };
|
|
@@ -70612,6 +71094,43 @@ var os7 = new Builder({
|
|
|
70612
71094
|
dedupeLeadingMiddlewares: true
|
|
70613
71095
|
});
|
|
70614
71096
|
|
|
71097
|
+
// node_modules/.pnpm/@orpc+client@1.15.4/node_modules/@orpc/client/dist/adapters/fetch/index.mjs
|
|
71098
|
+
var CompositeLinkFetchPlugin = class extends CompositeStandardLinkPlugin {
|
|
71099
|
+
initRuntimeAdapter(options) {
|
|
71100
|
+
for (const plugin of this.plugins) {
|
|
71101
|
+
plugin.initRuntimeAdapter?.(options);
|
|
71102
|
+
}
|
|
71103
|
+
}
|
|
71104
|
+
};
|
|
71105
|
+
var LinkFetchClient = class {
|
|
71106
|
+
fetch;
|
|
71107
|
+
toFetchRequestOptions;
|
|
71108
|
+
adapterInterceptors;
|
|
71109
|
+
constructor(options) {
|
|
71110
|
+
const plugin = new CompositeLinkFetchPlugin(options.plugins);
|
|
71111
|
+
plugin.initRuntimeAdapter(options);
|
|
71112
|
+
this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
71113
|
+
this.toFetchRequestOptions = options;
|
|
71114
|
+
this.adapterInterceptors = toArray(options.adapterInterceptors);
|
|
71115
|
+
}
|
|
71116
|
+
async call(standardRequest, options, path44, input2) {
|
|
71117
|
+
const request7 = toFetchRequest(standardRequest, this.toFetchRequestOptions);
|
|
71118
|
+
const fetchResponse = await intercept(
|
|
71119
|
+
this.adapterInterceptors,
|
|
71120
|
+
{ ...options, request: request7, path: path44, input: input2, init: { redirect: "manual" } },
|
|
71121
|
+
({ request: request22, path: path210, input: input22, init, ...options2 }) => this.fetch(request22, init, options2, path210, input22)
|
|
71122
|
+
);
|
|
71123
|
+
const lazyResponse = toStandardLazyResponse(fetchResponse, { signal: request7.signal });
|
|
71124
|
+
return lazyResponse;
|
|
71125
|
+
}
|
|
71126
|
+
};
|
|
71127
|
+
var RPCLink = class extends StandardRPCLink {
|
|
71128
|
+
constructor(options) {
|
|
71129
|
+
const linkClient = new LinkFetchClient(options);
|
|
71130
|
+
super(linkClient, options);
|
|
71131
|
+
}
|
|
71132
|
+
};
|
|
71133
|
+
|
|
70615
71134
|
// node_modules/.pnpm/@orpc+standard-server-node@1.15.4/node_modules/@orpc/standard-server-node/dist/index.mjs
|
|
70616
71135
|
var import_node_buffer = require("node:buffer");
|
|
70617
71136
|
var import_node_stream = require("node:stream");
|
|
@@ -71335,6 +71854,62 @@ function frontDoorRcApiClient(port, ca, token) {
|
|
|
71335
71854
|
return createORPCClient(frontDoorApiLink(port, ca, token));
|
|
71336
71855
|
}
|
|
71337
71856
|
|
|
71857
|
+
// src/frontdoor/eventSchemas.ts
|
|
71858
|
+
var DOOR_EVENT_SOURCE_RC = "rc";
|
|
71859
|
+
var LAUNCH_EVENT_SOURCE = "launch";
|
|
71860
|
+
var DoorEventSchema = external_exports.strictObject({
|
|
71861
|
+
source: external_exports.string().min(1),
|
|
71862
|
+
/** A positive integer because the backbone's counters start at one and only ever increase. */
|
|
71863
|
+
sequence: external_exports.number().int().positive(),
|
|
71864
|
+
payload: external_exports.unknown()
|
|
71865
|
+
});
|
|
71866
|
+
var DoorEventSourceQuerySchema = external_exports.strictObject({
|
|
71867
|
+
sources: external_exports.array(external_exports.string().min(1)).min(1).optional()
|
|
71868
|
+
});
|
|
71869
|
+
var LaunchLifecycleEventSchema = external_exports.strictObject({
|
|
71870
|
+
kind: external_exports.enum(["registered", "pruned", "ended"]),
|
|
71871
|
+
pid: external_exports.number().int().positive(),
|
|
71872
|
+
startedAt: external_exports.number(),
|
|
71873
|
+
observedAt: external_exports.number()
|
|
71874
|
+
});
|
|
71875
|
+
|
|
71876
|
+
// src/frontdoor/eventsApi.ts
|
|
71877
|
+
function createEventsApiRouter(deps) {
|
|
71878
|
+
const authed = doorApiAuth(deps.expectedToken);
|
|
71879
|
+
return {
|
|
71880
|
+
events: {
|
|
71881
|
+
subscribe: authed.input(DoorEventSourceQuerySchema).output(eventIterator(DoorEventSchema)).handler(async function* ({ input: input2, signal }) {
|
|
71882
|
+
if (input2.sources !== void 0) {
|
|
71883
|
+
const live = deps.events.sources();
|
|
71884
|
+
const unknown2 = input2.sources.filter((source) => !live.includes(source));
|
|
71885
|
+
if (unknown2.length > 0) {
|
|
71886
|
+
throw new ORPCError("NOT_FOUND", { message: `the door publishes no event source named ${unknown2.map((source) => `"${source}"`).join(", ")}; the live sources are ${live.map((source) => `"${source}"`).join(", ")}` });
|
|
71887
|
+
}
|
|
71888
|
+
}
|
|
71889
|
+
const stream = deps.events.stream(input2.sources);
|
|
71890
|
+
const ended = new Promise((resolve) => {
|
|
71891
|
+
signal?.addEventListener("abort", () => {
|
|
71892
|
+
resolve();
|
|
71893
|
+
}, { once: true });
|
|
71894
|
+
});
|
|
71895
|
+
try {
|
|
71896
|
+
for (; ; ) {
|
|
71897
|
+
signal?.throwIfAborted();
|
|
71898
|
+
const next = await Promise.race([stream.next(), ended.then(() => ({ value: void 0, done: true }))]);
|
|
71899
|
+
if (next.done === true) {
|
|
71900
|
+
signal?.throwIfAborted();
|
|
71901
|
+
return;
|
|
71902
|
+
}
|
|
71903
|
+
yield withEventMeta(next.value, { id: String(next.value.sequence) });
|
|
71904
|
+
}
|
|
71905
|
+
} finally {
|
|
71906
|
+
stream.close();
|
|
71907
|
+
}
|
|
71908
|
+
})
|
|
71909
|
+
}
|
|
71910
|
+
};
|
|
71911
|
+
}
|
|
71912
|
+
|
|
71338
71913
|
// src/frontdoor/controlApi.ts
|
|
71339
71914
|
function createControlApiRouter(deps) {
|
|
71340
71915
|
const authed = doorApiAuth(deps.expectedToken);
|
|
@@ -71373,14 +71948,156 @@ function createControlApiRouter(deps) {
|
|
|
71373
71948
|
};
|
|
71374
71949
|
}
|
|
71375
71950
|
function createDoorApiRouter(deps) {
|
|
71376
|
-
return { ...createRcApiRouter(deps), ...createControlApiRouter(deps) };
|
|
71951
|
+
return { ...createRcApiRouter(deps), ...createControlApiRouter(deps), ...createEventsApiRouter(deps) };
|
|
71377
71952
|
}
|
|
71378
71953
|
function createDoorApiNodeHandler(deps) {
|
|
71379
71954
|
return doorApiNodeHandlerOf(createDoorApiRouter(deps));
|
|
71380
71955
|
}
|
|
71381
71956
|
|
|
71957
|
+
// src/frontdoor/eventHub.ts
|
|
71958
|
+
var DOOR_EVENT_BUFFER_EVENTS = 100;
|
|
71959
|
+
function createDoorEventHub() {
|
|
71960
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
71961
|
+
const registered = /* @__PURE__ */ new Set();
|
|
71962
|
+
const every = /* @__PURE__ */ new Set();
|
|
71963
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
71964
|
+
const deliver = (event) => {
|
|
71965
|
+
for (const listener of every) {
|
|
71966
|
+
listener(event);
|
|
71967
|
+
}
|
|
71968
|
+
for (const listener of bySource.get(event.source) ?? []) {
|
|
71969
|
+
listener(event);
|
|
71970
|
+
}
|
|
71971
|
+
};
|
|
71972
|
+
const publish = (source, payload) => {
|
|
71973
|
+
const sequence2 = (sequences.get(source) ?? 0) + 1;
|
|
71974
|
+
sequences.set(source, sequence2);
|
|
71975
|
+
deliver({ source, sequence: sequence2, payload });
|
|
71976
|
+
};
|
|
71977
|
+
const addListener = (sources, listener) => {
|
|
71978
|
+
if (sources === void 0) {
|
|
71979
|
+
every.add(listener);
|
|
71980
|
+
return () => {
|
|
71981
|
+
every.delete(listener);
|
|
71982
|
+
};
|
|
71983
|
+
}
|
|
71984
|
+
const listenersFor = (source) => {
|
|
71985
|
+
const listeners = bySource.get(source) ?? /* @__PURE__ */ new Set();
|
|
71986
|
+
bySource.set(source, listeners);
|
|
71987
|
+
return listeners;
|
|
71988
|
+
};
|
|
71989
|
+
const detachers = sources.map((source) => {
|
|
71990
|
+
const listeners = listenersFor(source);
|
|
71991
|
+
listeners.add(listener);
|
|
71992
|
+
return () => {
|
|
71993
|
+
listeners.delete(listener);
|
|
71994
|
+
if (listeners.size === 0) {
|
|
71995
|
+
bySource.delete(source);
|
|
71996
|
+
}
|
|
71997
|
+
};
|
|
71998
|
+
});
|
|
71999
|
+
return () => {
|
|
72000
|
+
for (const detach of detachers) {
|
|
72001
|
+
detach();
|
|
72002
|
+
}
|
|
72003
|
+
};
|
|
72004
|
+
};
|
|
72005
|
+
return {
|
|
72006
|
+
publisher: (source) => {
|
|
72007
|
+
registered.add(source);
|
|
72008
|
+
return {
|
|
72009
|
+
source,
|
|
72010
|
+
publish: (payload) => {
|
|
72011
|
+
publish(source, payload);
|
|
72012
|
+
}
|
|
72013
|
+
};
|
|
72014
|
+
},
|
|
72015
|
+
subscribe: addListener,
|
|
72016
|
+
stream: (sources) => {
|
|
72017
|
+
const queue = [];
|
|
72018
|
+
let wake;
|
|
72019
|
+
let closed = false;
|
|
72020
|
+
const detach = addListener(sources, (event) => {
|
|
72021
|
+
if (queue.length >= DOOR_EVENT_BUFFER_EVENTS) {
|
|
72022
|
+
queue.shift();
|
|
72023
|
+
}
|
|
72024
|
+
queue.push(event);
|
|
72025
|
+
wake?.();
|
|
72026
|
+
});
|
|
72027
|
+
return {
|
|
72028
|
+
next: async () => {
|
|
72029
|
+
for (; ; ) {
|
|
72030
|
+
const event = queue.shift();
|
|
72031
|
+
if (event !== void 0) {
|
|
72032
|
+
return { value: event, done: false };
|
|
72033
|
+
}
|
|
72034
|
+
if (closed) {
|
|
72035
|
+
return { value: void 0, done: true };
|
|
72036
|
+
}
|
|
72037
|
+
await new Promise((resolve) => {
|
|
72038
|
+
wake = resolve;
|
|
72039
|
+
});
|
|
72040
|
+
}
|
|
72041
|
+
},
|
|
72042
|
+
close: () => {
|
|
72043
|
+
closed = true;
|
|
72044
|
+
detach();
|
|
72045
|
+
wake?.();
|
|
72046
|
+
}
|
|
72047
|
+
};
|
|
72048
|
+
},
|
|
72049
|
+
sources: () => [...registered].sort()
|
|
72050
|
+
};
|
|
72051
|
+
}
|
|
72052
|
+
function rcFanoutOnDoorHub(fanout, hub) {
|
|
72053
|
+
const publisher = hub.publisher(DOOR_EVENT_SOURCE_RC);
|
|
72054
|
+
return {
|
|
72055
|
+
publish: (event) => {
|
|
72056
|
+
fanout.publish(event);
|
|
72057
|
+
publisher.publish(event);
|
|
72058
|
+
},
|
|
72059
|
+
subscribe: (session, listener) => fanout.subscribe(session, listener)
|
|
72060
|
+
};
|
|
72061
|
+
}
|
|
72062
|
+
|
|
72063
|
+
// src/frontdoor/launchEvents.ts
|
|
72064
|
+
function createLaunchEventPublisher(hub, now) {
|
|
72065
|
+
const publisher = hub.publisher(LAUNCH_EVENT_SOURCE);
|
|
72066
|
+
let known;
|
|
72067
|
+
return {
|
|
72068
|
+
observe: (sessions, pruned) => {
|
|
72069
|
+
const previous = known;
|
|
72070
|
+
const listed = new Map(sessions.map((session) => [session.pid, session]));
|
|
72071
|
+
const prunedSet = new Set(pruned);
|
|
72072
|
+
known = new Map([...listed].filter(([pid]) => !prunedSet.has(pid)));
|
|
72073
|
+
if (previous === void 0) {
|
|
72074
|
+
return;
|
|
72075
|
+
}
|
|
72076
|
+
const emit = (kind, pid, startedAt) => {
|
|
72077
|
+
publisher.publish({ kind, pid, startedAt, observedAt: now() });
|
|
72078
|
+
};
|
|
72079
|
+
for (const pid of pruned) {
|
|
72080
|
+
const session = listed.get(pid);
|
|
72081
|
+
if (session !== void 0) {
|
|
72082
|
+
emit("pruned", pid, session.startedAt);
|
|
72083
|
+
}
|
|
72084
|
+
}
|
|
72085
|
+
for (const [pid, session] of previous) {
|
|
72086
|
+
if (!listed.has(pid) && !prunedSet.has(pid)) {
|
|
72087
|
+
emit("ended", pid, session.startedAt);
|
|
72088
|
+
}
|
|
72089
|
+
}
|
|
72090
|
+
for (const [pid, session] of listed) {
|
|
72091
|
+
if (!previous.has(pid) && !prunedSet.has(pid)) {
|
|
72092
|
+
emit("registered", pid, session.startedAt);
|
|
72093
|
+
}
|
|
72094
|
+
}
|
|
72095
|
+
}
|
|
72096
|
+
};
|
|
72097
|
+
}
|
|
72098
|
+
|
|
71382
72099
|
// src/frontdoor/headroomHop.ts
|
|
71383
|
-
var
|
|
72100
|
+
var http4 = __toESM(require("node:http"), 1);
|
|
71384
72101
|
var HTTP_BAD_GATEWAY2 = HTTP_STATUS.badGateway;
|
|
71385
72102
|
function responseHeaders(headers) {
|
|
71386
72103
|
const result = {};
|
|
@@ -71434,7 +72151,7 @@ async function answerBadGateway(response, message) {
|
|
|
71434
72151
|
await response.write(JSON.stringify({ type: "error", error: { type: "api_error", message } }));
|
|
71435
72152
|
response.end();
|
|
71436
72153
|
}
|
|
71437
|
-
var HOP_AGENT = new
|
|
72154
|
+
var HOP_AGENT = new http4.Agent({ keepAlive: false });
|
|
71438
72155
|
async function forwardThroughHeadroom(request7, response, target) {
|
|
71439
72156
|
const { socketPath, headers } = target;
|
|
71440
72157
|
await new Promise((resolve) => {
|
|
@@ -71462,7 +72179,7 @@ async function forwardThroughHeadroom(request7, response, target) {
|
|
|
71462
72179
|
};
|
|
71463
72180
|
void stream();
|
|
71464
72181
|
};
|
|
71465
|
-
const hop =
|
|
72182
|
+
const hop = http4.request({ socketPath, method: request7.method, path: request7.url, headers, agent: HOP_AGENT }, onUpstreamResponse);
|
|
71466
72183
|
hop.on("error", (error62) => {
|
|
71467
72184
|
const phase = response.headersSent ? "mid-stream" : "before the response started";
|
|
71468
72185
|
const code = "code" in error62 && typeof error62.code === "string" ? ` ${error62.code}` : "";
|
|
@@ -71651,7 +72368,7 @@ async function serveRouted(request7, deps) {
|
|
|
71651
72368
|
}
|
|
71652
72369
|
|
|
71653
72370
|
// src/codex/translate.ts
|
|
71654
|
-
var
|
|
72371
|
+
var import_node_crypto13 = require("node:crypto");
|
|
71655
72372
|
|
|
71656
72373
|
// src/codex/anthropic.ts
|
|
71657
72374
|
var TextBlockSchema = external_exports.looseObject({ type: external_exports.literal("text"), text: external_exports.string() });
|
|
@@ -71730,7 +72447,8 @@ function resolveCodexConfig(config2) {
|
|
|
71730
72447
|
sonnet: overrides?.sonnet ?? CODEX_DEFAULT_TIER_MODELS.sonnet,
|
|
71731
72448
|
haiku: overrides?.haiku ?? CODEX_DEFAULT_TIER_MODELS.haiku
|
|
71732
72449
|
},
|
|
71733
|
-
effort: config2?.effort ?? CODEX_DEFAULT_EFFORT
|
|
72450
|
+
effort: config2?.effort ?? CODEX_DEFAULT_EFFORT,
|
|
72451
|
+
login: config2?.login ?? CODEX_DEFAULT_LOGIN
|
|
71734
72452
|
};
|
|
71735
72453
|
}
|
|
71736
72454
|
function mapModel(requested, config2) {
|
|
@@ -71763,7 +72481,7 @@ function shortToolName(name, names) {
|
|
|
71763
72481
|
if (name.length <= CODEX_TOOL_NAME_LIMIT) {
|
|
71764
72482
|
return name;
|
|
71765
72483
|
}
|
|
71766
|
-
const hash2 = (0,
|
|
72484
|
+
const hash2 = (0, import_node_crypto13.createHash)("sha256").update(name).digest("hex").slice(0, TOOL_NAME_HASH_CHARS);
|
|
71767
72485
|
const shortened = `${name.slice(0, CODEX_TOOL_NAME_LIMIT - TOOL_NAME_HASH_CHARS - 1)}_${hash2}`;
|
|
71768
72486
|
names.set(shortened, name);
|
|
71769
72487
|
return shortened;
|
|
@@ -72039,17 +72757,17 @@ function unifiedQuotaHeaders(upstream, rejected, quotaError) {
|
|
|
72039
72757
|
}
|
|
72040
72758
|
return headers;
|
|
72041
72759
|
}
|
|
72042
|
-
var
|
|
72760
|
+
var MS_PER_SECOND6 = 1e3;
|
|
72043
72761
|
function buildUsageSnapshot(upstream, quotaError, nowMs) {
|
|
72044
72762
|
const used7 = upstream.get("x-codex-primary-used-percent") ?? (quotaError === void 0 ? null : EXHAUSTED_PERCENT);
|
|
72045
72763
|
const reset7 = upstream.get("x-codex-primary-reset-at") ?? (quotaError?.resets_at === void 0 ? null : String(quotaError.resets_at));
|
|
72046
|
-
const sevenDay = used7 !== null && reset7 !== null ? { used_percentage: Number(used7), resets_at: new Date(Number(reset7) *
|
|
72764
|
+
const sevenDay = used7 !== null && reset7 !== null ? { used_percentage: Number(used7), resets_at: new Date(Number(reset7) * MS_PER_SECOND6).toISOString() } : void 0;
|
|
72047
72765
|
let fiveHour;
|
|
72048
72766
|
if (Number(upstream.get("x-codex-secondary-window-minutes")) > 0) {
|
|
72049
72767
|
const used5 = upstream.get("x-codex-secondary-used-percent");
|
|
72050
72768
|
const reset5 = upstream.get("x-codex-secondary-reset-at");
|
|
72051
72769
|
if (used5 !== null && reset5 !== null) {
|
|
72052
|
-
fiveHour = { used_percentage: Number(used5), resets_at: new Date(Number(reset5) *
|
|
72770
|
+
fiveHour = { used_percentage: Number(used5), resets_at: new Date(Number(reset5) * MS_PER_SECOND6).toISOString() };
|
|
72053
72771
|
}
|
|
72054
72772
|
}
|
|
72055
72773
|
if (sevenDay === void 0 && fiveHour === void 0) {
|
|
@@ -72266,12 +72984,13 @@ function createCodexRoute(ports) {
|
|
|
72266
72984
|
}
|
|
72267
72985
|
const body = parsed.data;
|
|
72268
72986
|
const requestedModel = body.model ?? "";
|
|
72987
|
+
const upstreamPorts = ports.upstreams[config2.login];
|
|
72269
72988
|
const { request: upstreamRequest, toolNames } = translateRequest(body, config2);
|
|
72270
72989
|
const started = ports.now();
|
|
72271
72990
|
const elapsed = () => `${String(ports.now() - started)}ms`;
|
|
72272
72991
|
let upstream;
|
|
72273
72992
|
try {
|
|
72274
|
-
upstream = await callCodex(
|
|
72993
|
+
upstream = await callCodex(upstreamPorts, upstreamRequest, sessionIdFor(body.metadata?.user_id, upstreamPorts.randomId), request7.signal);
|
|
72275
72994
|
} catch (error62) {
|
|
72276
72995
|
if (request7.signal.aborted) {
|
|
72277
72996
|
return errorResponse(HTTP_STATUS.clientClosedRequest, "client disconnected");
|
|
@@ -72304,7 +73023,7 @@ function createCodexRoute(ports) {
|
|
|
72304
73023
|
});
|
|
72305
73024
|
}
|
|
72306
73025
|
snapshot(void 0);
|
|
72307
|
-
const relay = createRelay({ requestedModel, toolNames, fallbackId: () => `msg_${
|
|
73026
|
+
const relay = createRelay({ requestedModel, toolNames, fallbackId: () => `msg_${upstreamPorts.randomId()}` });
|
|
72308
73027
|
const upstreamBody = upstream.body;
|
|
72309
73028
|
const quota = { ...quotaHeaders(upstream.headers), ...unifiedQuotaHeaders(upstream.headers, false, void 0) };
|
|
72310
73029
|
const logCompleted = (message, usage) => {
|
|
@@ -72469,7 +73188,7 @@ function createCodexRouteMount(ports, upstreamBase, provider) {
|
|
|
72469
73188
|
}
|
|
72470
73189
|
|
|
72471
73190
|
// src/frontdoor/passthrough.ts
|
|
72472
|
-
var
|
|
73191
|
+
var http5 = __toESM(require("node:http"), 1);
|
|
72473
73192
|
var https4 = __toESM(require("node:https"), 1);
|
|
72474
73193
|
function responseHeaders2(headers) {
|
|
72475
73194
|
const result = {};
|
|
@@ -72523,7 +73242,7 @@ function createPassthroughRoute(name, target) {
|
|
|
72523
73242
|
};
|
|
72524
73243
|
void stream();
|
|
72525
73244
|
};
|
|
72526
|
-
const forward = tls2 ? https4.request(options, onUpstreamResponse) :
|
|
73245
|
+
const forward = tls2 ? https4.request(options, onUpstreamResponse) : http5.request(options, onUpstreamResponse);
|
|
72527
73246
|
forward.on("error", (error62) => {
|
|
72528
73247
|
if (!response.headersSent) {
|
|
72529
73248
|
response.start(HTTP_STATUS.badGateway, { "Content-Type": "application/json" });
|
|
@@ -72701,7 +73420,7 @@ var RC_SESSION_ID_PREFIX2 = "cse_";
|
|
|
72701
73420
|
var RC_SELF_HOST_API_BASE_URL = "https://api.anthropic.com";
|
|
72702
73421
|
var RC_SELF_HOST_OAUTH_HOST = "platform.claude.com";
|
|
72703
73422
|
var HTTP_CONFLICT = 409;
|
|
72704
|
-
var
|
|
73423
|
+
var MS_PER_SECOND7 = 1e3;
|
|
72705
73424
|
var HTTP_SERVICE_UNAVAILABLE = 503;
|
|
72706
73425
|
var RC_SELF_HOST_WORKER_JWT_TTL_SECONDS = 46800;
|
|
72707
73426
|
var RC_SELF_HOST_OAUTH_TOKEN_TTL_SECONDS = 3600;
|
|
@@ -72776,7 +73495,7 @@ function parseJsonObject2(body) {
|
|
|
72776
73495
|
function mintWorkerJwt(randomToken, issuedAt) {
|
|
72777
73496
|
const encode3 = (value2) => Buffer.from(JSON.stringify(value2), "utf8").toString("base64url");
|
|
72778
73497
|
const header = encode3({ alg: "HS256", typ: "JWT" });
|
|
72779
|
-
const payload = encode3({ exp: Math.floor((issuedAt + RC_SELF_HOST_WORKER_JWT_TTL_SECONDS *
|
|
73498
|
+
const payload = encode3({ exp: Math.floor((issuedAt + RC_SELF_HOST_WORKER_JWT_TTL_SECONDS * MS_PER_SECOND7) / MS_PER_SECOND7), iat: Math.floor(issuedAt / MS_PER_SECOND7) });
|
|
72780
73499
|
return `${header}.${payload}.${Buffer.from(randomToken(), "utf8").toString("base64url")}`;
|
|
72781
73500
|
}
|
|
72782
73501
|
function growthBookFeatures() {
|
|
@@ -73227,7 +73946,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
73227
73946
|
}
|
|
73228
73947
|
if (method === "POST" && pathname.startsWith("/api/eval/")) {
|
|
73229
73948
|
await readBody3(request7, CONTROL_BODY_CAP_BYTES);
|
|
73230
|
-
answerServerJson(response, HTTP_STATUS.ok, { features: growthBookFeatures(), dateUpdated: Math.floor(deps.now() /
|
|
73949
|
+
answerServerJson(response, HTTP_STATUS.ok, { features: growthBookFeatures(), dateUpdated: Math.floor(deps.now() / MS_PER_SECOND7) });
|
|
73231
73950
|
return true;
|
|
73232
73951
|
}
|
|
73233
73952
|
if (method === "GET" && pathname === "/api/oauth/profile") {
|
|
@@ -73715,7 +74434,7 @@ var ProviderQuotaError = class extends Error {
|
|
|
73715
74434
|
this.name = "ProviderQuotaError";
|
|
73716
74435
|
}
|
|
73717
74436
|
};
|
|
73718
|
-
var
|
|
74437
|
+
var MS_PER_SECOND8 = 1e3;
|
|
73719
74438
|
var SECONDS_PER_HOUR = 3600;
|
|
73720
74439
|
var HOURS_PER_DAY3 = 24;
|
|
73721
74440
|
var DAYS_PER_MONTH = 30;
|
|
@@ -73727,8 +74446,8 @@ var ZAI_QUOTA_URL = `https://${ZAI_HOST}/api/monitor/usage/quota/limit`;
|
|
|
73727
74446
|
var ZAI_UNIT_HOURS = 3;
|
|
73728
74447
|
var ZAI_UNIT_MONTHS = 5;
|
|
73729
74448
|
var ZAI_UNIT_MS = /* @__PURE__ */ new Map([
|
|
73730
|
-
[ZAI_UNIT_HOURS, SECONDS_PER_HOUR *
|
|
73731
|
-
[ZAI_UNIT_MONTHS, DAYS_PER_MONTH * HOURS_PER_DAY3 * SECONDS_PER_HOUR *
|
|
74449
|
+
[ZAI_UNIT_HOURS, SECONDS_PER_HOUR * MS_PER_SECOND8],
|
|
74450
|
+
[ZAI_UNIT_MONTHS, DAYS_PER_MONTH * HOURS_PER_DAY3 * SECONDS_PER_HOUR * MS_PER_SECOND8]
|
|
73732
74451
|
]);
|
|
73733
74452
|
var ZAI_MEASURES = { TOKENS_LIMIT: "tokens", TIME_LIMIT: "tool-calls" };
|
|
73734
74453
|
var ZaiLimitSchema = external_exports.object({
|
|
@@ -73761,8 +74480,8 @@ function zaiWindow(limit) {
|
|
|
73761
74480
|
var zaiQuotaAdapter = {
|
|
73762
74481
|
source: ZAI_SOURCE,
|
|
73763
74482
|
matches: (baseUrl) => URL.canParse(baseUrl) && new URL(baseUrl).hostname === ZAI_HOST,
|
|
73764
|
-
fetch: async (apiKey,
|
|
73765
|
-
const response = await
|
|
74483
|
+
fetch: async (apiKey, http7, signal, nowMs) => {
|
|
74484
|
+
const response = await http7(ZAI_QUOTA_URL, { authorization: apiKey, accept: "application/json" }, signal);
|
|
73766
74485
|
if (response.status !== HTTP_OK) {
|
|
73767
74486
|
throw new ProviderQuotaError(ZAI_SOURCE, `answered HTTP ${String(response.status)}`);
|
|
73768
74487
|
}
|
|
@@ -73792,7 +74511,7 @@ var OPENROUTER_HOST = "openrouter.ai";
|
|
|
73792
74511
|
var OPENROUTER_KEY_URL = `https://${OPENROUTER_HOST}/api/v1/key`;
|
|
73793
74512
|
var OPENROUTER_CREDITS_URL = `https://${OPENROUTER_HOST}/api/v1/credits`;
|
|
73794
74513
|
var HTTP_FORBIDDEN = 403;
|
|
73795
|
-
var MS_PER_DAY2 = HOURS_PER_DAY3 * SECONDS_PER_HOUR *
|
|
74514
|
+
var MS_PER_DAY2 = HOURS_PER_DAY3 * SECONDS_PER_HOUR * MS_PER_SECOND8;
|
|
73796
74515
|
var OpenRouterKeySchema = external_exports.object({
|
|
73797
74516
|
data: external_exports.object({
|
|
73798
74517
|
limit: external_exports.number().nonnegative().nullable(),
|
|
@@ -73803,8 +74522,8 @@ var OpenRouterKeySchema = external_exports.object({
|
|
|
73803
74522
|
})
|
|
73804
74523
|
});
|
|
73805
74524
|
var OpenRouterCreditsSchema = external_exports.object({ data: external_exports.object({ total_credits: external_exports.number().nonnegative(), total_usage: external_exports.number().nonnegative() }) });
|
|
73806
|
-
async function openRouterGet(url2, schema, apiKey,
|
|
73807
|
-
const response = await
|
|
74525
|
+
async function openRouterGet(url2, schema, apiKey, http7, signal) {
|
|
74526
|
+
const response = await http7(url2, { authorization: `Bearer ${apiKey}`, accept: "application/json" }, signal);
|
|
73808
74527
|
if (response.status === HTTP_FORBIDDEN) {
|
|
73809
74528
|
return "forbidden";
|
|
73810
74529
|
}
|
|
@@ -73829,12 +74548,12 @@ function nextUtcMidnight(nowMs) {
|
|
|
73829
74548
|
var openRouterQuotaAdapter = {
|
|
73830
74549
|
source: OPENROUTER_SOURCE,
|
|
73831
74550
|
matches: (baseUrl) => URL.canParse(baseUrl) && new URL(baseUrl).hostname === OPENROUTER_HOST,
|
|
73832
|
-
fetch: async (apiKey,
|
|
73833
|
-
const key = await openRouterGet(OPENROUTER_KEY_URL, OpenRouterKeySchema, apiKey,
|
|
74551
|
+
fetch: async (apiKey, http7, signal, nowMs) => {
|
|
74552
|
+
const key = await openRouterGet(OPENROUTER_KEY_URL, OpenRouterKeySchema, apiKey, http7, signal);
|
|
73834
74553
|
if (key === "forbidden") {
|
|
73835
74554
|
throw new ProviderQuotaError(OPENROUTER_SOURCE, "/api/v1/key refused the key (HTTP 403)");
|
|
73836
74555
|
}
|
|
73837
|
-
const credits = await openRouterGet(OPENROUTER_CREDITS_URL, OpenRouterCreditsSchema, apiKey,
|
|
74556
|
+
const credits = await openRouterGet(OPENROUTER_CREDITS_URL, OpenRouterCreditsSchema, apiKey, http7, signal);
|
|
73838
74557
|
const { limit, limit_remaining: limitRemaining, limit_reset: limitReset, free_model_daily_requests: free, is_free_tier: isFreeTier } = key.data;
|
|
73839
74558
|
const windows = [];
|
|
73840
74559
|
if (limit !== null && limit > 0) {
|
|
@@ -74010,7 +74729,7 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74010
74729
|
};
|
|
74011
74730
|
let directPort = 0;
|
|
74012
74731
|
const rcSelfHost = rcSelfHostFromEnv(process.env);
|
|
74013
|
-
const codexPorts = createCodexRoutePorts(log);
|
|
74732
|
+
const codexPorts = createCodexRoutePorts(log, paths.chatgptSignInFile);
|
|
74014
74733
|
let ca;
|
|
74015
74734
|
const loadCa = () => {
|
|
74016
74735
|
ca ??= ensureCa(realConnectCertStore(paths), () => generateCa(/* @__PURE__ */ new Date()));
|
|
@@ -74027,14 +74746,15 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74027
74746
|
};
|
|
74028
74747
|
const rcSelfHostSurface = rcSelfHost ? createRcSelfHostSurface({
|
|
74029
74748
|
now: () => Date.now(),
|
|
74030
|
-
newUuid:
|
|
74031
|
-
randomToken: () => (0,
|
|
74749
|
+
newUuid: import_node_crypto14.randomUUID,
|
|
74750
|
+
randomToken: () => (0, import_node_crypto14.randomBytes)(MINTED_TOKEN_RANDOM_BYTES).toString("base64url"),
|
|
74032
74751
|
credentialRecord: () => readRcSelfHostRecord(realFarmFs, paths.frontdoorDir),
|
|
74033
74752
|
log
|
|
74034
74753
|
}) : void 0;
|
|
74035
74754
|
const rcCredentialStore = createRcCredentialStore(realFarmFs, paths.frontdoorRcCredentialsDir);
|
|
74036
74755
|
const rcTracker = createRcSessionTracker({ now: () => Date.now(), idleMs: RC_IDLE_EXPIRY_MS, credentialStore: rcCredentialStore });
|
|
74037
|
-
const
|
|
74756
|
+
const doorEvents = createDoorEventHub();
|
|
74757
|
+
const rcFanout = rcFanoutOnDoorHub(createRcEventFanout(), doorEvents);
|
|
74038
74758
|
const rcHub = createRcStreamHub({
|
|
74039
74759
|
now: () => Date.now(),
|
|
74040
74760
|
credentialOf: rcTracker.credentialOf,
|
|
@@ -74045,7 +74765,7 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74045
74765
|
saveSequenceNum: rcCredentialStore.writeCursor,
|
|
74046
74766
|
dial: rcSelfHost ? lateRcStreamDial(rcSelfHostDialTarget) : realRcStreamDial(),
|
|
74047
74767
|
fanout: rcFanout,
|
|
74048
|
-
newClientId:
|
|
74768
|
+
newClientId: import_node_crypto14.randomUUID,
|
|
74049
74769
|
backoffMs: RC_STREAM_BACKOFF_MS,
|
|
74050
74770
|
sleep: async (ms) => {
|
|
74051
74771
|
await new Promise((resolve) => {
|
|
@@ -74056,7 +74776,7 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74056
74776
|
appendLog(paths, `frontdoor ${String(process.pid)}: ${line}`);
|
|
74057
74777
|
}
|
|
74058
74778
|
});
|
|
74059
|
-
const rcControlToken = (0,
|
|
74779
|
+
const rcControlToken = (0, import_node_crypto14.randomUUID)();
|
|
74060
74780
|
const resolveRoute = rcObservingResolver(
|
|
74061
74781
|
createProviderRouteResolver({ fs: realFsPort, providersDir: paths.providersDir, codexPorts, directPort: () => directPort, ...rcSelfHostSurface === void 0 ? {} : { rcSelfHostRoute: rcSelfHostSurface.route } }),
|
|
74062
74782
|
rcTracker,
|
|
@@ -74087,8 +74807,8 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74087
74807
|
now: () => Date.now(),
|
|
74088
74808
|
headroomSocket: () => headroomSocketTarget(realFarmFs, realHeadroomSocketTrust, paths),
|
|
74089
74809
|
// The per-generation capability the direct listener demands: held only in this process's memory, so a loopback process that discovers the direct port still cannot use it.
|
|
74090
|
-
hopSecret: (0,
|
|
74091
|
-
custody: createCredentialCustody(() => (0,
|
|
74810
|
+
hopSecret: (0, import_node_crypto14.randomUUID)(),
|
|
74811
|
+
custody: createCredentialCustody(() => (0, import_node_crypto14.randomUUID)()),
|
|
74092
74812
|
log
|
|
74093
74813
|
});
|
|
74094
74814
|
const onListenerError = (name) => (error62) => {
|
|
@@ -74109,9 +74829,9 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74109
74829
|
startProviderListener: async (preferredPort) => {
|
|
74110
74830
|
const authority = loadCa();
|
|
74111
74831
|
const rcDial = rcSelfHost ? lateRcEventDial(rcSelfHostDialTarget) : realRcEventDial();
|
|
74112
|
-
const rcInject = async (sessionId, text2) => await injectRcUserMessage({ credentialOf: rcTracker.credentialOf, noteSequenceNums: rcTracker.noteSequenceNums, dial: rcDial, newUuid:
|
|
74832
|
+
const rcInject = async (sessionId, text2) => await injectRcUserMessage({ credentialOf: rcTracker.credentialOf, noteSequenceNums: rcTracker.noteSequenceNums, dial: rcDial, newUuid: import_node_crypto14.randomUUID }, sessionId, text2);
|
|
74113
74833
|
const rcAnswer = async (sessionId, requestId, decision) => await answerRcControlRequest({ credentialOf: rcTracker.credentialOf, pendingOf: (id) => rcTracker.pendingOf(id), completePending: rcTracker.completePending, noteSequenceNums: rcTracker.noteSequenceNums, dial: rcDial }, sessionId, requestId, decision);
|
|
74114
|
-
const rcControlRequestDeps = { credentialOf: rcTracker.credentialOf, noteSequenceNums: rcTracker.noteSequenceNums, dial: rcDial, newUuid:
|
|
74834
|
+
const rcControlRequestDeps = { credentialOf: rcTracker.credentialOf, noteSequenceNums: rcTracker.noteSequenceNums, dial: rcDial, newUuid: import_node_crypto14.randomUUID };
|
|
74115
74835
|
const rcInterrupt = async (sessionId) => await interruptRcSession(rcControlRequestDeps, sessionId);
|
|
74116
74836
|
const rcSetModel = async (sessionId, model) => await setRcSessionModel(rcControlRequestDeps, sessionId, model);
|
|
74117
74837
|
const rcSetPermissionMode = async (sessionId, mode) => await setRcSessionPermissionMode(rcControlRequestDeps, sessionId, mode);
|
|
@@ -74144,7 +74864,8 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74144
74864
|
setModel: rcSetModel,
|
|
74145
74865
|
setPermissionMode: rcSetPermissionMode,
|
|
74146
74866
|
fanout: rcFanout,
|
|
74147
|
-
...controlDeps
|
|
74867
|
+
...controlDeps,
|
|
74868
|
+
events: doorEvents
|
|
74148
74869
|
})
|
|
74149
74870
|
);
|
|
74150
74871
|
const handle = await listenFrontDoor(server, { ...preferredPort === void 0 ? {} : { preferredPort }, ca: authority.certPem, onError: onListenerError("provider") });
|
|
@@ -74158,7 +74879,7 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74158
74879
|
},
|
|
74159
74880
|
startConnectListener: async (preferredPort) => {
|
|
74160
74881
|
const wantedTransparentPort = process.env.AGENT_SHIM_TRANSPARENT_SURFACE === void 0 ? void 0 : Number(process.env.AGENT_SHIM_TRANSPARENT_SURFACE);
|
|
74161
|
-
const transparentCapability = wantedTransparentPort === void 0 || Number.isNaN(wantedTransparentPort) ? void 0 : (0,
|
|
74882
|
+
const transparentCapability = wantedTransparentPort === void 0 || Number.isNaN(wantedTransparentPort) ? void 0 : (0, import_node_crypto14.randomUUID)();
|
|
74162
74883
|
if (transparentCapability !== void 0) {
|
|
74163
74884
|
writeFrontDoorSession(realFarmFs, paths.frontdoorSessionsDir, { pid: process.pid, startedAt: Date.now(), token: transparentCapability });
|
|
74164
74885
|
}
|
|
@@ -74231,6 +74952,8 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
74231
74952
|
return { port: handle.port, close: handle.close };
|
|
74232
74953
|
},
|
|
74233
74954
|
closeRcStreamHub: rcHub.close,
|
|
74955
|
+
// The launch lifecycle publisher over the same backbone the typed API serves: the tick's registry facts go in here, and the door's own register, prune and end moments come out as source-tagged events.
|
|
74956
|
+
observeLaunchRegistry: createLaunchEventPublisher(doorEvents, () => Date.now()).observe,
|
|
74234
74957
|
log: (line) => {
|
|
74235
74958
|
appendLog(paths, line);
|
|
74236
74959
|
}
|
|
@@ -74501,8 +75224,8 @@ function registerFrontDoorCommand(program2, deps) {
|
|
|
74501
75224
|
identitiesDir: paths.identitiesDir,
|
|
74502
75225
|
frontdoorDir: paths.frontdoorDir,
|
|
74503
75226
|
identity,
|
|
74504
|
-
newUuid:
|
|
74505
|
-
randomToken: () => (0,
|
|
75227
|
+
newUuid: import_node_crypto14.randomUUID,
|
|
75228
|
+
randomToken: () => (0, import_node_crypto14.randomBytes)(MINTED_TOKEN_RANDOM_BYTES).toString("base64url"),
|
|
74506
75229
|
force: options.force === true,
|
|
74507
75230
|
now: () => Date.now()
|
|
74508
75231
|
});
|
|
@@ -74816,7 +75539,7 @@ function registerCompletionCommand(program2) {
|
|
|
74816
75539
|
}
|
|
74817
75540
|
|
|
74818
75541
|
// src/credentialCommand.ts
|
|
74819
|
-
var
|
|
75542
|
+
var import_node_child_process5 = require("node:child_process");
|
|
74820
75543
|
|
|
74821
75544
|
// src/identityToken.ts
|
|
74822
75545
|
var import_node_fs14 = __toESM(require("node:fs"), 1);
|
|
@@ -74868,7 +75591,7 @@ function realCommandPorts(deps) {
|
|
|
74868
75591
|
cache: createRealCredentialCache(deps.paths.root),
|
|
74869
75592
|
platform: process.platform,
|
|
74870
75593
|
now: () => Date.now(),
|
|
74871
|
-
ssh: (host, remoteCommand, input2) => (0,
|
|
75594
|
+
ssh: (host, remoteCommand, input2) => (0, import_node_child_process5.spawnSync)("ssh", ["--", host, remoteCommand], { input: input2, stdio: ["pipe", "inherit", "inherit"] }).status
|
|
74872
75595
|
};
|
|
74873
75596
|
}
|
|
74874
75597
|
var REMOTE_ROOT_SCRIPT = 'root="${AGENT_SHIM_HOME:-${CLAUDE_USE_HOME:-}}"; if [ -z "$root" ]; then if [ ! -d "$HOME/.agent-shim" ] && [ -d "$HOME/.claude-use" ]; then root="$HOME/.claude-use"; else root="$HOME/.agent-shim"; fi; fi';
|
|
@@ -74999,15 +75722,15 @@ function registerDoctorCommand(program2, deps) {
|
|
|
74999
75722
|
|
|
75000
75723
|
// src/headroom/commands.ts
|
|
75001
75724
|
var import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
75002
|
-
var
|
|
75725
|
+
var import_node_http3 = __toESM(require("node:http"), 1);
|
|
75003
75726
|
var import_node_path39 = __toESM(require("node:path"), 1);
|
|
75004
|
-
var
|
|
75727
|
+
var import_node_child_process6 = require("node:child_process");
|
|
75005
75728
|
|
|
75006
75729
|
// src/frontdoor/realFrontDoorPort.ts
|
|
75007
75730
|
var import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
75008
75731
|
|
|
75009
75732
|
// src/frontdoor/ensure.ts
|
|
75010
|
-
var
|
|
75733
|
+
var import_node_crypto15 = require("node:crypto");
|
|
75011
75734
|
var FRONTDOOR_START_TIMEOUT_MS = 3e4;
|
|
75012
75735
|
var FRONTDOOR_LAUNCHER_POLL_MS = 100;
|
|
75013
75736
|
var FrontDoorStartError = class extends CliError {
|
|
@@ -75041,7 +75764,7 @@ function ensureFrontDoor(params) {
|
|
|
75041
75764
|
continue;
|
|
75042
75765
|
}
|
|
75043
75766
|
if (verdict.ok) {
|
|
75044
|
-
const token = (0,
|
|
75767
|
+
const token = (0, import_node_crypto15.randomUUID)();
|
|
75045
75768
|
writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token });
|
|
75046
75769
|
return { port: state.port, connectPort: state.connectPort, token };
|
|
75047
75770
|
}
|
|
@@ -75145,7 +75868,7 @@ function probeFrontDoorSync(port, caPem) {
|
|
|
75145
75868
|
}
|
|
75146
75869
|
|
|
75147
75870
|
// src/frontdoor/trust.ts
|
|
75148
|
-
var
|
|
75871
|
+
var import_node_crypto16 = require("node:crypto");
|
|
75149
75872
|
var import_node_path38 = __toESM(require("node:path"), 1);
|
|
75150
75873
|
var BUNDLE_NAME_HEX_DIGITS = 16;
|
|
75151
75874
|
function resolveTrustBundle(params) {
|
|
@@ -75168,7 +75891,7 @@ function resolveTrustBundle(params) {
|
|
|
75168
75891
|
}
|
|
75169
75892
|
const combined = `${inheritedPem.trimEnd()}
|
|
75170
75893
|
${caPem}`;
|
|
75171
|
-
const bundle = import_node_path38.default.join(bundlesDir, `${(0,
|
|
75894
|
+
const bundle = import_node_path38.default.join(bundlesDir, `${(0, import_node_crypto16.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
75172
75895
|
if (!fs19.exists(bundle)) {
|
|
75173
75896
|
fs19.mkdirp(bundlesDir);
|
|
75174
75897
|
fs19.writeFileAtomic(bundle, combined);
|
|
@@ -75308,7 +76031,7 @@ function headroomProxyArgs(socketPath, settings2) {
|
|
|
75308
76031
|
}
|
|
75309
76032
|
async function readyOverSocket(socketPath) {
|
|
75310
76033
|
return await new Promise((resolve) => {
|
|
75311
|
-
const probe =
|
|
76034
|
+
const probe = import_node_http3.default.get({ socketPath, path: "/readyz", timeout: READY_FETCH_TIMEOUT_MS }, (response) => {
|
|
75312
76035
|
response.resume();
|
|
75313
76036
|
resolve(response.statusCode === HTTP_STATUS.ok);
|
|
75314
76037
|
});
|
|
@@ -75322,7 +76045,7 @@ async function readyOverSocket(socketPath) {
|
|
|
75322
76045
|
}
|
|
75323
76046
|
var HEADROOM_TOOL_NAME = "headroom-ai";
|
|
75324
76047
|
function readInstalledHeadroomCommit() {
|
|
75325
|
-
const toolDir = (0,
|
|
76048
|
+
const toolDir = (0, import_node_child_process6.spawnSync)("uv", ["tool", "dir"], { encoding: "utf8" });
|
|
75326
76049
|
if (toolDir.status !== 0) {
|
|
75327
76050
|
return void 0;
|
|
75328
76051
|
}
|
|
@@ -75362,7 +76085,7 @@ function realSupervisorPorts(paths) {
|
|
|
75362
76085
|
}
|
|
75363
76086
|
const logFd = import_node_fs16.default.openSync(paths.headroomLogPath, "a");
|
|
75364
76087
|
try {
|
|
75365
|
-
const child = (0,
|
|
76088
|
+
const child = (0, import_node_child_process6.spawn)("headroom", headroomProxyArgs(socketPath, settings2), {
|
|
75366
76089
|
detached: true,
|
|
75367
76090
|
stdio: ["ignore", logFd, logFd],
|
|
75368
76091
|
env: headroomSpawnEnv(process.env, allowlist, settings2, trust?.path)
|
|
@@ -75402,7 +76125,7 @@ function realSupervisorPorts(paths) {
|
|
|
75402
76125
|
},
|
|
75403
76126
|
ready: readyOverSocket,
|
|
75404
76127
|
install: (spec) => {
|
|
75405
|
-
const result = (0,
|
|
76128
|
+
const result = (0, import_node_child_process6.spawnSync)("uv", ["tool", "install", spec], { encoding: "utf8" });
|
|
75406
76129
|
if (result.error !== void 0) {
|
|
75407
76130
|
return { ok: false, error: `uv is not installed or not on PATH (${result.error.message})` };
|
|
75408
76131
|
}
|
|
@@ -75415,7 +76138,7 @@ function realSupervisorPorts(paths) {
|
|
|
75415
76138
|
return result.status === 0 ? { ok: true } : { ok: false, error: `uv tool install exited ${String(result.status)}` };
|
|
75416
76139
|
},
|
|
75417
76140
|
headroomVersion: () => {
|
|
75418
|
-
const result = (0,
|
|
76141
|
+
const result = (0, import_node_child_process6.spawnSync)("headroom", ["--version"], { encoding: "utf8" });
|
|
75419
76142
|
return result.status === 0 ? result.stdout.trim() : void 0;
|
|
75420
76143
|
},
|
|
75421
76144
|
installedCommit: readInstalledHeadroomCommit,
|
|
@@ -75598,13 +76321,14 @@ function toProviderView(name, provider) {
|
|
|
75598
76321
|
};
|
|
75599
76322
|
}
|
|
75600
76323
|
function codexConfigFromOptions(options) {
|
|
75601
|
-
if (options.codexDefaultModel === void 0 && options.codexModel === void 0 && options.codexEffort === void 0) {
|
|
76324
|
+
if (options.codexDefaultModel === void 0 && options.codexModel === void 0 && options.codexEffort === void 0 && options.codexLogin === void 0) {
|
|
75602
76325
|
return void 0;
|
|
75603
76326
|
}
|
|
75604
76327
|
const candidate = {
|
|
75605
76328
|
...options.codexDefaultModel === void 0 ? {} : { defaultModel: options.codexDefaultModel },
|
|
75606
76329
|
...options.codexModel === void 0 ? {} : { models: options.codexModel },
|
|
75607
|
-
...options.codexEffort === void 0 ? {} : { effort: options.codexEffort }
|
|
76330
|
+
...options.codexEffort === void 0 ? {} : { effort: options.codexEffort },
|
|
76331
|
+
...options.codexLogin === void 0 ? {} : { login: options.codexLogin }
|
|
75608
76332
|
};
|
|
75609
76333
|
const parsed = CodexProviderConfigSchema.safeParse(candidate);
|
|
75610
76334
|
if (!parsed.success) {
|
|
@@ -75627,7 +76351,7 @@ function registerProviderCommand(program2, deps) {
|
|
|
75627
76351
|
new Option("--credential-target <target>", "Where the token goes: bearer sets ANTHROPIC_AUTH_TOKEN (default), apiKey sets ANTHROPIC_API_KEY.").choices(
|
|
75628
76352
|
PROVIDER_CREDENTIAL_TARGETS
|
|
75629
76353
|
)
|
|
75630
|
-
).option("--env <KEY=VALUE>", "Extra environment entry for the child (repeatable).", collectStringPair).option("--codex-default-model <model>", "Codex providers: the codex model a request maps to when no tier matches.").option("--codex-model <tier=model>", "Codex providers: the codex model one tier (fable, opus, sonnet or haiku) maps to (repeatable).", collectStringPair).addOption(new Option("--codex-effort <effort>", "Codex providers: the reasoning effort when a request asks for none the backend accepts.").choices(CODEX_EFFORTS)).option("--json", "Print the result as JSON.").action((name, options) => {
|
|
76354
|
+
).option("--env <KEY=VALUE>", "Extra environment entry for the child (repeatable).", collectStringPair).option("--codex-default-model <model>", "Codex providers: the codex model a request maps to when no tier matches.").option("--codex-model <tier=model>", "Codex providers: the codex model one tier (fable, opus, sonnet or haiku) maps to (repeatable).", collectStringPair).addOption(new Option("--codex-effort <effort>", "Codex providers: the reasoning effort when a request asks for none the backend accepts.").choices(CODEX_EFFORTS)).addOption(new Option("--codex-login <login>", "Codex providers: which login the upstream call uses, the Codex CLI's own login or a Sign in with ChatGPT grant from `agent-shim codex login`.").choices(CODEX_LOGINS)).option("--json", "Print the result as JSON.").action((name, options) => {
|
|
75631
76355
|
const codex = codexConfigFromOptions(options);
|
|
75632
76356
|
const created = addProvider(paths, name, {
|
|
75633
76357
|
...options.kind === void 0 ? {} : { kind: options.kind },
|
|
@@ -75659,14 +76383,14 @@ function registerProviderCommand(program2, deps) {
|
|
|
75659
76383
|
new Option("--credential-target <target>", "Where the token goes: bearer sets ANTHROPIC_AUTH_TOKEN, apiKey sets ANTHROPIC_API_KEY.").choices(
|
|
75660
76384
|
PROVIDER_CREDENTIAL_TARGETS
|
|
75661
76385
|
)
|
|
75662
|
-
).option("--env <KEY=VALUE>", "Add or replace an environment entry for the child (repeatable).", collectStringPair).option("--unset-env <KEY>", "Remove an environment entry (repeatable).", collectRepeated).option("--codex-default-model <model>", "Codex providers: replace the model a request maps to when no tier matches.").option("--codex-model <tier=model>", "Codex providers: set the codex model one tier maps to (repeatable; other tiers are kept).", collectStringPair).addOption(new Option("--codex-effort <effort>", "Codex providers: replace the default reasoning effort.").choices(CODEX_EFFORTS));
|
|
76386
|
+
).option("--env <KEY=VALUE>", "Add or replace an environment entry for the child (repeatable).", collectStringPair).option("--unset-env <KEY>", "Remove an environment entry (repeatable).", collectRepeated).option("--codex-default-model <model>", "Codex providers: replace the model a request maps to when no tier matches.").option("--codex-model <tier=model>", "Codex providers: set the codex model one tier maps to (repeatable; other tiers are kept).", collectStringPair).addOption(new Option("--codex-effort <effort>", "Codex providers: replace the default reasoning effort.").choices(CODEX_EFFORTS)).addOption(new Option("--codex-login <login>", "Codex providers: replace which login the upstream call uses.").choices(CODEX_LOGINS));
|
|
75663
76387
|
addCredentialCacheOptions(providerSet);
|
|
75664
76388
|
withExamples(
|
|
75665
76389
|
providerSet.option("--json", "Print the result as JSON.").action((name, allOptions) => {
|
|
75666
76390
|
const { json: json2, ...options } = allOptions;
|
|
75667
76391
|
if (Object.entries(allOptions).every(([key, value2]) => key === "json" || value2 === void 0)) {
|
|
75668
76392
|
throw new UsageError(
|
|
75669
|
-
"Nothing to change: pass --display-name, --base-url, --credential, --credential-target, a --credential-cache option, --env, --unset-env, --codex-default-model, --codex-model or --codex-
|
|
76393
|
+
"Nothing to change: pass --display-name, --base-url, --credential, --credential-target, a --credential-cache option, --env, --unset-env, --codex-default-model, --codex-model, --codex-effort or --codex-login."
|
|
75670
76394
|
);
|
|
75671
76395
|
}
|
|
75672
76396
|
const codex = codexConfigFromOptions(options);
|
|
@@ -75727,6 +76451,7 @@ function registerProviderCommand(program2, deps) {
|
|
|
75727
76451
|
const config2 = resolveCodexConfig(found.codex);
|
|
75728
76452
|
console.log(`Codex models: ${CODEX_TIERS.map((tier) => `${tier}=${config2.models[tier]}`).join(", ")}, otherwise ${config2.defaultModel}`);
|
|
75729
76453
|
console.log(`Codex effort: ${config2.effort}`);
|
|
76454
|
+
console.log(`Codex login: ${config2.login}`);
|
|
75730
76455
|
} else {
|
|
75731
76456
|
console.log(`Base URL: ${found.baseUrl}`);
|
|
75732
76457
|
}
|
|
@@ -76134,10 +76859,10 @@ function buildProgram(deps) {
|
|
|
76134
76859
|
|
|
76135
76860
|
// src/launchWiring.ts
|
|
76136
76861
|
var import_node_os8 = __toESM(require("node:os"), 1);
|
|
76137
|
-
var
|
|
76862
|
+
var import_node_crypto18 = require("node:crypto");
|
|
76138
76863
|
|
|
76139
76864
|
// src/launcher.ts
|
|
76140
|
-
var
|
|
76865
|
+
var import_node_crypto17 = require("node:crypto");
|
|
76141
76866
|
var import_node_path41 = __toESM(require("node:path"), 1);
|
|
76142
76867
|
|
|
76143
76868
|
// src/launcher/cliOverride.ts
|
|
@@ -76638,7 +77363,7 @@ function prepareLaunch(params) {
|
|
|
76638
77363
|
...identityCredential === void 0 ? {} : { identityCredential },
|
|
76639
77364
|
...frontDoor === void 0 ? {} : { frontdoor: frontDoor },
|
|
76640
77365
|
...headroom === void 0 ? {} : { headroom },
|
|
76641
|
-
sessionId: (0,
|
|
77366
|
+
sessionId: (0, import_node_crypto17.randomUUID)()
|
|
76642
77367
|
});
|
|
76643
77368
|
const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
|
|
76644
77369
|
const release = () => {
|
|
@@ -76683,7 +77408,7 @@ function buildFarmRuntime(paths, cwd) {
|
|
|
76683
77408
|
...cliOverride === void 0 ? {} : { cliOverride }
|
|
76684
77409
|
}).input,
|
|
76685
77410
|
now: () => Date.now(),
|
|
76686
|
-
uniqueSuffix: `${String(process.pid)}.${(0,
|
|
77411
|
+
uniqueSuffix: `${String(process.pid)}.${(0, import_node_crypto18.randomUUID)()}`,
|
|
76687
77412
|
// Zombie-aware on purpose: a previous launcher that crashed out of a resync without releasing the lock may sit unreaped, still answering signal 0 as alive, and must read as a dead holder so this launch takes the lock over instead of timing out.
|
|
76688
77413
|
lock: { pid: process.pid, isRunning: realIsProcessRunning, sleep: realSleepSync }
|
|
76689
77414
|
},
|