claude-use 9.6.0 → 9.7.1

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/cli.cjs CHANGED
@@ -26769,7 +26769,7 @@ function isCodexProvider(provider) {
26769
26769
  function poolMemberIdentity(member) {
26770
26770
  return typeof member === "string" ? member : member.identity;
26771
26771
  }
26772
- var import_node_path4, 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, PROVIDER_KINDS, CODEX_TIERS, CODEX_EFFORTS, CODEX_LOGINS, CODEX_DEFAULT_LOGIN, CODEX_DEFAULT_MODEL, CODEX_DEFAULT_TIER_MODELS, CODEX_DEFAULT_EFFORT, 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, FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES, FrontDoorGlobalConfigSchema, UPDATE_MODES, UpdateGlobalConfigSchema, GlobalConfigSchema, IdentitySchema, CategoryClassificationSchema, CategoryClassificationOverlaySchema, SHIPPED_CATEGORY_DEFAULTS;
26772
+ var import_node_path4, 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_TIERS, CODEX_EFFORTS, CODEX_LOGINS, CODEX_DEFAULT_LOGIN, CODEX_DEFAULT_MODEL, CODEX_DEFAULT_TIER_MODELS, CODEX_DEFAULT_EFFORT, 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, FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES, FrontDoorGlobalConfigSchema, UPDATE_MODES, UpdateGlobalConfigSchema, GlobalConfigSchema, IdentitySchema, CategoryClassificationSchema, CategoryClassificationOverlaySchema, SHIPPED_CATEGORY_DEFAULTS;
26773
26773
  var init_schema = __esm({
26774
26774
  "src/config/schema.ts"() {
26775
26775
  "use strict";
@@ -26825,20 +26825,33 @@ var init_schema = __esm({
26825
26825
  /** 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. */
26826
26826
  timeoutMs: external_exports.int().positive().optional()
26827
26827
  };
26828
+ EnvCredentialSourceSchema = external_exports.strictObject({ env: external_exports.string().min(1) });
26829
+ FileCredentialSourceSchema = external_exports.strictObject({
26830
+ file: external_exports.string().min(1).refine((filePath) => filePath.startsWith("~/") || import_node_path4.default.isAbsolute(filePath), {
26831
+ message: "a credential file must be an absolute or ~-rooted path, since a launch can start in any directory"
26832
+ })
26833
+ });
26834
+ CommandCredentialSourceSchema = external_exports.strictObject({ command: ArgvSchema, ...CommandSourceOptions });
26835
+ OpCredentialSourceSchema = external_exports.strictObject({ op: external_exports.string().startsWith("op://"), ...CommandSourceOptions });
26836
+ KeychainCredentialSourceSchema = external_exports.strictObject({
26837
+ keychain: external_exports.strictObject({ service: external_exports.string().min(1), account: external_exports.string().min(1).optional() }),
26838
+ ...CommandSourceOptions
26839
+ });
26840
+ LiteralCredentialSourceSchema = external_exports.strictObject({ literal: external_exports.string().min(1) });
26828
26841
  CredentialSourceSchema = external_exports.union([
26829
- external_exports.strictObject({ env: external_exports.string().min(1) }),
26830
- external_exports.strictObject({
26831
- file: external_exports.string().min(1).refine((filePath) => filePath.startsWith("~/") || import_node_path4.default.isAbsolute(filePath), {
26832
- message: "a credential file must be an absolute or ~-rooted path, since a launch can start in any directory"
26833
- })
26834
- }),
26835
- external_exports.strictObject({ command: ArgvSchema, ...CommandSourceOptions }),
26836
- external_exports.strictObject({ op: external_exports.string().startsWith("op://"), ...CommandSourceOptions }),
26837
- external_exports.strictObject({
26838
- keychain: external_exports.strictObject({ service: external_exports.string().min(1), account: external_exports.string().min(1).optional() }),
26839
- ...CommandSourceOptions
26840
- }),
26841
- external_exports.strictObject({ literal: external_exports.string().min(1) })
26842
+ EnvCredentialSourceSchema,
26843
+ FileCredentialSourceSchema,
26844
+ CommandCredentialSourceSchema,
26845
+ OpCredentialSourceSchema,
26846
+ KeychainCredentialSourceSchema,
26847
+ LiteralCredentialSourceSchema
26848
+ ]);
26849
+ RemoteCredentialSourceSchema = external_exports.union([
26850
+ EnvCredentialSourceSchema,
26851
+ FileCredentialSourceSchema,
26852
+ OpCredentialSourceSchema,
26853
+ KeychainCredentialSourceSchema,
26854
+ LiteralCredentialSourceSchema
26842
26855
  ]);
26843
26856
  CREDENTIAL_CACHE_STORES = ["keychain", "file"];
26844
26857
  CredentialCacheSchema = external_exports.strictObject({
@@ -27454,8 +27467,8 @@ function verifyHeadroomSocket(socketPath, ports) {
27454
27467
  }
27455
27468
  const uid = ports.currentUid();
27456
27469
  const directory = import_node_path7.default.dirname(socketPath);
27457
- const refusal = ownerOnlyRefusal("socket directory", directory, ports.lstat(directory), "dir", uid) ?? ownerOnlyRefusal("socket", socketPath, ports.lstat(socketPath), "socket", uid);
27458
- return refusal === void 0 ? { socketPath } : { refused: refusal };
27470
+ const refusal2 = ownerOnlyRefusal("socket directory", directory, ports.lstat(directory), "dir", uid) ?? ownerOnlyRefusal("socket", socketPath, ports.lstat(socketPath), "socket", uid);
27471
+ return refusal2 === void 0 ? { socketPath } : { refused: refusal2 };
27459
27472
  }
27460
27473
  function prepareHeadroomSocket(fs21, ports, paths, supervisorPid) {
27461
27474
  const unsupported = platformRefusal(ports.platform);
@@ -27473,8 +27486,8 @@ function prepareHeadroomSocket(fs21, ports, paths, supervisorPid) {
27473
27486
  return { refused: `the headroom socket directory ${paths.headroomSocketDir} is a symlink; it must be the real directory` };
27474
27487
  }
27475
27488
  fs21.mkdirPrivate(paths.headroomSocketDir);
27476
- const refusal = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
27477
- return refusal === void 0 ? { socketPath } : { refused: refusal };
27489
+ const refusal2 = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
27490
+ return refusal2 === void 0 ? { socketPath } : { refused: refusal2 };
27478
27491
  }
27479
27492
  function pruneStaleHeadroomSockets(fs21, paths, isRunning) {
27480
27493
  const removed = [];
@@ -33229,7 +33242,7 @@ var init_package = __esm({
33229
33242
  "package.json"() {
33230
33243
  package_default = {
33231
33244
  name: "claude-use",
33232
- version: "9.6.0",
33245
+ version: "9.7.1",
33233
33246
  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.",
33234
33247
  license: "MIT",
33235
33248
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -34028,14 +34041,14 @@ function capacityOf(plan) {
34028
34041
  return plan.kind === "subscription" ? plan.capacity : 1;
34029
34042
  }
34030
34043
  function assessRefusedNested(member, nested, nowMs) {
34031
- 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 };
34044
+ 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 };
34032
34045
  return {
34033
34046
  candidate: {
34034
34047
  identity: member.identity,
34035
34048
  class: "ineligible",
34036
- ...refusal.blockedUntilMs === void 0 ? {} : { blockedUntilMs: refusal.blockedUntilMs },
34049
+ ...refusal2.blockedUntilMs === void 0 ? {} : { blockedUntilMs: refusal2.blockedUntilMs },
34037
34050
  plan: planOf(member.account),
34038
- reasons: [refusal.reason]
34051
+ reasons: [refusal2.reason]
34039
34052
  }
34040
34053
  };
34041
34054
  }
@@ -34126,7 +34139,7 @@ function rankPool(input2) {
34126
34139
  const assessments = members2.map((member) => ({ member, ...assess(member, nowMs) }));
34127
34140
  const demands = assessments.flatMap(({ candidate, burn }) => burn === void 0 ? [] : [burn * capacityOf(candidate.plan)]);
34128
34141
  const sharedDemand = demands.length === 0 ? void 0 : Math.max(...demands);
34129
- const guarded = assessments.map((assessment) => {
34142
+ const guarded2 = assessments.map((assessment) => {
34130
34143
  const { candidate } = assessment;
34131
34144
  if (candidate.class === "ineligible" || assessment.member.policy === void 0) {
34132
34145
  return assessment;
@@ -34141,7 +34154,7 @@ function rankPool(input2) {
34141
34154
  }
34142
34155
  return { ...assessment, candidate: { ...candidate, class: "ineligible", reasons: [`skipped by policy (${verdict.checked.join(", ")}: did not hold)`, ...candidate.reasons] } };
34143
34156
  });
34144
- const candidates = guarded.map((assessment) => {
34157
+ const candidates = guarded2.map((assessment) => {
34145
34158
  const { candidate, fiveHour, burn } = assessment;
34146
34159
  const pace = burn ?? (sharedDemand === void 0 ? void 0 : sharedDemand / capacityOf(candidate.plan));
34147
34160
  const { sevenDay, sevenDayBurn } = assessment;
@@ -108445,6 +108458,48 @@ function removeProfile(paths, name) {
108445
108458
  requireProfileExists(paths, name);
108446
108459
  import_node_fs5.default.rmSync(profileJsonPath(paths, name));
108447
108460
  }
108461
+ function applyProfileChange(paths, name, change) {
108462
+ let touched = false;
108463
+ if (change.category !== void 0) {
108464
+ setProfileCategories(paths, name, change.category);
108465
+ touched = true;
108466
+ }
108467
+ if (change.entry !== void 0) {
108468
+ setProfileEntries(paths, name, change.entry);
108469
+ touched = true;
108470
+ }
108471
+ if (change.extends !== void 0 || change.description !== void 0) {
108472
+ setProfileMetadata(paths, name, {
108473
+ ...change.extends === void 0 ? {} : { extends: change.extends === false ? [] : change.extends },
108474
+ ...change.description === void 0 ? {} : { description: change.description }
108475
+ });
108476
+ touched = true;
108477
+ }
108478
+ const launchPatch = {};
108479
+ if (change.launchSkipPermissions !== void 0) {
108480
+ launchPatch.skipPermissions = change.launchSkipPermissions;
108481
+ }
108482
+ if (change.launchRemoteControl !== void 0) {
108483
+ launchPatch.remoteControl = change.launchRemoteControl;
108484
+ }
108485
+ if (change.launchHeadroom !== void 0) {
108486
+ launchPatch.headroom = change.launchHeadroom;
108487
+ }
108488
+ if (change.launchTrackUsage !== void 0) {
108489
+ launchPatch.trackUsage = change.launchTrackUsage;
108490
+ }
108491
+ if (change.launchProvider !== void 0) {
108492
+ launchPatch.provider = change.launchProvider === false ? void 0 : change.launchProvider;
108493
+ }
108494
+ if (change.launchClaudeVersion !== void 0) {
108495
+ launchPatch.claudeVersion = change.launchClaudeVersion === false ? void 0 : change.launchClaudeVersion;
108496
+ }
108497
+ if (Object.keys(launchPatch).length > 0) {
108498
+ setProfileLaunchFlags(paths, name, launchPatch);
108499
+ touched = true;
108500
+ }
108501
+ return touched;
108502
+ }
108448
108503
 
108449
108504
  // src/poolStore.ts
108450
108505
  init_store();
@@ -108579,6 +108634,14 @@ var InvalidIdentityNameError = class extends CliError {
108579
108634
  function identityJsonPath(paths, name) {
108580
108635
  return import_node_path13.default.join(paths.identitiesDir, name, "identity.json");
108581
108636
  }
108637
+ function requireIdentityNames(paths, names) {
108638
+ const existing = new Set(listIdentities(paths).map((entry) => entry.name));
108639
+ for (const name of names) {
108640
+ if (poolNameOf(name) === void 0 && !existing.has(name)) {
108641
+ throw new IdentityNotFoundError(name);
108642
+ }
108643
+ }
108644
+ }
108582
108645
  function identityExists(paths, name) {
108583
108646
  return import_node_fs6.default.existsSync(identityJsonPath(paths, name));
108584
108647
  }
@@ -108787,6 +108850,16 @@ function removeDirectoryRule(paths, rulePath) {
108787
108850
  }
108788
108851
  writeDirectoryRules(paths, { ...current, rules: nextRules });
108789
108852
  }
108853
+ function requireRuleSelector(paths, selector) {
108854
+ if (selector.startsWith(POOL_SELECTOR_PREFIX)) {
108855
+ const poolName = selector.slice(POOL_SELECTOR_PREFIX.length);
108856
+ if (readPools(paths)[poolName] === void 0) {
108857
+ throw new PoolNotFoundError(poolName);
108858
+ }
108859
+ } else if (readIdentity(paths, selector) === void 0) {
108860
+ throw new IdentityNotFoundError(selector);
108861
+ }
108862
+ }
108790
108863
 
108791
108864
  // src/configure.ts
108792
108865
  init_legacy();
@@ -109318,7 +109391,31 @@ var import_node_path22 = __toESM(require("node:path"), 1);
109318
109391
  init_commandDeps();
109319
109392
 
109320
109393
  // src/cli/credentialOption.ts
109394
+ init_cliError();
109395
+ init_schema();
109396
+
109397
+ // src/credentialCacheChange.ts
109398
+ init_cliError();
109321
109399
  init_schema();
109400
+ function mergeCredentialCache(request7, existing) {
109401
+ if (request7.enabled === false) {
109402
+ return false;
109403
+ }
109404
+ if (request7.ttl === void 0 && request7.store === void 0 && request7.enabled !== true) {
109405
+ return void 0;
109406
+ }
109407
+ const parsed = CredentialCacheSchema.safeParse({
109408
+ ...existing,
109409
+ ...request7.ttl === void 0 ? {} : { ttl: request7.ttl },
109410
+ ...request7.store === void 0 ? {} : { store: request7.store }
109411
+ });
109412
+ if (!parsed.success) {
109413
+ throw new UsageError(parsed.error.issues.map((issue2) => issue2.message).join("; "));
109414
+ }
109415
+ return parsed.data;
109416
+ }
109417
+
109418
+ // src/cli/credentialOption.ts
109322
109419
  var CREDENTIAL_SOURCE_SYNTAX = "env:<VAR>, file:<path>, command:<program and arguments>, op:<op://reference>, keychain:<service>[:<account>], literal:<placeholder>, or a JSON source object";
109323
109420
  function parseCredentialSource(spec) {
109324
109421
  let candidate;
@@ -109373,21 +109470,18 @@ function addCredentialCacheOptions(command) {
109373
109470
  ).option("--credential-cache", "Cache this credential in the default store with no expiry (add --credential-cache-ttl for one).").option("--no-credential-cache", "Stop caching this credential. Run `credential forget` first to drop the stored copy.");
109374
109471
  }
109375
109472
  function cacheChange(options, existing) {
109376
- if (options.credentialCache === false) {
109377
- return false;
109378
- }
109379
- if (options.credentialCacheTtl === void 0 && options.credentialCacheStore === void 0 && options.credentialCache !== true) {
109380
- return void 0;
109381
- }
109382
- const parsed = CredentialCacheSchema.safeParse({
109383
- ...existing,
109384
- ...options.credentialCacheTtl === void 0 ? {} : { ttl: options.credentialCacheTtl },
109385
- ...options.credentialCacheStore === void 0 ? {} : { store: options.credentialCacheStore }
109386
- });
109387
- if (!parsed.success) {
109388
- throw new InvalidArgumentError(parsed.error.issues.map((issue2) => issue2.message).join("; "));
109473
+ try {
109474
+ return mergeCredentialCache(
109475
+ {
109476
+ ...options.credentialCache === void 0 ? {} : { enabled: options.credentialCache },
109477
+ ...options.credentialCacheTtl === void 0 ? {} : { ttl: options.credentialCacheTtl },
109478
+ ...options.credentialCacheStore === void 0 ? {} : { store: options.credentialCacheStore }
109479
+ },
109480
+ existing
109481
+ );
109482
+ } catch (error63) {
109483
+ throw error63 instanceof UsageError ? new InvalidArgumentError(error63.message) : error63;
109389
109484
  }
109390
- return parsed.data;
109391
109485
  }
109392
109486
 
109393
109487
  // src/identityManager.ts
@@ -109502,48 +109596,6 @@ async function ensureProfileExists(deps, name) {
109502
109596
  function toProfileView(name, profile, globalDefault) {
109503
109597
  return { name, globalDefault: name === globalDefault, ...profile, $schema: void 0 };
109504
109598
  }
109505
- function applyProfileSet(paths, name, options) {
109506
- let touched = false;
109507
- if (options.category !== void 0) {
109508
- setProfileCategories(paths, name, options.category);
109509
- touched = true;
109510
- }
109511
- if (options.entry !== void 0) {
109512
- setProfileEntries(paths, name, options.entry);
109513
- touched = true;
109514
- }
109515
- if (options.extends !== void 0 || options.description !== void 0) {
109516
- setProfileMetadata(paths, name, {
109517
- ...options.extends === void 0 ? {} : { extends: options.extends === false ? [] : options.extends },
109518
- ...options.description === void 0 ? {} : { description: options.description }
109519
- });
109520
- touched = true;
109521
- }
109522
- const launchPatch = {};
109523
- if (options.launchSkipPermissions !== void 0) {
109524
- launchPatch.skipPermissions = options.launchSkipPermissions;
109525
- }
109526
- if (options.launchRemoteControl !== void 0) {
109527
- launchPatch.remoteControl = options.launchRemoteControl;
109528
- }
109529
- if (options.launchHeadroom !== void 0) {
109530
- launchPatch.headroom = options.launchHeadroom;
109531
- }
109532
- if (options.launchTrackUsage !== void 0) {
109533
- launchPatch.trackUsage = options.launchTrackUsage;
109534
- }
109535
- if (options.launchProvider !== void 0) {
109536
- launchPatch.provider = options.launchProvider === false ? void 0 : options.launchProvider;
109537
- }
109538
- if (options.launchClaudeVersion !== void 0) {
109539
- launchPatch.claudeVersion = options.launchClaudeVersion === false ? void 0 : options.launchClaudeVersion;
109540
- }
109541
- if (Object.keys(launchPatch).length > 0) {
109542
- setProfileLaunchFlags(paths, name, launchPatch);
109543
- touched = true;
109544
- }
109545
- return touched;
109546
- }
109547
109599
  function registerProfileCommand(program2, deps) {
109548
109600
  const { paths } = deps;
109549
109601
  const profile = withExamples(
@@ -109592,7 +109644,7 @@ function registerProfileCommand(program2, deps) {
109592
109644
  throw new PromptCancelledError();
109593
109645
  }
109594
109646
  } else {
109595
- applyProfileSet(paths, name, options);
109647
+ applyProfileChange(paths, name, options);
109596
109648
  }
109597
109649
  reportMutation(json2, { action: "updated", kind: "profile", name, value: readProfile(paths, name) }, () => {
109598
109650
  console.log(`Updated configuration profile "${name}".`);
@@ -110892,6 +110944,7 @@ var HTTP_STATUS = {
110892
110944
  forbidden: 403,
110893
110945
  notFound: 404,
110894
110946
  methodNotAllowed: 405,
110947
+ conflict: 409,
110895
110948
  payloadTooLarge: 413,
110896
110949
  tooManyRequests: 429,
110897
110950
  /** 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. */
@@ -122794,6 +122847,7 @@ init_capability();
122794
122847
  var RC_ORPC_PATH_PREFIX = "/__agent-shim/orpc";
122795
122848
  var RC_OPENAPI_DOC_PATH = "/openapi.json";
122796
122849
  var RC_SUBSCRIBER_BUFFER_EVENTS = 100;
122850
+ var READ_ONLY_OPERATION_EXTENSION = "x-agent-shim-read-only";
122797
122851
  function doorApiBearer(headers) {
122798
122852
  const presented = headers.authorization;
122799
122853
  const bearerPrefix = "bearer ".length;
@@ -122911,9 +122965,9 @@ function doorApiNodeHandlerOf(router, expectedToken) {
122911
122965
  if (request7.method === "GET" && request7.url === `${RC_ORPC_PATH_PREFIX}${RC_OPENAPI_DOC_PATH}`) {
122912
122966
  const token = doorApiBearer(request7.headers);
122913
122967
  if (token === void 0 || !isLiveCapability(token, [expectedToken])) {
122914
- const refusal = new ORPCError("UNAUTHORIZED", { message: "the front door's OpenAPI document demands this generation's control token as a Bearer credential" });
122968
+ const refusal2 = new ORPCError("UNAUTHORIZED", { message: "the front door's OpenAPI document demands this generation's control token as a Bearer credential" });
122915
122969
  response.writeHead(HTTP_STATUS.unauthorized, { "content-type": "application/json" });
122916
- response.end(JSON.stringify(refusal.toJSON()));
122970
+ response.end(JSON.stringify(refusal2.toJSON()));
122917
122971
  return { matched: true };
122918
122972
  }
122919
122973
  try {
@@ -122921,9 +122975,9 @@ function doorApiNodeHandlerOf(router, expectedToken) {
122921
122975
  response.writeHead(HTTP_STATUS.ok, { "content-type": "application/json" });
122922
122976
  response.end(JSON.stringify(doc));
122923
122977
  } catch (error63) {
122924
- const refusal = new ORPCError("INTERNAL_SERVER_ERROR", { message: `the OpenAPI document could not be generated from the door's own router: ${error63 instanceof Error ? error63.message : String(error63)}` });
122978
+ const refusal2 = new ORPCError("INTERNAL_SERVER_ERROR", { message: `the OpenAPI document could not be generated from the door's own router: ${error63 instanceof Error ? error63.message : String(error63)}` });
122925
122979
  response.writeHead(HTTP_STATUS.internalServerError, { "content-type": "application/json" });
122926
- response.end(JSON.stringify(refusal.toJSON()));
122980
+ response.end(JSON.stringify(refusal2.toJSON()));
122927
122981
  }
122928
122982
  return { matched: true };
122929
122983
  }
@@ -122991,6 +123045,438 @@ function createCodexApiRouter(deps) {
122991
123045
  };
122992
123046
  }
122993
123047
 
123048
+ // src/frontdoor/configApi.ts
123049
+ init_cliError();
123050
+ init_schema();
123051
+ init_credential();
123052
+ init_identity();
123053
+ init_providersStore();
123054
+
123055
+ // src/frontdoor/configSchemas.ts
123056
+ init_zod();
123057
+ init_schema();
123058
+ var RemovalConfirmationSchema = external_exports.boolean();
123059
+ var CredentialWriteSchema = (targets) => external_exports.strictObject({
123060
+ sources: external_exports.array(RemoteCredentialSourceSchema).min(1).optional(),
123061
+ target: external_exports.enum(targets).optional(),
123062
+ cache: external_exports.union([external_exports.literal(false), CredentialCacheSchema]).optional()
123063
+ });
123064
+ var CredentialSummarySchema2 = external_exports.strictObject({
123065
+ target: external_exports.enum(CREDENTIAL_TARGETS),
123066
+ sources: external_exports.readonly(external_exports.array(
123067
+ external_exports.discriminatedUnion("kind", [
123068
+ external_exports.strictObject({ kind: external_exports.literal("env"), variable: external_exports.string() }),
123069
+ external_exports.strictObject({ kind: external_exports.literal("file"), path: external_exports.string() }),
123070
+ external_exports.strictObject({ kind: external_exports.literal("command"), program: external_exports.string() }),
123071
+ external_exports.strictObject({ kind: external_exports.literal("op"), reference: external_exports.string() }),
123072
+ external_exports.strictObject({ kind: external_exports.literal("keychain"), service: external_exports.string(), account: external_exports.string().optional() }),
123073
+ external_exports.strictObject({ kind: external_exports.literal("literal") })
123074
+ ])
123075
+ )),
123076
+ cache: CredentialCacheSchema.optional()
123077
+ });
123078
+ var mutationOutput = (kind, action) => external_exports.strictObject({ action: external_exports.literal(action), kind: external_exports.literal(kind), name: external_exports.string() });
123079
+ var storedMutationOutput = (kind, action, value2) => external_exports.strictObject({ action: external_exports.literal(action), kind: external_exports.literal(kind), name: external_exports.string(), value: value2 });
123080
+ var IdentityValueSchema = external_exports.strictObject({
123081
+ name: external_exports.string(),
123082
+ defaultConfigProfile: external_exports.string().optional(),
123083
+ allowAmbientCredential: external_exports.boolean(),
123084
+ credential: CredentialSummarySchema2.optional()
123085
+ });
123086
+ var ProfileValueSchema = ConfigProfileSchema.omit({ $schema: true });
123087
+ var ProviderValueSchema = external_exports.strictObject({
123088
+ name: external_exports.string(),
123089
+ kind: external_exports.enum(PROVIDER_KINDS),
123090
+ displayName: external_exports.string(),
123091
+ baseUrl: external_exports.string().optional(),
123092
+ codex: CodexProviderConfigSchema.optional(),
123093
+ credential: CredentialSummarySchema2,
123094
+ env: external_exports.record(external_exports.string(), external_exports.string()).optional()
123095
+ });
123096
+ var ConfigNameInputSchema = external_exports.strictObject({ name: external_exports.string().min(1) });
123097
+ var ConfigIdentityAddOutputSchema = storedMutationOutput("identity", "created", IdentityValueSchema);
123098
+ var ConfigIdentitySetInputSchema = external_exports.strictObject({
123099
+ name: external_exports.string().min(1),
123100
+ defaultConfigProfile: external_exports.union([external_exports.string().min(1), external_exports.literal(false)]).optional(),
123101
+ allowAmbientCredential: external_exports.boolean().optional(),
123102
+ credential: external_exports.union([external_exports.literal(false), CredentialWriteSchema(CREDENTIAL_TARGETS)]).optional()
123103
+ });
123104
+ var ConfigIdentitySetOutputSchema = storedMutationOutput("identity", "updated", IdentityValueSchema);
123105
+ var ConfigIdentityRemoveInputSchema = external_exports.strictObject({ name: external_exports.string().min(1), confirm: RemovalConfirmationSchema });
123106
+ var ConfigIdentityRemoveOutputSchema = mutationOutput("identity", "removed");
123107
+ var ConfigIdentityUseOutputSchema = mutationOutput("identity", "selected");
123108
+ var ConfigProfileAddInputSchema = external_exports.strictObject({
123109
+ name: external_exports.string().min(1),
123110
+ extends: external_exports.array(external_exports.string().min(1)).optional(),
123111
+ description: external_exports.string().optional()
123112
+ });
123113
+ var ConfigProfileAddOutputSchema = storedMutationOutput("profile", "created", ProfileValueSchema);
123114
+ var ConfigProfileSetInputSchema = external_exports.strictObject({
123115
+ name: external_exports.string().min(1),
123116
+ category: external_exports.record(external_exports.string(), external_exports.boolean()).optional(),
123117
+ entry: external_exports.record(external_exports.string(), external_exports.boolean()).optional(),
123118
+ extends: external_exports.union([external_exports.array(external_exports.string().min(1)), external_exports.literal(false)]).optional(),
123119
+ description: external_exports.union([external_exports.string(), external_exports.literal(false)]).optional(),
123120
+ launch: external_exports.strictObject({
123121
+ skipPermissions: external_exports.boolean().optional(),
123122
+ remoteControl: external_exports.boolean().optional(),
123123
+ headroom: external_exports.boolean().optional(),
123124
+ trackUsage: external_exports.boolean().optional(),
123125
+ provider: external_exports.union([external_exports.string().min(1), external_exports.literal(false)]).optional(),
123126
+ claudeVersion: external_exports.union([external_exports.string().min(1), external_exports.literal(false)]).optional()
123127
+ }).optional()
123128
+ });
123129
+ var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
123130
+ var ConfigProfileRemoveInputSchema = external_exports.strictObject({ name: external_exports.string().min(1), confirm: RemovalConfirmationSchema });
123131
+ var ConfigProfileRemoveOutputSchema = mutationOutput("profile", "removed");
123132
+ var ConfigProfileUseOutputSchema = mutationOutput("profile", "selected");
123133
+ var PoolMembersInputSchema = external_exports.array(external_exports.string().min(1)).min(1);
123134
+ var ConfigPoolAddInputSchema = external_exports.strictObject({
123135
+ name: external_exports.string().min(1),
123136
+ identities: PoolMembersInputSchema,
123137
+ preference: external_exports.enum(POOL_PREFERENCES).optional()
123138
+ });
123139
+ var ConfigPoolAddOutputSchema = storedMutationOutput("pool", "created", PoolSchema);
123140
+ var ConfigPoolSetInputSchema = external_exports.strictObject({
123141
+ name: external_exports.string().min(1),
123142
+ identities: PoolMembersInputSchema.optional(),
123143
+ preference: external_exports.union([external_exports.enum(POOL_PREFERENCES), external_exports.literal(false)]).optional()
123144
+ });
123145
+ var ConfigPoolSetOutputSchema = storedMutationOutput("pool", "updated", PoolSchema);
123146
+ var ConfigPoolRemoveInputSchema = external_exports.strictObject({ name: external_exports.string().min(1), confirm: RemovalConfirmationSchema });
123147
+ var ConfigPoolRemoveOutputSchema = mutationOutput("pool", "removed");
123148
+ var ConfigPoolUseOutputSchema = mutationOutput("pool", "selected");
123149
+ var ConfigProviderAddInputSchema = external_exports.strictObject({
123150
+ name: external_exports.string().min(1),
123151
+ kind: external_exports.enum(PROVIDER_KINDS).optional(),
123152
+ displayName: external_exports.string().min(1),
123153
+ baseUrl: external_exports.string().min(1).optional(),
123154
+ credential: CredentialWriteSchema(PROVIDER_CREDENTIAL_TARGETS).required({ sources: true }),
123155
+ codex: CodexProviderConfigSchema.optional()
123156
+ });
123157
+ var ConfigProviderAddOutputSchema = storedMutationOutput("provider", "created", ProviderValueSchema);
123158
+ var ConfigProviderSetInputSchema = external_exports.strictObject({
123159
+ name: external_exports.string().min(1),
123160
+ displayName: external_exports.string().min(1).optional(),
123161
+ baseUrl: external_exports.string().min(1).optional(),
123162
+ credential: CredentialWriteSchema(PROVIDER_CREDENTIAL_TARGETS).optional(),
123163
+ codex: CodexProviderConfigSchema.optional()
123164
+ });
123165
+ var ConfigProviderSetOutputSchema = storedMutationOutput("provider", "updated", ProviderValueSchema);
123166
+ var ConfigProviderRemoveInputSchema = external_exports.strictObject({ name: external_exports.string().min(1), confirm: RemovalConfirmationSchema });
123167
+ var ConfigProviderRemoveOutputSchema = mutationOutput("provider", "removed");
123168
+ var ConfigRuleAddInputSchema = external_exports.strictObject({
123169
+ path: external_exports.string().min(1),
123170
+ configProfile: external_exports.string().min(1).optional(),
123171
+ identity: external_exports.string().min(1).optional()
123172
+ });
123173
+ var ConfigRuleAddOutputSchema = storedMutationOutput("rule", "created", DirectoryRuleSchema);
123174
+ var ConfigRuleSetInputSchema = external_exports.strictObject({
123175
+ path: external_exports.string().min(1),
123176
+ configProfile: external_exports.union([external_exports.string().min(1), external_exports.literal(false)]).optional(),
123177
+ identity: external_exports.union([external_exports.string().min(1), external_exports.literal(false)]).optional()
123178
+ });
123179
+ var ConfigRuleSetOutputSchema = storedMutationOutput("rule", "updated", DirectoryRuleSchema);
123180
+ var ConfigRuleRemoveInputSchema = external_exports.strictObject({ path: external_exports.string().min(1), confirm: RemovalConfirmationSchema });
123181
+ var ConfigRuleRemoveOutputSchema = mutationOutput("rule", "removed");
123182
+
123183
+ // src/frontdoor/configApi.ts
123184
+ var CONFIG_API_TAG = "config";
123185
+ function refusal(error63) {
123186
+ if (error63 instanceof IdentityNotFoundError || error63 instanceof ProfileNotFoundError || error63 instanceof PoolNotFoundError || error63 instanceof ProviderNotFoundError || error63 instanceof DirectoryRuleNotFoundError) {
123187
+ throw new ORPCError("NOT_FOUND", { message: error63.message });
123188
+ }
123189
+ if (error63 instanceof IdentityAlreadyExistsError || error63 instanceof ProfileAlreadyExistsError || error63 instanceof PoolAlreadyExistsError || error63 instanceof ProviderAlreadyExistsError || error63 instanceof DirectoryRuleAlreadyExistsError) {
123190
+ throw new ORPCError("CONFLICT", { message: error63.message });
123191
+ }
123192
+ if (error63 instanceof CliError) {
123193
+ throw new ORPCError("BAD_REQUEST", { message: error63.message });
123194
+ }
123195
+ throw error63;
123196
+ }
123197
+ function guarded(write) {
123198
+ try {
123199
+ return write();
123200
+ } catch (error63) {
123201
+ return refusal(error63);
123202
+ }
123203
+ }
123204
+ function requireConfirmation(confirm, what) {
123205
+ if (!confirm) {
123206
+ throw new ORPCError("BAD_REQUEST", { message: `removing ${what} needs confirm: true, the API's form of the CLI's --yes` });
123207
+ }
123208
+ }
123209
+ function requireChange(given, fields) {
123210
+ if (!given) {
123211
+ throw new ORPCError("BAD_REQUEST", { message: `Nothing to change: pass ${fields}.` });
123212
+ }
123213
+ }
123214
+ function identityValue(name, paths) {
123215
+ const identity = readIdentity(paths, name);
123216
+ if (identity === void 0) {
123217
+ throw new IdentityNotFoundError(name);
123218
+ }
123219
+ return {
123220
+ name: identity.name,
123221
+ ...identity.defaultConfigProfile === void 0 ? {} : { defaultConfigProfile: identity.defaultConfigProfile },
123222
+ allowAmbientCredential: identity.allowAmbientCredential,
123223
+ ...identity.credential === void 0 ? {} : { credential: summariseCredential(identity.credential) }
123224
+ };
123225
+ }
123226
+ function providerValue(name, provider) {
123227
+ return {
123228
+ name,
123229
+ kind: provider.kind ?? "http",
123230
+ displayName: provider.displayName,
123231
+ ...isCodexProvider(provider) ? provider.codex === void 0 ? {} : { codex: provider.codex } : { baseUrl: provider.baseUrl },
123232
+ credential: summariseCredential(provider.credential),
123233
+ ...provider.env === void 0 ? {} : { env: provider.env }
123234
+ };
123235
+ }
123236
+ function profileValue(name, paths) {
123237
+ const profile = { ...readProfile(paths, name) };
123238
+ delete profile.$schema;
123239
+ return profile;
123240
+ }
123241
+ function createConfigApiRouter(deps) {
123242
+ const authed = doorApiAuth(deps.expectedToken);
123243
+ const { paths } = deps;
123244
+ const route = (path48, summary) => authed.meta(openapi({ method: "POST", path: path48, summary, tags: [CONFIG_API_TAG] }));
123245
+ return {
123246
+ config: {
123247
+ identity: {
123248
+ add: route("/rest/config/identity/add", "Create an identity").input(ConfigNameInputSchema).output(ConfigIdentityAddOutputSchema).handler(
123249
+ ({ input: input2 }) => guarded(() => {
123250
+ addIdentity(paths, input2.name);
123251
+ return { action: "created", kind: "identity", name: input2.name, value: identityValue(input2.name, paths) };
123252
+ })
123253
+ ),
123254
+ set: route("/rest/config/identity/set", "Update an identity's default profile, ambient-credential setting or credential").input(ConfigIdentitySetInputSchema).output(ConfigIdentitySetOutputSchema).handler(
123255
+ ({ input: input2 }) => guarded(() => {
123256
+ requireChange(input2.defaultConfigProfile !== void 0 || input2.allowAmbientCredential !== void 0 || input2.credential !== void 0, "defaultConfigProfile, allowAmbientCredential or credential");
123257
+ if (!identityExists(paths, input2.name)) {
123258
+ throw new IdentityNotFoundError(input2.name);
123259
+ }
123260
+ if (typeof input2.defaultConfigProfile === "string") {
123261
+ requireProfileExists(paths, input2.defaultConfigProfile);
123262
+ }
123263
+ if (input2.defaultConfigProfile !== void 0) {
123264
+ setDefaultConfigProfile(paths, input2.name, input2.defaultConfigProfile === false ? void 0 : input2.defaultConfigProfile);
123265
+ }
123266
+ if (input2.allowAmbientCredential !== void 0) {
123267
+ setAllowAmbientCredential(paths, input2.name, input2.allowAmbientCredential);
123268
+ }
123269
+ if (input2.credential === false) {
123270
+ setIdentityCredential(paths, input2.name, false);
123271
+ } else if (input2.credential !== void 0) {
123272
+ const { sources, target, cache } = input2.credential;
123273
+ const merged = cache === void 0 ? void 0 : mergeCredentialCache(cache === false ? { enabled: false } : { ...cache, enabled: true }, readIdentity(paths, input2.name)?.credential?.cache);
123274
+ const change = {
123275
+ ...sources === void 0 ? {} : { sources },
123276
+ ...target === void 0 ? {} : { target },
123277
+ ...merged === void 0 ? {} : { cache: merged }
123278
+ };
123279
+ setIdentityCredential(paths, input2.name, change);
123280
+ }
123281
+ return { action: "updated", kind: "identity", name: input2.name, value: identityValue(input2.name, paths) };
123282
+ })
123283
+ ),
123284
+ remove: route("/rest/config/identity/remove", "Delete an identity and its directory").input(ConfigIdentityRemoveInputSchema).output(ConfigIdentityRemoveOutputSchema).handler(({ input: input2 }) => {
123285
+ requireConfirmation(input2.confirm, `identity "${input2.name}" and its directory`);
123286
+ return guarded(() => {
123287
+ removeIdentity(paths, input2.name);
123288
+ return { action: "removed", kind: "identity", name: input2.name };
123289
+ });
123290
+ }),
123291
+ use: route("/rest/config/identity/use", "Select the active identity").input(ConfigNameInputSchema).output(ConfigIdentityUseOutputSchema).handler(
123292
+ ({ input: input2 }) => guarded(() => {
123293
+ if (poolNameOf(input2.name) === void 0 && !identityExists(paths, input2.name)) {
123294
+ throw new IdentityNotFoundError(input2.name);
123295
+ }
123296
+ useIdentity(paths, input2.name);
123297
+ return { action: "selected", kind: "identity", name: input2.name };
123298
+ })
123299
+ )
123300
+ },
123301
+ profile: {
123302
+ add: route("/rest/config/profile/add", "Create a configuration profile").input(ConfigProfileAddInputSchema).output(ConfigProfileAddOutputSchema).handler(
123303
+ ({ input: input2 }) => guarded(() => {
123304
+ createProfile(paths, input2.name, input2.extends, input2.description);
123305
+ return { action: "created", kind: "profile", name: input2.name, value: profileValue(input2.name, paths) };
123306
+ })
123307
+ ),
123308
+ set: route("/rest/config/profile/set", "Update a configuration profile's categories, entries, extends list, description or launch settings").input(ConfigProfileSetInputSchema).output(ConfigProfileSetOutputSchema).handler(
123309
+ ({ input: input2 }) => guarded(() => {
123310
+ const { launch } = input2;
123311
+ requireChange(
123312
+ input2.category !== void 0 || input2.entry !== void 0 || input2.extends !== void 0 || input2.description !== void 0 || launch !== void 0,
123313
+ "category, entry, extends, description or launch"
123314
+ );
123315
+ requireProfileExists(paths, input2.name);
123316
+ applyProfileChange(paths, input2.name, {
123317
+ ...input2.category === void 0 ? {} : { category: input2.category },
123318
+ ...input2.entry === void 0 ? {} : { entry: input2.entry },
123319
+ ...input2.extends === void 0 ? {} : { extends: input2.extends },
123320
+ ...input2.description === void 0 ? {} : { description: input2.description },
123321
+ ...launch?.skipPermissions === void 0 ? {} : { launchSkipPermissions: launch.skipPermissions },
123322
+ ...launch?.remoteControl === void 0 ? {} : { launchRemoteControl: launch.remoteControl },
123323
+ ...launch?.headroom === void 0 ? {} : { launchHeadroom: launch.headroom },
123324
+ ...launch?.trackUsage === void 0 ? {} : { launchTrackUsage: launch.trackUsage },
123325
+ ...launch?.provider === void 0 ? {} : { launchProvider: launch.provider },
123326
+ ...launch?.claudeVersion === void 0 ? {} : { launchClaudeVersion: launch.claudeVersion }
123327
+ });
123328
+ return { action: "updated", kind: "profile", name: input2.name, value: profileValue(input2.name, paths) };
123329
+ })
123330
+ ),
123331
+ remove: route("/rest/config/profile/remove", "Delete a configuration profile").input(ConfigProfileRemoveInputSchema).output(ConfigProfileRemoveOutputSchema).handler(({ input: input2 }) => {
123332
+ requireConfirmation(input2.confirm, `configuration profile "${input2.name}"`);
123333
+ return guarded(() => {
123334
+ removeProfile(paths, input2.name);
123335
+ return { action: "removed", kind: "profile", name: input2.name };
123336
+ });
123337
+ }),
123338
+ use: route("/rest/config/profile/use", "Make a configuration profile the global default").input(ConfigNameInputSchema).output(ConfigProfileUseOutputSchema).handler(
123339
+ ({ input: input2 }) => guarded(() => {
123340
+ requireProfileExists(paths, input2.name);
123341
+ setGlobalDefaultProfile(paths, input2.name);
123342
+ return { action: "selected", kind: "profile", name: input2.name };
123343
+ })
123344
+ )
123345
+ },
123346
+ pool: {
123347
+ add: route("/rest/config/pool/add", "Define a pool").input(ConfigPoolAddInputSchema).output(ConfigPoolAddOutputSchema).handler(
123348
+ ({ input: input2 }) => guarded(() => {
123349
+ requireIdentityNames(paths, input2.identities);
123350
+ const created = addPool(paths, input2.name, input2.identities, input2.preference);
123351
+ return { action: "created", kind: "pool", name: input2.name, value: created };
123352
+ })
123353
+ ),
123354
+ set: route("/rest/config/pool/set", "Replace a pool's members, its preference or both").input(ConfigPoolSetInputSchema).output(ConfigPoolSetOutputSchema).handler(
123355
+ ({ input: input2 }) => guarded(() => {
123356
+ requireChange(input2.identities !== void 0 || input2.preference !== void 0, "identities or preference");
123357
+ const existing = requirePool(paths, input2.name);
123358
+ if (input2.identities !== void 0) {
123359
+ requireIdentityNames(paths, input2.identities);
123360
+ }
123361
+ const members2 = input2.identities ?? existing.identities;
123362
+ const preference = input2.preference === void 0 ? existing.preference : input2.preference === false ? void 0 : input2.preference;
123363
+ return { action: "updated", kind: "pool", name: input2.name, value: setPool(paths, input2.name, members2, preference) };
123364
+ })
123365
+ ),
123366
+ remove: route("/rest/config/pool/remove", "Delete a pool").input(ConfigPoolRemoveInputSchema).output(ConfigPoolRemoveOutputSchema).handler(({ input: input2 }) => {
123367
+ requireConfirmation(input2.confirm, `pool "${input2.name}"`);
123368
+ return guarded(() => {
123369
+ removePool(paths, input2.name);
123370
+ return { action: "removed", kind: "pool", name: input2.name };
123371
+ });
123372
+ }),
123373
+ use: route("/rest/config/pool/use", "Make launches with no other selection pick a member of a pool").input(ConfigNameInputSchema).output(ConfigPoolUseOutputSchema).handler(
123374
+ ({ input: input2 }) => guarded(() => {
123375
+ if (readPools(paths)[input2.name] === void 0) {
123376
+ throw new PoolNotFoundError(input2.name);
123377
+ }
123378
+ useIdentity(paths, `pool:${input2.name}`);
123379
+ return { action: "selected", kind: "pool", name: input2.name };
123380
+ })
123381
+ )
123382
+ },
123383
+ provider: {
123384
+ add: route("/rest/config/provider/add", "Create an API provider definition").input(ConfigProviderAddInputSchema).output(ConfigProviderAddOutputSchema).handler(
123385
+ ({ input: input2 }) => guarded(() => {
123386
+ const created = addProvider(paths, input2.name, {
123387
+ ...input2.kind === void 0 ? {} : { kind: input2.kind },
123388
+ displayName: input2.displayName,
123389
+ ...input2.baseUrl === void 0 ? {} : { baseUrl: input2.baseUrl },
123390
+ sources: input2.credential.sources,
123391
+ ...input2.credential.target === void 0 ? {} : { target: input2.credential.target },
123392
+ ...input2.codex === void 0 ? {} : { codex: input2.codex }
123393
+ });
123394
+ const cache = input2.credential.cache;
123395
+ const stored = cache === void 0 || cache === false ? created : updateProvider(paths, input2.name, { cache });
123396
+ return { action: "created", kind: "provider", name: input2.name, value: providerValue(input2.name, stored) };
123397
+ })
123398
+ ),
123399
+ set: route("/rest/config/provider/set", "Update an API provider definition").input(ConfigProviderSetInputSchema).output(ConfigProviderSetOutputSchema).handler(
123400
+ ({ input: input2 }) => guarded(() => {
123401
+ requireChange(input2.displayName !== void 0 || input2.baseUrl !== void 0 || input2.credential !== void 0 || input2.codex !== void 0, "displayName, baseUrl, credential or codex");
123402
+ const existing = readProvider(paths, input2.name);
123403
+ if (existing === void 0) {
123404
+ throw new ProviderNotFoundError(input2.name);
123405
+ }
123406
+ const credential = input2.credential;
123407
+ if (input2.baseUrl !== void 0 && !isCodexProvider(existing) && input2.baseUrl !== existing.baseUrl && credential?.sources === void 0) {
123408
+ throw new ORPCError("BAD_REQUEST", { message: `Changing the base URL of provider "${input2.name}" requires a credential block in the same call: the stored credential is not sent to a different endpoint.` });
123409
+ }
123410
+ const cache = credential?.cache === void 0 ? void 0 : mergeCredentialCache(credential.cache === false ? { enabled: false } : { ...credential.cache, enabled: true }, existing.credential.cache);
123411
+ const updated = updateProvider(paths, input2.name, {
123412
+ ...input2.displayName === void 0 ? {} : { displayName: input2.displayName },
123413
+ ...input2.baseUrl === void 0 ? {} : { baseUrl: input2.baseUrl },
123414
+ ...credential?.sources === void 0 ? {} : { sources: credential.sources },
123415
+ ...credential?.target === void 0 ? {} : { target: credential.target },
123416
+ ...cache === void 0 ? {} : { cache },
123417
+ ...input2.codex === void 0 ? {} : { codex: input2.codex }
123418
+ });
123419
+ return { action: "updated", kind: "provider", name: input2.name, value: providerValue(input2.name, updated) };
123420
+ })
123421
+ ),
123422
+ remove: route("/rest/config/provider/remove", "Delete an API provider definition").input(ConfigProviderRemoveInputSchema).output(ConfigProviderRemoveOutputSchema).handler(({ input: input2 }) => {
123423
+ requireConfirmation(input2.confirm, `provider "${input2.name}"`);
123424
+ return guarded(() => {
123425
+ if (!providerExists(paths, input2.name)) {
123426
+ throw new ProviderNotFoundError(input2.name);
123427
+ }
123428
+ removeProvider(paths, input2.name);
123429
+ return { action: "removed", kind: "provider", name: input2.name };
123430
+ });
123431
+ })
123432
+ },
123433
+ rule: {
123434
+ add: route("/rest/config/rule/add", "Add a directory rule for a path").input(ConfigRuleAddInputSchema).output(ConfigRuleAddOutputSchema).handler(
123435
+ ({ input: input2 }) => guarded(() => {
123436
+ if (input2.identity !== void 0) {
123437
+ requireRuleSelector(paths, input2.identity);
123438
+ }
123439
+ if (input2.configProfile !== void 0) {
123440
+ requireProfileExists(paths, input2.configProfile);
123441
+ }
123442
+ const created = addDirectoryRule(paths, input2.path, {
123443
+ ...input2.configProfile === void 0 ? {} : { configProfile: input2.configProfile },
123444
+ ...input2.identity === void 0 ? {} : { identity: input2.identity }
123445
+ });
123446
+ return { action: "created", kind: "rule", name: input2.path, value: created };
123447
+ })
123448
+ ),
123449
+ set: route("/rest/config/rule/set", "Update the directory rule for a path").input(ConfigRuleSetInputSchema).output(ConfigRuleSetOutputSchema).handler(
123450
+ ({ input: input2 }) => guarded(() => {
123451
+ requireChange(input2.configProfile !== void 0 || input2.identity !== void 0, "configProfile or identity");
123452
+ if (typeof input2.identity === "string") {
123453
+ requireRuleSelector(paths, input2.identity);
123454
+ }
123455
+ if (typeof input2.configProfile === "string") {
123456
+ requireProfileExists(paths, input2.configProfile);
123457
+ }
123458
+ const updated = updateDirectoryRule(paths, input2.path, {
123459
+ ...input2.configProfile === void 0 ? {} : { configProfile: input2.configProfile },
123460
+ ...input2.identity === void 0 ? {} : { identity: input2.identity }
123461
+ });
123462
+ return { action: "updated", kind: "rule", name: input2.path, value: updated };
123463
+ })
123464
+ ),
123465
+ remove: route("/rest/config/rule/remove", "Remove the directory rule for a path").input(ConfigRuleRemoveInputSchema).output(ConfigRuleRemoveOutputSchema).handler(({ input: input2 }) => {
123466
+ requireConfirmation(input2.confirm, `the directory rule for "${input2.path}"`);
123467
+ return guarded(() => {
123468
+ if (!listDirectoryRules(paths).some((entry) => entry.path === input2.path)) {
123469
+ throw new DirectoryRuleNotFoundError(input2.path);
123470
+ }
123471
+ removeDirectoryRule(paths, input2.path);
123472
+ return { action: "removed", kind: "rule", name: input2.path };
123473
+ });
123474
+ })
123475
+ }
123476
+ }
123477
+ };
123478
+ }
123479
+
122994
123480
  // src/frontdoor/eventSchemas.ts
122995
123481
  init_zod();
122996
123482
  var DOOR_EVENT_SOURCE_RC = "rc";
@@ -123159,7 +123645,16 @@ function createLaunchApiRouter(deps) {
123159
123645
  const authed = doorApiAuth(deps.expectedToken);
123160
123646
  return {
123161
123647
  launch: {
123162
- resolve: authed.meta(openapi({ 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: input2 }) => {
123648
+ resolve: authed.meta(
123649
+ openapi({
123650
+ method: "POST",
123651
+ path: "/rest/launch/resolve",
123652
+ summary: "Resolve what a launch from one directory would do, without performing it",
123653
+ tags: [LAUNCH_API_TAG],
123654
+ // A POST because the launch's environment and arguments are a body, but the answer changes nothing.
123655
+ spec: (current) => ({ ...current, [READ_ONLY_OPERATION_EXTENSION]: true })
123656
+ })
123657
+ ).input(LaunchResolveInputSchema).output(LaunchResolveOutputSchema).handler(({ input: input2 }) => {
123163
123658
  try {
123164
123659
  const { resolution, warnings } = deps.resolveLaunch({ path: input2.path, argv: input2.argv ?? [], env: input2.env ?? {} });
123165
123660
  return { ...resolution, warnings };
@@ -123241,7 +123736,7 @@ function createControlApiRouter(deps) {
123241
123736
  function createDoorApiRouter(deps) {
123242
123737
  const control = createControlApiRouter(deps);
123243
123738
  const lifecycle = createLifecycleApiRouter(deps);
123244
- return { ...createRcApiRouter(deps), ...control, ...lifecycle, ...createCodexApiRouter(deps), ...createLaunchApiRouter(deps), ...createEventsApiRouter(deps), frontdoor: { ...control.frontdoor, ...lifecycle.frontdoor } };
123739
+ return { ...createRcApiRouter(deps), ...control, ...lifecycle, ...createConfigApiRouter(deps), ...createCodexApiRouter(deps), ...createLaunchApiRouter(deps), ...createEventsApiRouter(deps), frontdoor: { ...control.frontdoor, ...lifecycle.frontdoor } };
123245
123740
  }
123246
123741
  function createDoorApiNodeHandler(deps) {
123247
123742
  return doorApiNodeHandlerOf(createDoorApiRouter(deps), deps.expectedToken);
@@ -126299,9 +126794,9 @@ async function serveRcCompatSessions(ctx, pathname, compatPath) {
126299
126794
  const slash = rest.indexOf("/");
126300
126795
  const address = slash === -1 ? rest : rest.slice(0, slash);
126301
126796
  const compatTail = slash === -1 ? "" : rest.slice(slash + 1);
126302
- const refusal = ctx.credentialRefusal(request7.headers);
126303
- if (refusal !== void 0) {
126304
- await ctx.unauthorized(response, refusal);
126797
+ const refusal2 = ctx.credentialRefusal(request7.headers);
126798
+ if (refusal2 !== void 0) {
126799
+ await ctx.unauthorized(response, refusal2);
126305
126800
  return;
126306
126801
  }
126307
126802
  const session = ctx.sessions.get(address) ?? ctx.sessions.get(`cse_${address}`);
@@ -126379,9 +126874,9 @@ function conversationRow(conversation) {
126379
126874
  }
126380
126875
  async function serveRcConversations(ctx, pathname, method) {
126381
126876
  const { request: request7, response, conversations } = ctx;
126382
- const refusal = ctx.credentialRefusal(request7.headers);
126383
- if (refusal !== void 0) {
126384
- await ctx.unauthorized(response, refusal);
126877
+ const refusal2 = ctx.credentialRefusal(request7.headers);
126878
+ if (refusal2 !== void 0) {
126879
+ await ctx.unauthorized(response, refusal2);
126385
126880
  return;
126386
126881
  }
126387
126882
  if (pathname === RC_CONVERSATIONS_PATH_PREFIX) {
@@ -126602,9 +127097,9 @@ async function fetchThroughWebProxy(url2, deps) {
126602
127097
  try {
126603
127098
  let redirects = 0;
126604
127099
  for (; ; ) {
126605
- const refusal = await checkTarget(current, deps);
126606
- if (refusal !== void 0) {
126607
- return refusal;
127100
+ const refusal2 = await checkTarget(current, deps);
127101
+ if (refusal2 !== void 0) {
127102
+ return refusal2;
126608
127103
  }
126609
127104
  let hop;
126610
127105
  try {
@@ -126974,8 +127469,8 @@ data: ${JSON.stringify(envelope)}
126974
127469
  "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",
126975
127470
  unrecognised: "the self-hosted Remote Control surface did not recognise the presented credential"
126976
127471
  };
126977
- const unauthorized = async (response, refusal) => {
126978
- await answerJson2(response, HTTP_STATUS.unauthorized, { type: "error", error: { type: "authentication_error", message: refusalMessages[refusal] } });
127472
+ const unauthorized = async (response, refusal2) => {
127473
+ await answerJson2(response, HTTP_STATUS.unauthorized, { type: "error", error: { type: "authentication_error", message: refusalMessages[refusal2] } });
126979
127474
  };
126980
127475
  const serveSessionPath = async (session, tail, request7, response) => {
126981
127476
  const method = request7.method.toUpperCase();
@@ -126986,9 +127481,9 @@ data: ${JSON.stringify(envelope)}
126986
127481
  session.lastTrafficAt = deps.now();
126987
127482
  if (tail === "") {
126988
127483
  if (method === "PATCH" || method === "PUT") {
126989
- const refusal = credentialRefusal(request7.headers);
126990
- if (refusal !== void 0) {
126991
- await unauthorized(response, refusal);
127484
+ const refusal2 = credentialRefusal(request7.headers);
127485
+ if (refusal2 !== void 0) {
127486
+ await unauthorized(response, refusal2);
126992
127487
  return;
126993
127488
  }
126994
127489
  const body = parseJsonObject5(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
@@ -127011,9 +127506,9 @@ data: ${JSON.stringify(envelope)}
127011
127506
  return;
127012
127507
  }
127013
127508
  if (tail === "bridge" && method === "POST") {
127014
- const refusal = credentialRefusal(request7.headers);
127015
- if (refusal !== void 0) {
127016
- await unauthorized(response, refusal);
127509
+ const refusal2 = credentialRefusal(request7.headers);
127510
+ if (refusal2 !== void 0) {
127511
+ await unauthorized(response, refusal2);
127017
127512
  return;
127018
127513
  }
127019
127514
  const workerJwt = mintWorkerJwt(deps.randomToken, deps.now());
@@ -127023,9 +127518,9 @@ data: ${JSON.stringify(envelope)}
127023
127518
  return;
127024
127519
  }
127025
127520
  if (tail === "archive" && method === "POST") {
127026
- const refusal = credentialRefusal(request7.headers);
127027
- if (refusal !== void 0) {
127028
- await unauthorized(response, refusal);
127521
+ const refusal2 = credentialRefusal(request7.headers);
127522
+ if (refusal2 !== void 0) {
127523
+ await unauthorized(response, refusal2);
127029
127524
  return;
127030
127525
  }
127031
127526
  retireSession(session);
@@ -127036,9 +127531,9 @@ data: ${JSON.stringify(envelope)}
127036
127531
  if (tail === "worker" || tail.startsWith("worker/")) {
127037
127532
  const workerTail = tail === "worker" ? "" : tail.slice("worker/".length);
127038
127533
  const webProxy = workerTail === "web-fetch" || workerTail === "web-search";
127039
- const refusal = webProxy ? workerOrCredentialRefusal(request7.headers, session) : workerRefusal(request7.headers, session);
127040
- if (refusal !== void 0) {
127041
- await unauthorized(response, refusal);
127534
+ const refusal2 = webProxy ? workerOrCredentialRefusal(request7.headers, session) : workerRefusal(request7.headers, session);
127535
+ if (refusal2 !== void 0) {
127536
+ await unauthorized(response, refusal2);
127042
127537
  return;
127043
127538
  }
127044
127539
  if (workerTail === "" && method === "GET") {
@@ -127969,6 +128464,7 @@ function realFrontDoorSupervisorPorts(paths) {
127969
128464
  [
127970
128465
  createDoorApiNodeHandler({
127971
128466
  expectedToken: rcControlToken,
128467
+ paths,
127972
128468
  statusOf: rcTracker.statusOf,
127973
128469
  pendingOf: rcTracker.pendingOf,
127974
128470
  inject: rcInject,
@@ -137879,6 +138375,7 @@ var OperationSchema = external_exports.object({
137879
138375
  summary: external_exports.string().optional(),
137880
138376
  description: external_exports.string().optional(),
137881
138377
  tags: external_exports.array(external_exports.string()).optional(),
138378
+ [READ_ONLY_OPERATION_EXTENSION]: external_exports.boolean().optional(),
137882
138379
  parameters: external_exports.array(external_exports.object({ in: external_exports.string(), name: external_exports.string(), required: external_exports.boolean().optional(), schema: external_exports.unknown().optional(), description: external_exports.string().optional() })).optional(),
137883
138380
  requestBody: external_exports.object({ content: external_exports.record(external_exports.string(), external_exports.object({ schema: JsonSchemaObjectSchema.optional() })) }).optional(),
137884
138381
  responses: external_exports.record(external_exports.string(), external_exports.object({ content: external_exports.record(external_exports.string(), external_exports.unknown()).optional() })).optional()
@@ -137927,7 +138424,7 @@ function toolsFromOpenApiDocument(document, permissions) {
137927
138424
  if (isStream(operation)) {
137928
138425
  continue;
137929
138426
  }
137930
- const readOnly = method === "get";
138427
+ const readOnly = method === "get" || operation[READ_ONLY_OPERATION_EXTENSION] === true;
137931
138428
  const tag = operation.tags?.[0];
137932
138429
  if (!permitted(tag, readOnly, permissions)) {
137933
138430
  continue;
@@ -138579,7 +139076,6 @@ function registerHeadroomCommand(program2, deps) {
138579
139076
  init_commandDeps();
138580
139077
  init_cliError();
138581
139078
  init_schema();
138582
- init_identity();
138583
139079
  init_schema();
138584
139080
  init_realPorts();
138585
139081
  init_preflight();
@@ -138593,14 +139089,6 @@ function formatPoolPick(report, nowMs) {
138593
139089
  });
138594
139090
  return [head, ...rows, ...report.missing.map((name) => ` (skipped: ${name} is not an identity)`), ...report.stickyProblem === void 0 ? [] : [`Note: ${report.stickyProblem}; the last-pick record was ignored.`]];
138595
139091
  }
138596
- function requireIdentities(paths, names) {
138597
- const existing = new Set(listIdentities(paths).map((entry) => entry.name));
138598
- for (const name of names) {
138599
- if (poolNameOf(name) === void 0 && !existing.has(name)) {
138600
- throw new IdentityNotFoundError(name);
138601
- }
138602
- }
138603
- }
138604
139092
  function membersOf(options) {
138605
139093
  if (options.identity === void 0 || options.identity.length === 0) {
138606
139094
  throw new UsageError("A pool needs at least one member: pass --identity <name> (repeatable).");
@@ -138617,7 +139105,7 @@ function registerPoolCommand(program2, deps) {
138617
139105
  withExamples(
138618
139106
  pool.command("add <name>").description("Define a pool. Fails if one with this name already exists.").option("--identity <name>", "A member: an identity name, or pool:<name> to nest another pool with its own policy (repeatable).", collectRepeated).addOption(new Option("--preference <mode>", PREFERENCE_DESCRIPTION).choices(POOL_PREFERENCES)).option("--json", "Print the result as JSON.").action((name, options) => {
138619
139107
  const members2 = membersOf(options);
138620
- requireIdentities(paths, members2);
139108
+ requireIdentityNames(paths, members2);
138621
139109
  const created = addPool(paths, name, members2, options.preference);
138622
139110
  reportMutation(options.json, { action: "created", kind: "pool", name, value: created }, () => {
138623
139111
  console.log(`Created pool "${name}" with ${members2.join(", ")}.`);
@@ -138633,7 +139121,7 @@ function registerPoolCommand(program2, deps) {
138633
139121
  }
138634
139122
  const members2 = options.identity === void 0 ? existing.identities : membersOf(options);
138635
139123
  if (options.identity !== void 0) {
138636
- requireIdentities(paths, membersOf(options));
139124
+ requireIdentityNames(paths, membersOf(options));
138637
139125
  }
138638
139126
  const preference = options.preference === void 0 ? existing.preference : options.preference === false ? void 0 : options.preference;
138639
139127
  const updated = setPool(paths, name, members2, preference);
@@ -138889,21 +139377,13 @@ function registerProviderCommand(program2, deps) {
138889
139377
  // src/directoryRules.ts
138890
139378
  init_commandDeps();
138891
139379
  init_cliError();
138892
- init_schema();
138893
139380
  function describeRule(rule) {
138894
139381
  const parts = Object.entries(rule).filter(([key]) => key !== "path").map(([key, value2]) => `${key}=${typeof value2 === "string" ? value2 : JSON.stringify(value2)}`);
138895
139382
  return parts.length === 0 ? "(nothing)" : parts.join(", ");
138896
139383
  }
138897
139384
  async function checkRuleTargets(deps, options) {
138898
139385
  if (typeof options.identity === "string") {
138899
- if (options.identity.startsWith(POOL_SELECTOR_PREFIX)) {
138900
- const poolName = options.identity.slice(POOL_SELECTOR_PREFIX.length);
138901
- if (readPools(deps.paths)[poolName] === void 0) {
138902
- throw new PoolNotFoundError(poolName);
138903
- }
138904
- } else if (readIdentity(deps.paths, options.identity) === void 0) {
138905
- throw new IdentityNotFoundError(options.identity);
138906
- }
139386
+ requireRuleSelector(deps.paths, options.identity);
138907
139387
  }
138908
139388
  if (typeof options.configProfile === "string") {
138909
139389
  await ensureProfileExists(deps, options.configProfile);