claude-use 9.6.0 → 9.7.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/dist/index.mjs CHANGED
@@ -209,7 +209,7 @@ function isCodexProvider(provider) {
209
209
  function poolMemberIdentity(member) {
210
210
  return typeof member === "string" ? member : member.identity;
211
211
  }
212
- var CATEGORY_NAMES, OVERRIDABLE_CATEGORIES, CategoryMapSchema, DURATION_RE, DurationSchema, WhenConditionObjectSchema, WhenSchema, EntryValueSchema, ENTRY_KEY_RE, EntriesSchema, LaunchSchema, CREDENTIAL_TARGETS, PROVIDER_CREDENTIAL_TARGETS, CREDENTIAL_TARGET_VARS, ArgvSchema, CommandSourceOptions, CredentialSourceSchema, CREDENTIAL_CACHE_STORES, CredentialCacheSchema, CredentialSchema, ProviderCredentialSchema, RESERVED_PROVIDER_ENV_KEYS, ProviderEnvSchema, CODEX_EFFORTS, CODEX_LOGINS, CODEX_DEFAULT_TIER_MODELS, CodexProviderConfigSchema, ProviderRouteSchema, HttpProviderSchema, CodexProviderSchema, ProviderSchema, ConfigProfileSchema, POOL_SELECTOR_PREFIX, POOL_NAME_PATTERN, IDENTITY_NAME_PATTERN, PoolNameSchema, SELECTOR_RE, IdentitySelectorSchema, PoolMemberSchema, POOL_PREFERENCES, PoolPreferenceSchema, PoolSchema, DirectoryRuleSchema, DirectoryRulesSchema, PortableConfigSchema, HEADROOM_MODES, HEADROOM_CCR_MODES, HEADROOM_ROLLOUT_CHANNELS, INTERCEPT_CHANNELS, READ_MATURATION_CHANNELS, HeadroomGlobalConfigObjectSchema, HeadroomGlobalConfigSchema, HEADROOM_DEFAULT_SOURCE, HEADROOM_DEFAULT_IDLE_SHUTDOWN_MINUTES, FrontDoorGlobalConfigSchema, UPDATE_MODES, UpdateGlobalConfigSchema, GlobalConfigSchema, IdentitySchema, CategoryClassificationSchema, CategoryClassificationOverlaySchema, SHIPPED_CATEGORY_DEFAULTS;
212
+ var CATEGORY_NAMES, OVERRIDABLE_CATEGORIES, CategoryMapSchema, DURATION_RE, DurationSchema, WhenConditionObjectSchema, WhenSchema, EntryValueSchema, ENTRY_KEY_RE, EntriesSchema, LaunchSchema, CREDENTIAL_TARGETS, PROVIDER_CREDENTIAL_TARGETS, CREDENTIAL_TARGET_VARS, ArgvSchema, CommandSourceOptions, EnvCredentialSourceSchema, FileCredentialSourceSchema, CommandCredentialSourceSchema, OpCredentialSourceSchema, KeychainCredentialSourceSchema, LiteralCredentialSourceSchema, CredentialSourceSchema, RemoteCredentialSourceSchema, CREDENTIAL_CACHE_STORES, CredentialCacheSchema, CredentialSchema, ProviderCredentialSchema, RESERVED_PROVIDER_ENV_KEYS, ProviderEnvSchema, PROVIDER_KINDS, CODEX_EFFORTS, CODEX_LOGINS, CODEX_DEFAULT_TIER_MODELS, CodexProviderConfigSchema, ProviderRouteSchema, HttpProviderSchema, CodexProviderSchema, ProviderSchema, ConfigProfileSchema, POOL_SELECTOR_PREFIX, POOL_NAME_PATTERN, IDENTITY_NAME_PATTERN, PoolNameSchema, SELECTOR_RE, IdentitySelectorSchema, PoolMemberSchema, POOL_PREFERENCES, PoolPreferenceSchema, PoolSchema, DirectoryRuleSchema, DirectoryRulesSchema, PortableConfigSchema, HEADROOM_MODES, HEADROOM_CCR_MODES, HEADROOM_ROLLOUT_CHANNELS, INTERCEPT_CHANNELS, READ_MATURATION_CHANNELS, HeadroomGlobalConfigObjectSchema, HeadroomGlobalConfigSchema, HEADROOM_DEFAULT_SOURCE, HEADROOM_DEFAULT_IDLE_SHUTDOWN_MINUTES, FrontDoorGlobalConfigSchema, UPDATE_MODES, UpdateGlobalConfigSchema, GlobalConfigSchema, IdentitySchema, CategoryClassificationSchema, CategoryClassificationOverlaySchema, SHIPPED_CATEGORY_DEFAULTS;
213
213
  var init_schema = __esm({
214
214
  "src/config/schema.ts"() {
215
215
  "use strict";
@@ -262,20 +262,33 @@ var init_schema = __esm({
262
262
  /** How long the command may run before it is killed and counted as failed. Defaults to `CREDENTIAL_COMMAND_TIMEOUT_MS`, or `CREDENTIAL_INTERACTIVE_TIMEOUT_MS` for an interactive source. */
263
263
  timeoutMs: z.int().positive().optional()
264
264
  };
265
+ EnvCredentialSourceSchema = z.strictObject({ env: z.string().min(1) });
266
+ FileCredentialSourceSchema = z.strictObject({
267
+ file: z.string().min(1).refine((filePath) => filePath.startsWith("~/") || path2.isAbsolute(filePath), {
268
+ message: "a credential file must be an absolute or ~-rooted path, since a launch can start in any directory"
269
+ })
270
+ });
271
+ CommandCredentialSourceSchema = z.strictObject({ command: ArgvSchema, ...CommandSourceOptions });
272
+ OpCredentialSourceSchema = z.strictObject({ op: z.string().startsWith("op://"), ...CommandSourceOptions });
273
+ KeychainCredentialSourceSchema = z.strictObject({
274
+ keychain: z.strictObject({ service: z.string().min(1), account: z.string().min(1).optional() }),
275
+ ...CommandSourceOptions
276
+ });
277
+ LiteralCredentialSourceSchema = z.strictObject({ literal: z.string().min(1) });
265
278
  CredentialSourceSchema = z.union([
266
- z.strictObject({ env: z.string().min(1) }),
267
- z.strictObject({
268
- file: z.string().min(1).refine((filePath) => filePath.startsWith("~/") || path2.isAbsolute(filePath), {
269
- message: "a credential file must be an absolute or ~-rooted path, since a launch can start in any directory"
270
- })
271
- }),
272
- z.strictObject({ command: ArgvSchema, ...CommandSourceOptions }),
273
- z.strictObject({ op: z.string().startsWith("op://"), ...CommandSourceOptions }),
274
- z.strictObject({
275
- keychain: z.strictObject({ service: z.string().min(1), account: z.string().min(1).optional() }),
276
- ...CommandSourceOptions
277
- }),
278
- z.strictObject({ literal: z.string().min(1) })
279
+ EnvCredentialSourceSchema,
280
+ FileCredentialSourceSchema,
281
+ CommandCredentialSourceSchema,
282
+ OpCredentialSourceSchema,
283
+ KeychainCredentialSourceSchema,
284
+ LiteralCredentialSourceSchema
285
+ ]);
286
+ RemoteCredentialSourceSchema = z.union([
287
+ EnvCredentialSourceSchema,
288
+ FileCredentialSourceSchema,
289
+ OpCredentialSourceSchema,
290
+ KeychainCredentialSourceSchema,
291
+ LiteralCredentialSourceSchema
279
292
  ]);
280
293
  CREDENTIAL_CACHE_STORES = ["keychain", "file"];
281
294
  CredentialCacheSchema = z.strictObject({
@@ -292,6 +305,7 @@ var init_schema = __esm({
292
305
  ProviderEnvSchema = z.record(z.string().min(1), z.string()).refine((env) => !Object.keys(env).some((key) => RESERVED_PROVIDER_ENV_KEYS.includes(key)), {
293
306
  message: `env may not set ${RESERVED_PROVIDER_ENV_KEYS.join(", ")}: the credential block's target sets one and agent-shim removes the others`
294
307
  });
308
+ PROVIDER_KINDS = ["http", "codex"];
295
309
  CODEX_EFFORTS = ["none", "low", "medium", "high"];
296
310
  CODEX_LOGINS = ["codex-cli", "chatgpt-sign-in"];
297
311
  CODEX_DEFAULT_TIER_MODELS = Object.freeze({
@@ -2625,7 +2639,7 @@ var init_package = __esm({
2625
2639
  "package.json"() {
2626
2640
  package_default = {
2627
2641
  name: "claude-use",
2628
- version: "9.6.0",
2642
+ version: "9.7.0",
2629
2643
  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.",
2630
2644
  license: "MIT",
2631
2645
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -3028,8 +3042,8 @@ function verifyHeadroomSocket(socketPath, ports) {
3028
3042
  }
3029
3043
  const uid = ports.currentUid();
3030
3044
  const directory = path12.dirname(socketPath);
3031
- const refusal = ownerOnlyRefusal("socket directory", directory, ports.lstat(directory), "dir", uid) ?? ownerOnlyRefusal("socket", socketPath, ports.lstat(socketPath), "socket", uid);
3032
- return refusal === void 0 ? { socketPath } : { refused: refusal };
3045
+ const refusal2 = ownerOnlyRefusal("socket directory", directory, ports.lstat(directory), "dir", uid) ?? ownerOnlyRefusal("socket", socketPath, ports.lstat(socketPath), "socket", uid);
3046
+ return refusal2 === void 0 ? { socketPath } : { refused: refusal2 };
3033
3047
  }
3034
3048
  function prepareHeadroomSocket(fs12, ports, paths, supervisorPid) {
3035
3049
  const unsupported = platformRefusal(ports.platform);
@@ -3047,8 +3061,8 @@ function prepareHeadroomSocket(fs12, ports, paths, supervisorPid) {
3047
3061
  return { refused: `the headroom socket directory ${paths.headroomSocketDir} is a symlink; it must be the real directory` };
3048
3062
  }
3049
3063
  fs12.mkdirPrivate(paths.headroomSocketDir);
3050
- const refusal = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
3051
- return refusal === void 0 ? { socketPath } : { refused: refusal };
3064
+ const refusal2 = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
3065
+ return refusal2 === void 0 ? { socketPath } : { refused: refusal2 };
3052
3066
  }
3053
3067
  function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
3054
3068
  const removed = [];
@@ -4560,14 +4574,14 @@ function capacityOf(plan) {
4560
4574
  return plan.kind === "subscription" ? plan.capacity : 1;
4561
4575
  }
4562
4576
  function assessRefusedNested(member, nested, nowMs) {
4563
- const refusal = nested.earliestReturn === void 0 ? { reason: `no member of pool "${nested.pool}" can be picked` } : { reason: `every member of pool "${nested.pool}" is refused; ${nested.earliestReturn.identity} returns at ${new Date(nested.earliestReturn.atMs).toISOString()} (in ${formatAge(nested.earliestReturn.atMs - nowMs)})`, blockedUntilMs: nested.earliestReturn.atMs };
4577
+ const refusal2 = nested.earliestReturn === void 0 ? { reason: `no member of pool "${nested.pool}" can be picked` } : { reason: `every member of pool "${nested.pool}" is refused; ${nested.earliestReturn.identity} returns at ${new Date(nested.earliestReturn.atMs).toISOString()} (in ${formatAge(nested.earliestReturn.atMs - nowMs)})`, blockedUntilMs: nested.earliestReturn.atMs };
4564
4578
  return {
4565
4579
  candidate: {
4566
4580
  identity: member.identity,
4567
4581
  class: "ineligible",
4568
- ...refusal.blockedUntilMs === void 0 ? {} : { blockedUntilMs: refusal.blockedUntilMs },
4582
+ ...refusal2.blockedUntilMs === void 0 ? {} : { blockedUntilMs: refusal2.blockedUntilMs },
4569
4583
  plan: planOf(member.account),
4570
- reasons: [refusal.reason]
4584
+ reasons: [refusal2.reason]
4571
4585
  }
4572
4586
  };
4573
4587
  }
@@ -4658,7 +4672,7 @@ function rankPool(input) {
4658
4672
  const assessments = members.map((member) => ({ member, ...assess(member, nowMs) }));
4659
4673
  const demands = assessments.flatMap(({ candidate, burn }) => burn === void 0 ? [] : [burn * capacityOf(candidate.plan)]);
4660
4674
  const sharedDemand = demands.length === 0 ? void 0 : Math.max(...demands);
4661
- const guarded = assessments.map((assessment) => {
4675
+ const guarded2 = assessments.map((assessment) => {
4662
4676
  const { candidate } = assessment;
4663
4677
  if (candidate.class === "ineligible" || assessment.member.policy === void 0) {
4664
4678
  return assessment;
@@ -4673,7 +4687,7 @@ function rankPool(input) {
4673
4687
  }
4674
4688
  return { ...assessment, candidate: { ...candidate, class: "ineligible", reasons: [`skipped by policy (${verdict.checked.join(", ")}: did not hold)`, ...candidate.reasons] } };
4675
4689
  });
4676
- const candidates = guarded.map((assessment) => {
4690
+ const candidates = guarded2.map((assessment) => {
4677
4691
  const { candidate, fiveHour, burn } = assessment;
4678
4692
  const pace = burn ?? (sharedDemand === void 0 ? void 0 : sharedDemand / capacityOf(candidate.plan));
4679
4693
  const { sevenDay, sevenDayBurn } = assessment;
@@ -7669,7 +7683,7 @@ var init_anthropicUsageRefresh = __esm({
7669
7683
  });
7670
7684
 
7671
7685
  // src/usage/providerQuota.ts
7672
- import { z as z22 } from "zod";
7686
+ import { z as z23 } from "zod";
7673
7687
  var MS_PER_SECOND7, SECONDS_PER_HOUR, HOURS_PER_DAY3, DAYS_PER_MONTH, ZAI_HOST, ZAI_QUOTA_URL, ZAI_UNIT_HOURS, ZAI_UNIT_MONTHS, ZAI_UNIT_MS, ZaiLimitSchema, ZaiResponseSchema, OPENROUTER_HOST, OPENROUTER_KEY_URL, OPENROUTER_CREDITS_URL, MS_PER_DAY3, OpenRouterKeySchema, OpenRouterCreditsSchema;
7674
7688
  var init_providerQuota = __esm({
7675
7689
  "src/usage/providerQuota.ts"() {
@@ -7687,35 +7701,35 @@ var init_providerQuota = __esm({
7687
7701
  [ZAI_UNIT_HOURS, SECONDS_PER_HOUR * MS_PER_SECOND7],
7688
7702
  [ZAI_UNIT_MONTHS, DAYS_PER_MONTH * HOURS_PER_DAY3 * SECONDS_PER_HOUR * MS_PER_SECOND7]
7689
7703
  ]);
7690
- ZaiLimitSchema = z22.object({
7691
- type: z22.string(),
7692
- unit: z22.number().int(),
7693
- number: z22.number().int().positive(),
7694
- percentage: z22.number().nonnegative(),
7695
- nextResetTime: z22.number().positive().optional(),
7696
- usage: z22.number().nonnegative().optional(),
7697
- currentValue: z22.number().nonnegative().optional(),
7698
- remaining: z22.number().nonnegative().optional()
7704
+ ZaiLimitSchema = z23.object({
7705
+ type: z23.string(),
7706
+ unit: z23.number().int(),
7707
+ number: z23.number().int().positive(),
7708
+ percentage: z23.number().nonnegative(),
7709
+ nextResetTime: z23.number().positive().optional(),
7710
+ usage: z23.number().nonnegative().optional(),
7711
+ currentValue: z23.number().nonnegative().optional(),
7712
+ remaining: z23.number().nonnegative().optional()
7699
7713
  });
7700
- ZaiResponseSchema = z22.object({
7701
- success: z22.boolean(),
7702
- msg: z22.string().optional(),
7703
- data: z22.object({ level: z22.string().optional(), limits: z22.array(ZaiLimitSchema) })
7714
+ ZaiResponseSchema = z23.object({
7715
+ success: z23.boolean(),
7716
+ msg: z23.string().optional(),
7717
+ data: z23.object({ level: z23.string().optional(), limits: z23.array(ZaiLimitSchema) })
7704
7718
  });
7705
7719
  OPENROUTER_HOST = "openrouter.ai";
7706
7720
  OPENROUTER_KEY_URL = `https://${OPENROUTER_HOST}/api/v1/key`;
7707
7721
  OPENROUTER_CREDITS_URL = `https://${OPENROUTER_HOST}/api/v1/credits`;
7708
7722
  MS_PER_DAY3 = HOURS_PER_DAY3 * SECONDS_PER_HOUR * MS_PER_SECOND7;
7709
- OpenRouterKeySchema = z22.object({
7710
- data: z22.object({
7711
- limit: z22.number().nonnegative().nullable(),
7712
- limit_remaining: z22.number().nullable(),
7713
- limit_reset: z22.string().nullable(),
7714
- is_free_tier: z22.boolean().optional(),
7715
- free_model_daily_requests: z22.object({ used: z22.number().nonnegative(), limit: z22.number().nonnegative(), remaining: z22.number() }).optional()
7723
+ OpenRouterKeySchema = z23.object({
7724
+ data: z23.object({
7725
+ limit: z23.number().nonnegative().nullable(),
7726
+ limit_remaining: z23.number().nullable(),
7727
+ limit_reset: z23.string().nullable(),
7728
+ is_free_tier: z23.boolean().optional(),
7729
+ free_model_daily_requests: z23.object({ used: z23.number().nonnegative(), limit: z23.number().nonnegative(), remaining: z23.number() }).optional()
7716
7730
  })
7717
7731
  });
7718
- OpenRouterCreditsSchema = z22.object({ data: z22.object({ total_credits: z22.number().nonnegative(), total_usage: z22.number().nonnegative() }) });
7732
+ OpenRouterCreditsSchema = z23.object({ data: z23.object({ total_credits: z23.number().nonnegative(), total_usage: z23.number().nonnegative() }) });
7719
7733
  }
7720
7734
  });
7721
7735
 
@@ -8693,6 +8707,7 @@ var HTTP_STATUS = {
8693
8707
  forbidden: 403,
8694
8708
  notFound: 404,
8695
8709
  methodNotAllowed: 405,
8710
+ conflict: 409,
8696
8711
  payloadTooLarge: 413,
8697
8712
  tooManyRequests: 429,
8698
8713
  /** Not sent to anyone: the client is gone. Recorded for a response abandoned because the client disconnected, following the convention nginx uses for the same case. */
@@ -10818,9 +10833,9 @@ function doorApiNodeHandlerOf(router, expectedToken) {
10818
10833
  if (request4.method === "GET" && request4.url === `${RC_ORPC_PATH_PREFIX}${RC_OPENAPI_DOC_PATH}`) {
10819
10834
  const token = doorApiBearer(request4.headers);
10820
10835
  if (token === void 0 || !isLiveCapability(token, [expectedToken])) {
10821
- const refusal = new ORPCError("UNAUTHORIZED", { message: "the front door's OpenAPI document demands this generation's control token as a Bearer credential" });
10836
+ const refusal2 = new ORPCError("UNAUTHORIZED", { message: "the front door's OpenAPI document demands this generation's control token as a Bearer credential" });
10822
10837
  response.writeHead(HTTP_STATUS.unauthorized, { "content-type": "application/json" });
10823
- response.end(JSON.stringify(refusal.toJSON()));
10838
+ response.end(JSON.stringify(refusal2.toJSON()));
10824
10839
  return { matched: true };
10825
10840
  }
10826
10841
  try {
@@ -10828,9 +10843,9 @@ function doorApiNodeHandlerOf(router, expectedToken) {
10828
10843
  response.writeHead(HTTP_STATUS.ok, { "content-type": "application/json" });
10829
10844
  response.end(JSON.stringify(doc));
10830
10845
  } catch (error) {
10831
- const refusal = new ORPCError("INTERNAL_SERVER_ERROR", { message: `the OpenAPI document could not be generated from the door's own router: ${error instanceof Error ? error.message : String(error)}` });
10846
+ const refusal2 = new ORPCError("INTERNAL_SERVER_ERROR", { message: `the OpenAPI document could not be generated from the door's own router: ${error instanceof Error ? error.message : String(error)}` });
10832
10847
  response.writeHead(HTTP_STATUS.internalServerError, { "content-type": "application/json" });
10833
- response.end(JSON.stringify(refusal.toJSON()));
10848
+ response.end(JSON.stringify(refusal2.toJSON()));
10834
10849
  }
10835
10850
  return { matched: true };
10836
10851
  }
@@ -10879,8 +10894,8 @@ init_cliError();
10879
10894
  init_realPorts();
10880
10895
 
10881
10896
  // src/frontdoor/controlApi.ts
10882
- import { createORPCClient as createORPCClient2, ORPCError as ORPCError5 } from "@orpc/client";
10883
- import { openapi as openapi6 } from "@orpc/openapi";
10897
+ import { createORPCClient as createORPCClient2, ORPCError as ORPCError6 } from "@orpc/client";
10898
+ import { openapi as openapi7 } from "@orpc/openapi";
10884
10899
 
10885
10900
  // src/checkReport.ts
10886
10901
  init_classify();
@@ -11064,6 +11079,48 @@ function removeProfile(paths, name) {
11064
11079
  requireProfileExists(paths, name);
11065
11080
  fs4.rmSync(profileJsonPath(paths, name));
11066
11081
  }
11082
+ function applyProfileChange(paths, name, change) {
11083
+ let touched = false;
11084
+ if (change.category !== void 0) {
11085
+ setProfileCategories(paths, name, change.category);
11086
+ touched = true;
11087
+ }
11088
+ if (change.entry !== void 0) {
11089
+ setProfileEntries(paths, name, change.entry);
11090
+ touched = true;
11091
+ }
11092
+ if (change.extends !== void 0 || change.description !== void 0) {
11093
+ setProfileMetadata(paths, name, {
11094
+ ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
11095
+ ...change.description === void 0 ? {} : { description: change.description }
11096
+ });
11097
+ touched = true;
11098
+ }
11099
+ const launchPatch = {};
11100
+ if (change.launchSkipPermissions !== void 0) {
11101
+ launchPatch.skipPermissions = change.launchSkipPermissions;
11102
+ }
11103
+ if (change.launchRemoteControl !== void 0) {
11104
+ launchPatch.remoteControl = change.launchRemoteControl;
11105
+ }
11106
+ if (change.launchHeadroom !== void 0) {
11107
+ launchPatch.headroom = change.launchHeadroom;
11108
+ }
11109
+ if (change.launchTrackUsage !== void 0) {
11110
+ launchPatch.trackUsage = change.launchTrackUsage;
11111
+ }
11112
+ if (change.launchProvider !== void 0) {
11113
+ launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
11114
+ }
11115
+ if (change.launchClaudeVersion !== void 0) {
11116
+ launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
11117
+ }
11118
+ if (Object.keys(launchPatch).length > 0) {
11119
+ setProfileLaunchFlags(paths, name, launchPatch);
11120
+ touched = true;
11121
+ }
11122
+ return touched;
11123
+ }
11067
11124
 
11068
11125
  // src/poolStore.ts
11069
11126
  init_store();
@@ -11837,6 +11894,14 @@ var InvalidIdentityNameError = class extends CliError {
11837
11894
  function identityJsonPath(paths, name) {
11838
11895
  return path27.join(paths.identitiesDir, name, "identity.json");
11839
11896
  }
11897
+ function requireIdentityNames(paths, names) {
11898
+ const existing = new Set(listIdentities(paths).map((entry) => entry.name));
11899
+ for (const name of names) {
11900
+ if (poolNameOf(name) === void 0 && !existing.has(name)) {
11901
+ throw new IdentityNotFoundError(name);
11902
+ }
11903
+ }
11904
+ }
11840
11905
  function identityExists(paths, name) {
11841
11906
  return fs9.existsSync(identityJsonPath(paths, name));
11842
11907
  }
@@ -12729,47 +12794,608 @@ function createCodexApiRouter(deps) {
12729
12794
  };
12730
12795
  }
12731
12796
 
12732
- // src/frontdoor/eventsApi.ts
12797
+ // src/frontdoor/configApi.ts
12798
+ init_cliError();
12799
+ init_schema();
12733
12800
  import { ORPCError as ORPCError2 } from "@orpc/client";
12734
12801
  import { openapi as openapi3 } from "@orpc/openapi";
12802
+ init_credential();
12803
+
12804
+ // src/credentialCacheChange.ts
12805
+ init_cliError();
12806
+ init_schema();
12807
+ function mergeCredentialCache(request4, existing) {
12808
+ if (request4.enabled === false) {
12809
+ return false;
12810
+ }
12811
+ if (request4.ttl === void 0 && request4.store === void 0 && request4.enabled !== true) {
12812
+ return void 0;
12813
+ }
12814
+ const parsed = CredentialCacheSchema.safeParse({
12815
+ ...existing,
12816
+ ...request4.ttl === void 0 ? {} : { ttl: request4.ttl },
12817
+ ...request4.store === void 0 ? {} : { store: request4.store }
12818
+ });
12819
+ if (!parsed.success) {
12820
+ throw new UsageError(parsed.error.issues.map((issue) => issue.message).join("; "));
12821
+ }
12822
+ return parsed.data;
12823
+ }
12824
+
12825
+ // src/directoryRulesStore.ts
12826
+ init_store();
12827
+ init_load();
12828
+ init_schema();
12829
+ init_cliError();
12830
+ var DirectoryRuleNotFoundError = class extends CliError {
12831
+ constructor(rulePath) {
12832
+ super(`No directory rule found for path "${rulePath}".`);
12833
+ this.rulePath = rulePath;
12834
+ this.name = "DirectoryRuleNotFoundError";
12835
+ }
12836
+ rulePath;
12837
+ };
12838
+ var DirectoryRuleMissingTargetError = class extends CliError {
12839
+ constructor() {
12840
+ super("A directory rule must set at least one of --config-profile or --identity.");
12841
+ this.name = "DirectoryRuleMissingTargetError";
12842
+ }
12843
+ };
12844
+ var DirectoryRuleAlreadyExistsError = class extends CliError {
12845
+ constructor(rulePath) {
12846
+ super(`A directory rule for path "${rulePath}" already exists. Use \`agent-shim rule set\` to change it.`);
12847
+ this.rulePath = rulePath;
12848
+ this.name = "DirectoryRuleAlreadyExistsError";
12849
+ }
12850
+ rulePath;
12851
+ };
12852
+ function readDirectoryRules(paths) {
12853
+ return readJson(paths.directoryRulesFile, DirectoryRulesSchema) ?? { rules: [] };
12854
+ }
12855
+ function writeDirectoryRules(paths, rules) {
12856
+ const parsed = DirectoryRulesSchema.safeParse(rules);
12857
+ if (!parsed.success) {
12858
+ throw new ConfigValidationError(paths.directoryRulesFile, parsed.error.issues);
12859
+ }
12860
+ writeJsonAtomic(paths.directoryRulesFile, parsed.data);
12861
+ }
12862
+ function listDirectoryRules(paths) {
12863
+ return readDirectoryRules(paths).rules;
12864
+ }
12865
+ function addDirectoryRule(paths, rulePath, options) {
12866
+ if (options.configProfile === void 0 && options.identity === void 0) {
12867
+ throw new DirectoryRuleMissingTargetError();
12868
+ }
12869
+ const current = readDirectoryRules(paths);
12870
+ if (current.rules.some((rule) => rule.path === rulePath)) {
12871
+ throw new DirectoryRuleAlreadyExistsError(rulePath);
12872
+ }
12873
+ const created = buildNewRule(rulePath, options);
12874
+ writeDirectoryRules(paths, { ...current, rules: [...current.rules, created] });
12875
+ return created;
12876
+ }
12877
+ function ruleHasEffect(rule) {
12878
+ return rule.configProfile !== void 0 || rule.identity !== void 0 || rule.categories !== void 0 || rule.entries !== void 0 || rule.launch !== void 0;
12879
+ }
12880
+ function updateDirectoryRule(paths, rulePath, options) {
12881
+ const current = readDirectoryRules(paths);
12882
+ const index = current.rules.findIndex((rule) => rule.path === rulePath);
12883
+ const existing = index === -1 ? void 0 : current.rules[index];
12884
+ if (existing === void 0) {
12885
+ throw new DirectoryRuleNotFoundError(rulePath);
12886
+ }
12887
+ const { configProfile, identity, ...rest } = existing;
12888
+ const nextConfigProfile = options.configProfile === void 0 ? configProfile : options.configProfile === false ? void 0 : options.configProfile;
12889
+ const nextIdentity = options.identity === void 0 ? identity : options.identity === false ? void 0 : options.identity;
12890
+ const updated = {
12891
+ ...rest,
12892
+ ...nextConfigProfile === void 0 ? {} : { configProfile: nextConfigProfile },
12893
+ ...nextIdentity === void 0 ? {} : { identity: nextIdentity }
12894
+ };
12895
+ if (!ruleHasEffect(updated)) {
12896
+ throw new DirectoryRuleMissingTargetError();
12897
+ }
12898
+ const nextRules = [...current.rules];
12899
+ nextRules[index] = updated;
12900
+ writeDirectoryRules(paths, { ...current, rules: nextRules });
12901
+ return updated;
12902
+ }
12903
+ function buildNewRule(rulePath, options) {
12904
+ return {
12905
+ path: rulePath,
12906
+ ...options.configProfile !== void 0 ? { configProfile: options.configProfile } : {},
12907
+ ...options.identity !== void 0 ? { identity: options.identity } : {}
12908
+ };
12909
+ }
12910
+ function removeDirectoryRule(paths, rulePath) {
12911
+ const current = readDirectoryRules(paths);
12912
+ const nextRules = current.rules.filter((rule) => rule.path !== rulePath);
12913
+ if (nextRules.length === current.rules.length) {
12914
+ throw new DirectoryRuleNotFoundError(rulePath);
12915
+ }
12916
+ writeDirectoryRules(paths, { ...current, rules: nextRules });
12917
+ }
12918
+ function requireRuleSelector(paths, selector) {
12919
+ if (selector.startsWith(POOL_SELECTOR_PREFIX)) {
12920
+ const poolName = selector.slice(POOL_SELECTOR_PREFIX.length);
12921
+ if (readPools(paths)[poolName] === void 0) {
12922
+ throw new PoolNotFoundError(poolName);
12923
+ }
12924
+ } else if (readIdentity(paths, selector) === void 0) {
12925
+ throw new IdentityNotFoundError(selector);
12926
+ }
12927
+ }
12928
+
12929
+ // src/frontdoor/configApi.ts
12930
+ init_identity();
12931
+ init_providersStore();
12932
+
12933
+ // src/frontdoor/configSchemas.ts
12934
+ init_schema();
12935
+ import { z as z20 } from "zod";
12936
+ var RemovalConfirmationSchema = z20.boolean();
12937
+ var CredentialWriteSchema = (targets) => z20.strictObject({
12938
+ sources: z20.array(RemoteCredentialSourceSchema).min(1).optional(),
12939
+ target: z20.enum(targets).optional(),
12940
+ cache: z20.union([z20.literal(false), CredentialCacheSchema]).optional()
12941
+ });
12942
+ var CredentialSummarySchema2 = z20.strictObject({
12943
+ target: z20.enum(CREDENTIAL_TARGETS),
12944
+ sources: z20.readonly(z20.array(
12945
+ z20.discriminatedUnion("kind", [
12946
+ z20.strictObject({ kind: z20.literal("env"), variable: z20.string() }),
12947
+ z20.strictObject({ kind: z20.literal("file"), path: z20.string() }),
12948
+ z20.strictObject({ kind: z20.literal("command"), program: z20.string() }),
12949
+ z20.strictObject({ kind: z20.literal("op"), reference: z20.string() }),
12950
+ z20.strictObject({ kind: z20.literal("keychain"), service: z20.string(), account: z20.string().optional() }),
12951
+ z20.strictObject({ kind: z20.literal("literal") })
12952
+ ])
12953
+ )),
12954
+ cache: CredentialCacheSchema.optional()
12955
+ });
12956
+ var mutationOutput = (kind, action) => z20.strictObject({ action: z20.literal(action), kind: z20.literal(kind), name: z20.string() });
12957
+ var storedMutationOutput = (kind, action, value) => z20.strictObject({ action: z20.literal(action), kind: z20.literal(kind), name: z20.string(), value });
12958
+ var IdentityValueSchema = z20.strictObject({
12959
+ name: z20.string(),
12960
+ defaultConfigProfile: z20.string().optional(),
12961
+ allowAmbientCredential: z20.boolean(),
12962
+ credential: CredentialSummarySchema2.optional()
12963
+ });
12964
+ var ProfileValueSchema = ConfigProfileSchema.omit({ $schema: true });
12965
+ var ProviderValueSchema = z20.strictObject({
12966
+ name: z20.string(),
12967
+ kind: z20.enum(PROVIDER_KINDS),
12968
+ displayName: z20.string(),
12969
+ baseUrl: z20.string().optional(),
12970
+ codex: CodexProviderConfigSchema.optional(),
12971
+ credential: CredentialSummarySchema2,
12972
+ env: z20.record(z20.string(), z20.string()).optional()
12973
+ });
12974
+ var ConfigNameInputSchema = z20.strictObject({ name: z20.string().min(1) });
12975
+ var ConfigIdentityAddOutputSchema = storedMutationOutput("identity", "created", IdentityValueSchema);
12976
+ var ConfigIdentitySetInputSchema = z20.strictObject({
12977
+ name: z20.string().min(1),
12978
+ defaultConfigProfile: z20.union([z20.string().min(1), z20.literal(false)]).optional(),
12979
+ allowAmbientCredential: z20.boolean().optional(),
12980
+ credential: z20.union([z20.literal(false), CredentialWriteSchema(CREDENTIAL_TARGETS)]).optional()
12981
+ });
12982
+ var ConfigIdentitySetOutputSchema = storedMutationOutput("identity", "updated", IdentityValueSchema);
12983
+ var ConfigIdentityRemoveInputSchema = z20.strictObject({ name: z20.string().min(1), confirm: RemovalConfirmationSchema });
12984
+ var ConfigIdentityRemoveOutputSchema = mutationOutput("identity", "removed");
12985
+ var ConfigIdentityUseOutputSchema = mutationOutput("identity", "selected");
12986
+ var ConfigProfileAddInputSchema = z20.strictObject({
12987
+ name: z20.string().min(1),
12988
+ extends: z20.array(z20.string().min(1)).optional(),
12989
+ description: z20.string().optional()
12990
+ });
12991
+ var ConfigProfileAddOutputSchema = storedMutationOutput("profile", "created", ProfileValueSchema);
12992
+ var ConfigProfileSetInputSchema = z20.strictObject({
12993
+ name: z20.string().min(1),
12994
+ category: z20.record(z20.string(), z20.boolean()).optional(),
12995
+ entry: z20.record(z20.string(), z20.boolean()).optional(),
12996
+ extends: z20.union([z20.array(z20.string().min(1)), z20.literal(false)]).optional(),
12997
+ description: z20.union([z20.string(), z20.literal(false)]).optional(),
12998
+ launch: z20.strictObject({
12999
+ skipPermissions: z20.boolean().optional(),
13000
+ remoteControl: z20.boolean().optional(),
13001
+ headroom: z20.boolean().optional(),
13002
+ trackUsage: z20.boolean().optional(),
13003
+ provider: z20.union([z20.string().min(1), z20.literal(false)]).optional(),
13004
+ claudeVersion: z20.union([z20.string().min(1), z20.literal(false)]).optional()
13005
+ }).optional()
13006
+ });
13007
+ var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
13008
+ var ConfigProfileRemoveInputSchema = z20.strictObject({ name: z20.string().min(1), confirm: RemovalConfirmationSchema });
13009
+ var ConfigProfileRemoveOutputSchema = mutationOutput("profile", "removed");
13010
+ var ConfigProfileUseOutputSchema = mutationOutput("profile", "selected");
13011
+ var PoolMembersInputSchema = z20.array(z20.string().min(1)).min(1);
13012
+ var ConfigPoolAddInputSchema = z20.strictObject({
13013
+ name: z20.string().min(1),
13014
+ identities: PoolMembersInputSchema,
13015
+ preference: z20.enum(POOL_PREFERENCES).optional()
13016
+ });
13017
+ var ConfigPoolAddOutputSchema = storedMutationOutput("pool", "created", PoolSchema);
13018
+ var ConfigPoolSetInputSchema = z20.strictObject({
13019
+ name: z20.string().min(1),
13020
+ identities: PoolMembersInputSchema.optional(),
13021
+ preference: z20.union([z20.enum(POOL_PREFERENCES), z20.literal(false)]).optional()
13022
+ });
13023
+ var ConfigPoolSetOutputSchema = storedMutationOutput("pool", "updated", PoolSchema);
13024
+ var ConfigPoolRemoveInputSchema = z20.strictObject({ name: z20.string().min(1), confirm: RemovalConfirmationSchema });
13025
+ var ConfigPoolRemoveOutputSchema = mutationOutput("pool", "removed");
13026
+ var ConfigPoolUseOutputSchema = mutationOutput("pool", "selected");
13027
+ var ConfigProviderAddInputSchema = z20.strictObject({
13028
+ name: z20.string().min(1),
13029
+ kind: z20.enum(PROVIDER_KINDS).optional(),
13030
+ displayName: z20.string().min(1),
13031
+ baseUrl: z20.string().min(1).optional(),
13032
+ credential: CredentialWriteSchema(PROVIDER_CREDENTIAL_TARGETS).required({ sources: true }),
13033
+ codex: CodexProviderConfigSchema.optional()
13034
+ });
13035
+ var ConfigProviderAddOutputSchema = storedMutationOutput("provider", "created", ProviderValueSchema);
13036
+ var ConfigProviderSetInputSchema = z20.strictObject({
13037
+ name: z20.string().min(1),
13038
+ displayName: z20.string().min(1).optional(),
13039
+ baseUrl: z20.string().min(1).optional(),
13040
+ credential: CredentialWriteSchema(PROVIDER_CREDENTIAL_TARGETS).optional(),
13041
+ codex: CodexProviderConfigSchema.optional()
13042
+ });
13043
+ var ConfigProviderSetOutputSchema = storedMutationOutput("provider", "updated", ProviderValueSchema);
13044
+ var ConfigProviderRemoveInputSchema = z20.strictObject({ name: z20.string().min(1), confirm: RemovalConfirmationSchema });
13045
+ var ConfigProviderRemoveOutputSchema = mutationOutput("provider", "removed");
13046
+ var ConfigRuleAddInputSchema = z20.strictObject({
13047
+ path: z20.string().min(1),
13048
+ configProfile: z20.string().min(1).optional(),
13049
+ identity: z20.string().min(1).optional()
13050
+ });
13051
+ var ConfigRuleAddOutputSchema = storedMutationOutput("rule", "created", DirectoryRuleSchema);
13052
+ var ConfigRuleSetInputSchema = z20.strictObject({
13053
+ path: z20.string().min(1),
13054
+ configProfile: z20.union([z20.string().min(1), z20.literal(false)]).optional(),
13055
+ identity: z20.union([z20.string().min(1), z20.literal(false)]).optional()
13056
+ });
13057
+ var ConfigRuleSetOutputSchema = storedMutationOutput("rule", "updated", DirectoryRuleSchema);
13058
+ var ConfigRuleRemoveInputSchema = z20.strictObject({ path: z20.string().min(1), confirm: RemovalConfirmationSchema });
13059
+ var ConfigRuleRemoveOutputSchema = mutationOutput("rule", "removed");
13060
+
13061
+ // src/frontdoor/configApi.ts
13062
+ var CONFIG_API_TAG = "config";
13063
+ function refusal(error) {
13064
+ if (error instanceof IdentityNotFoundError || error instanceof ProfileNotFoundError || error instanceof PoolNotFoundError || error instanceof ProviderNotFoundError || error instanceof DirectoryRuleNotFoundError) {
13065
+ throw new ORPCError2("NOT_FOUND", { message: error.message });
13066
+ }
13067
+ if (error instanceof IdentityAlreadyExistsError || error instanceof ProfileAlreadyExistsError || error instanceof PoolAlreadyExistsError || error instanceof ProviderAlreadyExistsError || error instanceof DirectoryRuleAlreadyExistsError) {
13068
+ throw new ORPCError2("CONFLICT", { message: error.message });
13069
+ }
13070
+ if (error instanceof CliError) {
13071
+ throw new ORPCError2("BAD_REQUEST", { message: error.message });
13072
+ }
13073
+ throw error;
13074
+ }
13075
+ function guarded(write) {
13076
+ try {
13077
+ return write();
13078
+ } catch (error) {
13079
+ return refusal(error);
13080
+ }
13081
+ }
13082
+ function requireConfirmation(confirm, what) {
13083
+ if (!confirm) {
13084
+ throw new ORPCError2("BAD_REQUEST", { message: `removing ${what} needs confirm: true, the API's form of the CLI's --yes` });
13085
+ }
13086
+ }
13087
+ function requireChange(given, fields) {
13088
+ if (!given) {
13089
+ throw new ORPCError2("BAD_REQUEST", { message: `Nothing to change: pass ${fields}.` });
13090
+ }
13091
+ }
13092
+ function identityValue(name, paths) {
13093
+ const identity = readIdentity(paths, name);
13094
+ if (identity === void 0) {
13095
+ throw new IdentityNotFoundError(name);
13096
+ }
13097
+ return {
13098
+ name: identity.name,
13099
+ ...identity.defaultConfigProfile === void 0 ? {} : { defaultConfigProfile: identity.defaultConfigProfile },
13100
+ allowAmbientCredential: identity.allowAmbientCredential,
13101
+ ...identity.credential === void 0 ? {} : { credential: summariseCredential(identity.credential) }
13102
+ };
13103
+ }
13104
+ function providerValue(name, provider) {
13105
+ return {
13106
+ name,
13107
+ kind: provider.kind ?? "http",
13108
+ displayName: provider.displayName,
13109
+ ...isCodexProvider(provider) ? provider.codex === void 0 ? {} : { codex: provider.codex } : { baseUrl: provider.baseUrl },
13110
+ credential: summariseCredential(provider.credential),
13111
+ ...provider.env === void 0 ? {} : { env: provider.env }
13112
+ };
13113
+ }
13114
+ function profileValue(name, paths) {
13115
+ const profile = { ...readProfile(paths, name) };
13116
+ delete profile.$schema;
13117
+ return profile;
13118
+ }
13119
+ function createConfigApiRouter(deps) {
13120
+ const authed = doorApiAuth(deps.expectedToken);
13121
+ const { paths } = deps;
13122
+ const route = (path36, summary) => authed.meta(openapi3({ method: "POST", path: path36, summary, tags: [CONFIG_API_TAG] }));
13123
+ return {
13124
+ config: {
13125
+ identity: {
13126
+ add: route("/rest/config/identity/add", "Create an identity").input(ConfigNameInputSchema).output(ConfigIdentityAddOutputSchema).handler(
13127
+ ({ input }) => guarded(() => {
13128
+ addIdentity(paths, input.name);
13129
+ return { action: "created", kind: "identity", name: input.name, value: identityValue(input.name, paths) };
13130
+ })
13131
+ ),
13132
+ set: route("/rest/config/identity/set", "Update an identity's default profile, ambient-credential setting or credential").input(ConfigIdentitySetInputSchema).output(ConfigIdentitySetOutputSchema).handler(
13133
+ ({ input }) => guarded(() => {
13134
+ requireChange(input.defaultConfigProfile !== void 0 || input.allowAmbientCredential !== void 0 || input.credential !== void 0, "defaultConfigProfile, allowAmbientCredential or credential");
13135
+ if (!identityExists(paths, input.name)) {
13136
+ throw new IdentityNotFoundError(input.name);
13137
+ }
13138
+ if (typeof input.defaultConfigProfile === "string") {
13139
+ requireProfileExists(paths, input.defaultConfigProfile);
13140
+ }
13141
+ if (input.defaultConfigProfile !== void 0) {
13142
+ setDefaultConfigProfile(paths, input.name, input.defaultConfigProfile === false ? void 0 : input.defaultConfigProfile);
13143
+ }
13144
+ if (input.allowAmbientCredential !== void 0) {
13145
+ setAllowAmbientCredential(paths, input.name, input.allowAmbientCredential);
13146
+ }
13147
+ if (input.credential === false) {
13148
+ setIdentityCredential(paths, input.name, false);
13149
+ } else if (input.credential !== void 0) {
13150
+ const { sources, target, cache } = input.credential;
13151
+ const merged = cache === void 0 ? void 0 : mergeCredentialCache(cache === false ? { enabled: false } : { ...cache, enabled: true }, readIdentity(paths, input.name)?.credential?.cache);
13152
+ const change = {
13153
+ ...sources === void 0 ? {} : { sources },
13154
+ ...target === void 0 ? {} : { target },
13155
+ ...merged === void 0 ? {} : { cache: merged }
13156
+ };
13157
+ setIdentityCredential(paths, input.name, change);
13158
+ }
13159
+ return { action: "updated", kind: "identity", name: input.name, value: identityValue(input.name, paths) };
13160
+ })
13161
+ ),
13162
+ remove: route("/rest/config/identity/remove", "Delete an identity and its directory").input(ConfigIdentityRemoveInputSchema).output(ConfigIdentityRemoveOutputSchema).handler(({ input }) => {
13163
+ requireConfirmation(input.confirm, `identity "${input.name}" and its directory`);
13164
+ return guarded(() => {
13165
+ removeIdentity(paths, input.name);
13166
+ return { action: "removed", kind: "identity", name: input.name };
13167
+ });
13168
+ }),
13169
+ use: route("/rest/config/identity/use", "Select the active identity").input(ConfigNameInputSchema).output(ConfigIdentityUseOutputSchema).handler(
13170
+ ({ input }) => guarded(() => {
13171
+ if (poolNameOf(input.name) === void 0 && !identityExists(paths, input.name)) {
13172
+ throw new IdentityNotFoundError(input.name);
13173
+ }
13174
+ useIdentity(paths, input.name);
13175
+ return { action: "selected", kind: "identity", name: input.name };
13176
+ })
13177
+ )
13178
+ },
13179
+ profile: {
13180
+ add: route("/rest/config/profile/add", "Create a configuration profile").input(ConfigProfileAddInputSchema).output(ConfigProfileAddOutputSchema).handler(
13181
+ ({ input }) => guarded(() => {
13182
+ createProfile(paths, input.name, input.extends, input.description);
13183
+ return { action: "created", kind: "profile", name: input.name, value: profileValue(input.name, paths) };
13184
+ })
13185
+ ),
13186
+ set: route("/rest/config/profile/set", "Update a configuration profile's categories, entries, extends list, description or launch settings").input(ConfigProfileSetInputSchema).output(ConfigProfileSetOutputSchema).handler(
13187
+ ({ input }) => guarded(() => {
13188
+ const { launch } = input;
13189
+ requireChange(
13190
+ input.category !== void 0 || input.entry !== void 0 || input.extends !== void 0 || input.description !== void 0 || launch !== void 0,
13191
+ "category, entry, extends, description or launch"
13192
+ );
13193
+ requireProfileExists(paths, input.name);
13194
+ applyProfileChange(paths, input.name, {
13195
+ ...input.category === void 0 ? {} : { category: input.category },
13196
+ ...input.entry === void 0 ? {} : { entry: input.entry },
13197
+ ...input.extends === void 0 ? {} : { extends: input.extends },
13198
+ ...input.description === void 0 ? {} : { description: input.description },
13199
+ ...launch?.skipPermissions === void 0 ? {} : { launchSkipPermissions: launch.skipPermissions },
13200
+ ...launch?.remoteControl === void 0 ? {} : { launchRemoteControl: launch.remoteControl },
13201
+ ...launch?.headroom === void 0 ? {} : { launchHeadroom: launch.headroom },
13202
+ ...launch?.trackUsage === void 0 ? {} : { launchTrackUsage: launch.trackUsage },
13203
+ ...launch?.provider === void 0 ? {} : { launchProvider: launch.provider },
13204
+ ...launch?.claudeVersion === void 0 ? {} : { launchClaudeVersion: launch.claudeVersion }
13205
+ });
13206
+ return { action: "updated", kind: "profile", name: input.name, value: profileValue(input.name, paths) };
13207
+ })
13208
+ ),
13209
+ remove: route("/rest/config/profile/remove", "Delete a configuration profile").input(ConfigProfileRemoveInputSchema).output(ConfigProfileRemoveOutputSchema).handler(({ input }) => {
13210
+ requireConfirmation(input.confirm, `configuration profile "${input.name}"`);
13211
+ return guarded(() => {
13212
+ removeProfile(paths, input.name);
13213
+ return { action: "removed", kind: "profile", name: input.name };
13214
+ });
13215
+ }),
13216
+ use: route("/rest/config/profile/use", "Make a configuration profile the global default").input(ConfigNameInputSchema).output(ConfigProfileUseOutputSchema).handler(
13217
+ ({ input }) => guarded(() => {
13218
+ requireProfileExists(paths, input.name);
13219
+ setGlobalDefaultProfile(paths, input.name);
13220
+ return { action: "selected", kind: "profile", name: input.name };
13221
+ })
13222
+ )
13223
+ },
13224
+ pool: {
13225
+ add: route("/rest/config/pool/add", "Define a pool").input(ConfigPoolAddInputSchema).output(ConfigPoolAddOutputSchema).handler(
13226
+ ({ input }) => guarded(() => {
13227
+ requireIdentityNames(paths, input.identities);
13228
+ const created = addPool(paths, input.name, input.identities, input.preference);
13229
+ return { action: "created", kind: "pool", name: input.name, value: created };
13230
+ })
13231
+ ),
13232
+ set: route("/rest/config/pool/set", "Replace a pool's members, its preference or both").input(ConfigPoolSetInputSchema).output(ConfigPoolSetOutputSchema).handler(
13233
+ ({ input }) => guarded(() => {
13234
+ requireChange(input.identities !== void 0 || input.preference !== void 0, "identities or preference");
13235
+ const existing = requirePool(paths, input.name);
13236
+ if (input.identities !== void 0) {
13237
+ requireIdentityNames(paths, input.identities);
13238
+ }
13239
+ const members = input.identities ?? existing.identities;
13240
+ const preference = input.preference === void 0 ? existing.preference : input.preference === false ? void 0 : input.preference;
13241
+ return { action: "updated", kind: "pool", name: input.name, value: setPool(paths, input.name, members, preference) };
13242
+ })
13243
+ ),
13244
+ remove: route("/rest/config/pool/remove", "Delete a pool").input(ConfigPoolRemoveInputSchema).output(ConfigPoolRemoveOutputSchema).handler(({ input }) => {
13245
+ requireConfirmation(input.confirm, `pool "${input.name}"`);
13246
+ return guarded(() => {
13247
+ removePool(paths, input.name);
13248
+ return { action: "removed", kind: "pool", name: input.name };
13249
+ });
13250
+ }),
13251
+ use: route("/rest/config/pool/use", "Make launches with no other selection pick a member of a pool").input(ConfigNameInputSchema).output(ConfigPoolUseOutputSchema).handler(
13252
+ ({ input }) => guarded(() => {
13253
+ if (readPools(paths)[input.name] === void 0) {
13254
+ throw new PoolNotFoundError(input.name);
13255
+ }
13256
+ useIdentity(paths, `pool:${input.name}`);
13257
+ return { action: "selected", kind: "pool", name: input.name };
13258
+ })
13259
+ )
13260
+ },
13261
+ provider: {
13262
+ add: route("/rest/config/provider/add", "Create an API provider definition").input(ConfigProviderAddInputSchema).output(ConfigProviderAddOutputSchema).handler(
13263
+ ({ input }) => guarded(() => {
13264
+ const created = addProvider(paths, input.name, {
13265
+ ...input.kind === void 0 ? {} : { kind: input.kind },
13266
+ displayName: input.displayName,
13267
+ ...input.baseUrl === void 0 ? {} : { baseUrl: input.baseUrl },
13268
+ sources: input.credential.sources,
13269
+ ...input.credential.target === void 0 ? {} : { target: input.credential.target },
13270
+ ...input.codex === void 0 ? {} : { codex: input.codex }
13271
+ });
13272
+ const cache = input.credential.cache;
13273
+ const stored = cache === void 0 || cache === false ? created : updateProvider(paths, input.name, { cache });
13274
+ return { action: "created", kind: "provider", name: input.name, value: providerValue(input.name, stored) };
13275
+ })
13276
+ ),
13277
+ set: route("/rest/config/provider/set", "Update an API provider definition").input(ConfigProviderSetInputSchema).output(ConfigProviderSetOutputSchema).handler(
13278
+ ({ input }) => guarded(() => {
13279
+ requireChange(input.displayName !== void 0 || input.baseUrl !== void 0 || input.credential !== void 0 || input.codex !== void 0, "displayName, baseUrl, credential or codex");
13280
+ const existing = readProvider(paths, input.name);
13281
+ if (existing === void 0) {
13282
+ throw new ProviderNotFoundError(input.name);
13283
+ }
13284
+ const credential = input.credential;
13285
+ if (input.baseUrl !== void 0 && !isCodexProvider(existing) && input.baseUrl !== existing.baseUrl && credential?.sources === void 0) {
13286
+ throw new ORPCError2("BAD_REQUEST", { message: `Changing the base URL of provider "${input.name}" requires a credential block in the same call: the stored credential is not sent to a different endpoint.` });
13287
+ }
13288
+ const cache = credential?.cache === void 0 ? void 0 : mergeCredentialCache(credential.cache === false ? { enabled: false } : { ...credential.cache, enabled: true }, existing.credential.cache);
13289
+ const updated = updateProvider(paths, input.name, {
13290
+ ...input.displayName === void 0 ? {} : { displayName: input.displayName },
13291
+ ...input.baseUrl === void 0 ? {} : { baseUrl: input.baseUrl },
13292
+ ...credential?.sources === void 0 ? {} : { sources: credential.sources },
13293
+ ...credential?.target === void 0 ? {} : { target: credential.target },
13294
+ ...cache === void 0 ? {} : { cache },
13295
+ ...input.codex === void 0 ? {} : { codex: input.codex }
13296
+ });
13297
+ return { action: "updated", kind: "provider", name: input.name, value: providerValue(input.name, updated) };
13298
+ })
13299
+ ),
13300
+ remove: route("/rest/config/provider/remove", "Delete an API provider definition").input(ConfigProviderRemoveInputSchema).output(ConfigProviderRemoveOutputSchema).handler(({ input }) => {
13301
+ requireConfirmation(input.confirm, `provider "${input.name}"`);
13302
+ return guarded(() => {
13303
+ if (!providerExists(paths, input.name)) {
13304
+ throw new ProviderNotFoundError(input.name);
13305
+ }
13306
+ removeProvider(paths, input.name);
13307
+ return { action: "removed", kind: "provider", name: input.name };
13308
+ });
13309
+ })
13310
+ },
13311
+ rule: {
13312
+ add: route("/rest/config/rule/add", "Add a directory rule for a path").input(ConfigRuleAddInputSchema).output(ConfigRuleAddOutputSchema).handler(
13313
+ ({ input }) => guarded(() => {
13314
+ if (input.identity !== void 0) {
13315
+ requireRuleSelector(paths, input.identity);
13316
+ }
13317
+ if (input.configProfile !== void 0) {
13318
+ requireProfileExists(paths, input.configProfile);
13319
+ }
13320
+ const created = addDirectoryRule(paths, input.path, {
13321
+ ...input.configProfile === void 0 ? {} : { configProfile: input.configProfile },
13322
+ ...input.identity === void 0 ? {} : { identity: input.identity }
13323
+ });
13324
+ return { action: "created", kind: "rule", name: input.path, value: created };
13325
+ })
13326
+ ),
13327
+ set: route("/rest/config/rule/set", "Update the directory rule for a path").input(ConfigRuleSetInputSchema).output(ConfigRuleSetOutputSchema).handler(
13328
+ ({ input }) => guarded(() => {
13329
+ requireChange(input.configProfile !== void 0 || input.identity !== void 0, "configProfile or identity");
13330
+ if (typeof input.identity === "string") {
13331
+ requireRuleSelector(paths, input.identity);
13332
+ }
13333
+ if (typeof input.configProfile === "string") {
13334
+ requireProfileExists(paths, input.configProfile);
13335
+ }
13336
+ const updated = updateDirectoryRule(paths, input.path, {
13337
+ ...input.configProfile === void 0 ? {} : { configProfile: input.configProfile },
13338
+ ...input.identity === void 0 ? {} : { identity: input.identity }
13339
+ });
13340
+ return { action: "updated", kind: "rule", name: input.path, value: updated };
13341
+ })
13342
+ ),
13343
+ remove: route("/rest/config/rule/remove", "Remove the directory rule for a path").input(ConfigRuleRemoveInputSchema).output(ConfigRuleRemoveOutputSchema).handler(({ input }) => {
13344
+ requireConfirmation(input.confirm, `the directory rule for "${input.path}"`);
13345
+ return guarded(() => {
13346
+ if (!listDirectoryRules(paths).some((entry) => entry.path === input.path)) {
13347
+ throw new DirectoryRuleNotFoundError(input.path);
13348
+ }
13349
+ removeDirectoryRule(paths, input.path);
13350
+ return { action: "removed", kind: "rule", name: input.path };
13351
+ });
13352
+ })
13353
+ }
13354
+ }
13355
+ };
13356
+ }
13357
+
13358
+ // src/frontdoor/eventsApi.ts
13359
+ import { ORPCError as ORPCError3 } from "@orpc/client";
13360
+ import { openapi as openapi4 } from "@orpc/openapi";
12735
13361
  import { eventIterator as eventIterator2, withEventMeta as withEventMeta2 } from "@orpc/server";
12736
13362
 
12737
13363
  // src/frontdoor/eventSchemas.ts
12738
- import { z as z20 } from "zod";
13364
+ import { z as z21 } from "zod";
12739
13365
  var DOOR_EVENT_SOURCE_RC = "rc";
12740
13366
  var LAUNCH_EVENT_SOURCE = "launch";
12741
13367
  var USAGE_EVENT_SOURCE = "usage";
12742
13368
  var DOOR_HEALTH_EVENT_SOURCE = "door";
12743
13369
  var QUOTA_EXPIRING_EVENT_SOURCE = "quota-expiring";
12744
- var DoorEventSchema = z20.strictObject({
12745
- source: z20.string().min(1),
13370
+ var DoorEventSchema = z21.strictObject({
13371
+ source: z21.string().min(1),
12746
13372
  /** A positive integer because the backbone's counters start at one and only ever increase. */
12747
- sequence: z20.number().int().positive(),
12748
- payload: z20.unknown()
12749
- });
12750
- var DoorEventSourceQuerySchema = z20.strictObject({
12751
- sources: z20.array(z20.string().min(1)).min(1).optional()
12752
- });
12753
- var LaunchLifecycleEventSchema = z20.strictObject({
12754
- kind: z20.enum(["registered", "pruned", "ended"]),
12755
- pid: z20.number().int().positive(),
12756
- startedAt: z20.number(),
12757
- observedAt: z20.number()
12758
- });
12759
- var DoorHealthEventSchema = z20.discriminatedUnion("kind", [
12760
- z20.strictObject({ kind: z20.literal("generation"), pid: z20.number().int().positive(), providerPort: z20.number().int().positive(), connectPort: z20.number().int().positive(), directPort: z20.number().int().positive(), observedAt: z20.number() }),
12761
- z20.strictObject({ kind: z20.literal("listenerFailed"), pid: z20.number().int().positive(), listener: z20.enum(["provider", "connect", "direct"]), message: z20.string(), observedAt: z20.number() }),
12762
- z20.strictObject({ kind: z20.literal("binaryTurnover"), pid: z20.number().int().positive(), observedAt: z20.number() }),
12763
- z20.strictObject({ kind: z20.literal("idleShutdown"), pid: z20.number().int().positive(), observedAt: z20.number() })
13373
+ sequence: z21.number().int().positive(),
13374
+ payload: z21.unknown()
13375
+ });
13376
+ var DoorEventSourceQuerySchema = z21.strictObject({
13377
+ sources: z21.array(z21.string().min(1)).min(1).optional()
13378
+ });
13379
+ var LaunchLifecycleEventSchema = z21.strictObject({
13380
+ kind: z21.enum(["registered", "pruned", "ended"]),
13381
+ pid: z21.number().int().positive(),
13382
+ startedAt: z21.number(),
13383
+ observedAt: z21.number()
13384
+ });
13385
+ var DoorHealthEventSchema = z21.discriminatedUnion("kind", [
13386
+ z21.strictObject({ kind: z21.literal("generation"), pid: z21.number().int().positive(), providerPort: z21.number().int().positive(), connectPort: z21.number().int().positive(), directPort: z21.number().int().positive(), observedAt: z21.number() }),
13387
+ z21.strictObject({ kind: z21.literal("listenerFailed"), pid: z21.number().int().positive(), listener: z21.enum(["provider", "connect", "direct"]), message: z21.string(), observedAt: z21.number() }),
13388
+ z21.strictObject({ kind: z21.literal("binaryTurnover"), pid: z21.number().int().positive(), observedAt: z21.number() }),
13389
+ z21.strictObject({ kind: z21.literal("idleShutdown"), pid: z21.number().int().positive(), observedAt: z21.number() })
12764
13390
  ]);
12765
- var QuotaExpiringEventSchema = z20.strictObject({
12766
- identity: z20.string().min(1),
12767
- provider: z20.string().min(1),
12768
- window: z20.enum(["fiveHour", "sevenDay"]),
13391
+ var QuotaExpiringEventSchema = z21.strictObject({
13392
+ identity: z21.string().min(1),
13393
+ provider: z21.string().min(1),
13394
+ window: z21.enum(["fiveHour", "sevenDay"]),
12769
13395
  /** The fraction of the window already used when it was seen expiring, always below one because a fully used window has nothing left to spend. */
12770
- utilization: z20.number().min(0).max(1),
12771
- resetsAt: z20.iso.datetime(),
12772
- observedAt: z20.number()
13396
+ utilization: z21.number().min(0).max(1),
13397
+ resetsAt: z21.iso.datetime(),
13398
+ observedAt: z21.number()
12773
13399
  });
12774
13400
 
12775
13401
  // src/frontdoor/eventsApi.ts
@@ -12778,12 +13404,12 @@ function createEventsApiRouter(deps) {
12778
13404
  const authed = doorApiAuth(deps.expectedToken);
12779
13405
  return {
12780
13406
  events: {
12781
- subscribe: authed.meta(openapi3({ method: "GET", path: "/rest/events", summary: "Stream the door's every event source (SSE)", tags: [EVENTS_API_TAG] })).input(DoorEventSourceQuerySchema).output(eventIterator2(DoorEventSchema)).handler(async function* ({ input, signal }) {
13407
+ subscribe: authed.meta(openapi4({ method: "GET", path: "/rest/events", summary: "Stream the door's every event source (SSE)", tags: [EVENTS_API_TAG] })).input(DoorEventSourceQuerySchema).output(eventIterator2(DoorEventSchema)).handler(async function* ({ input, signal }) {
12782
13408
  if (input.sources !== void 0) {
12783
13409
  const live = deps.events.sources();
12784
13410
  const unknown = input.sources.filter((source) => !live.includes(source));
12785
13411
  if (unknown.length > 0) {
12786
- throw new ORPCError2("NOT_FOUND", { message: `the door publishes no event source named ${unknown.map((source) => `"${source}"`).join(", ")}; the live sources are ${live.map((source) => `"${source}"`).join(", ")}` });
13412
+ throw new ORPCError3("NOT_FOUND", { message: `the door publishes no event source named ${unknown.map((source) => `"${source}"`).join(", ")}; the live sources are ${live.map((source) => `"${source}"`).join(", ")}` });
12787
13413
  }
12788
13414
  }
12789
13415
  const stream = deps.events.stream(input.sources);
@@ -12812,32 +13438,32 @@ function createEventsApiRouter(deps) {
12812
13438
 
12813
13439
  // src/frontdoor/lifecycleApi.ts
12814
13440
  init_update();
12815
- import { ORPCError as ORPCError3 } from "@orpc/client";
12816
- import { openapi as openapi4 } from "@orpc/openapi";
13441
+ import { ORPCError as ORPCError4 } from "@orpc/client";
13442
+ import { openapi as openapi5 } from "@orpc/openapi";
12817
13443
  var FRONTDOOR_API_TAG = "frontdoor";
12818
13444
  var UPDATE_API_TAG = "update";
12819
13445
  function createLifecycleApiRouter(deps) {
12820
13446
  const authed = doorApiAuth(deps.expectedToken);
12821
13447
  return {
12822
13448
  frontdoor: {
12823
- restart: authed.meta(openapi4({ method: "POST", path: "/rest/frontdoor/restart", summary: "Replace the serving front door in place", description: "Answers with the pid of the door being replaced, then replaces it. The replacement is a new generation with its own control token: the caller reopens its client from the state root once the door's supervisor pid differs from the one returned.", tags: [FRONTDOOR_API_TAG] })).output(FrontDoorRestartOutputSchema).handler(({ context }) => {
13449
+ restart: authed.meta(openapi5({ method: "POST", path: "/rest/frontdoor/restart", summary: "Replace the serving front door in place", description: "Answers with the pid of the door being replaced, then replaces it. The replacement is a new generation with its own control token: the caller reopens its client from the state root once the door's supervisor pid differs from the one returned.", tags: [FRONTDOOR_API_TAG] })).output(FrontDoorRestartOutputSchema).handler(({ context }) => {
12824
13450
  context.afterResponse(deps.restartDoor);
12825
13451
  return { action: "restarting", previousPid: deps.doorPid };
12826
13452
  })
12827
13453
  },
12828
13454
  update: {
12829
- check: authed.meta(openapi4({ method: "GET", path: "/rest/update/check", summary: "Check whether a newer release exists", tags: [UPDATE_API_TAG] })).output(UpdateCheckOutputSchema).handler(async () => {
13455
+ check: authed.meta(openapi5({ method: "GET", path: "/rest/update/check", summary: "Check whether a newer release exists", tags: [UPDATE_API_TAG] })).output(UpdateCheckOutputSchema).handler(async () => {
12830
13456
  try {
12831
13457
  return await deps.checkForUpdate();
12832
13458
  } catch (error) {
12833
13459
  if (error instanceof UpdateChannelError) {
12834
- throw new ORPCError3("PRECONDITION_FAILED", { message: error.message });
13460
+ throw new ORPCError4("PRECONDITION_FAILED", { message: error.message });
12835
13461
  }
12836
13462
  if (error instanceof UpdateConflictError) {
12837
- throw new ORPCError3("CONFLICT", { message: error.message });
13463
+ throw new ORPCError4("CONFLICT", { message: error.message });
12838
13464
  }
12839
13465
  if (error instanceof UpdateDownloadError) {
12840
- throw new ORPCError3("BAD_GATEWAY", { message: error.message });
13466
+ throw new ORPCError4("BAD_GATEWAY", { message: error.message });
12841
13467
  }
12842
13468
  throw error;
12843
13469
  }
@@ -12848,56 +13474,56 @@ function createLifecycleApiRouter(deps) {
12848
13474
 
12849
13475
  // src/frontdoor/launchApi.ts
12850
13476
  init_cliError();
12851
- import { ORPCError as ORPCError4 } from "@orpc/client";
12852
- import { openapi as openapi5 } from "@orpc/openapi";
13477
+ import { ORPCError as ORPCError5 } from "@orpc/client";
13478
+ import { openapi as openapi6 } from "@orpc/openapi";
12853
13479
 
12854
13480
  // src/frontdoor/launchSchemas.ts
12855
13481
  import path30 from "node:path";
12856
- import { z as z21 } from "zod";
13482
+ import { z as z22 } from "zod";
12857
13483
  init_claudeVersion();
12858
13484
  init_identity();
12859
- var LaunchResolveInputSchema = z21.strictObject({
12860
- path: z21.string().min(1),
13485
+ var LaunchResolveInputSchema = z22.strictObject({
13486
+ path: z22.string().min(1),
12861
13487
  /** `@name`, launch flags, then the arguments for `claude`; empty for a bare launch. */
12862
- argv: z21.readonly(z21.array(z21.string())).optional(),
13488
+ argv: z22.readonly(z22.array(z22.string())).optional(),
12863
13489
  /** The launch's inherited environment. Absent means an empty one: the door's own environment is never a substitute for the caller's, so a caller that wants `AGENT_SHIM_*` switches or a `CLAUDE_CONFIG_DIR` considered names them here. Values are read, never reported. */
12864
- env: z21.record(z21.string(), z21.string()).optional()
13490
+ env: z22.record(z22.string(), z22.string()).optional()
12865
13491
  }).refine((input) => path30.isAbsolute(input.path), { message: "path must be absolute: the door cannot resolve a relative path against the caller's working directory" });
12866
- var LaunchPoolDecisionSchema = z21.strictObject({
12867
- name: z21.string(),
12868
- reasons: z21.readonly(z21.array(z21.string())),
12869
- movedOff: z21.strictObject({ identity: z21.string(), reason: z21.string() }).optional()
12870
- });
12871
- var LaunchDecisionSchema = z21.strictObject({
12872
- identity: z21.string().optional(),
12873
- identitySource: z21.enum(IDENTITY_DECISION_SOURCES),
13492
+ var LaunchPoolDecisionSchema = z22.strictObject({
13493
+ name: z22.string(),
13494
+ reasons: z22.readonly(z22.array(z22.string())),
13495
+ movedOff: z22.strictObject({ identity: z22.string(), reason: z22.string() }).optional()
13496
+ });
13497
+ var LaunchDecisionSchema = z22.strictObject({
13498
+ identity: z22.string().optional(),
13499
+ identitySource: z22.enum(IDENTITY_DECISION_SOURCES),
12874
13500
  pool: LaunchPoolDecisionSchema.optional(),
12875
- configDirEscapeHatch: z21.boolean(),
12876
- configDir: z21.string().optional(),
12877
- configProfile: z21.string().optional(),
12878
- configProfileSource: z21.enum(CONFIG_PROFILE_DECISION_SOURCES),
12879
- provider: z21.string().optional()
12880
- });
12881
- var LaunchFlagsSchema = z21.strictObject({
12882
- skipPermissions: z21.boolean(),
12883
- remoteControl: z21.boolean(),
12884
- headroom: z21.boolean(),
12885
- trackUsage: z21.boolean()
12886
- });
12887
- var LaunchResolveOutputSchema = z21.strictObject({
13501
+ configDirEscapeHatch: z22.boolean(),
13502
+ configDir: z22.string().optional(),
13503
+ configProfile: z22.string().optional(),
13504
+ configProfileSource: z22.enum(CONFIG_PROFILE_DECISION_SOURCES),
13505
+ provider: z22.string().optional()
13506
+ });
13507
+ var LaunchFlagsSchema = z22.strictObject({
13508
+ skipPermissions: z22.boolean(),
13509
+ remoteControl: z22.boolean(),
13510
+ headroom: z22.boolean(),
13511
+ trackUsage: z22.boolean()
13512
+ });
13513
+ var LaunchResolveOutputSchema = z22.strictObject({
12888
13514
  decision: LaunchDecisionSchema,
12889
13515
  flags: LaunchFlagsSchema,
12890
- claudeVersion: z21.strictObject({ version: z21.string(), source: z21.enum(CLAUDE_VERSION_SOURCES) }).optional(),
13516
+ claudeVersion: z22.strictObject({ version: z22.string(), source: z22.enum(CLAUDE_VERSION_SOURCES) }).optional(),
12891
13517
  /** The real `claude` binary the launch would spawn, on the door's host. */
12892
- bin: z21.string(),
13518
+ bin: z22.string(),
12893
13519
  /** The arguments the launch would pass it: the tool's own flags, then `CLAUDE_EXTRA_FLAGS`, then the caller's own. */
12894
- args: z21.readonly(z21.array(z21.string())),
13520
+ args: z22.readonly(z22.array(z22.string())),
12895
13521
  /** The credential the launch would authenticate with, by target and source kinds. Absent when none applies. */
12896
- credential: z21.strictObject({ subject: z21.enum(["provider", "identity"]), name: z21.string(), summary: CredentialSummarySchema }).optional(),
12897
- routing: z21.strictObject({ frontDoor: z21.boolean(), headroom: z21.boolean() }),
13522
+ credential: z22.strictObject({ subject: z22.enum(["provider", "identity"]), name: z22.string(), summary: CredentialSummarySchema }).optional(),
13523
+ routing: z22.strictObject({ frontDoor: z22.boolean(), headroom: z22.boolean() }),
12898
13524
  /** The names of the environment variables the launch would set or unset, sorted. Values are not reported. */
12899
- environment: z21.readonly(z21.array(z21.string())),
12900
- warnings: z21.readonly(z21.array(z21.string()))
13525
+ environment: z22.readonly(z22.array(z22.string())),
13526
+ warnings: z22.readonly(z22.array(z22.string()))
12901
13527
  });
12902
13528
 
12903
13529
  // src/frontdoor/launchApi.ts
@@ -12906,13 +13532,13 @@ function createLaunchApiRouter(deps) {
12906
13532
  const authed = doorApiAuth(deps.expectedToken);
12907
13533
  return {
12908
13534
  launch: {
12909
- resolve: authed.meta(openapi5({ method: "POST", path: "/rest/launch/resolve", summary: "Resolve what a launch from one directory would do, without performing it", tags: [LAUNCH_API_TAG] })).input(LaunchResolveInputSchema).output(LaunchResolveOutputSchema).handler(({ input }) => {
13535
+ resolve: authed.meta(openapi6({ method: "POST", path: "/rest/launch/resolve", summary: "Resolve what a launch from one directory would do, without performing it", tags: [LAUNCH_API_TAG] })).input(LaunchResolveInputSchema).output(LaunchResolveOutputSchema).handler(({ input }) => {
12910
13536
  try {
12911
13537
  const { resolution, warnings } = deps.resolveLaunch({ path: input.path, argv: input.argv ?? [], env: input.env ?? {} });
12912
13538
  return { ...resolution, warnings };
12913
13539
  } catch (error) {
12914
13540
  if (error instanceof CliError) {
12915
- throw new ORPCError4("BAD_REQUEST", { message: error.message });
13541
+ throw new ORPCError5("BAD_REQUEST", { message: error.message });
12916
13542
  }
12917
13543
  throw error;
12918
13544
  }
@@ -12931,11 +13557,11 @@ function createControlApiRouter(deps) {
12931
13557
  const authed = doorApiAuth(deps.expectedToken);
12932
13558
  return {
12933
13559
  usage: {
12934
- list: authed.meta(openapi6({ method: "GET", path: "/rest/usage/snapshots", summary: "List every identity's usage snapshot", tags: [USAGE_API_TAG] })).output(UsageListOutputSchema).handler(() => ({ snapshots: deps.usageSnapshots() })),
12935
- effectiveWindow: authed.meta(openapi6({ method: "GET", path: "/rest/usage/windows", summary: "Read one identity's effective quota windows", tags: [USAGE_API_TAG] })).input(UsageWindowsInputSchema).output(UsageWindowsOutputSchema).handler(({ input }) => {
13560
+ list: authed.meta(openapi7({ method: "GET", path: "/rest/usage/snapshots", summary: "List every identity's usage snapshot", tags: [USAGE_API_TAG] })).output(UsageListOutputSchema).handler(() => ({ snapshots: deps.usageSnapshots() })),
13561
+ effectiveWindow: authed.meta(openapi7({ method: "GET", path: "/rest/usage/windows", summary: "Read one identity's effective quota windows", tags: [USAGE_API_TAG] })).input(UsageWindowsInputSchema).output(UsageWindowsOutputSchema).handler(({ input }) => {
12936
13562
  const snapshot = deps.usageSnapshotOf(input.identity);
12937
13563
  if (snapshot === void 0) {
12938
- throw new ORPCError5("NOT_FOUND", { message: `identity ${input.identity} has no usage snapshot yet, so no quota window has been observed for it` });
13564
+ throw new ORPCError6("NOT_FOUND", { message: `identity ${input.identity} has no usage snapshot yet, so no quota window has been observed for it` });
12939
13565
  }
12940
13566
  const provider = input.provider ?? ANTHROPIC_PROVIDER;
12941
13567
  const rateLimit = snapshot.providers[provider]?.rateLimit;
@@ -12949,34 +13575,34 @@ function createControlApiRouter(deps) {
12949
13575
  ...unified?.sevenDay === void 0 ? {} : { sevenDay: effectiveWindow(unified.sevenDay, now) }
12950
13576
  };
12951
13577
  }),
12952
- live: authed.meta(openapi6({ method: "GET", path: "/rest/usage/live", summary: "Read the live rate-limit observations the event backbone files", tags: [USAGE_API_TAG] })).input(RcSessionQuerySchema).output(UsageLiveOutputSchema).handler(({ input }) => {
13578
+ live: authed.meta(openapi7({ method: "GET", path: "/rest/usage/live", summary: "Read the live rate-limit observations the event backbone files", tags: [USAGE_API_TAG] })).input(RcSessionQuerySchema).output(UsageLiveOutputSchema).handler(({ input }) => {
12953
13579
  const sessions = deps.liveRateLimits(input.session);
12954
13580
  if (input.session !== void 0 && sessions.length === 0) {
12955
13581
  if (deps.list().some((session) => session.id === input.session)) {
12956
- throw new ORPCError5("NOT_FOUND", { message: `session ${input.session} has filed no rate_limit_event on its stream yet: the worker emits one only once a turn has completed, so retry after this session's next turn` });
13582
+ throw new ORPCError6("NOT_FOUND", { message: `session ${input.session} has filed no rate_limit_event on its stream yet: the worker emits one only once a turn has completed, so retry after this session's next turn` });
12957
13583
  }
12958
- throw new ORPCError5("NOT_FOUND", { message: rcSessionNotObservedMessage(input.session) });
13584
+ throw new ORPCError6("NOT_FOUND", { message: rcSessionNotObservedMessage(input.session) });
12959
13585
  }
12960
13586
  return { latest: deps.latestRateLimit(), sessions };
12961
13587
  })
12962
13588
  },
12963
13589
  frontdoor: {
12964
- status: authed.meta(openapi6({ method: "GET", path: "/rest/frontdoor/status", summary: "Read the front door's status", tags: [FRONTDOOR_API_TAG2] })).output(FrontDoorStatusOutputSchema).handler(() => deps.frontDoorStatus()),
12965
- sessions: authed.meta(openapi6({ method: "GET", path: "/rest/frontdoor/sessions", summary: "Read the front door's session registry", tags: [FRONTDOOR_API_TAG2] })).output(FrontDoorSessionsOutputSchema).handler(() => ({ sessions: deps.frontDoorStatus().sessions }))
13590
+ status: authed.meta(openapi7({ method: "GET", path: "/rest/frontdoor/status", summary: "Read the front door's status", tags: [FRONTDOOR_API_TAG2] })).output(FrontDoorStatusOutputSchema).handler(() => deps.frontDoorStatus()),
13591
+ sessions: authed.meta(openapi7({ method: "GET", path: "/rest/frontdoor/sessions", summary: "Read the front door's session registry", tags: [FRONTDOOR_API_TAG2] })).output(FrontDoorSessionsOutputSchema).handler(() => ({ sessions: deps.frontDoorStatus().sessions }))
12966
13592
  },
12967
13593
  check: {
12968
13594
  // The report's own JSON shape is the contract (the same one `check --json` prints and `checkReportSchema.ts` defines), so the procedure returns exactly that conversion.
12969
- run: authed.meta(openapi6({ method: "GET", path: "/rest/check", summary: "Run the check report for one directory", tags: [CHECK_API_TAG] })).input(CheckRunInputSchema).output(CheckReportJsonSchema).handler(({ input }) => checkReportToJson(deps.checkReport(input.path, input.identity)))
13595
+ run: authed.meta(openapi7({ method: "GET", path: "/rest/check", summary: "Run the check report for one directory", tags: [CHECK_API_TAG] })).input(CheckRunInputSchema).output(CheckReportJsonSchema).handler(({ input }) => checkReportToJson(deps.checkReport(input.path, input.identity)))
12970
13596
  },
12971
13597
  doctor: {
12972
- run: authed.meta(openapi6({ method: "GET", path: "/rest/doctor", summary: "Run the doctor report", tags: [DOCTOR_API_TAG] })).output(DoctorRunOutputSchema).handler(() => deps.doctorReport())
13598
+ run: authed.meta(openapi7({ method: "GET", path: "/rest/doctor", summary: "Run the doctor report", tags: [DOCTOR_API_TAG] })).output(DoctorRunOutputSchema).handler(() => deps.doctorReport())
12973
13599
  },
12974
13600
  pool: {
12975
- pick: authed.meta(openapi6({ method: "GET", path: "/rest/pool/pick", summary: "Rank one pool exactly as a launch from a directory would right now", tags: [POOL_API_TAG] })).input(PoolPickInputSchema).output(PoolPickReportSchema).handler(({ input }) => {
13601
+ pick: authed.meta(openapi7({ method: "GET", path: "/rest/pool/pick", summary: "Rank one pool exactly as a launch from a directory would right now", tags: [POOL_API_TAG] })).input(PoolPickInputSchema).output(PoolPickReportSchema).handler(({ input }) => {
12976
13602
  const report = deps.poolPick(input.pool, input.path);
12977
13603
  if (report === void 0) {
12978
13604
  const live = deps.poolNames();
12979
- throw new ORPCError5("NOT_FOUND", {
13605
+ throw new ORPCError6("NOT_FOUND", {
12980
13606
  message: live.length === 0 ? `no pools are configured, so none is named ${input.pool}` : `no pool is named ${input.pool}; the live pools are ${live.map((name) => `"${name}"`).join(", ")}`
12981
13607
  });
12982
13608
  }
@@ -12988,7 +13614,7 @@ function createControlApiRouter(deps) {
12988
13614
  function createDoorApiRouter(deps) {
12989
13615
  const control = createControlApiRouter(deps);
12990
13616
  const lifecycle = createLifecycleApiRouter(deps);
12991
- return { ...createRcApiRouter(deps), ...control, ...lifecycle, ...createCodexApiRouter(deps), ...createLaunchApiRouter(deps), ...createEventsApiRouter(deps), frontdoor: { ...control.frontdoor, ...lifecycle.frontdoor } };
13617
+ return { ...createRcApiRouter(deps), ...control, ...lifecycle, ...createConfigApiRouter(deps), ...createCodexApiRouter(deps), ...createLaunchApiRouter(deps), ...createEventsApiRouter(deps), frontdoor: { ...control.frontdoor, ...lifecycle.frontdoor } };
12992
13618
  }
12993
13619
  function createDoorApiNodeHandler(deps) {
12994
13620
  return doorApiNodeHandlerOf(createDoorApiRouter(deps), deps.expectedToken);
@@ -13800,9 +14426,9 @@ async function serveRcCompatSessions(ctx, pathname, compatPath) {
13800
14426
  const slash = rest.indexOf("/");
13801
14427
  const address = slash === -1 ? rest : rest.slice(0, slash);
13802
14428
  const compatTail = slash === -1 ? "" : rest.slice(slash + 1);
13803
- const refusal = ctx.credentialRefusal(request4.headers);
13804
- if (refusal !== void 0) {
13805
- await ctx.unauthorized(response, refusal);
14429
+ const refusal2 = ctx.credentialRefusal(request4.headers);
14430
+ if (refusal2 !== void 0) {
14431
+ await ctx.unauthorized(response, refusal2);
13806
14432
  return;
13807
14433
  }
13808
14434
  const session = ctx.sessions.get(address) ?? ctx.sessions.get(`cse_${address}`);
@@ -13880,9 +14506,9 @@ function conversationRow(conversation) {
13880
14506
  }
13881
14507
  async function serveRcConversations(ctx, pathname, method) {
13882
14508
  const { request: request4, response, conversations } = ctx;
13883
- const refusal = ctx.credentialRefusal(request4.headers);
13884
- if (refusal !== void 0) {
13885
- await ctx.unauthorized(response, refusal);
14509
+ const refusal2 = ctx.credentialRefusal(request4.headers);
14510
+ if (refusal2 !== void 0) {
14511
+ await ctx.unauthorized(response, refusal2);
13886
14512
  return;
13887
14513
  }
13888
14514
  if (pathname === RC_CONVERSATIONS_PATH_PREFIX) {
@@ -14206,9 +14832,9 @@ async function fetchThroughWebProxy(url, deps) {
14206
14832
  try {
14207
14833
  let redirects = 0;
14208
14834
  for (; ; ) {
14209
- const refusal = await checkTarget(current, deps);
14210
- if (refusal !== void 0) {
14211
- return refusal;
14835
+ const refusal2 = await checkTarget(current, deps);
14836
+ if (refusal2 !== void 0) {
14837
+ return refusal2;
14212
14838
  }
14213
14839
  let hop;
14214
14840
  try {
@@ -14578,8 +15204,8 @@ data: ${JSON.stringify(envelope)}
14578
15204
  "doubled-scheme-word": "the self-hosted Remote Control surface reads one Bearer scheme word, and this call's Authorization header carried it twice: a persisted session record holds the whole header value with the scheme word included, so prefixing Bearer onto it presents a different credential",
14579
15205
  unrecognised: "the self-hosted Remote Control surface did not recognise the presented credential"
14580
15206
  };
14581
- const unauthorized = async (response, refusal) => {
14582
- await answerJson2(response, HTTP_STATUS.unauthorized, { type: "error", error: { type: "authentication_error", message: refusalMessages[refusal] } });
15207
+ const unauthorized = async (response, refusal2) => {
15208
+ await answerJson2(response, HTTP_STATUS.unauthorized, { type: "error", error: { type: "authentication_error", message: refusalMessages[refusal2] } });
14583
15209
  };
14584
15210
  const serveSessionPath = async (session, tail, request4, response) => {
14585
15211
  const method = request4.method.toUpperCase();
@@ -14590,9 +15216,9 @@ data: ${JSON.stringify(envelope)}
14590
15216
  session.lastTrafficAt = deps.now();
14591
15217
  if (tail === "") {
14592
15218
  if (method === "PATCH" || method === "PUT") {
14593
- const refusal = credentialRefusal(request4.headers);
14594
- if (refusal !== void 0) {
14595
- await unauthorized(response, refusal);
15219
+ const refusal2 = credentialRefusal(request4.headers);
15220
+ if (refusal2 !== void 0) {
15221
+ await unauthorized(response, refusal2);
14596
15222
  return;
14597
15223
  }
14598
15224
  const body = parseJsonObject5(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
@@ -14615,9 +15241,9 @@ data: ${JSON.stringify(envelope)}
14615
15241
  return;
14616
15242
  }
14617
15243
  if (tail === "bridge" && method === "POST") {
14618
- const refusal = credentialRefusal(request4.headers);
14619
- if (refusal !== void 0) {
14620
- await unauthorized(response, refusal);
15244
+ const refusal2 = credentialRefusal(request4.headers);
15245
+ if (refusal2 !== void 0) {
15246
+ await unauthorized(response, refusal2);
14621
15247
  return;
14622
15248
  }
14623
15249
  const workerJwt = mintWorkerJwt(deps.randomToken, deps.now());
@@ -14627,9 +15253,9 @@ data: ${JSON.stringify(envelope)}
14627
15253
  return;
14628
15254
  }
14629
15255
  if (tail === "archive" && method === "POST") {
14630
- const refusal = credentialRefusal(request4.headers);
14631
- if (refusal !== void 0) {
14632
- await unauthorized(response, refusal);
15256
+ const refusal2 = credentialRefusal(request4.headers);
15257
+ if (refusal2 !== void 0) {
15258
+ await unauthorized(response, refusal2);
14633
15259
  return;
14634
15260
  }
14635
15261
  retireSession(session);
@@ -14640,9 +15266,9 @@ data: ${JSON.stringify(envelope)}
14640
15266
  if (tail === "worker" || tail.startsWith("worker/")) {
14641
15267
  const workerTail = tail === "worker" ? "" : tail.slice("worker/".length);
14642
15268
  const webProxy = workerTail === "web-fetch" || workerTail === "web-search";
14643
- const refusal = webProxy ? workerOrCredentialRefusal(request4.headers, session) : workerRefusal(request4.headers, session);
14644
- if (refusal !== void 0) {
14645
- await unauthorized(response, refusal);
15269
+ const refusal2 = webProxy ? workerOrCredentialRefusal(request4.headers, session) : workerRefusal(request4.headers, session);
15270
+ if (refusal2 !== void 0) {
15271
+ await unauthorized(response, refusal2);
14646
15272
  return;
14647
15273
  }
14648
15274
  if (workerTail === "" && method === "GET") {
@@ -15055,102 +15681,6 @@ init_paths();
15055
15681
  init_cliError();
15056
15682
  init_schema();
15057
15683
  init_providersStore();
15058
-
15059
- // src/directoryRulesStore.ts
15060
- init_store();
15061
- init_load();
15062
- init_schema();
15063
- init_cliError();
15064
- var DirectoryRuleNotFoundError = class extends CliError {
15065
- constructor(rulePath) {
15066
- super(`No directory rule found for path "${rulePath}".`);
15067
- this.rulePath = rulePath;
15068
- this.name = "DirectoryRuleNotFoundError";
15069
- }
15070
- rulePath;
15071
- };
15072
- var DirectoryRuleMissingTargetError = class extends CliError {
15073
- constructor() {
15074
- super("A directory rule must set at least one of --config-profile or --identity.");
15075
- this.name = "DirectoryRuleMissingTargetError";
15076
- }
15077
- };
15078
- var DirectoryRuleAlreadyExistsError = class extends CliError {
15079
- constructor(rulePath) {
15080
- super(`A directory rule for path "${rulePath}" already exists. Use \`agent-shim rule set\` to change it.`);
15081
- this.rulePath = rulePath;
15082
- this.name = "DirectoryRuleAlreadyExistsError";
15083
- }
15084
- rulePath;
15085
- };
15086
- function readDirectoryRules(paths) {
15087
- return readJson(paths.directoryRulesFile, DirectoryRulesSchema) ?? { rules: [] };
15088
- }
15089
- function writeDirectoryRules(paths, rules) {
15090
- const parsed = DirectoryRulesSchema.safeParse(rules);
15091
- if (!parsed.success) {
15092
- throw new ConfigValidationError(paths.directoryRulesFile, parsed.error.issues);
15093
- }
15094
- writeJsonAtomic(paths.directoryRulesFile, parsed.data);
15095
- }
15096
- function listDirectoryRules(paths) {
15097
- return readDirectoryRules(paths).rules;
15098
- }
15099
- function addDirectoryRule(paths, rulePath, options) {
15100
- if (options.configProfile === void 0 && options.identity === void 0) {
15101
- throw new DirectoryRuleMissingTargetError();
15102
- }
15103
- const current = readDirectoryRules(paths);
15104
- if (current.rules.some((rule) => rule.path === rulePath)) {
15105
- throw new DirectoryRuleAlreadyExistsError(rulePath);
15106
- }
15107
- const created = buildNewRule(rulePath, options);
15108
- writeDirectoryRules(paths, { ...current, rules: [...current.rules, created] });
15109
- return created;
15110
- }
15111
- function ruleHasEffect(rule) {
15112
- return rule.configProfile !== void 0 || rule.identity !== void 0 || rule.categories !== void 0 || rule.entries !== void 0 || rule.launch !== void 0;
15113
- }
15114
- function updateDirectoryRule(paths, rulePath, options) {
15115
- const current = readDirectoryRules(paths);
15116
- const index = current.rules.findIndex((rule) => rule.path === rulePath);
15117
- const existing = index === -1 ? void 0 : current.rules[index];
15118
- if (existing === void 0) {
15119
- throw new DirectoryRuleNotFoundError(rulePath);
15120
- }
15121
- const { configProfile, identity, ...rest } = existing;
15122
- const nextConfigProfile = options.configProfile === void 0 ? configProfile : options.configProfile === false ? void 0 : options.configProfile;
15123
- const nextIdentity = options.identity === void 0 ? identity : options.identity === false ? void 0 : options.identity;
15124
- const updated = {
15125
- ...rest,
15126
- ...nextConfigProfile === void 0 ? {} : { configProfile: nextConfigProfile },
15127
- ...nextIdentity === void 0 ? {} : { identity: nextIdentity }
15128
- };
15129
- if (!ruleHasEffect(updated)) {
15130
- throw new DirectoryRuleMissingTargetError();
15131
- }
15132
- const nextRules = [...current.rules];
15133
- nextRules[index] = updated;
15134
- writeDirectoryRules(paths, { ...current, rules: nextRules });
15135
- return updated;
15136
- }
15137
- function buildNewRule(rulePath, options) {
15138
- return {
15139
- path: rulePath,
15140
- ...options.configProfile !== void 0 ? { configProfile: options.configProfile } : {},
15141
- ...options.identity !== void 0 ? { identity: options.identity } : {}
15142
- };
15143
- }
15144
- function removeDirectoryRule(paths, rulePath) {
15145
- const current = readDirectoryRules(paths);
15146
- const nextRules = current.rules.filter((rule) => rule.path !== rulePath);
15147
- if (nextRules.length === current.rules.length) {
15148
- throw new DirectoryRuleNotFoundError(rulePath);
15149
- }
15150
- writeDirectoryRules(paths, { ...current, rules: nextRules });
15151
- }
15152
-
15153
- // src/index.ts
15154
15684
  init_launcher();
15155
15685
  init_spawn();
15156
15686
  init_launchWiring();
@@ -15264,10 +15794,44 @@ export {
15264
15794
  CodexLogoutOutputSchema,
15265
15795
  CodexSignInSchema,
15266
15796
  CodexStatusOutputSchema,
15797
+ ConfigIdentityAddOutputSchema,
15798
+ ConfigIdentityRemoveInputSchema,
15799
+ ConfigIdentityRemoveOutputSchema,
15800
+ ConfigIdentitySetInputSchema,
15801
+ ConfigIdentitySetOutputSchema,
15802
+ ConfigIdentityUseOutputSchema,
15803
+ ConfigNameInputSchema,
15804
+ ConfigPoolAddInputSchema,
15805
+ ConfigPoolAddOutputSchema,
15806
+ ConfigPoolRemoveInputSchema,
15807
+ ConfigPoolRemoveOutputSchema,
15808
+ ConfigPoolSetInputSchema,
15809
+ ConfigPoolSetOutputSchema,
15810
+ ConfigPoolUseOutputSchema,
15811
+ ConfigProfileAddInputSchema,
15812
+ ConfigProfileAddOutputSchema,
15813
+ ConfigProfileRemoveInputSchema,
15814
+ ConfigProfileRemoveOutputSchema,
15267
15815
  ConfigProfileSchema,
15816
+ ConfigProfileSetInputSchema,
15817
+ ConfigProfileSetOutputSchema,
15818
+ ConfigProfileUseOutputSchema,
15819
+ ConfigProviderAddInputSchema,
15820
+ ConfigProviderAddOutputSchema,
15821
+ ConfigProviderRemoveInputSchema,
15822
+ ConfigProviderRemoveOutputSchema,
15823
+ ConfigProviderSetInputSchema,
15824
+ ConfigProviderSetOutputSchema,
15825
+ ConfigRuleAddInputSchema,
15826
+ ConfigRuleAddOutputSchema,
15827
+ ConfigRuleRemoveInputSchema,
15828
+ ConfigRuleRemoveOutputSchema,
15829
+ ConfigRuleSetInputSchema,
15830
+ ConfigRuleSetOutputSchema,
15268
15831
  CredentialCacheSchema,
15269
15832
  CredentialSchema,
15270
15833
  CredentialSourceSchema,
15834
+ CredentialSummarySchema2 as CredentialSummarySchema,
15271
15835
  DOOR_EVENT_BUFFER_EVENTS,
15272
15836
  DOOR_EVENT_SOURCE_RC,
15273
15837
  DOOR_HEALTH_EVENT_SOURCE,
@@ -15398,6 +15962,7 @@ export {
15398
15962
  collectFrontDoorStatus,
15399
15963
  collectPoolPick,
15400
15964
  createCodexApiRouter,
15965
+ createConfigApiRouter,
15401
15966
  createControlApiRouter,
15402
15967
  createDoorApiNodeHandler,
15403
15968
  createDoorApiRouter,