@vtxmacro/cli 2026.9.52 → 2026.9.53

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.
@@ -16,7 +16,7 @@ import { fileURLToPath } from "node:url";
16
16
  // agent-cli-release.json
17
17
  var agent_cli_release_default = {
18
18
  package_name: "@vtxmacro/cli",
19
- package_version: "2026.9.52",
19
+ package_version: "2026.9.53",
20
20
  codex_package_name: "@openai/codex",
21
21
  codex_version: "0.153.3",
22
22
  copilot_sdk_package_name: "@github/copilot-sdk",
@@ -200,6 +200,14 @@ var runtime_policy_generated_default = {
200
200
  host_liveness_heartbeat_interval_ms: 3e4,
201
201
  host_liveness_recovery_nudge_ttl_ms: 1e4
202
202
  }
203
+ },
204
+ server_runtime: {
205
+ prompt_rescue: {
206
+ client_long_poll_seconds: 20,
207
+ client_claim_http_timeout_milliseconds: 25e3,
208
+ client_presence_heartbeat_interval_milliseconds: 3e4,
209
+ client_presence_http_timeout_milliseconds: 5e3
210
+ }
203
211
  }
204
212
  }
205
213
  },
@@ -244,7 +252,7 @@ var runtime_policy_generated_default = {
244
252
  exchange: {
245
253
  hyperliquid: {
246
254
  client_public_read_budget: {
247
- max_weight: 900,
255
+ max_weight: 1200,
248
256
  window_seconds: 60,
249
257
  cooldown_seconds: 60,
250
258
  metadata_ttl_seconds: 300,
@@ -255,6 +263,7 @@ var runtime_policy_generated_default = {
255
263
  },
256
264
  read_budget: {
257
265
  weights: {
266
+ exchange: 1,
258
267
  exchangeStatus: 2,
259
268
  clearinghouseState: 2,
260
269
  spotClearinghouseState: 2,
@@ -285,7 +294,8 @@ var runtime_policy_generated_default = {
285
294
  authorizedAgents: 20,
286
295
  agents: 20,
287
296
  apiWallets: 20
288
- }
297
+ },
298
+ exchange_action_batch_size: 40
289
299
  }
290
300
  }
291
301
  }
@@ -83,6 +83,14 @@ var runtime_policy_generated_default = {
83
83
  host_liveness_heartbeat_interval_ms: 3e4,
84
84
  host_liveness_recovery_nudge_ttl_ms: 1e4
85
85
  }
86
+ },
87
+ server_runtime: {
88
+ prompt_rescue: {
89
+ client_long_poll_seconds: 20,
90
+ client_claim_http_timeout_milliseconds: 25e3,
91
+ client_presence_heartbeat_interval_milliseconds: 3e4,
92
+ client_presence_http_timeout_milliseconds: 5e3
93
+ }
86
94
  }
87
95
  }
88
96
  },
