@evident-ai/cli 3.4.1-dev.bcdc457 → 3.4.1-dev.d8ffc5f

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
@@ -722,6 +722,14 @@ function toReportedWindow(window) {
722
722
  if (!window) return null;
723
723
  return { utilization: window.utilization, resets_at: window.resetsAt };
724
724
  }
725
+ function toReportedOwner(snapshot) {
726
+ if (!snapshot.owner) return null;
727
+ return {
728
+ email: snapshot.owner.email,
729
+ organization_name: snapshot.owner.organizationName,
730
+ rate_limit_tier: snapshot.owner.rateLimitTier
731
+ };
732
+ }
725
733
  async function reportClaudeUsage(agentId, authHeader, snapshot) {
726
734
  try {
727
735
  const apiUrl = getApiUrlConfig();
@@ -730,7 +738,8 @@ async function reportClaudeUsage(agentId, authHeader, snapshot) {
730
738
  headers: { Authorization: authHeader, "Content-Type": "application/json" },
731
739
  body: JSON.stringify({
732
740
  five_hour: toReportedWindow(snapshot.fiveHour),
733
- seven_day: toReportedWindow(snapshot.sevenDay)
741
+ seven_day: toReportedWindow(snapshot.sevenDay),
742
+ owner: toReportedOwner(snapshot)
734
743
  }),
735
744
  signal: AbortSignal.timeout(BEST_EFFORT_NOTIFY_TIMEOUT_MS)
736
745
  });
@@ -996,7 +1005,10 @@ import { readFileSync } from "fs";
996
1005
  import { homedir } from "os";
997
1006
  import { join } from "path";
998
1007
  var CLAUDE_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
1008
+ var CLAUDE_PROFILE_URL = "https://api.anthropic.com/api/oauth/profile";
1009
+ var CLAUDE_PROFILE_TIMEOUT_MS = 2e3;
999
1010
  var KEYCHAIN_SERVICE = "Claude Code-credentials";
1011
+ var cachedOwner = null;
1000
1012
  var CLAUDE_CREDENTIALS_SEGMENTS = [".claude", ".credentials.json"];
1001
1013
  function parseClaudeCliCredentials(raw) {
1002
1014
  let parsed;
@@ -1070,6 +1082,47 @@ function toWindow(value) {
1070
1082
  }
1071
1083
  return { utilization: window.utilization, resetsAt };
1072
1084
  }
1085
+ function ownerLookupFailure(error2) {
1086
+ const name = error2?.name;
1087
+ return name === "TimeoutError" || name === "AbortError" ? "timed out" : "request failed";
1088
+ }
1089
+ async function getClaudeUsageOwner(accessToken) {
1090
+ if (cachedOwner?.accessToken === accessToken) {
1091
+ return { owner: cachedOwner.owner, ownerLookupError: null };
1092
+ }
1093
+ try {
1094
+ const response = await fetch(CLAUDE_PROFILE_URL, {
1095
+ headers: {
1096
+ Authorization: `Bearer ${accessToken}`,
1097
+ "Content-Type": "application/json",
1098
+ "anthropic-version": "2023-06-01"
1099
+ },
1100
+ signal: AbortSignal.timeout(CLAUDE_PROFILE_TIMEOUT_MS)
1101
+ });
1102
+ if (!response.ok) {
1103
+ return { owner: null, ownerLookupError: `HTTP ${response.status}` };
1104
+ }
1105
+ let body;
1106
+ try {
1107
+ body = await response.json();
1108
+ } catch (error2) {
1109
+ return { owner: null, ownerLookupError: "malformed response" };
1110
+ }
1111
+ const profile = body;
1112
+ if (typeof profile.account?.email !== "string" || !profile.account.email.trim()) {
1113
+ return { owner: null, ownerLookupError: "malformed response" };
1114
+ }
1115
+ const owner = {
1116
+ email: profile.account.email,
1117
+ organizationName: typeof profile.organization?.name === "string" && profile.organization.name.trim() ? profile.organization.name.trim() : null,
1118
+ rateLimitTier: typeof profile.organization?.rate_limit_tier === "string" && profile.organization.rate_limit_tier.trim() ? profile.organization.rate_limit_tier.trim() : null
1119
+ };
1120
+ cachedOwner = { accessToken, owner };
1121
+ return { owner, ownerLookupError: null };
1122
+ } catch (error2) {
1123
+ return { owner: null, ownerLookupError: ownerLookupFailure(error2) };
1124
+ }
1125
+ }
1073
1126
  async function getClaudeUsage() {
1074
1127
  const credentials2 = readClaudeCliCredentials();
1075
1128
  if (!credentials2) {
@@ -1089,15 +1142,19 @@ async function getClaudeUsage() {
1089
1142
  Authorization: `Bearer ${credentials2.accessToken}`,
1090
1143
  "Content-Type": "application/json",
1091
1144
  "anthropic-version": "2023-06-01"
1092
- }
1145
+ },
1146
+ signal: AbortSignal.timeout(CLAUDE_PROFILE_TIMEOUT_MS)
1093
1147
  });
