@evident-ai/cli 3.4.1-dev.4a15fbd → 3.4.1-dev.5210d05

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.js CHANGED
@@ -805,6 +805,7 @@ async function reportResourceUsage(agentId, authHeader, usage) {
805
805
  headers: { Authorization: authHeader, "Content-Type": "application/json" },
806
806
  body: JSON.stringify({
807
807
  cpu_percent: usage.cpuPercent,
808
+ cpu_peak_percent: usage.cpuPeakPercent,
808
809
  cpu_count: usage.cpuCount,
809
810
  memory_total_bytes: usage.memoryTotalBytes,
810
811
  memory_available_bytes: usage.memoryAvailableBytes,
@@ -1215,6 +1216,7 @@ var TelemetryEventTypes = {
1215
1216
  // ../../packages/types/src/tunnel/index.ts
1216
1217
  var MAX_FRAME_BYTES = 256 * 1024;
1217
1218
  var TUNNEL_DRAIN_PING_PATH = "/__evident/drain";
1219
+ var TUNNEL_USAGE_REARM_PING_PATH = "/__evident/usage-rearm";
1218
1220
 
1219
1221
  // ../../packages/types/src/runner-files.ts
1220
1222
  var MAX_FILE_PUSH_BYTES = 64 * 1024;
@@ -3150,6 +3152,44 @@ function findLastAssistantReplyFor(messages, userMessageId) {
3150
3152
  }
3151
3153
  return lastOk ?? last;
3152
3154
  }
3155
+ function collectSubagentSessions(messages, userMessageId) {
3156
+ if (!messages || messages.length === 0) return [];
3157
+ const byParent = messages.filter(
3158
+ (message) => roleOf(message) === "assistant" && parentIdOf(message) === userMessageId
3159
+ );
3160
+ const assistants = byParent.length > 0 ? byParent : [];
3161
+ if (assistants.length === 0) {
3162
+ const userIndex = messages.findIndex((message) => idOf(message) === userMessageId);
3163
+ if (userIndex === -1) return [];
3164
+ for (let i = userIndex + 1; i < messages.length; i++) {
3165
+ const message = messages[i];
3166
+ if (roleOf(message) === "user") break;
3167
+ if (roleOf(message) === "assistant") assistants.push(message);
3168
+ }
3169
+ }
3170
+ const refs = [];
3171
+ const seen = /* @__PURE__ */ new Set();
3172
+ for (const message of assistants) {
3173
+ const parts = Array.isArray(message.parts) ? message.parts : [];
3174
+ for (const part of parts) {
3175
+ if (!part || typeof part !== "object" || part.type !== "tool" || part.tool !== "task")
3176
+ continue;
3177
+ const state = part.state;
3178
+ if (!state || typeof state !== "object") continue;
3179
+ const metadata = state.metadata;
3180
+ if (!metadata || typeof metadata !== "object") continue;
3181
+ const sessionId = metadata.sessionId;
3182
+ if (typeof sessionId !== "string" || sessionId.length === 0 || seen.has(sessionId)) continue;
3183
+ seen.add(sessionId);
3184
+ const start = state.time?.start;
3185
+ refs.push({
3186
+ sessionId,
3187
+ startedAtMs: typeof start === "number" && Number.isFinite(start) ? start : null
3188
+ });
3189
+ }
3190
+ }
3191
+ return refs;
3192
+ }
3153
3193
  function messageUsage(messages, userMessageId) {
3154
3194
  if (!messages || messages.length === 0) return null;
3155
3195
  const byParentAll = messages.filter(
@@ -3278,8 +3318,7 @@ function isAbortedTerminalReply(messages, userMessageId) {
3278
3318
  }
3279
3319
  return false;
3280
3320
  }
3281
- function messageFailure(messages, userMessageId) {
3282
- const reply = findLastAssistantReplyFor(messages, userMessageId);
3321
+ function classifyReplyAuthError(reply) {
3283
3322
  const error2 = errorOf(reply);
3284
3323
  if (error2 == null || typeof error2 !== "object") return null;
3285
3324
  const e = error2;
@@ -3304,6 +3343,32 @@ function messageFailure(messages, userMessageId) {
3304
3343
  }
3305
3344
  return null;
3306
3345
  }
3346
+ function messageFailure(messages, userMessageId) {
3347
+ return classifyReplyAuthError(findLastAssistantReplyFor(messages, userMessageId));
3348
+ }
3349
+ function findLatestSubagentAuthOutcome(messages, sinceMs) {
3350
+ if (!messages || messages.length === 0) return null;
3351
+ for (let i = messages.length - 1; i >= 0; i--) {
3352
+ const message = messages[i];
3353
+ if (roleOf(message) !== "assistant") continue;
3354
+ const created = createdOf(message);
3355
+ if (sinceMs !== null && typeof created === "number" && created < sinceMs) continue;
3356
+ const failure = classifyReplyAuthError(message);
3357
+ if (failure) {
3358
+ if (!failure.providerId) return null;
3359
+ return { providerId: failure.providerId, outcome: "failed", failure };
3360
+ }
3361
+ const providerId = message.info?.providerID;
3362
+ if (errorOf(message) == null && typeof providerId === "string" && providerId.length > 0) {
3363
+ return { providerId, outcome: "succeeded" };
3364
+ }
3365
+ return null;
3366
+ }
3367
+ return null;
3368
+ }
3369
+ function findSubagentAuthOutcome(messages, sinceMs) {
3370
+ return findLatestSubagentAuthOutcome(messages, sinceMs);
3371
+ }
3307
3372
  function applyZeroProviderFallback(classified, hasConfiguredProvider, replyProviderId, replyModelId = null) {
3308
3373
  if (classified != null) return classified;
3309
3374
  if (hasConfiguredProvider !== false) return null;
@@ -3634,7 +3699,6 @@ var StreamForwarder = class {
3634
3699
  handleFrame(frame) {
3635
3700
  switch (frame.type) {
3636
3701
  case "open":
3637
- this.callbacks.onOpen?.(frame.sid, frame.method, frame.path);
3638
3702
  void this.handleOpen(frame);
3639
3703
  break;
3640
3704
  case "req_data":
@@ -3670,12 +3734,21 @@ var StreamForwarder = class {
3670
3734
  const { sid, method, path, headers, has_body } = frame;
3671
3735
  const correlationId = headers?.[CORRELATION_ID_HEADER];
3672
3736
  const startedAt = Date.now();
3737
+ if (path !== TUNNEL_DRAIN_PING_PATH && path !== TUNNEL_USAGE_REARM_PING_PATH) {
3738
+ this.callbacks.onOpen?.(sid, method, path);
3739
+ }
3673
3740
  if (path === TUNNEL_DRAIN_PING_PATH) {
3674
3741
  this.callbacks.onDrainPing?.();
3675
3742
  this.send({ type: "head", sid, status: 204, headers: {} });
3676
3743
  this.send({ type: "res_end", sid });
3677
3744
  return;
3678
3745
  }
3746
+ if (path === TUNNEL_USAGE_REARM_PING_PATH) {
3747
+ this.callbacks.onUsageRearmPing?.();
3748
+ this.send({ type: "head", sid, status: 204, headers: {} });
3749
+ this.send({ type: "res_end", sid });
3750
+ return;
3751
+ }
3679
3752
  if (process.env.DEBUG) {
3680
3753
  log("debug", "agent_request", {
3681
3754
  correlation_id: correlationId,
@@ -3820,7 +3893,8 @@ function connectTunnel(options) {
3820
3893
  onResponse,
3821
3894
  onInfo,
3822
3895
  onWarning,
3823
- onDrainPing
3896
+ onDrainPing,
3897
+ onUsageRearmPing
3824
3898
  } = options;
3825
3899
  const tunnelUrl = getTunnelUrlConfig();
3826
3900
  const url = `${tunnelUrl}/tunnel/${agentId}/connect`;
@@ -3832,7 +3906,8 @@ function connectTunnel(options) {
3832
3906
  });
3833
3907
  const forwarder = new StreamForwarder(ws, port, {
3834
3908
  onHead: () => onResponse?.(),
3835
- onDrainPing: () => onDrainPing?.()
3909
+ onDrainPing: () => onDrainPing?.(),
3910
+ onUsageRearmPing: () => onUsageRearmPing?.()
3836
3911
  });
3837
3912
  const connectionTimeout = setTimeout(() => {
3838
3913
  ws.close();
@@ -3993,6 +4068,7 @@ var RunnerConnection = class {
3993
4068
  onError: (error2) => events.onError?.(error2),
3994
4069
  onResponse: () => events.onResponse?.(),
3995
4070
  onDrainPing: () => events.onDrainPing?.(),
4071
+ onUsageRearmPing: () => events.onUsageRearmPing?.(),
3996
4072
  onInfo: (message) => events.onInfo?.(message),
3997
4073
  onWarning: (message) => events.onWarning?.(message)
3998
4074
  });
@@ -4437,45 +4513,84 @@ function readDisk(homeDir) {
4437
4513
  };
4438
4514
  }
4439
4515
  }
4440
- function createResourceUsageCollector(homeDir) {
4441
- let previous = readCpuSample();
4442
- return async () => {
4516
+ var CPU_PEAK_WINDOW_MS = 6e4;
4517
+ var CPU_PEAK_WINDOW_SAMPLE_COUNT = 4;
4518
+ var CPU_PEAK_SAMPLE_INTERVAL_MS = CPU_PEAK_WINDOW_MS / CPU_PEAK_WINDOW_SAMPLE_COUNT;
4519
+ function createCpuPeakSampler() {
4520
+ const sampleHistory = new Array(CPU_PEAK_WINDOW_SAMPLE_COUNT);
4521
+ sampleHistory[0] = readCpuSample();
4522
+ let nextSampleIndex = 1;
4523
+ let sampleCount = 1;
4524
+ let peak = null;
4525
+ const timer = setInterval(() => {
4443
4526
  const current = readCpuSample();
4444
- const hostCpuPercent = cpuPercentBetween(previous, current);
4445
- const hostCpuCount = cpus().length;
4446
- previous = current;
4447
- const disk = readDisk(homeDir);
4448
- const opencodeDbBytes = statSessionDbBytes(homeDir);
4449
- const { limits, warning: ecsWarning } = await readEcsTaskLimits(process.env);
4450
- const warnings = [];
4451
- if (disk.warning) warnings.push(disk.warning);
4452
- if (ecsWarning) warnings.push(ecsWarning);
4453
- let cpuPercent = hostCpuPercent;
4454
- let cpuCount = hostCpuCount;
4455
- let memoryTotalBytes = totalmem();
4456
- let memoryAvailableBytes = freemem();
4457
- if (limits !== null) {
4458
- cpuCount = limits.cpuCount;
4459
- memoryTotalBytes = limits.memoryTotalBytes;
4460
- memoryAvailableBytes = clamp(
4461
- limits.memoryTotalBytes - (totalmem() - freemem()),
4462
- 0,
4463
- limits.memoryTotalBytes
4464
- );
4465
- cpuPercent = hostCpuPercent === null ? null : clamp(round2(hostCpuPercent * hostCpuCount / limits.cpuCount), 0, 100);
4527
+ const sampleFromWindowAgo = sampleCount === CPU_PEAK_WINDOW_SAMPLE_COUNT ? sampleHistory[nextSampleIndex] : void 0;
4528
+ if (sampleFromWindowAgo !== void 0) {
4529
+ const percentage = cpuPercentBetween(sampleFromWindowAgo, current);
4530
+ if (percentage !== null) {
4531
+ peak = peak === null ? percentage : Math.max(peak, percentage);
4532
+ }
4466
4533
  }
4467
- return {
4468
- usage: {
4469
- cpuPercent,
4470
- cpuCount,
4471
- memoryTotalBytes,
4472
- memoryAvailableBytes,
4473
- diskTotalBytes: disk.totalBytes,
4474
- diskFreeBytes: disk.freeBytes,
4475
- opencodeDbBytes
4476
- },
4477
- warnings
4478
- };
4534
+ sampleHistory[nextSampleIndex] = current;
4535
+ nextSampleIndex = (nextSampleIndex + 1) % CPU_PEAK_WINDOW_SAMPLE_COUNT;
4536
+ sampleCount = Math.min(sampleCount + 1, CPU_PEAK_WINDOW_SAMPLE_COUNT);
4537
+ }, CPU_PEAK_SAMPLE_INTERVAL_MS);
4538
+ return {
4539
+ takeAndReset: () => {
4540
+ const currentPeak = peak;
4541
+ peak = null;
4542
+ return currentPeak;
4543
+ },
4544
+ stop: () => clearInterval(timer)
4545
+ };
4546
+ }
4547
+ function createResourceUsageCollector(homeDir) {
4548
+ let previous = readCpuSample();
4549
+ const cpuPeakSampler = createCpuPeakSampler();
4550
+ return {
4551
+ collect: async () => {
4552
+ const current = readCpuSample();
4553
+ const hostCpuPercent = cpuPercentBetween(previous, current);
4554
+ const hostCpuPeakPercent = cpuPeakSampler.takeAndReset();
4555
+ const hostCpuCount = cpus().length;
4556
+ previous = current;
4557
+ const disk = readDisk(homeDir);
4558
+ const opencodeDbBytes = statSessionDbBytes(homeDir);
4559
+ const { limits, warning: ecsWarning } = await readEcsTaskLimits(process.env);
4560
+ const warnings = [];
4561
+ if (disk.warning) warnings.push(disk.warning);
4562
+ if (ecsWarning) warnings.push(ecsWarning);
4563
+ let cpuPercent = hostCpuPercent;
4564
+ let cpuPeakPercent = hostCpuPeakPercent;
4565
+ let cpuCount = hostCpuCount;
4566
+ let memoryTotalBytes = totalmem();
4567
+ let memoryAvailableBytes = freemem();
4568
+ if (limits !== null) {
4569
+ cpuCount = limits.cpuCount;
4570
+ memoryTotalBytes = limits.memoryTotalBytes;
4571
+ memoryAvailableBytes = clamp(
4572
+ limits.memoryTotalBytes - (totalmem() - freemem()),
4573
+ 0,
4574
+ limits.memoryTotalBytes
4575
+ );
4576
+ cpuPercent = hostCpuPercent === null ? null : clamp(round2(hostCpuPercent * hostCpuCount / limits.cpuCount), 0, 100);
4577
+ cpuPeakPercent = hostCpuPeakPercent === null ? null : clamp(round2(hostCpuPeakPercent * hostCpuCount / limits.cpuCount), 0, 100);
4578
+ }
4579
+ return {
4580
+ usage: {
4581
+ cpuPercent,
4582
+ cpuPeakPercent,
4583
+ cpuCount,
4584
+ memoryTotalBytes,
4585
+ memoryAvailableBytes,
4586
+ diskTotalBytes: disk.totalBytes,
4587
+ diskFreeBytes: disk.freeBytes,
4588
+ opencodeDbBytes
4589
+ },
4590
+ warnings
4591
+ };
4592
+ },
4593
+ stop: cpuPeakSampler.stop
4479
4594
  };
4480
4595
  }
4481
4596
 
@@ -6062,6 +6177,9 @@ var ChannelDriver = class _ChannelDriver {
6062
6177
  });
6063
6178
  await this.markFailed(conv.id, message.id, sessionId, error2, usage, failure);
6064
6179
  }
6180
+ if (ocId !== null) {
6181
+ await this.reportSubagentAuthFailures(conv.id, ocId, message.id, messages);
6182
+ }
6065
6183
  } catch (err) {
6066
6184
  if (err instanceof ChannelAuthError) throw err;
6067
6185
  this.log({
@@ -7026,6 +7144,12 @@ var ChannelDriver = class _ChannelDriver {
7026
7144
  return;
7027
7145
  }
7028
7146
  inFlight.done = true;
7147
+ await this.reportSubagentAuthFailures(
7148
+ watcher.conv.id,
7149
+ inFlight.opencodeMessageId,
7150
+ inFlight.evidentMessageId,
7151
+ messages
7152
+ );
7029
7153
  }
7030
7154
  this.removeInFlight(watcher, inFlight.evidentMessageId);
7031
7155
  return;
@@ -7268,6 +7392,12 @@ var ChannelDriver = class _ChannelDriver {
7268
7392
  return;
7269
7393
  }
7270
7394
  inFlight.done = true;
7395
+ await this.reportSubagentAuthFailures(
7396
+ watcher.conv.id,
7397
+ inFlight.opencodeMessageId,
7398
+ inFlight.evidentMessageId,
7399
+ messages
7400
+ );
7271
7401
  }
7272
7402
  this.removeInFlight(watcher, inFlight.evidentMessageId);
7273
7403
  }
@@ -7438,6 +7568,7 @@ var ChannelDriver = class _ChannelDriver {
7438
7568
  });
7439
7569
  return;
7440
7570
  }
7571
+ await this.reportSubagentAuthFailures(row.conversation_id, ocId ?? "", row.id, messages);
7441
7572
  this.dontRedispatch.delete(row.id);
7442
7573
  void this.postSignal(row.conversation_id, row.id, "readopt_failed");
7443
7574
  return;
@@ -7599,6 +7730,9 @@ var ChannelDriver = class _ChannelDriver {
7599
7730
  });
7600
7731
  return;
7601
7732
  }
7733
+ if (ocId !== null) {
7734
+ await this.reportSubagentAuthFailures(row.conversation_id, ocId, row.id, messages);
7735
+ }
7602
7736
  this.dontRedispatch.delete(row.id);
7603
7737
  void this.postSignal(row.conversation_id, row.id, "readopt_done");
7604
7738
  }
@@ -8550,6 +8684,111 @@ var ChannelDriver = class _ChannelDriver {
8550
8684
  reply?.info?.modelID ?? null
8551
8685
  );
8552
8686
  }
8687
+ async recordSubagentModelAuthFailure(failure, conversationId, messageId) {
8688
+ const providerId = failure.providerId ?? "(unknown)";
8689
+ try {
8690
+ const res = await this.fetchImpl(
8691
+ `${this.apiUrl}/runners/${this.agentId}/model-auth-failures`,
8692
+ {
8693
+ method: "POST",
8694
+ headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
8695
+ body: JSON.stringify({
8696
+ provider_id: failure.providerId,
8697
+ model_id: failure.modelId,
8698
+ reason: failure.reason
8699
+ })
8700
+ }
8701
+ );
8702
+ if (!res.ok) {
8703
+ this.log({
8704
+ level: "warn",
8705
+ message: `Sub-agent model-auth report for provider ${providerId} (${failure.reason}) returned HTTP ${res.status} (conversation ${conversationId.slice(0, 8)}, message ${messageId.slice(0, 8)})`,
8706
+ conversation_id: conversationId,
8707
+ message_id: messageId
8708
+ });
8709
+ }
8710
+ } catch (err) {
8711
+ this.log({
8712
+ level: "warn",
8713
+ message: `Sub-agent model-auth report for provider ${providerId} (${failure.reason}) failed with status network-error (conversation ${conversationId.slice(0, 8)}, message ${messageId.slice(0, 8)}): ${err instanceof Error ? err.message : String(err)}`,
8714
+ conversation_id: conversationId,
8715
+ message_id: messageId
8716
+ });
8717
+ }
8718
+ }
8719
+ async clearSubagentModelAuthFailure(providerId, conversationId, messageId) {
8720
+ try {
8721
+ const res = await this.fetchImpl(
8722
+ `${this.apiUrl}/runners/${this.agentId}/model-auth-failures/${encodeURIComponent(providerId)}`,
8723
+ {
8724
+ method: "DELETE",
8725
+ headers: { Authorization: this.getAuthHeader() }
8726
+ }
8727
+ );
8728
+ if (!res.ok) {
8729
+ this.log({
8730
+ level: "warn",
8731
+ message: `Sub-agent model-auth clear for provider ${providerId} returned HTTP ${res.status} (conversation ${conversationId.slice(0, 8)}, message ${messageId.slice(0, 8)})`,
8732
+ conversation_id: conversationId,
8733
+ message_id: messageId
8734
+ });
8735
+ }
8736
+ } catch (err) {
8737
+ this.log({
8738
+ level: "warn",
8739
+ message: `Sub-agent model-auth clear for provider ${providerId} failed with status network-error (conversation ${conversationId.slice(0, 8)}, message ${messageId.slice(0, 8)}): ${err instanceof Error ? err.message : String(err)}`,
8740
+ conversation_id: conversationId,
8741
+ message_id: messageId
8742
+ });
8743
+ }
8744
+ }
8745
+ async reportSubagentAuthFailures(conversationId, opencodeMessageId, evidentMessageId, messages) {
8746
+ const refs = collectSubagentSessions(messages, opencodeMessageId);
8747
+ if (refs.length === 0) return;
8748
+ const failedProviders = /* @__PURE__ */ new Map();
8749
+ const succeededProviders = /* @__PURE__ */ new Set();
8750
+ for (const ref of refs) {
8751
+ try {
8752
+ const childMessages = await getSessionMessages(this.port, ref.sessionId);
8753
+ if (childMessages === null) {
8754
+ this.log({
8755
+ level: "debug",
8756
+ message: `Could not read sub-agent session ${ref.sessionId} while checking credential failures \u2014 skipping it`,
8757
+ conversation_id: conversationId,
8758
+ message_id: evidentMessageId
8759
+ });
8760
+ continue;
8761
+ }
8762
+ const outcome = findSubagentAuthOutcome(childMessages, ref.startedAtMs);
8763
+ if (!outcome) continue;
8764
+ if (outcome.outcome === "failed") {
8765
+ failedProviders.set(outcome.providerId, outcome.failure);
8766
+ } else {
8767
+ succeededProviders.add(outcome.providerId);
8768
+ }
8769
+ } catch (err) {
8770
+ this.log({
8771
+ level: "warn",
8772
+ message: `Failed to inspect sub-agent session ${ref.sessionId} for credential failures (conversation ${conversationId.slice(0, 8)}, message ${evidentMessageId.slice(0, 8)}): ${err instanceof Error ? err.message : String(err)}`,
8773
+ conversation_id: conversationId,
8774
+ message_id: evidentMessageId
8775
+ });
8776
+ }
8777
+ }
8778
+ for (const [providerId, failure] of failedProviders) {
8779
+ this.log({
8780
+ level: "warn",
8781
+ message: `Sub-agent turn failed on provider ${providerId} (${failure.reason}) \u2014 recording credential evidence`,
8782
+ conversation_id: conversationId,
8783
+ message_id: evidentMessageId
8784
+ });
8785
+ await this.recordSubagentModelAuthFailure(failure, conversationId, evidentMessageId);
8786
+ }
8787
+ for (const providerId of succeededProviders) {
8788
+ if (failedProviders.has(providerId)) continue;
8789
+ await this.clearSubagentModelAuthFailure(providerId, conversationId, evidentMessageId);
8790
+ }
8791
+ }
8553
8792
  /**
8554
8793
  * Best-effort, SINGLE-ATTEMPT runner→server telemetry ping
8555
8794
  * (queued-followup-redrive). `POST .../messages/:id/signal {signal, ...extra}`
@@ -10080,7 +10319,8 @@ function scheduleResourceUsageReporting(state, options) {
10080
10319
  });
10081
10320
  return;
10082
10321
  }
10083
- const collect = createResourceUsageCollector(homedir5());
10322
+ const { collect, stop } = createResourceUsageCollector(homedir5());
10323
+ state.stopResourceUsageSampling = stop;
10084
10324
  let consecutiveFailures = 0;
10085
10325
  const tick = async () => {
10086
10326
  try {
@@ -10190,6 +10430,8 @@ async function cleanup(state, opts = {}) {
10190
10430
  clearTimeout(state.resourceUsageTimer);
10191
10431
  state.resourceUsageTimer = null;
10192
10432
  }
10433
+ state.stopResourceUsageSampling?.();
10434
+ state.stopResourceUsageSampling = null;
10193
10435
  const credentialSync = state.credentialSync;
10194
10436
  const flushCredentials = credentialSync ? async (phase, publish) => {
10195
10437
  await timeShutdownPhase(state, durations, phase, async () => {
@@ -10357,6 +10599,7 @@ async function run(options) {
10357
10599
  openaiUsageTimer: null,
10358
10600
  openaiUsageRearm: null,
10359
10601
  resourceUsageTimer: null,
10602
+ stopResourceUsageSampling: null,
10360
10603
  credentialSync: null,
10361
10604
  authHeader: ""
10362
10605
  };
@@ -10917,6 +11160,18 @@ async function run(options) {
10917
11160
  if (state.interactive) displayStatus(state);
10918
11161
  });
10919
11162
  },
11163
+ // Both loops are rearmed because `rearm()` is idempotent for the
11164
+ // provider that did not just connect, and is a no-op when reporting is off.
11165
+ onUsageRearmPing: () => {
11166
+ if (!state.running) return;
11167
+ logActivity(state, {
11168
+ type: "info",
11169
+ level: "debug",
11170
+ message: "Usage rearm ping received"
11171
+ });
11172
+ state.claudeUsageRearm?.();
11173
+ state.openaiUsageRearm?.();
11174
+ },
10920
11175
  onInfo: (message) => logActivity(state, { type: "info", message })
10921
11176
  }
10922
11177
  });