@@ -127,7 +135,7 @@ var runtime_policy_generated_default = {
127
135
  exchange: {
128
136
  hyperliquid: {
129
137
  client_public_read_budget: {
130
- max_weight: 900,
138
+ max_weight: 1200,
131
139
  window_seconds: 60,
132
140
  cooldown_seconds: 60,
133
141
  metadata_ttl_seconds: 300,
@@ -138,6 +146,7 @@ var runtime_policy_generated_default = {
138
146
  },
139
147
  read_budget: {
140
148
  weights: {
149
+ exchange: 1,
141
150
  exchangeStatus: 2,
142
151
  clearinghouseState: 2,
143
152
  spotClearinghouseState: 2,
@@ -168,7 +177,8 @@ var runtime_policy_generated_default = {
168
177
  authorizedAgents: 20,
169
178
  agents: 20,
170
179
  apiWallets: 20
171
- }
180
+ },
181
+ exchange_action_batch_size: 40
172
182
  }
173
183
  }
174
184
  }
package/bin/vtx.js CHANGED
@@ -77,7 +77,7 @@ var init_agent_cli_release = __esm({
77
77
  "agent-cli-release.json"() {
78
78
  agent_cli_release_default = {
79
79
  package_name: "@vtxmacro/cli",
80
- package_version: "2026.9.52",
80
+ package_version: "2026.9.53",
81
81
  codex_package_name: "@openai/codex",
82
82
  codex_version: "0.153.3",
83
83
  copilot_sdk_package_name: "@github/copilot-sdk",
@@ -20541,6 +20541,14 @@ var init_runtime_policy_generated = __esm({
20541
20541
  host_liveness_heartbeat_interval_ms: 3e4,
20542
20542
  host_liveness_recovery_nudge_ttl_ms: 1e4
20543
20543
  }
20544
+ },
20545
+ server_runtime: {
20546
+ prompt_rescue: {
20547
+ client_long_poll_seconds: 20,
20548
+ client_claim_http_timeout_milliseconds: 25e3,
20549
+ client_presence_heartbeat_interval_milliseconds: 3e4,
20550
+ client_presence_http_timeout_milliseconds: 5e3
20551
+ }
20544
20552
  }
20545
20553
  }
20546
20554
  },
@@ -20585,7 +20593,7 @@ var init_runtime_policy_generated = __esm({
20585
20593
  exchange: {
20586
20594
  hyperliquid: {
20587
20595
  client_public_read_budget: {
20588
- max_weight: 900,
20596
+ max_weight: 1200,
20589
20597
  window_seconds: 60,
20590
20598
  cooldown_seconds: 60,
20591
20599
  metadata_ttl_seconds: 300,
@@ -20596,6 +20604,7 @@ var init_runtime_policy_generated = __esm({
20596
20604
  },
20597
20605
  read_budget: {
20598
20606
  weights: {
20607
+ exchange: 1,
20599
20608
  exchangeStatus: 2,
20600
20609
  clearinghouseState: 2,
20601
20610
  spotClearinghouseState: 2,
@@ -20626,7 +20635,8 @@ var init_runtime_policy_generated = __esm({
20626
20635
  authorizedAgents: 20,
20627
20636
  agents: 20,
20628
20637
  apiWallets: 20
20629
- }
20638
+ },
20639
+ exchange_action_batch_size: 40
20630
20640
  }
20631
20641
  }
20632
20642
  }
@@ -42519,6 +42529,14 @@ var init_runtime_policy_generated2 = __esm({
42519
42529
  host_liveness_heartbeat_interval_ms: 3e4,
42520
42530
  host_liveness_recovery_nudge_ttl_ms: 1e4
42521
42531
  }
42532
+ },
42533
+ server_runtime: {
42534
+ prompt_rescue: {
42535
+ client_long_poll_seconds: 20,
42536
+ client_claim_http_timeout_milliseconds: 25e3,
42537
+ client_presence_heartbeat_interval_milliseconds: 3e4,
42538
+ client_presence_http_timeout_milliseconds: 5e3
42539
+ }
42522
42540
  }
42523
42541
  }
42524
42542
  },
@@ -42563,7 +42581,7 @@ var init_runtime_policy_generated2 = __esm({
42563
42581
  exchange: {
42564
42582
  hyperliquid: {
42565
42583
  client_public_read_budget: {
42566
- max_weight: 900,
42584
+ max_weight: 1200,
42567
42585
  window_seconds: 60,
42568
42586
  cooldown_seconds: 60,
42569
42587
  metadata_ttl_seconds: 300,
@@ -42574,6 +42592,7 @@ var init_runtime_policy_generated2 = __esm({
42574
42592
  },
42575
42593
  read_budget: {
42576
42594
  weights: {
42595
+ exchange: 1,
42577
42596
  exchangeStatus: 2,
42578
42597
  clearinghouseState: 2,
42579
42598
  spotClearinghouseState: 2,
@@ -42604,7 +42623,8 @@ var init_runtime_policy_generated2 = __esm({
42604
42623
  authorizedAgents: 20,
42605
42624
  agents: 20,
42606
42625
  apiWallets: 20
42607
- }
42626
+ },
42627
+ exchange_action_batch_size: 40
42608
42628
  }
42609
42629
  }
42610
42630
  }
@@ -48546,7 +48566,7 @@ var init_runtime_redaction = __esm({
48546
48566
  });
48547
48567
 
48548
48568
  // lib/runtime/hyperliquid-public-read.ts
48549
- var policy, weights, budgets, unpersistedBudgets, cache, pending2, PREFIX, abortError2, checkAbort, wait, storage, loadBudget, saveBudget, withBudgetLock, admit, cooldown, reserveHyperliquidPublicReads, readHyperliquidPublicInfo;
48569
+ var policy, weights, budgets, unpersistedBudgets, cache, pending2, PREFIX, abortError2, checkAbort, wait, storage, loadBudget, saveBudget, withBudgetLock, HyperliquidPublicReadError, cooldownError, admit, cooldown, cacheTtlMs, eligibleCache, reserveHyperliquidPublicReads, releaseHyperliquidPublicReadReservation, admitHyperliquidExchangeRequest, recordHyperliquidExchangeResponse, readHyperliquidPublicInfo;
48550
48570
  var init_hyperliquid_public_read = __esm({
48551
48571
  "lib/runtime/hyperliquid-public-read.ts"() {
48552
48572
  "use strict";
@@ -48618,31 +48638,54 @@ var init_hyperliquid_public_read = __esm({
48618
48638
  }
48619
48639
  return work();
48620
48640
  };
48621
- admit = async (apiUrl, requestType, signal, bundleWeight, bundleId) => {
48641
+ HyperliquidPublicReadError = class extends Error {
48642
+ constructor(code, message, requestType, status, retryAfterMs, requiredWeight, usedWeight, maxWeight) {
48643
+ super(message);
48644
+ this.code = code;
48645
+ this.requestType = requestType;
48646
+ this.status = status;
48647
+ this.retryAfterMs = retryAfterMs;
48648
+ this.requiredWeight = requiredWeight;
48649
+ this.usedWeight = usedWeight;
48650
+ this.maxWeight = maxWeight;
48651
+ this.name = "HyperliquidPublicReadError";
48652
+ }
48653
+ };
48654
+ cooldownError = (requestType, until) => new HyperliquidPublicReadError(
48655
+ "public_cooldown_active",
48656
+ "Hyperliquid public request cooldown is active.",
48657
+ requestType,
48658
+ void 0,
48659
+ Math.max(0, until - Date.now())
48660
+ );
48661
+ admit = async (apiUrl, requestType, signal, bundleWeight, bundleId, deadlineMs) => {
48622
48662
  const key = `${PREFIX}${apiUrl}`;
48623
48663
  const weight = bundleWeight ?? weights[requestType] ?? policy.default_request_weight;
48624
- if (!(weight > 0 && weight <= policy.max_weight)) throw new Error("Invalid Hyperliquid public read weight.");
48664
+ if (!(weight > 0 && weight <= policy.max_weight)) throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid public request exceeds the available allowance.", requestType, void 0, void 0, weight, void 0, policy.max_weight);
48625
48665
  for (; ; ) {
48626
48666
  checkAbort(signal);
48627
- const delay2 = await withBudgetLock(key, signal, () => {
48667
+ const { delay: delay2, usedWeight } = await withBudgetLock(key, signal, () => {
48628
48668
  const now = Date.now();
48629
48669
  const budget = loadBudget(key);
48630
48670
  budget.reservations = budget.reservations.filter((r) => r.at > now - policy.window_seconds * 1e3);
48631
- if (budget.cooldownUntil > now) throw Object.assign(new Error("Hyperliquid public read rate-limit cooldown."), { status: 429, requestType });
48671
+ if (budget.cooldownUntil > now) throw cooldownError(requestType, budget.cooldownUntil);
48632
48672
  let used = budget.reservations.reduce((sum, r) => sum + r.weight, 0);
48673
+ const usedWeight2 = used;
48633
48674
  if (used + weight <= policy.max_weight) {
48634
48675
  budget.reservations.push({ at: now, weight, ...bundleId ? { id: bundleId } : {} });
48635
48676
  saveBudget(key, budget);
48636
- return 0;
48677
+ return { delay: 0, usedWeight: usedWeight2 };
48637
48678
  }
48638
48679
  for (const reservation of budget.reservations) {
48639
48680
  used -= reservation.weight;
48640
- if (used + weight <= policy.max_weight) return Math.max(1, reservation.at + policy.window_seconds * 1e3 - now);
48681
+ if (used + weight <= policy.max_weight) return { delay: Math.max(1, reservation.at + policy.window_seconds * 1e3 - now), usedWeight: usedWeight2 };
48641
48682
  }
48642
48683
  throw new Error("Invalid Hyperliquid public read budget.");
48643
48684
  });
48644
48685
  if (!delay2) return;
48645
- if (bundleWeight != null) throw Object.assign(new Error("Hyperliquid public read bundle budget exhausted."), { code: "public_budget_exhausted" });
48686
+ if (bundleWeight != null || deadlineMs != null && Date.now() + delay2 >= deadlineMs) {
48687
+ throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid local public request allowance is exhausted.", requestType, void 0, delay2, weight, usedWeight, policy.max_weight);
48688
+ }
48646
48689
  await wait(delay2, signal);
48647
48690
  }
48648
48691
  };
@@ -48657,29 +48700,70 @@ var init_hyperliquid_public_read = __esm({
48657
48700
  saveBudget(key, budget);
48658
48701
  });
48659
48702
  };
48660
- reserveHyperliquidPublicReads = async (endpoint, bodies, signal) => {
48703
+ cacheTtlMs = (body, options) => {
48704
+ const requestType = String(body.type);
48705
+ return (["meta", "spotMeta", "perpDexs"].includes(requestType) ? policy.metadata_ttl_seconds : requestType === "userFees" ? policy.user_fees_ttl_seconds : options.cacheAccountMode && ["userAbstraction", "userDexAbstraction"].includes(requestType) ? policy.account_mode_ttl_seconds : 0) * 1e3;
48706
+ };
48707
+ eligibleCache = (apiUrl, body, options) => {
48708
+ const ttl = cacheTtlMs(body, options);
48709
+ const existing = cache.get(`${apiUrl}:${JSON.stringify(body)}`);
48710
+ const horizon = Math.max(Date.now(), options.cacheValidUntilMs ?? Date.now());
48711
+ return ttl > 0 && existing && Date.now() >= existing.fetchedAtMs && horizon - existing.fetchedAtMs < ttl ? existing : void 0;
48712
+ };
48713
+ reserveHyperliquidPublicReads = async (endpoint, bodies, signal, options = {}) => {
48661
48714
  const apiUrl = endpoint.replace(/\/$/, "");
48662
- const weight = bodies.reduce((sum, body) => sum + (weights[String(body.type)] ?? policy.default_request_weight), 0);
48663
- const id2 = crypto.randomUUID();
48664
- const admittedAtMs = Date.now();
48665
- await admit(apiUrl, "bundle", signal, weight, id2);
48715
+ const cached2 = /* @__PURE__ */ new Map();
48666
48716
  const remaining = /* @__PURE__ */ new Map();
48717
+ let weight = 0;
48667
48718
  for (const body of bodies) {
48668
48719
  const key = JSON.stringify(body);
48720
+ const hit = eligibleCache(apiUrl, body, options);
48721
+ if (hit) {
48722
+ cached2.set(key, hit);
48723
+ continue;
48724
+ }
48669
48725
  remaining.set(key, (remaining.get(key) ?? 0) + 1);
48726
+ weight += weights[String(body.type)] ?? policy.default_request_weight;
48670
48727
  }
48671
- return { id: id2, endpoint: apiUrl, expiresAtMs: admittedAtMs + policy.window_seconds * 1e3, remaining };
48728
+ const id2 = crypto.randomUUID();
48729
+ const admittedAtMs = Date.now();
48730
+ if (weight) await admit(apiUrl, "bundle", signal, weight, id2, options.cacheValidUntilMs);
48731
+ return { id: id2, closed: false, endpoint: apiUrl, expiresAtMs: admittedAtMs + policy.window_seconds * 1e3, remaining, cached: cached2, cacheValidUntilMs: options.cacheValidUntilMs };
48732
+ };
48733
+ releaseHyperliquidPublicReadReservation = async (reservation) => {
48734
+ reservation.closed = true;
48735
+ const key = `${PREFIX}${reservation.endpoint}`;
48736
+ await withBudgetLock(key, void 0, () => {
48737
+ const budget = loadBudget(key);
48738
+ const row = budget.reservations.find((entry) => entry.id === reservation.id);
48739
+ if (row) {
48740
+ const unused = [...reservation.remaining].reduce((sum, [body, count4]) => sum + (weights[String(JSON.parse(body).type)] ?? policy.default_request_weight) * count4, 0);
48741
+ row.weight = Math.max(0, row.weight - unused);
48742
+ budget.reservations = budget.reservations.filter((entry) => entry.weight > 0);
48743
+ saveBudget(key, budget);
48744
+ }
48745
+ reservation.remaining.clear();
48746
+ });
48747
+ };
48748
+ admitHyperliquidExchangeRequest = async (endpoint, action, signal) => {
48749
+ const batchLength = Math.max(0, ...[action.orders, action.cancels, action.modifies].filter(Array.isArray).map((value) => value.length));
48750
+ const weight = weights.exchange + Math.floor(batchLength / runtime_policy_generated_default.exchange.hyperliquid.read_budget.exchange_action_batch_size);
48751
+ await admit(endpoint.replace(/\/$/, ""), "exchange", signal, weight);
48752
+ };
48753
+ recordHyperliquidExchangeResponse = async (endpoint, response) => {
48754
+ if (response.status === 429) await cooldown(endpoint.replace(/\/$/, ""), response.headers.get("Retry-After"));
48672
48755
  };
48673
48756
  readHyperliquidPublicInfo = async (endpoint, body, options = {}) => {
48674
48757
  const apiUrl = endpoint.replace(/\/$/, "");
48675
48758
  const requestType = String(body.type ?? "info");
48676
- const ttlSeconds = ["meta", "spotMeta", "perpDexs"].includes(requestType) ? policy.metadata_ttl_seconds : requestType === "userFees" ? policy.user_fees_ttl_seconds : options.cacheAccountMode && ["userAbstraction", "userDexAbstraction"].includes(requestType) ? policy.account_mode_ttl_seconds : 0;
48759
+ const cacheOptions = { ...options, cacheValidUntilMs: options.reservation?.cacheValidUntilMs ?? options.cacheValidUntilMs };
48760
+ const ttlMs = cacheTtlMs(body, cacheOptions);
48677
48761
  const key = `${apiUrl}:${JSON.stringify(body)}`;
48678
48762
  checkAbort(options.signal);
48679
- if (ttlSeconds) {
48763
+ if (ttlMs) {
48680
48764
  for (; ; ) {
48681
- const existing = cache.get(key);
48682
- if (existing && Date.now() - existing.fetchedAtMs >= 0 && Date.now() - existing.fetchedAtMs < ttlSeconds * 500) return existing;
48765
+ const existing = options.reservation?.cached.get(JSON.stringify(body)) ?? eligibleCache(apiUrl, body, cacheOptions);
48766
+ if (existing) return existing;
48683
48767
  const running = pending2.get(key);
48684
48768
  if (!running) break;
48685
48769
  await new Promise((resolve13, reject) => {
@@ -48697,26 +48781,31 @@ var init_hyperliquid_public_read = __esm({
48697
48781
  }
48698
48782
  }
48699
48783
  let settled;
48700
- if (ttlSeconds) pending2.set(key, new Promise((resolve13) => {
48784
+ if (ttlMs) pending2.set(key, new Promise((resolve13) => {
48701
48785
  settled = resolve13;
48702
48786
  }));
48703
48787
  try {
48704
48788
  const reservedKey = JSON.stringify(body);
48705
48789
  const remaining = options.reservation?.remaining.get(reservedKey) ?? 0;
48706
48790
  if (options.reservation?.endpoint === apiUrl && remaining > 0) {
48707
- if (Date.now() >= options.reservation.expiresAtMs) throw Object.assign(new Error("Hyperliquid public read reservation expired."), { code: "public_budget_exhausted" });
48791
+ if (Date.now() >= options.reservation.expiresAtMs) throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid public read reservation expired.", requestType);
48708
48792
  await withBudgetLock(`${PREFIX}${apiUrl}`, options.signal, () => {
48793
+ if (options.reservation.closed) throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid public read bundle is closed.", requestType);
48794
+ if ((options.reservation.remaining.get(reservedKey) ?? 0) <= 0) throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid request is outside its admitted bundle.", requestType);
48709
48795
  const budget = loadBudget(`${PREFIX}${apiUrl}`);
48710
48796
  const row = budget.reservations.find((entry) => entry.id === options.reservation.id);
48711
- if (!row || Date.now() >= options.reservation.expiresAtMs) throw Object.assign(new Error("Hyperliquid public read reservation expired."), { code: "public_budget_exhausted" });
48797
+ if (!row || Date.now() >= options.reservation.expiresAtMs) throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid public read reservation expired.", requestType);
48712
48798
  row.at = Date.now();
48713
48799
  budget.reservations.sort((a, b2) => a.at - b2.at);
48800
+ options.reservation.remaining.set(reservedKey, (options.reservation.remaining.get(reservedKey) ?? 0) - 1);
48714
48801
  saveBudget(`${PREFIX}${apiUrl}`, budget);
48715
48802
  });
48716
- options.reservation.remaining.set(reservedKey, remaining - 1);
48717
- } else await admit(apiUrl, requestType, options.signal);
48803
+ } else if (options.reservation) throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid request is outside its admitted bundle.", requestType);
48804
+ else await admit(apiUrl, requestType, options.signal, void 0, void 0, options.deadlineMs);
48718
48805
  checkAbort(options.signal);
48719
- if (loadBudget(`${PREFIX}${apiUrl}`).cooldownUntil > Date.now()) throw Object.assign(new Error("Hyperliquid public read rate-limit cooldown."), { status: 429, requestType });
48806
+ if (options.reservation?.closed) throw new HyperliquidPublicReadError("public_budget_exhausted", "Hyperliquid public read bundle is closed.", requestType);
48807
+ const cooldownUntil = loadBudget(`${PREFIX}${apiUrl}`).cooldownUntil;
48808
+ if (cooldownUntil > Date.now()) throw cooldownError(requestType, cooldownUntil);
48720
48809
  const response = await fetch(`${apiUrl}/info`, {
48721
48810
  method: "POST",
48722
48811
  headers: { "Content-Type": "application/json" },
@@ -48724,22 +48813,31 @@ var init_hyperliquid_public_read = __esm({
48724
48813
  signal: options.signal
48725
48814
  });
48726
48815
  if (response.status === 429) await cooldown(apiUrl, response.headers.get("Retry-After"));
48727
- const payload = await response.json().catch(() => ({}));
48816
+ const payload = await response.json().catch((error48) => {
48817
+ if (error48 instanceof SyntaxError) return {};
48818
+ throw error48;
48819
+ });
48728
48820
  if (!response.ok) {
48729
48821
  const detail = sanitizeRuntimeDiagnosticValue(typeof payload?.response === "string" ? payload.response : typeof payload?.detail === "string" ? payload.detail : "");
48822
+ if (response.status === 429) throw new HyperliquidPublicReadError("public_rate_limited", "Hyperliquid public API returned HTTP 429.", requestType, 429);
48730
48823
  throw Object.assign(new Error(`Hyperliquid info request failed (${response.status}) request_type=${requestType}.${detail ? ` ${detail}` : ""}`), {
48731
48824
  status: response.status,
48732
48825
  requestType
48733
48826
  });
48734
48827
  }
48735
48828
  const result2 = { payload, fetchedAtMs: Date.now() };
48736
- if (ttlSeconds) {
48829
+ if (ttlMs) {
48737
48830
  cache.set(key, result2);
48738
48831
  while (cache.size > policy.cache_max_entries) cache.delete(cache.keys().next().value);
48739
48832
  }
48740
48833
  return result2;
48834
+ } catch (error48) {
48835
+ if (options.signal?.aborted || error48 instanceof HyperliquidPublicReadError) throw error48;
48836
+ if (error48 instanceof TypeError) throw new HyperliquidPublicReadError("public_network_error", "Hyperliquid public request network failure.", requestType);
48837
+ if (error48 instanceof Error && (error48.name === "TimeoutError" || error48.name === "AbortError")) throw new HyperliquidPublicReadError("public_timeout", "Hyperliquid public request timed out.", requestType);
48838
+ throw error48;
48741
48839
  } finally {
48742
- if (ttlSeconds) {
48840
+ if (ttlMs) {
48743
48841
  pending2.delete(key);
48744
48842
  settled?.();
48745
48843
  }
@@ -50736,273 +50834,283 @@ var init_hyperliquid_account_state_adapter = __esm({
50736
50834
  dexNames,
50737
50835
  staleIf429MaxAgeMs
50738
50836
  }) => {
50739
- const userFeesPromise = input.includeEffectiveTakerRate === true ? (async () => ({
50740
- ...await readHyperliquidPublicInfo(apiUrl, { type: "userFees", user: walletAddress }, { signal: input.signal }).catch((error48) => {
50741
- if (input.signal?.aborted) throw error48;
50742
- return { payload: null, fetchedAtMs: Date.now() };
50743
- }).then((result2) => ({ payload: result2.payload, capturedAt: new Date(result2.fetchedAtMs).toISOString() }))
50744
- }))() : Promise.resolve(null);
50745
- const exactAccountModePromise = input.includeExactAccountMode === true ? (async () => {
50746
- const abstractionRead = await readHyperliquidPublicInfo(apiUrl, { type: "userAbstraction", user: walletAddress }, { signal: input.signal, cacheAccountMode: true });
50747
- const userAbstraction = abstractionRead.payload;
50748
- let capturedAtMs = abstractionRead.fetchedAtMs;
50749
- const preliminaryMode = extractCanonicalHyperliquidAccountMode(userAbstraction);
50750
- if (!preliminaryMode) {
50751
- throw new Error("Exact Hyperliquid userAbstraction response is invalid.");
50752
- }
50753
- let userDexAbstraction;
50754
- if (preliminaryMode === "default" || preliminaryMode === "disabled") {
50755
- const dexRead = await readHyperliquidPublicInfo(apiUrl, { type: "userDexAbstraction", user: walletAddress }, { signal: input.signal, cacheAccountMode: true });
50756
- userDexAbstraction = dexRead.payload;
50757
- capturedAtMs = Math.min(capturedAtMs, dexRead.fetchedAtMs);
50758
- }
50759
- return {
50760
- accountMode: resolveExactHyperliquidAccountMode(
50761
- userAbstraction,
50762
- userDexAbstraction
50763
- ),
50764
- capturedAt: new Date(capturedAtMs).toISOString()
50765
- };
50766
- })() : Promise.resolve(null);
50767
- await Promise.all([userFeesPromise, exactAccountModePromise]);
50768
- const metadataByDex = /* @__PURE__ */ new Map();
50769
- if (input.includeEffectiveTakerRate === true) {
50770
- await Promise.all(["", ...dexNames].map(async (dex) => {
50771
- try {
50772
- metadataByDex.set(dex, await fetchHyperliquidInfoPayload(apiUrl, { type: "meta", ...dex ? { dex } : {} }, input.signal));
50773
- } catch (error48) {
50774
- if (input.signal?.aborted) throw error48;
50775
- metadataByDex.set(dex, null);
50776
- }
50777
- }));
50778
- }
50837
+ const metadataBodies = input.includeEffectiveTakerRate === true ? ["", ...dexNames].map((dex) => ({ type: "meta", ...dex ? { dex } : {} })) : [];
50779
50838
  const reservation = await reserveHyperliquidPublicReads(apiUrl, [
50780
50839
  { type: "clearinghouseState", user: walletAddress },
50781
50840
  ...dexNames.map((dex) => ({ type: "clearinghouseState", user: walletAddress, dex })),
50782
50841
  { type: "spotClearinghouseState", user: walletAddress },
50783
- ...input.includeActiveAssetData === false ? [] : activeAssetRequestTypes.map((type) => ({ type, user: walletAddress, coin: symbol2 }))
50784
- ], input.signal);
50785
- const perpsPromise = (async () => {
50786
- const defaultResponse = await fetchHyperliquidInfoPayload(
50787
- apiUrl,
50788
- { type: "clearinghouseState", user: walletAddress },
50789
- input.signal,
50790
- reservation
50791
- );
50842
+ ...input.includeActiveAssetData === false ? [] : activeAssetRequestTypes.map((type) => ({ type, user: walletAddress, coin: symbol2 })),
50843
+ ...input.includeEffectiveTakerRate === true ? [{ type: "userFees", user: walletAddress }, ...metadataBodies] : [],
50844
+ ...input.includeExactAccountMode === true ? [
50845
+ { type: "userAbstraction", user: walletAddress },
50846
+ { type: "userDexAbstraction", user: walletAddress }
50847
+ ] : []
50848
+ ], input.signal, { cacheAccountMode: true, cacheValidUntilMs: input.publicReadDeadlineMs });
50849
+ try {
50850
+ const userFeesPromise = input.includeEffectiveTakerRate === true ? (async () => ({
50851
+ ...await readHyperliquidPublicInfo(apiUrl, { type: "userFees", user: walletAddress }, { signal: input.signal, reservation }).catch((error48) => {
50852
+ if (input.signal?.aborted || error48 instanceof HyperliquidPublicReadError || isRateLimitError(error48)) throw error48;
50853
+ return { payload: null, fetchedAtMs: Date.now() };
50854
+ }).then((result2) => ({ payload: result2.payload, capturedAt: new Date(result2.fetchedAtMs).toISOString() }))
50855
+ }))() : Promise.resolve(null);
50856
+ const exactAccountModePromise = input.includeExactAccountMode === true ? (async () => {
50857
+ const abstractionRead = await readHyperliquidPublicInfo(apiUrl, { type: "userAbstraction", user: walletAddress }, { signal: input.signal, reservation, cacheAccountMode: true });
50858
+ const userAbstraction = abstractionRead.payload;
50859
+ let capturedAtMs = abstractionRead.fetchedAtMs;
50860
+ const preliminaryMode = extractCanonicalHyperliquidAccountMode(userAbstraction);
50861
+ if (!preliminaryMode) {
50862
+ throw new Error("Exact Hyperliquid userAbstraction response is invalid.");
50863
+ }
50864
+ let userDexAbstraction;
50865
+ if (preliminaryMode === "default" || preliminaryMode === "disabled") {
50866
+ const dexRead = await readHyperliquidPublicInfo(apiUrl, { type: "userDexAbstraction", user: walletAddress }, { signal: input.signal, reservation, cacheAccountMode: true });
50867
+ userDexAbstraction = dexRead.payload;
50868
+ capturedAtMs = Math.min(capturedAtMs, dexRead.fetchedAtMs);
50869
+ }
50870
+ return {
50871
+ accountMode: resolveExactHyperliquidAccountMode(
50872
+ userAbstraction,
50873
+ userDexAbstraction
50874
+ ),
50875
+ capturedAt: new Date(capturedAtMs).toISOString()
50876
+ };
50877
+ })() : Promise.resolve(null);
50878
+ await Promise.all([userFeesPromise, exactAccountModePromise]);
50879
+ const metadataByDex = /* @__PURE__ */ new Map();
50792
50880
  if (input.includeEffectiveTakerRate === true) {
50793
- requirePromptClearinghouseState(defaultResponse, "default");
50794
- }
50795
- const dexResponses = await Promise.all(
50796
- dexNames.map(async (dexName) => {
50797
- const response = await fetchHyperliquidInfoPayload(
50798
- apiUrl,
50799
- { type: "clearinghouseState", user: walletAddress, dex: dexName },
50800
- input.signal,
50801
- reservation
50802
- );
50803
- if (input.includeEffectiveTakerRate === true) {
50804
- requirePromptClearinghouseState(response, dexName);
50881
+ await Promise.all(["", ...dexNames].map(async (dex) => {
50882
+ try {
50883
+ metadataByDex.set(dex, await fetchHyperliquidInfoPayload(apiUrl, { type: "meta", ...dex ? { dex } : {} }, input.signal, reservation));
50884
+ } catch (error48) {
50885
+ if (input.signal?.aborted || error48 instanceof HyperliquidPublicReadError || isRateLimitError(error48)) throw error48;
50886
+ metadataByDex.set(dex, null);
50805
50887
  }
50806
- return {
50807
- dex: dexName,
50808
- payload: prefixHip3PositionCoins(response, dexName),
50809
- rawPayload: response
50810
- };
50811
- })
50812
- );
50813
- const selectedPayload = selectedDex ? dexResponses.find((entry) => entry.dex === selectedDex)?.payload : defaultResponse;
50814
- if (!selectedPayload) {
50815
- throw new Error(`Missing selected Hyperliquid clearinghouse state for DEX ${selectedDex}.`);
50888
+ }));
50816
50889
  }
50817
- return {
50818
- payload: aggregateClearinghouseResponses([
50819
- defaultResponse,
50820
- ...dexResponses.map((entry) => entry.payload)
50821
- ]),
50822
- selectedPayload,
50823
- dexPayloads: [
50824
- { dex: "", payload: defaultResponse },
50825
- ...dexResponses.map(({ dex, rawPayload }) => ({ dex, payload: rawPayload }))
50826
- ],
50827
- capturedAt: (/* @__PURE__ */ new Date()).toISOString()
50828
- };
50829
- })();
50830
- const spotPromise = (async () => {
50831
- let payload;
50832
- try {
50833
- payload = await fetchHyperliquidInfoPayload(
50890
+ const perpsPromise = (async () => {
50891
+ const defaultResponse = await fetchHyperliquidInfoPayload(
50834
50892
  apiUrl,
50835
- { type: "spotClearinghouseState", user: walletAddress },
50893
+ { type: "clearinghouseState", user: walletAddress },
50836
50894
  input.signal,
50837
50895
  reservation
50838
50896
  );
50839
- } catch (error48) {
50840
- recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
50841
- if (input.forceRefresh || input.includeEffectiveTakerRate === true) {
50842
- throw error48;
50897
+ if (input.includeEffectiveTakerRate === true) {
50898
+ requirePromptClearinghouseState(defaultResponse, "default");
50899
+ }
50900
+ const dexResponses = await Promise.all(
50901
+ dexNames.map(async (dexName) => {
50902
+ const response = await fetchHyperliquidInfoPayload(
50903
+ apiUrl,
50904
+ { type: "clearinghouseState", user: walletAddress, dex: dexName },
50905
+ input.signal,
50906
+ reservation
50907
+ );
50908
+ if (input.includeEffectiveTakerRate === true) {
50909
+ requirePromptClearinghouseState(response, dexName);
50910
+ }
50911
+ return {
50912
+ dex: dexName,
50913
+ payload: prefixHip3PositionCoins(response, dexName),
50914
+ rawPayload: response
50915
+ };
50916
+ })
50917
+ );
50918
+ const selectedPayload = selectedDex ? dexResponses.find((entry) => entry.dex === selectedDex)?.payload : defaultResponse;
50919
+ if (!selectedPayload) {
50920
+ throw new Error(`Missing selected Hyperliquid clearinghouse state for DEX ${selectedDex}.`);
50843
50921
  }
50844
- payload = {};
50845
- }
50846
- return { payload, capturedAt: (/* @__PURE__ */ new Date()).toISOString() };
50847
- })();
50848
- const activeAssetPromise = input.includeActiveAssetData === false ? Promise.resolve(null) : (async () => {
50849
- let lastError = null;
50850
- for (const typeName of activeAssetRequestTypes) {
50922
+ return {
50923
+ payload: aggregateClearinghouseResponses([
50924
+ defaultResponse,
50925
+ ...dexResponses.map((entry) => entry.payload)
50926
+ ]),
50927
+ selectedPayload,
50928
+ dexPayloads: [
50929
+ { dex: "", payload: defaultResponse },
50930
+ ...dexResponses.map(({ dex, rawPayload }) => ({ dex, payload: rawPayload }))
50931
+ ],
50932
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString()
50933
+ };
50934
+ })();
50935
+ const spotPromise = (async () => {
50936
+ let payload;
50851
50937
  try {
50852
- const payload = await fetchHyperliquidInfoPayload(
50938
+ payload = await fetchHyperliquidInfoPayload(
50853
50939
  apiUrl,
50854
- { type: typeName, user: walletAddress, coin: symbol2 },
50940
+ { type: "spotClearinghouseState", user: walletAddress },
50855
50941
  input.signal,
50856
50942
  reservation
50857
50943
  );
50858
- return { payload, type: typeName };
50859
50944
  } catch (error48) {
50860
- lastError = error48;
50861
50945
  recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
50862
- if (isRateLimitError(error48)) throw error48;
50863
- if (typeName === "userActiveAssetData" && isUnsupportedUserActiveAssetError(error48)) {
50864
- rememberUnsupportedUserActiveAssetKey(activeAssetCacheKey);
50946
+ if (input.forceRefresh || input.includeEffectiveTakerRate === true) {
50947
+ throw error48;
50865
50948
  }
50949
+ payload = {};
50866
50950
  }
50867
- }
50868
- throw lastError instanceof Error ? lastError : new Error("Failed to fetch browser active asset data.");
50869
- })();
50870
- const [perpsResult, spotResult, activeAssetResult, userFeesResult, exactAccountMode] = await Promise.all([
50871
- perpsPromise,
50872
- spotPromise,
50873
- activeAssetPromise,
50874
- userFeesPromise,
50875
- exactAccountModePromise
50876
- ]);
50877
- const perpsResponse = perpsResult.payload;
50878
- const accountSummaryPerpsResponse = input.scopeAccountSummaryToSelectedDex === true ? perpsResult.selectedPayload : perpsResponse;
50879
- const spotResponse = spotResult.payload;
50880
- const userFeesResponse = userFeesResult?.payload ?? null;
50881
- if (input.includeEffectiveTakerRate === true) {
50882
- requirePromptSpotState(spotResponse);
50883
- }
50884
- let takerRate;
50885
- if (input.includeEffectiveTakerRate === true) {
50886
- const raw = userFeesResponse?.userCrossRate;
50887
- if ((typeof raw === "number" || typeof raw === "string" && raw.trim() !== "") && Number.isFinite(Number(raw)) && Number(raw) >= 0 && Number(raw) < 1) takerRate = Number(raw);
50888
- }
50889
- let effectiveTakerRates;
50890
- if (input.includeEffectiveTakerRate === true) {
50891
- const feeSymbols = [...new Set([
50892
- ...input.feeSymbols ?? [symbol2],
50893
- ...parseInfoPositions(perpsResponse).filter((position) => Number(position.size) !== 0).map((position) => position.symbol)
50894
- ].map(normalizeHyperliquidMarketSymbol).filter(Boolean))].sort();
50895
- const feeDexes = [...new Set(feeSymbols.map(getHyperliquidMarketDex))];
50896
- const metadata = await Promise.all(feeDexes.map(async (dex) => {
50897
- try {
50898
- const payload = metadataByDex.get(dex) ?? null;
50899
- return [dex, payload];
50900
- } catch (error48) {
50901
- if (input.signal?.aborted) throw error48;
50902
- return [dex, null];
50951
+ return { payload, capturedAt: (/* @__PURE__ */ new Date()).toISOString() };
50952
+ })();
50953
+ const activeAssetPromise = input.includeActiveAssetData === false ? Promise.resolve(null) : (async () => {
50954
+ let lastError = null;
50955
+ for (const typeName of activeAssetRequestTypes) {
50956
+ try {
50957
+ const payload = await fetchHyperliquidInfoPayload(
50958
+ apiUrl,
50959
+ { type: typeName, user: walletAddress, coin: symbol2 },
50960
+ input.signal,
50961
+ reservation
50962
+ );
50963
+ return { payload, type: typeName };
50964
+ } catch (error48) {
50965
+ lastError = error48;
50966
+ recordInfoRateLimitCooldownFromError(apiUrl, error48, staleIf429MaxAgeMs);
50967
+ if (isRateLimitError(error48)) throw error48;
50968
+ if (typeName === "userActiveAssetData" && isUnsupportedUserActiveAssetError(error48)) {
50969
+ rememberUnsupportedUserActiveAssetKey(activeAssetCacheKey);
50970
+ }
50971
+ }
50903
50972
  }
50904
- }));
50905
- effectiveTakerRates = effectiveHyperliquidTakerRates(feeSymbols, userFeesResponse ?? {}, Object.fromEntries(metadata));
50906
- }
50907
- const accountStateConfig = input.config.client_runtime_hyperliquid_account_state;
50908
- const summaryPerpsResponse = exactAccountMode ? { ...accountSummaryPerpsResponse, accountMode: exactAccountMode.accountMode } : accountSummaryPerpsResponse;
50909
- const accountSummaryOptions = {
50910
- spotDominatesMinTotalUsd: accountStateConfig?.spot_dominates_min_total_usd,
50911
- spotDominatesPerpsMultiplier: accountStateConfig?.spot_dominates_perps_multiplier,
50912
- mirroredAccountValueAbsoluteToleranceUsd: accountStateConfig?.mirrored_account_value_absolute_tolerance_usd,
50913
- mirroredAccountValueRelativeTolerance: accountStateConfig?.mirrored_account_value_relative_tolerance
50914
- };
50915
- const walletSummary = exactAccountMode && input.scopeAccountSummaryToSelectedDex !== true ? buildServerPromptRescueAccountSummary(
50916
- perpsResponse,
50917
- spotResponse,
50918
- exactAccountMode.accountMode,
50919
- accountSummaryOptions
50920
- ) : buildAccountSummaryFromInfoResponses(
50921
- perpsResponse,
50922
- spotResponse,
50923
- accountSummaryOptions
50924
- );
50925
- const normalizedSummary = input.scopeAccountSummaryToSelectedDex === true ? {
50926
- ...buildAccountSummaryFromInfoResponses(
50973
+ throw lastError instanceof Error ? lastError : new Error("Failed to fetch browser active asset data.");
50974
+ })();
50975
+ const [perpsResult, spotResult, activeAssetResult, userFeesResult, exactAccountMode] = await Promise.all([
50976
+ perpsPromise,
50977
+ spotPromise,
50978
+ activeAssetPromise,
50979
+ userFeesPromise,
50980
+ exactAccountModePromise
50981
+ ]);
50982
+ const perpsResponse = perpsResult.payload;
50983
+ const accountSummaryPerpsResponse = input.scopeAccountSummaryToSelectedDex === true ? perpsResult.selectedPayload : perpsResponse;
50984
+ const spotResponse = spotResult.payload;
50985
+ const userFeesResponse = userFeesResult?.payload ?? null;
50986
+ if (input.includeEffectiveTakerRate === true) {
50987
+ requirePromptSpotState(spotResponse);
50988
+ }
50989
+ let takerRate;
50990
+ if (input.includeEffectiveTakerRate === true) {
50991
+ const raw = userFeesResponse?.userCrossRate;
50992
+ if ((typeof raw === "number" || typeof raw === "string" && raw.trim() !== "") && Number.isFinite(Number(raw)) && Number(raw) >= 0 && Number(raw) < 1) takerRate = Number(raw);
50993
+ }
50994
+ let effectiveTakerRates;
50995
+ if (input.includeEffectiveTakerRate === true) {
50996
+ const feeSymbols = [...new Set([
50997
+ ...input.feeSymbols ?? [symbol2],
50998
+ ...parseInfoPositions(perpsResponse).filter((position) => Number(position.size) !== 0).map((position) => position.symbol)
50999
+ ].map(normalizeHyperliquidMarketSymbol).filter(Boolean))].sort();
51000
+ const feeDexes = [...new Set(feeSymbols.map(getHyperliquidMarketDex))];
51001
+ const metadata = await Promise.all(feeDexes.map(async (dex) => {
51002
+ try {
51003
+ const payload = metadataByDex.get(dex) ?? null;
51004
+ return [dex, payload];
51005
+ } catch (error48) {
51006
+ if (input.signal?.aborted) throw error48;
51007
+ return [dex, null];
51008
+ }
51009
+ }));
51010
+ effectiveTakerRates = effectiveHyperliquidTakerRates(feeSymbols, userFeesResponse ?? {}, Object.fromEntries(metadata));
51011
+ }
51012
+ const accountStateConfig = input.config.client_runtime_hyperliquid_account_state;
51013
+ const summaryPerpsResponse = exactAccountMode ? { ...accountSummaryPerpsResponse, accountMode: exactAccountMode.accountMode } : accountSummaryPerpsResponse;
51014
+ const accountSummaryOptions = {
51015
+ spotDominatesMinTotalUsd: accountStateConfig?.spot_dominates_min_total_usd,
51016
+ spotDominatesPerpsMultiplier: accountStateConfig?.spot_dominates_perps_multiplier,
51017
+ mirroredAccountValueAbsoluteToleranceUsd: accountStateConfig?.mirrored_account_value_absolute_tolerance_usd,
51018
+ mirroredAccountValueRelativeTolerance: accountStateConfig?.mirrored_account_value_relative_tolerance
51019
+ };
51020
+ const walletSummary = exactAccountMode && input.scopeAccountSummaryToSelectedDex !== true ? buildServerPromptRescueAccountSummary(
51021
+ perpsResponse,
51022
+ spotResponse,
51023
+ exactAccountMode.accountMode,
51024
+ accountSummaryOptions
51025
+ ) : buildAccountSummaryFromInfoResponses(
51026
+ perpsResponse,
51027
+ spotResponse,
51028
+ accountSummaryOptions
51029
+ );
51030
+ const normalizedSummary = input.scopeAccountSummaryToSelectedDex === true ? {
51031
+ ...buildAccountSummaryFromInfoResponses(
51032
+ summaryPerpsResponse,
51033
+ {},
51034
+ accountSummaryOptions
51035
+ ),
51036
+ balances: walletSummary.balances
51037
+ } : exactAccountMode ? buildServerPromptRescueAccountSummary(
51038
+ accountSummaryPerpsResponse,
51039
+ spotResponse,
51040
+ exactAccountMode.accountMode,
51041
+ accountSummaryOptions
51042
+ ) : buildAccountSummaryFromInfoResponses(
50927
51043
  summaryPerpsResponse,
50928
- {},
51044
+ spotResponse,
50929
51045
  accountSummaryOptions
50930
- ),
50931
- balances: walletSummary.balances
50932
- } : exactAccountMode ? buildServerPromptRescueAccountSummary(
50933
- accountSummaryPerpsResponse,
50934
- spotResponse,
50935
- exactAccountMode.accountMode,
50936
- accountSummaryOptions
50937
- ) : buildAccountSummaryFromInfoResponses(
50938
- summaryPerpsResponse,
50939
- spotResponse,
50940
- accountSummaryOptions
50941
- );
50942
- const accountSummary = {
50943
- ...normalizedSummary,
50944
- ...input.scopeAccountSummaryToSelectedDex === true ? {} : {
50945
- perp_dex_accounts: perpsResult.dexPayloads.filter(({ payload }) => hasCompletePerpDexAccountMetrics(payload)).map(({ dex, payload }) => {
50946
- const summary = buildServerPromptRescueAccountSummary({
50947
- ...payload,
50948
- crossMaintenanceMarginUsed: firstFiniteNumber([
50949
- payload.crossMaintenanceMarginUsed,
50950
- payload.marginSummary?.crossMaintenanceMarginUsed,
50951
- payload.marginSummary?.totalMaintenanceMargin
50952
- ])
50953
- }, {}, "disabled", accountSummaryOptions);
50954
- const accountValue = Number(payload.marginSummary.accountValue);
50955
- const calculatedAvailable = accountValue - summary.total_margin_used;
50956
- const availableMargin = summary.maintenance_margin > 0 ? Math.max(calculatedAvailable, Math.max(0, accountValue - 4 * summary.maintenance_margin), summary.withdrawable) : Math.max(calculatedAvailable, summary.withdrawable);
50957
- return {
50958
- dex,
50959
- account_value: accountValue,
50960
- total_margin_used: summary.total_margin_used,
50961
- available_margin: availableMargin,
50962
- withdrawable: summary.withdrawable,
50963
- maintenance_margin: summary.maintenance_margin,
50964
- cross_account_leverage: summary.cross_account_leverage,
50965
- total_unrealized_pnl: summary.total_unrealized_pnl ?? 0
50966
- };
50967
- })
50968
- },
50969
- ...exactAccountMode == null ? {} : { account_mode: exactAccountMode.accountMode, mode_source: "canonical" },
50970
- address: walletAddress,
50971
- dex: input.scopeAccountSummaryToSelectedDex === true ? selectedDex : "all",
50972
- market_type: "perp"
50973
- };
50974
- const activeAssetPayload = activeAssetResult?.payload ?? null;
50975
- const activeAssetType = activeAssetResult?.type ?? "promptAccountState";
50976
- const normalizedActiveAsset = normalizeActiveAssetData(activeAssetPayload, symbol2);
50977
- const markPrice = toPositiveFinite(normalizedActiveAsset.mark_price, toPositiveFinite(input.tickerPrice));
50978
- const fallbackLeverage = toPositiveFinite(input.leverage, 1);
50979
- const availableBase = Math.max(0, toFinite(accountSummary.available_margin, 0));
50980
- const availableToTrade = {
50981
- symbol: symbol2,
50982
- available_to_trade_buy: Math.max(0, toFinite(normalizedActiveAsset.available_to_trade_buy, availableBase)),
50983
- available_to_trade_sell: Math.max(0, toFinite(normalizedActiveAsset.available_to_trade_sell, availableBase)),
50984
- max_trade_size_buy: Math.max(0, toFinite(normalizedActiveAsset.max_trade_size_buy, availableBase * fallbackLeverage)),
50985
- max_trade_size_sell: Math.max(0, toFinite(normalizedActiveAsset.max_trade_size_sell, availableBase * fallbackLeverage)),
50986
- mark_price: markPrice,
50987
- source: `browser_exchange:${activeAssetType}`
50988
- };
50989
- return {
50990
- accountSummary,
50991
- availableToTrade,
50992
- positions: parseInfoPositions(perpsResponse),
50993
- ...takerRate == null ? {} : { takerRate },
50994
- ...effectiveTakerRates == null ? {} : { effectiveTakerRates },
50995
- ...exactAccountMode == null || userFeesResult == null ? {} : {
50996
- promptRescueEvidence: {
50997
- capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
50998
- perpsCapturedAt: perpsResult.capturedAt,
50999
- spotCapturedAt: spotResult.capturedAt,
51000
- feesCapturedAt: userFeesResult.capturedAt,
51001
- accountModeCapturedAt: exactAccountMode.capturedAt,
51002
- accountModeSource: "canonical"
51046
+ );
51047
+ const accountSummary = {
51048
+ ...normalizedSummary,
51049
+ ...input.scopeAccountSummaryToSelectedDex === true ? {} : {
51050
+ perp_dex_accounts: perpsResult.dexPayloads.filter(({ payload }) => hasCompletePerpDexAccountMetrics(payload)).map(({ dex, payload }) => {
51051
+ const summary = buildServerPromptRescueAccountSummary({
51052
+ ...payload,
51053
+ crossMaintenanceMarginUsed: firstFiniteNumber([
51054
+ payload.crossMaintenanceMarginUsed,
51055
+ payload.marginSummary?.crossMaintenanceMarginUsed,
51056
+ payload.marginSummary?.totalMaintenanceMargin
51057
+ ])
51058
+ }, {}, "disabled", accountSummaryOptions);
51059
+ const accountValue = Number(payload.marginSummary.accountValue);
51060
+ const calculatedAvailable = accountValue - summary.total_margin_used;
51061
+ const availableMargin = summary.maintenance_margin > 0 ? Math.max(calculatedAvailable, Math.max(0, accountValue - 4 * summary.maintenance_margin), summary.withdrawable) : Math.max(calculatedAvailable, summary.withdrawable);
51062
+ return {
51063
+ dex,
51064
+ account_value: accountValue,
51065
+ total_margin_used: summary.total_margin_used,
51066
+ available_margin: availableMargin,
51067
+ withdrawable: summary.withdrawable,
51068
+ maintenance_margin: summary.maintenance_margin,
51069
+ cross_account_leverage: summary.cross_account_leverage,
51070
+ total_unrealized_pnl: summary.total_unrealized_pnl ?? 0
51071
+ };
51072
+ })
51073
+ },
51074
+ ...exactAccountMode == null ? {} : { account_mode: exactAccountMode.accountMode, mode_source: "canonical" },
51075
+ address: walletAddress,
51076
+ dex: input.scopeAccountSummaryToSelectedDex === true ? selectedDex : "all",
51077
+ market_type: "perp"
51078
+ };
51079
+ const activeAssetPayload = activeAssetResult?.payload ?? null;
51080
+ const activeAssetType = activeAssetResult?.type ?? "promptAccountState";
51081
+ const normalizedActiveAsset = normalizeActiveAssetData(activeAssetPayload, symbol2);
51082
+ const markPrice = toPositiveFinite(normalizedActiveAsset.mark_price, toPositiveFinite(input.tickerPrice));
51083
+ const fallbackLeverage = toPositiveFinite(input.leverage, 1);
51084
+ const availableBase = Math.max(0, toFinite(accountSummary.available_margin, 0));
51085
+ const availableToTrade = {
51086
+ symbol: symbol2,
51087
+ available_to_trade_buy: Math.max(0, toFinite(normalizedActiveAsset.available_to_trade_buy, availableBase)),
51088
+ available_to_trade_sell: Math.max(0, toFinite(normalizedActiveAsset.available_to_trade_sell, availableBase)),
51089
+ max_trade_size_buy: Math.max(0, toFinite(normalizedActiveAsset.max_trade_size_buy, availableBase * fallbackLeverage)),
51090
+ max_trade_size_sell: Math.max(0, toFinite(normalizedActiveAsset.max_trade_size_sell, availableBase * fallbackLeverage)),
51091
+ mark_price: markPrice,
51092
+ source: `browser_exchange:${activeAssetType}`
51093
+ };
51094
+ return {
51095
+ accountSummary,
51096
+ availableToTrade,
51097
+ positions: parseInfoPositions(perpsResponse),
51098
+ ...takerRate == null ? {} : { takerRate },
51099
+ ...effectiveTakerRates == null ? {} : { effectiveTakerRates },
51100
+ ...exactAccountMode == null || userFeesResult == null ? {} : {
51101
+ promptRescueEvidence: {
51102
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
51103
+ perpsCapturedAt: perpsResult.capturedAt,
51104
+ spotCapturedAt: spotResult.capturedAt,
51105
+ feesCapturedAt: userFeesResult.capturedAt,
51106
+ accountModeCapturedAt: exactAccountMode.capturedAt,
51107
+ accountModeSource: "canonical"
51108
+ }
51003
51109
  }
51004
- }
51005
- };
51110
+ };
51111
+ } finally {
51112
+ await releaseHyperliquidPublicReadReservation(reservation);
51113
+ }
51006
51114
  };
51007
51115
  fetchBrowserUserFills = async (input) => {
51008
51116
  configureHyperliquidMarketSymbolCasing(input.config.client_runtime_hyperliquid_case_sensitive_symbols);
@@ -85510,9 +85618,11 @@ var init_hyperliquid_client = __esm({
85510
85618
  }
85511
85619
  }
85512
85620
  try {
85621
+ await admitHyperliquidExchangeRequest(apiUrl, input.payload.action, input.signal);
85513
85622
  assertFreshPreparedExecutionContext(input.preparedContext);
85514
85623
  } catch (preparedContextError) {
85515
85624
  await settleDurableMutation("rejected");
85625
+ if (isAbortLikeError(preparedContextError) || preparedContextError instanceof HyperliquidPublicReadError) throw preparedContextError;
85516
85626
  throw new RuntimeExecutionError(
85517
85627
  preparedContextError instanceof Error ? preparedContextError.message : "Prepared exchange context expired before dispatch.",
85518
85628
  "local_safety_block"
@@ -85545,6 +85655,7 @@ var init_hyperliquid_client = __esm({
85545
85655
  body: serializedPayload
85546
85656
  });
85547
85657
  responseStatus = response.status;
85658
+ await recordHyperliquidExchangeResponse(apiUrl, response);
85548
85659
  const payload = await response.json().catch(() => ({}));
85549
85660
  if (!response.ok) {
85550
85661
  await settleDurableMutation("transport_ambiguous");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtxmacro/cli",
3
- "version": "2026.9.52",
3
+ "version": "2026.9.53",
4
4
  "description": "VTX Macro CLI, MCP server, and durable external inference host.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",