1094
1148
  if (!res.ok) {
1095
1149
  throw new ClaudeUsageError(`Claude usage request failed: HTTP ${res.status}`, "request_failed");
1096
1150
  }
1097
1151
  const body = await res.json();
1152
+ const { owner, ownerLookupError } = await getClaudeUsageOwner(credentials2.accessToken);
1098
1153
  return {
1099
1154
  fiveHour: toWindow(body.five_hour),
1100
- sevenDay: toWindow(body.seven_day)
1155
+ sevenDay: toWindow(body.seven_day),
1156
+ owner,
1157
+ ownerLookupError
1101
1158
  };
1102
1159
  }
1103
1160
 
@@ -2394,7 +2451,7 @@ function isPreamblePinnedRunning(messages, userMessageId) {
2394
2451
  return completedOf(reply) != null && finishOf(reply) === "tool-calls";
2395
2452
  }
2396
2453
  function isB2AbandonmentConfirmed(params) {
2397
- return params.pinnedForMs >= params.minPinnedMs && params.descendantOngoing === false;
2454
+ return params.pinnedForMs >= params.minPinnedMs && params.descendantOngoing === false && params.rootOngoing === false;
2398
2455
  }
2399
2456
  function isAmbiguousTerminalFinish(m) {
2400
2457
  if (completedOf(m) == null) return false;
@@ -2407,7 +2464,7 @@ function isAmbiguousFinishPinnedRunning(messages, userMessageId) {
2407
2464
  return isAmbiguousTerminalFinish(reply);
2408
2465
  }
2409
2466
  function isAmbiguousFinishResolved(params) {
2410
- return params.sessionOngoing === false || params.pinnedForMs >= params.maxPinnedMs;
2467
+ return params.sessionOngoing === false || params.sessionOngoing !== true && params.pinnedForMs >= params.maxPinnedMs;
2411
2468
  }
2412
2469
  function messageError(messages, userMessageId) {
2413
2470
  const reply = findLastAssistantReplyFor(messages, userMessageId);
@@ -5683,6 +5740,7 @@ var ChannelDriver = class _ChannelDriver {
5683
5740
  deliveryDeadlineAnchored: false,
5684
5741
  b2PinnedSinceMs: 0,
5685
5742
  b2LastDescendantCheckMs: 0,
5743
+ b2RootOngoingHeldLogged: false,
5686
5744
  b2AbandonedSignalled: false,
5687
5745
  ambiguousPinnedSinceMs: 0,
5688
5746
  ambiguousResolved: false
@@ -5777,6 +5835,7 @@ var ChannelDriver = class _ChannelDriver {
5777
5835
  deliveryDeadlineAnchored: false,
5778
5836
  b2PinnedSinceMs: 0,
5779
5837
  b2LastDescendantCheckMs: 0,
5838
+ b2RootOngoingHeldLogged: false,
5780
5839
  b2AbandonedSignalled: false,
5781
5840
  ambiguousPinnedSinceMs: 0,
5782
5841
  ambiguousResolved: false
@@ -6130,6 +6189,7 @@ var ChannelDriver = class _ChannelDriver {
6130
6189
  if (snapshotReadable) {
6131
6190
  inFlight.b2PinnedSinceMs = 0;
6132
6191
  inFlight.b2LastDescendantCheckMs = 0;
6192
+ inFlight.b2RootOngoingHeldLogged = false;
6133
6193
  inFlight.b2AbandonedSignalled = false;
6134
6194
  }
6135
6195
  } else {
@@ -6141,11 +6201,15 @@ var ChannelDriver = class _ChannelDriver {
6141
6201
  const pinnedForMs = this.now() - inFlight.b2PinnedSinceMs;
6142
6202
  if (pinnedForMs >= B2_ABANDONMENT_MIN_PINNED_MS && this.now() - inFlight.b2LastDescendantCheckMs >= B2_ABANDONMENT_RECHECK_MS) {
6143
6203
  inFlight.b2LastDescendantCheckMs = this.now();
6144
- const descendantOngoing = await this.isAnyDescendantSessionOngoing(sessionId);
6204
+ const [descendantOngoing, rootOngoing] = await Promise.all([
6205
+ this.isAnyDescendantSessionOngoing(sessionId),
6206
+ isSessionOngoing(this.port, sessionId)
6207
+ ]);
6145
6208
  if (isB2AbandonmentConfirmed({
6146
6209
  pinnedForMs,
6147
6210
  minPinnedMs: B2_ABANDONMENT_MIN_PINNED_MS,
6148
- descendantOngoing
6211
+ descendantOngoing,
6212
+ rootOngoing
6149
6213
  })) {
6150
6214
  inFlight.b2AbandonedSignalled = true;
6151
6215
  this.log({
@@ -6154,12 +6218,26 @@ var ChannelDriver = class _ChannelDriver {
6154
6218
  conversation_id: conv.id,
6155
6219
  message_id: id
6156
6220
  });
6221
+ const reply = findLastAssistantReplyFor(messages, inFlight.opencodeMessageId);
6157
6222
  void this.postSignal(conv.id, id, "b2_abandoned_resolved", {
6158
- watched_for_ms: pinnedForMs
6223
+ watched_for_ms: pinnedForMs,
6224
+ finish: reply?.info?.finish ?? reply?.finish,
6225
+ ...rootOngoing != null ? { root_ongoing: rootOngoing } : {},
6226
+ ...descendantOngoing != null ? { descendant_ongoing: descendantOngoing } : {},
6227
+ opencode_message_id: inFlight.opencodeMessageId
6159
6228
  });
6160
6229
  await this.settleMessageDone(sessionId, watcher, inFlight, messages);
6161
6230
  return;
6162
6231
  }
6232
+ if (rootOngoing === true && !inFlight.b2RootOngoingHeldLogged) {
6233
+ inFlight.b2RootOngoingHeldLogged = true;
6234
+ this.log({
6235
+ level: "warn",
6236
+ message: `Message ${id.slice(0, 8)} b2-pinned for ${Math.round(pinnedForMs / 1e3)}s with root_ongoing=${rootOngoing} and descendant_ongoing=${descendantOngoing} \u2014 holding until OpenCode confirms the root is idle`,
6237
+ conversation_id: conv.id,
6238
+ message_id: id
6239
+ });
6240
+ }
6163
6241
  }
6164
6242
  }
6165
6243
  const ambiguousPinnedNow = activelyRunning && isAmbiguousFinishPinnedRunning(messages, inFlight.opencodeMessageId);
@@ -8507,7 +8585,17 @@ function scheduleClaudeUsageReporting(state, options) {
8507
8585
  setTimer: (timer) => {
8508
8586
  state.claudeUsageTimer = timer;
8509
8587
  },
8510
- fetchUsage: getClaudeUsage,
8588
+ fetchUsage: async () => {
8589
+ const usage = await getClaudeUsage();
8590
+ if (usage.ownerLookupError) {
8591
+ logActivity(state, {
8592
+ type: "info",
8593
+ level: "debug",
8594
+ message: `Claude usage owner lookup failed: ${usage.ownerLookupError}`
8595
+ });
8596
+ }
8597
+ return usage;
8598
+ },
8511
8599
  report: (usage) => reportClaudeUsage(state.agentId, state.authHeader, usage),
8512
8600
  isLocalCredentialProblem,
8513
8601
  forcedOnHint: "run `claude` to sign in",