agent-shim 8.15.0 → 8.17.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 +5 -2
- package/dist/cli.cjs +1406 -217
- package/dist/index.cjs +376 -46
- package/dist/index.mjs +365 -45
- package/dist/types/index.d.ts +174 -30
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,8 @@ __export(index_exports, {
|
|
|
46
46
|
CredentialCacheSchema: () => CredentialCacheSchema,
|
|
47
47
|
CredentialSchema: () => CredentialSchema,
|
|
48
48
|
CredentialSourceSchema: () => CredentialSourceSchema,
|
|
49
|
+
DOOR_EVENT_BUFFER_EVENTS: () => DOOR_EVENT_BUFFER_EVENTS,
|
|
50
|
+
DOOR_EVENT_SOURCE_RC: () => DOOR_EVENT_SOURCE_RC,
|
|
49
51
|
DirectoryRuleAlreadyExistsError: () => DirectoryRuleAlreadyExistsError,
|
|
50
52
|
DirectoryRuleMissingTargetError: () => DirectoryRuleMissingTargetError,
|
|
51
53
|
DirectoryRuleNotFoundError: () => DirectoryRuleNotFoundError,
|
|
@@ -53,6 +55,8 @@ __export(index_exports, {
|
|
|
53
55
|
DirectoryRulesSchema: () => DirectoryRulesSchema,
|
|
54
56
|
DoctorFindingSchema: () => DoctorFindingSchema,
|
|
55
57
|
DoctorRunOutputSchema: () => DoctorRunOutputSchema,
|
|
58
|
+
DoorEventSchema: () => DoorEventSchema,
|
|
59
|
+
DoorEventSourceQuerySchema: () => DoorEventSourceQuerySchema,
|
|
56
60
|
EXIT_FAILURE: () => EXIT_FAILURE,
|
|
57
61
|
EXIT_USAGE: () => EXIT_USAGE,
|
|
58
62
|
EffectiveWindowSchema: () => EffectiveWindowSchema,
|
|
@@ -72,6 +76,8 @@ __export(index_exports, {
|
|
|
72
76
|
InvalidCategoryNameError: () => InvalidCategoryNameError,
|
|
73
77
|
InvalidIdentityNameError: () => InvalidIdentityNameError,
|
|
74
78
|
InvalidProviderNameError: () => InvalidProviderNameError,
|
|
79
|
+
LAUNCH_EVENT_SOURCE: () => LAUNCH_EVENT_SOURCE,
|
|
80
|
+
LaunchLifecycleEventSchema: () => LaunchLifecycleEventSchema,
|
|
75
81
|
LaunchRefusedError: () => LaunchRefusedError,
|
|
76
82
|
LegacyProviderFileError: () => LegacyProviderFileError,
|
|
77
83
|
PROMPT_CACHE_TTL_MS: () => PROMPT_CACHE_TTL_MS,
|
|
@@ -135,6 +141,9 @@ __export(index_exports, {
|
|
|
135
141
|
createControlApiRouter: () => createControlApiRouter,
|
|
136
142
|
createDoorApiNodeHandler: () => createDoorApiNodeHandler,
|
|
137
143
|
createDoorApiRouter: () => createDoorApiRouter,
|
|
144
|
+
createDoorEventHub: () => createDoorEventHub,
|
|
145
|
+
createEventsApiRouter: () => createEventsApiRouter,
|
|
146
|
+
createLaunchEventPublisher: () => createLaunchEventPublisher,
|
|
138
147
|
createLeafCache: () => createLeafCache,
|
|
139
148
|
createProfile: () => createProfile,
|
|
140
149
|
createRcApiNodeHandler: () => createRcApiNodeHandler,
|
|
@@ -193,6 +202,7 @@ __export(index_exports, {
|
|
|
193
202
|
providerExists: () => providerExists,
|
|
194
203
|
rankPool: () => rankPool,
|
|
195
204
|
rcEventWriteResultFromAnswer: () => rcEventWriteResultFromAnswer,
|
|
205
|
+
rcFanoutOnDoorHub: () => rcFanoutOnDoorHub,
|
|
196
206
|
rcObserverAsPassthrough: () => rcObserverAsPassthrough,
|
|
197
207
|
rcSelfHostFromEnv: () => rcSelfHostFromEnv,
|
|
198
208
|
readActiveIdentity: () => readActiveIdentity,
|
|
@@ -507,6 +517,7 @@ var ProviderEnvSchema = import_zod.z.record(import_zod.z.string().min(1), import
|
|
|
507
517
|
message: `env may not set ${RESERVED_PROVIDER_ENV_KEYS.join(", ")}: the credential block's target sets one and agent-shim removes the others`
|
|
508
518
|
});
|
|
509
519
|
var CODEX_EFFORTS = ["none", "low", "medium", "high"];
|
|
520
|
+
var CODEX_LOGINS = ["codex-cli", "chatgpt-sign-in"];
|
|
510
521
|
var CODEX_DEFAULT_TIER_MODELS = Object.freeze({
|
|
511
522
|
fable: "gpt-5.6-sol",
|
|
512
523
|
opus: "gpt-5.6-sol",
|
|
@@ -524,7 +535,9 @@ var CodexProviderConfigSchema = import_zod.z.strictObject({
|
|
|
524
535
|
haiku: import_zod.z.string().min(1).optional()
|
|
525
536
|
}).optional(),
|
|
526
537
|
/** The reasoning effort used when the request's own `output_config.effort` is not one the backend accepts. */
|
|
527
|
-
effort: import_zod.z.enum(CODEX_EFFORTS).optional()
|
|
538
|
+
effort: import_zod.z.enum(CODEX_EFFORTS).optional(),
|
|
539
|
+
/** Which login the upstream call is made with; see `CODEX_LOGINS`. */
|
|
540
|
+
login: import_zod.z.enum(CODEX_LOGINS).optional()
|
|
528
541
|
});
|
|
529
542
|
var HttpProviderSchema = import_zod.z.strictObject({
|
|
530
543
|
$schema: import_zod.z.string().optional(),
|
|
@@ -3013,8 +3026,11 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
3013
3026
|
return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
|
|
3014
3027
|
}
|
|
3015
3028
|
ticks += 1;
|
|
3016
|
-
|
|
3017
|
-
|
|
3029
|
+
const listed = listFrontDoorSessions(fs12, paths.frontdoorSessionsDir);
|
|
3030
|
+
const pruned = pruneDeadFrontDoorSessions(fs12, paths.frontdoorSessionsDir, ports.isRunning);
|
|
3031
|
+
ports.observeLaunchRegistry(listed, pruned);
|
|
3032
|
+
const prunedPids = new Set(pruned);
|
|
3033
|
+
if (listed.filter((session) => !prunedPids.has(session.pid)).length === 0) {
|
|
3018
3034
|
idleSince ??= ports.now();
|
|
3019
3035
|
if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
|
|
3020
3036
|
ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
|
|
@@ -5236,7 +5252,7 @@ function frontDoorRcApiClient(port, ca, token) {
|
|
|
5236
5252
|
}
|
|
5237
5253
|
|
|
5238
5254
|
// src/frontdoor/controlApi.ts
|
|
5239
|
-
var
|
|
5255
|
+
var import_client3 = require("@orpc/client");
|
|
5240
5256
|
|
|
5241
5257
|
// src/checkReport.ts
|
|
5242
5258
|
var import_node_os4 = __toESM(require("node:os"), 1);
|
|
@@ -5586,6 +5602,7 @@ function buildLayoutPaths(root) {
|
|
|
5586
5602
|
frontdoorCaCertFile: import_node_path14.default.join(root, "frontdoor", "ca", "ca.pem"),
|
|
5587
5603
|
frontdoorCaKeyFile: import_node_path14.default.join(root, "frontdoor", "ca", "ca.key"),
|
|
5588
5604
|
frontdoorCaBundlesDir: import_node_path14.default.join(root, "frontdoor", "ca", "bundles"),
|
|
5605
|
+
chatgptSignInFile: import_node_path14.default.join(root, "codex", "chatgpt-sign-in.json"),
|
|
5589
5606
|
frontdoorStateFile: import_node_path14.default.join(root, "frontdoor", "state.json"),
|
|
5590
5607
|
frontdoorLockFile: import_node_path14.default.join(root, "frontdoor", "start.lock"),
|
|
5591
5608
|
frontdoorControlTokenFile: import_node_path14.default.join(root, "frontdoor", "control-token"),
|
|
@@ -7021,7 +7038,7 @@ var ProviderKindMismatchError = class extends UsageError {
|
|
|
7021
7038
|
}
|
|
7022
7039
|
};
|
|
7023
7040
|
function isEmptyCodexConfig(config) {
|
|
7024
|
-
return config === void 0 || config.defaultModel === void 0 && config.effort === void 0 && (config.models === void 0 || Object.keys(config.models).length === 0);
|
|
7041
|
+
return config === void 0 || config.defaultModel === void 0 && config.effort === void 0 && config.login === void 0 && (config.models === void 0 || Object.keys(config.models).length === 0);
|
|
7025
7042
|
}
|
|
7026
7043
|
function addProvider(paths, name, input) {
|
|
7027
7044
|
if (providerExists(paths, name)) {
|
|
@@ -8689,7 +8706,7 @@ var CheckReportJsonSchema = import_zod14.z.strictObject({
|
|
|
8689
8706
|
|
|
8690
8707
|
// src/frontdoor/controlSchemas.ts
|
|
8691
8708
|
var import_node_path27 = __toESM(require("node:path"), 1);
|
|
8692
|
-
var
|
|
8709
|
+
var import_zod19 = require("zod");
|
|
8693
8710
|
|
|
8694
8711
|
// src/claudeShim.ts
|
|
8695
8712
|
var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
@@ -8893,6 +8910,85 @@ function removeIdentity(paths, name) {
|
|
|
8893
8910
|
// src/doctorReport.ts
|
|
8894
8911
|
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
8895
8912
|
var import_node_path26 = __toESM(require("node:path"), 1);
|
|
8913
|
+
|
|
8914
|
+
// src/codex/siwcStore.ts
|
|
8915
|
+
var import_zod18 = require("zod");
|
|
8916
|
+
|
|
8917
|
+
// src/codex/auth.ts
|
|
8918
|
+
var import_zod16 = require("zod");
|
|
8919
|
+
var AuthFileSchema = import_zod16.z.looseObject({
|
|
8920
|
+
tokens: import_zod16.z.looseObject({
|
|
8921
|
+
access_token: import_zod16.z.string().optional(),
|
|
8922
|
+
refresh_token: import_zod16.z.string().optional(),
|
|
8923
|
+
id_token: import_zod16.z.string().optional(),
|
|
8924
|
+
account_id: import_zod16.z.string().optional()
|
|
8925
|
+
}).nullish(),
|
|
8926
|
+
last_refresh: import_zod16.z.string().optional()
|
|
8927
|
+
});
|
|
8928
|
+
var TokenGrantSchema = import_zod16.z.looseObject({
|
|
8929
|
+
access_token: import_zod16.z.string().min(1).optional(),
|
|
8930
|
+
refresh_token: import_zod16.z.string().min(1).optional(),
|
|
8931
|
+
id_token: import_zod16.z.string().min(1).optional(),
|
|
8932
|
+
account_id: import_zod16.z.string().min(1).optional()
|
|
8933
|
+
});
|
|
8934
|
+
var CodexAuthError = class extends Error {
|
|
8935
|
+
constructor(message) {
|
|
8936
|
+
super(message);
|
|
8937
|
+
this.name = "CodexAuthError";
|
|
8938
|
+
}
|
|
8939
|
+
};
|
|
8940
|
+
|
|
8941
|
+
// src/codex/siwc.ts
|
|
8942
|
+
var import_zod17 = require("zod");
|
|
8943
|
+
var SIWC_RESOURCE = "https://api.openai.com/v1";
|
|
8944
|
+
var SIWC_RESPONSES_URL = `${SIWC_RESOURCE}/responses`;
|
|
8945
|
+
var SIWC_PLAN_SCOPE = "chatgpt.tokens.use.direct";
|
|
8946
|
+
var TokenResponseSchema = import_zod17.z.looseObject({
|
|
8947
|
+
access_token: import_zod17.z.string().min(1),
|
|
8948
|
+
refresh_token: import_zod17.z.string().min(1).optional(),
|
|
8949
|
+
id_token: import_zod17.z.string().min(1).optional(),
|
|
8950
|
+
expires_in: import_zod17.z.number().positive(),
|
|
8951
|
+
scope: import_zod17.z.string().optional()
|
|
8952
|
+
});
|
|
8953
|
+
var JwtHeaderSchema = import_zod17.z.looseObject({ alg: import_zod17.z.string(), kid: import_zod17.z.string().optional() });
|
|
8954
|
+
var IdTokenClaimsSchema = import_zod17.z.looseObject({
|
|
8955
|
+
iss: import_zod17.z.string(),
|
|
8956
|
+
sub: import_zod17.z.string().min(1),
|
|
8957
|
+
aud: import_zod17.z.union([import_zod17.z.string(), import_zod17.z.array(import_zod17.z.string())]),
|
|
8958
|
+
exp: import_zod17.z.number(),
|
|
8959
|
+
nonce: import_zod17.z.string().optional(),
|
|
8960
|
+
email: import_zod17.z.string().optional()
|
|
8961
|
+
});
|
|
8962
|
+
var JwksSchema = import_zod17.z.object({ keys: import_zod17.z.array(import_zod17.z.looseObject({ kid: import_zod17.z.string().optional(), kty: import_zod17.z.string() })) });
|
|
8963
|
+
|
|
8964
|
+
// src/codex/siwcStore.ts
|
|
8965
|
+
var SiwcGrantSchema = import_zod18.z.strictObject({
|
|
8966
|
+
clientId: import_zod18.z.string().min(1),
|
|
8967
|
+
sub: import_zod18.z.string().min(1),
|
|
8968
|
+
email: import_zod18.z.string().optional(),
|
|
8969
|
+
idToken: import_zod18.z.string().min(1),
|
|
8970
|
+
accessToken: import_zod18.z.string().min(1),
|
|
8971
|
+
refreshToken: import_zod18.z.string().min(1),
|
|
8972
|
+
scopes: import_zod18.z.array(import_zod18.z.string()).readonly(),
|
|
8973
|
+
/** When the access token stops working, in milliseconds since the epoch. */
|
|
8974
|
+
expiresAt: import_zod18.z.number()
|
|
8975
|
+
});
|
|
8976
|
+
var SiwcFileSchema = import_zod18.z.strictObject({ registeredClientId: import_zod18.z.string().min(1).optional(), grant: SiwcGrantSchema.optional() });
|
|
8977
|
+
function parseSiwcFile(raw, filePath) {
|
|
8978
|
+
let json;
|
|
8979
|
+
try {
|
|
8980
|
+
json = JSON.parse(raw);
|
|
8981
|
+
} catch {
|
|
8982
|
+
throw new CodexAuthError(`${filePath} is not valid JSON: run \`agent-shim codex login\` again`);
|
|
8983
|
+
}
|
|
8984
|
+
const parsed = SiwcFileSchema.safeParse(json);
|
|
8985
|
+
if (!parsed.success) {
|
|
8986
|
+
throw new CodexAuthError(`${filePath} is not a Sign in with ChatGPT file: run \`agent-shim codex login\` again`);
|
|
8987
|
+
}
|
|
8988
|
+
return parsed.data;
|
|
8989
|
+
}
|
|
8990
|
+
|
|
8991
|
+
// src/doctorReport.ts
|
|
8896
8992
|
var DOCTOR_SEVERITIES = ["pass", "warn", "fail"];
|
|
8897
8993
|
var DOCTOR_SECTIONS = [
|
|
8898
8994
|
"ambient-credential",
|
|
@@ -8983,7 +9079,21 @@ function cacheClause(cacheEnv, owner, block) {
|
|
|
8983
9079
|
const state = describeCachedCredential({ port: cacheEnv.port, platform: cacheEnv.platform, owner, cache: block.cache, nowMs: cacheEnv.now() });
|
|
8984
9080
|
return { text: `; ${formatCachedCredentialState(state)}`, unreadable: state.status === "unreadable" };
|
|
8985
9081
|
}
|
|
8986
|
-
function
|
|
9082
|
+
function signInProblem(signIn) {
|
|
9083
|
+
if (signIn.raw === void 0) {
|
|
9084
|
+
return "nobody is signed in: run `agent-shim codex login`.";
|
|
9085
|
+
}
|
|
9086
|
+
try {
|
|
9087
|
+
const grant = parseSiwcFile(signIn.raw, signIn.path).grant;
|
|
9088
|
+
if (grant === void 0) {
|
|
9089
|
+
return "nobody is signed in: run `agent-shim codex login`.";
|
|
9090
|
+
}
|
|
9091
|
+
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.";
|
|
9092
|
+
} catch (error) {
|
|
9093
|
+
return error instanceof Error ? error.message : String(error);
|
|
9094
|
+
}
|
|
9095
|
+
}
|
|
9096
|
+
function pushProvider(push, entry, cacheEnv, signIn) {
|
|
8987
9097
|
if (entry.raw === void 0) {
|
|
8988
9098
|
push("provider", "fail", `${entry.path} is missing.`, entry.name);
|
|
8989
9099
|
return;
|
|
@@ -9010,6 +9120,12 @@ function pushProvider(push, entry, cacheEnv) {
|
|
|
9010
9120
|
if (validated2.data.env?.ENABLE_TOOL_SEARCH === void 0) {
|
|
9011
9121
|
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);
|
|
9012
9122
|
}
|
|
9123
|
+
if (signIn !== void 0 && isCodexProvider(validated2.data) && validated2.data.codex?.login === "chatgpt-sign-in") {
|
|
9124
|
+
const problem = signInProblem(signIn);
|
|
9125
|
+
if (problem !== void 0) {
|
|
9126
|
+
push("provider", "warn", `${entry.name} uses the Sign in with ChatGPT login, but ${problem}`, entry.name);
|
|
9127
|
+
}
|
|
9128
|
+
}
|
|
9013
9129
|
}
|
|
9014
9130
|
function pushLegacyName(push, params) {
|
|
9015
9131
|
const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
|
|
@@ -9134,7 +9250,7 @@ function runDoctor(params) {
|
|
|
9134
9250
|
return poolName === void 0 ? validIdentityNames.has(selector) : poolName in pools;
|
|
9135
9251
|
};
|
|
9136
9252
|
for (const entry of params.providers) {
|
|
9137
|
-
pushProvider(push, entry, params.credentialCache);
|
|
9253
|
+
pushProvider(push, entry, params.credentialCache, params.chatgptSignIn);
|
|
9138
9254
|
}
|
|
9139
9255
|
if (params.platform !== "darwin" || params.run === void 0) {
|
|
9140
9256
|
push("keychain", "pass", "Skipped (not macOS).");
|
|
@@ -9376,6 +9492,7 @@ function collectDoctorReport(params) {
|
|
|
9376
9492
|
const report = runDoctor({
|
|
9377
9493
|
env: params.env,
|
|
9378
9494
|
credentialCache: realCredentialCacheEnv(paths),
|
|
9495
|
+
chatgptSignIn: { path: paths.chatgptSignInFile, raw: realFsPort.readFileUtf8(paths.chatgptSignInFile) },
|
|
9379
9496
|
installedClaudeVersions: realInstalledClaudeVersions(),
|
|
9380
9497
|
identities,
|
|
9381
9498
|
configProfiles,
|
|
@@ -9412,60 +9529,121 @@ function collectDoctorReport(params) {
|
|
|
9412
9529
|
}
|
|
9413
9530
|
|
|
9414
9531
|
// src/frontdoor/controlSchemas.ts
|
|
9415
|
-
var UsageListOutputSchema =
|
|
9416
|
-
var UsageWindowsInputSchema =
|
|
9417
|
-
identity:
|
|
9418
|
-
provider:
|
|
9532
|
+
var UsageListOutputSchema = import_zod19.z.strictObject({ snapshots: import_zod19.z.readonly(import_zod19.z.array(UsageSnapshotSchema)) });
|
|
9533
|
+
var UsageWindowsInputSchema = import_zod19.z.strictObject({
|
|
9534
|
+
identity: import_zod19.z.string().min(1),
|
|
9535
|
+
provider: import_zod19.z.string().min(1).optional()
|
|
9419
9536
|
});
|
|
9420
|
-
var EffectiveWindowSchema =
|
|
9537
|
+
var EffectiveWindowSchema = import_zod19.z.strictObject({
|
|
9421
9538
|
/** True when the window's reset time has passed, so the recorded observation describes a window that no longer exists. */
|
|
9422
|
-
reset:
|
|
9539
|
+
reset: import_zod19.z.boolean(),
|
|
9423
9540
|
/** The fraction used: 0 for a reset window, otherwise what was last observed, absent when none was reported. */
|
|
9424
|
-
utilization:
|
|
9541
|
+
utilization: import_zod19.z.number().optional(),
|
|
9425
9542
|
/** The reset instant, for a window that has not reset yet and reported one. */
|
|
9426
|
-
resetsAtMs:
|
|
9543
|
+
resetsAtMs: import_zod19.z.number().optional(),
|
|
9427
9544
|
/** The window's own status, for a window that has not reset yet. */
|
|
9428
|
-
status:
|
|
9545
|
+
status: import_zod19.z.string().optional()
|
|
9429
9546
|
});
|
|
9430
|
-
var UsageWindowsOutputSchema =
|
|
9431
|
-
identity:
|
|
9432
|
-
provider:
|
|
9547
|
+
var UsageWindowsOutputSchema = import_zod19.z.strictObject({
|
|
9548
|
+
identity: import_zod19.z.string(),
|
|
9549
|
+
provider: import_zod19.z.string(),
|
|
9433
9550
|
/** When the rate-limit state the windows come from was observed. */
|
|
9434
|
-
observedAt:
|
|
9551
|
+
observedAt: import_zod19.z.iso.datetime().optional(),
|
|
9435
9552
|
fiveHour: EffectiveWindowSchema.optional(),
|
|
9436
9553
|
sevenDay: EffectiveWindowSchema.optional()
|
|
9437
9554
|
});
|
|
9438
|
-
var FrontDoorSessionStatusSchema =
|
|
9439
|
-
pid:
|
|
9440
|
-
startedAt:
|
|
9441
|
-
alive:
|
|
9555
|
+
var FrontDoorSessionStatusSchema = import_zod19.z.strictObject({
|
|
9556
|
+
pid: import_zod19.z.int().positive(),
|
|
9557
|
+
startedAt: import_zod19.z.number(),
|
|
9558
|
+
alive: import_zod19.z.boolean()
|
|
9442
9559
|
});
|
|
9443
|
-
var HeadroomSocketTargetSchema =
|
|
9444
|
-
var FrontDoorStatusOutputSchema =
|
|
9560
|
+
var HeadroomSocketTargetSchema = import_zod19.z.union([import_zod19.z.strictObject({ socketPath: import_zod19.z.string() }), import_zod19.z.strictObject({ refused: import_zod19.z.string() })]);
|
|
9561
|
+
var FrontDoorStatusOutputSchema = import_zod19.z.strictObject({
|
|
9445
9562
|
state: FrontDoorStateSchema,
|
|
9446
|
-
supervisorAlive:
|
|
9447
|
-
sessions:
|
|
9563
|
+
supervisorAlive: import_zod19.z.boolean(),
|
|
9564
|
+
sessions: import_zod19.z.readonly(import_zod19.z.array(FrontDoorSessionStatusSchema)),
|
|
9448
9565
|
headroomSocket: HeadroomSocketTargetSchema.optional(),
|
|
9449
|
-
logPath:
|
|
9450
|
-
logExists:
|
|
9566
|
+
logPath: import_zod19.z.string(),
|
|
9567
|
+
logExists: import_zod19.z.boolean()
|
|
9451
9568
|
});
|
|
9452
|
-
var FrontDoorSessionsOutputSchema =
|
|
9453
|
-
var CheckRunInputSchema =
|
|
9454
|
-
path:
|
|
9455
|
-
identity:
|
|
9569
|
+
var FrontDoorSessionsOutputSchema = import_zod19.z.strictObject({ sessions: import_zod19.z.readonly(import_zod19.z.array(FrontDoorSessionStatusSchema)) });
|
|
9570
|
+
var CheckRunInputSchema = import_zod19.z.strictObject({
|
|
9571
|
+
path: import_zod19.z.string().min(1),
|
|
9572
|
+
identity: import_zod19.z.string().min(1).optional()
|
|
9456
9573
|
}).refine((input) => import_node_path27.default.isAbsolute(input.path), { message: "path must be absolute: the door cannot resolve a relative path against the caller's working directory" });
|
|
9457
|
-
var DoctorFindingSchema =
|
|
9458
|
-
section:
|
|
9459
|
-
subject:
|
|
9460
|
-
severity:
|
|
9461
|
-
message:
|
|
9574
|
+
var DoctorFindingSchema = import_zod19.z.strictObject({
|
|
9575
|
+
section: import_zod19.z.enum(DOCTOR_SECTIONS),
|
|
9576
|
+
subject: import_zod19.z.string().optional(),
|
|
9577
|
+
severity: import_zod19.z.enum(DOCTOR_SEVERITIES),
|
|
9578
|
+
message: import_zod19.z.string()
|
|
9462
9579
|
});
|
|
9463
|
-
var DoctorRunOutputSchema =
|
|
9580
|
+
var DoctorRunOutputSchema = import_zod19.z.strictObject({
|
|
9464
9581
|
/** False exactly when any finding is a `fail`; a `warn` never fails the report on its own. */
|
|
9465
|
-
ok:
|
|
9466
|
-
findings:
|
|
9582
|
+
ok: import_zod19.z.boolean(),
|
|
9583
|
+
findings: import_zod19.z.readonly(import_zod19.z.array(DoctorFindingSchema))
|
|
9584
|
+
});
|
|
9585
|
+
|
|
9586
|
+
// src/frontdoor/eventsApi.ts
|
|
9587
|
+
var import_client2 = require("@orpc/client");
|
|
9588
|
+
var import_server3 = require("@orpc/server");
|
|
9589
|
+
|
|
9590
|
+
// src/frontdoor/eventSchemas.ts
|
|
9591
|
+
var import_zod20 = require("zod");
|
|
9592
|
+
var DOOR_EVENT_SOURCE_RC = "rc";
|
|
9593
|
+
var LAUNCH_EVENT_SOURCE = "launch";
|
|
9594
|
+
var DoorEventSchema = import_zod20.z.strictObject({
|
|
9595
|
+
source: import_zod20.z.string().min(1),
|
|
9596
|
+
/** A positive integer because the backbone's counters start at one and only ever increase. */
|
|
9597
|
+
sequence: import_zod20.z.number().int().positive(),
|
|
9598
|
+
payload: import_zod20.z.unknown()
|
|
9599
|
+
});
|
|
9600
|
+
var DoorEventSourceQuerySchema = import_zod20.z.strictObject({
|
|
9601
|
+
sources: import_zod20.z.array(import_zod20.z.string().min(1)).min(1).optional()
|
|
9602
|
+
});
|
|
9603
|
+
var LaunchLifecycleEventSchema = import_zod20.z.strictObject({
|
|
9604
|
+
kind: import_zod20.z.enum(["registered", "pruned", "ended"]),
|
|
9605
|
+
pid: import_zod20.z.number().int().positive(),
|
|
9606
|
+
startedAt: import_zod20.z.number(),
|
|
9607
|
+
observedAt: import_zod20.z.number()
|
|
9467
9608
|
});
|
|
9468
9609
|
|
|
9610
|
+
// src/frontdoor/eventsApi.ts
|
|
9611
|
+
function createEventsApiRouter(deps) {
|
|
9612
|
+
const authed = doorApiAuth(deps.expectedToken);
|
|
9613
|
+
return {
|
|
9614
|
+
events: {
|
|
9615
|
+
subscribe: authed.input(DoorEventSourceQuerySchema).output((0, import_server3.eventIterator)(DoorEventSchema)).handler(async function* ({ input, signal }) {
|
|
9616
|
+
if (input.sources !== void 0) {
|
|
9617
|
+
const live = deps.events.sources();
|
|
9618
|
+
const unknown = input.sources.filter((source) => !live.includes(source));
|
|
9619
|
+
if (unknown.length > 0) {
|
|
9620
|
+
throw new import_client2.ORPCError("NOT_FOUND", { message: `the door publishes no event source named ${unknown.map((source) => `"${source}"`).join(", ")}; the live sources are ${live.map((source) => `"${source}"`).join(", ")}` });
|
|
9621
|
+
}
|
|
9622
|
+
}
|
|
9623
|
+
const stream = deps.events.stream(input.sources);
|
|
9624
|
+
const ended = new Promise((resolve) => {
|
|
9625
|
+
signal?.addEventListener("abort", () => {
|
|
9626
|
+
resolve();
|
|
9627
|
+
}, { once: true });
|
|
9628
|
+
});
|
|
9629
|
+
try {
|
|
9630
|
+
for (; ; ) {
|
|
9631
|
+
signal?.throwIfAborted();
|
|
9632
|
+
const next = await Promise.race([stream.next(), ended.then(() => ({ value: void 0, done: true }))]);
|
|
9633
|
+
if (next.done === true) {
|
|
9634
|
+
signal?.throwIfAborted();
|
|
9635
|
+
return;
|
|
9636
|
+
}
|
|
9637
|
+
yield (0, import_server3.withEventMeta)(next.value, { id: String(next.value.sequence) });
|
|
9638
|
+
}
|
|
9639
|
+
} finally {
|
|
9640
|
+
stream.close();
|
|
9641
|
+
}
|
|
9642
|
+
})
|
|
9643
|
+
}
|
|
9644
|
+
};
|
|
9645
|
+
}
|
|
9646
|
+
|
|
9469
9647
|
// src/frontdoor/controlApi.ts
|
|
9470
9648
|
function createControlApiRouter(deps) {
|
|
9471
9649
|
const authed = doorApiAuth(deps.expectedToken);
|
|
@@ -9475,7 +9653,7 @@ function createControlApiRouter(deps) {
|
|
|
9475
9653
|
effectiveWindow: authed.input(UsageWindowsInputSchema).output(UsageWindowsOutputSchema).handler(({ input }) => {
|
|
9476
9654
|
const snapshot = deps.usageSnapshotOf(input.identity);
|
|
9477
9655
|
if (snapshot === void 0) {
|
|
9478
|
-
throw new
|
|
9656
|
+
throw new import_client3.ORPCError("NOT_FOUND", { message: `identity ${input.identity} has no usage snapshot yet, so no quota window has been observed for it` });
|
|
9479
9657
|
}
|
|
9480
9658
|
const provider = input.provider ?? ANTHROPIC_PROVIDER;
|
|
9481
9659
|
const rateLimit = snapshot.providers[provider]?.rateLimit;
|
|
@@ -9504,13 +9682,13 @@ function createControlApiRouter(deps) {
|
|
|
9504
9682
|
};
|
|
9505
9683
|
}
|
|
9506
9684
|
function createDoorApiRouter(deps) {
|
|
9507
|
-
return { ...createRcApiRouter(deps), ...createControlApiRouter(deps) };
|
|
9685
|
+
return { ...createRcApiRouter(deps), ...createControlApiRouter(deps), ...createEventsApiRouter(deps) };
|
|
9508
9686
|
}
|
|
9509
9687
|
function createDoorApiNodeHandler(deps) {
|
|
9510
9688
|
return doorApiNodeHandlerOf(createDoorApiRouter(deps));
|
|
9511
9689
|
}
|
|
9512
9690
|
function frontDoorApiClient(port, ca, token) {
|
|
9513
|
-
return (0,
|
|
9691
|
+
return (0, import_client3.createORPCClient)(frontDoorApiLink(port, ca, token));
|
|
9514
9692
|
}
|
|
9515
9693
|
|
|
9516
9694
|
// src/frontdoor/status.ts
|
|
@@ -9566,6 +9744,148 @@ function formatFrontDoorStatus(status, caCertPath) {
|
|
|
9566
9744
|
return lines;
|
|
9567
9745
|
}
|
|
9568
9746
|
|
|
9747
|
+
// src/frontdoor/eventHub.ts
|
|
9748
|
+
var DOOR_EVENT_BUFFER_EVENTS = 100;
|
|
9749
|
+
function createDoorEventHub() {
|
|
9750
|
+
const sequences = /* @__PURE__ */ new Map();
|
|
9751
|
+
const registered = /* @__PURE__ */ new Set();
|
|
9752
|
+
const every = /* @__PURE__ */ new Set();
|
|
9753
|
+
const bySource = /* @__PURE__ */ new Map();
|
|
9754
|
+
const deliver = (event) => {
|
|
9755
|
+
for (const listener of every) {
|
|
9756
|
+
listener(event);
|
|
9757
|
+
}
|
|
9758
|
+
for (const listener of bySource.get(event.source) ?? []) {
|
|
9759
|
+
listener(event);
|
|
9760
|
+
}
|
|
9761
|
+
};
|
|
9762
|
+
const publish = (source, payload) => {
|
|
9763
|
+
const sequence2 = (sequences.get(source) ?? 0) + 1;
|
|
9764
|
+
sequences.set(source, sequence2);
|
|
9765
|
+
deliver({ source, sequence: sequence2, payload });
|
|
9766
|
+
};
|
|
9767
|
+
const addListener = (sources, listener) => {
|
|
9768
|
+
if (sources === void 0) {
|
|
9769
|
+
every.add(listener);
|
|
9770
|
+
return () => {
|
|
9771
|
+
every.delete(listener);
|
|
9772
|
+
};
|
|
9773
|
+
}
|
|
9774
|
+
const listenersFor = (source) => {
|
|
9775
|
+
const listeners = bySource.get(source) ?? /* @__PURE__ */ new Set();
|
|
9776
|
+
bySource.set(source, listeners);
|
|
9777
|
+
return listeners;
|
|
9778
|
+
};
|
|
9779
|
+
const detachers = sources.map((source) => {
|
|
9780
|
+
const listeners = listenersFor(source);
|
|
9781
|
+
listeners.add(listener);
|
|
9782
|
+
return () => {
|
|
9783
|
+
listeners.delete(listener);
|
|
9784
|
+
if (listeners.size === 0) {
|
|
9785
|
+
bySource.delete(source);
|
|
9786
|
+
}
|
|
9787
|
+
};
|
|
9788
|
+
});
|
|
9789
|
+
return () => {
|
|
9790
|
+
for (const detach of detachers) {
|
|
9791
|
+
detach();
|
|
9792
|
+
}
|
|
9793
|
+
};
|
|
9794
|
+
};
|
|
9795
|
+
return {
|
|
9796
|
+
publisher: (source) => {
|
|
9797
|
+
registered.add(source);
|
|
9798
|
+
return {
|
|
9799
|
+
source,
|
|
9800
|
+
publish: (payload) => {
|
|
9801
|
+
publish(source, payload);
|
|
9802
|
+
}
|
|
9803
|
+
};
|
|
9804
|
+
},
|
|
9805
|
+
subscribe: addListener,
|
|
9806
|
+
stream: (sources) => {
|
|
9807
|
+
const queue = [];
|
|
9808
|
+
let wake;
|
|
9809
|
+
let closed = false;
|
|
9810
|
+
const detach = addListener(sources, (event) => {
|
|
9811
|
+
if (queue.length >= DOOR_EVENT_BUFFER_EVENTS) {
|
|
9812
|
+
queue.shift();
|
|
9813
|
+
}
|
|
9814
|
+
queue.push(event);
|
|
9815
|
+
wake?.();
|
|
9816
|
+
});
|
|
9817
|
+
return {
|
|
9818
|
+
next: async () => {
|
|
9819
|
+
for (; ; ) {
|
|
9820
|
+
const event = queue.shift();
|
|
9821
|
+
if (event !== void 0) {
|
|
9822
|
+
return { value: event, done: false };
|
|
9823
|
+
}
|
|
9824
|
+
if (closed) {
|
|
9825
|
+
return { value: void 0, done: true };
|
|
9826
|
+
}
|
|
9827
|
+
await new Promise((resolve) => {
|
|
9828
|
+
wake = resolve;
|
|
9829
|
+
});
|
|
9830
|
+
}
|
|
9831
|
+
},
|
|
9832
|
+
close: () => {
|
|
9833
|
+
closed = true;
|
|
9834
|
+
detach();
|
|
9835
|
+
wake?.();
|
|
9836
|
+
}
|
|
9837
|
+
};
|
|
9838
|
+
},
|
|
9839
|
+
sources: () => [...registered].sort()
|
|
9840
|
+
};
|
|
9841
|
+
}
|
|
9842
|
+
function rcFanoutOnDoorHub(fanout, hub) {
|
|
9843
|
+
const publisher = hub.publisher(DOOR_EVENT_SOURCE_RC);
|
|
9844
|
+
return {
|
|
9845
|
+
publish: (event) => {
|
|
9846
|
+
fanout.publish(event);
|
|
9847
|
+
publisher.publish(event);
|
|
9848
|
+
},
|
|
9849
|
+
subscribe: (session, listener) => fanout.subscribe(session, listener)
|
|
9850
|
+
};
|
|
9851
|
+
}
|
|
9852
|
+
|
|
9853
|
+
// src/frontdoor/launchEvents.ts
|
|
9854
|
+
function createLaunchEventPublisher(hub, now) {
|
|
9855
|
+
const publisher = hub.publisher(LAUNCH_EVENT_SOURCE);
|
|
9856
|
+
let known;
|
|
9857
|
+
return {
|
|
9858
|
+
observe: (sessions, pruned) => {
|
|
9859
|
+
const previous = known;
|
|
9860
|
+
const listed = new Map(sessions.map((session) => [session.pid, session]));
|
|
9861
|
+
const prunedSet = new Set(pruned);
|
|
9862
|
+
known = new Map([...listed].filter(([pid]) => !prunedSet.has(pid)));
|
|
9863
|
+
if (previous === void 0) {
|
|
9864
|
+
return;
|
|
9865
|
+
}
|
|
9866
|
+
const emit = (kind, pid, startedAt) => {
|
|
9867
|
+
publisher.publish({ kind, pid, startedAt, observedAt: now() });
|
|
9868
|
+
};
|
|
9869
|
+
for (const pid of pruned) {
|
|
9870
|
+
const session = listed.get(pid);
|
|
9871
|
+
if (session !== void 0) {
|
|
9872
|
+
emit("pruned", pid, session.startedAt);
|
|
9873
|
+
}
|
|
9874
|
+
}
|
|
9875
|
+
for (const [pid, session] of previous) {
|
|
9876
|
+
if (!listed.has(pid) && !prunedSet.has(pid)) {
|
|
9877
|
+
emit("ended", pid, session.startedAt);
|
|
9878
|
+
}
|
|
9879
|
+
}
|
|
9880
|
+
for (const [pid, session] of listed) {
|
|
9881
|
+
if (!previous.has(pid) && !prunedSet.has(pid)) {
|
|
9882
|
+
emit("registered", pid, session.startedAt);
|
|
9883
|
+
}
|
|
9884
|
+
}
|
|
9885
|
+
}
|
|
9886
|
+
};
|
|
9887
|
+
}
|
|
9888
|
+
|
|
9569
9889
|
// src/frontdoor/rcStream.ts
|
|
9570
9890
|
var RC_STREAM_EVENT_NAME = "client_event";
|
|
9571
9891
|
var SSE_BYTE_ORDER_MARK = 65279;
|
|
@@ -11652,6 +11972,8 @@ function prepareClaudeLaunch(options) {
|
|
|
11652
11972
|
CredentialCacheSchema,
|
|
11653
11973
|
CredentialSchema,
|
|
11654
11974
|
CredentialSourceSchema,
|
|
11975
|
+
DOOR_EVENT_BUFFER_EVENTS,
|
|
11976
|
+
DOOR_EVENT_SOURCE_RC,
|
|
11655
11977
|
DirectoryRuleAlreadyExistsError,
|
|
11656
11978
|
DirectoryRuleMissingTargetError,
|
|
11657
11979
|
DirectoryRuleNotFoundError,
|
|
@@ -11659,6 +11981,8 @@ function prepareClaudeLaunch(options) {
|
|
|
11659
11981
|
DirectoryRulesSchema,
|
|
11660
11982
|
DoctorFindingSchema,
|
|
11661
11983
|
DoctorRunOutputSchema,
|
|
11984
|
+
DoorEventSchema,
|
|
11985
|
+
DoorEventSourceQuerySchema,
|
|
11662
11986
|
EXIT_FAILURE,
|
|
11663
11987
|
EXIT_USAGE,
|
|
11664
11988
|
EffectiveWindowSchema,
|
|
@@ -11678,6 +12002,8 @@ function prepareClaudeLaunch(options) {
|
|
|
11678
12002
|
InvalidCategoryNameError,
|
|
11679
12003
|
InvalidIdentityNameError,
|
|
11680
12004
|
InvalidProviderNameError,
|
|
12005
|
+
LAUNCH_EVENT_SOURCE,
|
|
12006
|
+
LaunchLifecycleEventSchema,
|
|
11681
12007
|
LaunchRefusedError,
|
|
11682
12008
|
LegacyProviderFileError,
|
|
11683
12009
|
PROMPT_CACHE_TTL_MS,
|
|
@@ -11741,6 +12067,9 @@ function prepareClaudeLaunch(options) {
|
|
|
11741
12067
|
createControlApiRouter,
|
|
11742
12068
|
createDoorApiNodeHandler,
|
|
11743
12069
|
createDoorApiRouter,
|
|
12070
|
+
createDoorEventHub,
|
|
12071
|
+
createEventsApiRouter,
|
|
12072
|
+
createLaunchEventPublisher,
|
|
11744
12073
|
createLeafCache,
|
|
11745
12074
|
createProfile,
|
|
11746
12075
|
createRcApiNodeHandler,
|
|
@@ -11799,6 +12128,7 @@ function prepareClaudeLaunch(options) {
|
|
|
11799
12128
|
providerExists,
|
|
11800
12129
|
rankPool,
|
|
11801
12130
|
rcEventWriteResultFromAnswer,
|
|
12131
|
+
rcFanoutOnDoorHub,
|
|
11802
12132
|
rcObserverAsPassthrough,
|
|
11803
12133
|
rcSelfHostFromEnv,
|
|
11804
12134
|
readActiveIdentity,
|