agent-shim 8.30.0 → 8.32.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.cjs CHANGED
@@ -48,6 +48,7 @@ __export(index_exports, {
48
48
  CredentialSourceSchema: () => CredentialSourceSchema,
49
49
  DOOR_EVENT_BUFFER_EVENTS: () => DOOR_EVENT_BUFFER_EVENTS,
50
50
  DOOR_EVENT_SOURCE_RC: () => DOOR_EVENT_SOURCE_RC,
51
+ DOOR_HEALTH_EVENT_SOURCE: () => DOOR_HEALTH_EVENT_SOURCE,
51
52
  DirectoryRuleAlreadyExistsError: () => DirectoryRuleAlreadyExistsError,
52
53
  DirectoryRuleMissingTargetError: () => DirectoryRuleMissingTargetError,
53
54
  DirectoryRuleNotFoundError: () => DirectoryRuleNotFoundError,
@@ -57,6 +58,7 @@ __export(index_exports, {
57
58
  DoctorRunOutputSchema: () => DoctorRunOutputSchema,
58
59
  DoorEventSchema: () => DoorEventSchema,
59
60
  DoorEventSourceQuerySchema: () => DoorEventSourceQuerySchema,
61
+ DoorHealthEventSchema: () => DoorHealthEventSchema,
60
62
  EXIT_FAILURE: () => EXIT_FAILURE,
61
63
  EXIT_USAGE: () => EXIT_USAGE,
62
64
  EffectiveWindowSchema: () => EffectiveWindowSchema,
@@ -93,6 +95,8 @@ __export(index_exports, {
93
95
  ProviderKindMismatchError: () => ProviderKindMismatchError,
94
96
  ProviderNotFoundError: () => ProviderNotFoundError,
95
97
  ProviderSchema: () => ProviderSchema,
98
+ QUOTA_EXPIRING_EVENT_SOURCE: () => QUOTA_EXPIRING_EVENT_SOURCE,
99
+ QuotaExpiringEventSchema: () => QuotaExpiringEventSchema,
96
100
  RC_CONTEXT_USAGE_DETAILS: () => RC_CONTEXT_USAGE_DETAILS,
97
101
  RC_IDLE_EXPIRY_MS: () => RC_IDLE_EXPIRY_MS,
98
102
  RC_ORPC_PATH_PREFIX: () => RC_ORPC_PATH_PREFIX,
@@ -120,6 +124,7 @@ __export(index_exports, {
120
124
  RcRateLimitWindowSchema: () => RcRateLimitWindowSchema,
121
125
  RcStreamEnvelopeSchema: () => RcStreamEnvelopeSchema,
122
126
  RcStreamEventSchema: () => RcStreamEventSchema,
127
+ USAGE_EVENT_SOURCE: () => USAGE_EVENT_SOURCE,
123
128
  UsageError: () => UsageError,
124
129
  UsageListOutputSchema: () => UsageListOutputSchema,
125
130
  UsageLiveOutputSchema: () => UsageLiveOutputSchema,
@@ -165,10 +170,12 @@ __export(index_exports, {
165
170
  createDoorApiNodeHandler: () => createDoorApiNodeHandler,
166
171
  createDoorApiRouter: () => createDoorApiRouter,
167
172
  createDoorEventHub: () => createDoorEventHub,
173
+ createDoorHealthPublisher: () => createDoorHealthPublisher,
168
174
  createEventsApiRouter: () => createEventsApiRouter,
169
175
  createLaunchEventPublisher: () => createLaunchEventPublisher,
170
176
  createLeafCache: () => createLeafCache,
171
177
  createProfile: () => createProfile,
178
+ createQuotaExpiringPublisher: () => createQuotaExpiringPublisher,
172
179
  createRcApiNodeHandler: () => createRcApiNodeHandler,
173
180
  createRcApiRouter: () => createRcApiRouter,
174
181
  createRcControlHandler: () => createRcControlHandler,
@@ -3034,6 +3041,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
3034
3041
  try {
3035
3042
  http3 = await ports.startProviderListener(lastPort);
3036
3043
  } catch (error) {
3044
+ ports.doorHealth.listenerFailed("provider", error instanceof Error ? error.message : String(error));
3037
3045
  return fail(`could not start the provider listener: ${error instanceof Error ? error.message : String(error)}`);
3038
3046
  }
3039
3047
  if (previousSticky !== void 0 && http3.port !== previousSticky) {
@@ -3046,6 +3054,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
3046
3054
  connect3 = await ports.startConnectListener(lastConnectPort);
3047
3055
  } catch (error) {
3048
3056
  await http3.close();
3057
+ ports.doorHealth.listenerFailed("connect", error instanceof Error ? error.message : String(error));
3049
3058
  return fail(`could not start the CONNECT surface: ${error instanceof Error ? error.message : String(error)}`);
3050
3059
  }
3051
3060
  if (previousStickyConnect !== void 0 && connect3.port !== previousStickyConnect) {
@@ -3059,6 +3068,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
3059
3068
  } catch (error) {
3060
3069
  await connect3.close();
3061
3070
  await http3.close();
3071
+ ports.doorHealth.listenerFailed("direct", error instanceof Error ? error.message : String(error));
3062
3072
  return fail(`could not start the direct listener: ${error instanceof Error ? error.message : String(error)}`);
3063
3073
  }
3064
3074
  if (previousStickyDirect !== void 0 && direct.port !== previousStickyDirect) {
@@ -3066,6 +3076,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
3066
3076
  }
3067
3077
  lastDirectPort = direct.port;
3068
3078
  writeFrontDoorState(fs12, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http3.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
3079
+ ports.doorHealth.generation({ providerPort: http3.port, connectPort: connect3.port, directPort: direct.port });
3069
3080
  fs12.removeRecursive(paths.frontdoorLockFile);
3070
3081
  ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http3.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
3071
3082
  let idleSince;
@@ -3078,11 +3089,13 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
3078
3089
  const listed = listFrontDoorSessions(fs12, paths.frontdoorSessionsDir);
3079
3090
  const pruned = pruneDeadFrontDoorSessions(fs12, paths.frontdoorSessionsDir, ports.isRunning);
3080
3091
  ports.observeLaunchRegistry(listed, pruned);
3092
+ ports.checkQuotaExpiry();
3081
3093
  const prunedPids = new Set(pruned);
3082
3094
  if (listed.filter((session) => !prunedPids.has(session.pid)).length === 0) {
3083
3095
  idleSince ??= ports.now();
3084
3096
  if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
3085
3097
  ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
3098
+ ports.doorHealth.idleShutdown();
3086
3099
  await direct.close();
3087
3100
  await connect3.close();
3088
3101
  await http3.close();
@@ -5342,7 +5355,7 @@ var import_undici = require("undici");
5342
5355
  // package.json
5343
5356
  var package_default = {
5344
5357
  name: "agent-shim",
5345
- version: "8.30.0",
5358
+ version: "8.32.0",
5346
5359
  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.",
5347
5360
  license: "MIT",
5348
5361
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -6524,10 +6537,10 @@ function windowBlockedUntil(windows) {
6524
6537
  const resets = windows.flatMap((window) => window.status === "rejected" && window.resetsAtMs !== void 0 ? [window.resetsAtMs] : []);
6525
6538
  return resets.length === 0 ? void 0 : Math.max(...resets);
6526
6539
  }
6527
- function fiveHourBurn(records) {
6540
+ function windowBurn(records, which) {
6528
6541
  const points = [];
6529
6542
  for (const record of records) {
6530
- const window = record.rateLimitHeaders === void 0 ? void 0 : parseUnifiedRateLimit(record.rateLimitHeaders)?.fiveHour;
6543
+ const window = record.rateLimitHeaders === void 0 ? void 0 : parseUnifiedRateLimit(record.rateLimitHeaders)?.[which];
6531
6544
  if (window?.utilization !== void 0 && window.resetsAt !== void 0) {
6532
6545
  points.push({ resetsAt: window.resetsAt, point: { atMs: Date.parse(record.at), utilization: window.utilization } });
6533
6546
  }
@@ -6621,11 +6634,16 @@ function assessIdentity(member, nowMs) {
6621
6634
  const score = remaining * plan.capacity / (untilResetMs / MS_PER_HOUR);
6622
6635
  const fiveRemaining = five?.utilization === void 0 ? void 0 : Math.max(0, 1 - five.utilization);
6623
6636
  const fiveUntil = five?.resetsAtMs === void 0 ? FIVE_HOUR_WINDOW_MS : Math.max(five.resetsAtMs - nowMs, MS_PER_SECOND4);
6624
- const burn = fiveHourBurn(member.records);
6637
+ const burn = windowBurn(member.records, "fiveHour");
6638
+ const sevenRemaining = seven?.utilization === void 0 ? void 0 : Math.max(0, 1 - seven.utilization);
6639
+ const sevenUntil = seven?.resetsAtMs === void 0 ? SEVEN_DAY_WINDOW_MS : Math.max(seven.resetsAtMs - nowMs, MS_PER_SECOND4);
6640
+ const sevenDayBurn = windowBurn(member.records, "sevenDay");
6625
6641
  return {
6626
6642
  candidate: { ...base, class: "scored", score, reasons: [...windowReasons.map((reason, index) => index === windowReasons.length - 1 ? `${reason}${observedAgo}` : reason), ...planReasons] },
6627
6643
  ...fiveRemaining === void 0 ? {} : { fiveHour: { remaining: fiveRemaining, untilResetMs: fiveUntil } },
6628
- ...burn === void 0 ? {} : { burn }
6644
+ ...burn === void 0 ? {} : { burn },
6645
+ ...sevenRemaining === void 0 ? {} : { sevenDay: { remaining: sevenRemaining, untilResetMs: sevenUntil } },
6646
+ ...sevenDayBurn === void 0 ? {} : { sevenDayBurn }
6629
6647
  };
6630
6648
  }
6631
6649
  function rankPool(input) {
@@ -6636,14 +6654,27 @@ function rankPool(input) {
6636
6654
  const candidates = assessments.map((assessment) => {
6637
6655
  const { candidate, fiveHour, burn } = assessment;
6638
6656
  const pace = burn ?? (sharedDemand === void 0 ? void 0 : sharedDemand / capacityOf(candidate.plan));
6639
- if (candidate.class !== "scored" || fiveHour === void 0 || pace === void 0) {
6657
+ const { sevenDay, sevenDayBurn } = assessment;
6658
+ if (candidate.class !== "scored") {
6640
6659
  return { ...candidate, feasible: true };
6641
6660
  }
6642
- const runsDryInMs = fiveHour.remaining / pace;
6643
- if (runsDryInMs >= fiveHour.untilResetMs) {
6661
+ const drySpots = [];
6662
+ if (fiveHour !== void 0 && pace !== void 0) {
6663
+ const runsDryInMs = fiveHour.remaining / pace;
6664
+ if (runsDryInMs < fiveHour.untilResetMs) {
6665
+ drySpots.push(`5h window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(fiveHour.untilResetMs)}`);
6666
+ }
6667
+ }
6668
+ if (sevenDay !== void 0 && sevenDayBurn !== void 0) {
6669
+ const runsDryInMs = sevenDay.remaining / sevenDayBurn;
6670
+ if (runsDryInMs < sevenDay.untilResetMs) {
6671
+ drySpots.push(`7d window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(sevenDay.untilResetMs)}`);
6672
+ }
6673
+ }
6674
+ if (drySpots.length === 0) {
6644
6675
  return { ...candidate, feasible: true };
6645
6676
  }
6646
- return { ...candidate, feasible: false, reasons: [`5h window would run dry in ${formatAge(runsDryInMs)}, before it resets in ${formatAge(fiveHour.untilResetMs)}`, ...candidate.reasons] };
6677
+ return { ...candidate, feasible: false, reasons: [...drySpots, ...candidate.reasons] };
6647
6678
  });
6648
6679
  const ordered = input.preference === "listed" ? [...candidates] : [...candidates].sort(
6649
6680
  (left, right) => CLASS_ORDER[left.class] - CLASS_ORDER[right.class] || Number(right.feasible) - Number(left.feasible) || (right.score ?? 0) - (left.score ?? 0) || left.identity.localeCompare(right.identity)
@@ -6651,7 +6682,8 @@ function rankPool(input) {
6651
6682
  const sticky = input.sticky;
6652
6683
  const stickyIndex = sticky === void 0 ? -1 : ordered.findIndex((candidate) => candidate.identity === sticky.identity);
6653
6684
  const stickyCandidate = ordered[stickyIndex];
6654
- if (sticky !== void 0 && stickyCandidate?.class === "scored" && stickyCandidate.feasible) {
6685
+ const keepSticky = stickyCandidate?.class === "scored" && stickyCandidate.feasible;
6686
+ if (sticky !== void 0 && keepSticky) {
6655
6687
  const ageMs = nowMs - Date.parse(sticky.at);
6656
6688
  const warm = ageMs <= PROMPT_CACHE_TTL_MS;
6657
6689
  if (input.resuming || warm) {
@@ -6660,12 +6692,14 @@ function rankPool(input) {
6660
6692
  ordered.unshift({ ...stickyCandidate, reasons: [why, ...stickyCandidate.reasons] });
6661
6693
  }
6662
6694
  }
6695
+ const movedOff = sticky !== void 0 && input.resuming && !keepSticky ? { identity: sticky.identity, reason: stickyCandidate?.reasons[0] ?? "no longer among the pool's members" } : void 0;
6663
6696
  const pick = ordered.find((candidate) => candidate.class !== "ineligible");
6664
6697
  const returns = ordered.flatMap((candidate) => candidate.blockedUntilMs === void 0 ? [] : [{ identity: candidate.identity, atMs: candidate.blockedUntilMs }]);
6665
6698
  const earliestReturn = returns.length === 0 ? void 0 : returns.reduce((soonest, entry) => entry.atMs < soonest.atMs ? entry : soonest);
6666
6699
  return {
6667
6700
  candidates: ordered,
6668
- ...pick === void 0 ? { ...earliestReturn === void 0 ? {} : { earliestReturn } } : { pick }
6701
+ ...pick === void 0 ? { ...earliestReturn === void 0 ? {} : { earliestReturn } } : { pick },
6702
+ ...movedOff === void 0 || pick === void 0 ? {} : { movedOff }
6669
6703
  };
6670
6704
  }
6671
6705
 
@@ -6923,6 +6957,7 @@ function collectPoolPick(params) {
6923
6957
  candidates: ranking.candidates.map(candidateView),
6924
6958
  missing: missing.map(({ identity }) => identity),
6925
6959
  ...ranking.earliestReturn === void 0 ? {} : { earliestReturn: { identity: ranking.earliestReturn.identity, at: new Date(ranking.earliestReturn.atMs).toISOString() } },
6960
+ ...ranking.movedOff === void 0 ? {} : { movedOff: ranking.movedOff },
6926
6961
  ...sticky.problem === void 0 ? {} : { stickyProblem: sticky.problem }
6927
6962
  };
6928
6963
  }
@@ -9194,6 +9229,8 @@ var PoolPickReportSchema = import_zod13.z.strictObject({
9194
9229
  missing: import_zod13.z.array(import_zod13.z.string()),
9195
9230
  /** When nothing can be picked, the soonest any member returns. */
9196
9231
  earliestReturn: import_zod13.z.strictObject({ identity: import_zod13.z.string(), at: import_zod13.z.iso.datetime() }).optional(),
9232
+ /** The member a resumed conversation started on but moved off, and why, when the ranking could not keep it. */
9233
+ movedOff: import_zod13.z.strictObject({ identity: import_zod13.z.string(), reason: import_zod13.z.string() }).optional(),
9197
9234
  /** Why the last-pick record could not be read, when that is the case. */
9198
9235
  stickyProblem: import_zod13.z.string().optional()
9199
9236
  });
@@ -10204,6 +10241,9 @@ var import_server3 = require("@orpc/server");
10204
10241
  var import_zod20 = require("zod");
10205
10242
  var DOOR_EVENT_SOURCE_RC = "rc";
10206
10243
  var LAUNCH_EVENT_SOURCE = "launch";
10244
+ var USAGE_EVENT_SOURCE = "usage";
10245
+ var DOOR_HEALTH_EVENT_SOURCE = "door";
10246
+ var QUOTA_EXPIRING_EVENT_SOURCE = "quota-expiring";
10207
10247
  var DoorEventSchema = import_zod20.z.strictObject({
10208
10248
  source: import_zod20.z.string().min(1),
10209
10249
  /** A positive integer because the backbone's counters start at one and only ever increase. */
@@ -10219,6 +10259,20 @@ var LaunchLifecycleEventSchema = import_zod20.z.strictObject({
10219
10259
  startedAt: import_zod20.z.number(),
10220
10260
  observedAt: import_zod20.z.number()
10221
10261
  });
10262
+ var DoorHealthEventSchema = import_zod20.z.discriminatedUnion("kind", [
10263
+ import_zod20.z.strictObject({ kind: import_zod20.z.literal("generation"), pid: import_zod20.z.number().int().positive(), providerPort: import_zod20.z.number().int().positive(), connectPort: import_zod20.z.number().int().positive(), directPort: import_zod20.z.number().int().positive(), observedAt: import_zod20.z.number() }),
10264
+ import_zod20.z.strictObject({ kind: import_zod20.z.literal("listenerFailed"), pid: import_zod20.z.number().int().positive(), listener: import_zod20.z.enum(["provider", "connect", "direct"]), message: import_zod20.z.string(), observedAt: import_zod20.z.number() }),
10265
+ import_zod20.z.strictObject({ kind: import_zod20.z.literal("idleShutdown"), pid: import_zod20.z.number().int().positive(), observedAt: import_zod20.z.number() })
10266
+ ]);
10267
+ var QuotaExpiringEventSchema = import_zod20.z.strictObject({
10268
+ identity: import_zod20.z.string().min(1),
10269
+ provider: import_zod20.z.string().min(1),
10270
+ window: import_zod20.z.enum(["fiveHour", "sevenDay"]),
10271
+ /** The fraction of the window already used when it was seen expiring, always below one because a fully used window has nothing left to spend. */
10272
+ utilization: import_zod20.z.number().min(0).max(1),
10273
+ resetsAt: import_zod20.z.iso.datetime(),
10274
+ observedAt: import_zod20.z.number()
10275
+ });
10222
10276
 
10223
10277
  // src/frontdoor/eventsApi.ts
10224
10278
  var EVENTS_API_TAG = "events";
@@ -10527,6 +10581,81 @@ function createLaunchEventPublisher(hub, now) {
10527
10581
  };
10528
10582
  }
10529
10583
 
10584
+ // src/frontdoor/doorHealthEvents.ts
10585
+ function createDoorHealthPublisher(hub, now, pid) {
10586
+ const publisher = hub.publisher(DOOR_HEALTH_EVENT_SOURCE);
10587
+ return {
10588
+ generation: (ports) => {
10589
+ publisher.publish({ kind: "generation", pid, providerPort: ports.providerPort, connectPort: ports.connectPort, directPort: ports.directPort, observedAt: now() });
10590
+ },
10591
+ listenerFailed: (listener, message) => {
10592
+ publisher.publish({ kind: "listenerFailed", pid, listener, message, observedAt: now() });
10593
+ },
10594
+ idleShutdown: () => {
10595
+ publisher.publish({ kind: "idleShutdown", pid, observedAt: now() });
10596
+ }
10597
+ };
10598
+ }
10599
+
10600
+ // src/frontdoor/quotaExpiringEvents.ts
10601
+ var MS_PER_HOUR2 = 36e5;
10602
+ var MS_PER_DAY2 = 864e5;
10603
+ var FIVE_HOUR_WINDOW_HOURS = 5;
10604
+ var SEVEN_DAY_WINDOW_DAYS = 7;
10605
+ var FIVE_HOUR_WINDOW_MS2 = FIVE_HOUR_WINDOW_HOURS * MS_PER_HOUR2;
10606
+ var SEVEN_DAY_WINDOW_MS2 = SEVEN_DAY_WINDOW_DAYS * MS_PER_DAY2;
10607
+ var FINAL_SPAN_DENOMINATOR = 30;
10608
+ var QUOTA_EXPIRING_WINDOW_FRACTION = 1 / FINAL_SPAN_DENOMINATOR;
10609
+ function createQuotaExpiringPublisher(hub, deps) {
10610
+ const publisher = hub.publisher(QUOTA_EXPIRING_EVENT_SOURCE);
10611
+ const latest = /* @__PURE__ */ new Map();
10612
+ for (const snapshot of deps.seed) {
10613
+ latest.set(snapshot.identity, snapshot);
10614
+ }
10615
+ hub.subscribe([USAGE_EVENT_SOURCE], (event) => {
10616
+ const snapshot = UsageSnapshotSchema.parse(event.payload);
10617
+ latest.set(snapshot.identity, snapshot);
10618
+ });
10619
+ const announced = /* @__PURE__ */ new Set();
10620
+ const windowsOf = (snapshot) => {
10621
+ const views = [];
10622
+ for (const provider of Object.keys(snapshot.providers).sort()) {
10623
+ const unified = snapshot.providers[provider]?.rateLimit?.unified;
10624
+ const fiveHour = unified?.fiveHour;
10625
+ if (fiveHour?.utilization !== void 0 && fiveHour.resetsAt !== void 0) {
10626
+ views.push({ provider, view: { window: "fiveHour", spanMs: FIVE_HOUR_WINDOW_MS2, utilization: fiveHour.utilization, resetsAtMs: Date.parse(fiveHour.resetsAt) } });
10627
+ }
10628
+ const sevenDay = unified?.sevenDay;
10629
+ if (sevenDay?.utilization !== void 0 && sevenDay.resetsAt !== void 0) {
10630
+ views.push({ provider, view: { window: "sevenDay", spanMs: SEVEN_DAY_WINDOW_MS2, utilization: sevenDay.utilization, resetsAtMs: Date.parse(sevenDay.resetsAt) } });
10631
+ }
10632
+ }
10633
+ return views;
10634
+ };
10635
+ return {
10636
+ check: () => {
10637
+ const now = deps.now();
10638
+ for (const identity of [...latest.keys()].sort()) {
10639
+ const snapshot = latest.get(identity);
10640
+ if (snapshot === void 0) {
10641
+ continue;
10642
+ }
10643
+ for (const { provider, view } of windowsOf(snapshot)) {
10644
+ if (view.utilization >= 1 || view.resetsAtMs <= now || view.resetsAtMs - now >= view.spanMs * QUOTA_EXPIRING_WINDOW_FRACTION) {
10645
+ continue;
10646
+ }
10647
+ const key = `${identity}:${provider}:${view.window}:${String(view.resetsAtMs)}`;
10648
+ if (announced.has(key)) {
10649
+ continue;
10650
+ }
10651
+ announced.add(key);
10652
+ publisher.publish({ identity, provider, window: view.window, utilization: view.utilization, resetsAt: new Date(view.resetsAtMs).toISOString(), observedAt: now });
10653
+ }
10654
+ }
10655
+ }
10656
+ };
10657
+ }
10658
+
10530
10659
  // src/frontdoor/rcLiveUsage.ts
10531
10660
  var RC_RATE_LIMIT_EVENT_TYPE = "rate_limit_event";
10532
10661
  function isRecord5(value) {
@@ -12848,10 +12977,11 @@ function resolvePoolLaunch(params) {
12848
12977
  if (graph.ranking.candidates.length === 0) {
12849
12978
  return { ok: false, message: `agent-shim: no member of pool "${poolName}" is an existing identity.` };
12850
12979
  }
12851
- const { pick, earliestReturn } = graph.ranking;
12980
+ const { pick, earliestReturn, movedOff } = graph.ranking;
12852
12981
  if (pick !== void 0) {
12853
12982
  recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
12854
- return { ok: true, identity: pick.identity, explanation: `pool ${poolName}: ${pick.reasons.slice(0, REASONS_LOGGED).join("; ")}` };
12983
+ const move = movedOff === void 0 ? "" : `moved off ${movedOff.identity} (${movedOff.reason}); `;
12984
+ return { ok: true, identity: pick.identity, explanation: `pool ${poolName}: ${move}${pick.reasons.slice(0, REASONS_LOGGED).join("; ")}` };
12855
12985
  }
12856
12986
  if (earliestReturn === void 0) {
12857
12987
  return { ok: false, message: `agent-shim: no member of pool "${poolName}" can be picked.` };
@@ -13520,6 +13650,7 @@ function prepareClaudeLaunch(options) {
13520
13650
  CredentialSourceSchema,
13521
13651
  DOOR_EVENT_BUFFER_EVENTS,
13522
13652
  DOOR_EVENT_SOURCE_RC,
13653
+ DOOR_HEALTH_EVENT_SOURCE,
13523
13654
  DirectoryRuleAlreadyExistsError,
13524
13655
  DirectoryRuleMissingTargetError,
13525
13656
  DirectoryRuleNotFoundError,
@@ -13529,6 +13660,7 @@ function prepareClaudeLaunch(options) {
13529
13660
  DoctorRunOutputSchema,
13530
13661
  DoorEventSchema,
13531
13662
  DoorEventSourceQuerySchema,
13663
+ DoorHealthEventSchema,
13532
13664
  EXIT_FAILURE,
13533
13665
  EXIT_USAGE,
13534
13666
  EffectiveWindowSchema,
@@ -13565,6 +13697,8 @@ function prepareClaudeLaunch(options) {
13565
13697
  ProviderKindMismatchError,
13566
13698
  ProviderNotFoundError,
13567
13699
  ProviderSchema,
13700
+ QUOTA_EXPIRING_EVENT_SOURCE,
13701
+ QuotaExpiringEventSchema,
13568
13702
  RC_CONTEXT_USAGE_DETAILS,
13569
13703
  RC_IDLE_EXPIRY_MS,
13570
13704
  RC_ORPC_PATH_PREFIX,
@@ -13592,6 +13726,7 @@ function prepareClaudeLaunch(options) {
13592
13726
  RcRateLimitWindowSchema,
13593
13727
  RcStreamEnvelopeSchema,
13594
13728
  RcStreamEventSchema,
13729
+ USAGE_EVENT_SOURCE,
13595
13730
  UsageError,
13596
13731
  UsageListOutputSchema,
13597
13732
  UsageLiveOutputSchema,
@@ -13637,10 +13772,12 @@ function prepareClaudeLaunch(options) {
13637
13772
  createDoorApiNodeHandler,
13638
13773
  createDoorApiRouter,
13639
13774
  createDoorEventHub,
13775
+ createDoorHealthPublisher,
13640
13776
  createEventsApiRouter,
13641
13777
  createLaunchEventPublisher,
13642
13778
  createLeafCache,
13643
13779
  createProfile,
13780
+ createQuotaExpiringPublisher,
13644
13781
  createRcApiNodeHandler,
13645
13782
  createRcApiRouter,
13646
13783
  createRcControlHandler,