claude-use 9.16.0 → 9.18.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
@@ -2669,7 +2669,7 @@ var init_package = __esm({
2669
2669
  "package.json"() {
2670
2670
  package_default = {
2671
2671
  name: "claude-use",
2672
- version: "9.16.0",
2672
+ version: "9.18.0",
2673
2673
  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.",
2674
2674
  license: "MIT",
2675
2675
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -4791,22 +4791,25 @@ function rankPool(input) {
4791
4791
  return { ...candidate, feasible: true };
4792
4792
  }
4793
4793
  const drySpots = [];
4794
+ const dryAfterMs = [];
4794
4795
  if (fiveHour !== void 0 && pace !== void 0) {
4795
4796
  const runsDryInMs = fiveHour.remaining / pace;
4796
4797
  if (runsDryInMs < fiveHour.untilResetMs) {
4798
+ dryAfterMs.push(runsDryInMs);
4797
4799
  drySpots.push(`5h window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(fiveHour.untilResetMs)}`);
4798
4800
  }
4799
4801
  }
4800
4802
  if (sevenDay !== void 0 && sevenDayBurn !== void 0) {
4801
4803
  const runsDryInMs = sevenDay.remaining / sevenDayBurn;
4802
4804
  if (runsDryInMs < sevenDay.untilResetMs) {
4805
+ dryAfterMs.push(runsDryInMs);
4803
4806
  drySpots.push(`7d window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(sevenDay.untilResetMs)}`);
4804
4807
  }
4805
4808
  }
4806
4809
  if (drySpots.length === 0) {
4807
4810
  return { ...candidate, feasible: true };
4808
4811
  }
4809
- return { ...candidate, feasible: false, reasons: [...drySpots, ...candidate.reasons] };
4812
+ return { ...candidate, feasible: false, runsDryAtMs: nowMs + Math.min(...dryAfterMs), reasons: [...drySpots, ...candidate.reasons] };
4810
4813
  });
4811
4814
  const ordered = input.preference === "listed" ? [...candidates] : [...candidates].sort(
4812
4815
  (left, right) => CLASS_ORDER[left.class] - CLASS_ORDER[right.class] || Number(left.policyDemoted ?? false) - Number(right.policyDemoted ?? false) || Number(right.feasible) - Number(left.feasible) || (right.headroom ?? 1) - (left.headroom ?? 1) || (right.score ?? 0) - (left.score ?? 0) || left.identity.localeCompare(right.identity)
@@ -4828,11 +4831,13 @@ function rankPool(input) {
4828
4831
  const pick = ordered.find((candidate) => candidate.class !== "ineligible");
4829
4832
  const returns = ordered.flatMap((candidate) => candidate.blockedUntilMs === void 0 ? [] : [{ identity: candidate.identity, atMs: candidate.blockedUntilMs }]);
4830
4833
  const earliestReturn = returns.length === 0 ? void 0 : returns.reduce((soonest, entry) => entry.atMs < soonest.atMs ? entry : soonest);
4834
+ const holdForReturn = pick?.runsDryAtMs === void 0 ? void 0 : returns.filter((entry) => entry.atMs < (pick.runsDryAtMs ?? 0)).reduce((soonest, entry) => soonest === void 0 || entry.atMs < soonest.atMs ? entry : soonest, void 0);
4831
4835
  return {
4832
4836
  candidates: ordered,
4833
4837
  ...pick === void 0 ? { ...earliestReturn === void 0 ? {} : { earliestReturn } } : { pick },
4834
4838
  ...movedOff === void 0 || pick === void 0 ? {} : { movedOff },
4835
- ...pick?.planReturnsAtMs === void 0 ? {} : { planReturn: { identity: pick.identity, atMs: pick.planReturnsAtMs } }
4839
+ ...pick?.planReturnsAtMs === void 0 ? {} : { planReturn: { identity: pick.identity, atMs: pick.planReturnsAtMs } },
4840
+ ...holdForReturn === void 0 ? {} : { holdForReturn }
4836
4841
  };
4837
4842
  }
4838
4843
  var MS_PER_SECOND4, MS_PER_HOUR2, HOURS_PER_DAY2, FIVE_HOURS, PROMPT_CACHE_TTL_HOURS, PERCENT, SEVEN_DAYS, FIVE_HOUR_WINDOW_MS, SEVEN_DAY_WINDOW_MS, PROMPT_CACHE_TTL_MS, CLASS_ORDER;
@@ -6630,7 +6635,7 @@ var init_headers = __esm({
6630
6635
  });
6631
6636
 
6632
6637
  // src/launcher/flags.ts
6633
- import path34 from "node:path";
6638
+ import path35 from "node:path";
6634
6639
  function resolveLaunchFlags(params) {
6635
6640
  return {
6636
6641
  skipPermissions: params.flags?.skipPermissions ?? parseEnvBool("AGENT_SHIM_SKIP_PERMISSIONS", params.env.AGENT_SHIM_SKIP_PERMISSIONS) ?? params.cascade?.skipPermissions ?? false,
@@ -6661,7 +6666,7 @@ function buildEnv(params) {
6661
6666
  const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
6662
6667
  let providerCustomHeaders;
6663
6668
  if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
6664
- env.CLAUDE_CONFIG_DIR = path34.join(params.identitiesDir, params.resolvedIdentityName);
6669
+ env.CLAUDE_CONFIG_DIR = path35.join(params.identitiesDir, params.resolvedIdentityName);
6665
6670
  }
6666
6671
  if (params.provider !== void 0) {
6667
6672
  const providerEnv = params.provider.definition.env ?? {};
@@ -6782,12 +6787,17 @@ function resolvePoolLaunch(params) {
6782
6787
  if (graph.ranking.candidates.length === 0) {
6783
6788
  return { ok: false, message: `agent-shim: no member of pool "${poolName}" is an existing identity.` };
6784
6789
  }
6785
- const { pick, earliestReturn, movedOff, planReturn } = graph.ranking;
6790
+ const { pick, earliestReturn, movedOff, planReturn, holdForReturn } = graph.ranking;
6786
6791
  if (pick !== void 0 && params.wait && planReturn !== void 0) {
6787
6792
  log.info(`agent-shim: pool "${poolName}" would continue ${planReturn.identity} on extra usage; waiting until ${new Date(planReturn.atMs).toISOString()} for its plan window`);
6788
6793
  params.sleep(Math.max(planReturn.atMs - nowMs, 0));
6789
6794
  continue;
6790
6795
  }
6796
+ if (pick !== void 0 && params.wait && holdForReturn !== void 0) {
6797
+ log.info(`agent-shim: pool "${poolName}" pick ${pick.identity} would run dry before its window resets; waiting until ${new Date(holdForReturn.atMs).toISOString()} for ${holdForReturn.identity}`);
6798
+ params.sleep(Math.max(holdForReturn.atMs - nowMs, 0));
6799
+ continue;
6800
+ }
6791
6801
  if (pick !== void 0) {
6792
6802
  if (params.recordPick) {
6793
6803
  recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
@@ -6928,7 +6938,7 @@ var init_launchHook = __esm({
6928
6938
 
6929
6939
  // src/launcher.ts
6930
6940
  import { randomUUID as randomUUID4 } from "node:crypto";
6931
- import path35 from "node:path";
6941
+ import path36 from "node:path";
6932
6942
  function resolveIdentityCredential(identity, credential, env, port) {
6933
6943
  if (port === void 0) {
6934
6944
  return { ok: false, status: 1, message: `agent-shim: identity ${identity} needs its credential resolved, but this launcher has no credential port wired` };
@@ -7038,7 +7048,7 @@ function decideLaunch(params, readOnly) {
7038
7048
  identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
7039
7049
  globalDefaultConfigProfile: params.globalDefaultConfigProfile
7040
7050
  });
7041
- if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(path35.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
7051
+ if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(path36.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
7042
7052
  log.error(
7043
7053
  `agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
7044
7054
  );
@@ -7150,7 +7160,7 @@ function decideLaunch(params, readOnly) {
7150
7160
  extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
7151
7161
  passthrough: parsedArgv.rest
7152
7162
  });
7153
- const configDir = configDirEscapeHatchApplies || identityDecision.name === void 0 ? env.CLAUDE_CONFIG_DIR : path35.join(paths.identitiesDir, identityDecision.name);
7163
+ const configDir = configDirEscapeHatchApplies || identityDecision.name === void 0 ? env.CLAUDE_CONFIG_DIR : path36.join(paths.identitiesDir, identityDecision.name);
7154
7164
  const decision = {
7155
7165
  identitySource: identityDecision.source,
7156
7166
  configDirEscapeHatch: identityDecision.configDirEscapeHatch,
@@ -7191,7 +7201,7 @@ function prepareLaunch(params) {
7191
7201
  );
7192
7202
  const updateCheck = runLaunchUpdateCheck({
7193
7203
  mode: params.updateMode ?? "off",
7194
- checkPath: path35.join(paths.root, "update.check"),
7204
+ checkPath: path36.join(paths.root, "update.check"),
7195
7205
  currentVersion: package_default.version,
7196
7206
  port: params.update
7197
7207
  });
@@ -7351,12 +7361,12 @@ var init_launcher = __esm({
7351
7361
  });
7352
7362
 
7353
7363
  // src/ownCli.ts
7354
- import path36 from "node:path";
7364
+ import path37 from "node:path";
7355
7365
  function agentShimCliPath(distDir = typeof __AGENT_SHIM_DIST_DIR__ === "string" ? __AGENT_SHIM_DIST_DIR__ : void 0) {
7356
7366
  if (distDir === void 0) {
7357
7367
  throw new OwnCliPathUnknownError();
7358
7368
  }
7359
- return path36.join(distDir, OWN_CLI_FILE_NAME);
7369
+ return path37.join(distDir, OWN_CLI_FILE_NAME);
7360
7370
  }
7361
7371
  var OWN_CLI_FILE_NAME, OwnCliPathUnknownError;
7362
7372
  var init_ownCli = __esm({
@@ -7445,10 +7455,10 @@ request.on("error", (error) => finish(failed, (error.code ? error.code + ": " :
7445
7455
 
7446
7456
  // src/frontdoor/trust.ts
7447
7457
  import { createHash as createHash6 } from "node:crypto";
7448
- import path37 from "node:path";
7458
+ import path38 from "node:path";
7449
7459
  function resolveTrustBundle(params) {
7450
7460
  const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
7451
- if (inherited === void 0 || inherited === "" || path37.resolve(inherited) === path37.resolve(caCertFile)) {
7461
+ if (inherited === void 0 || inherited === "" || path38.resolve(inherited) === path38.resolve(caCertFile)) {
7452
7462
  return { path: caCertFile };
7453
7463
  }
7454
7464
  const caPem = fs12.readFileUtf8(caCertFile);
@@ -7466,7 +7476,7 @@ function resolveTrustBundle(params) {
7466
7476
  }
7467
7477
  const combined = `${inheritedPem.trimEnd()}
7468
7478
  ${caPem}`;
7469
- const bundle = path37.join(bundlesDir, `${createHash6("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
7479
+ const bundle = path38.join(bundlesDir, `${createHash6("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
7470
7480
  if (!fs12.exists(bundle)) {
7471
7481
  fs12.mkdirp(bundlesDir);
7472
7482
  fs12.writeFileAtomic(bundle, combined);
@@ -7866,7 +7876,7 @@ var init_identityClaude = __esm({
7866
7876
  });
7867
7877
 
7868
7878
  // src/usage/providerQuota.ts
7869
- import { z as z27 } from "zod";
7879
+ import { z as z28 } from "zod";
7870
7880
  var MS_PER_SECOND7, SECONDS_PER_HOUR, HOURS_PER_DAY4, 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;
7871
7881
  var init_providerQuota = __esm({
7872
7882
  "src/usage/providerQuota.ts"() {
@@ -7884,35 +7894,35 @@ var init_providerQuota = __esm({
7884
7894
  [ZAI_UNIT_HOURS, SECONDS_PER_HOUR * MS_PER_SECOND7],
7885
7895
  [ZAI_UNIT_MONTHS, DAYS_PER_MONTH * HOURS_PER_DAY4 * SECONDS_PER_HOUR * MS_PER_SECOND7]
7886
7896
  ]);
7887
- ZaiLimitSchema = z27.object({
7888
- type: z27.string(),
7889
- unit: z27.number().int(),
7890
- number: z27.number().int().positive(),
7891
- percentage: z27.number().nonnegative(),
7892
- nextResetTime: z27.number().positive().optional(),
7893
- usage: z27.number().nonnegative().optional(),
7894
- currentValue: z27.number().nonnegative().optional(),
7895
- remaining: z27.number().nonnegative().optional()
7897
+ ZaiLimitSchema = z28.object({
7898
+ type: z28.string(),
7899
+ unit: z28.number().int(),
7900
+ number: z28.number().int().positive(),
7901
+ percentage: z28.number().nonnegative(),
7902
+ nextResetTime: z28.number().positive().optional(),
7903
+ usage: z28.number().nonnegative().optional(),
7904
+ currentValue: z28.number().nonnegative().optional(),
7905
+ remaining: z28.number().nonnegative().optional()
7896
7906
  });
7897
- ZaiResponseSchema = z27.object({
7898
- success: z27.boolean(),
7899
- msg: z27.string().optional(),
7900
- data: z27.object({ level: z27.string().optional(), limits: z27.array(ZaiLimitSchema) })
7907
+ ZaiResponseSchema = z28.object({
7908
+ success: z28.boolean(),
7909
+ msg: z28.string().optional(),
7910
+ data: z28.object({ level: z28.string().optional(), limits: z28.array(ZaiLimitSchema) })
7901
7911
  });
7902
7912
  OPENROUTER_HOST = "openrouter.ai";
7903
7913
  OPENROUTER_KEY_URL = `https://${OPENROUTER_HOST}/api/v1/key`;
7904
7914
  OPENROUTER_CREDITS_URL = `https://${OPENROUTER_HOST}/api/v1/credits`;
7905
7915
  MS_PER_DAY3 = HOURS_PER_DAY4 * SECONDS_PER_HOUR * MS_PER_SECOND7;
7906
- OpenRouterKeySchema = z27.object({
7907
- data: z27.object({
7908
- limit: z27.number().nonnegative().nullable(),
7909
- limit_remaining: z27.number().nullable(),
7910
- limit_reset: z27.string().nullable(),
7911
- is_free_tier: z27.boolean().optional(),
7912
- free_model_daily_requests: z27.object({ used: z27.number().nonnegative(), limit: z27.number().nonnegative(), remaining: z27.number() }).optional()
7916
+ OpenRouterKeySchema = z28.object({
7917
+ data: z28.object({
7918
+ limit: z28.number().nonnegative().nullable(),
7919
+ limit_remaining: z28.number().nullable(),
7920
+ limit_reset: z28.string().nullable(),
7921
+ is_free_tier: z28.boolean().optional(),
7922
+ free_model_daily_requests: z28.object({ used: z28.number().nonnegative(), limit: z28.number().nonnegative(), remaining: z28.number() }).optional()
7913
7923
  })
7914
7924
  });
7915
- OpenRouterCreditsSchema = z27.object({ data: z27.object({ total_credits: z27.number().nonnegative(), total_usage: z27.number().nonnegative() }) });
7925
+ OpenRouterCreditsSchema = z28.object({ data: z28.object({ total_credits: z28.number().nonnegative(), total_usage: z28.number().nonnegative() }) });
7916
7926
  }
7917
7927
  });
7918
7928
 
@@ -8525,8 +8535,8 @@ function parseConnectTarget(authority) {
8525
8535
  function isInterceptedHost(host, interceptHosts) {
8526
8536
  return interceptHosts.includes(host);
8527
8537
  }
8528
- function servedByPipeline(path38) {
8529
- return path38?.startsWith(ROUTED_PATH_PREFIX) === true;
8538
+ function servedByPipeline(path39) {
8539
+ return path39?.startsWith(ROUTED_PATH_PREFIX) === true;
8530
8540
  }
8531
8541
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
8532
8542
  "connection",
@@ -9061,11 +9071,11 @@ function createRcSessionTracker(deps) {
9061
9071
  };
9062
9072
  const observeExchange = (request4) => {
9063
9073
  const method = (request4.method ?? "").toUpperCase();
9064
- const path38 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
9065
- if (!path38.startsWith(RC_SESSIONS_PATH_PREFIX)) {
9074
+ const path39 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
9075
+ if (!path39.startsWith(RC_SESSIONS_PATH_PREFIX)) {
9066
9076
  return void 0;
9067
9077
  }
9068
- const tail = path38.slice(RC_SESSIONS_PATH_PREFIX.length);
9078
+ const tail = path39.slice(RC_SESSIONS_PATH_PREFIX.length);
9069
9079
  const facts = {
9070
9080
  oauthAuthorization: oauthAuthorizationOf(request4.headers),
9071
9081
  anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
@@ -9447,8 +9457,8 @@ var RC_READ_FILE_ENCODINGS = ["utf-8", "base64"];
9447
9457
  function isRcReadFileEncoding(value) {
9448
9458
  return RC_READ_FILE_ENCODINGS.some((encoding) => encoding === value);
9449
9459
  }
9450
- function buildRcReadFilePayload(requestId, path38, options) {
9451
- return buildRcControlRequestPayload(requestId, { subtype: "read_file", path: path38, ...options?.maxBytes === void 0 ? {} : { max_bytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } });
9460
+ function buildRcReadFilePayload(requestId, path39, options) {
9461
+ return buildRcControlRequestPayload(requestId, { subtype: "read_file", path: path39, ...options?.maxBytes === void 0 ? {} : { max_bytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } });
9452
9462
  }
9453
9463
  function buildRcFileSuggestionsPayload(requestId, query) {
9454
9464
  return buildRcControlRequestPayload(requestId, { subtype: "file_suggestions", query });
@@ -9550,15 +9560,15 @@ async function getRcSessionContextUsage(deps, sessionId, detail) {
9550
9560
  const result = await deliverRcClientPayload(deps, sessionId, buildRcGetContextUsagePayload(requestId, detail), `request the context usage of session ${sessionId}`);
9551
9561
  return result.ok ? { ...result, requestId } : result;
9552
9562
  }
9553
- async function readRcSessionFile(deps, sessionId, path38, options) {
9554
- if (path38 === "") {
9563
+ async function readRcSessionFile(deps, sessionId, path39, options) {
9564
+ if (path39 === "") {
9555
9565
  return { ok: false, message: "a read-file write needs a non-empty path: the SDK's own field names the file the worker resolves against the session's cwd, and an empty string names none" };
9556
9566
  }
9557
9567
  if (options?.maxBytes !== void 0 && (!Number.isInteger(options.maxBytes) || options.maxBytes <= 0)) {
9558
9568
  return { ok: false, message: "a read-file write's max-bytes is a positive whole number of bytes: the SDK's own field caps the read, and a zero or negative cap reads nothing" };
9559
9569
  }
9560
9570
  const requestId = deps.newUuid();
9561
- const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId, path38, options), `read ${path38} from session ${sessionId}`);
9571
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId, path39, options), `read ${path39} from session ${sessionId}`);
9562
9572
  return result.ok ? { ...result, requestId } : result;
9563
9573
  }
9564
9574
  async function suggestRcSessionFiles(deps, sessionId, query) {
@@ -9727,11 +9737,11 @@ function createRcControlHandler(deps) {
9727
9737
  path: "read-file",
9728
9738
  read: (body) => {
9729
9739
  const session = bodyString(body, "session");
9730
- const path38 = bodyString(body, "path");
9740
+ const path39 = bodyString(body, "path");
9731
9741
  const maxBytes = "maxBytes" in body ? bodyPositiveInteger(body, "maxBytes") : void 0;
9732
9742
  const encoding = "encoding" in body && isRcReadFileEncoding(body.encoding) ? body.encoding : void 0;
9733
- const refused2 = session === void 0 || path38 === void 0 || "maxBytes" in body && maxBytes === void 0 || "encoding" in body && encoding === void 0;
9734
- return refused2 ? { error: `the read-file body must be JSON naming a non-empty session id and path, maxBytes only as a positive whole number or absent, and an encoding the SDK's own type permits (${RC_READ_FILE_ENCODINGS.join(", ")}) or none` } : { session, run: async () => await deps.readFile(session, path38, { ...maxBytes === void 0 ? {} : { maxBytes }, ...encoding === void 0 ? {} : { encoding } }) };
9743
+ const refused2 = session === void 0 || path39 === void 0 || "maxBytes" in body && maxBytes === void 0 || "encoding" in body && encoding === void 0;
9744
+ return refused2 ? { error: `the read-file body must be JSON naming a non-empty session id and path, maxBytes only as a positive whole number or absent, and an encoding the SDK's own type permits (${RC_READ_FILE_ENCODINGS.join(", ")}) or none` } : { session, run: async () => await deps.readFile(session, path39, { ...maxBytes === void 0 ? {} : { maxBytes }, ...encoding === void 0 ? {} : { encoding } }) };
9735
9745
  }
9736
9746
  },
9737
9747
  {
@@ -10041,9 +10051,9 @@ function requestIdOfBody(body) {
10041
10051
  }
10042
10052
  function frontDoorRcControl(transport, token) {
10043
10053
  const headers = { authorization: `Bearer ${token}` };
10044
- const listAnswerOf = async (path38, what) => {
10054
+ const listAnswerOf = async (path39, what) => {
10045
10055
  try {
10046
- return await transport.request({ method: "GET", path: path38, headers });
10056
+ return await transport.request({ method: "GET", path: path39, headers });
10047
10057
  } catch (error) {
10048
10058
  throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
10049
10059
  }
@@ -10115,10 +10125,10 @@ function frontDoorRcControl(transport, token) {
10115
10125
  }
10116
10126
  return pending;
10117
10127
  };
10118
- const writeOf = async (path38, body, describeFailure2) => {
10128
+ const writeOf = async (path39, body, describeFailure2) => {
10119
10129
  let answer;
10120
10130
  try {
10121
- answer = await transport.request({ method: "POST", path: path38, headers: { ...headers, "content-type": "application/json" }, body });
10131
+ answer = await transport.request({ method: "POST", path: path39, headers: { ...headers, "content-type": "application/json" }, body });
10122
10132
  } catch (error) {
10123
10133
  return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
10124
10134
  }
@@ -10149,10 +10159,10 @@ function frontDoorRcControl(transport, token) {
10149
10159
  endSession: async (sessionId, reason) => await writeOf(`${CONTROL_PATH_PREFIX}/end-session`, JSON.stringify({ session: sessionId, ...reason === void 0 ? {} : { reason } }), (status, message) => `ending ${sessionId} failed (HTTP ${String(status)}): ${message}`),
10150
10160
  getUsage: async (sessionId, skipBehaviors) => await writeOf(`${CONTROL_PATH_PREFIX}/get-usage`, JSON.stringify({ session: sessionId, ...skipBehaviors === void 0 ? {} : { skipBehaviors } }), (status, message) => `requesting the usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
10151
10161
  getContextUsage: async (sessionId, detail) => await writeOf(`${CONTROL_PATH_PREFIX}/get-context-usage`, JSON.stringify({ session: sessionId, ...detail === void 0 ? {} : { detail } }), (status, message) => `requesting the context usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
10152
- readFile: async (sessionId, path38, options) => await writeOf(
10162
+ readFile: async (sessionId, path39, options) => await writeOf(
10153
10163
  `${CONTROL_PATH_PREFIX}/read-file`,
10154
- JSON.stringify({ session: sessionId, path: path38, ...options?.maxBytes === void 0 ? {} : { maxBytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } }),
10155
- (status, message) => `reading ${path38} from ${sessionId} failed (HTTP ${String(status)}): ${message}`
10164
+ JSON.stringify({ session: sessionId, path: path39, ...options?.maxBytes === void 0 ? {} : { maxBytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } }),
10165
+ (status, message) => `reading ${path39} from ${sessionId} failed (HTTP ${String(status)}): ${message}`
10156
10166
  ),
10157
10167
  fileSuggestions: async (sessionId, query) => await writeOf(`${CONTROL_PATH_PREFIX}/file-suggestions`, JSON.stringify({ session: sessionId, query }), (status, message) => `requesting file suggestions from ${sessionId} failed (HTTP ${String(status)}): ${message}`),
10158
10168
  keepAlive: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/keep-alive`, JSON.stringify({ session: sessionId }), (status, message) => `keeping ${sessionId} alive failed (HTTP ${String(status)}): ${message}`),
@@ -10311,12 +10321,12 @@ function tlsFacts(options) {
10311
10321
  }
10312
10322
  function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
10313
10323
  const agent = new ExemptTlsAgent();
10314
- const post = async (path38, headers, body) => await new Promise((resolve, reject) => {
10324
+ const post = async (path39, headers, body) => await new Promise((resolve, reject) => {
10315
10325
  const options = {
10316
10326
  host: target.host,
10317
10327
  port: target.port,
10318
10328
  method: "POST",
10319
- path: path38,
10329
+ path: path39,
10320
10330
  // The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
10321
10331
  headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
10322
10332
  agent
@@ -10381,12 +10391,12 @@ function lateRcStreamDial(resolve) {
10381
10391
  }
10382
10392
  function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
10383
10393
  const agent = new ExemptTlsAgent();
10384
- const request4 = async (method, path38, headers, body, signal) => await new Promise((resolve, reject) => {
10394
+ const request4 = async (method, path39, headers, body, signal) => await new Promise((resolve, reject) => {
10385
10395
  const options = {
10386
10396
  host: target.host,
10387
10397
  port: target.port,
10388
10398
  method,
10389
- path: path38,
10399
+ path: path39,
10390
10400
  // The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
10391
10401
  headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
10392
10402
  agent,
@@ -10428,9 +10438,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
10428
10438
  return { status, body: await readAll(response) };
10429
10439
  },
10430
10440
  openStream: async (sessionId, headers, resume, signal) => {
10431
- const path38 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
10441
+ const path39 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
10432
10442
  const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
10433
- const { status, response } = await request4("GET", path38, streamHeaders, void 0, signal);
10443
+ const { status, response } = await request4("GET", path39, streamHeaders, void 0, signal);
10434
10444
  if (!isSuccessful2(status)) {
10435
10445
  await readAll(response);
10436
10446
  return { status, chunks: NO_CHUNKS };
@@ -10897,6 +10907,7 @@ var RC_ORPC_PATH_PREFIX = "/__agent-shim/orpc";
10897
10907
  var RC_OPENAPI_DOC_PATH = "/openapi.json";
10898
10908
  var RC_SUBSCRIBER_BUFFER_EVENTS = 100;
10899
10909
  var READ_ONLY_OPERATION_EXTENSION = "x-agent-shim-read-only";
10910
+ var SESSION_HISTORY_TAG = "agent-trees";
10900
10911
  function doorApiBearer(headers) {
10901
10912
  const presented = headers.authorization;
10902
10913
  const bearerPrefix = "bearer ".length;
@@ -11311,8 +11322,8 @@ init_cliError();
11311
11322
  init_realPorts();
11312
11323
 
11313
11324
  // src/frontdoor/controlApi.ts
11314
- import { createORPCClient as createORPCClient2, ORPCError as ORPCError6 } from "@orpc/client";
11315
- import { openapi as openapi7 } from "@orpc/openapi";
11325
+ import { createORPCClient as createORPCClient2, ORPCError as ORPCError7 } from "@orpc/client";
11326
+ import { openapi as openapi8 } from "@orpc/openapi";
11316
11327
 
11317
11328
  // src/checkReport.ts
11318
11329
  init_classify();
@@ -11581,19 +11592,19 @@ function writePools(paths, pools) {
11581
11592
  applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
11582
11593
  }
11583
11594
  function poolCycleOf(pools, name) {
11584
- const walk = (current, path38) => {
11595
+ const walk = (current, path39) => {
11585
11596
  for (const entry of pools[current]?.identities ?? []) {
11586
11597
  const nested = poolNameOf(poolMemberIdentity(entry));
11587
11598
  if (nested === void 0) {
11588
11599
  continue;
11589
11600
  }
11590
11601
  if (nested === name) {
11591
- return [...path38, nested];
11602
+ return [...path39, nested];
11592
11603
  }
11593
- if (path38.includes(nested)) {
11604
+ if (path39.includes(nested)) {
11594
11605
  continue;
11595
11606
  }
11596
- const found = walk(nested, [...path38, nested]);
11607
+ const found = walk(nested, [...path39, nested]);
11597
11608
  if (found !== void 0) {
11598
11609
  return found;
11599
11610
  }
@@ -13727,7 +13738,7 @@ function profileValue(name, paths) {
13727
13738
  function createConfigApiRouter(deps) {
13728
13739
  const authed = doorApiAuth(deps.expectedToken);
13729
13740
  const { paths } = deps;
13730
- const route = (path38, summary) => authed.meta(openapi3({ method: "POST", path: path38, summary, tags: [CONFIG_API_TAG] }));
13741
+ const route = (path39, summary) => authed.meta(openapi3({ method: "POST", path: path39, summary, tags: [CONFIG_API_TAG] }));
13731
13742
  return {
13732
13743
  config: {
13733
13744
  identity: {
@@ -14169,6 +14180,166 @@ function createLaunchApiRouter(deps) {
14169
14180
  };
14170
14181
  }
14171
14182
 
14183
+ // src/frontdoor/agentTreesApi.ts
14184
+ import { ORPCError as ORPCError6 } from "@orpc/client";
14185
+ import { openapi as openapi7 } from "@orpc/openapi";
14186
+ import { z as z26 } from "zod";
14187
+
14188
+ // src/agents/schema.ts
14189
+ import { z as z25 } from "zod";
14190
+ var AgentMetaSchema = z25.looseObject({
14191
+ agentType: z25.string(),
14192
+ isFork: z25.boolean().optional(),
14193
+ description: z25.string().optional(),
14194
+ name: z25.string().optional(),
14195
+ toolUseId: z25.string().optional(),
14196
+ spawnDepth: z25.number().int().nonnegative().optional(),
14197
+ parentAgentId: z25.string().optional(),
14198
+ model: z25.string().optional(),
14199
+ requestShape: z25.string().optional(),
14200
+ requestNonInteractive: z25.boolean().optional(),
14201
+ workflowPhase: z25.string().optional(),
14202
+ taskKind: z25.string().optional(),
14203
+ teamName: z25.string().optional(),
14204
+ worktreePath: z25.string().optional(),
14205
+ worktreeBranch: z25.string().optional(),
14206
+ stoppedByUser: z25.boolean().optional()
14207
+ });
14208
+ var AgentKindSchema = z25.enum(["subagent", "fork", "workflow-agent", "teammate"]);
14209
+ var AgentNodeSchema = z25.lazy(
14210
+ () => z25.strictObject({
14211
+ id: z25.string(),
14212
+ kind: AgentKindSchema,
14213
+ agentType: z25.string(),
14214
+ description: z25.string().optional(),
14215
+ name: z25.string().optional(),
14216
+ toolUseId: z25.string().optional(),
14217
+ spawnDepth: z25.number().int().nonnegative().optional(),
14218
+ model: z25.string().optional(),
14219
+ background: z25.boolean().optional(),
14220
+ workflowRunId: z25.string().optional(),
14221
+ workflowPhase: z25.string().optional(),
14222
+ teamName: z25.string().optional(),
14223
+ stoppedByUser: z25.boolean().optional(),
14224
+ transcript: z25.string(),
14225
+ children: z25.array(AgentNodeSchema)
14226
+ })
14227
+ );
14228
+ var TaskItemSchema = z25.strictObject({
14229
+ id: z25.string(),
14230
+ subject: z25.string(),
14231
+ description: z25.string().optional(),
14232
+ status: z25.string(),
14233
+ /** What a spinner shows while the task runs. */
14234
+ activeForm: z25.string().optional(),
14235
+ /** The teammate or agent name the task is assigned to, as Agent Teams writes it. */
14236
+ owner: z25.string().optional(),
14237
+ /** Free-form data the harness attaches to a task, kept as written. */
14238
+ metadata: z25.record(z25.string(), z25.unknown()).optional(),
14239
+ blocks: z25.array(z25.string()),
14240
+ blockedBy: z25.array(z25.string()),
14241
+ /** The id of the shared task list this task belongs to (a team's name, or a custom list id), absent for the session's own list. */
14242
+ taskList: z25.string().optional()
14243
+ });
14244
+ var WorkflowRunSchema = z25.strictObject({
14245
+ runId: z25.string(),
14246
+ workflowName: z25.string().optional(),
14247
+ status: z25.string().optional(),
14248
+ startTime: z25.number().optional(),
14249
+ phases: z25.array(z25.string()),
14250
+ summary: z25.string().optional()
14251
+ });
14252
+ var AgentTreeProblemSchema = z25.strictObject({
14253
+ /** Relative to the identity's configuration directory. */
14254
+ path: z25.string(),
14255
+ reason: z25.string()
14256
+ });
14257
+ var SessionSummarySchema = z25.strictObject({
14258
+ project: z25.string(),
14259
+ sessionId: z25.string(),
14260
+ superseded: z25.boolean(),
14261
+ /** The directory and transcript stem exactly as on disk, which differs from `sessionId` for a superseded session. */
14262
+ entry: z25.string(),
14263
+ agentCount: z25.number().int().nonnegative(),
14264
+ workflowRunCount: z25.number().int().nonnegative(),
14265
+ /** When the transcript was last written, as an ISO instant; absent when there is no transcript file. */
14266
+ updatedAt: z25.iso.datetime().optional(),
14267
+ identities: z25.array(z25.string())
14268
+ });
14269
+ var SessionAgentTreeSchema = z25.strictObject({
14270
+ project: z25.string(),
14271
+ sessionId: z25.string(),
14272
+ /** True for a session directory a resume superseded (`<session-id>.superseded-<epoch-ms>`). */
14273
+ superseded: z25.boolean(),
14274
+ /** The agents the session itself spawned, each with its descendants. */
14275
+ agents: z25.array(AgentNodeSchema),
14276
+ tasks: z25.array(TaskItemSchema),
14277
+ workflowRuns: z25.array(WorkflowRunSchema),
14278
+ problems: z25.array(AgentTreeProblemSchema)
14279
+ });
14280
+
14281
+ // src/frontdoor/agentTreesApi.ts
14282
+ init_cliError();
14283
+ var AgentTreesListInputSchema = z26.strictObject({
14284
+ /** Only this identity's sessions. */
14285
+ identity: z26.string().optional(),
14286
+ /** Include sessions that spawned no agent and ran no workflow. */
14287
+ all: z26.boolean().optional()
14288
+ });
14289
+ var AgentTreesListOutputSchema = z26.array(SessionSummarySchema);
14290
+ var AgentTreesShowInputSchema = z26.strictObject({
14291
+ /** A session id, or an unambiguous prefix of one. */
14292
+ session: z26.string().min(1),
14293
+ /** Look only in this identity. */
14294
+ identity: z26.string().optional()
14295
+ });
14296
+ var AgentTreesShowOutputSchema = z26.strictObject({ identities: z26.array(z26.string()), ...SessionAgentTreeSchema.shape });
14297
+ function asBadRequest(error) {
14298
+ if (error instanceof CliError) {
14299
+ throw new ORPCError6("BAD_REQUEST", { message: error.message });
14300
+ }
14301
+ throw error;
14302
+ }
14303
+ function createAgentTreesApiRouter(deps) {
14304
+ const authed = doorApiAuth(deps.expectedToken);
14305
+ return {
14306
+ agentTrees: {
14307
+ list: authed.meta(
14308
+ openapi7({
14309
+ method: "POST",
14310
+ path: "/rest/agent-trees/list",
14311
+ summary: "List the sessions that spawned agents or ran workflows, newest transcript first",
14312
+ tags: [SESSION_HISTORY_TAG],
14313
+ // A POST because the filters are a body, but the answer changes nothing.
14314
+ spec: (current) => ({ ...current, [READ_ONLY_OPERATION_EXTENSION]: true })
14315
+ })
14316
+ ).input(AgentTreesListInputSchema).output(AgentTreesListOutputSchema).handler(({ input }) => {
14317
+ try {
14318
+ return deps.sessionList(input).map((session) => ({ ...session, identities: [...session.identities] }));
14319
+ } catch (error) {
14320
+ return asBadRequest(error);
14321
+ }
14322
+ }),
14323
+ show: authed.meta(
14324
+ openapi7({
14325
+ method: "POST",
14326
+ path: "/rest/agent-trees/show",
14327
+ summary: "Show one session's agent tree, task list and workflow runs",
14328
+ tags: [SESSION_HISTORY_TAG],
14329
+ spec: (current) => ({ ...current, [READ_ONLY_OPERATION_EXTENSION]: true })
14330
+ })
14331
+ ).input(AgentTreesShowInputSchema).output(AgentTreesShowOutputSchema).handler(({ input }) => {
14332
+ try {
14333
+ const view = deps.sessionShow(input.session, input.identity);
14334
+ return { identities: [...view.identities], ...view.tree };
14335
+ } catch (error) {
14336
+ return asBadRequest(error);
14337
+ }
14338
+ })
14339
+ }
14340
+ };
14341
+ }
14342
+
14172
14343
  // src/frontdoor/controlApi.ts
14173
14344
  var USAGE_API_TAG = "usage";
14174
14345
  var FRONTDOOR_API_TAG2 = "frontdoor";
@@ -14179,12 +14350,12 @@ function createControlApiRouter(deps) {
14179
14350
  const authed = doorApiAuth(deps.expectedToken);
14180
14351
  return {
14181
14352
  usage: {
14182
- 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() })),
14183
- resets: authed.meta(openapi7({ method: "GET", path: "/rest/usage/resets", summary: "List every recorded quota window with when it resets", tags: [USAGE_API_TAG] })).output(ResetScheduleSchema).handler(() => collectResets(deps.usageSnapshots(), deps.now())),
14184
- 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 }) => {
14353
+ list: authed.meta(openapi8({ method: "GET", path: "/rest/usage/snapshots", summary: "List every identity's usage snapshot", tags: [USAGE_API_TAG] })).output(UsageListOutputSchema).handler(() => ({ snapshots: deps.usageSnapshots() })),
14354
+ resets: authed.meta(openapi8({ method: "GET", path: "/rest/usage/resets", summary: "List every recorded quota window with when it resets", tags: [USAGE_API_TAG] })).output(ResetScheduleSchema).handler(() => collectResets(deps.usageSnapshots(), deps.now())),
14355
+ effectiveWindow: authed.meta(openapi8({ method: "GET", path: "/rest/usage/windows", summary: "Read one identity's effective quota windows", tags: [USAGE_API_TAG] })).input(UsageWindowsInputSchema).output(UsageWindowsOutputSchema).handler(({ input }) => {
14185
14356
  const snapshot = deps.usageSnapshotOf(input.identity);
14186
14357
  if (snapshot === void 0) {
14187
- throw new ORPCError6("NOT_FOUND", { message: `identity ${input.identity} has no usage snapshot yet, so no quota window has been observed for it` });
14358
+ throw new ORPCError7("NOT_FOUND", { message: `identity ${input.identity} has no usage snapshot yet, so no quota window has been observed for it` });
14188
14359
  }
14189
14360
  const provider = input.provider ?? ANTHROPIC_PROVIDER;
14190
14361
  const rateLimit = snapshot.providers[provider]?.rateLimit;
@@ -14198,34 +14369,34 @@ function createControlApiRouter(deps) {
14198
14369
  ...unified?.sevenDay === void 0 ? {} : { sevenDay: effectiveWindow(unified.sevenDay, now) }
14199
14370
  };
14200
14371
  }),
14201
- 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 }) => {
14372
+ live: authed.meta(openapi8({ 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 }) => {
14202
14373
  const sessions = deps.liveRateLimits(input.session);
14203
14374
  if (input.session !== void 0 && sessions.length === 0) {
14204
14375
  if (deps.list().some((session) => session.id === input.session)) {
14205
- 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` });
14376
+ throw new ORPCError7("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` });
14206
14377
  }
14207
- throw new ORPCError6("NOT_FOUND", { message: rcSessionNotObservedMessage(input.session) });
14378
+ throw new ORPCError7("NOT_FOUND", { message: rcSessionNotObservedMessage(input.session) });
14208
14379
  }
14209
14380
  return { latest: deps.latestRateLimit(), sessions };
14210
14381
  })
14211
14382
  },
14212
14383
  frontdoor: {
14213
- 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()),
14214
- 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 }))
14384
+ status: authed.meta(openapi8({ method: "GET", path: "/rest/frontdoor/status", summary: "Read the front door's status", tags: [FRONTDOOR_API_TAG2] })).output(FrontDoorStatusOutputSchema).handler(() => deps.frontDoorStatus()),
14385
+ sessions: authed.meta(openapi8({ 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 }))
14215
14386
  },
14216
14387
  check: {
14217
14388
  // 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.
14218
- 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)))
14389
+ run: authed.meta(openapi8({ 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)))
14219
14390
  },
14220
14391
  doctor: {
14221
- run: authed.meta(openapi7({ method: "GET", path: "/rest/doctor", summary: "Run the doctor report", tags: [DOCTOR_API_TAG] })).output(DoctorRunOutputSchema).handler(() => deps.doctorReport())
14392
+ run: authed.meta(openapi8({ method: "GET", path: "/rest/doctor", summary: "Run the doctor report", tags: [DOCTOR_API_TAG] })).output(DoctorRunOutputSchema).handler(() => deps.doctorReport())
14222
14393
  },
14223
14394
  pool: {
14224
- 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 }) => {
14395
+ pick: authed.meta(openapi8({ 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 }) => {
14225
14396
  const report = deps.poolPick(input.pool, input.path);
14226
14397
  if (report === void 0) {
14227
14398
  const live = deps.poolNames();
14228
- throw new ORPCError6("NOT_FOUND", {
14399
+ throw new ORPCError7("NOT_FOUND", {
14229
14400
  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(", ")}`
14230
14401
  });
14231
14402
  }
@@ -14237,7 +14408,7 @@ function createControlApiRouter(deps) {
14237
14408
  function createDoorApiRouter(deps) {
14238
14409
  const control = createControlApiRouter(deps);
14239
14410
  const lifecycle = createLifecycleApiRouter(deps);
14240
- return { ...createRcApiRouter(deps), ...control, ...lifecycle, ...createConfigApiRouter(deps), ...createCodexApiRouter(deps), ...createLaunchApiRouter(deps), ...createEventsApiRouter(deps), frontdoor: { ...control.frontdoor, ...lifecycle.frontdoor } };
14411
+ return { ...createRcApiRouter(deps), ...control, ...lifecycle, ...createConfigApiRouter(deps), ...createCodexApiRouter(deps), ...createLaunchApiRouter(deps), ...createAgentTreesApiRouter(deps), ...createEventsApiRouter(deps), frontdoor: { ...control.frontdoor, ...lifecycle.frontdoor } };
14241
14412
  }
14242
14413
  function createDoorApiNodeHandler(deps) {
14243
14414
  return doorApiNodeHandlerOf(createDoorApiRouter(deps), deps.expectedToken);
@@ -16305,90 +16476,7 @@ init_poolPick();
16305
16476
 
16306
16477
  // src/agents/read.ts
16307
16478
  import path33 from "node:path";
16308
- import { z as z26 } from "zod";
16309
-
16310
- // src/agents/schema.ts
16311
- import { z as z25 } from "zod";
16312
- var AgentMetaSchema = z25.looseObject({
16313
- agentType: z25.string(),
16314
- isFork: z25.boolean().optional(),
16315
- description: z25.string().optional(),
16316
- name: z25.string().optional(),
16317
- toolUseId: z25.string().optional(),
16318
- spawnDepth: z25.number().int().nonnegative().optional(),
16319
- parentAgentId: z25.string().optional(),
16320
- model: z25.string().optional(),
16321
- requestShape: z25.string().optional(),
16322
- requestNonInteractive: z25.boolean().optional(),
16323
- workflowPhase: z25.string().optional(),
16324
- taskKind: z25.string().optional(),
16325
- teamName: z25.string().optional(),
16326
- worktreePath: z25.string().optional(),
16327
- worktreeBranch: z25.string().optional(),
16328
- stoppedByUser: z25.boolean().optional()
16329
- });
16330
- var AgentKindSchema = z25.enum(["subagent", "fork", "workflow-agent", "teammate"]);
16331
- var AgentNodeSchema = z25.lazy(
16332
- () => z25.strictObject({
16333
- id: z25.string(),
16334
- kind: AgentKindSchema,
16335
- agentType: z25.string(),
16336
- description: z25.string().optional(),
16337
- name: z25.string().optional(),
16338
- toolUseId: z25.string().optional(),
16339
- spawnDepth: z25.number().int().nonnegative().optional(),
16340
- model: z25.string().optional(),
16341
- background: z25.boolean().optional(),
16342
- workflowRunId: z25.string().optional(),
16343
- workflowPhase: z25.string().optional(),
16344
- teamName: z25.string().optional(),
16345
- stoppedByUser: z25.boolean().optional(),
16346
- transcript: z25.string(),
16347
- children: z25.array(AgentNodeSchema)
16348
- })
16349
- );
16350
- var TaskItemSchema = z25.strictObject({
16351
- id: z25.string(),
16352
- subject: z25.string(),
16353
- description: z25.string().optional(),
16354
- status: z25.string(),
16355
- /** What a spinner shows while the task runs. */
16356
- activeForm: z25.string().optional(),
16357
- /** The teammate or agent name the task is assigned to, as Agent Teams writes it. */
16358
- owner: z25.string().optional(),
16359
- /** Free-form data the harness attaches to a task, kept as written. */
16360
- metadata: z25.record(z25.string(), z25.unknown()).optional(),
16361
- blocks: z25.array(z25.string()),
16362
- blockedBy: z25.array(z25.string()),
16363
- /** The id of the shared task list this task belongs to (a team's name, or a custom list id), absent for the session's own list. */
16364
- taskList: z25.string().optional()
16365
- });
16366
- var WorkflowRunSchema = z25.strictObject({
16367
- runId: z25.string(),
16368
- workflowName: z25.string().optional(),
16369
- status: z25.string().optional(),
16370
- startTime: z25.number().optional(),
16371
- phases: z25.array(z25.string()),
16372
- summary: z25.string().optional()
16373
- });
16374
- var AgentTreeProblemSchema = z25.strictObject({
16375
- /** Relative to the identity's configuration directory. */
16376
- path: z25.string(),
16377
- reason: z25.string()
16378
- });
16379
- var SessionAgentTreeSchema = z25.strictObject({
16380
- project: z25.string(),
16381
- sessionId: z25.string(),
16382
- /** True for a session directory a resume superseded (`<session-id>.superseded-<epoch-ms>`). */
16383
- superseded: z25.boolean(),
16384
- /** The agents the session itself spawned, each with its descendants. */
16385
- agents: z25.array(AgentNodeSchema),
16386
- tasks: z25.array(TaskItemSchema),
16387
- workflowRuns: z25.array(WorkflowRunSchema),
16388
- problems: z25.array(AgentTreeProblemSchema)
16389
- });
16390
-
16391
- // src/agents/read.ts
16479
+ import { z as z27 } from "zod";
16392
16480
  var PROJECTS_DIR = "projects";
16393
16481
  var TASKS_DIR = "tasks";
16394
16482
  var SUBAGENTS_DIR = "subagents";
@@ -16507,15 +16595,30 @@ function parseJson2(text) {
16507
16595
  return void 0;
16508
16596
  }
16509
16597
  }
16510
- var TaskFileSchema = z26.object({ ...TaskItemSchema.omit({ taskList: true }).shape, blocks: z26.array(z26.string()).default([]), blockedBy: z26.array(z26.string()).default([]) });
16511
- var WorkflowRunFileSchema = z26.object({
16512
- runId: z26.string(),
16513
- workflowName: z26.string().optional(),
16514
- status: z26.string().optional(),
16515
- startTime: z26.number().optional(),
16516
- phases: z26.array(z26.object({ title: z26.string() })).default([]),
16517
- summary: z26.string().optional()
16598
+ var TaskFileSchema = z27.object({ ...TaskItemSchema.omit({ taskList: true }).shape, blocks: z27.array(z27.string()).default([]), blockedBy: z27.array(z27.string()).default([]) });
16599
+ var WorkflowRunFileSchema = z27.object({
16600
+ runId: z27.string(),
16601
+ workflowName: z27.string().optional(),
16602
+ status: z27.string().optional(),
16603
+ startTime: z27.number().optional(),
16604
+ phases: z27.array(z27.object({ title: z27.string() })).default([]),
16605
+ summary: z27.string().optional()
16518
16606
  });
16607
+ function summariseSession(fs12, configDir, ref) {
16608
+ const sessionRelative = path33.join(PROJECTS_DIR, ref.project, ref.entry);
16609
+ const subagentsRelative = path33.join(sessionRelative, SUBAGENTS_DIR);
16610
+ const workflowsUnderSubagents = path33.join(subagentsRelative, WORKFLOWS_DIR);
16611
+ const isMeta = (name) => name.startsWith(AGENT_FILE_PREFIX) && name.endsWith(META_SUFFIX);
16612
+ let agentCount = fs12.readdir(path33.join(configDir, subagentsRelative)).filter(isMeta).length;
16613
+ for (const runDir of fs12.readdir(path33.join(configDir, workflowsUnderSubagents))) {
16614
+ if (runDir.startsWith(WORKFLOW_RUN_PREFIX)) {
16615
+ agentCount += fs12.readdir(path33.join(configDir, workflowsUnderSubagents, runDir)).filter(isMeta).length;
16616
+ }
16617
+ }
16618
+ const workflowRunCount = fs12.readdir(path33.join(configDir, sessionRelative, WORKFLOWS_DIR)).filter((name) => name.startsWith(WORKFLOW_RUN_PREFIX) && name.endsWith(JSON_SUFFIX)).length;
16619
+ const transcript = fs12.lstat(path33.join(configDir, PROJECTS_DIR, ref.project, `${ref.entry}${TRANSCRIPT_SUFFIX}`));
16620
+ return { ...ref, agentCount, workflowRunCount, ...transcript === void 0 ? {} : { updatedAt: new Date(transcript.mtimeMs).toISOString() } };
16621
+ }
16519
16622
  function readSessionAgentTree(fs12, configDir, ref, options = {}) {
16520
16623
  const problems = [];
16521
16624
  const report = (problem) => {
@@ -16671,6 +16774,94 @@ function readWorkflowRuns(fs12, configDir, relativeDir, report) {
16671
16774
  return runs;
16672
16775
  }
16673
16776
 
16777
+ // src/agents/sessions.ts
16778
+ init_cliError();
16779
+ import path34 from "node:path";
16780
+ var SessionLookupError = class extends CliError {
16781
+ constructor(message) {
16782
+ super(message);
16783
+ this.name = "SessionLookupError";
16784
+ }
16785
+ };
16786
+ function identityConfigDir(identitiesDir, identity) {
16787
+ return path34.join(identitiesDir, identity);
16788
+ }
16789
+ function historyStores(fs12, identitiesDir, identities) {
16790
+ const byRealPath = /* @__PURE__ */ new Map();
16791
+ for (const identity of identities) {
16792
+ const configDir = identityConfigDir(identitiesDir, identity);
16793
+ const real = fs12.realpath(path34.join(configDir, "projects"));
16794
+ if (real === void 0) {
16795
+ continue;
16796
+ }
16797
+ const store = byRealPath.get(real);
16798
+ if (store === void 0) {
16799
+ byRealPath.set(real, { configDir, identities: [identity] });
16800
+ } else {
16801
+ store.identities.push(identity);
16802
+ }
16803
+ }
16804
+ return [...byRealPath.values()];
16805
+ }
16806
+ function collectSessionList(fs12, identitiesDir, identities, filters) {
16807
+ const names = filters.identity === void 0 ? identities : identities.filter((name) => name === filters.identity);
16808
+ if (filters.identity !== void 0 && names.length === 0) {
16809
+ throw new SessionLookupError(`no identity named "${filters.identity}"`);
16810
+ }
16811
+ const sessions = [];
16812
+ for (const store of historyStores(fs12, identitiesDir, names)) {
16813
+ for (const ref of listSessions2(fs12, store.configDir)) {
16814
+ const summary = summariseSession(fs12, store.configDir, ref);
16815
+ if (filters.all === true || summary.agentCount > 0 || summary.workflowRunCount > 0) {
16816
+ sessions.push({ ...summary, identities: store.identities });
16817
+ }
16818
+ }
16819
+ }
16820
+ return sessions.sort((left, right) => (right.updatedAt ?? "").localeCompare(left.updatedAt ?? "") || left.sessionId.localeCompare(right.sessionId));
16821
+ }
16822
+ function locateSession(fs12, identitiesDir, identities, query, onlyIdentity) {
16823
+ const names = onlyIdentity === void 0 ? identities : identities.filter((name) => name === onlyIdentity);
16824
+ if (onlyIdentity !== void 0 && names.length === 0) {
16825
+ throw new SessionLookupError(`no identity named "${onlyIdentity}"`);
16826
+ }
16827
+ const matches = [];
16828
+ for (const store of historyStores(fs12, identitiesDir, names)) {
16829
+ for (const ref of listSessions2(fs12, store.configDir)) {
16830
+ if (ref.sessionId.startsWith(query)) {
16831
+ matches.push({ identities: store.identities, configDir: store.configDir, ref });
16832
+ }
16833
+ }
16834
+ }
16835
+ const exact = matches.filter((match) => match.ref.sessionId === query);
16836
+ const candidates = exact.length > 0 ? exact : matches;
16837
+ const only = candidates[0];
16838
+ if (candidates.length === 1 && only !== void 0) {
16839
+ return only;
16840
+ }
16841
+ if (candidates.length === 0) {
16842
+ throw new SessionLookupError(`no session matches "${query}"`);
16843
+ }
16844
+ throw new SessionLookupError(`"${query}" matches ${String(candidates.length)} sessions: ${candidates.map((match) => `${match.ref.sessionId} (${match.identities.join(", ")})`).join("; ")}; give more of the id or pass --identity`);
16845
+ }
16846
+ function showSession(fs12, identitiesDir, identities, query, onlyIdentity) {
16847
+ const located = locateSession(fs12, identitiesDir, identities, query, onlyIdentity);
16848
+ return { identities: located.identities, tree: readSessionAgentTree(fs12, located.configDir, located.ref) };
16849
+ }
16850
+
16851
+ // src/agents/realFs.ts
16852
+ init_realPorts();
16853
+ import nodeFs from "node:fs";
16854
+ var realSessionFs = {
16855
+ ...realFarmFs,
16856
+ realpath: (candidate) => {
16857
+ try {
16858
+ return nodeFs.realpathSync(candidate);
16859
+ } catch {
16860
+ return void 0;
16861
+ }
16862
+ }
16863
+ };
16864
+
16674
16865
  // src/index.ts
16675
16866
  init_conditions();
16676
16867
  init_ensure();
@@ -16782,6 +16973,10 @@ export {
16782
16973
  AgentKindSchema,
16783
16974
  AgentMetaSchema,
16784
16975
  AgentNodeSchema,
16976
+ AgentTreesListInputSchema,
16977
+ AgentTreesListOutputSchema,
16978
+ AgentTreesShowInputSchema,
16979
+ AgentTreesShowOutputSchema,
16785
16980
  CHECK_CREDENTIAL_APPLIES,
16786
16981
  CODEX_APP_SERVER_GENERATED_AGAINST,
16787
16982
  CODEX_APP_SERVER_TIMEOUT_MS,
@@ -16929,6 +17124,8 @@ export {
16929
17124
  ResetRowSchema,
16930
17125
  ResetScheduleSchema,
16931
17126
  SessionAgentTreeSchema,
17127
+ SessionLookupError,
17128
+ SessionSummarySchema,
16932
17129
  TaskItemSchema,
16933
17130
  USAGE_EVENT_SOURCE,
16934
17131
  UpdateCheckOutputSchema,
@@ -16976,6 +17173,8 @@ export {
16976
17173
  collectFrontDoorStatus,
16977
17174
  collectPoolPick,
16978
17175
  collectResets,
17176
+ collectSessionList,
17177
+ createAgentTreesApiRouter,
16979
17178
  createCodexApiRouter,
16980
17179
  createConfigApiRouter,
16981
17180
  createControlApiRouter,
@@ -17044,6 +17243,7 @@ export {
17044
17243
  listProviders,
17045
17244
  listSessions2 as listSessions,
17046
17245
  listUsageSnapshots,
17246
+ locateSession,
17047
17247
  matchBranch,
17048
17248
  mintLeaf,
17049
17249
  mintRcSelfHostCredential,
@@ -17086,6 +17286,7 @@ export {
17086
17286
  realRcEventDial,
17087
17287
  realRcStreamDial,
17088
17288
  realRcWebFetch,
17289
+ realSessionFs,
17089
17290
  reconnectRcSessionMcpServer,
17090
17291
  recoverFarm,
17091
17292
  recoveryDiagnostics,
@@ -17127,11 +17328,13 @@ export {
17127
17328
  setProfileMetadata,
17128
17329
  setRcSessionModel,
17129
17330
  setRcSessionPermissionMode,
17331
+ showSession,
17130
17332
  snapshotPath,
17131
17333
  spawnClaude,
17132
17334
  startConnectServer,
17133
17335
  submitRcSessionMcpOAuthCallbackUrl,
17134
17336
  suggestRcSessionFiles,
17337
+ summariseSession,
17135
17338
  teleportRcSession,
17136
17339
  topLevelNames,
17137
17340
  updateDirectoryRule,