@vtxmacro/cli 2026.10.7 → 2026.10.8

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/bin/vtx.js CHANGED
@@ -113,7 +113,7 @@ var init_routing = __esm({
113
113
  var agent_cli_release_default;
114
114
  var init_agent_cli_release = __esm({
115
115
  "agent-cli-release.json"() {
116
- agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.7", codex_package_name: "@openai/codex", codex_version: "0.155.0", copilot_sdk_package_name: "@github/copilot-sdk", copilot_sdk_version: "1.0.0-beta.8", copilot_cli_package_name: "@github/copilot", copilot_cli_version: "1.0.80", deepseek_harness_version: "0.1.1-rc.2", deepseek_harness_packages: ["@deepseek-ai/dsh-agent", "@deepseek-ai/dsh-agent-instructions", "@deepseek-ai/dsh-agent-loop", "@deepseek-ai/dsh-agent-spine-demo", "@deepseek-ai/dsh-anonymous-user-id", "@deepseek-ai/dsh-atomic-write", "@deepseek-ai/dsh-attachment", "@deepseek-ai/dsh-brand", "@deepseek-ai/dsh-code-runtime", "@deepseek-ai/dsh-credentials", "@deepseek-ai/dsh-fs", "@deepseek-ai/dsh-goal", "@deepseek-ai/dsh-goal-round-driver", "@deepseek-ai/dsh-home-paths", "@deepseek-ai/dsh-invariants", "@deepseek-ai/dsh-jobs", "@deepseek-ai/dsh-jobs-local", "@deepseek-ai/dsh-launch-environment", "@deepseek-ai/dsh-llm", "@deepseek-ai/dsh-llm-deepseek", "@deepseek-ai/dsh-llm-retry", "@deepseek-ai/dsh-output-retention", "@deepseek-ai/dsh-sandbox", "@deepseek-ai/dsh-sandbox-policy", "@deepseek-ai/dsh-scope", "@deepseek-ai/dsh-session", "@deepseek-ai/dsh-session-checkpoint-policy", "@deepseek-ai/dsh-session-persistence", "@deepseek-ai/dsh-session-persistence-jsonl", "@deepseek-ai/dsh-session-projection", "@deepseek-ai/dsh-session-title", "@deepseek-ai/dsh-settings", "@deepseek-ai/dsh-shell", "@deepseek-ai/dsh-shell-env", "@deepseek-ai/dsh-skill", "@deepseek-ai/dsh-skill-filesystem", "@deepseek-ai/dsh-subprocess", "@deepseek-ai/dsh-system-prompt", "@deepseek-ai/dsh-timeout", "@deepseek-ai/dsh-tool-bash", "@deepseek-ai/dsh-tool-goal", "@deepseek-ai/dsh-tool-jobs", "@deepseek-ai/dsh-tool-skill", "@deepseek-ai/dsh-tools", "@deepseek-ai/dsh-typert-protocol", "@deepseek-ai/dsh-user-approval"], deepseek_cordis_package_name: "@deepseek-ai/cordis", deepseek_cordis_version: "4.0.1", deepseek_support_packages: { "@deepseek-ai/cordis-plugin-timer": "1.1.3" }, platforms: { "linux-x64": { package_name: "@openai/codex-linux-x64", target: "x86_64-unknown-linux-musl", binary_name: "codex", sha256: "660e159a49e823ac8e5986cb238f73158ce4b957d40d9292f8de90862644b501" }, "win32-x64": { package_name: "@openai/codex-win32-x64", target: "x86_64-pc-windows-msvc", binary_name: "codex.exe", sha256: "e4c11374bd9de8ad5c3b7617fd4654bb7839901edb0863f9930666863c7a021b" } }, pi_coding_agent_package_name: "@earendil-works/pi-coding-agent", pi_ai_package_name: "@earendil-works/pi-ai", pi_version: "0.85.1", pi_support_packages: ["@earendil-works/pi-agent-core", "@earendil-works/pi-telemetry", "@earendil-works/pi-tui", "@earendil-works/chord"], grok_version: "1.0.30", grok_platforms: { "linux-x64": { package_name: "@xai-official/grok-linux-x64", binary_name: "grok", sha256: "504dd6546ab991b75d36698242875ce461489cd1f8cd84285873cb55bd5c7d54" }, "win32-x64": { package_name: "@xai-official/grok-win32-x64", binary_name: "grok.exe", sha256: "48736d1a4342a801ea26d0ecde4c516b653f791399065adaa55973f83abd8867" } } };
116
+ agent_cli_release_default = { package_name: "@vtxmacro/cli", package_version: "2026.10.8", codex_package_name: "@openai/codex", codex_version: "0.155.0", copilot_sdk_package_name: "@github/copilot-sdk", copilot_sdk_version: "1.0.0-beta.8", copilot_cli_package_name: "@github/copilot", copilot_cli_version: "1.0.80", deepseek_harness_version: "0.1.1-rc.2", deepseek_harness_packages: ["@deepseek-ai/dsh-agent", "@deepseek-ai/dsh-agent-instructions", "@deepseek-ai/dsh-agent-loop", "@deepseek-ai/dsh-agent-spine-demo", "@deepseek-ai/dsh-anonymous-user-id", "@deepseek-ai/dsh-atomic-write", "@deepseek-ai/dsh-attachment", "@deepseek-ai/dsh-brand", "@deepseek-ai/dsh-code-runtime", "@deepseek-ai/dsh-credentials", "@deepseek-ai/dsh-fs", "@deepseek-ai/dsh-goal", "@deepseek-ai/dsh-goal-round-driver", "@deepseek-ai/dsh-home-paths", "@deepseek-ai/dsh-invariants", "@deepseek-ai/dsh-jobs", "@deepseek-ai/dsh-jobs-local", "@deepseek-ai/dsh-launch-environment", "@deepseek-ai/dsh-llm", "@deepseek-ai/dsh-llm-deepseek", "@deepseek-ai/dsh-llm-retry", "@deepseek-ai/dsh-output-retention", "@deepseek-ai/dsh-sandbox", "@deepseek-ai/dsh-sandbox-policy", "@deepseek-ai/dsh-scope", "@deepseek-ai/dsh-session", "@deepseek-ai/dsh-session-checkpoint-policy", "@deepseek-ai/dsh-session-persistence", "@deepseek-ai/dsh-session-persistence-jsonl", "@deepseek-ai/dsh-session-projection", "@deepseek-ai/dsh-session-title", "@deepseek-ai/dsh-settings", "@deepseek-ai/dsh-shell", "@deepseek-ai/dsh-shell-env", "@deepseek-ai/dsh-skill", "@deepseek-ai/dsh-skill-filesystem", "@deepseek-ai/dsh-subprocess", "@deepseek-ai/dsh-system-prompt", "@deepseek-ai/dsh-timeout", "@deepseek-ai/dsh-tool-bash", "@deepseek-ai/dsh-tool-goal", "@deepseek-ai/dsh-tool-jobs", "@deepseek-ai/dsh-tool-skill", "@deepseek-ai/dsh-tools", "@deepseek-ai/dsh-typert-protocol", "@deepseek-ai/dsh-user-approval"], deepseek_cordis_package_name: "@deepseek-ai/cordis", deepseek_cordis_version: "4.0.1", deepseek_support_packages: { "@deepseek-ai/cordis-plugin-timer": "1.1.3" }, platforms: { "linux-x64": { package_name: "@openai/codex-linux-x64", target: "x86_64-unknown-linux-musl", binary_name: "codex", sha256: "660e159a49e823ac8e5986cb238f73158ce4b957d40d9292f8de90862644b501" }, "win32-x64": { package_name: "@openai/codex-win32-x64", target: "x86_64-pc-windows-msvc", binary_name: "codex.exe", sha256: "e4c11374bd9de8ad5c3b7617fd4654bb7839901edb0863f9930666863c7a021b" } }, pi_coding_agent_package_name: "@earendil-works/pi-coding-agent", pi_ai_package_name: "@earendil-works/pi-ai", pi_version: "0.85.1", pi_support_packages: ["@earendil-works/pi-agent-core", "@earendil-works/pi-telemetry", "@earendil-works/pi-tui", "@earendil-works/chord"], grok_version: "1.0.30", grok_platforms: { "linux-x64": { package_name: "@xai-official/grok-linux-x64", binary_name: "grok", sha256: "504dd6546ab991b75d36698242875ce461489cd1f8cd84285873cb55bd5c7d54" }, "win32-x64": { package_name: "@xai-official/grok-win32-x64", binary_name: "grok.exe", sha256: "48736d1a4342a801ea26d0ecde4c516b653f791399065adaa55973f83abd8867" } } };
117
117
  }
118
118
  });
119
119
 
@@ -213,6 +213,9 @@ var init_runtime_policy_generated = __esm({
213
213
  evidence_max_items: 32,
214
214
  evidence_shared_read_seconds: 10
215
215
  },
216
+ protective_plan_set_lock: {
217
+ wait_seconds: 120
218
+ },
216
219
  history_evidence: {
217
220
  device_rounds_per_beat: 6,
218
221
  device_retry_seconds: 60
@@ -1623,7 +1626,7 @@ async function writeAtomicInferencePrivateFile(path, contents, dependencies = {}
1623
1626
  throw error48;
1624
1627
  }
1625
1628
  }
1626
- async function readInferencePrivateFile(path, label, dependencies = {}) {
1629
+ async function readInferencePrivateFile(path, label2, dependencies = {}) {
1627
1630
  const platform = dependencies.platform ?? process.platform;
1628
1631
  const runner = dependencies.runner ?? runWindowsPrivateAcl;
1629
1632
  const defaultRoot = dependencies.defaultRoot ?? resolve(homedir2(), ".vtx", "inference-host");
@@ -1635,7 +1638,7 @@ async function readInferencePrivateFile(path, label, dependencies = {}) {
1635
1638
  throw error48;
1636
1639
  }
1637
1640
  if (before.isSymbolicLink() || !before.isFile()) {
1638
- throw new Error(`${label} is unsafe.`);
1641
+ throw new Error(`${label2} is unsafe.`);
1639
1642
  }
1640
1643
  await secureExistingWindowsPath(
1641
1644
  dirname2(path),
@@ -1649,21 +1652,21 @@ async function readInferencePrivateFile(path, label, dependencies = {}) {
1649
1652
  try {
1650
1653
  const opened = await handle.stat();
1651
1654
  if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size > MAX_INFERENCE_PRIVATE_FILE_BYTES || typeof process.getuid === "function" && opened.uid !== process.getuid()) {
1652
- throw new Error(`${label} changed while it was opened.`);
1655
+ throw new Error(`${label2} changed while it was opened.`);
1653
1656
  }
1654
1657
  if (platform !== "win32" && (opened.mode & 63) !== 0) {
1655
- throw new Error(`${label} must have mode 0600.`);
1658
+ throw new Error(`${label2} must have mode 0600.`);
1656
1659
  }
1657
1660
  return await handle.readFile("utf8");
1658
1661
  } finally {
1659
1662
  await handle.close();
1660
1663
  }
1661
1664
  }
1662
- async function clearInferencePrivateFile(path, label) {
1665
+ async function clearInferencePrivateFile(path, label2) {
1663
1666
  try {
1664
1667
  const metadata = await lstat(path);
1665
1668
  if (metadata.isSymbolicLink() || !metadata.isFile()) {
1666
- throw new Error(`${label} is unsafe.`);
1669
+ throw new Error(`${label2} is unsafe.`);
1667
1670
  }
1668
1671
  await secureExistingWindowsPath(dirname2(path), "directory");
1669
1672
  await secureExistingWindowsPath(path, "file");
@@ -1785,7 +1788,7 @@ async function acquireInferenceHostProcessLock(path, dependencies = {}) {
1785
1788
  }
1786
1789
  };
1787
1790
  }
1788
- var loadInferenceReceiptDurabilityTimeoutMs, loadInferenceAgentDataRequestTimeoutMs, loadInferenceAgentCommandLockPolicy, InferenceHostProcessLockBusyError, INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, WINDOWS_PRIVATE_ACL_BROKER_SCRIPT, WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS, WINDOWS_PRIVATE_ACL_BROKER_STARTUP_TIMEOUT_MS, SMALL_IDENTITY_COMMAND_TIMEOUT_MS, windowsPowerShellEnvironment, windowsPrivateAclBrokerInvocation, WindowsPrivateAclBroker, defaultWindowsPrivateAclBroker, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, rebindHardenedWindowsAclAfterRename, rebindHardenedWindowsDirectoryAfterOwnedMutation, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentityInvocation, windowsBootIdentityInvocation, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, cachedCurrentProcessIdentity, defaultCurrentProcessIdentity, readInferenceHostProcessLockStatus, processLockObservationCache, inferenceProcessIdentitiesMatch, resolveInferenceHostApiUrl, inferenceHostSupervisorServiceManifestPath, DEFAULT_INFERENCE_HOST_INSTANCE, SAFE_INFERENCE_HOST_INSTANCE, requireNamedInstancePath, credentialStoreIdentity, inferenceHostCredentialContextPath, inferenceHostCredentialContextTransitionPath, credentialContextForConfig, WINDOWS_PRIVATE_FILE_REPLACE_ERROR_CODES, PROCESS_LOCK_PUBLICATION_GRACE_MS, PROCESS_LOCK_MAX_RECORD_BYTES, PROCESS_LOCK_GUARD_ELECTION_LEASE_MS, PROCESS_LOCK_GUARD_ELECTION_STALE_MS, PROCESS_LOCK_GUARD_ELECTION_ATTEMPTS, PROCESS_LOCK_GUARD_ELECTION_BACKOFF_MS, PROCESS_LOCK_LABEL, PROCESS_LOCK_GUARD_LABEL, sameProcessLockFile, openExclusiveProcessLockFile, inspectProcessLockFile, removeVerifiedStaleProcessLockFile, removeStaleProcessLockReclaimGuard, acquireProcessLockReclaimGuard;
1791
+ var loadInferenceReceiptDurabilityTimeoutMs, loadInferenceAgentDataRequestTimeoutMs, loadInferenceAgentCommandLockPolicy, InferenceHostProcessLockBusyError, INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, WINDOWS_PRIVATE_ACL_MODES, WINDOWS_PRIVATE_ACL_BROKER_SCRIPT, WINDOWS_IDENTITY_COMMAND_TIMEOUT_MS, WINDOWS_PRIVATE_ACL_BROKER_STARTUP_TIMEOUT_MS, SMALL_IDENTITY_COMMAND_TIMEOUT_MS, windowsPowerShellEnvironment, windowsPrivateAclBrokerInvocation, WindowsPrivateAclBroker, defaultWindowsPrivateAclBroker, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, rebindHardenedWindowsAclAfterRename, rebindHardenedWindowsDirectoryAfterOwnedMutation, isWindowsPrivateAclVerificationFailure, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentityInvocation, windowsBootIdentityInvocation, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, cachedCurrentProcessIdentity, defaultCurrentProcessIdentity, readInferenceHostProcessLockStatus, processLockObservationCache, inferenceProcessIdentitiesMatch, resolveInferenceHostApiUrl, inferenceHostSupervisorServiceManifestPath, DEFAULT_INFERENCE_HOST_INSTANCE, SAFE_INFERENCE_HOST_INSTANCE, requireNamedInstancePath, credentialStoreIdentity, inferenceHostCredentialContextPath, inferenceHostCredentialContextTransitionPath, credentialContextForConfig, WINDOWS_PRIVATE_FILE_REPLACE_ERROR_CODES, PROCESS_LOCK_PUBLICATION_GRACE_MS, PROCESS_LOCK_MAX_RECORD_BYTES, PROCESS_LOCK_GUARD_ELECTION_LEASE_MS, PROCESS_LOCK_GUARD_ELECTION_STALE_MS, PROCESS_LOCK_GUARD_ELECTION_ATTEMPTS, PROCESS_LOCK_GUARD_ELECTION_BACKOFF_MS, PROCESS_LOCK_LABEL, PROCESS_LOCK_GUARD_LABEL, sameProcessLockFile, openExclusiveProcessLockFile, inspectProcessLockFile, removeVerifiedStaleProcessLockFile, removeStaleProcessLockReclaimGuard, acquireProcessLockReclaimGuard;
1789
1792
  var init_config2 = __esm({
1790
1793
  "lib/inference-host/config.ts"() {
1791
1794
  "use strict";
@@ -1847,6 +1850,7 @@ var init_config2 = __esm({
1847
1850
  };
1848
1851
  INFERENCE_CREDENTIAL_NAMESPACE = "vtxmacro-insights-inference";
1849
1852
  MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
1853
+ WINDOWS_PRIVATE_ACL_MODES = ["harden", "verify", "verify-owner", "verify-private"];
1850
1854
  WINDOWS_PRIVATE_ACL_BROKER_SCRIPT = `$ErrorActionPreference='Stop'
1851
1855
  $ProgressPreference='SilentlyContinue'
1852
1856
  while(($line=[Console]::In.ReadLine()) -ne $null) {
@@ -1863,7 +1867,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
1863
1867
  $kind=[string]$request.kind
1864
1868
  $mode=[string]$request.mode
1865
1869
  if($kind -ne 'directory' -and $kind -ne 'file') { throw 'invalid path kind' }
1866
- if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner') { throw 'invalid ACL mode' }
1870
+ if($mode -ne 'harden' -and $mode -ne 'verify' -and $mode -ne 'verify-owner' -and $mode -ne 'verify-private') { throw 'invalid ACL mode' }
1867
1871
  $path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String([string]$request.path_b64))
1868
1872
  if([string]::IsNullOrWhiteSpace($path) -or $path.Length -gt 32767 -or $path.Contains([char]0)) { throw 'invalid path' }
1869
1873
  $failureStage='path_lookup'
@@ -1912,11 +1916,12 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
1912
1916
  $owner=(New-Object Security.Principal.NTAccount($actual.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
1913
1917
  if($owner -ne $current.Value -and ($owner -ne $admins.Value -or -not $currentIsAdmin)) { throw 'private ACL owner is invalid' }
1914
1918
  if($mode -ne 'verify-owner') {
1915
- if(-not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
1919
+ $inheritedAllowed=$mode -eq 'verify-private'
1920
+ if(-not $inheritedAllowed -and -not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
1916
1921
  $userFull=$false
1917
1922
  foreach($rule in $actual.Access) {
1918
1923
  $sid=$rule.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value
1919
- if($rule.IsInherited -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
1924
+ if(($rule.IsInherited -and -not $inheritedAllowed) -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
1920
1925
  throw 'private ACL contains an unauthorized access rule'
1921
1926
  }
1922
1927
  if($sid -eq $current.Value -and (($rule.FileSystemRights -band [Security.AccessControl.FileSystemRights]::FullControl) -eq [Security.AccessControl.FileSystemRights]::FullControl)) { $userFull=$true }
@@ -2052,9 +2057,9 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
2052
2057
  error48.code = "ENOENT";
2053
2058
  pending3.reject(error48);
2054
2059
  } else {
2055
- pending3.reject(new Error(
2060
+ pending3.reject(Object.assign(new Error(
2056
2061
  `Windows private ACL ${pending3.mode} failed (${response.error_code}).`
2057
- ));
2062
+ ), { aclStage: response.error_code }));
2058
2063
  }
2059
2064
  this.scheduleIdleShutdown();
2060
2065
  }
@@ -2159,7 +2164,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
2159
2164
  };
2160
2165
  invalidateWindowsAclCache = (path) => {
2161
2166
  for (const kind of ["file", "directory"]) {
2162
- for (const mode of ["harden", "verify", "verify-owner"]) {
2167
+ for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
2163
2168
  windowsAclCache.delete(aclCacheKey(path, kind, mode));
2164
2169
  }
2165
2170
  }
@@ -2178,7 +2183,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
2178
2183
  }
2179
2184
  invalidateWindowsAclCache(source);
2180
2185
  invalidateWindowsAclCache(destination);
2181
- for (const mode of ["harden", "verify", "verify-owner"]) {
2186
+ for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
2182
2187
  windowsAclCache.set(aclCacheKey(destination, kind, mode), published);
2183
2188
  }
2184
2189
  };
@@ -2189,10 +2194,11 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
2189
2194
  throw new Error("Windows private directory identity changed during atomic publication.");
2190
2195
  }
2191
2196
  invalidateWindowsAclCache(path);
2192
- for (const mode of ["harden", "verify", "verify-owner"]) {
2197
+ for (const mode of WINDOWS_PRIVATE_ACL_MODES) {
2193
2198
  windowsAclCache.set(aclCacheKey(path, "directory", mode), current);
2194
2199
  }
2195
2200
  };
2201
+ isWindowsPrivateAclVerificationFailure = (error48) => error48?.aclStage === "acl_verification";
2196
2202
  isDefaultWindowsPrivatePath = (path, root = resolve(homedir2(), ".vtx", "inference-host")) => {
2197
2203
  const child = relative(root, resolve(path));
2198
2204
  return child === "" || !child.startsWith("..") && !child.includes(":");
@@ -2421,11 +2427,11 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
2421
2427
  inferenceHostSupervisorServiceManifestPath = (env) => `${join2(inferenceBaseDir(env), "state.json")}.service.json`;
2422
2428
  DEFAULT_INFERENCE_HOST_INSTANCE = "default";
2423
2429
  SAFE_INFERENCE_HOST_INSTANCE = /^[a-z0-9](?:[a-z0-9-]{0,46}[a-z0-9])?$/u;
2424
- requireNamedInstancePath = (instanceName, instanceDir, rawPath, label) => {
2430
+ requireNamedInstancePath = (instanceName, instanceDir, rawPath, label2) => {
2425
2431
  if (!rawPath || instanceName === DEFAULT_INFERENCE_HOST_INSTANCE) return rawPath;
2426
2432
  const relativePath = relative(resolve(instanceDir), resolve(rawPath));
2427
2433
  if (relativePath === ".." || relativePath.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute2(relativePath)) {
2428
- throw new Error(`${label} for a named instance must stay inside its isolated instance directory.`);
2434
+ throw new Error(`${label2} for a named instance must stay inside its isolated instance directory.`);
2429
2435
  }
2430
2436
  return rawPath;
2431
2437
  };
@@ -2480,7 +2486,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
2480
2486
  throw error48;
2481
2487
  }
2482
2488
  };
2483
- inspectProcessLockFile = async (path, label, probes) => {
2489
+ inspectProcessLockFile = async (path, label2, probes) => {
2484
2490
  let before;
2485
2491
  try {
2486
2492
  before = await lstat(path);
@@ -2489,7 +2495,7 @@ while(($line=[Console]::In.ReadLine()) -ne $null) {
2489
2495
  throw error48;
2490
2496
  }
2491
2497
  if (before.isSymbolicLink() || !before.isFile() || process.platform !== "win32" && (before.mode & 63) !== 0 || typeof process.getuid === "function" && before.uid !== process.getuid()) {
2492
- throw new Error(`${label} is unsafe.`);
2498
+ throw new Error(`${label2} is unsafe.`);
2493
2499
  }
2494
2500
  let handle;
2495
2501
  try {
@@ -2736,7 +2742,7 @@ __export(updater_exports, {
2736
2742
  });
2737
2743
  import { spawn as spawn2 } from "node:child_process";
2738
2744
  import { createHash, randomUUID } from "node:crypto";
2739
- import { access, appendFile, chmod, lstat as lstat2, mkdir as mkdir3, readFile as readFile3, readdir as readdir3, realpath as realpath2, rename as rename2, rm as rm3 } from "node:fs/promises";
2745
+ import { access, appendFile, chmod, lstat as lstat2, readFile as readFile3, readdir as readdir3, realpath as realpath2, rename as rename2, rm as rm3 } from "node:fs/promises";
2740
2746
  import { constants as osConstants, homedir as homedir3 } from "node:os";
2741
2747
  import { dirname as dirname3, isAbsolute as isAbsolute3, join as join3, relative as relative2, resolve as resolve2, win32 as windowsPath2 } from "node:path";
2742
2748
  var CLI_PACKAGE_NAME, OFFICIAL_NPM_REGISTRY, CLI_UPDATE_COMMAND, parseCliReleaseVersion, compareCliReleaseVersions, isPathWithin, defaultRunCliCommand, runCliReleaseNpmCommand, fetchLatestCliRelease, verifyCliReleaseIntegrity, verifyInstalledCliRelease, cleanupInterruptedReleaseStaging, ensureUpdaterPrivateDirectory, stageCliRelease, stageCliReleaseWithin, readCliReleaseRejection, writeCliReleaseRejection, CLI_BACKGROUND_STAGE_ARGUMENT, READY_MESSAGE_TYPE, CHILD_ENV, READY_PROTOCOL_ENV, EMPTY_STATE, resolveCliUpdatePaths, cliAutoUpdateDisabled, resolveRegistry, validSelection, readState, writeState, appendCliUpdateLog, isSkippedInvocation, isVersionQuery, policyApiUrl, fetchMinimumSupportedVersion, classifyCliInstall, refusal, inferenceHostServiceManifestPaths, prune, stageAndSelect, planCliEntryUpdate, spawnBackgroundStage, runCliBackgroundStage, installStopTracker, runReleaseProcess, reportCliEntryReady, markConfirmed, ROLLBACK_SKIPPED, rollBack, finishRollBack, INTERRUPTED_EXIT_CODE, superviseRuntime, releaseEntryScript, runCliEntry, RUNTIME_RESTART_FOR_UPDATE_EXIT_CODE, RUNTIME_SUPERVISED_ENV, RUNTIME_RESUME_ENV, RUNTIME_SUPERVISOR_PID_ENV, RUNTIME_RESUME_FILE_ENV, runtimeResumeFile, parseRuntimeResumeRecord, readRuntimeResume, writeRuntimeResume, clearRuntimeResume, isSupervisableRuntimeCommand, isRuntimeResume, runtimeRestartEligible, pollRuntimeRelease, createRuntimeRestartCheck;
@@ -2872,7 +2878,32 @@ var init_updater = __esm({
2872
2878
  };
2873
2879
  ensureUpdaterPrivateDirectory = async (path, root, dependencies = {}) => {
2874
2880
  const platform = dependencies.platform ?? process.platform;
2875
- if (platform !== "win32" && (resolve2(path) === resolve2(root) || isPathWithin(root, path))) {
2881
+ if (platform === "win32") {
2882
+ const existing = await lstat2(path).catch((error48) => {
2883
+ if (error48.code === "ENOENT") return null;
2884
+ throw error48;
2885
+ });
2886
+ if (!existing) {
2887
+ await ensureInferencePrivateDirectory(path, { ...dependencies, defaultRoot: root });
2888
+ return;
2889
+ }
2890
+ if (existing.isSymbolicLink() || !existing.isDirectory()) {
2891
+ throw new Error("Inference host state directory is unsafe.");
2892
+ }
2893
+ const runner = dependencies.runner ?? runWindowsPrivateAcl;
2894
+ try {
2895
+ await secureWindowsPrivatePath(path, "directory", "verify-private", platform, runner);
2896
+ } catch (error48) {
2897
+ if (!isWindowsPrivateAclVerificationFailure(error48)) throw error48;
2898
+ if ((await readdir3(path)).length > 0) {
2899
+ const recovery = /\.service-releases$/u.test(path) ? "run 'vtx inference-host service uninstall' then 'install'" : "delete this directory; it is recreated private";
2900
+ throw new Error(`updater_dir_not_private: ${recovery} (${path})`, { cause: error48 });
2901
+ }
2902
+ await secureWindowsPrivatePath(path, "directory", "harden", platform, runner);
2903
+ }
2904
+ return;
2905
+ }
2906
+ if (resolve2(path) === resolve2(root) || isPathWithin(root, path)) {
2876
2907
  const existing = await lstat2(path).catch(() => null);
2877
2908
  if (existing && existing.isDirectory() && !existing.isSymbolicLink() && (existing.mode & 63) !== 0 && (typeof process.getuid !== "function" || existing.uid === process.getuid())) {
2878
2909
  await chmod(path, 448);
@@ -2929,8 +2960,8 @@ var init_updater = __esm({
2929
2960
  } catch (error48) {
2930
2961
  if (error48.code !== "ENOENT") throw error48;
2931
2962
  }
2932
- await mkdir3(stagingPath, { recursive: true, mode: 448 });
2933
- await mkdir3(downloadPath, { recursive: true, mode: 448 });
2963
+ await ensureUpdaterPrivateDirectory(stagingPath, input.privateRoot, { platform });
2964
+ await ensureUpdaterPrivateDirectory(downloadPath, input.privateRoot, { platform });
2934
2965
  try {
2935
2966
  const packed = await runCliReleaseNpmCommand(executable, [
2936
2967
  "pack",
@@ -20407,25 +20438,25 @@ var init_external_inference_contract = __esm({
20407
20438
  // lib/inference-host/credential-store.ts
20408
20439
  import { createHash as createHash2 } from "node:crypto";
20409
20440
  import { spawn as spawn3 } from "node:child_process";
20410
- function canonicalUrl(raw, label) {
20441
+ function canonicalUrl(raw, label2) {
20411
20442
  let parsed;
20412
20443
  try {
20413
20444
  parsed = new URL(raw);
20414
20445
  } catch {
20415
- throw new Error(`${label} is invalid.`);
20446
+ throw new Error(`${label2} is invalid.`);
20416
20447
  }
20417
20448
  if (parsed.username || parsed.password || parsed.search || parsed.hash || !parsed.hostname || !["http:", "https:"].includes(parsed.protocol)) {
20418
- throw new Error(`${label} is invalid.`);
20449
+ throw new Error(`${label2} is invalid.`);
20419
20450
  }
20420
20451
  const isLoopback = ["localhost", "127.0.0.1", "[::1]"].includes(parsed.hostname);
20421
20452
  if (parsed.protocol !== "https:" && !isLoopback) {
20422
- throw new Error(`${label} must use HTTPS outside loopback.`);
20453
+ throw new Error(`${label2} must use HTTPS outside loopback.`);
20423
20454
  }
20424
20455
  return parsed.toString().replace(/\/$/u, "");
20425
20456
  }
20426
- function isoTimestamp(value, label) {
20457
+ function isoTimestamp(value, label2) {
20427
20458
  if (typeof value !== "string" || !value || !Number.isFinite(Date.parse(value))) {
20428
- throw new Error(`${label} is invalid.`);
20459
+ throw new Error(`${label2} is invalid.`);
20429
20460
  }
20430
20461
  return value;
20431
20462
  }
@@ -21396,33 +21427,33 @@ var init_crypto = __esm({
21396
21427
  // lib/inference-host/oauth.ts
21397
21428
  import { createHash as createHash4, randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
21398
21429
  import { createServer } from "node:http";
21399
- function requireObject(value, label) {
21430
+ function requireObject(value, label2) {
21400
21431
  if (!value || typeof value !== "object" || Array.isArray(value)) {
21401
- throw new Error(`${label} is invalid.`);
21432
+ throw new Error(`${label2} is invalid.`);
21402
21433
  }
21403
21434
  return value;
21404
21435
  }
21405
- function exactUrl(raw, label) {
21406
- if (typeof raw !== "string" || !raw) throw new Error(`${label} is unavailable.`);
21436
+ function exactUrl(raw, label2) {
21437
+ if (typeof raw !== "string" || !raw) throw new Error(`${label2} is unavailable.`);
21407
21438
  let parsed;
21408
21439
  try {
21409
21440
  parsed = new URL(raw);
21410
21441
  } catch {
21411
- throw new Error(`${label} is invalid.`);
21442
+ throw new Error(`${label2} is invalid.`);
21412
21443
  }
21413
21444
  if (parsed.username || parsed.password || parsed.search || parsed.hash || !parsed.hostname) {
21414
- throw new Error(`${label} is invalid.`);
21445
+ throw new Error(`${label2} is invalid.`);
21415
21446
  }
21416
21447
  const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(parsed.hostname);
21417
21448
  if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && loopback)) {
21418
- throw new Error(`${label} must use HTTPS outside loopback.`);
21449
+ throw new Error(`${label2} must use HTTPS outside loopback.`);
21419
21450
  }
21420
21451
  return parsed.toString();
21421
21452
  }
21422
- function requireSameOrigin(endpoint, issuer, label) {
21423
- const parsed = new URL(exactUrl(endpoint, label));
21453
+ function requireSameOrigin(endpoint, issuer, label2) {
21454
+ const parsed = new URL(exactUrl(endpoint, label2));
21424
21455
  if (parsed.origin !== new URL(issuer).origin) {
21425
- throw new Error(`${label} has an unexpected origin.`);
21456
+ throw new Error(`${label2} has an unexpected origin.`);
21426
21457
  }
21427
21458
  return parsed.toString();
21428
21459
  }
@@ -22158,6 +22189,9 @@ var init_runtime_policy_generated2 = __esm({
22158
22189
  evidence_max_items: 32,
22159
22190
  evidence_shared_read_seconds: 10
22160
22191
  },
22192
+ protective_plan_set_lock: {
22193
+ wait_seconds: 120
22194
+ },
22161
22195
  history_evidence: {
22162
22196
  device_rounds_per_beat: 6,
22163
22197
  device_retry_seconds: 60
@@ -33244,10 +33278,10 @@ var init_runner = __esm({
33244
33278
  if (known && (!window2 || window2.windowDurationMins !== known.windowDurationMins)) return false;
33245
33279
  return window2 === null || window2.resetsAt !== null && window2.resetsAt * 1e3 > nowMs2 && (window2.usedPercent < 100 || codexCreditsAvailable(rateLimits.rateLimits));
33246
33280
  });
33247
- finitePositiveOption = (value, fallback, label) => {
33281
+ finitePositiveOption = (value, fallback, label2) => {
33248
33282
  const result = value ?? fallback;
33249
33283
  if (!Number.isSafeInteger(result) || result < 1) {
33250
- throw new InferenceHostRunnerError("invalid_configuration", `${label} must be a positive integer.`);
33284
+ throw new InferenceHostRunnerError("invalid_configuration", `${label2} must be a positive integer.`);
33251
33285
  }
33252
33286
  return result;
33253
33287
  };
@@ -46377,10 +46411,10 @@ Durable service:
46377
46411
  vtx inference-host service recover --instance codex-1 --force-recovery
46378
46412
  vtx inference-host service <start|stop|status|logs|recover|uninstall>
46379
46413
  `;
46380
- parseHostConcurrency = (raw, label) => {
46414
+ parseHostConcurrency = (raw, label2) => {
46381
46415
  const value = Number(raw);
46382
46416
  if (!Number.isSafeInteger(value) || value < 1) {
46383
- throw new Error(`${label} must be a positive safe integer.`);
46417
+ throw new Error(`${label2} must be a positive safe integer.`);
46384
46418
  }
46385
46419
  return value;
46386
46420
  };
@@ -46688,8 +46722,8 @@ Durable service:
46688
46722
  throw new Error("Inference host revocation checkpoint does not match credential recovery.");
46689
46723
  }
46690
46724
  };
46691
- fileExistsPrivately = async (path, label) => {
46692
- const raw = await readInferencePrivateFile(path, label);
46725
+ fileExistsPrivately = async (path, label2) => {
46726
+ const raw = await readInferencePrivateFile(path, label2);
46693
46727
  return raw !== null;
46694
46728
  };
46695
46729
  inspectCodexAuthentication = async (config2) => {
@@ -50232,7 +50266,7 @@ var init_shared = __esm({
50232
50266
  runtimeRequestErrorKind: kind,
50233
50267
  runtimeRequestTransientNetwork: kind === "network" && isTransientNetworkFetchError(error48)
50234
50268
  });
50235
- buildMarketDataFetchError = async (response, label, path) => {
50269
+ buildMarketDataFetchError = async (response, label2, path) => {
50236
50270
  let responseText = "";
50237
50271
  try {
50238
50272
  responseText = (await response.clone().text()).trim();
@@ -50242,21 +50276,21 @@ var init_shared = __esm({
50242
50276
  const statusText = response.statusText ? ` ${response.statusText}` : "";
50243
50277
  const detail = responseText ? `: ${responseText.slice(0, 240)}` : "";
50244
50278
  return annotateMarketDataRequestError(
50245
- new Error(`Market data request failed: ${label} unavailable (HTTP ${response.status}${statusText})${detail}`),
50279
+ new Error(`Market data request failed: ${label2} unavailable (HTTP ${response.status}${statusText})${detail}`),
50246
50280
  path,
50247
50281
  response.status,
50248
50282
  "http"
50249
50283
  );
50250
50284
  };
50251
- buildMarketDataNetworkError = (error48, label, path) => {
50285
+ buildMarketDataNetworkError = (error48, label2, path) => {
50252
50286
  const message = error48 instanceof Error ? error48.message : String(error48 || "unknown error");
50253
50287
  return annotateMarketDataRequestError(Object.assign(
50254
- new Error(`Market data request failed: ${label} network error (${message})`),
50288
+ new Error(`Market data request failed: ${label2} network error (${message})`),
50255
50289
  { cause: error48, name: error48 instanceof Error ? error48.name : "Error" }
50256
50290
  ), path, null, "network");
50257
50291
  };
50258
- buildMarketDataResponseBodyError = (error48, label, response, path) => annotateMarketDataRequestError(Object.assign(
50259
- new Error(`Market data request failed: ${label} response body could not be read (HTTP ${response.status})`),
50292
+ buildMarketDataResponseBodyError = (error48, label2, response, path) => annotateMarketDataRequestError(Object.assign(
50293
+ new Error(`Market data request failed: ${label2} response body could not be read (HTTP ${response.status})`),
50260
50294
  { cause: error48, name: error48 instanceof Error ? error48.name : "Error" }
50261
50295
  ), path, response.status, "response_body");
50262
50296
  isTransientNetworkFetchError = (error48) => {
@@ -51171,10 +51205,10 @@ var init_network_debug = __esm({
51171
51205
  };
51172
51206
  getLatestRuntimeProviderFailureTelemetrySnapshot = (options = {}) => {
51173
51207
  const maxAgeMs = Number.isFinite(Number(options.maxAgeMs)) ? Math.max(0, Number(options.maxAgeMs)) : 5 * 60 * 1e3;
51174
- const label = typeof options.label === "string" && options.label.trim() ? options.label.trim().toLowerCase() : null;
51208
+ const label2 = typeof options.label === "string" && options.label.trim() ? options.label.trim().toLowerCase() : null;
51175
51209
  const traceId = typeof options.traceId === "string" && options.traceId.trim() ? options.traceId.trim() : null;
51176
51210
  const now = Date.now();
51177
- const candidates = getRuntimeProviderFailureDebugEntries().filter((entry) => entry.kind === "provider" && entry.outcome === "error").filter((entry) => !traceId || entry.id === traceId).filter((entry) => !label || entry.label.toLowerCase() === label).filter((entry) => Math.abs(now - (entry.completedAt ?? entry.startedAt)) <= maxAgeMs).sort((a, b2) => (b2.completedAt ?? b2.startedAt) - (a.completedAt ?? a.startedAt));
51211
+ const candidates = getRuntimeProviderFailureDebugEntries().filter((entry) => entry.kind === "provider" && entry.outcome === "error").filter((entry) => !traceId || entry.id === traceId).filter((entry) => !label2 || entry.label.toLowerCase() === label2).filter((entry) => Math.abs(now - (entry.completedAt ?? entry.startedAt)) <= maxAgeMs).sort((a, b2) => (b2.completedAt ?? b2.startedAt) - (a.completedAt ?? a.startedAt));
51178
51212
  const latest = candidates[0] ?? null;
51179
51213
  if (!latest) {
51180
51214
  return null;
@@ -52072,6 +52106,288 @@ var init_server_runtime_lease = __esm({
52072
52106
  }
52073
52107
  });
52074
52108
 
52109
+ // lib/runtime/hyperliquid-account-mode-contract.ts
52110
+ function resolveExactHyperliquidAccountMode(userAbstraction, ...dexEvidence) {
52111
+ const mode = extractCanonicalHyperliquidAccountMode(userAbstraction);
52112
+ if (!mode) {
52113
+ throw new Error("Exact Hyperliquid userAbstraction response is invalid.");
52114
+ }
52115
+ if (mode !== "default" && mode !== "disabled") return mode;
52116
+ if (dexEvidence.length < 1) {
52117
+ throw new Error("Exact Hyperliquid userDexAbstraction response is unavailable.");
52118
+ }
52119
+ return parseExactDexAbstractionEnabled(dexEvidence[0]) ? "dexAbstraction" : mode;
52120
+ }
52121
+ var UNIFIED_MODE_ALIASES, CANONICAL_ACCOUNT_MODE_ALIASES, EXACT_MODE_KEYS, EXACT_MODE_BOOLEAN_KEYS, isExactTruthyFlag, normalizeCanonicalHyperliquidAccountMode, extractCanonicalHyperliquidAccountMode, parseExactDexAbstractionEnabled, normalizeAccountMode, extractAccountModeFromPayload, extractAccountModeCandidateFromPayload, isUnifiedAccountMode;
52122
+ var init_hyperliquid_account_mode_contract = __esm({
52123
+ "lib/runtime/hyperliquid-account-mode-contract.ts"() {
52124
+ "use strict";
52125
+ init_define_VTX_EXO_POLICY();
52126
+ init_define_VTX_GROK_POLICY();
52127
+ init_define_VTX_PI_MODEL_POLICY();
52128
+ UNIFIED_MODE_ALIASES = /* @__PURE__ */ new Set([
52129
+ "unifiedaccount",
52130
+ "dexabstraction",
52131
+ "portfoliomargin",
52132
+ "unified",
52133
+ "pm"
52134
+ ]);
52135
+ CANONICAL_ACCOUNT_MODE_ALIASES = /* @__PURE__ */ new Map([
52136
+ ["default", "default"],
52137
+ ["standard", "default"],
52138
+ ["classic", "default"],
52139
+ ["disabled", "disabled"],
52140
+ ["unifiedaccount", "unifiedAccount"],
52141
+ ["unified", "unifiedAccount"],
52142
+ ["portfoliomargin", "portfolioMargin"],
52143
+ ["pm", "portfolioMargin"],
52144
+ ["dexabstraction", "dexAbstraction"]
52145
+ ]);
52146
+ EXACT_MODE_KEYS = [
52147
+ "accountMode",
52148
+ "account_mode",
52149
+ "accountType",
52150
+ "account_type",
52151
+ "accountUnificationMode",
52152
+ "account_unification_mode",
52153
+ "abstractionMode",
52154
+ "abstraction_mode",
52155
+ "abstraction",
52156
+ "abstractionState",
52157
+ "dexAbstractionState",
52158
+ "marginMode",
52159
+ "state",
52160
+ "mode",
52161
+ "value"
52162
+ ];
52163
+ EXACT_MODE_BOOLEAN_KEYS = [
52164
+ ["unifiedAccount", ["isUnifiedAccount", "unifiedAccount", "isUnified", "unified", "is_unified_account"]],
52165
+ ["portfolioMargin", ["isPortfolioMargin", "portfolioMargin", "isPm", "pm", "is_portfolio_margin"]],
52166
+ ["dexAbstraction", ["isDexAbstraction", "dexAbstraction", "dexAbstractionEnabled", "is_dex_abstraction"]],
52167
+ ["default", ["isClassic", "classic", "isStandard", "standard"]]
52168
+ ];
52169
+ isExactTruthyFlag = (value) => value === true || value === 1 || typeof value === "string" && value.trim().toLowerCase() === "true";
52170
+ normalizeCanonicalHyperliquidAccountMode = (value) => {
52171
+ if (typeof value !== "string") return null;
52172
+ const key = value.trim().replace(/[_\s-]/g, "").toLowerCase();
52173
+ return CANONICAL_ACCOUNT_MODE_ALIASES.get(key) ?? null;
52174
+ };
52175
+ extractCanonicalHyperliquidAccountMode = (payload, depth = 0) => {
52176
+ if (depth > 6) return null;
52177
+ const direct = normalizeCanonicalHyperliquidAccountMode(payload);
52178
+ if (direct) return direct;
52179
+ if (Array.isArray(payload)) {
52180
+ for (const item of payload) {
52181
+ const mode = extractCanonicalHyperliquidAccountMode(item, depth + 1);
52182
+ if (mode) return mode;
52183
+ }
52184
+ return null;
52185
+ }
52186
+ if (!payload || typeof payload !== "object") return null;
52187
+ const source = payload;
52188
+ for (const key of EXACT_MODE_KEYS) {
52189
+ if (!(key in source)) continue;
52190
+ const mode = normalizeCanonicalHyperliquidAccountMode(source[key]);
52191
+ if (mode) return mode;
52192
+ }
52193
+ for (const [mode, keys] of EXACT_MODE_BOOLEAN_KEYS) {
52194
+ for (const key of keys) {
52195
+ if (isExactTruthyFlag(source[key])) return mode;
52196
+ }
52197
+ }
52198
+ for (const value of Object.values(source)) {
52199
+ const mode = extractCanonicalHyperliquidAccountMode(value, depth + 1);
52200
+ if (mode) return mode;
52201
+ }
52202
+ return null;
52203
+ };
52204
+ parseExactDexAbstractionEnabled = (payload) => {
52205
+ if (payload == null || payload === false) return false;
52206
+ if (payload === true) return true;
52207
+ if (typeof payload === "string") {
52208
+ const normalized = payload.trim().toLowerCase();
52209
+ if (normalized === "true") return true;
52210
+ if (normalized === "false") return false;
52211
+ }
52212
+ if (typeof payload === "number" && Number.isFinite(payload)) {
52213
+ if (payload === 1) return true;
52214
+ if (payload === 0) return false;
52215
+ }
52216
+ throw new Error("Exact Hyperliquid userDexAbstraction response is invalid.");
52217
+ };
52218
+ normalizeAccountMode = (mode) => String(mode ?? "").trim().toLowerCase().replace(/[_\s-]/g, "");
52219
+ extractAccountModeFromPayload = (payload) => {
52220
+ const candidate = extractAccountModeCandidateFromPayload(payload);
52221
+ if (candidate && candidate.trim().length > 0) {
52222
+ return candidate;
52223
+ }
52224
+ return "default";
52225
+ };
52226
+ extractAccountModeCandidateFromPayload = (payload) => {
52227
+ if (!payload || typeof payload !== "object") {
52228
+ return null;
52229
+ }
52230
+ const source = payload;
52231
+ if ("accountMode" in source) {
52232
+ return String(source.accountMode ?? "");
52233
+ }
52234
+ if ("account_mode" in source) {
52235
+ return String(source.account_mode ?? "");
52236
+ }
52237
+ return null;
52238
+ };
52239
+ isUnifiedAccountMode = (mode) => UNIFIED_MODE_ALIASES.has(normalizeAccountMode(mode));
52240
+ }
52241
+ });
52242
+
52243
+ // lib/runtime/hyperliquid-account-contract.ts
52244
+ var toNumber, firstNumber, roundTo, canonicalAvailableMargin, STABLE_SPOT_SYMBOLS, spotBalanceValueUsd, normalizeSpotBalancesFromInfoResponse, sumBalanceHoldUsd, sumPositionUnrealizedPnl, resolveTotalUnrealizedPnl, approximatelyEqualAccountValues, buildAccountSummaryFromInfoResponses;
52245
+ var init_hyperliquid_account_contract = __esm({
52246
+ "lib/runtime/hyperliquid-account-contract.ts"() {
52247
+ "use strict";
52248
+ init_define_VTX_EXO_POLICY();
52249
+ init_define_VTX_GROK_POLICY();
52250
+ init_define_VTX_PI_MODEL_POLICY();
52251
+ init_hyperliquid_account_mode_contract();
52252
+ toNumber = (value, fallback = 0) => {
52253
+ const numeric2 = Number(value);
52254
+ return Number.isFinite(numeric2) ? numeric2 : fallback;
52255
+ };
52256
+ firstNumber = (values, fallback = 0) => {
52257
+ for (const value of values) {
52258
+ if (value == null || typeof value === "string" && value.trim() === "") {
52259
+ continue;
52260
+ }
52261
+ const numeric2 = Number(value);
52262
+ if (Number.isFinite(numeric2)) {
52263
+ return numeric2;
52264
+ }
52265
+ }
52266
+ return fallback;
52267
+ };
52268
+ roundTo = (value, digits = 12) => Number(value.toFixed(digits));
52269
+ canonicalAvailableMargin = (accountValue, totalMarginUsed) => Math.max(0, accountValue - totalMarginUsed);
52270
+ STABLE_SPOT_SYMBOLS = /* @__PURE__ */ new Set(["USDC", "USD", "USDT"]);
52271
+ spotBalanceValueUsd = (balance, coin, total) => {
52272
+ const explicit = firstNumber([balance?.value_usd, balance?.usdValue, balance?.usdcValue], Number.NaN);
52273
+ if (Number.isFinite(explicit)) {
52274
+ return explicit;
52275
+ }
52276
+ return STABLE_SPOT_SYMBOLS.has(coin) ? total : 0;
52277
+ };
52278
+ normalizeSpotBalancesFromInfoResponse = (spotResponse) => {
52279
+ const containers = [];
52280
+ if (spotResponse && typeof spotResponse === "object") {
52281
+ containers.push(spotResponse);
52282
+ const keys = ["spotState", "userState", "clearinghouseState", "state", "data"];
52283
+ for (const key of keys) {
52284
+ if (spotResponse[key] && typeof spotResponse[key] === "object") {
52285
+ containers.push(spotResponse[key]);
52286
+ }
52287
+ }
52288
+ }
52289
+ const firstWithBalances = containers.find((container) => Array.isArray(container?.balances));
52290
+ const balances = Array.isArray(firstWithBalances?.balances) ? firstWithBalances.balances : [];
52291
+ return balances.map((balance) => {
52292
+ const coin = String(balance?.coin ?? "").toUpperCase();
52293
+ const total = toNumber(balance?.total, 0);
52294
+ const hold = toNumber(balance?.hold, 0);
52295
+ const available = roundTo(Math.max(0, total - hold));
52296
+ const value_usd = spotBalanceValueUsd(balance, coin, total);
52297
+ return {
52298
+ coin,
52299
+ total,
52300
+ hold,
52301
+ available,
52302
+ value_usd
52303
+ };
52304
+ }).filter((balance) => balance.coin.length > 0);
52305
+ };
52306
+ sumBalanceHoldUsd = (balances) => balances.reduce((acc, balance) => {
52307
+ const hold = toNumber(balance.hold, 0);
52308
+ const total = toNumber(balance.total, 0);
52309
+ const valueUsd = toNumber(balance.value_usd, 0);
52310
+ if (hold <= 0 || total <= 0 || valueUsd <= 0) {
52311
+ return acc;
52312
+ }
52313
+ return acc + Math.max(0, valueUsd * (hold / total));
52314
+ }, 0);
52315
+ sumPositionUnrealizedPnl = (perpsResponse) => {
52316
+ const assetPositions = Array.isArray(perpsResponse?.assetPositions) ? perpsResponse.assetPositions : [];
52317
+ return assetPositions.reduce((total, entry) => {
52318
+ const unrealizedPnl = toNumber(entry?.position?.unrealizedPnl, 0);
52319
+ return total + unrealizedPnl;
52320
+ }, 0);
52321
+ };
52322
+ resolveTotalUnrealizedPnl = (perpsResponse) => {
52323
+ const topLevel = toNumber(perpsResponse?.totalUnrealizedPnl, 0);
52324
+ const positionTotal = sumPositionUnrealizedPnl(perpsResponse);
52325
+ if (Math.abs(topLevel) < 1e-12 && Math.abs(positionTotal) >= 1e-12) {
52326
+ return positionTotal;
52327
+ }
52328
+ return topLevel;
52329
+ };
52330
+ approximatelyEqualAccountValues = (left, right, absoluteToleranceUsd, relativeTolerance) => {
52331
+ const reference = Math.max(Math.abs(left), Math.abs(right), 1);
52332
+ return Math.abs(left - right) <= Math.max(
52333
+ absoluteToleranceUsd,
52334
+ reference * relativeTolerance
52335
+ );
52336
+ };
52337
+ buildAccountSummaryFromInfoResponses = (perpsResponse, spotResponse, options = {}) => {
52338
+ const marginSummary = perpsResponse?.marginSummary ?? {};
52339
+ const perpsAccountValue = toNumber(marginSummary?.accountValue, 0);
52340
+ const total_margin_used = toNumber(marginSummary?.totalMarginUsed, 0);
52341
+ const totalNtlPos = toNumber(marginSummary?.totalNtlPos, 0);
52342
+ const withdrawable = toNumber(perpsResponse?.withdrawable, 0);
52343
+ const maintenance_margin = firstNumber([
52344
+ perpsResponse?.crossMaintenanceMarginUsed,
52345
+ marginSummary?.crossMaintenanceMarginUsed,
52346
+ marginSummary?.totalMaintenanceMargin
52347
+ ], 0);
52348
+ const balances = normalizeSpotBalancesFromInfoResponse(spotResponse);
52349
+ const spotPortfolioValue = balances.reduce((acc, balance) => acc + toNumber(balance.value_usd, 0), 0);
52350
+ const balancesHoldUsd = sumBalanceHoldUsd(balances);
52351
+ const account_mode = extractAccountModeFromPayload(perpsResponse);
52352
+ const crossMarginSummary = perpsResponse?.crossMarginSummary && typeof perpsResponse.crossMarginSummary === "object" ? perpsResponse.crossMarginSummary : null;
52353
+ const crossMarginAccountValue = crossMarginSummary ? toNumber(crossMarginSummary.accountValue, 0) : 0;
52354
+ const normalizedMode = String(account_mode || "").trim().toLowerCase().replace(/[_\s-]/g, "");
52355
+ const isAmbiguousDefaultMode = normalizedMode.length === 0 || normalizedMode === "default";
52356
+ const spotDominatesMinTotalUsd = Number(options.spotDominatesMinTotalUsd ?? options.spot_dominates_min_total_usd);
52357
+ const spotDominatesPerpsMultiplier = Number(options.spotDominatesPerpsMultiplier ?? options.spot_dominates_perps_multiplier);
52358
+ const mirroredAccountValueAbsoluteToleranceUsd = Number(
52359
+ options.mirroredAccountValueAbsoluteToleranceUsd ?? options.mirrored_account_value_absolute_tolerance_usd
52360
+ );
52361
+ const mirroredAccountValueRelativeTolerance = Number(
52362
+ options.mirroredAccountValueRelativeTolerance ?? options.mirrored_account_value_relative_tolerance
52363
+ );
52364
+ const hasSpotDominanceThresholds = Number.isFinite(spotDominatesMinTotalUsd) && spotDominatesMinTotalUsd >= 0 && Number.isFinite(spotDominatesPerpsMultiplier) && spotDominatesPerpsMultiplier >= 0;
52365
+ const hasMirroredAccountValueTolerances = Number.isFinite(mirroredAccountValueAbsoluteToleranceUsd) && mirroredAccountValueAbsoluteToleranceUsd >= 0 && Number.isFinite(mirroredAccountValueRelativeTolerance) && mirroredAccountValueRelativeTolerance >= 0;
52366
+ const spotDominatesPerps = hasSpotDominanceThresholds && spotPortfolioValue >= spotDominatesMinTotalUsd && (perpsAccountValue <= 0 || spotPortfolioValue >= perpsAccountValue * spotDominatesPerpsMultiplier);
52367
+ const ambiguousDefaultLooksUnified = isAmbiguousDefaultMode && spotDominatesPerps;
52368
+ const ambiguousDefaultSpotAlreadyIncludesPerps = ambiguousDefaultLooksUnified && perpsAccountValue > 0 && balancesHoldUsd > 0 && hasMirroredAccountValueTolerances && approximatelyEqualAccountValues(
52369
+ balancesHoldUsd,
52370
+ perpsAccountValue,
52371
+ mirroredAccountValueAbsoluteToleranceUsd,
52372
+ mirroredAccountValueRelativeTolerance
52373
+ );
52374
+ const account_value = isUnifiedAccountMode(account_mode) && crossMarginSummary !== null && crossMarginAccountValue > 0 ? crossMarginAccountValue + spotPortfolioValue : ambiguousDefaultLooksUnified && !ambiguousDefaultSpotAlreadyIncludesPerps ? perpsAccountValue + spotPortfolioValue : Math.max(perpsAccountValue, spotPortfolioValue);
52375
+ return {
52376
+ account_value,
52377
+ total_margin_used,
52378
+ available_margin: roundTo(canonicalAvailableMargin(account_value, total_margin_used)),
52379
+ withdrawable,
52380
+ cross_margin_ratio: account_value > 0 ? maintenance_margin / account_value : 0,
52381
+ maintenance_margin,
52382
+ cross_account_leverage: account_value > 0 ? totalNtlPos / account_value : 0,
52383
+ total_unrealized_pnl: resolveTotalUnrealizedPnl(perpsResponse),
52384
+ account_mode,
52385
+ balances
52386
+ };
52387
+ };
52388
+ }
52389
+ });
52390
+
52075
52391
  // lib/runtime/order-identity.ts
52076
52392
  var clientOrderIdForMutation, clientDecisionMutationId;
52077
52393
  var init_order_identity = __esm({
@@ -52147,7 +52463,7 @@ var init_hyperliquid_order_status = __esm({
52147
52463
  });
52148
52464
 
52149
52465
  // lib/runtime/hyperliquid-public-read.ts
52150
- var policy, weights, recoveryPolicy, budgets, unpersistedBudgets, cache, pending2, PREFIX, priorityRank, createHyperliquidPublicPriorityScope, promoteHyperliquidPublicPriority, abortError2, checkAbort, wait, waitUnlessPromoted, storage, loadBudget, saveBudget, withBudgetLock, HyperliquidPublicReadError, getHyperliquidPublicReadBudget, cooldownError, recoveryWaitError, nonTradingWeightCap, nonTradingWaitMs, fallbackDelayMs, admit, cooldown, finishHyperliquidRecoveryRequest, assertHyperliquidRecoveryDispatch, cacheTtlMs, eligibleCache, reserveHyperliquidPublicReads, releaseHyperliquidPublicReadReservation, admitHyperliquidExchangeRequest, recordHyperliquidExchangeResponse, readHyperliquidPublicInfo;
52466
+ var policy, weights, recoveryPolicy, budgets, unpersistedBudgets, cache, pending2, PREFIX, priorityRank, createHyperliquidPublicPriorityScope, promoteHyperliquidPublicPriority, hostTransport, abortError2, checkAbort, wait, waitUnlessPromoted, storage, loadBudget, saveBudget, withBudgetLock, HyperliquidPublicReadError, getHyperliquidPublicReadBudget, cooldownError, recoveryWaitError, nonTradingWeightCap, nonTradingWaitMs, fallbackDelayMs, admit, cooldown, finishHyperliquidRecoveryRequest, assertHyperliquidRecoveryDispatch, validateHyperliquidRecoveryDispatch, cacheTtlMs, eligibleCache, reserveHyperliquidPublicReads, releaseHyperliquidPublicReadReservation, admitHyperliquidExchangeRequest, recordHyperliquidExchangeResponse, readHyperliquidPublicInfo;
52151
52467
  var init_hyperliquid_public_read = __esm({
52152
52468
  "lib/runtime/hyperliquid-public-read.ts"() {
52153
52469
  "use strict";
@@ -52171,6 +52487,7 @@ var init_hyperliquid_public_read = __esm({
52171
52487
  scope.value = priority;
52172
52488
  scope.followers?.forEach((promote) => promote(priority));
52173
52489
  };
52490
+ hostTransport = null;
52174
52491
  abortError2 = (signal) => getSanitizedRuntimeAbortReason(signal, "Aborted");
52175
52492
  checkAbort = (signal) => {
52176
52493
  if (signal?.aborted) throw abortError2(signal);
@@ -52308,6 +52625,10 @@ var init_hyperliquid_public_read = __esm({
52308
52625
  const weight = weightOverride ?? weights[requestType] ?? policy.default_request_weight;
52309
52626
  const ticket = crypto.randomUUID();
52310
52627
  const deadline = Math.min(deadlineMs ?? Infinity, Date.now() + recoveryPolicy.recovery_queue_wait_seconds * 1e3);
52628
+ if (hostTransport) {
52629
+ const permit = await hostTransport.admission.acquire({ requestType, weight, priority: priority.value, deadlineMs: deadline, signal });
52630
+ return { ...permit, endpoint: apiUrl, fleet: true };
52631
+ }
52311
52632
  let admitted = false;
52312
52633
  try {
52313
52634
  for (; ; ) {
@@ -52378,7 +52699,11 @@ var init_hyperliquid_public_read = __esm({
52378
52699
  });
52379
52700
  }
52380
52701
  };
52381
- cooldown = async (apiUrl, retryAfter) => {
52702
+ cooldown = async (apiUrl, retryAfter, requestType) => {
52703
+ if (hostTransport) {
52704
+ await hostTransport.admission.record429(retryAfter, requestType);
52705
+ return;
52706
+ }
52382
52707
  const key = `${PREFIX}${apiUrl}`;
52383
52708
  await withBudgetLock(key, void 0, () => {
52384
52709
  const now = Date.now();
@@ -52404,6 +52729,11 @@ var init_hyperliquid_public_read = __esm({
52404
52729
  };
52405
52730
  finishHyperliquidRecoveryRequest = async (permit, outcome) => {
52406
52731
  if (!permit) return;
52732
+ if (permit.fleet) {
52733
+ if (!hostTransport) throw new Error("A fleet Hyperliquid permit needs the host transport that issued it.");
52734
+ await hostTransport.admission.finish(permit, outcome);
52735
+ return;
52736
+ }
52407
52737
  const key = `${PREFIX}${permit.endpoint}`;
52408
52738
  await withBudgetLock(key, void 0, () => {
52409
52739
  const budget = loadBudget(key);
@@ -52440,6 +52770,15 @@ var init_hyperliquid_public_read = __esm({
52440
52770
  }
52441
52771
  if (!permit && budget.recovery) throw recoveryWaitError(requestType);
52442
52772
  };
52773
+ validateHyperliquidRecoveryDispatch = async (endpoint, permit, requestType) => {
52774
+ if (permit?.fleet) {
52775
+ if (!hostTransport) throw recoveryWaitError(requestType);
52776
+ await hostTransport.admission.validate(permit, requestType);
52777
+ return;
52778
+ }
52779
+ if (hostTransport) throw recoveryWaitError(requestType);
52780
+ assertHyperliquidRecoveryDispatch(endpoint, permit, requestType);
52781
+ };
52443
52782
  cacheTtlMs = (body, options) => {
52444
52783
  const requestType = String(body.type);
52445
52784
  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;
@@ -52469,7 +52808,7 @@ var init_hyperliquid_public_read = __esm({
52469
52808
  return admit(endpoint.replace(/\/$/, ""), "exchange", signal, weight, void 0, createHyperliquidPublicPriorityScope(priority));
52470
52809
  };
52471
52810
  recordHyperliquidExchangeResponse = async (endpoint, response, permit) => {
52472
- if (response.status === 429) await cooldown(endpoint.replace(/\/$/, ""), response.headers.get("Retry-After"));
52811
+ if (response.status === 429) await cooldown(endpoint.replace(/\/$/, ""), response.headers.get("Retry-After"), "exchange");
52473
52812
  await finishHyperliquidRecoveryRequest(permit, response.status < 400 ? "success" : "failure");
52474
52813
  };
52475
52814
  readHyperliquidPublicInfo = async (endpoint, body, options) => {
@@ -52503,6 +52842,7 @@ var init_hyperliquid_public_read = __esm({
52503
52842
  let settled;
52504
52843
  let acquiring = false;
52505
52844
  let observedRateLimit;
52845
+ let privateRouteUsed = false;
52506
52846
  let pendingPhase = null;
52507
52847
  const setPendingPhase = (next) => {
52508
52848
  if (next === pendingPhase) return;
@@ -52547,14 +52887,18 @@ var init_hyperliquid_public_read = __esm({
52547
52887
  }), priority });
52548
52888
  }
52549
52889
  if (options.reservation?.closed) throw new DOMException("Hyperliquid account read was cancelled.", "AbortError");
52550
- acquiring = true;
52551
- setPendingPhase("admission");
52552
- permit = await admit(apiUrl, requestType, signal, void 0, deadline, priority);
52553
- acquiring = false;
52554
- armDeadline(Math.min(deadline, permit?.expiresAt ?? Infinity));
52555
- checkAbort(signal);
52556
- if (options.reservation?.closed) throw new DOMException("Hyperliquid account read was cancelled.", "AbortError");
52557
- assertHyperliquidRecoveryDispatch(apiUrl, permit, requestType);
52890
+ const privateRoute = await hostTransport?.routeInfo?.(body, priority.value, deadline) ?? null;
52891
+ privateRouteUsed = privateRoute !== null;
52892
+ if (!privateRoute) {
52893
+ acquiring = true;
52894
+ setPendingPhase("admission");
52895
+ permit = await admit(apiUrl, requestType, signal, void 0, deadline, priority);
52896
+ acquiring = false;
52897
+ armDeadline(Math.min(deadline, permit?.expiresAt ?? Infinity));
52898
+ checkAbort(signal);
52899
+ if (options.reservation?.closed) throw new DOMException("Hyperliquid account read was cancelled.", "AbortError");
52900
+ await validateHyperliquidRecoveryDispatch(apiUrl, permit, requestType);
52901
+ }
52558
52902
  outcome = "failure";
52559
52903
  let transportAborted;
52560
52904
  let response;
@@ -52567,16 +52911,16 @@ var init_hyperliquid_public_read = __esm({
52567
52911
  });
52568
52912
  const transport = (async () => {
52569
52913
  setPendingPhase("transport");
52570
- const received = await fetch(`${apiUrl}/info`, {
52914
+ const received = await fetch(`${privateRoute?.url.replace(/\/$/, "") ?? apiUrl}/info`, {
52571
52915
  method: "POST",
52572
- headers: { "Content-Type": "application/json" },
52916
+ headers: { ...privateRoute?.headers, "Content-Type": "application/json" },
52573
52917
  body: JSON.stringify(body),
52574
52918
  signal
52575
52919
  });
52576
52920
  checkAbort(signal);
52577
52921
  if (received.status === 429) {
52578
52922
  observedRateLimit = new HyperliquidPublicReadError("public_rate_limited", "Hyperliquid public API returned HTTP 429.", requestType, 429);
52579
- await cooldown(apiUrl, received.headers.get("Retry-After"));
52923
+ if (!privateRoute) await cooldown(apiUrl, received.headers.get("Retry-After"), requestType);
52580
52924
  throw observedRateLimit;
52581
52925
  }
52582
52926
  let receivedText;
@@ -52623,6 +52967,13 @@ var init_hyperliquid_public_read = __esm({
52623
52967
  outcome = "cancelled";
52624
52968
  throw abortError2(options.signal);
52625
52969
  }
52970
+ const failedStatus = error48?.status;
52971
+ if (outcome === "failure" && privateRouteUsed && !(typeof failedStatus === "number" && failedStatus < 500)) {
52972
+ try {
52973
+ hostTransport?.onPrivateInfoFailure?.(body);
52974
+ } catch {
52975
+ }
52976
+ }
52626
52977
  if (acquiring && signal.aborted && signal.reason?.name === "TimeoutError") throw recoveryWaitError(requestType);
52627
52978
  if (error48 instanceof HyperliquidPublicReadError) throw error48;
52628
52979
  if (error48 instanceof TypeError) throw new HyperliquidPublicReadError("public_network_error", "Hyperliquid public request network failure.", requestType);
@@ -52646,6 +52997,32 @@ var init_hyperliquid_public_read = __esm({
52646
52997
  }
52647
52998
  });
52648
52999
 
53000
+ // lib/runtime/hyperliquid-exchange-rejections.ts
53001
+ var listeners, onHyperliquidExchangeRejection, emitHyperliquidExchangeRejection;
53002
+ var init_hyperliquid_exchange_rejections = __esm({
53003
+ "lib/runtime/hyperliquid-exchange-rejections.ts"() {
53004
+ "use strict";
53005
+ init_define_VTX_EXO_POLICY();
53006
+ init_define_VTX_GROK_POLICY();
53007
+ init_define_VTX_PI_MODEL_POLICY();
53008
+ listeners = /* @__PURE__ */ new Set();
53009
+ onHyperliquidExchangeRejection = (listener) => {
53010
+ listeners.add(listener);
53011
+ return () => {
53012
+ listeners.delete(listener);
53013
+ };
53014
+ };
53015
+ emitHyperliquidExchangeRejection = (message) => {
53016
+ for (const listener of listeners) {
53017
+ try {
53018
+ listener(message);
53019
+ } catch {
53020
+ }
53021
+ }
53022
+ };
53023
+ }
53024
+ });
53025
+
52649
53026
  // lib/runtime/hyperliquid-market-symbol.ts
52650
53027
  var configuredCaseSensitiveSymbols, isHyperliquidSpotSymbol, normalizeCaseSensitiveSymbols, configureHyperliquidMarketSymbolCasing, canonicalBaseSymbol, normalizeHyperliquidMarketSymbol, getHyperliquidMarketDex;
52651
53028
  var init_hyperliquid_market_symbol = __esm({
@@ -54091,7 +54468,7 @@ function getNumber(value, name) {
54091
54468
  }
54092
54469
  assertArgument(false, "invalid numeric value", name || "value", value);
54093
54470
  }
54094
- function toNumber(value) {
54471
+ function toNumber2(value) {
54095
54472
  return getNumber(toBigInt(value));
54096
54473
  }
54097
54474
  function toBeHex(_value, _width) {
@@ -56513,7 +56890,7 @@ var init_abstract_coder = __esm({
56513
56890
  return toBigInt(this.readBytes(WordSize));
56514
56891
  }
56515
56892
  readIndex() {
56516
- return toNumber(this.readBytes(WordSize));
56893
+ return toNumber2(this.readBytes(WordSize));
56517
56894
  }
56518
56895
  };
56519
56896
  }
@@ -63801,8 +64178,8 @@ function split2(name, nf, ef) {
63801
64178
  if (!name) return [];
63802
64179
  init();
63803
64180
  let offset = 0;
63804
- return name.split(STOP_CH).map((label) => {
63805
- let input = explode_cp(label);
64181
+ return name.split(STOP_CH).map((label2) => {
64182
+ let input = explode_cp(label2);
63806
64183
  let info = {
63807
64184
  input,
63808
64185
  offset
@@ -69477,8 +69854,8 @@ var init_contract = __esm({
69477
69854
  }
69478
69855
  const { subs } = getInternal(this);
69479
69856
  let total = 0;
69480
- for (const { listeners: listeners2 } of subs.values()) {
69481
- total += listeners2.length;
69857
+ for (const { listeners: listeners3 } of subs.values()) {
69858
+ total += listeners3.length;
69482
69859
  }
69483
69860
  return total;
69484
69861
  }
@@ -69496,8 +69873,8 @@ var init_contract = __esm({
69496
69873
  }
69497
69874
  const { subs } = getInternal(this);
69498
69875
  let result = [];
69499
- for (const { listeners: listeners2 } of subs.values()) {
69500
- result = result.concat(listeners2.map(({ listener }) => listener));
69876
+ for (const { listeners: listeners3 } of subs.values()) {
69877
+ result = result.concat(listeners3.map(({ listener }) => listener));
69501
69878
  }
69502
69879
  return result;
69503
69880
  }
@@ -72334,8 +72711,8 @@ var init_abstract_provider = __esm({
72334
72711
  return sub.listeners.length;
72335
72712
  }
72336
72713
  let total = 0;
72337
- for (const { listeners: listeners2 } of this.#subs.values()) {
72338
- total += listeners2.length;
72714
+ for (const { listeners: listeners3 } of this.#subs.values()) {
72715
+ total += listeners3.length;
72339
72716
  }
72340
72717
  return total;
72341
72718
  }
@@ -72348,8 +72725,8 @@ var init_abstract_provider = __esm({
72348
72725
  return sub.listeners.map(({ listener }) => listener);
72349
72726
  }
72350
72727
  let result = [];
72351
- for (const { listeners: listeners2 } of this.#subs.values()) {
72352
- result = result.concat(listeners2.map(({ listener }) => listener));
72728
+ for (const { listeners: listeners3 } of this.#subs.values()) {
72729
+ result = result.concat(listeners3.map(({ listener }) => listener));
72353
72730
  }
72354
72731
  return result;
72355
72732
  }
@@ -82950,7 +83327,7 @@ __export(ethers_exports, {
82950
83327
  toBeArray: () => toBeArray,
82951
83328
  toBeHex: () => toBeHex,
82952
83329
  toBigInt: () => toBigInt,
82953
- toNumber: () => toNumber,
83330
+ toNumber: () => toNumber2,
82954
83331
  toQuantity: () => toQuantity,
82955
83332
  toTwos: () => toTwos,
82956
83333
  toUtf8Bytes: () => toUtf8Bytes,
@@ -83168,7 +83545,7 @@ __export(lib_exports, {
83168
83545
  toBeArray: () => toBeArray,
83169
83546
  toBeHex: () => toBeHex,
83170
83547
  toBigInt: () => toBigInt,
83171
- toNumber: () => toNumber,
83548
+ toNumber: () => toNumber2,
83172
83549
  toQuantity: () => toQuantity,
83173
83550
  toTwos: () => toTwos,
83174
83551
  toUtf8Bytes: () => toUtf8Bytes,
@@ -83871,9 +84248,9 @@ var init_hyperliquid_signer = __esm({
83871
84248
  { name: "connectionId", type: "bytes32" }
83872
84249
  ]
83873
84250
  };
83874
- assertUint64 = (value, label) => {
84251
+ assertUint64 = (value, label2) => {
83875
84252
  if (!Number.isInteger(value) || value < 0) {
83876
- throw new Error(`${label} must be a non-negative integer.`);
84253
+ throw new Error(`${label2} must be a non-negative integer.`);
83877
84254
  }
83878
84255
  };
83879
84256
  concatBytes3 = (...parts) => {
@@ -83898,10 +84275,10 @@ var init_hyperliquid_signer = __esm({
83898
84275
  }
83899
84276
  return bytes3;
83900
84277
  };
83901
- hexToBytes2 = (value, label) => {
84278
+ hexToBytes2 = (value, label2) => {
83902
84279
  const normalized = value.trim().replace(/^0x/i, "");
83903
84280
  if (!normalized || normalized.length % 2 !== 0 || /[^0-9a-f]/i.test(normalized)) {
83904
- throw new Error(`Invalid ${label}.`);
84281
+ throw new Error(`Invalid ${label2}.`);
83905
84282
  }
83906
84283
  const bytes3 = new Uint8Array(normalized.length / 2);
83907
84284
  for (let index = 0; index < normalized.length; index += 2) {
@@ -84130,19 +84507,21 @@ var init_hyperliquid_signer = __esm({
84130
84507
  });
84131
84508
 
84132
84509
  // lib/runtime/hyperliquid-client.ts
84133
- var HyperliquidExchangeRejectionError, durableMutationAuthorityArgs, assertFreshPreparedExecutionContext, normalizeSymbol, HYPERLIQUID_NONCE_STORAGE_KEY, HYPERLIQUID_NONCE_LOCK_NAME, lastGeneratedNonce, readBrowserStoredHyperliquidNonce, writeBrowserStoredHyperliquidNonce, browserNonceCoordinator, allocateHyperliquidNonce, generateHyperliquidNonce, normalizeDecimalString, HYPERLIQUID_PRICE_SIGNIFICANT_FIGURES, HYPERLIQUID_INTEGER_PRICE_MINIMUM, shortestDecimalParts, formatHyperliquidPerpPriceGrid, formatHyperliquidTriggerPriceWire, hyperliquidOrderPriceRounding, formatHyperliquidOrderPriceWire, countSignificantDigits, countDecimalPlaces, validateHyperliquidPerpPriceWire, validateHyperliquidSizeWire, formatSizeWire, inferApiUrl, inferIsTestnet, postHyperliquidInfoRead, postHyperliquidInfo, fetchBrowserHyperliquidInfoPayload, fetchBrowserHyperliquidInfoText, toFiniteNumber, OPEN_ORDER_NUMERIC_STRING, OPEN_ORDER_ID_STRING, parseCanonicalOpenOrderId, parseOpenOrderFiniteNumber, parseOpenOrderPositiveNumber, parseOpenOrderPresentationNumber, readOpenOrderField, firstFiniteNumber, parseFundingUsdcFromInfoPosition, isExchangeIsolatedOnly, computeHip3AssetId, getPerpDexIndexMap, buildAssetInfosFromMetaResponse, requireWalletAddress, assertPositiveInteger, assertPositiveNumber, normalizeOrderSide, normalizeHyperliquidClientOrderId, resolveAssets, findResolvedAsset, normalizeExecutionAssetMetadata, resolveHyperliquidAsset, resolveHyperliquidAssetIndex, decimalUnits, quantizeHyperliquidOrderSizeValue, finitePositive, readDevicePrivateExecutionContext, quantizeHyperliquidOrderSize, fetchBrowserAvailableAssets, fetchBrowserAllMids, fetchBrowserSymbolMidPrice, fetchBrowserOpenOrders, parseCanonicalHyperliquidOrderStatusEvidence, fetchBrowserOrderStatusEvidence, fetchBrowserUserRole, fetchBrowserAccountState, fetchBrowserPosition, buildHyperliquidOrderWire, buildHyperliquidTriggerOrderWire, signHyperliquidPayload, signHyperliquidPreparedAction, buildHyperliquidCancelPayload, buildHyperliquidUpdateLeveragePayload, buildHyperliquidMarketOrderPayload, buildHyperliquidLimitOrderPayload, buildHyperliquidTriggerOrderPayload, buildHyperliquidOrderBatchPayload, buildHyperliquidModifyOrderPayload, extractHyperliquidExchangeError, resolveHyperliquidTriggerAcknowledgements, isDefinitiveHyperliquidExchangeResponse, extractDefinitiveHyperliquidOrderId, CANONICAL_POSITIVE_DECIMAL_PATTERN, extractCanonicalHyperliquidOrderStateAcknowledgement, extractCanonicalHyperliquidOrderStateAcknowledgements, extractCanonicalHyperliquidFilledOrderAcknowledgement, extractDefinitiveHyperliquidOrderMemberResults, buildHyperliquidOrderDiagnostics, loadClientExecutionReferenceEvidence, sha256Hex, extractSignedPayloadClientOrderId, extractSignedPayloadMutationCorrelation, assertDurableMutationMatchesSignedAction, exchangeRejectionReason, exchangeActionPriority, submitHyperliquidExchangePayload;
84510
+ var HyperliquidExchangeRejectionError, durableMutationAuthorityArgs, assertFreshPreparedExecutionContext, normalizeSymbol, HYPERLIQUID_NONCE_STORAGE_KEY, HYPERLIQUID_NONCE_LOCK_NAME, lastGeneratedNonce, readBrowserStoredHyperliquidNonce, writeBrowserStoredHyperliquidNonce, browserNonceCoordinator, allocateHyperliquidNonce, hostNonceAllocator, allocateActionNonce, generateHyperliquidNonce, normalizeDecimalString, HYPERLIQUID_PRICE_SIGNIFICANT_FIGURES, HYPERLIQUID_INTEGER_PRICE_MINIMUM, shortestDecimalParts, formatHyperliquidPerpPriceGrid, formatHyperliquidTriggerPriceWire, hyperliquidOrderPriceRounding, formatHyperliquidOrderPriceWire, countSignificantDigits, countDecimalPlaces, validateHyperliquidPerpPriceWire, validateHyperliquidSizeWire, formatSizeWire, inferApiUrl, inferIsTestnet, postHyperliquidInfoRead, postHyperliquidInfo, fetchBrowserHyperliquidInfoPayload, fetchBrowserHyperliquidInfoText, toFiniteNumber, OPEN_ORDER_NUMERIC_STRING, OPEN_ORDER_ID_STRING, parseCanonicalOpenOrderId, parseOpenOrderFiniteNumber, parseOpenOrderPositiveNumber, parseOpenOrderPresentationNumber, readOpenOrderField, firstFiniteNumber, parseFundingUsdcFromInfoPosition, isExchangeIsolatedOnly, computeHip3AssetId, getPerpDexIndexMap, buildAssetInfosFromMetaResponse, requireWalletAddress, assertPositiveInteger, assertPositiveNumber, normalizeOrderSide, normalizeHyperliquidClientOrderId, resolveAssets, findResolvedAsset, normalizeExecutionAssetMetadata, resolveHyperliquidAsset, resolveHyperliquidAssetIndex, decimalUnits, quantizeHyperliquidOrderSizeValue, hyperliquidSignedSizeMatchesRequestedSize, finitePositive, readDevicePrivateExecutionContext, quantizeHyperliquidOrderSize, fetchBrowserAvailableAssets, fetchBrowserAllMids, fetchBrowserSymbolMidPrice, fetchBrowserOpenOrders, parseCanonicalHyperliquidOrderStatusEvidence, fetchBrowserOrderStatusEvidence, fetchBrowserUserRole, fetchBrowserAccountState, fetchBrowserPosition, buildHyperliquidOrderWire, buildHyperliquidTriggerOrderWire, signHyperliquidPayload, signHyperliquidPreparedAction, buildHyperliquidCancelPayload, buildHyperliquidUpdateLeveragePayload, buildHyperliquidMarketOrderPayload, buildHyperliquidLimitOrderPayload, buildHyperliquidTriggerOrderPayload, buildHyperliquidOrderBatchPayload, buildHyperliquidModifyOrderPayload, extractHyperliquidExchangeError, resolveHyperliquidTriggerAcknowledgements, isDefinitiveHyperliquidExchangeResponse, extractDefinitiveHyperliquidOrderId, CANONICAL_POSITIVE_DECIMAL_PATTERN, extractCanonicalHyperliquidOrderStateAcknowledgement, extractCanonicalHyperliquidOrderStateAcknowledgements, extractCanonicalHyperliquidFilledOrderAcknowledgement, extractDefinitiveHyperliquidOrderMemberResults, buildHyperliquidOrderDiagnostics, loadClientExecutionReferenceEvidence, sha256Hex, extractSignedPayloadClientOrderId, extractSignedPayloadMutationCorrelation, assertDurableMutationMatchesSignedAction, exchangeRejectionReason, exchangeActionPriority, submitHyperliquidExchangePayload;
84134
84511
  var init_hyperliquid_client = __esm({
84135
84512
  "lib/runtime/hyperliquid-client.ts"() {
84136
84513
  "use strict";
84137
84514
  init_define_VTX_EXO_POLICY();
84138
84515
  init_define_VTX_GROK_POLICY();
84139
84516
  init_define_VTX_PI_MODEL_POLICY();
84517
+ init_hyperliquid_account_contract();
84140
84518
  init_order_identity();
84141
84519
  init_hyperliquid_order_status();
84142
84520
  init_runtime_policy_generated2();
84143
84521
  init_hyperliquid_public_read();
84144
84522
  init_api2();
84145
84523
  init_abort();
84524
+ init_hyperliquid_exchange_rejections();
84146
84525
  init_hyperliquid_market_symbol();
84147
84526
  init_network_debug();
84148
84527
  init_runtime_redaction();
@@ -84237,6 +84616,14 @@ var init_hyperliquid_client = __esm({
84237
84616
  coordinator.write?.(lastGeneratedNonce);
84238
84617
  return lastGeneratedNonce;
84239
84618
  };
84619
+ hostNonceAllocator = null;
84620
+ allocateActionNonce = async (input, apiUrl) => {
84621
+ if (hostNonceAllocator) {
84622
+ if (!input.signingKey) throw new Error("A fleet-allocated Hyperliquid nonce needs the action's signing key.");
84623
+ return hostNonceAllocator({ signingKey: input.signingKey, apiUrl });
84624
+ }
84625
+ return generateHyperliquidNonce(input.nonceCoordinator);
84626
+ };
84240
84627
  generateHyperliquidNonce = async (coordinator) => {
84241
84628
  const resolvedCoordinator = coordinator ?? browserNonceCoordinator();
84242
84629
  if (resolvedCoordinator.withLock) {
@@ -84362,12 +84749,12 @@ var init_hyperliquid_client = __esm({
84362
84749
  throw new Error("Missing client runtime Hyperliquid API URL.");
84363
84750
  };
84364
84751
  inferIsTestnet = (apiUrl) => apiUrl.toLowerCase().includes("testnet");
84365
- postHyperliquidInfoRead = async (input, body, label, includeBodyText = false) => {
84752
+ postHyperliquidInfoRead = async (input, body, label2, includeBodyText = false) => {
84366
84753
  const apiUrl = inferApiUrl(input);
84367
84754
  const requestUrl = `${apiUrl.replace(/\/$/, "")}/info`;
84368
84755
  const trace = startRuntimeNetworkDebugTrace({
84369
84756
  kind: "exchange",
84370
- label,
84757
+ label: label2,
84371
84758
  method: "POST",
84372
84759
  url: requestUrl
84373
84760
  });
@@ -84385,10 +84772,10 @@ var init_hyperliquid_client = __esm({
84385
84772
  throw sanitizedError;
84386
84773
  }
84387
84774
  };
84388
- postHyperliquidInfo = async (input, body, label) => (await postHyperliquidInfoRead(input, body, label)).payload;
84389
- fetchBrowserHyperliquidInfoPayload = (input, body, label) => postHyperliquidInfo(input, body, label);
84390
- fetchBrowserHyperliquidInfoText = async (input, body, label) => {
84391
- const { bodyText } = await postHyperliquidInfoRead(input, body, label, true);
84775
+ postHyperliquidInfo = async (input, body, label2) => (await postHyperliquidInfoRead(input, body, label2)).payload;
84776
+ fetchBrowserHyperliquidInfoPayload = (input, body, label2) => postHyperliquidInfo(input, body, label2);
84777
+ fetchBrowserHyperliquidInfoText = async (input, body, label2) => {
84778
+ const { bodyText } = await postHyperliquidInfoRead(input, body, label2, true);
84392
84779
  if (typeof bodyText !== "string") throw new Error("Hyperliquid returned no response text.");
84393
84780
  return bodyText;
84394
84781
  };
@@ -84558,14 +84945,14 @@ var init_hyperliquid_client = __esm({
84558
84945
  }
84559
84946
  return normalized;
84560
84947
  };
84561
- assertPositiveInteger = (value, label) => {
84948
+ assertPositiveInteger = (value, label2) => {
84562
84949
  if (!Number.isInteger(value) || value <= 0) {
84563
- throw new Error(`${label} must be a positive integer.`);
84950
+ throw new Error(`${label2} must be a positive integer.`);
84564
84951
  }
84565
84952
  };
84566
- assertPositiveNumber = (value, label) => {
84953
+ assertPositiveNumber = (value, label2) => {
84567
84954
  if (!Number.isFinite(value) || value <= 0) {
84568
- throw new Error(`${label} must be a positive number.`);
84955
+ throw new Error(`${label2} must be a positive number.`);
84569
84956
  }
84570
84957
  };
84571
84958
  normalizeOrderSide = (value) => {
@@ -84702,6 +85089,17 @@ var init_hyperliquid_client = __esm({
84702
85089
  const units = decimalUnits(value, decimals, roundingMode);
84703
85090
  return units / 10 ** decimals;
84704
85091
  };
85092
+ hyperliquidSignedSizeMatchesRequestedSize = (requestedSize, sizeDecimals, signedSize) => {
85093
+ if (!Number.isFinite(requestedSize) || requestedSize <= 0 || !Number.isFinite(signedSize) || signedSize <= 0 || !Number.isInteger(sizeDecimals) || sizeDecimals < 0) {
85094
+ return false;
85095
+ }
85096
+ const tolerance = 10 ** -(sizeDecimals + 4);
85097
+ const candidates = [
85098
+ quantizeHyperliquidOrderSizeValue(requestedSize, sizeDecimals, "nearest"),
85099
+ Number(requestedSize.toFixed(sizeDecimals))
85100
+ ];
85101
+ return candidates.some((candidate) => candidate > 0 && Math.abs(candidate - signedSize) <= tolerance);
85102
+ };
84705
85103
  finitePositive = (value) => {
84706
85104
  const parsed = Number(value);
84707
85105
  return typeof value !== "boolean" && value !== null && value !== "" && Number.isFinite(parsed) && parsed > 0 ? parsed : null;
@@ -85210,7 +85608,7 @@ var init_hyperliquid_client = __esm({
85210
85608
  accountSummary: {
85211
85609
  account_value: accountValue,
85212
85610
  total_margin_used: totalMarginUsed,
85213
- available_margin: Math.max(0, accountValue - totalMarginUsed),
85611
+ available_margin: canonicalAvailableMargin(accountValue, totalMarginUsed),
85214
85612
  withdrawable,
85215
85613
  cross_margin_ratio: accountValue > 0 ? maintenanceMargin / accountValue : 0,
85216
85614
  maintenance_margin: maintenanceMargin,
@@ -85231,7 +85629,8 @@ var init_hyperliquid_client = __esm({
85231
85629
  buildHyperliquidOrderWire = async (input, tif, price, priceKind) => {
85232
85630
  const { asset_index: assetIndex, sz_decimals: sizeDecimals } = await resolveHyperliquidAsset(input);
85233
85631
  const side = normalizeOrderSide(input.side);
85234
- const roundedSize = Number(input.size.toFixed(sizeDecimals));
85632
+ assertPositiveNumber(input.size, "Hyperliquid order size");
85633
+ const roundedSize = quantizeHyperliquidOrderSizeValue(input.size, sizeDecimals, "nearest");
85235
85634
  assertPositiveNumber(roundedSize, "Hyperliquid order size");
85236
85635
  const priceWire = formatHyperliquidOrderPriceWire(price, sizeDecimals, side, priceKind);
85237
85636
  const sizeWire = formatSizeWire(roundedSize, sizeDecimals);
@@ -85259,7 +85658,7 @@ var init_hyperliquid_client = __esm({
85259
85658
  assertPositiveNumber(input.limitPrice, "Hyperliquid trigger limit price");
85260
85659
  const { asset_index: assetIndex, sz_decimals: sizeDecimals } = await resolveHyperliquidAsset(input);
85261
85660
  const side = normalizeOrderSide(input.side);
85262
- const roundedSize = Number(input.size.toFixed(sizeDecimals));
85661
+ const roundedSize = quantizeHyperliquidOrderSizeValue(input.size, sizeDecimals, "nearest");
85263
85662
  assertPositiveNumber(roundedSize, "Hyperliquid trigger order size");
85264
85663
  const triggerPriceWire = formatHyperliquidTriggerPriceWire(input.triggerPrice, sizeDecimals);
85265
85664
  const limitPriceWire = input.limitPrice === input.triggerPrice ? triggerPriceWire : formatHyperliquidOrderPriceWire(input.limitPrice, sizeDecimals, side, "limit");
@@ -85295,7 +85694,7 @@ var init_hyperliquid_client = __esm({
85295
85694
  signHyperliquidPayload = async (input, action) => {
85296
85695
  const apiUrl = inferApiUrl(input);
85297
85696
  const { signHyperliquidAction: signHyperliquidAction2 } = await Promise.resolve().then(() => (init_hyperliquid_signer(), hyperliquid_signer_exports));
85298
- const nonce = input.nonce ?? await generateHyperliquidNonce(input.nonceCoordinator);
85697
+ const nonce = input.nonce ?? await allocateActionNonce(input, apiUrl);
85299
85698
  const expiresAfter = input.expiresAfterSeconds == null ? null : nonce + input.expiresAfterSeconds * 1e3;
85300
85699
  const signed2 = await signHyperliquidAction2({
85301
85700
  privateKey: input.signingKey,
@@ -85319,7 +85718,7 @@ var init_hyperliquid_client = __esm({
85319
85718
  }
85320
85719
  const apiUrl = inferApiUrl(input);
85321
85720
  const { signHyperliquidAction: signHyperliquidAction2 } = await Promise.resolve().then(() => (init_hyperliquid_signer(), hyperliquid_signer_exports));
85322
- const nonce = await generateHyperliquidNonce(input.nonceCoordinator);
85721
+ const nonce = await allocateActionNonce(input, apiUrl);
85323
85722
  const expiresAfter = nonce + input.expiresAfterSeconds * 1e3;
85324
85723
  const signed2 = await signHyperliquidAction2({
85325
85724
  privateKey: input.signingKey,
@@ -85347,7 +85746,7 @@ var init_hyperliquid_client = __esm({
85347
85746
  const apiUrl = inferApiUrl(input);
85348
85747
  const assetIndex = await resolveHyperliquidAssetIndex(input);
85349
85748
  const { signHyperliquidAction: signHyperliquidAction2 } = await Promise.resolve().then(() => (init_hyperliquid_signer(), hyperliquid_signer_exports));
85350
- const nonce = input.nonce ?? await generateHyperliquidNonce(input.nonceCoordinator);
85749
+ const nonce = input.nonce ?? await allocateActionNonce(input, apiUrl);
85351
85750
  const expiresAfter = input.expiresAfterSeconds == null ? null : nonce + input.expiresAfterSeconds * 1e3;
85352
85751
  const action = clientOrderId != null ? {
85353
85752
  type: "cancelByCloid",
@@ -85377,7 +85776,7 @@ var init_hyperliquid_client = __esm({
85377
85776
  const apiUrl = inferApiUrl(input);
85378
85777
  const asset = await resolveHyperliquidAsset(input);
85379
85778
  const { signHyperliquidAction: signHyperliquidAction2 } = await Promise.resolve().then(() => (init_hyperliquid_signer(), hyperliquid_signer_exports));
85380
- const nonce = input.nonce ?? await generateHyperliquidNonce(input.nonceCoordinator);
85779
+ const nonce = input.nonce ?? await allocateActionNonce(input, apiUrl);
85381
85780
  const expiresAfter = input.expiresAfterSeconds == null ? null : nonce + input.expiresAfterSeconds * 1e3;
85382
85781
  const leverage = Math.max(1, Math.min(asset.max_leverage, Math.trunc(input.leverage)));
85383
85782
  const isCross = isExchangeIsolatedOnly(asset) ? false : input.isCross !== false;
@@ -86204,7 +86603,7 @@ var init_hyperliquid_client = __esm({
86204
86603
  try {
86205
86604
  recoveryPermit = await admitHyperliquidExchangeRequest(apiUrl, input.payload.action, input.signal, input.publicRequestPriority);
86206
86605
  assertFreshPreparedExecutionContext(input.preparedContext);
86207
- assertHyperliquidRecoveryDispatch(apiUrl, recoveryPermit, "exchange");
86606
+ await validateHyperliquidRecoveryDispatch(apiUrl, recoveryPermit, "exchange");
86208
86607
  } catch (preparedContextError) {
86209
86608
  await settleDurableMutation("rejected");
86210
86609
  if (isAbortLikeError(preparedContextError) || preparedContextError instanceof HyperliquidPublicReadError) throw preparedContextError;
@@ -86295,6 +86694,7 @@ var init_hyperliquid_client = __esm({
86295
86694
  }
86296
86695
  const exchangeError = extractHyperliquidExchangeError(payload);
86297
86696
  if (exchangeError) {
86697
+ emitHyperliquidExchangeRejection(String(exchangeError.message ?? ""));
86298
86698
  await settleDurableMutation(
86299
86699
  exchangeError.partial ? "transport_ambiguous" : "rejected",
86300
86700
  null,
@@ -87268,6 +87668,81 @@ async function adoptClientProtectiveLegs(profileId, payload, requiredRuntimeSess
87268
87668
  { ...authority.requestOptions, signal: payload.signal }
87269
87669
  );
87270
87670
  }
87671
+ async function claimServerHostExecution(profileId, payload, signal, requiredRuntimeSessionId, explicitRuntimeLeaseToken, explicitRuntimeDeviceId, explicitSchedulerInstanceId) {
87672
+ const authority = resolveClientExchangeMutationAuthority(
87673
+ profileId,
87674
+ requiredRuntimeSessionId,
87675
+ explicitRuntimeLeaseToken,
87676
+ explicitRuntimeDeviceId,
87677
+ explicitSchedulerInstanceId
87678
+ );
87679
+ return postClientRuntime(
87680
+ "/runtime/execution-claim",
87681
+ authority.numericProfileId,
87682
+ JSON.stringify({
87683
+ ...clientExchangeMutationAuthorityBody(authority),
87684
+ cycle_id: payload.cycleId ?? null,
87685
+ symbol: payload.symbol,
87686
+ intent: payload.intent,
87687
+ side: payload.side,
87688
+ requested_units: payload.requestedUnits,
87689
+ reduce_only: payload.reduceOnly,
87690
+ margin_mode: payload.marginMode ?? null,
87691
+ last_price: payload.lastPrice
87692
+ }),
87693
+ { ...authority.requestOptions, signal }
87694
+ );
87695
+ }
87696
+ async function recordServerHostExecutionAudit(profileId, payload, signal, requiredRuntimeSessionId, explicitRuntimeLeaseToken, explicitRuntimeDeviceId, explicitSchedulerInstanceId) {
87697
+ const authority = resolveClientExchangeMutationAuthority(
87698
+ profileId,
87699
+ requiredRuntimeSessionId,
87700
+ explicitRuntimeLeaseToken,
87701
+ explicitRuntimeDeviceId,
87702
+ explicitSchedulerInstanceId
87703
+ );
87704
+ return postClientRuntime(
87705
+ "/runtime/execution-audit",
87706
+ authority.numericProfileId,
87707
+ JSON.stringify({
87708
+ ...clientExchangeMutationAuthorityBody(authority),
87709
+ audit_id: payload.auditId,
87710
+ cycle_id: payload.cycleId ?? null,
87711
+ symbol: payload.symbol,
87712
+ intent: payload.intent,
87713
+ side: payload.side,
87714
+ requested_units: payload.requestedUnits,
87715
+ reduce_only: payload.reduceOnly,
87716
+ last_price: payload.lastPrice,
87717
+ status: payload.status,
87718
+ reason_code: payload.reasonCode,
87719
+ order_id: payload.orderId ?? null
87720
+ }),
87721
+ { ...authority.requestOptions, signal }
87722
+ );
87723
+ }
87724
+ async function checkServerHostExecutionCapacity(profileId, plans, signal, requiredRuntimeSessionId, explicitRuntimeLeaseToken, explicitRuntimeDeviceId, explicitSchedulerInstanceId) {
87725
+ const authority = resolveClientExchangeMutationAuthority(
87726
+ profileId,
87727
+ requiredRuntimeSessionId,
87728
+ explicitRuntimeLeaseToken,
87729
+ explicitRuntimeDeviceId,
87730
+ explicitSchedulerInstanceId
87731
+ );
87732
+ const answer = await postClientRuntime(
87733
+ "/runtime/execution-capacity",
87734
+ authority.numericProfileId,
87735
+ JSON.stringify({
87736
+ ...clientExchangeMutationAuthorityBody(authority),
87737
+ plans
87738
+ }),
87739
+ { ...authority.requestOptions, signal }
87740
+ );
87741
+ if (!Array.isArray(answer.results) || answer.results.length !== plans.length) {
87742
+ throw new Error("Server execution capacity answered a different number of plans.");
87743
+ }
87744
+ return answer.results;
87745
+ }
87271
87746
  async function reportClientRuntimeExchangeAttemptTransition(profileId, mutationId, payload, signal, requiredRuntimeSessionId, explicitRuntimeLeaseToken, explicitRuntimeDeviceId, explicitSchedulerInstanceId) {
87272
87747
  const authority = resolveClientExchangeMutationAuthority(
87273
87748
  profileId,
@@ -87396,6 +87871,9 @@ async function sendClientRuntimeHeartbeat(profileId, payload, options) {
87396
87871
  if (payload.isExecuting !== void 0) {
87397
87872
  extras.is_executing = payload.isExecuting;
87398
87873
  }
87874
+ if (payload.analyzingObservedAtMs !== void 0) {
87875
+ extras.analyzing_observed_at_ms = payload.analyzingObservedAtMs;
87876
+ }
87399
87877
  return postClientRuntime(
87400
87878
  "/runtime/heartbeat",
87401
87879
  profileId,
@@ -88259,14 +88737,14 @@ var init_api2 = __esm({
88259
88737
  ]);
88260
88738
  CLIENT_EXCHANGE_AUTHORITY_DEVICE_KEY = "vtx_client_exchange_authority_device_v1";
88261
88739
  CLIENT_EXCHANGE_AUTHORITY_SESSION_KEY = "vtx_client_exchange_authority_session_v1";
88262
- getOrCreateClientExchangeAuthorityIdentity = (storage3, key, label) => {
88740
+ getOrCreateClientExchangeAuthorityIdentity = (storage3, key, label2) => {
88263
88741
  const existing = String(storage3.getItem(key) || "").trim().toLowerCase();
88264
88742
  if (/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(existing)) {
88265
88743
  return existing;
88266
88744
  }
88267
88745
  const generated = globalThis.crypto?.randomUUID?.().toLowerCase();
88268
88746
  if (!generated || !/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(generated)) {
88269
- throw new Error(`Secure ${label} generation is unavailable.`);
88747
+ throw new Error(`Secure ${label2} generation is unavailable.`);
88270
88748
  }
88271
88749
  storage3.setItem(key, generated);
88272
88750
  return generated;
@@ -88485,7 +88963,7 @@ var init_api2 = __esm({
88485
88963
  });
88486
88964
 
88487
88965
  // lib/runtime/hyperliquid-signer-binding.ts
88488
- var DeviceSigningKeyError, DEVICE_SIGNING_KEY_FAILURES, getDeviceSigningKeyFailure, normalizeAddress, extractRoleAddress, assertBrowserHyperliquidSignerWalletBinding;
88966
+ var DeviceSigningKeyError, DEVICE_SIGNING_KEY_FAILURES, getDeviceSigningKeyFailure, normalizeAddress, extractRoleAddress, signerBindingCache, validatedSignerBindings, SIGNER_NOT_FOUND, invalidateHyperliquidSignerBindingAfterRejection, assertBrowserHyperliquidSignerWalletBinding;
88489
88967
  var init_hyperliquid_signer_binding = __esm({
88490
88968
  "lib/runtime/hyperliquid-signer-binding.ts"() {
88491
88969
  "use strict";
@@ -88493,6 +88971,7 @@ var init_hyperliquid_signer_binding = __esm({
88493
88971
  init_define_VTX_GROK_POLICY();
88494
88972
  init_define_VTX_PI_MODEL_POLICY();
88495
88973
  init_hyperliquid_client();
88974
+ init_hyperliquid_exchange_rejections();
88496
88975
  init_error_surface_contract();
88497
88976
  DeviceSigningKeyError = class extends RuntimeExecutionError {
88498
88977
  constructor(message, reasonCode, deviceSigningKeyFailure) {
@@ -88508,10 +88987,10 @@ var init_hyperliquid_signer_binding = __esm({
88508
88987
  const failure2 = error48?.deviceSigningKeyFailure;
88509
88988
  return typeof failure2 === "string" && DEVICE_SIGNING_KEY_FAILURES.has(failure2) ? failure2 : null;
88510
88989
  };
88511
- normalizeAddress = (value, label) => {
88990
+ normalizeAddress = (value, label2) => {
88512
88991
  const normalized = String(value || "").trim().toLowerCase();
88513
88992
  if (!/^0x[0-9a-f]{40}$/.test(normalized)) {
88514
- throw new Error(`Invalid Hyperliquid ${label}.`);
88993
+ throw new Error(`Invalid Hyperliquid ${label2}.`);
88515
88994
  }
88516
88995
  return normalized;
88517
88996
  };
@@ -88529,6 +89008,22 @@ var init_hyperliquid_signer_binding = __esm({
88529
89008
  }
88530
89009
  return null;
88531
89010
  };
89011
+ signerBindingCache = null;
89012
+ validatedSignerBindings = /* @__PURE__ */ new Map();
89013
+ SIGNER_NOT_FOUND = /^(?:L1 error:\s*)?User or API Wallet\s+(0x[0-9a-fA-F]{40})\s+does not exist\.?$/i;
89014
+ invalidateHyperliquidSignerBindingAfterRejection = async (message) => {
89015
+ const match = SIGNER_NOT_FOUND.exec(String(message ?? "").trim());
89016
+ if (!match || !signerBindingCache) return;
89017
+ const signerAddress = match[1].toLowerCase();
89018
+ for (const [key, entry] of [...validatedSignerBindings.entries()]) {
89019
+ if (entry.binding.signerAddress !== signerAddress) continue;
89020
+ validatedSignerBindings.delete(key);
89021
+ await signerBindingCache.invalidate(entry.binding.walletAddress, signerAddress).catch(() => void 0);
89022
+ }
89023
+ };
89024
+ onHyperliquidExchangeRejection((message) => {
89025
+ void invalidateHyperliquidSignerBindingAfterRejection(message);
89026
+ });
88532
89027
  assertBrowserHyperliquidSignerWalletBinding = async (input) => {
88533
89028
  let walletAddress;
88534
89029
  try {
@@ -88554,6 +89049,24 @@ var init_hyperliquid_signer_binding = __esm({
88554
89049
  "device_signing_key_invalid"
88555
89050
  );
88556
89051
  }
89052
+ const cacheKey = `${walletAddress}:${signerAddress}`;
89053
+ let generation = null;
89054
+ if (signerBindingCache) {
89055
+ try {
89056
+ generation = await signerBindingCache.generation(walletAddress, signerAddress);
89057
+ } catch {
89058
+ throw new RuntimeExecutionError(
89059
+ "VTX could not verify the cached signing-key authorization because its coordination state was temporarily unavailable. The signing key was not rejected.",
89060
+ "signer_validation_unavailable"
89061
+ );
89062
+ }
89063
+ const cached2 = validatedSignerBindings.get(cacheKey);
89064
+ if (cached2 && cached2.generation === generation) return cached2.binding;
89065
+ }
89066
+ const remember = (binding) => {
89067
+ if (signerBindingCache && generation !== null) validatedSignerBindings.set(cacheKey, { generation, binding });
89068
+ return binding;
89069
+ };
88557
89070
  let roleResponse;
88558
89071
  try {
88559
89072
  roleResponse = await fetchBrowserUserRole({
@@ -88571,11 +89084,11 @@ var init_hyperliquid_signer_binding = __esm({
88571
89084
  }
88572
89085
  const signerRole = String(roleResponse.role || "").trim().toLowerCase();
88573
89086
  if (signerRole === "user" && signerAddress === walletAddress) {
88574
- return {
89087
+ return remember({
88575
89088
  signerAddress,
88576
89089
  walletAddress,
88577
89090
  signerRole: "user"
88578
- };
89091
+ });
88579
89092
  }
88580
89093
  if (signerRole === "agent") {
88581
89094
  const masterWallet = extractRoleAddress(
@@ -88583,11 +89096,11 @@ var init_hyperliquid_signer_binding = __esm({
88583
89096
  ["user"]
88584
89097
  );
88585
89098
  if (masterWallet === walletAddress) {
88586
- return {
89099
+ return remember({
88587
89100
  signerAddress,
88588
89101
  walletAddress,
88589
89102
  signerRole: "agent"
88590
- };
89103
+ });
88591
89104
  }
88592
89105
  }
88593
89106
  throw new DeviceSigningKeyError(
@@ -89543,9 +90056,9 @@ var init_browser_trading = __esm({
89543
90056
  }
89544
90057
  return profileId;
89545
90058
  };
89546
- requirePositiveNumber = (value, label) => {
90059
+ requirePositiveNumber = (value, label2) => {
89547
90060
  if (!Number.isFinite(value) || value <= 0) {
89548
- throw new Error(`${label} must be a positive number.`);
90061
+ throw new Error(`${label2} must be a positive number.`);
89549
90062
  }
89550
90063
  };
89551
90064
  assertFreshPreparedContext = (preparedContext) => {
@@ -90018,287 +90531,6 @@ var init_browser_trading = __esm({
90018
90531
  }
90019
90532
  });
90020
90533
 
90021
- // lib/runtime/hyperliquid-account-mode-contract.ts
90022
- function resolveExactHyperliquidAccountMode(userAbstraction, ...dexEvidence) {
90023
- const mode = extractCanonicalHyperliquidAccountMode(userAbstraction);
90024
- if (!mode) {
90025
- throw new Error("Exact Hyperliquid userAbstraction response is invalid.");
90026
- }
90027
- if (mode !== "default" && mode !== "disabled") return mode;
90028
- if (dexEvidence.length < 1) {
90029
- throw new Error("Exact Hyperliquid userDexAbstraction response is unavailable.");
90030
- }
90031
- return parseExactDexAbstractionEnabled(dexEvidence[0]) ? "dexAbstraction" : mode;
90032
- }
90033
- var UNIFIED_MODE_ALIASES, CANONICAL_ACCOUNT_MODE_ALIASES, EXACT_MODE_KEYS, EXACT_MODE_BOOLEAN_KEYS, isExactTruthyFlag, normalizeCanonicalHyperliquidAccountMode, extractCanonicalHyperliquidAccountMode, parseExactDexAbstractionEnabled, normalizeAccountMode, extractAccountModeFromPayload, extractAccountModeCandidateFromPayload, isUnifiedAccountMode;
90034
- var init_hyperliquid_account_mode_contract = __esm({
90035
- "lib/runtime/hyperliquid-account-mode-contract.ts"() {
90036
- "use strict";
90037
- init_define_VTX_EXO_POLICY();
90038
- init_define_VTX_GROK_POLICY();
90039
- init_define_VTX_PI_MODEL_POLICY();
90040
- UNIFIED_MODE_ALIASES = /* @__PURE__ */ new Set([
90041
- "unifiedaccount",
90042
- "dexabstraction",
90043
- "portfoliomargin",
90044
- "unified",
90045
- "pm"
90046
- ]);
90047
- CANONICAL_ACCOUNT_MODE_ALIASES = /* @__PURE__ */ new Map([
90048
- ["default", "default"],
90049
- ["standard", "default"],
90050
- ["classic", "default"],
90051
- ["disabled", "disabled"],
90052
- ["unifiedaccount", "unifiedAccount"],
90053
- ["unified", "unifiedAccount"],
90054
- ["portfoliomargin", "portfolioMargin"],
90055
- ["pm", "portfolioMargin"],
90056
- ["dexabstraction", "dexAbstraction"]
90057
- ]);
90058
- EXACT_MODE_KEYS = [
90059
- "accountMode",
90060
- "account_mode",
90061
- "accountType",
90062
- "account_type",
90063
- "accountUnificationMode",
90064
- "account_unification_mode",
90065
- "abstractionMode",
90066
- "abstraction_mode",
90067
- "abstraction",
90068
- "abstractionState",
90069
- "dexAbstractionState",
90070
- "marginMode",
90071
- "state",
90072
- "mode",
90073
- "value"
90074
- ];
90075
- EXACT_MODE_BOOLEAN_KEYS = [
90076
- ["unifiedAccount", ["isUnifiedAccount", "unifiedAccount", "isUnified", "unified", "is_unified_account"]],
90077
- ["portfolioMargin", ["isPortfolioMargin", "portfolioMargin", "isPm", "pm", "is_portfolio_margin"]],
90078
- ["dexAbstraction", ["isDexAbstraction", "dexAbstraction", "dexAbstractionEnabled", "is_dex_abstraction"]],
90079
- ["default", ["isClassic", "classic", "isStandard", "standard"]]
90080
- ];
90081
- isExactTruthyFlag = (value) => value === true || value === 1 || typeof value === "string" && value.trim().toLowerCase() === "true";
90082
- normalizeCanonicalHyperliquidAccountMode = (value) => {
90083
- if (typeof value !== "string") return null;
90084
- const key = value.trim().replace(/[_\s-]/g, "").toLowerCase();
90085
- return CANONICAL_ACCOUNT_MODE_ALIASES.get(key) ?? null;
90086
- };
90087
- extractCanonicalHyperliquidAccountMode = (payload, depth = 0) => {
90088
- if (depth > 6) return null;
90089
- const direct = normalizeCanonicalHyperliquidAccountMode(payload);
90090
- if (direct) return direct;
90091
- if (Array.isArray(payload)) {
90092
- for (const item of payload) {
90093
- const mode = extractCanonicalHyperliquidAccountMode(item, depth + 1);
90094
- if (mode) return mode;
90095
- }
90096
- return null;
90097
- }
90098
- if (!payload || typeof payload !== "object") return null;
90099
- const source = payload;
90100
- for (const key of EXACT_MODE_KEYS) {
90101
- if (!(key in source)) continue;
90102
- const mode = normalizeCanonicalHyperliquidAccountMode(source[key]);
90103
- if (mode) return mode;
90104
- }
90105
- for (const [mode, keys] of EXACT_MODE_BOOLEAN_KEYS) {
90106
- for (const key of keys) {
90107
- if (isExactTruthyFlag(source[key])) return mode;
90108
- }
90109
- }
90110
- for (const value of Object.values(source)) {
90111
- const mode = extractCanonicalHyperliquidAccountMode(value, depth + 1);
90112
- if (mode) return mode;
90113
- }
90114
- return null;
90115
- };
90116
- parseExactDexAbstractionEnabled = (payload) => {
90117
- if (payload == null || payload === false) return false;
90118
- if (payload === true) return true;
90119
- if (typeof payload === "string") {
90120
- const normalized = payload.trim().toLowerCase();
90121
- if (normalized === "true") return true;
90122
- if (normalized === "false") return false;
90123
- }
90124
- if (typeof payload === "number" && Number.isFinite(payload)) {
90125
- if (payload === 1) return true;
90126
- if (payload === 0) return false;
90127
- }
90128
- throw new Error("Exact Hyperliquid userDexAbstraction response is invalid.");
90129
- };
90130
- normalizeAccountMode = (mode) => String(mode ?? "").trim().toLowerCase().replace(/[_\s-]/g, "");
90131
- extractAccountModeFromPayload = (payload) => {
90132
- const candidate = extractAccountModeCandidateFromPayload(payload);
90133
- if (candidate && candidate.trim().length > 0) {
90134
- return candidate;
90135
- }
90136
- return "default";
90137
- };
90138
- extractAccountModeCandidateFromPayload = (payload) => {
90139
- if (!payload || typeof payload !== "object") {
90140
- return null;
90141
- }
90142
- const source = payload;
90143
- if ("accountMode" in source) {
90144
- return String(source.accountMode ?? "");
90145
- }
90146
- if ("account_mode" in source) {
90147
- return String(source.account_mode ?? "");
90148
- }
90149
- return null;
90150
- };
90151
- isUnifiedAccountMode = (mode) => UNIFIED_MODE_ALIASES.has(normalizeAccountMode(mode));
90152
- }
90153
- });
90154
-
90155
- // lib/runtime/hyperliquid-account-contract.ts
90156
- var toNumber2, firstNumber, roundTo, STABLE_SPOT_SYMBOLS, spotBalanceValueUsd, normalizeSpotBalancesFromInfoResponse, sumBalanceHoldUsd, sumPositionUnrealizedPnl, resolveTotalUnrealizedPnl, approximatelyEqualAccountValues, buildAccountSummaryFromInfoResponses;
90157
- var init_hyperliquid_account_contract = __esm({
90158
- "lib/runtime/hyperliquid-account-contract.ts"() {
90159
- "use strict";
90160
- init_define_VTX_EXO_POLICY();
90161
- init_define_VTX_GROK_POLICY();
90162
- init_define_VTX_PI_MODEL_POLICY();
90163
- init_hyperliquid_account_mode_contract();
90164
- toNumber2 = (value, fallback = 0) => {
90165
- const numeric2 = Number(value);
90166
- return Number.isFinite(numeric2) ? numeric2 : fallback;
90167
- };
90168
- firstNumber = (values, fallback = 0) => {
90169
- for (const value of values) {
90170
- if (value == null || typeof value === "string" && value.trim() === "") {
90171
- continue;
90172
- }
90173
- const numeric2 = Number(value);
90174
- if (Number.isFinite(numeric2)) {
90175
- return numeric2;
90176
- }
90177
- }
90178
- return fallback;
90179
- };
90180
- roundTo = (value, digits = 12) => Number(value.toFixed(digits));
90181
- STABLE_SPOT_SYMBOLS = /* @__PURE__ */ new Set(["USDC", "USD", "USDT"]);
90182
- spotBalanceValueUsd = (balance, coin, total) => {
90183
- const explicit = firstNumber([balance?.value_usd, balance?.usdValue, balance?.usdcValue], Number.NaN);
90184
- if (Number.isFinite(explicit)) {
90185
- return explicit;
90186
- }
90187
- return STABLE_SPOT_SYMBOLS.has(coin) ? total : 0;
90188
- };
90189
- normalizeSpotBalancesFromInfoResponse = (spotResponse) => {
90190
- const containers = [];
90191
- if (spotResponse && typeof spotResponse === "object") {
90192
- containers.push(spotResponse);
90193
- const keys = ["spotState", "userState", "clearinghouseState", "state", "data"];
90194
- for (const key of keys) {
90195
- if (spotResponse[key] && typeof spotResponse[key] === "object") {
90196
- containers.push(spotResponse[key]);
90197
- }
90198
- }
90199
- }
90200
- const firstWithBalances = containers.find((container) => Array.isArray(container?.balances));
90201
- const balances = Array.isArray(firstWithBalances?.balances) ? firstWithBalances.balances : [];
90202
- return balances.map((balance) => {
90203
- const coin = String(balance?.coin ?? "").toUpperCase();
90204
- const total = toNumber2(balance?.total, 0);
90205
- const hold = toNumber2(balance?.hold, 0);
90206
- const available = roundTo(Math.max(0, total - hold));
90207
- const value_usd = spotBalanceValueUsd(balance, coin, total);
90208
- return {
90209
- coin,
90210
- total,
90211
- hold,
90212
- available,
90213
- value_usd
90214
- };
90215
- }).filter((balance) => balance.coin.length > 0);
90216
- };
90217
- sumBalanceHoldUsd = (balances) => balances.reduce((acc, balance) => {
90218
- const hold = toNumber2(balance.hold, 0);
90219
- const total = toNumber2(balance.total, 0);
90220
- const valueUsd = toNumber2(balance.value_usd, 0);
90221
- if (hold <= 0 || total <= 0 || valueUsd <= 0) {
90222
- return acc;
90223
- }
90224
- return acc + Math.max(0, valueUsd * (hold / total));
90225
- }, 0);
90226
- sumPositionUnrealizedPnl = (perpsResponse) => {
90227
- const assetPositions = Array.isArray(perpsResponse?.assetPositions) ? perpsResponse.assetPositions : [];
90228
- return assetPositions.reduce((total, entry) => {
90229
- const unrealizedPnl = toNumber2(entry?.position?.unrealizedPnl, 0);
90230
- return total + unrealizedPnl;
90231
- }, 0);
90232
- };
90233
- resolveTotalUnrealizedPnl = (perpsResponse) => {
90234
- const topLevel = toNumber2(perpsResponse?.totalUnrealizedPnl, 0);
90235
- const positionTotal = sumPositionUnrealizedPnl(perpsResponse);
90236
- if (Math.abs(topLevel) < 1e-12 && Math.abs(positionTotal) >= 1e-12) {
90237
- return positionTotal;
90238
- }
90239
- return topLevel;
90240
- };
90241
- approximatelyEqualAccountValues = (left, right, absoluteToleranceUsd, relativeTolerance) => {
90242
- const reference = Math.max(Math.abs(left), Math.abs(right), 1);
90243
- return Math.abs(left - right) <= Math.max(
90244
- absoluteToleranceUsd,
90245
- reference * relativeTolerance
90246
- );
90247
- };
90248
- buildAccountSummaryFromInfoResponses = (perpsResponse, spotResponse, options = {}) => {
90249
- const marginSummary = perpsResponse?.marginSummary ?? {};
90250
- const perpsAccountValue = toNumber2(marginSummary?.accountValue, 0);
90251
- const total_margin_used = toNumber2(marginSummary?.totalMarginUsed, 0);
90252
- const totalNtlPos = toNumber2(marginSummary?.totalNtlPos, 0);
90253
- const withdrawable = toNumber2(perpsResponse?.withdrawable, 0);
90254
- const maintenance_margin = firstNumber([
90255
- perpsResponse?.crossMaintenanceMarginUsed,
90256
- marginSummary?.crossMaintenanceMarginUsed,
90257
- marginSummary?.totalMaintenanceMargin
90258
- ], 0);
90259
- const balances = normalizeSpotBalancesFromInfoResponse(spotResponse);
90260
- const spotPortfolioValue = balances.reduce((acc, balance) => acc + toNumber2(balance.value_usd, 0), 0);
90261
- const balancesHoldUsd = sumBalanceHoldUsd(balances);
90262
- const account_mode = extractAccountModeFromPayload(perpsResponse);
90263
- const crossMarginSummary = perpsResponse?.crossMarginSummary && typeof perpsResponse.crossMarginSummary === "object" ? perpsResponse.crossMarginSummary : null;
90264
- const crossMarginAccountValue = crossMarginSummary ? toNumber2(crossMarginSummary.accountValue, 0) : 0;
90265
- const normalizedMode = String(account_mode || "").trim().toLowerCase().replace(/[_\s-]/g, "");
90266
- const isAmbiguousDefaultMode = normalizedMode.length === 0 || normalizedMode === "default";
90267
- const spotDominatesMinTotalUsd = Number(options.spotDominatesMinTotalUsd ?? options.spot_dominates_min_total_usd);
90268
- const spotDominatesPerpsMultiplier = Number(options.spotDominatesPerpsMultiplier ?? options.spot_dominates_perps_multiplier);
90269
- const mirroredAccountValueAbsoluteToleranceUsd = Number(
90270
- options.mirroredAccountValueAbsoluteToleranceUsd ?? options.mirrored_account_value_absolute_tolerance_usd
90271
- );
90272
- const mirroredAccountValueRelativeTolerance = Number(
90273
- options.mirroredAccountValueRelativeTolerance ?? options.mirrored_account_value_relative_tolerance
90274
- );
90275
- const hasSpotDominanceThresholds = Number.isFinite(spotDominatesMinTotalUsd) && spotDominatesMinTotalUsd >= 0 && Number.isFinite(spotDominatesPerpsMultiplier) && spotDominatesPerpsMultiplier >= 0;
90276
- const hasMirroredAccountValueTolerances = Number.isFinite(mirroredAccountValueAbsoluteToleranceUsd) && mirroredAccountValueAbsoluteToleranceUsd >= 0 && Number.isFinite(mirroredAccountValueRelativeTolerance) && mirroredAccountValueRelativeTolerance >= 0;
90277
- const spotDominatesPerps = hasSpotDominanceThresholds && spotPortfolioValue >= spotDominatesMinTotalUsd && (perpsAccountValue <= 0 || spotPortfolioValue >= perpsAccountValue * spotDominatesPerpsMultiplier);
90278
- const ambiguousDefaultLooksUnified = isAmbiguousDefaultMode && spotDominatesPerps;
90279
- const ambiguousDefaultSpotAlreadyIncludesPerps = ambiguousDefaultLooksUnified && perpsAccountValue > 0 && balancesHoldUsd > 0 && hasMirroredAccountValueTolerances && approximatelyEqualAccountValues(
90280
- balancesHoldUsd,
90281
- perpsAccountValue,
90282
- mirroredAccountValueAbsoluteToleranceUsd,
90283
- mirroredAccountValueRelativeTolerance
90284
- );
90285
- const account_value = isUnifiedAccountMode(account_mode) && crossMarginSummary !== null && crossMarginAccountValue > 0 ? crossMarginAccountValue + spotPortfolioValue : ambiguousDefaultLooksUnified && !ambiguousDefaultSpotAlreadyIncludesPerps ? perpsAccountValue + spotPortfolioValue : Math.max(perpsAccountValue, spotPortfolioValue);
90286
- return {
90287
- account_value,
90288
- total_margin_used,
90289
- available_margin: roundTo(Math.max(0, account_value - total_margin_used)),
90290
- withdrawable,
90291
- cross_margin_ratio: account_value > 0 ? maintenance_margin / account_value : 0,
90292
- maintenance_margin,
90293
- cross_account_leverage: account_value > 0 ? totalNtlPos / account_value : 0,
90294
- total_unrealized_pnl: resolveTotalUnrealizedPnl(perpsResponse),
90295
- account_mode,
90296
- balances
90297
- };
90298
- };
90299
- }
90300
- });
90301
-
90302
90534
  // lib/runtime/hyperliquid-active-asset-contract.ts
90303
90535
  var unwrapActiveAssetPayload, normalizePair, normalizeActiveAssetData;
90304
90536
  var init_hyperliquid_active_asset_contract = __esm({
@@ -90326,15 +90558,15 @@ var init_hyperliquid_active_asset_contract = __esm({
90326
90558
  };
90327
90559
  normalizePair = (raw) => {
90328
90560
  if (Array.isArray(raw) && raw.length >= 2) {
90329
- return [toNumber2(raw[0], 0), toNumber2(raw[1], 0)];
90561
+ return [toNumber(raw[0], 0), toNumber(raw[1], 0)];
90330
90562
  }
90331
90563
  if (raw && typeof raw === "object") {
90332
- const buy = toNumber2(raw.buy ?? raw.long ?? raw.b, 0);
90333
- const sell = toNumber2(raw.sell ?? raw.short ?? raw.s, 0);
90564
+ const buy = toNumber(raw.buy ?? raw.long ?? raw.b, 0);
90565
+ const sell = toNumber(raw.sell ?? raw.short ?? raw.s, 0);
90334
90566
  return [buy, sell];
90335
90567
  }
90336
90568
  if (typeof raw === "string" || typeof raw === "number") {
90337
- const value = toNumber2(raw, 0);
90569
+ const value = toNumber(raw, 0);
90338
90570
  return [value, value];
90339
90571
  }
90340
90572
  return [0, 0];
@@ -90345,21 +90577,21 @@ var init_hyperliquid_active_asset_contract = __esm({
90345
90577
  const directSell = source.available_to_trade_sell;
90346
90578
  const hasDirectAvailable = directBuy !== void 0 || directSell !== void 0;
90347
90579
  const [pairBuy, pairSell] = normalizePair(source.availableToTrade);
90348
- const available_to_trade_buy = hasDirectAvailable ? toNumber2(directBuy, pairBuy) : pairBuy;
90349
- const available_to_trade_sell = hasDirectAvailable ? toNumber2(directSell, pairSell) : pairSell;
90580
+ const available_to_trade_buy = hasDirectAvailable ? toNumber(directBuy, pairBuy) : pairBuy;
90581
+ const available_to_trade_sell = hasDirectAvailable ? toNumber(directSell, pairSell) : pairSell;
90350
90582
  const directMaxBuy = source.max_trade_size_buy;
90351
90583
  const directMaxSell = source.max_trade_size_sell;
90352
90584
  const hasDirectMax = directMaxBuy !== void 0 || directMaxSell !== void 0;
90353
90585
  const [pairMaxBuy, pairMaxSell] = normalizePair(source.maxTradeSzs);
90354
- const max_trade_size_buy = hasDirectMax ? toNumber2(directMaxBuy, pairMaxBuy) : pairMaxBuy;
90355
- const max_trade_size_sell = hasDirectMax ? toNumber2(directMaxSell, pairMaxSell) : pairMaxSell;
90586
+ const max_trade_size_buy = hasDirectMax ? toNumber(directMaxBuy, pairMaxBuy) : pairMaxBuy;
90587
+ const max_trade_size_sell = hasDirectMax ? toNumber(directMaxSell, pairMaxSell) : pairMaxSell;
90356
90588
  return {
90357
90589
  symbol: String(source.coin || symbol2),
90358
90590
  available_to_trade_buy,
90359
90591
  available_to_trade_sell,
90360
90592
  max_trade_size_buy,
90361
90593
  max_trade_size_sell,
90362
- mark_price: toNumber2(source.markPx ?? source.mark_price, 0)
90594
+ mark_price: toNumber(source.markPx ?? source.mark_price, 0)
90363
90595
  };
90364
90596
  };
90365
90597
  }
@@ -90551,12 +90783,7 @@ var init_server_prompt_rescue_account_contract = __esm({
90551
90783
  };
90552
90784
  const accountValue = computeEffectiveAccountValue(formulaInput);
90553
90785
  const maintenanceMargin = toNumber3(perps.crossMaintenanceMarginUsed);
90554
- const calculatedAvailable = accountValue - totalMarginUsed;
90555
- const availableMargin = maintenanceMargin > 0 ? Math.max(
90556
- calculatedAvailable,
90557
- Math.max(0, accountValue - 4 * maintenanceMargin),
90558
- withdrawable
90559
- ) : Math.max(calculatedAvailable, withdrawable);
90786
+ const availableMargin = canonicalAvailableMargin(accountValue, totalMarginUsed);
90560
90787
  let totalNotional = 0;
90561
90788
  let totalUnrealizedPnl = 0;
90562
90789
  const positions = Array.isArray(perps.assetPositions) ? perps.assetPositions : [];
@@ -91014,18 +91241,18 @@ var init_hyperliquid_account_state_adapter = __esm({
91014
91241
  }
91015
91242
  return parsed;
91016
91243
  };
91017
- requirePromptClearinghouseState = (response, label) => {
91244
+ requirePromptClearinghouseState = (response, label2) => {
91018
91245
  if (!response || typeof response !== "object" || Array.isArray(response)) {
91019
- throw new Error(`Malformed ${label} clearinghouseState response for client runtime prompt context.`);
91246
+ throw new Error(`Malformed ${label2} clearinghouseState response for client runtime prompt context.`);
91020
91247
  }
91021
91248
  const marginSummary = response.marginSummary;
91022
91249
  if (!marginSummary || typeof marginSummary !== "object" || Array.isArray(marginSummary)) {
91023
- throw new Error(`${label} clearinghouseState is missing marginSummary for client runtime prompt context.`);
91250
+ throw new Error(`${label2} clearinghouseState is missing marginSummary for client runtime prompt context.`);
91024
91251
  }
91025
- requireFinitePromptMetric(marginSummary.accountValue, `${label}.marginSummary.accountValue`);
91026
- requireFinitePromptMetric(marginSummary.totalMarginUsed, `${label}.marginSummary.totalMarginUsed`);
91027
- requireFinitePromptMetric(marginSummary.totalNtlPos, `${label}.marginSummary.totalNtlPos`);
91028
- requireFinitePromptMetric(response.withdrawable, `${label}.withdrawable`);
91252
+ requireFinitePromptMetric(marginSummary.accountValue, `${label2}.marginSummary.accountValue`);
91253
+ requireFinitePromptMetric(marginSummary.totalMarginUsed, `${label2}.marginSummary.totalMarginUsed`);
91254
+ requireFinitePromptMetric(marginSummary.totalNtlPos, `${label2}.marginSummary.totalNtlPos`);
91255
+ requireFinitePromptMetric(response.withdrawable, `${label2}.withdrawable`);
91029
91256
  const maintenanceCandidates = [
91030
91257
  response.crossMaintenanceMarginUsed,
91031
91258
  marginSummary.crossMaintenanceMarginUsed,
@@ -91034,33 +91261,33 @@ var init_hyperliquid_account_state_adapter = __esm({
91034
91261
  const maintenance = maintenanceCandidates.find(
91035
91262
  (value) => value != null && !(typeof value === "string" && value.trim() === "")
91036
91263
  );
91037
- requireFinitePromptMetric(maintenance, `${label}.maintenanceMargin`);
91264
+ requireFinitePromptMetric(maintenance, `${label2}.maintenanceMargin`);
91038
91265
  if (!Array.isArray(response.assetPositions)) {
91039
- throw new Error(`${label} clearinghouseState is missing assetPositions for client runtime prompt context.`);
91266
+ throw new Error(`${label2} clearinghouseState is missing assetPositions for client runtime prompt context.`);
91040
91267
  }
91041
91268
  response.assetPositions.forEach((entry, index) => {
91042
91269
  const position = entry?.position;
91043
91270
  if (!position || typeof position !== "object" || Array.isArray(position)) {
91044
- throw new Error(`${label}.assetPositions[${index}] is malformed for client runtime prompt context.`);
91271
+ throw new Error(`${label2}.assetPositions[${index}] is malformed for client runtime prompt context.`);
91045
91272
  }
91046
91273
  if (!String(entry?.coin || position.coin || "").trim()) {
91047
- throw new Error(`${label}.assetPositions[${index}] is missing its symbol for client runtime prompt context.`);
91274
+ throw new Error(`${label2}.assetPositions[${index}] is missing its symbol for client runtime prompt context.`);
91048
91275
  }
91049
91276
  const size = requireFinitePromptMetric(
91050
91277
  position.szi,
91051
- `${label}.assetPositions[${index}].position.szi`
91278
+ `${label2}.assetPositions[${index}].position.szi`
91052
91279
  );
91053
91280
  if (size !== 0) {
91054
91281
  const entryPrice = requireFinitePromptMetric(
91055
91282
  position.entryPx,
91056
- `${label}.assetPositions[${index}].position.entryPx`
91283
+ `${label2}.assetPositions[${index}].position.entryPx`
91057
91284
  );
91058
91285
  if (entryPrice <= 0) {
91059
- throw new Error(`${label}.assetPositions[${index}] has a nonpositive entry price for client runtime prompt context.`);
91286
+ throw new Error(`${label2}.assetPositions[${index}] has a nonpositive entry price for client runtime prompt context.`);
91060
91287
  }
91061
91288
  requireFinitePromptMetric(
91062
91289
  position.unrealizedPnl,
91063
- `${label}.assetPositions[${index}].position.unrealizedPnl`
91290
+ `${label2}.assetPositions[${index}].position.unrealizedPnl`
91064
91291
  );
91065
91292
  }
91066
91293
  });
@@ -91084,9 +91311,12 @@ var init_hyperliquid_account_state_adapter = __esm({
91084
91311
  perpDexConfig.allowed_dexes.map(normalizePerpDexName).filter((value) => value.length > 0)
91085
91312
  ));
91086
91313
  };
91087
- listPerpDexsForAccountState = (config2, selectedDex, aggregatePerpDexs) => {
91314
+ listPerpDexsForAccountState = (config2, selectedDex, aggregatePerpDexs, perpDexScope) => {
91088
91315
  if (aggregatePerpDexs) {
91089
- return listConfiguredPerpDexs(config2);
91316
+ const configured = listConfiguredPerpDexs(config2);
91317
+ if (!perpDexScope) return configured;
91318
+ const scope = new Set(perpDexScope.map(normalizePerpDexName));
91319
+ return configured.filter((dex) => scope.has(dex));
91090
91320
  }
91091
91321
  return selectedDex ? [selectedDex] : [];
91092
91322
  };
@@ -91294,7 +91524,7 @@ var init_hyperliquid_account_state_adapter = __esm({
91294
91524
  const includeEffectiveTakerRate = input.includeEffectiveTakerRate === true;
91295
91525
  const includeExactAccountMode = input.includeExactAccountMode === true;
91296
91526
  const includeActiveAssetData = input.includeActiveAssetData !== false;
91297
- const dexNames = listPerpDexsForAccountState(input.config, dex, aggregatePerpDexs);
91527
+ const dexNames = listPerpDexsForAccountState(input.config, dex, aggregatePerpDexs, input.perpDexScope);
91298
91528
  if (scopeAccountSummaryToSelectedDex && dex && !dexNames.includes(dex)) {
91299
91529
  dexNames.push(dex);
91300
91530
  }
@@ -91592,8 +91822,7 @@ var init_hyperliquid_account_state_adapter = __esm({
91592
91822
  ])
91593
91823
  }, {}, "disabled", accountSummaryOptions);
91594
91824
  const accountValue = Number(payload.marginSummary.accountValue);
91595
- const calculatedAvailable = accountValue - summary.total_margin_used;
91596
- const availableMargin = summary.maintenance_margin > 0 ? Math.max(calculatedAvailable, Math.max(0, accountValue - 4 * summary.maintenance_margin), summary.withdrawable) : Math.max(calculatedAvailable, summary.withdrawable);
91825
+ const availableMargin = canonicalAvailableMargin(accountValue, summary.total_margin_used);
91597
91826
  return {
91598
91827
  dex,
91599
91828
  account_value: accountValue,
@@ -91898,7 +92127,7 @@ var init_protective_evidence = __esm({
91898
92127
  const perDex = /* @__PURE__ */ new Map();
91899
92128
  const scope = `${String(input.apiUrl ?? "")}|${wallet.toLowerCase()}`;
91900
92129
  const shareable = batch.every((item) => item.kind !== "fills" && item.shareable);
91901
- const dexRead = (key, body, label) => {
92130
+ const dexRead = (key, body, label2) => {
91902
92131
  let read = perDex.get(key);
91903
92132
  if (read) return read;
91904
92133
  const sharedKey = `${scope}|${key}`;
@@ -91908,7 +92137,7 @@ var init_protective_evidence = __esm({
91908
92137
  startedAtMonotonicMs = Math.min(startedAtMonotonicMs, shared.startedAtMonotonicMs);
91909
92138
  read = shared.read;
91910
92139
  } else {
91911
- read = readOrNull(() => fetchBrowserHyperliquidInfoPayload(input, body, label));
92140
+ read = readOrNull(() => fetchBrowserHyperliquidInfoPayload(input, body, label2));
91912
92141
  const entry = { startedAtMonotonicMs: now, read };
91913
92142
  sharedAccountReads.set(sharedKey, entry);
91914
92143
  void read.then((value) => {
@@ -92085,19 +92314,19 @@ var init_protective_actions = __esm({
92085
92314
  "local_safety_block"
92086
92315
  );
92087
92316
  };
92088
- exactKeys = (value, keys, label) => {
92089
- if (!value || typeof value !== "object" || Array.isArray(value)) fail2(`${label} is not an object.`);
92317
+ exactKeys = (value, keys, label2) => {
92318
+ if (!value || typeof value !== "object" || Array.isArray(value)) fail2(`${label2} is not an object.`);
92090
92319
  const record5 = value;
92091
92320
  const present = Object.keys(record5).sort();
92092
- if (present.join(",") !== [...keys].sort().join(",")) fail2(`${label} has unexpected fields.`);
92321
+ if (present.join(",") !== [...keys].sort().join(",")) fail2(`${label2} has unexpected fields.`);
92093
92322
  return record5;
92094
92323
  };
92095
- nonNegativeInteger = (value, label) => {
92096
- if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) fail2(`${label} is invalid.`);
92324
+ nonNegativeInteger = (value, label2) => {
92325
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) fail2(`${label2} is invalid.`);
92097
92326
  return value;
92098
92327
  };
92099
- decimalString = (value, label) => {
92100
- if (typeof value !== "string" || !DECIMAL.test(value) || Number(value) <= 0) fail2(`${label} is invalid.`);
92328
+ decimalString = (value, label2) => {
92329
+ if (typeof value !== "string" || !DECIMAL.test(value) || Number(value) <= 0) fail2(`${label2} is invalid.`);
92101
92330
  return value;
92102
92331
  };
92103
92332
  canonicalTriggerOrder = (value) => {
@@ -92407,6 +92636,119 @@ var init_protective_actions = __esm({
92407
92636
  }
92408
92637
  });
92409
92638
 
92639
+ // lib/runtime/bounded-lock.ts
92640
+ var webLocks, inProcessTails, abortReason, waitBounded, withInProcessLock, withBoundedExclusiveLock;
92641
+ var init_bounded_lock = __esm({
92642
+ "lib/runtime/bounded-lock.ts"() {
92643
+ "use strict";
92644
+ init_define_VTX_EXO_POLICY();
92645
+ init_define_VTX_GROK_POLICY();
92646
+ init_define_VTX_PI_MODEL_POLICY();
92647
+ webLocks = () => {
92648
+ const locks = typeof navigator === "undefined" ? void 0 : navigator.locks;
92649
+ return locks && typeof locks.request === "function" ? locks : null;
92650
+ };
92651
+ inProcessTails = /* @__PURE__ */ new Map();
92652
+ abortReason = (signal) => signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
92653
+ waitBounded = (gate, waitMs, signal) => new Promise((resolve14, reject) => {
92654
+ if (signal?.aborted) {
92655
+ reject(abortReason(signal));
92656
+ return;
92657
+ }
92658
+ const finish = () => {
92659
+ clearTimeout(timer);
92660
+ signal?.removeEventListener("abort", onAbort);
92661
+ };
92662
+ const onAbort = () => {
92663
+ finish();
92664
+ reject(abortReason(signal));
92665
+ };
92666
+ const timer = setTimeout(() => {
92667
+ finish();
92668
+ resolve14();
92669
+ }, waitMs);
92670
+ signal?.addEventListener("abort", onAbort, { once: true });
92671
+ void gate.then(() => {
92672
+ finish();
92673
+ resolve14();
92674
+ });
92675
+ });
92676
+ withInProcessLock = async (name, waitMs, work, signal) => {
92677
+ const previous = inProcessTails.get(name) ?? Promise.resolve();
92678
+ let release;
92679
+ const released = new Promise((resolve14) => {
92680
+ release = resolve14;
92681
+ });
92682
+ const tail = previous.then(() => released);
92683
+ inProcessTails.set(name, tail);
92684
+ try {
92685
+ await waitBounded(previous, waitMs, signal);
92686
+ return await work();
92687
+ } finally {
92688
+ release();
92689
+ if (inProcessTails.get(name) === tail) inProcessTails.delete(name);
92690
+ }
92691
+ };
92692
+ withBoundedExclusiveLock = async (name, waitMs, work, signal) => {
92693
+ if (!Number.isFinite(waitMs) || waitMs <= 0) {
92694
+ throw new Error(`Invalid lock wait bound for ${name}.`);
92695
+ }
92696
+ const locks = webLocks();
92697
+ if (locks == null) return withInProcessLock(name, waitMs, work, signal);
92698
+ const waitTimeout = new AbortController();
92699
+ const timer = setTimeout(() => waitTimeout.abort(), waitMs);
92700
+ const relayAbort = () => waitTimeout.abort();
92701
+ signal?.addEventListener("abort", relayAbort, { once: true });
92702
+ let acquired = false;
92703
+ try {
92704
+ return await locks.request(name, { signal: waitTimeout.signal }, async () => {
92705
+ acquired = true;
92706
+ clearTimeout(timer);
92707
+ signal?.removeEventListener("abort", relayAbort);
92708
+ return work();
92709
+ });
92710
+ } catch (error48) {
92711
+ if (acquired) throw error48;
92712
+ if (signal?.aborted) throw abortReason(signal);
92713
+ if (!waitTimeout.signal.aborted) throw error48;
92714
+ return work();
92715
+ } finally {
92716
+ clearTimeout(timer);
92717
+ signal?.removeEventListener("abort", relayAbort);
92718
+ }
92719
+ };
92720
+ }
92721
+ });
92722
+
92723
+ // lib/api/client-exchange-mutations.ts
92724
+ async function getClientRuntimeExchangeMutation(profileId, mutationId, signal) {
92725
+ const numericProfileId = Number(profileId);
92726
+ const response = await apiFetch(
92727
+ `${getApiUrl()}/trading/ai/runtime/exchange-mutations/${encodeURIComponent(String(mutationId).trim().toLowerCase())}`,
92728
+ {
92729
+ method: "GET",
92730
+ credentials: "include",
92731
+ cache: "no-store",
92732
+ headers: getProfileHeaders({}, Number.isSafeInteger(numericProfileId) ? numericProfileId : void 0),
92733
+ signal
92734
+ }
92735
+ );
92736
+ if (response.status === 404) return null;
92737
+ if (!response.ok) {
92738
+ throw new Error(await getErrorMessageFromResponse(response, "Failed to read the exchange mutation"));
92739
+ }
92740
+ return response.json();
92741
+ }
92742
+ var init_client_exchange_mutations = __esm({
92743
+ "lib/api/client-exchange-mutations.ts"() {
92744
+ "use strict";
92745
+ init_define_VTX_EXO_POLICY();
92746
+ init_define_VTX_GROK_POLICY();
92747
+ init_define_VTX_PI_MODEL_POLICY();
92748
+ init_shared();
92749
+ }
92750
+ });
92751
+
92410
92752
  // lib/runtime/execution-guard-contract.ts
92411
92753
  var unitsFromPosition, signedUnitsFromPosition, signedUnitsFromEntryPosition, classifyExecutionIntent, resolveExecutionTarget;
92412
92754
  var init_execution_guard_contract = __esm({
@@ -92692,7 +93034,7 @@ var init_protective_trigger_price = __esm({
92692
93034
  });
92693
93035
 
92694
93036
  // lib/runtime/runtime-execution.ts
92695
- var clientProtectiveMutationAuthority, executionReadPriority, fetchClientRuntimeOpenOrders, _extractOrderResponseStates, createRuntimeId, _extractOrderId, _toExecutionMetadata, _extractClientMutationId, _stableMutationIdentity, trailingStopMemory, protectiveGroupMemory, protectiveGroupReadFailures, windowHandoffCleanupAttempts, clientRuntimeProtectionStorage, resolveClientRuntimeProtectionStorage, setClientRuntimeProtectionStorage, trailingStopStorageKey, readTrackedTrailingStops, writeTrackedTrailingStops, rememberTrailingStop, protectiveGroupStorageKey, readClientProtectiveGroups, writeClientProtectiveGroups, hasClientProtectiveGroupReadFailure, readFreshClientProtectiveGroups, stableProtectionSnapshot, exactClientProtectiveGroupSnapshot, exactClientProtectiveGroupSetSnapshot, replaceExactClientProtectiveGroup, replaceExactClientProtectiveGroupSet, isClientRuntimeLeaseOwnershipError, hasClientRuntimeProtectionState, clearClientRuntimeVetoedProtectiveIntent, rethrowWindowHandoffAfterProtectiveReplacementVeto, canPersistClientProtectiveGroups, removeTrackedTrailingStop, replaceTrackedTrailingStop, replaceProtectiveLeg, replacementJournalEntryOrderId, buildProtectiveReplacementJournalGroup, isProtectiveReplacementJournalGroup, reserveProtectiveLegReplacement, ensureProtectiveReplacementJournalCompanion, buildVetoedProtectiveReplacementCleanup, assertExactProtectiveReplacementDispatchAuthority, transitionProtectiveReplacementAcknowledgement, transitionTerminalProtectiveReplacement, pendingProtectiveReplacementReport, isConfiguredProtectionRequested, protectiveAction, isExactClientPositionTpslPair, deviceOwnsClientProtectiveLegKind, isAdoptionNarrowedPositionTpslLeg, hasAmbiguousClientPositionTpslAuthority, protectiveStableShapeMatches, protectiveLiveShapeMatches, protectiveTerminalShapeMatches, cancelClientProtectiveLeg, buildPendingProtectivePlan, persistPendingClientProtectiveGroup, attachClientProtectivePlan, resolveJournaledAttachmentContinuity, recoverJournaledClientProtectiveAttachments, recoverPendingClientProtectiveGroups, recoverPendingProtectiveReplacements, reconcileClientProtectiveGroups, cancelAllClientProtectiveGroups, tightenClientTrailingStops, throwIfAborted2, sleep2, roundAssetSize, resolvePositionSize, resolveCurrentPositionSize, buildPositionSnapshot, signedRemainingExposureAfterConfirmedReduction, runtimeProtectionAuthority, runtimeProtectionOwners, resolveRuntimeProtectionOwner, drainServerProtectionForRuntime, drainServerProtectionIfOwned, verifyNoLiveClientProtectiveTriggers, clientExecutionMutations, withClientExecutionMutation, withClientProtectiveAdoptionMutation, executeClientRuntimeDecision, maintainClientRuntimeTrailingStops, listPendingClientProtectiveSymbols, listStoredClientProtectiveSymbols, hasUnresolvedClientProtectiveIdentity, resolveClientProtectiveIdentitiesForAdoption, exportClientProtectiveGroupsForAdoption, adoptionGroupKey, applyClientProtectiveAdoptionOutcomes, hasStoredClientProtectiveGroupsForWallet, hasPendingClientProtectiveGroups, recoverManualClientProtectiveGroups, executeClientRuntimeDecisionUnlocked, executeClientCopyTradingIntent, executeClientCopyTradingOrderAction;
93037
+ var clientProtectiveMutationAuthority, executionReadPriority, serverEntryLeverageAlreadyHeld, fetchClientRuntimeOpenOrders, _extractOrderResponseStates, createRuntimeId, _extractOrderId, _toExecutionMetadata, _extractClientMutationId, _stableMutationIdentity, trailingStopMemory, protectiveGroupMemory, protectiveGroupReadFailures, windowHandoffCleanupAttempts, clientRuntimeProtectionStorage, resolveClientRuntimeProtectionStorage, setClientRuntimeProtectionStorage, trailingStopStorageKey, readTrackedTrailingStops, writeTrackedTrailingStops, rememberTrailingStop, protectiveGroupStorageKey, withClientProtectivePlanSetLock, readClientProtectiveGroups, writeClientProtectiveGroups, hasClientProtectiveGroupReadFailure, readFreshClientProtectiveGroups, stableProtectionSnapshot, exactClientProtectiveGroupSnapshot, exactClientProtectiveGroupSetSnapshot, replaceExactClientProtectiveGroup, replaceExactClientProtectiveGroupSet, isClientRuntimeLeaseOwnershipError, hasClientRuntimeProtectionState, clearClientRuntimeVetoedProtectiveIntent, rethrowWindowHandoffAfterProtectiveReplacementVeto, canPersistClientProtectiveGroups, removeTrackedTrailingStop, replaceTrackedTrailingStop, replaceProtectiveLeg, replacementJournalEntryOrderId, buildProtectiveReplacementJournalGroup, isProtectiveReplacementJournalGroup, reserveProtectiveLegReplacement, ensureProtectiveReplacementJournalCompanion, buildVetoedProtectiveReplacementCleanup, assertExactProtectiveReplacementDispatchAuthority, transitionProtectiveReplacementAcknowledgement, transitionTerminalProtectiveReplacement, pendingProtectiveReplacementReport, isConfiguredProtectionRequested, protectiveAction, isExactClientPositionTpslPair, deviceOwnsClientProtectiveLegKind, isAdoptionNarrowedPositionTpslLeg, hasAmbiguousClientPositionTpslAuthority, protectiveStableShapeMatches, protectiveLiveShapeMatches, protectiveTerminalShapeMatches, cancelClientProtectiveLeg, buildPendingProtectivePlan, persistPendingClientProtectiveGroup, attachClientProtectivePlan, resolveJournaledAttachmentContinuity, recoverJournaledClientProtectiveAttachments, readPendingEntryMutation, requireClientRuntimeConfigSeconds, replacePendingEntryRecovery, recoverPendingClientProtectiveGroups, recoverPendingProtectiveReplacements, reconcileClientProtectiveGroups, cancelAllClientProtectiveGroups, tightenClientTrailingStops, throwIfAborted2, sleep2, isDefinitiveEntryRejection, resolveExchangeSizeDecimals, roundAssetSize, resolvePositionSize, resolveCurrentPositionSize, buildPositionSnapshot, signedRemainingExposureAfterConfirmedReduction, runtimeProtectionAuthority, runtimeProtectionOwners, resolveRuntimeProtectionOwner, drainServerProtectionForRuntime, drainServerProtectionIfOwned, verifyNoLiveClientProtectiveTriggers, clientExecutionMutations, withClientExecutionMutation, allocateServerExecutionCapacity, withClientProtectiveAdoptionMutation, executeClientRuntimeDecisionLocked, SERVER_AUDIT_RECORDED_ELSEWHERE, serverExecutionAuditOutcome, executeClientRuntimeDecision, waitForFlipCloseFreshness, maintainClientRuntimeTrailingStops, listPendingClientProtectiveSymbols, listStoredClientProtectiveSymbols, hasUnresolvedClientProtectiveIdentity, resolveClientProtectiveIdentitiesForAdoption, exportClientProtectiveGroupsForAdoption, adoptionGroupKey, applyClientProtectiveAdoptionOutcomes, hasStoredClientProtectiveGroupsForWallet, hasPendingClientProtectiveGroups, recoverManualClientProtectiveGroups, clientRuntimeDecisionSizesOrders, executeClientRuntimeDecisionUnlocked, executeClientCopyTradingIntent, executeClientCopyTradingOrderAction;
92696
93038
  var init_runtime_execution = __esm({
92697
93039
  "lib/runtime/runtime-execution.ts"() {
92698
93040
  "use strict";
@@ -92700,8 +93042,11 @@ var init_runtime_execution = __esm({
92700
93042
  init_define_VTX_GROK_POLICY();
92701
93043
  init_define_VTX_PI_MODEL_POLICY();
92702
93044
  init_order_identity();
93045
+ init_runtime_policy_generated2();
93046
+ init_bounded_lock();
92703
93047
  init_client_runtime_ownership_errors();
92704
93048
  init_api2();
93049
+ init_client_exchange_mutations();
92705
93050
  init_hyperliquid_order_status();
92706
93051
  init_protective_actions();
92707
93052
  init_browser_trading();
@@ -92729,6 +93074,26 @@ var init_runtime_execution = __esm({
92729
93074
  );
92730
93075
  return classified.reduceOnly ? "trading_reduce" : "trading_execute";
92731
93076
  };
93077
+ serverEntryLeverageAlreadyHeld = async (input) => {
93078
+ if (input.executionMode !== "server") return false;
93079
+ const context = input.executionContext;
93080
+ const symbol2 = normalizeHyperliquidMarketSymbol(context.symbol);
93081
+ const wallet = String(context.walletAddress || "").trim();
93082
+ if (!symbol2 || !wallet || !Number.isInteger(context.leverage) || context.leverage <= 0 || !Number.isFinite(context.currentPositionSize) || context.currentPositionSize === 0) return false;
93083
+ let active;
93084
+ try {
93085
+ active = await fetchBrowserHyperliquidInfoPayload(
93086
+ { config: input.config ?? null, signal: input.signal, publicRequestPriority: "trading_reconcile" },
93087
+ { type: "activeAssetData", user: wallet, coin: symbol2 },
93088
+ "hyperliquid.activeAssetData"
93089
+ );
93090
+ } catch {
93091
+ throwIfAborted2(input.signal);
93092
+ return false;
93093
+ }
93094
+ const leverage = active?.leverage;
93095
+ return leverage?.value === context.leverage && leverage?.type === (context.marginMode === "isolated" ? "isolated" : "cross");
93096
+ };
92732
93097
  fetchClientRuntimeOpenOrders = async (request, publicRequestPriority = "trading_reconcile") => {
92733
93098
  const normalizedSymbol = normalizeHyperliquidMarketSymbol(
92734
93099
  request.executionContext.symbol
@@ -92943,6 +93308,12 @@ var init_runtime_execution = __esm({
92943
93308
  ]);
92944
93309
  };
92945
93310
  protectiveGroupStorageKey = (profileId, symbol2) => `vtx:auto-protective-group:${profileId}:${symbol2}`;
93311
+ withClientProtectivePlanSetLock = (profileId, symbol2, work, signal) => withBoundedExclusiveLock(
93312
+ `vtx:protective-plan-set:${protectiveGroupStorageKey(String(profileId).trim(), String(symbol2).trim())}`,
93313
+ runtime_policy_generated_default2.trading.engine.client_runtime.protective_plan_set_lock.wait_seconds * 1e3,
93314
+ work,
93315
+ signal
93316
+ );
92946
93317
  readClientProtectiveGroups = (profileId, symbol2) => {
92947
93318
  const key = protectiveGroupStorageKey(profileId, symbol2);
92948
93319
  const inMemory = protectiveGroupMemory.get(key);
@@ -93036,12 +93407,41 @@ var init_runtime_execution = __esm({
93036
93407
  const pending3 = pendingRecord;
93037
93408
  const stopLoss = pending3.stopLoss;
93038
93409
  const takeProfit = pending3.takeProfit;
93039
- if (typeof pending3.entryMutationId !== "string" || !/^[0-9a-f-]{36}$/.test(pending3.entryMutationId) || typeof pending3.entryClientOrderId !== "string" || !/^0x[0-9a-f]{32}$/.test(pending3.entryClientOrderId) || pending3.entrySide !== "buy" && pending3.entrySide !== "sell" || !Number.isFinite(Number(pending3.requestedSize)) || Number(pending3.requestedSize) <= 0 || stopLoss == null || typeof stopLoss !== "object" || Array.isArray(stopLoss) || takeProfit == null || typeof takeProfit !== "object" || Array.isArray(takeProfit)) {
93410
+ if (typeof pending3.entryMutationId !== "string" || !/^[0-9a-f-]{36}$/.test(pending3.entryMutationId) || typeof pending3.entryClientOrderId !== "string" || !/^0x[0-9a-f]{32}$/.test(pending3.entryClientOrderId) || pending3.entrySide !== "buy" && pending3.entrySide !== "sell" || !Number.isFinite(Number(pending3.requestedSize)) || Number(pending3.requestedSize) <= 0 || pending3.createdAtMs != null && (typeof pending3.createdAtMs !== "number" || !Number.isSafeInteger(pending3.createdAtMs) || pending3.createdAtMs <= 0) || stopLoss == null || typeof stopLoss !== "object" || Array.isArray(stopLoss) || takeProfit == null || typeof takeProfit !== "object" || Array.isArray(takeProfit)) {
93040
93411
  protectiveGroupReadFailures.add(key);
93041
93412
  return [];
93042
93413
  }
93043
93414
  const sl = stopLoss;
93044
93415
  const tp = takeProfit;
93416
+ let recovery;
93417
+ if (pending3.recovery != null) {
93418
+ const recoveryRecord = pending3.recovery;
93419
+ if (typeof recoveryRecord !== "object" || Array.isArray(recoveryRecord)) {
93420
+ protectiveGroupReadFailures.add(key);
93421
+ return [];
93422
+ }
93423
+ const {
93424
+ unknownOidObservedAtMs,
93425
+ unknownOidFirstSeenAtMs,
93426
+ attempts,
93427
+ nextAttemptAtMs,
93428
+ staleReported,
93429
+ entryFilled
93430
+ } = recoveryRecord;
93431
+ const invalidCount = (value, minimum) => value != null && (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum);
93432
+ if (invalidCount(unknownOidObservedAtMs, 1) || invalidCount(unknownOidFirstSeenAtMs, 1) || invalidCount(attempts, 0) || invalidCount(nextAttemptAtMs, 0) || staleReported != null && typeof staleReported !== "boolean" || entryFilled != null && typeof entryFilled !== "boolean") {
93433
+ protectiveGroupReadFailures.add(key);
93434
+ return [];
93435
+ }
93436
+ recovery = {
93437
+ ...typeof unknownOidObservedAtMs === "number" ? { unknownOidObservedAtMs } : {},
93438
+ ...typeof unknownOidFirstSeenAtMs === "number" ? { unknownOidFirstSeenAtMs } : {},
93439
+ ...typeof attempts === "number" ? { attempts } : {},
93440
+ ...typeof nextAttemptAtMs === "number" ? { nextAttemptAtMs } : {},
93441
+ ...typeof staleReported === "boolean" ? { staleReported } : {},
93442
+ ...typeof entryFilled === "boolean" ? { entryFilled } : {}
93443
+ };
93444
+ }
93045
93445
  if (typeof sl.enabled !== "boolean" || sl.mode !== "percent" && sl.mode !== "usdc" || !Number.isFinite(Number(sl.value)) || Number(sl.value) < 0 || typeof sl.isTrailing !== "boolean" || typeof tp.enabled !== "boolean" || tp.mode !== "percent" && tp.mode !== "usdc" || !Number.isFinite(Number(tp.value)) || Number(tp.value) < 0) {
93046
93446
  protectiveGroupReadFailures.add(key);
93047
93447
  return [];
@@ -93051,6 +93451,7 @@ var init_runtime_execution = __esm({
93051
93451
  entryClientOrderId: pending3.entryClientOrderId,
93052
93452
  entrySide: pending3.entrySide,
93053
93453
  requestedSize: Number(pending3.requestedSize),
93454
+ ...typeof pending3.createdAtMs === "number" ? { createdAtMs: pending3.createdAtMs } : {},
93054
93455
  stopLoss: {
93055
93456
  enabled: sl.enabled,
93056
93457
  mode: sl.mode,
@@ -93061,7 +93462,8 @@ var init_runtime_execution = __esm({
93061
93462
  enabled: tp.enabled,
93062
93463
  mode: tp.mode,
93063
93464
  value: Number(tp.value)
93064
- }
93465
+ },
93466
+ ...recovery ? { recovery } : {}
93065
93467
  };
93066
93468
  }
93067
93469
  const attachmentRecord = record5.attachmentJournal;
@@ -93805,6 +94207,7 @@ var init_runtime_execution = __esm({
93805
94207
  };
93806
94208
  buildPendingProtectivePlan = (settings, input) => ({
93807
94209
  ...input,
94210
+ createdAtMs: Date.now(),
93808
94211
  stopLoss: {
93809
94212
  enabled: settings.stopLossEnabled !== false,
93810
94213
  mode: settings.stopLossMode === "usdc" ? "usdc" : "percent",
@@ -94430,7 +94833,7 @@ var init_runtime_execution = __esm({
94430
94833
  }
94431
94834
  return reports;
94432
94835
  };
94433
- resolveJournaledAttachmentContinuity = async (request, group) => {
94836
+ resolveJournaledAttachmentContinuity = async (request, group, options = {}) => {
94434
94837
  const journal = group.attachmentJournal;
94435
94838
  const plan = group.pendingEntry;
94436
94839
  if (journal == null || plan == null) {
@@ -94527,7 +94930,7 @@ var init_runtime_execution = __esm({
94527
94930
  throw new Error("Journaled protective entry chronology is unresolved.");
94528
94931
  }
94529
94932
  const firstEntry = canonicalRows[firstEntryIndex];
94530
- if (expectedSign * firstEntry.startPosition < -positionTolerance(firstEntry.startPosition, 0)) {
94933
+ if (options.allowOppositeStart !== true && expectedSign * firstEntry.startPosition < -positionTolerance(firstEntry.startPosition, 0)) {
94531
94934
  throw new Error("Journaled protective entry start position is directionally unresolved.");
94532
94935
  }
94533
94936
  let expectedExposureEstablished = false;
@@ -94929,20 +95332,117 @@ var init_runtime_execution = __esm({
94929
95332
  }
94930
95333
  return reports;
94931
95334
  };
94932
- recoverPendingClientProtectiveGroups = async (request, pendingGroups) => {
95335
+ readPendingEntryMutation = async (request, plan) => {
95336
+ try {
95337
+ const mutation = await getClientRuntimeExchangeMutation(
95338
+ request.profileId,
95339
+ plan.entryMutationId,
95340
+ request.signal
95341
+ );
95342
+ if (mutation == null) return { kind: "absent" };
95343
+ return mutation.operation_kind === "order" && String(mutation.client_order_id ?? "").trim().toLowerCase() === plan.entryClientOrderId ? { kind: "found", mutation } : { kind: "unavailable" };
95344
+ } catch (error48) {
95345
+ if (request.signal?.aborted) throw error48;
95346
+ return { kind: "unavailable" };
95347
+ }
95348
+ };
95349
+ requireClientRuntimeConfigSeconds = (config2, key) => {
95350
+ const value = Number(config2?.[key]);
95351
+ if (!Number.isFinite(value) || value < 0) {
95352
+ throw new Error(`Missing required client runtime config: ${String(key)}`);
95353
+ }
95354
+ return value;
95355
+ };
95356
+ replacePendingEntryRecovery = (profileId, symbol2, group, recovery) => {
95357
+ const plan = group.pendingEntry;
95358
+ if (plan == null) throw new Error("Pending entry plan is unavailable.");
95359
+ const updated = { ...group, pendingEntry: { ...plan, recovery } };
95360
+ if (!replaceExactClientProtectiveGroup(profileId, symbol2, group, updated)) {
95361
+ throw new Error("Pending entry recovery state could not be saved durably.");
95362
+ }
95363
+ return updated;
95364
+ };
95365
+ recoverPendingClientProtectiveGroups = async (request, pendingGroups, retirements = [], reportsStale = false) => {
94933
95366
  const reports = [];
94934
95367
  const profileId = String(request.profileId).trim();
94935
95368
  const symbol2 = request.executionContext.symbol;
94936
- for (const group of pendingGroups) {
95369
+ const retryInitialMs = requireClientRuntimeConfigSeconds(
95370
+ request.config,
95371
+ "client_pending_entry_retry_initial_seconds"
95372
+ ) * 1e3;
95373
+ const retryMaxMs = Math.max(retryInitialMs, requireClientRuntimeConfigSeconds(
95374
+ request.config,
95375
+ "client_pending_entry_retry_max_seconds"
95376
+ ) * 1e3);
95377
+ const staleAfterAttempts = Math.max(1, Math.trunc(requireClientRuntimeConfigSeconds(
95378
+ request.config,
95379
+ "client_pending_entry_stale_after_attempts"
95380
+ )));
95381
+ for (const storedGroup of pendingGroups) {
95382
+ let group = storedGroup;
94937
95383
  const plan = group.pendingEntry;
94938
95384
  if (plan == null) continue;
95385
+ const waitMs = (plan.recovery?.nextAttemptAtMs ?? 0) - Date.now();
95386
+ if (waitMs > 0 && waitMs <= retryMaxMs) continue;
95387
+ let entryFilled = plan.recovery?.entryFilled === true || group.attachmentJournal != null;
95388
+ const recordUnresolved = (errorMessage) => {
95389
+ const currentRecovery = group.pendingEntry?.recovery ?? plan.recovery;
95390
+ const attempts = (currentRecovery?.attempts ?? 0) + 1;
95391
+ const reachedCap = attempts >= staleAfterAttempts;
95392
+ const reportStale = reachedCap && reportsStale && currentRecovery?.staleReported !== true;
95393
+ try {
95394
+ group = replacePendingEntryRecovery(profileId, symbol2, group, {
95395
+ ...currentRecovery,
95396
+ attempts,
95397
+ nextAttemptAtMs: entryFilled ? Date.now() : Date.now() + Math.min(retryMaxMs, retryInitialMs * 2 ** Math.min(30, attempts - 1)),
95398
+ ...entryFilled ? { entryFilled: true } : {},
95399
+ ...reportStale || currentRecovery?.staleReported === true ? { staleReported: true } : {}
95400
+ });
95401
+ } catch {
95402
+ reports.push({
95403
+ order_id: plan.entryClientOrderId,
95404
+ client_mutation_id: plan.entryMutationId,
95405
+ symbol: symbol2,
95406
+ action: "PROTECTIVE_RECONCILIATION",
95407
+ status: "failed",
95408
+ execution_metadata: { reason_code: "protective_lifecycle_persistence_failed" }
95409
+ });
95410
+ }
95411
+ if (errorMessage == null && !reportStale) return;
95412
+ if (reachedCap && !reportStale) return;
95413
+ reports.push({
95414
+ order_id: plan.entryClientOrderId,
95415
+ client_mutation_id: plan.entryMutationId,
95416
+ symbol: symbol2,
95417
+ action: "PROTECTIVE_RECONCILIATION",
95418
+ status: "failed",
95419
+ execution_metadata: {
95420
+ reason_code: reportStale ? "pending_protective_entry_stale" : "pending_protective_entry_unresolved",
95421
+ attempts,
95422
+ ...errorMessage ? { error: errorMessage } : {}
95423
+ }
95424
+ });
95425
+ };
95426
+ const recordIfStillPending = () => {
95427
+ const stored = readFreshClientProtectiveGroups(profileId, symbol2);
95428
+ const snapshot = exactClientProtectiveGroupSnapshot(group);
95429
+ if (stored.some((candidate) => exactClientProtectiveGroupSnapshot(candidate) === snapshot)) {
95430
+ recordUnresolved(null);
95431
+ }
95432
+ };
95433
+ const retire = (reasonCode) => {
95434
+ if (!replaceExactClientProtectiveGroup(profileId, symbol2, group, null)) {
95435
+ throw new Error("Pending entry plan could not be retired durably.");
95436
+ }
95437
+ retirements.push({ entryOrderId: plan.entryClientOrderId, reasonCode });
95438
+ };
94939
95439
  try {
94940
95440
  if (group.attachmentJournal != null) {
94941
- const { disposition } = await resolveJournaledAttachmentContinuity(
95441
+ const { disposition: disposition2 } = await resolveJournaledAttachmentContinuity(
94942
95442
  request,
94943
95443
  group
94944
95444
  );
94945
- if (disposition !== "matching") {
95445
+ if (disposition2 !== "matching") {
94946
95446
  if (!replaceExactClientProtectiveGroup(profileId, symbol2, group, null)) {
94947
95447
  reports.push({
94948
95448
  order_id: group.attachmentJournal.entryOrderId,
@@ -94965,6 +95465,13 @@ var init_runtime_execution = __esm({
94965
95465
  attachment2.handoffCleanup
94966
95466
  );
94967
95467
  }
95468
+ recordIfStillPending();
95469
+ continue;
95470
+ }
95471
+ const ledger = await readPendingEntryMutation(request, plan);
95472
+ const mutation = ledger.kind === "found" ? ledger.mutation : null;
95473
+ if (mutation != null && (mutation.status === "settled" || mutation.status === "reconciled") && mutation.outcome_code === "rejected") {
95474
+ retire("pending_protective_entry_rejected");
94968
95475
  continue;
94969
95476
  }
94970
95477
  const evidence = await fetchBrowserOrderStatusEvidence({
@@ -94974,12 +95481,102 @@ var init_runtime_execution = __esm({
94974
95481
  signal: request.signal,
94975
95482
  orderId: plan.entryClientOrderId
94976
95483
  });
95484
+ if (evidence.responseValid && evidence.responseStatus === "unknownOid") {
95485
+ const observedAtMs = Date.now();
95486
+ const marginMs = requireClientRuntimeConfigSeconds(
95487
+ request.config,
95488
+ "client_pending_entry_never_landed_margin_seconds"
95489
+ ) * 1e3;
95490
+ const firstSeenAtMs = plan.recovery?.unknownOidFirstSeenAtMs ?? observedAtMs;
95491
+ const recordFirstSeen = () => {
95492
+ if (plan.recovery?.unknownOidFirstSeenAtMs != null) return;
95493
+ group = replacePendingEntryRecovery(profileId, symbol2, group, {
95494
+ ...group.pendingEntry?.recovery ?? plan.recovery,
95495
+ unknownOidFirstSeenAtMs: firstSeenAtMs
95496
+ });
95497
+ };
95498
+ let provableAtMs;
95499
+ if (ledger.kind === "found") {
95500
+ const expiresAfterMs = Number(ledger.mutation.exchange_expires_after_ms);
95501
+ if (!Number.isSafeInteger(expiresAfterMs) || expiresAfterMs <= 0) {
95502
+ throw new Error("Pending entry is unknown to Hyperliquid and its signed expiry is unavailable.");
95503
+ }
95504
+ provableAtMs = expiresAfterMs + marginMs;
95505
+ } else if (ledger.kind === "absent") {
95506
+ const ageStartMs = plan.createdAtMs ?? firstSeenAtMs;
95507
+ const signedLifetimeSeconds = Number(
95508
+ request.config?.client_runtime_exchange_mutation?.expires_after_seconds
95509
+ );
95510
+ if (!Number.isInteger(signedLifetimeSeconds) || signedLifetimeSeconds <= 0) {
95511
+ throw new Error("Missing required client runtime config: client_runtime_exchange_mutation.expires_after_seconds");
95512
+ }
95513
+ provableAtMs = ageStartMs + signedLifetimeSeconds * 1e3 + marginMs;
95514
+ } else {
95515
+ recordFirstSeen();
95516
+ throw new Error("Pending entry is unknown to Hyperliquid and the ledger cannot answer.");
95517
+ }
95518
+ if (observedAtMs < provableAtMs) {
95519
+ recordFirstSeen();
95520
+ throw new Error("Pending entry is unknown to Hyperliquid while its signed action can still land.");
95521
+ }
95522
+ const confirmedAtMs = plan.recovery?.unknownOidObservedAtMs;
95523
+ if (confirmedAtMs == null || confirmedAtMs < provableAtMs) {
95524
+ group = replacePendingEntryRecovery(profileId, symbol2, group, {
95525
+ ...group.pendingEntry?.recovery ?? plan.recovery,
95526
+ unknownOidFirstSeenAtMs: firstSeenAtMs,
95527
+ unknownOidObservedAtMs: observedAtMs
95528
+ });
95529
+ throw new Error("Pending entry is unknown to Hyperliquid; a second read confirms it never landed.");
95530
+ }
95531
+ const { rawFills: unknownEntryFills, evidence: unknownEntryFillEvidence } = await fetchBrowserUserFills({
95532
+ publicRequestPriority: "trading_reconcile",
95533
+ config: request.config ?? {},
95534
+ walletAddress: String(request.executionContext.walletAddress || "").trim(),
95535
+ symbols: [symbol2],
95536
+ forceRefresh: true,
95537
+ signal: request.signal
95538
+ });
95539
+ if (unknownEntryFillEvidence?.exactTerminalFillEvidenceComplete !== true) {
95540
+ throw new Error(
95541
+ `Never-landed pending entry fills are incomplete (${unknownEntryFillEvidence?.source ?? "unknown"}; provider_rows=${unknownEntryFillEvidence?.providerRowCount ?? "unknown"}).`
95542
+ );
95543
+ }
95544
+ if (unknownEntryFills.some((fill) => String(fill.cloid ?? "").trim().toLowerCase() === plan.entryClientOrderId)) {
95545
+ throw new Error("Pending entry is unknown to Hyperliquid but has fills for its CLOID.");
95546
+ }
95547
+ if (ledger.kind === "absent" && (await readPendingEntryMutation(request, plan)).kind !== "absent") {
95548
+ throw new Error("Pending entry reached the ledger while its retirement was being proven.");
95549
+ }
95550
+ retire("pending_protective_entry_never_landed");
95551
+ continue;
95552
+ }
94977
95553
  const expectedSide = plan.entrySide === "buy" ? ["b", "buy"] : ["a", "sell"];
94978
- const sizeTolerance = Math.max(1e-10, plan.requestedSize * 1e-8);
94979
- const shapeMatches = evidence.responseValid && evidence.orderMatches && String(evidence.coin ?? "").trim().toUpperCase() === symbol2.trim().toUpperCase() && expectedSide.includes(String(evidence.side ?? "").trim().toLowerCase()) && evidence.reduceOnly === false && evidence.isTrigger === false && evidence.isPositionTpsl === false && evidence.originalSize != null && Math.abs(evidence.originalSize - plan.requestedSize) <= sizeTolerance;
95554
+ const signedSize = evidence.originalSize;
95555
+ const sizeTolerance = Math.max(1e-10, (signedSize ?? 0) * 1e-8);
95556
+ const shapeMatches = evidence.responseValid && evidence.orderMatches && String(evidence.coin ?? "").trim().toUpperCase() === symbol2.trim().toUpperCase() && expectedSide.includes(String(evidence.side ?? "").trim().toLowerCase()) && evidence.reduceOnly === false && evidence.isTrigger === false && evidence.isPositionTpsl === false && signedSize != null && hyperliquidSignedSizeMatchesRequestedSize(
95557
+ plan.requestedSize,
95558
+ request.executionContext.sizeDecimals,
95559
+ signedSize
95560
+ );
95561
+ if (!shapeMatches && evidence.responseValid && evidence.orderMatches && evidence.terminal) {
95562
+ retire("pending_protective_entry_shape_mismatch");
95563
+ reports.push({
95564
+ order_id: plan.entryClientOrderId,
95565
+ client_mutation_id: plan.entryMutationId,
95566
+ symbol: symbol2,
95567
+ action: "PROTECTIVE_RECONCILIATION",
95568
+ status: "failed",
95569
+ execution_metadata: {
95570
+ reason_code: "pending_protective_entry_shape_mismatch",
95571
+ order_status: evidence.orderStatus
95572
+ }
95573
+ });
95574
+ continue;
95575
+ }
94980
95576
  if (!shapeMatches || !evidence.terminal) {
94981
95577
  throw new Error("Pending entry status or shape is unresolved.");
94982
95578
  }
95579
+ if (evidence.fulfilled === true) entryFilled = true;
94983
95580
  const { rawFills, evidence: fillEvidence } = await fetchBrowserUserFills({
94984
95581
  publicRequestPriority: "trading_reconcile",
94985
95582
  config: request.config ?? {},
@@ -95020,14 +95617,37 @@ var init_runtime_execution = __esm({
95020
95617
  filledNotional += canonicalSize * canonicalPrice;
95021
95618
  }
95022
95619
  if (matchingFills.length === 0 && evidence.fulfilled === false) {
95023
- if (!replaceExactClientProtectiveGroup(profileId, symbol2, group, null)) {
95024
- throw new Error("Non-filled pending entry could not be cleared durably.");
95025
- }
95620
+ retire("pending_protective_entry_unfilled");
95026
95621
  continue;
95027
95622
  }
95028
- if (!fillRowsValid || !Number.isFinite(filledSize) || filledSize <= 0 || filledSize > plan.requestedSize + sizeTolerance || !Number.isFinite(filledNotional) || filledNotional <= 0) {
95623
+ if (!fillRowsValid || !Number.isFinite(filledSize) || filledSize <= 0 || filledSize > (signedSize ?? 0) + sizeTolerance || !Number.isFinite(filledNotional) || filledNotional <= 0) {
95029
95624
  throw new Error("Exact pending entry fills are unavailable.");
95030
95625
  }
95626
+ const { disposition } = await resolveJournaledAttachmentContinuity(request, {
95627
+ ...group,
95628
+ attachmentJournal: {
95629
+ phase: "awaiting_member_outcome",
95630
+ entryOrderId: confirmedEntryOrderId,
95631
+ filledSize,
95632
+ averagePrice: filledNotional / filledSize,
95633
+ members: []
95634
+ }
95635
+ }, { allowOppositeStart: true });
95636
+ if (disposition === "interrupted") {
95637
+ retire("protective_attachment_continuity_interrupted");
95638
+ reports.push({
95639
+ order_id: plan.entryClientOrderId,
95640
+ client_mutation_id: plan.entryMutationId,
95641
+ symbol: symbol2,
95642
+ action: "PROTECTIVE_RECONCILIATION",
95643
+ status: "failed",
95644
+ execution_metadata: {
95645
+ reason_code: "protective_attachment_continuity_interrupted",
95646
+ entry_order_id: plan.entryClientOrderId
95647
+ }
95648
+ });
95649
+ continue;
95650
+ }
95031
95651
  const attachment = await attachClientProtectivePlan(request, group, {
95032
95652
  orderId: String(evidence.orderId),
95033
95653
  filledSize,
@@ -95039,21 +95659,12 @@ var init_runtime_execution = __esm({
95039
95659
  attachment.handoffCleanup
95040
95660
  );
95041
95661
  }
95662
+ recordIfStillPending();
95042
95663
  } catch (error48) {
95043
95664
  if (isClientRuntimeWindowHandoffBeforePlanDispatch(error48) || isClientRuntimeLeaseOwnershipError(error48)) {
95044
95665
  throw error48;
95045
95666
  }
95046
- reports.push({
95047
- order_id: plan.entryClientOrderId,
95048
- client_mutation_id: plan.entryMutationId,
95049
- symbol: symbol2,
95050
- action: "PROTECTIVE_RECONCILIATION",
95051
- status: "failed",
95052
- execution_metadata: {
95053
- reason_code: "pending_protective_entry_unresolved",
95054
- error: getSanitizedRuntimeErrorMessage(error48) || "Pending entry protection is unresolved."
95055
- }
95056
- });
95667
+ recordUnresolved(getSanitizedRuntimeErrorMessage(error48) || "Pending entry protection is unresolved.");
95057
95668
  }
95058
95669
  }
95059
95670
  if (hasClientProtectiveGroupReadFailure(profileId, symbol2)) {
@@ -95617,11 +96228,10 @@ var init_runtime_execution = __esm({
95617
96228
  ...await recoverJournaledClientProtectiveAttachments(
95618
96229
  request,
95619
96230
  readClientProtectiveGroups(profileId, symbol2).filter((group) => group.pendingEntry != null && group.legs.length > 0)
95620
- ),
95621
- ...await recoverPendingClientProtectiveGroups(
95622
- request,
95623
- readClientProtectiveGroups(profileId, symbol2).filter((group) => group.pendingEntry != null && group.legs.length === 0)
95624
96231
  )
96232
+ // Pending entries (no legs yet) are polled by one owner, the runtime's
96233
+ // pending-protection sweep (or the app host without a runtime), never
96234
+ // again by each decision.
95625
96235
  ];
95626
96236
  const reconciliationGroupSet = readFreshClientProtectiveGroups(profileId, symbol2);
95627
96237
  if (hasClientProtectiveGroupReadFailure(profileId, symbol2)) {
@@ -96676,6 +97286,18 @@ var init_runtime_execution = __esm({
96676
97286
  signal?.addEventListener("abort", onAbort, { once: true });
96677
97287
  });
96678
97288
  };
97289
+ isDefinitiveEntryRejection = (error48, entryMutationId) => error48 instanceof HyperliquidExchangeRejectionError && Boolean(entryMutationId) && String(error48.clientMutationId ?? "").trim().toLowerCase() === String(entryMutationId).trim().toLowerCase();
97290
+ resolveExchangeSizeDecimals = async (symbol2, config2, publicRequestPriority) => {
97291
+ const { sz_decimals: sizeDecimals } = await resolveHyperliquidAsset({
97292
+ symbol: symbol2,
97293
+ config: config2,
97294
+ publicRequestPriority
97295
+ });
97296
+ if (!Number.isInteger(sizeDecimals) || sizeDecimals < 0) {
97297
+ throw new Error(`Hyperliquid size precision is unavailable for ${symbol2}.`);
97298
+ }
97299
+ return sizeDecimals;
97300
+ };
96679
97301
  roundAssetSize = (size, decimals) => {
96680
97302
  if (!Number.isFinite(size)) {
96681
97303
  return 0;
@@ -96793,6 +97415,7 @@ var init_runtime_execution = __esm({
96793
97415
  return pending3;
96794
97416
  };
96795
97417
  drainServerProtectionForRuntime = async (request, initialActions) => {
97418
+ if (request.executionMode === "server") return;
96796
97419
  try {
96797
97420
  await drainClientProtectiveActions({
96798
97421
  profileId: request.profileId,
@@ -96877,9 +97500,178 @@ var init_runtime_execution = __esm({
96877
97500
  if (clientExecutionMutations.get(key) === pending3) clientExecutionMutations.delete(key);
96878
97501
  }
96879
97502
  };
97503
+ allocateServerExecutionCapacity = async (authority, plans) => {
97504
+ if (plans.length === 0) return [];
97505
+ try {
97506
+ return await checkServerHostExecutionCapacity(
97507
+ authority.profileId,
97508
+ plans,
97509
+ authority.signal,
97510
+ authority.sessionId,
97511
+ authority.runtimeLeaseToken,
97512
+ authority.runtimeDeviceId,
97513
+ authority.schedulerInstanceId
97514
+ );
97515
+ } catch {
97516
+ throwIfAborted2(authority.signal);
97517
+ return plans.map(() => "unavailable");
97518
+ }
97519
+ };
96880
97520
  withClientProtectiveAdoptionMutation = (profileId, work, signal) => withClientExecutionMutation({ profileId: String(profileId).trim(), signal }, work);
96881
- executeClientRuntimeDecision = (input) => withClientExecutionMutation(input, () => executeClientRuntimeDecisionUnlocked(input));
96882
- maintainClientRuntimeTrailingStops = (request) => withClientExecutionMutation(request, async () => {
97521
+ executeClientRuntimeDecisionLocked = (input) => withClientExecutionMutation(input, () => withClientProtectivePlanSetLock(
97522
+ input.profileId,
97523
+ input.executionContext.symbol,
97524
+ () => executeClientRuntimeDecisionUnlocked(input),
97525
+ input.signal
97526
+ ));
97527
+ SERVER_AUDIT_RECORDED_ELSEWHERE = /* @__PURE__ */ new Set([
97528
+ "suppressed_duplicate_decision",
97529
+ "same_intent_cooldown",
97530
+ "redis_unavailable",
97531
+ "execution_capacity_refused",
97532
+ "execution_capacity_unavailable"
97533
+ ]);
97534
+ serverExecutionAuditOutcome = (result) => {
97535
+ if (result.status === "executed") {
97536
+ if (result.reasonCode === "close_fill_unresolved") return ["executed", "close_fill_unresolved"];
97537
+ if (result.reasonCode === "flip_close_fill_unresolved") return ["blocked", "flip_close_fill_unresolved"];
97538
+ if (result.reasonCode === "protective_reconciliation_unresolved") return ["blocked", "protective_reconciliation_unresolved"];
97539
+ return ["executed", "executed"];
97540
+ }
97541
+ if (result.status === "skipped") {
97542
+ if (result.reasonCode === "noop_already_at_target" || result.reasonCode === "stale_target_conflict") {
97543
+ return ["noop", result.reasonCode];
97544
+ }
97545
+ if (result.reasonCode === "protective_reconciliation_unresolved") return ["blocked", result.reasonCode];
97546
+ return ["blocked", "local_safety_block"];
97547
+ }
97548
+ const failure2 = result.executionReports.find((report) => report.status === "failed");
97549
+ const failureReason = String(failure2?.execution_metadata?.reason_code ?? "");
97550
+ if (failureReason === "outcome_unknown") return ["outcome_unknown", "outcome_unknown"];
97551
+ return ["error", failureReason === "exchange_rejected" ? "exchange_rejected" : "execution_error"];
97552
+ };
97553
+ executeClientRuntimeDecision = async (input) => {
97554
+ if (input.executionMode !== "server") return executeClientRuntimeDecisionLocked(input);
97555
+ const audit = input.serverExecutionAudit ?? { auditId: null };
97556
+ let entryDispatched = false;
97557
+ let result;
97558
+ try {
97559
+ result = await executeClientRuntimeDecisionLocked({
97560
+ ...input,
97561
+ serverExecutionAudit: audit,
97562
+ onExchangeOrderDispatched: (kind) => {
97563
+ input.onExchangeOrderDispatched?.(kind);
97564
+ if (kind === "entry") entryDispatched = true;
97565
+ }
97566
+ });
97567
+ } catch (error48) {
97568
+ if (audit.auditId !== null && !input.signal?.aborted && (input.decision === "BUY" || input.decision === "SELL")) {
97569
+ const reason = String(error48?.reasonCode ?? "");
97570
+ const [status2, reasonCode2] = reason === "outcome_unknown" || !reason && entryDispatched ? ["outcome_unknown", "outcome_unknown"] : ["error", reason === "exchange_rejected" ? "exchange_rejected" : "execution_error"];
97571
+ try {
97572
+ await recordServerHostExecutionAudit(
97573
+ input.profileId,
97574
+ {
97575
+ auditId: audit.auditId,
97576
+ cycleId: input.cycleId ?? null,
97577
+ symbol: input.executionContext.symbol,
97578
+ intent: "open",
97579
+ side: input.decision === "BUY" ? "buy" : "sell",
97580
+ requestedUnits: Math.max(0, Math.trunc(input.units)),
97581
+ reduceOnly: false,
97582
+ lastPrice: input.executionContext.lastPrice,
97583
+ status: status2,
97584
+ reasonCode: reasonCode2,
97585
+ orderId: null
97586
+ },
97587
+ input.signal,
97588
+ input.sessionId,
97589
+ input.runtimeLeaseToken,
97590
+ input.runtimeDeviceId,
97591
+ input.schedulerInstanceId
97592
+ );
97593
+ } catch (auditError) {
97594
+ appendRuntimeDebugEvent({
97595
+ label: "server_execution_audit_failed",
97596
+ note: getSanitizedRuntimeErrorMessage(auditError) || "unknown",
97597
+ outcome: "error"
97598
+ });
97599
+ }
97600
+ }
97601
+ throw error48;
97602
+ }
97603
+ if (result.intent === "hold" || !(input.decision === "BUY" || input.decision === "SELL") || SERVER_AUDIT_RECORDED_ELSEWHERE.has(String(result.reasonCode ?? ""))) {
97604
+ return result;
97605
+ }
97606
+ const [status, reasonCode] = serverExecutionAuditOutcome(result);
97607
+ const orderId = result.executionReports.find((report) => report.status === "executed" && report.order_id)?.order_id ?? null;
97608
+ try {
97609
+ const recorded = await recordServerHostExecutionAudit(
97610
+ input.profileId,
97611
+ {
97612
+ auditId: audit.auditId,
97613
+ cycleId: input.cycleId ?? null,
97614
+ symbol: input.executionContext.symbol,
97615
+ intent: result.intent,
97616
+ side: result.side ?? null,
97617
+ requestedUnits: Math.max(0, Math.trunc(result.requestedUnits)),
97618
+ reduceOnly: result.reduceOnly,
97619
+ lastPrice: input.executionContext.lastPrice,
97620
+ status,
97621
+ reasonCode,
97622
+ orderId: orderId === null ? null : String(orderId)
97623
+ },
97624
+ input.signal,
97625
+ input.sessionId,
97626
+ input.runtimeLeaseToken,
97627
+ input.runtimeDeviceId,
97628
+ input.schedulerInstanceId
97629
+ );
97630
+ audit.auditId = recorded.audit_id;
97631
+ } catch (error48) {
97632
+ appendRuntimeDebugEvent({
97633
+ label: "server_execution_audit_failed",
97634
+ note: getSanitizedRuntimeErrorMessage(error48) || "unknown",
97635
+ outcome: "error"
97636
+ });
97637
+ }
97638
+ if (audit.auditId === null) return result;
97639
+ const auditId = audit.auditId;
97640
+ return {
97641
+ ...result,
97642
+ executionReports: result.executionReports.map((report) => report.status === "executed" && ["BUY", "SELL", "FLIP_OPEN"].includes(String(report.action).toUpperCase()) ? { ...report, execution_metadata: { ...report.execution_metadata, execution_audit_id: auditId } } : report)
97643
+ };
97644
+ };
97645
+ waitForFlipCloseFreshness = async (input) => {
97646
+ const delayMs = Math.round(input.executionContext.closePositionDelaySeconds * 1e3);
97647
+ if (!(delayMs > 0)) return;
97648
+ const pollMs = Number(input.executionContext.closePositionFreshnessPollMs);
97649
+ const walletAddress = String(input.executionContext.walletAddress || "").trim();
97650
+ if (input.executionMode !== "server" || !(pollMs > 0) || !walletAddress) {
97651
+ await sleep2(delayMs, input.signal);
97652
+ return;
97653
+ }
97654
+ const deadline = Date.now() + delayMs;
97655
+ for (; ; ) {
97656
+ throwIfAborted2(input.signal);
97657
+ try {
97658
+ const snapshot = await fetchBrowserPositionSnapshot(
97659
+ input.config ?? {},
97660
+ walletAddress,
97661
+ input.executionContext.symbol,
97662
+ input.signal,
97663
+ executionReadPriority(input)
97664
+ );
97665
+ if (Number(snapshot.size) === 0) return;
97666
+ } catch {
97667
+ throwIfAborted2(input.signal);
97668
+ }
97669
+ const remaining = deadline - Date.now();
97670
+ if (remaining <= 0) return;
97671
+ await sleep2(Math.min(pollMs, remaining), input.signal);
97672
+ }
97673
+ };
97674
+ maintainClientRuntimeTrailingStops = (request) => withClientExecutionMutation(request, () => withClientProtectivePlanSetLock(request.profileId, request.executionContext.symbol, async () => {
96883
97675
  const context = request.executionContext;
96884
97676
  const capturedAt = Date.parse(context.decisionSnapshotCapturedAt ?? "");
96885
97677
  const maxAge = Number(context.executionFreshnessMaxAgeSeconds) * 1e3;
@@ -96888,15 +97680,11 @@ var init_runtime_execution = __esm({
96888
97680
  const groups = readFreshClientProtectiveGroups(String(request.profileId).trim(), context.symbol);
96889
97681
  if (hasClientProtectiveGroupReadFailure(String(request.profileId).trim(), context.symbol) || groups.some((group) => group.walletAddress !== String(context.walletAddress ?? "").trim().toLowerCase() || group.pendingEntry || group.attachmentJournal || group.cleanupRequired || group.legs.some((leg) => leg.replacement))) return [];
96890
97682
  if (!groups.some((group) => group.legs.some((leg) => leg.isTrailing && typeof leg.orderId === "number"))) return [];
96891
- const { sz_decimals: assetSizeDecimals } = await resolveHyperliquidAsset({
96892
- symbol: context.symbol,
96893
- config: request.config,
96894
- publicRequestPriority: "trading_reduce"
96895
- });
97683
+ const assetSizeDecimals = await resolveExchangeSizeDecimals(context.symbol, request.config ?? void 0, "trading_reduce");
96896
97684
  const isLong = context.currentPositionSize > 0;
96897
97685
  const improves = groups.some((group) => group.isLong === isLong && group.legs.some((leg) => {
96898
97686
  if (!leg.isTrailing || typeof leg.orderId !== "number") return false;
96899
- const size = roundAssetSize(Math.min(leg.size, Math.abs(context.currentPositionSize)), context.sizeDecimals);
97687
+ const size = roundAssetSize(Math.min(leg.size, Math.abs(context.currentPositionSize)), assetSizeDecimals);
96900
97688
  if (!(size > 0)) return false;
96901
97689
  return resolveTrailingStopTightening({
96902
97690
  currentPrice: context.lastPrice,
@@ -96911,12 +97699,16 @@ var init_runtime_execution = __esm({
96911
97699
  }));
96912
97700
  if (!improves) return [];
96913
97701
  await request.beforeTrailingMaintenance?.(request.signal);
96914
- const guardedRequest = { ...request, onExchangeOrderDispatched: (kind) => {
96915
- if (Date.now() - capturedAt > maxAge) throw new Error("Trailing observation expired before exchange dispatch.");
96916
- request.onExchangeOrderDispatched?.(kind);
96917
- } };
97702
+ const guardedRequest = {
97703
+ ...request,
97704
+ executionContext: { ...context, sizeDecimals: assetSizeDecimals },
97705
+ onExchangeOrderDispatched: (kind) => {
97706
+ if (Date.now() - capturedAt > maxAge) throw new Error("Trailing observation expired before exchange dispatch.");
97707
+ request.onExchangeOrderDispatched?.(kind);
97708
+ }
97709
+ };
96918
97710
  return tightenClientTrailingStops({ request: guardedRequest, currentPositionSize: context.currentPositionSize, currentPrice: context.lastPrice });
96919
- });
97711
+ }, request.signal));
96920
97712
  listPendingClientProtectiveSymbols = (profileId) => {
96921
97713
  const storage3 = resolveClientRuntimeProtectionStorage();
96922
97714
  if (!storage3) return [];
@@ -96970,11 +97762,7 @@ var init_runtime_execution = __esm({
96970
97762
  if (!hasUnresolvedClientProtectiveIdentity(groups)) continue;
96971
97763
  let symbolReports = [];
96972
97764
  try {
96973
- const { sz_decimals: sizeDecimals } = await resolveHyperliquidAsset({
96974
- symbol: symbol2,
96975
- config: input.config,
96976
- publicRequestPriority: "trading_reconcile"
96977
- });
97765
+ const sizeDecimals = await resolveExchangeSizeDecimals(symbol2, input.config, "trading_reconcile");
96978
97766
  const core = {
96979
97767
  profileId,
96980
97768
  config: input.config,
@@ -97186,7 +97974,8 @@ var init_runtime_execution = __esm({
97186
97974
  const results = [];
97187
97975
  for (const symbol2 of listPendingClientProtectiveSymbols(profileId)) {
97188
97976
  throwIfAborted2(input.signal);
97189
- const reports = await withClientExecutionMutation({ profileId, signal: input.signal }, async () => {
97977
+ const retired = [];
97978
+ const reports = await withClientExecutionMutation({ profileId, signal: input.signal }, () => withClientProtectivePlanSetLock(profileId, symbol2, async () => {
97190
97979
  const groups = readFreshClientProtectiveGroups(profileId, symbol2);
97191
97980
  if (hasClientProtectiveGroupReadFailure(profileId, symbol2)) {
97192
97981
  return [{
@@ -97199,14 +97988,7 @@ var init_runtime_execution = __esm({
97199
97988
  }
97200
97989
  const ownGroups = groups.filter((group) => group.pendingEntry != null && group.walletAddress === walletAddress.toLowerCase());
97201
97990
  if (ownGroups.length === 0) return [];
97202
- const { sz_decimals: sizeDecimals } = await resolveHyperliquidAsset({
97203
- symbol: symbol2,
97204
- config: input.config,
97205
- publicRequestPriority: "trading_reconcile"
97206
- });
97207
- if (!Number.isInteger(sizeDecimals) || sizeDecimals < 0) {
97208
- throw new Error(`Hyperliquid size precision is unavailable for ${symbol2}.`);
97209
- }
97991
+ const sizeDecimals = await resolveExchangeSizeDecimals(symbol2, input.config, "trading_reconcile");
97210
97992
  const request = {
97211
97993
  mutationAuthority: "manual_session",
97212
97994
  profileId,
@@ -97222,21 +98004,100 @@ var init_runtime_execution = __esm({
97222
98004
  ),
97223
98005
  ...await recoverPendingClientProtectiveGroups(
97224
98006
  request,
97225
- readClientProtectiveGroups(profileId, symbol2).filter((group) => group.pendingEntry != null && group.legs.length === 0 && group.walletAddress === walletAddress.toLowerCase())
98007
+ readClientProtectiveGroups(profileId, symbol2).filter((group) => group.pendingEntry != null && group.legs.length === 0 && group.walletAddress === walletAddress.toLowerCase()),
98008
+ retired,
98009
+ input.reportsStale !== false
97226
98010
  )
97227
98011
  ];
97228
- });
97229
- results.push({ symbol: symbol2, reports });
98012
+ }, input.signal));
98013
+ results.push({ symbol: symbol2, reports, ...retired.length > 0 ? { retired } : {} });
97230
98014
  }
97231
98015
  return results;
97232
98016
  };
97233
- executeClientRuntimeDecisionUnlocked = async (input) => {
97234
- throwIfAborted2(input.signal);
97235
- const requestedUnits = Math.max(0, Math.trunc(input.units));
98017
+ clientRuntimeDecisionSizesOrders = (input) => {
98018
+ const context = input.executionContext;
98019
+ const profileId = String(input.profileId).trim();
98020
+ if (input.decision !== "HOLD" && Math.max(0, Math.trunc(input.units)) > 0) return true;
98021
+ if (readClientProtectiveGroups(profileId, context.symbol).some((group) => group.legs.length > 0 || group.attachmentJournal != null) || hasClientProtectiveGroupReadFailure(profileId, context.symbol)) {
98022
+ return true;
98023
+ }
98024
+ const positionSize = Number.isFinite(context.currentPositionSize) ? Number(context.currentPositionSize) : 0;
98025
+ return !input.skipTrailingMaintenance && context.tpSlEnabled === true && context.stopLossEnabled !== false && context.stopLossType === "trailing" && positionSize !== 0;
98026
+ };
98027
+ executeClientRuntimeDecisionUnlocked = async (unsizedInput) => {
98028
+ throwIfAborted2(unsizedInput.signal);
98029
+ const requestedUnits = Math.max(0, Math.trunc(unsizedInput.units));
97236
98030
  appendRuntimeDebugEvent({
97237
98031
  label: "execution_start",
97238
- note: `decision=${input.decision} units=${requestedUnits} symbol=${input.executionContext.symbol}`
98032
+ note: `decision=${unsizedInput.decision} units=${requestedUnits} symbol=${unsizedInput.executionContext.symbol}`
97239
98033
  });
98034
+ if (!clientRuntimeDecisionSizesOrders(unsizedInput)) {
98035
+ return {
98036
+ status: "skipped",
98037
+ intent: "hold",
98038
+ side: null,
98039
+ reduceOnly: false,
98040
+ requestedUnits,
98041
+ targetSignedUnits: signedUnitsFromEntryPosition(
98042
+ Number.isFinite(unsizedInput.executionContext.currentPositionSize) ? Number(unsizedInput.executionContext.currentPositionSize) : 0,
98043
+ unsizedInput.executionContext.currentPositionEntryPrice,
98044
+ unsizedInput.executionContext.unitSizeUsdc
98045
+ ),
98046
+ executedSizeAsset: 0,
98047
+ executionReports: [],
98048
+ message: unsizedInput.decision === "HOLD" ? "Hold (No Action)" : "Unsupported decision",
98049
+ executionSnapshotId: createRuntimeId(),
98050
+ executionSnapshotCapturedAt: (/* @__PURE__ */ new Date()).toISOString()
98051
+ };
98052
+ }
98053
+ if (unsizedInput.executionMode === "server" && !unsizedInput.serverCapacityChecked && (unsizedInput.decision === "BUY" || unsizedInput.decision === "SELL") && requestedUnits > 0) {
98054
+ const skipped = (reasonCode, message) => ({
98055
+ status: "skipped",
98056
+ intent: "hold",
98057
+ side: null,
98058
+ reduceOnly: false,
98059
+ requestedUnits,
98060
+ targetSignedUnits: 0,
98061
+ executedSizeAsset: 0,
98062
+ executionReports: [],
98063
+ message,
98064
+ reasonCode,
98065
+ executionSnapshotId: createRuntimeId(),
98066
+ executionSnapshotCapturedAt: (/* @__PURE__ */ new Date()).toISOString()
98067
+ });
98068
+ const capacity = unsizedInput.serverCapacityAllocation ?? (await allocateServerExecutionCapacity(unsizedInput, [
98069
+ { symbol: unsizedInput.executionContext.symbol, decision: unsizedInput.decision, units: requestedUnits }
98070
+ ]))[0];
98071
+ if (capacity === "unavailable") {
98072
+ throwIfAborted2(unsizedInput.signal);
98073
+ return skipped("execution_capacity_unavailable", "Execution skipped: Failed to fetch positions before limit check.");
98074
+ }
98075
+ if (!capacity.accepted || !(capacity.units > 0)) {
98076
+ appendRuntimeDebugEvent({
98077
+ label: "execution_capacity_refused",
98078
+ note: `symbol=${unsizedInput.executionContext.symbol} reason=${capacity.reason_code ?? "unknown"}`,
98079
+ outcome: "ok"
98080
+ });
98081
+ return skipped("execution_capacity_refused", `Skipped: runtime constraint ${capacity.reason_code ?? "capacity"}.`);
98082
+ }
98083
+ return executeClientRuntimeDecisionUnlocked({
98084
+ ...unsizedInput,
98085
+ units: Math.min(requestedUnits, Math.trunc(capacity.units)),
98086
+ serverCapacityChecked: true
98087
+ });
98088
+ }
98089
+ const input = {
98090
+ ...unsizedInput,
98091
+ executionContext: {
98092
+ ...unsizedInput.executionContext,
98093
+ sizeDecimals: await resolveExchangeSizeDecimals(
98094
+ unsizedInput.executionContext.symbol,
98095
+ unsizedInput.config ?? void 0,
98096
+ unsizedInput.decision === "HOLD" || requestedUnits <= 0 ? "trading_reconcile" : executionReadPriority(unsizedInput)
98097
+ )
98098
+ }
98099
+ };
98100
+ throwIfAborted2(input.signal);
97240
98101
  const decisionSnapshotPositionSize = Number.isFinite(input.executionContext.currentPositionSize) ? Number(input.executionContext.currentPositionSize) : 0;
97241
98102
  const decisionSnapshotSignedUnits = signedUnitsFromEntryPosition(
97242
98103
  decisionSnapshotPositionSize,
@@ -97449,7 +98310,52 @@ var init_runtime_execution = __esm({
97449
98310
  executionSnapshotCapturedAt
97450
98311
  };
97451
98312
  }
97452
- if (!targetResolution.closeOpposingPosition && classified.reduceOnly !== true) {
98313
+ if (input.executionMode === "server") {
98314
+ throwIfAborted2(input.signal);
98315
+ const claim = await claimServerHostExecution(
98316
+ input.profileId,
98317
+ {
98318
+ cycleId: input.cycleId ?? null,
98319
+ symbol: input.executionContext.symbol,
98320
+ intent: classified.intent,
98321
+ side: classified.side,
98322
+ requestedUnits: Math.max(0, Math.trunc(classified.requestedUnits)),
98323
+ reduceOnly: classified.reduceOnly,
98324
+ marginMode: input.executionContext.marginMode === "auto" ? null : input.executionContext.marginMode,
98325
+ lastPrice: input.executionContext.lastPrice
98326
+ },
98327
+ input.signal,
98328
+ input.sessionId,
98329
+ input.runtimeLeaseToken,
98330
+ input.runtimeDeviceId,
98331
+ input.schedulerInstanceId
98332
+ );
98333
+ if (input.serverExecutionAudit && typeof claim.audit_id === "number") {
98334
+ input.serverExecutionAudit.auditId = claim.audit_id;
98335
+ }
98336
+ if (!claim.allowed) {
98337
+ appendRuntimeDebugEvent({
98338
+ label: "execution_guard_suppressed",
98339
+ note: `symbol=${input.executionContext.symbol} intent=${classified.intent} reason=${claim.reason_code}`,
98340
+ outcome: "ok"
98341
+ });
98342
+ return {
98343
+ status: "skipped",
98344
+ intent: classified.intent,
98345
+ side: classified.side,
98346
+ reduceOnly: classified.reduceOnly,
98347
+ requestedUnits: classified.requestedUnits,
98348
+ targetSignedUnits: classified.targetSignedUnits,
98349
+ executedSizeAsset: 0,
98350
+ executionReports: reconciliationReports,
98351
+ message: "The execution guard suppressed a duplicate or repeated decision.",
98352
+ reasonCode: claim.reason_code,
98353
+ executionSnapshotId,
98354
+ executionSnapshotCapturedAt
98355
+ };
98356
+ }
98357
+ }
98358
+ if (!targetResolution.closeOpposingPosition && classified.reduceOnly !== true && !await serverEntryLeverageAlreadyHeld(input)) {
97453
98359
  throwIfAborted2(input.signal);
97454
98360
  await executeClientLeverageUpdate({
97455
98361
  profileId: input.profileId,
@@ -97662,9 +98568,7 @@ var init_runtime_execution = __esm({
97662
98568
  input.executionContext.symbol,
97663
98569
  []
97664
98570
  );
97665
- if (input.executionContext.closePositionDelaySeconds > 0) {
97666
- await sleep2(Math.round(input.executionContext.closePositionDelaySeconds * 1e3), input.signal);
97667
- }
98571
+ await waitForFlipCloseFreshness(input);
97668
98572
  throwIfAborted2(input.signal);
97669
98573
  await executeClientLeverageUpdate({
97670
98574
  profileId: input.profileId,
@@ -97683,10 +98587,8 @@ var init_runtime_execution = __esm({
97683
98587
  throwIfAborted2(input.signal);
97684
98588
  }
97685
98589
  const actualUnits = targetResolution.orderUnits;
97686
- const sizeAsset = roundAssetSize(
97687
- input.executionContext.unitSizeUsdc * actualUnits / executionPrice,
97688
- input.executionContext.sizeDecimals
97689
- );
98590
+ const intendedSizeAsset = input.executionContext.unitSizeUsdc * actualUnits / executionPrice;
98591
+ const sizeAsset = Number.isFinite(intendedSizeAsset) && intendedSizeAsset > 0 ? quantizeHyperliquidOrderSizeValue(intendedSizeAsset, input.executionContext.sizeDecimals, "nearest") : 0;
97690
98592
  appendRuntimeDebugEvent({
97691
98593
  label: "execution_size_computed",
97692
98594
  note: `symbol=${input.executionContext.symbol} actualUnits=${actualUnits} sizeAsset=${sizeAsset} price=${executionPrice}`
@@ -97694,7 +98596,7 @@ var init_runtime_execution = __esm({
97694
98596
  if (sizeAsset <= 0) {
97695
98597
  appendRuntimeDebugEvent({
97696
98598
  label: "execution_skipped_zero_size",
97697
- note: `actualUnits=${actualUnits} unitSize=${input.executionContext.unitSizeUsdc} decimals=${input.executionContext.sizeDecimals}`,
98599
+ note: `reason=size_below_lot_precision actualUnits=${actualUnits} unitSize=${input.executionContext.unitSizeUsdc} intendedSize=${intendedSizeAsset} decimals=${input.executionContext.sizeDecimals}`,
97698
98600
  outcome: "error"
97699
98601
  });
97700
98602
  return {
@@ -97890,6 +98792,9 @@ var init_runtime_execution = __esm({
97890
98792
  const handoffBeforeDispatch = handoffVeto || !entryDispatchBoundaryPassed && input.shouldCancelBeforeExchangeOrderDispatch?.() === true;
97891
98793
  const hasCommittedReports = executionReports.some((report) => report.status === "executed" && String(report.order_id || "").trim().length > 0);
97892
98794
  let vetoedProtectionCleanupFailed = false;
98795
+ if (pendingProtectiveGroup != null && entryDispatchBoundaryPassed && pendingProtectiveCleanup != null && isDefinitiveEntryRejection(entryDispatchError, entryMutationId)) {
98796
+ clearClientRuntimeVetoedProtectiveIntent(pendingProtectiveCleanup);
98797
+ }
97893
98798
  if (pendingProtectiveGroup != null && !entryDispatchBoundaryPassed) {
97894
98799
  if (pendingProtectiveCleanup == null || !clearClientRuntimeVetoedProtectiveIntent(pendingProtectiveCleanup)) {
97895
98800
  vetoedProtectionCleanupFailed = true;
@@ -98843,7 +99748,7 @@ var init_runtime_execution = __esm({
98843
99748
  });
98844
99749
 
98845
99750
  // lib/runtime/protective-adoption-status.ts
98846
- var deferrals, listeners, notify, recordClientProtectiveAdoptionDeferral, clearClientProtectiveAdoptionDeferral;
99751
+ var deferrals, listeners2, notify, recordClientProtectiveAdoptionDeferral, clearClientProtectiveAdoptionDeferral;
98847
99752
  var init_protective_adoption_status = __esm({
98848
99753
  "lib/runtime/protective-adoption-status.ts"() {
98849
99754
  "use strict";
@@ -98851,9 +99756,9 @@ var init_protective_adoption_status = __esm({
98851
99756
  init_define_VTX_GROK_POLICY();
98852
99757
  init_define_VTX_PI_MODEL_POLICY();
98853
99758
  deferrals = /* @__PURE__ */ new Map();
98854
- listeners = /* @__PURE__ */ new Set();
99759
+ listeners2 = /* @__PURE__ */ new Set();
98855
99760
  notify = () => {
98856
- listeners.forEach((listener) => listener());
99761
+ listeners2.forEach((listener) => listener());
98857
99762
  };
98858
99763
  recordClientProtectiveAdoptionDeferral = (profileId, symbols) => {
98859
99764
  deferrals.set(String(profileId).trim(), { deferredAtMs: Date.now(), symbols: [...symbols] });
@@ -104023,7 +104928,7 @@ var init_inference_observability = __esm({
104023
104928
  });
104024
104929
 
104025
104930
  // lib/runtime/provider-client.ts
104026
- var mapOpenAiCompatibleNativeRequestPath, isRetryableProviderFailureForFallback, extractRuntimeProviderFailureStatusCode, isModelSpecificProviderFailure, isKeySpecificOrTransientProviderFailure, providerDispatchClockMs, beginProviderDispatch, providerDispatchLatencyMs, attachProviderDispatchFailure, attachProviderFailureTrace, toRuntimeExecutionMode, buildNoneReasoningPayload, normalizeLevelValue, buildRuntimeReasoningPayload, resolveProviderReasoningParameters, requestedReasoningParameters, usesReasoningCompletionTokens, shouldRequestReasoningTrace, normalizeProviderToken, runtimeProviderForByokProvider, findByokProviderForRuntime, findNativeRequestParametersForModel, modelHasNativeRequestApiSurface, setDottedRequestValue, normalizeProviderMaxTokens, applyRuntimeRequestContract, normalizeProvider2, requireProviderEndpoint, estimateTokenCount, normalizeUsageCount, buildOpenAiUsagePayload, buildAnthropicUsagePayload, buildGoogleUsagePayload, normalizeProviderUsageMetrics, providerResponseSignals, fetchProvider, readProviderPayload, emitRuntimeDelta, readProviderTextStream, extractOpenAiCompatibleDeltaText, readOpenAiCompatibleTextStream, rawProviderTextForDebug, extractProviderErrorDetail, buildCanonicalProviderFailureMessage, toProviderNetworkDebugError, REASONING_ONLY_CONTENT_TYPES, extractOpenAiContentPartText, extractOpenAiReasoningPartText, extractOpenAiMessageContent, extractOpenAiMessageReasoningContent, extractOpenAiCompatibleText, normalizeRuntimeChatHistory, calculateProviderCost, callOpenAiCompatible, extractOpenAiResponsesText, extractOpenAiResponsesReasoning, callOpenAiResponses, extractAnthropicMessageText, extractAnthropicReasoningContent, callAnthropic, isVertexExpressKey, googlePublicModelIdRegexes, shouldUseGooglePublicEndpointForModel, normalizeGoogleModelId, shouldRetryGoogleVertexRequestPublicly, GOOGLE_VERTEX_PUBLIC_RETRY_NOTE, buildGoogleRequest, isGoogleReasoningPart, extractGoogleMessageText, extractGoogleReasoningContent, extractGoogleSafetyMetadata, GOOGLE_BLOCKED_FINISH_REASONS, googleProviderBlockReason, callGoogle, resolveRuntimeProvider, defaultInvocationContext, defaultProviderTransport, invocationFailureCode, buildBrowserInvocation, resolveProviderSecretKey, resolveNativeProviderCredentialSlots, resolveProviderSecretKeySlots, requireOpenAiCompatibleRuntimeBaseUrl, runtimeSubscriptionPlan, runtimeKeySlotSupportsModel, invokeRuntimeProviderAttempt, invokeRuntimeProvider;
104931
+ var mapOpenAiCompatibleNativeRequestPath, isRetryableProviderFailureForFallback, extractRuntimeProviderFailureStatusCode, isModelSpecificProviderFailure, isKeySpecificOrTransientProviderFailure, providerDispatchClockMs, beginProviderDispatch, providerDispatchLatencyMs, attachProviderDispatchFailure, attachProviderFailureTrace, toRuntimeExecutionMode, buildNoneReasoningPayload, normalizeLevelValue, buildRuntimeReasoningPayload, resolveProviderReasoningParameters, requestedReasoningParameters, usesReasoningCompletionTokens, shouldRequestReasoningTrace, normalizeProviderToken, runtimeProviderForByokProvider, findByokProviderForRuntime, findNativeRequestParametersForModel, modelHasNativeRequestApiSurface, setDottedRequestValue, normalizeProviderMaxTokens, applyRuntimeRequestContract, normalizeProvider2, requireProviderEndpoint, estimateTokenCount, normalizeUsageCount, buildOpenAiUsagePayload, buildAnthropicUsagePayload, buildGoogleUsagePayload, normalizeProviderUsageMetrics, providerResponseSignals, fetchProvider, readProviderPayload, emitRuntimeDelta, readProviderTextStream, extractOpenAiCompatibleDeltaText, readOpenAiCompatibleTextStream, rawProviderTextForDebug, extractProviderErrorDetail, buildCanonicalProviderFailureMessage, toProviderNetworkDebugError, REASONING_ONLY_CONTENT_TYPES, extractOpenAiContentPartText, extractOpenAiReasoningPartText, extractOpenAiMessageContent, extractOpenAiMessageReasoningContent, extractOpenAiCompatibleText, normalizeRuntimeChatHistory, calculateProviderCost, callOpenAiCompatible, extractOpenAiResponsesText, extractOpenAiResponsesReasoning, callOpenAiResponses, extractAnthropicMessageText, extractAnthropicReasoningContent, callAnthropic, isVertexExpressKey, googlePublicModelIdRegexes, shouldUseGooglePublicEndpointForModel, normalizeGoogleModelId, shouldRetryGoogleVertexRequestPublicly, GOOGLE_VERTEX_PUBLIC_RETRY_NOTE, buildGoogleRequest, isGoogleReasoningPart, extractGoogleMessageText, extractGoogleReasoningContent, extractGoogleSafetyMetadata, GOOGLE_BLOCKED_FINISH_REASONS, googleProviderBlockReason, callGoogle, resolveRuntimeProvider, defaultInvocationContext, defaultProviderTransport, invocationFailureCode, buildBrowserInvocation, resolveProviderSecretKey, resolveNativeProviderCredentialSlots, resolveProviderSecretKeySlots, requireOpenAiCompatibleRuntimeBaseUrl, runtimeSubscriptionPlan, runtimeKeySlotSupportsModel, invokeRuntimeProviderAttempt, runtimeProviderInvoker, invokeRuntimeProvider;
104027
104932
  var init_provider_client = __esm({
104028
104933
  "lib/runtime/provider-client.ts"() {
104029
104934
  "use strict";
@@ -106738,8 +107643,10 @@ var init_provider_client = __esm({
106738
107643
  toolCalls: response.toolCalls
106739
107644
  };
106740
107645
  };
107646
+ runtimeProviderInvoker = null;
106741
107647
  invokeRuntimeProvider = async (input) => {
106742
107648
  if (input.signal?.aborted) throw input.signal.reason ?? new DOMException("Cancelled", "AbortError");
107649
+ if (runtimeProviderInvoker) return runtimeProviderInvoker(input);
106743
107650
  const policy2 = input.provider === "google" && Number(input.profileId) > 0 && !input.tools?.length && !input.onDelta && shouldUseGooglePublicEndpointForModel(input.config, input.model) ? googleEgressPolicyForModel(input.config.google_egress, input.model) : void 0;
106744
107651
  if (policy2) {
106745
107652
  const timeoutMs = Math.min(input.timeoutMs ?? policy2.deadline_seconds * 1e3, policy2.deadline_seconds * 1e3);
@@ -107730,7 +108637,7 @@ var init_reasoning_controls = __esm({
107730
108637
  return buildNoneReasoningControls();
107731
108638
  }
107732
108639
  seen.add(key);
107733
- const label = typeof record5.label === "string" && record5.label.trim() ? record5.label.trim() : void 0;
108640
+ const label2 = typeof record5.label === "string" && record5.label.trim() ? record5.label.trim() : void 0;
107734
108641
  const nested = normalizeReasoningControls({
107735
108642
  ...Object.fromEntries(Object.entries(record5).filter(([itemKey]) => !["key", "label"].includes(itemKey))),
107736
108643
  schema_version: 1
@@ -107740,7 +108647,7 @@ var init_reasoning_controls = __esm({
107740
108647
  }
107741
108648
  nestedControls.push({
107742
108649
  key,
107743
- ...label ? { label } : {},
108650
+ ...label2 ? { label: label2 } : {},
107744
108651
  ...nested
107745
108652
  });
107746
108653
  }
@@ -107905,24 +108812,170 @@ var init_model_controller_provenance = __esm({
107905
108812
  }
107906
108813
  });
107907
108814
 
108815
+ // lib/runtime/ai-schedule.ts
108816
+ function evaluateAiSchedule(schedule, defaults, nowMs2) {
108817
+ if (!isAiScheduleEnabled(schedule)) {
108818
+ return { shouldRun: true, nextChangeAtMs: null, message: "Schedule Disabled (Running 24/7)" };
108819
+ }
108820
+ try {
108821
+ const timeZone = schedule.timezone ?? defaults?.timezone;
108822
+ if (typeof timeZone !== "string" || !timeZone.trim()) throw new Error("Invalid schedule timezone");
108823
+ const nowWall = wallAt(timeZone, nowMs2);
108824
+ const windows = schedule.windows ?? defaults?.windows;
108825
+ if (!truthy(windows)) return { shouldRun: false, nextChangeAtMs: null, message: "No windows configured" };
108826
+ if (!Array.isArray(windows)) throw new Error("Invalid schedule windows");
108827
+ const nowDay = Math.floor(nowWall / DAY_MS) * DAY_MS;
108828
+ const candidates = [];
108829
+ for (let dayOffset = -6; dayOffset < 8; dayOffset += 1) {
108830
+ const dateMs = nowDay + dayOffset * DAY_MS;
108831
+ const weekday = (new Date(dateMs).getUTCDay() + 6) % 7;
108832
+ for (const window2 of windows) {
108833
+ if (!window2 || typeof window2 !== "object" || Array.isArray(window2)) {
108834
+ throw new Error("Invalid schedule window");
108835
+ }
108836
+ const startDay = dayNumber(window2.start_day);
108837
+ if (startDay === null || startDay !== weekday) continue;
108838
+ const start = parseClock(window2.start_time);
108839
+ const end = parseClock(window2.end_time);
108840
+ const endDay = dayNumber(window2.end_day);
108841
+ if (!start || !end || endDay === null) continue;
108842
+ const startWall = dateMs + (start[0] * 60 + start[1]) * MINUTE_MS;
108843
+ const daysDiff = ((endDay - startDay) % 7 + 7) % 7;
108844
+ const shifted = startWall + Math.round(daysDiff * DAY_MS);
108845
+ const endWall = Math.floor(shifted / DAY_MS) * DAY_MS + (end[0] * 60 + end[1]) * MINUTE_MS + shifted % MINUTE_MS;
108846
+ if (endWall <= startWall) continue;
108847
+ candidates.push([startWall, endWall]);
108848
+ }
108849
+ }
108850
+ candidates.sort((left, right) => left[0] - right[0]);
108851
+ const active = candidates.find(([start, end]) => start <= nowWall && nowWall < end);
108852
+ if (active) {
108853
+ const endsAt = instantOfWall(timeZone, active[1]);
108854
+ return { shouldRun: true, nextChangeAtMs: endsAt, message: `Active until ${label(timeZone, endsAt, active[1])}` };
108855
+ }
108856
+ const next = candidates.find(([start]) => start > nowWall);
108857
+ if (next) {
108858
+ const startsAt = instantOfWall(timeZone, next[0]);
108859
+ return { shouldRun: false, nextChangeAtMs: startsAt, message: `Paused until ${label(timeZone, startsAt, next[0])}` };
108860
+ }
108861
+ return { shouldRun: false, nextChangeAtMs: null, message: "No future schedule found" };
108862
+ } catch {
108863
+ return { shouldRun: true, nextChangeAtMs: null, message: "Schedule Error (Defaulting to Active)" };
108864
+ }
108865
+ }
108866
+ var MINUTE_MS, DAY_MS, truthy, isAiScheduleEnabled, formatters, formatterFor, wallAt, offsetAt, instantOfWall, digitValue, clockPart, dayNumber, parseClock, label;
108867
+ var init_ai_schedule = __esm({
108868
+ "lib/runtime/ai-schedule.ts"() {
108869
+ "use strict";
108870
+ init_define_VTX_EXO_POLICY();
108871
+ init_define_VTX_GROK_POLICY();
108872
+ init_define_VTX_PI_MODEL_POLICY();
108873
+ MINUTE_MS = 6e4;
108874
+ DAY_MS = 864e5;
108875
+ truthy = (value) => {
108876
+ if (Array.isArray(value)) return value.length > 0;
108877
+ if (value && typeof value === "object") return Object.keys(value).length > 0;
108878
+ return Boolean(value);
108879
+ };
108880
+ isAiScheduleEnabled = (schedule) => Boolean(schedule) && typeof schedule === "object" && truthy(schedule.enabled);
108881
+ formatters = /* @__PURE__ */ new Map();
108882
+ formatterFor = (timeZone) => {
108883
+ let formatter = formatters.get(timeZone);
108884
+ if (!formatter) {
108885
+ formatter = new Intl.DateTimeFormat("en-US", {
108886
+ timeZone,
108887
+ hourCycle: "h23",
108888
+ year: "numeric",
108889
+ month: "numeric",
108890
+ day: "numeric",
108891
+ hour: "numeric",
108892
+ minute: "numeric",
108893
+ second: "numeric"
108894
+ });
108895
+ const resolved = formatter.resolvedOptions().timeZone;
108896
+ if (resolved !== timeZone && resolved.toLowerCase() === timeZone.toLowerCase() || timeZone === timeZone.toLowerCase()) {
108897
+ throw new RangeError(`Invalid time zone: ${timeZone}`);
108898
+ }
108899
+ formatters.set(timeZone, formatter);
108900
+ }
108901
+ return formatter;
108902
+ };
108903
+ wallAt = (timeZone, instantMs) => {
108904
+ const parts = {};
108905
+ for (const part of formatterFor(timeZone).formatToParts(new Date(instantMs))) {
108906
+ if (part.type !== "literal") parts[part.type] = Number(part.value);
108907
+ }
108908
+ const wholeSecond = Math.floor(instantMs / 1e3) * 1e3;
108909
+ return Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second) + (instantMs - wholeSecond);
108910
+ };
108911
+ offsetAt = (timeZone, instantMs) => wallAt(timeZone, instantMs) - instantMs;
108912
+ instantOfWall = (timeZone, wallMs) => {
108913
+ const before = offsetAt(timeZone, wallMs - DAY_MS);
108914
+ if (offsetAt(timeZone, wallMs - before) === before) return wallMs - before;
108915
+ const after = offsetAt(timeZone, wallMs + DAY_MS);
108916
+ if (offsetAt(timeZone, wallMs - after) === after) return wallMs - after;
108917
+ return wallMs - before;
108918
+ };
108919
+ digitValue = (char) => {
108920
+ let start = char.codePointAt(0);
108921
+ while (start > 0 && new RegExp("\\p{Nd}", "u").test(String.fromCodePoint(start - 1))) start -= 1;
108922
+ return (char.codePointAt(0) - start) % 10;
108923
+ };
108924
+ clockPart = (text) => {
108925
+ const match = new RegExp("^\\s*([+-]?)(\\p{Nd}+(?:_\\p{Nd}+)*)\\s*$", "u").exec(text);
108926
+ if (!match) return null;
108927
+ const value = [...match[2].replace(/_/g, "")].reduce((total, char) => total * 10 + digitValue(char), 0);
108928
+ return match[1] === "-" ? -value : value;
108929
+ };
108930
+ dayNumber = (value) => {
108931
+ if (typeof value === "boolean") return Number(value);
108932
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
108933
+ };
108934
+ parseClock = (value) => {
108935
+ if (typeof value !== "string") return null;
108936
+ const parts = value.split(":");
108937
+ if (parts.length !== 2) return null;
108938
+ const hour = clockPart(parts[0]);
108939
+ const minute = clockPart(parts[1]);
108940
+ if (hour === null || minute === null || hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;
108941
+ return [hour, minute];
108942
+ };
108943
+ label = (timeZone, instantMs, wallMs) => {
108944
+ const wall = new Date(wallMs);
108945
+ const day = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][wall.getUTCDay()];
108946
+ const clock = `${String(wall.getUTCHours()).padStart(2, "0")}:${String(wall.getUTCMinutes()).padStart(2, "0")}`;
108947
+ const zone = new Intl.DateTimeFormat("en-US", { timeZone, timeZoneName: "short" }).formatToParts(new Date(instantMs)).find((part) => part.type === "timeZoneName")?.value || timeZone;
108948
+ return `${day} ${clock} ${zone}`;
108949
+ };
108950
+ }
108951
+ });
108952
+
107908
108953
  // lib/runtime/local-analysis.ts
107909
108954
  var local_analysis_exports = {};
107910
108955
  __export(local_analysis_exports, {
107911
108956
  ClientRuntimeAgentInstructionEmpty: () => ClientRuntimeAgentInstructionEmpty,
108957
+ ClientRuntimeAiSchedulePaused: () => ClientRuntimeAiSchedulePaused,
108958
+ ClientRuntimeAiScheduleStillActive: () => ClientRuntimeAiScheduleStillActive,
108959
+ ServerDispatchAccountStateStale: () => ServerDispatchAccountStateStale,
108960
+ aiOrderSlippageFraction: () => aiOrderSlippageFraction,
107912
108961
  buildLocalRuntimePromptArtifacts: () => buildLocalRuntimePromptArtifacts,
107913
108962
  buildPromptBehaviorStateArtifacts: () => buildPromptBehaviorStateArtifacts,
107914
108963
  buildPromptBehaviorStateValue: () => buildPromptBehaviorStateValue,
107915
108964
  derivePromptVisibleSections: () => derivePromptVisibleSections,
107916
108965
  isClientRuntimeAgentInstructionEmpty: () => isClientRuntimeAgentInstructionEmpty,
108966
+ isClientRuntimeAiSchedulePaused: () => isClientRuntimeAiSchedulePaused,
108967
+ isClientRuntimeAiScheduleStillActive: () => isClientRuntimeAiScheduleStillActive,
108968
+ isServerDispatchAccountStateStale: () => isServerDispatchAccountStateStale,
107917
108969
  resolveEffectivePromptRuntimeProvenance: () => resolveEffectivePromptRuntimeProvenance,
107918
108970
  resolveExternalInferenceRuntimeTimeoutSeconds: () => resolveExternalInferenceRuntimeTimeoutSeconds,
107919
108971
  resolveLocalRuntimeSecretProvider: () => resolveLocalRuntimeSecretProvider,
107920
108972
  resolveLocalRuntimeSecretRequirements: () => resolveLocalRuntimeSecretRequirements,
107921
108973
  resolveNativeValuesForModel: () => resolveNativeValuesForModel,
107922
108974
  runLocalRuntimeCycle: () => runLocalRuntimeCycle,
108975
+ serverPerpDexScope: () => serverPerpDexScope,
107923
108976
  summarizeReviewFailureExplanation: () => summarizeReviewFailureExplanation
107924
108977
  });
107925
- var normalizeNativeValues, assertPromptModelController, resolveRuntimeReasoningControlsForModel, modelScopedKey, resolveNativeValuesForModel, observeRuntimeCycle, observeAccountState, ClientRuntimeAgentInstructionEmpty, isClientRuntimeAgentInstructionEmpty, buildClaimedAgentRuntimeCycleResult, resolveRuntimeMarginModePreference, resolveRuntimeLeveragePreference, resolveBooleanSetting2, CLIENT_RUNTIME_LIVE_CONTEXT_UNAVAILABLE_ERRORS, BEHAVIOR_STATE_UNAVAILABLE_ERROR, CriticalBehaviorStateError, clampNumber, resolveExternalInferenceRuntimeTimeoutSeconds, toPositiveFinite3, compactSnippet, hashRuntimeDebugText, EFFECTIVE_INPUT_MANIFEST_SCHEMA_VERSION, PROMPT_ASSEMBLY_DEFINITION_VERSION, RUNTIME_SOURCE_DEFINITION_VERSION, DECISION_INPUT_DEFINITION_VERSION, CONTEXT_ENVELOPE_DEFINITION_VERSION, CLIENT_RUNTIME_SOURCE_VERSION, CLIENT_MAIN_PROMPT_RENDERER, SERVER_MAIN_PROMPT_RENDERER, CLIENT_REVIEW_PROMPT_RENDERER, SERVER_REVIEW_PROMPT_RENDERER, resolveEffectivePromptRuntimeProvenance, canonicalManifestValue, canonicalManifestJson, sha256ManifestHex, effectiveInputComponent, buildEffectiveInputManifest, derivePromptVisibleSections, decodeDecisionTracePayload, extractDecisionSymbolTrace, formatDecisionSymbolTrace, formatActionableDecisionSymbols, normalizePromptSymbols, JSON_MODEL_OUTPUT_FENCE_PATTERN, STRICT_MODEL_OUTPUT_KEYS, currentModelOutputValidationErrors, currentModelOutputMatchesContract, projectCurrentModelDecisionContent, modelOutputValidationError, buildMissingDecisionHold, buildDecisionPlansFromResponse, buildReviewCandidatePlansFromResponse, forceUnavailableSymbolsToHold, extractTemplatePlaceholders, requireReviewPrimaryUserPromptTemplate, containsCompetingBehaviorStateMarkup, containsCompetingMainBehaviorStateMarkup, requireStrategyReviewTemplates, preflightStrategyReviewPromptContract, extractRuntimeReasoningSelection, isAbortError, isRuntimeTimeoutAbortReason, REVIEW_FAILURE_SENSITIVE_DB_TOKENS, REVIEW_FAILURE_SCHEMA_DISCLOSURE_TOKENS, REVIEW_FAILURE_SQL_STATEMENT_PATTERN, REVIEW_FAILURE_TRACEBACK_PATTERN, isSensitiveReviewFailureDetail, summarizeReviewFailureExplanation, buildReviewFailureHoldReason, createAbortError2, settleRuntimeCyclePromise, unwrapRuntimeCycleSettledResult, normalizeDecisionLabel, normalizeRuntimeSymbol, PromptContractFetchError, isLivePromptContextUnavailableError, buildFailClosedHoldResult, buildPromptConstructionFailureResult, buildLivePromptContextUnavailableFailureResult, pickFirstString, normalizeRuntimeStringList, requirePositiveRuntimeLimit, resolveRuntimeTradingScope, normalizeRuntimeProviderAlias, resolveCatalogModelEntry, createClientRuntimeProviderSetupError, createProviderSetupRejectionError, evaluateModelEligibility, extractReviewRuntimeReasoningSelection, isUsableRuntimeSettingsFallback, resolveRuntimeSettings, formatRuntimeDurationMs, normalizeRuntimeTimingNote, appendRuntimeTimingEvent, reportPromptParityTelemetry, resolveLocalRuntimeSecretRequirements, resolveLocalRuntimeSecretProvider, toEpochSeconds, REQUIRED_AI_INDICATOR_KEYS, TIMEFRAME_ORDER, sortTradingTimeframes, normalizePromptIdentityTimestamp, resolveCompletedCandleBoundary, normalizeAiIndicatorFlags, getPromptLookback, computeSma, computeEma, computeRsi, computeAtr, computeMacd, computeBollingerBands, getIndicatorValue, buildPromptCandlesComponent, buildPromptCandlesPayload, formatUtcTimestampWithWeekday, formatUtcNowWithWeekday, formatPromptPrice, computePromptUnitsUsedForPosition, buildPromptAccountStatusValue, buildPromptPositionsValue, sanitizePromptSymbol, fillTimeMs, fillSize, normalizeFillSide, normalizeFillOrderId, normalizeFillRiskOrderIdentity, fillStartPosition, fillSortValue, sortFillsAscending, sortFillsDescending, inferEntryFromStartPositionChain, inferEntryFromCurrentPositionSize, calculateCurrentPositionState, calculatePositionEntryTimes, countPositionAdds, latestPositionRiskIncreaseTimeMs, latestPositionRiskIncreaseEvidence, compactPromptRiskIncrease, roundPositiveDecimalHalfUp, compactPromptLastTrade, ENTRY_TRADE_FIELDS, PREVIOUS_DECISION_FIELDS, PREVIOUS_CAMPAIGN_FIELDS, hasExactKeys2, isNonnegativeInteger, isFiniteNumber, isExactEnumString, isNonemptyPromptText, isCampaignReasoningText, projectBackendDecisionMemoryItem, requireRenderedStrategyBehaviorState, canonicalFillSideForRiskEvidence, isValidRiskEvidenceFill, isValidCampaignBoundaryFill, normalizeFillHistoryCoverage, resolveFillHistoryCoverageForSymbol, buildPromptBehaviorStateArtifacts, buildPromptBehaviorStateValue, shouldCompareServerPromptParity, buildLocalRuntimePromptArtifacts, createRuntimeId2, asRecord, buildRuntimeConstraintRejectionMessage, hasDeviceProviderSecret, requireNonEmptyStringField, requirePositiveIntegerField, compareContractVersion, parsePromptContractTimestamp, assertPromptContractCompatibility, assertPromptContractTemporalBounds, sleepWithAbort, requireAgentPollRetryAfterMs, materializeClaimedClientRuntimeAgentInstruction, attachClientRuntimeErrorProvenance, isExternalRuntimeProviderResult, invokeClientExternalInference, assertPromptContractBindingTupleEqual, assertPromptContractScopeMatch, fetchBoundPromptContracts, formatTemplateWithNamedVariables, runLocalRuntimeCycle;
108978
+ var normalizeNativeValues, assertPromptModelController, resolveRuntimeReasoningControlsForModel, modelScopedKey, resolveNativeValuesForModel, observeRuntimeCycle, observeAccountState, aiOrderSlippageFraction, serverPerpDexScope, serverBehaviorStateArtifacts, ClientRuntimeAgentInstructionEmpty, isClientRuntimeAgentInstructionEmpty, ClientRuntimeAiSchedulePaused, ClientRuntimeAiScheduleStillActive, isClientRuntimeAiScheduleStillActive, ServerDispatchAccountStateStale, isServerDispatchAccountStateStale, isClientRuntimeAiSchedulePaused, buildClaimedAgentRuntimeCycleResult, resolveRuntimeMarginModePreference, resolveRuntimeLeveragePreference, resolveBooleanSetting2, CLIENT_RUNTIME_LIVE_CONTEXT_UNAVAILABLE_ERRORS, BEHAVIOR_STATE_UNAVAILABLE_ERROR, CriticalBehaviorStateError, clampNumber, resolveExternalInferenceRuntimeTimeoutSeconds, toPositiveFinite3, compactSnippet, hashRuntimeDebugText, EFFECTIVE_INPUT_MANIFEST_SCHEMA_VERSION, PROMPT_ASSEMBLY_DEFINITION_VERSION, RUNTIME_SOURCE_DEFINITION_VERSION, DECISION_INPUT_DEFINITION_VERSION, CONTEXT_ENVELOPE_DEFINITION_VERSION, CLIENT_RUNTIME_SOURCE_VERSION, CLIENT_MAIN_PROMPT_RENDERER, SERVER_MAIN_PROMPT_RENDERER, CLIENT_REVIEW_PROMPT_RENDERER, SERVER_REVIEW_PROMPT_RENDERER, resolveEffectivePromptRuntimeProvenance, canonicalManifestValue, canonicalManifestJson, sha256ManifestHex, effectiveInputComponent, buildEffectiveInputManifest, derivePromptVisibleSections, decodeDecisionTracePayload, extractDecisionSymbolTrace, formatDecisionSymbolTrace, formatActionableDecisionSymbols, normalizePromptSymbols, JSON_MODEL_OUTPUT_FENCE_PATTERN, STRICT_MODEL_OUTPUT_KEYS, currentModelOutputValidationErrors, currentModelOutputMatchesContract, projectCurrentModelDecisionContent, modelOutputValidationError, buildMissingDecisionHold, buildDecisionPlansFromResponse, buildReviewCandidatePlansFromResponse, forceUnavailableSymbolsToHold, extractTemplatePlaceholders, requireReviewPrimaryUserPromptTemplate, containsCompetingBehaviorStateMarkup, containsCompetingMainBehaviorStateMarkup, requireStrategyReviewTemplates, preflightStrategyReviewPromptContract, extractRuntimeReasoningSelection, isAbortError, isRuntimeTimeoutAbortReason, REVIEW_FAILURE_SENSITIVE_DB_TOKENS, REVIEW_FAILURE_SCHEMA_DISCLOSURE_TOKENS, REVIEW_FAILURE_SQL_STATEMENT_PATTERN, REVIEW_FAILURE_TRACEBACK_PATTERN, isSensitiveReviewFailureDetail, summarizeReviewFailureExplanation, buildReviewFailureHoldReason, createAbortError2, settleRuntimeCyclePromise, unwrapRuntimeCycleSettledResult, normalizeDecisionLabel, normalizeRuntimeSymbol, PromptContractFetchError, isLivePromptContextUnavailableError, buildFailClosedHoldResult, buildPromptConstructionFailureResult, buildLivePromptContextUnavailableFailureResult, pickFirstString, normalizeRuntimeStringList, requirePositiveRuntimeLimit, resolveRuntimeTradingScope, normalizeRuntimeProviderAlias, resolveCatalogModelEntry, createClientRuntimeProviderSetupError, createProviderSetupRejectionError, evaluateModelEligibility, extractReviewRuntimeReasoningSelection, isUsableRuntimeSettingsFallback, resolveRuntimeSettings, formatRuntimeDurationMs, normalizeRuntimeTimingNote, appendRuntimeTimingEvent, reportPromptParityTelemetry, resolveLocalRuntimeSecretRequirements, resolveLocalRuntimeSecretProvider, toEpochSeconds, REQUIRED_AI_INDICATOR_KEYS, TIMEFRAME_ORDER, sortTradingTimeframes, normalizePromptIdentityTimestamp, resolveCompletedCandleBoundary, normalizeAiIndicatorFlags, getPromptLookback, computeSma, computeEma, computeRsi, computeAtr, computeMacd, computeBollingerBands, getIndicatorValue, buildPromptCandlesComponent, buildPromptCandlesPayload, formatUtcTimestampWithWeekday, formatUtcNowWithWeekday, formatPromptPrice, computePromptUnitsUsedForPosition, buildPromptAccountStatusValue, buildPromptPositionsValue, sanitizePromptSymbol, fillTimeMs, fillSize, normalizeFillSide, normalizeFillOrderId, normalizeFillRiskOrderIdentity, fillStartPosition, fillSortValue, sortFillsAscending, sortFillsDescending, inferEntryFromStartPositionChain, inferEntryFromCurrentPositionSize, calculateCurrentPositionState, calculatePositionEntryTimes, countPositionAdds, latestPositionRiskIncreaseTimeMs, latestPositionRiskIncreaseEvidence, compactPromptRiskIncrease, roundPositiveDecimalHalfUp, compactPromptLastTrade, ENTRY_TRADE_FIELDS, PREVIOUS_DECISION_FIELDS, PREVIOUS_CAMPAIGN_FIELDS, hasExactKeys2, isNonnegativeInteger, isFiniteNumber, isExactEnumString, isNonemptyPromptText, isCampaignReasoningText, projectBackendDecisionMemoryItem, requireRenderedStrategyBehaviorState, canonicalFillSideForRiskEvidence, isValidRiskEvidenceFill, isValidCampaignBoundaryFill, normalizeFillHistoryCoverage, resolveFillHistoryCoverageForSymbol, buildPromptBehaviorStateArtifacts, buildPromptBehaviorStateValue, shouldCompareServerPromptParity, buildLocalRuntimePromptArtifacts, createRuntimeId2, asRecord, buildRuntimeConstraintRejectionMessage, hasDeviceProviderSecret, requireNonEmptyStringField, requirePositiveIntegerField, compareContractVersion, parsePromptContractTimestamp, assertPromptContractCompatibility, assertPromptContractTemporalBounds, sleepWithAbort, requireAgentPollRetryAfterMs, materializeClaimedClientRuntimeAgentInstruction, attachClientRuntimeErrorProvenance, isExternalRuntimeProviderResult, invokeClientExternalInference, assertPromptContractBindingTupleEqual, assertPromptContractScopeMatch, fetchBoundPromptContracts, formatTemplateWithNamedVariables, runLocalRuntimeCycle;
107926
108979
  var init_local_analysis = __esm({
107927
108980
  "lib/runtime/local-analysis.ts"() {
107928
108981
  "use strict";
@@ -107962,6 +109015,7 @@ var init_local_analysis = __esm({
107962
109015
  init_hyperliquid_market_symbol();
107963
109016
  init_external_inference_contract();
107964
109017
  init_model_controller_provenance();
109018
+ init_ai_schedule();
107965
109019
  normalizeNativeValues = (value) => {
107966
109020
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
107967
109021
  const entries = {};
@@ -108030,6 +109084,29 @@ var init_local_analysis = __esm({
108030
109084
  }
108031
109085
  });
108032
109086
  };
109087
+ aiOrderSlippageFraction = (config2, executionMode) => executionMode === "server" ? Number(config2.server_ai_max_slippage) / 100 : clampNumber(void 0, config2.default_max_slippage) / 100;
109088
+ serverPerpDexScope = (symbols, executionMode) => {
109089
+ if (executionMode !== "server") return void 0;
109090
+ const dexes = /* @__PURE__ */ new Set();
109091
+ for (const raw of symbols) {
109092
+ if (!String(raw ?? "").trim()) continue;
109093
+ if (!normalizeHyperliquidMarketSymbol(raw)) return void 0;
109094
+ dexes.add(getHyperliquidMarketDex(raw));
109095
+ }
109096
+ return dexes.size > 0 ? [...dexes].filter(Boolean) : void 0;
109097
+ };
109098
+ serverBehaviorStateArtifacts = (derived) => {
109099
+ const rendered = derived.behavior_state;
109100
+ if (derived.behavior_state_owner !== "server" || typeof rendered !== "string" || !rendered.trim()) {
109101
+ throw new Error("The server did not build this Server bot's behavior state.");
109102
+ }
109103
+ const preMemory = derived.behavior_state_pre_memory;
109104
+ return {
109105
+ rendered,
109106
+ preMemoryRendered: typeof preMemory === "string" && preMemory.trim() ? preMemory : rendered,
109107
+ policyState: asRecord(derived.behavior_policy_state)
109108
+ };
109109
+ };
108033
109110
  ClientRuntimeAgentInstructionEmpty = class extends Error {
108034
109111
  constructor(retryAfterMs) {
108035
109112
  super("No Agent instruction is currently queued for this Client runtime.");
@@ -108038,6 +109115,31 @@ var init_local_analysis = __esm({
108038
109115
  }
108039
109116
  };
108040
109117
  isClientRuntimeAgentInstructionEmpty = (value) => value instanceof ClientRuntimeAgentInstructionEmpty;
109118
+ ClientRuntimeAiSchedulePaused = class extends Error {
109119
+ constructor(input) {
109120
+ super(input.message);
109121
+ this.name = "ClientRuntimeAiSchedulePaused";
109122
+ this.nextChangeAtMs = input.nextChangeAtMs;
109123
+ this.closeOnStop = input.closeOnStop;
109124
+ this.settings = input.settings;
109125
+ this.config = input.config;
109126
+ }
109127
+ };
109128
+ ClientRuntimeAiScheduleStillActive = class extends Error {
109129
+ constructor() {
109130
+ super("The AI schedule still lets this bot run.");
109131
+ this.name = "ClientRuntimeAiScheduleStillActive";
109132
+ }
109133
+ };
109134
+ isClientRuntimeAiScheduleStillActive = (value) => value instanceof ClientRuntimeAiScheduleStillActive;
109135
+ ServerDispatchAccountStateStale = class extends Error {
109136
+ constructor() {
109137
+ super("Server account context could not be rebuilt inside the dispatch freshness window");
109138
+ this.name = "ServerDispatchAccountStateStale";
109139
+ }
109140
+ };
109141
+ isServerDispatchAccountStateStale = (value) => value instanceof Error && value.name === "ServerDispatchAccountStateStale";
109142
+ isClientRuntimeAiSchedulePaused = (value) => value instanceof ClientRuntimeAiSchedulePaused;
108041
109143
  buildClaimedAgentRuntimeCycleResult = async (input) => {
108042
109144
  const { config: config2, settings, instruction, runtimeInput, signal } = input;
108043
109145
  const binding = runtimeInput.runtimeContractBinding;
@@ -108074,6 +109176,7 @@ var init_local_analysis = __esm({
108074
109176
  tickerPrice: 0,
108075
109177
  leverage,
108076
109178
  aggregatePerpDexs: true,
109179
+ perpDexScope: serverPerpDexScope(symbols, runtimeInput.executionMode),
108077
109180
  feeSymbols: symbols,
108078
109181
  includeEffectiveTakerRate: true,
108079
109182
  sessionId: String(runtimeInput.sessionId || "").trim(),
@@ -108168,11 +109271,11 @@ var init_local_analysis = __esm({
108168
109271
  walletAddress,
108169
109272
  lastPrice: price,
108170
109273
  unitSizeUsdc: tradeSize,
108171
- sizeDecimals: Number(config2.default_size_decimals),
108172
109274
  leverage,
108173
109275
  marginMode,
108174
109276
  closePositionDelaySeconds: Number(config2.client_runtime_close_position_delay_seconds),
108175
- maxSlippageFraction: clampNumber(void 0, config2.default_max_slippage) / 100,
109277
+ closePositionFreshnessPollMs: Number(config2.close_position_freshness_poll_milliseconds),
109278
+ maxSlippageFraction: aiOrderSlippageFraction(config2, runtimeInput.executionMode),
108176
109279
  ...buildRuntimeSlTpExecutionSettings(settings, config2)
108177
109280
  };
108178
109281
  };
@@ -109522,14 +110625,14 @@ ${reviewOutputContract}`;
109522
110625
  const normalized = String(value || "").replace(/\s+/g, " ").trim();
109523
110626
  return normalized.length > 0 ? normalized : null;
109524
110627
  };
109525
- appendRuntimeTimingEvent = (label, startedAtMs, note, outcome) => {
110628
+ appendRuntimeTimingEvent = (label2, startedAtMs, note, outcome) => {
109526
110629
  const parts = [`duration=${formatRuntimeDurationMs(Date.now() - startedAtMs)}`];
109527
110630
  const normalizedNote = normalizeRuntimeTimingNote(note);
109528
110631
  if (normalizedNote) {
109529
110632
  parts.push(normalizedNote);
109530
110633
  }
109531
110634
  appendRuntimeDebugEvent({
109532
- label,
110635
+ label: label2,
109533
110636
  note: parts.join(" "),
109534
110637
  outcome
109535
110638
  });
@@ -111008,17 +112111,17 @@ ${behaviorJson}
111008
112111
  }
111009
112112
  return hasValue(secrets.providerKeys[provider]) || hasSlotValue(secrets.providerKeySlots?.[provider]);
111010
112113
  };
111011
- requireNonEmptyStringField = (value, label) => {
112114
+ requireNonEmptyStringField = (value, label2) => {
111012
112115
  const normalized = String(value ?? "").trim();
111013
112116
  if (!normalized) {
111014
- throw new Error(`Missing required prompt contract field: ${label}`);
112117
+ throw new Error(`Missing required prompt contract field: ${label2}`);
111015
112118
  }
111016
112119
  return normalized;
111017
112120
  };
111018
- requirePositiveIntegerField = (value, label) => {
112121
+ requirePositiveIntegerField = (value, label2) => {
111019
112122
  const parsed = Number(value);
111020
112123
  if (!Number.isFinite(parsed) || parsed <= 0) {
111021
- throw new Error(`Missing required positive prompt contract field: ${label}`);
112124
+ throw new Error(`Missing required positive prompt contract field: ${label2}`);
111022
112125
  }
111023
112126
  return Math.trunc(parsed);
111024
112127
  };
@@ -111768,6 +112871,25 @@ ${behaviorJson}
111768
112871
  }
111769
112872
  const config2 = configResult.value;
111770
112873
  const runtimeSettings = runtimeSettingsResult.value;
112874
+ const aiSchedule = runtimeSettings.settings.ai_schedule ?? config2.default_ai_schedule;
112875
+ if (!input.ignoreAiSchedule) {
112876
+ if (isAiScheduleEnabled(aiSchedule)) {
112877
+ const scheduleState = evaluateAiSchedule(aiSchedule, config2.default_ai_schedule, Date.now());
112878
+ if (!scheduleState.shouldRun) {
112879
+ throw new ClientRuntimeAiSchedulePaused({
112880
+ message: scheduleState.message,
112881
+ nextChangeAtMs: scheduleState.nextChangeAtMs,
112882
+ closeOnStop: isAiScheduleEnabled({ enabled: aiSchedule?.close_on_stop }),
112883
+ settings: runtimeSettings.settings,
112884
+ config: config2
112885
+ });
112886
+ }
112887
+ input.onAiScheduleWindowActive?.(scheduleState.nextChangeAtMs);
112888
+ } else {
112889
+ input.onAiScheduleOff?.();
112890
+ }
112891
+ if (input.aiScheduleCheckOnly) throw new ClientRuntimeAiScheduleStillActive();
112892
+ }
111771
112893
  input = {
111772
112894
  ...input,
111773
112895
  secrets: await ClientVault.refreshProviderSecretsForVersion(
@@ -111945,11 +113067,11 @@ ${behaviorJson}
111945
113067
  walletAddress: String(settings.hyperliquid_wallet_address || "").trim() || void 0,
111946
113068
  lastPrice: 0,
111947
113069
  unitSizeUsdc: clampNumber(promptKnobs2.trade_size, config2.default_ai_trade_amount),
111948
- sizeDecimals: Number(config2.default_size_decimals),
111949
113070
  leverage: clampNumber(promptKnobs2.leverage, config2.default_leverage),
111950
113071
  marginMode: resolveRuntimeMarginModePreference(settings, config2),
111951
113072
  closePositionDelaySeconds: Number(config2.client_runtime_close_position_delay_seconds),
111952
- maxSlippageFraction: clampNumber(void 0, config2.default_max_slippage) / 100,
113073
+ closePositionFreshnessPollMs: Number(config2.close_position_freshness_poll_milliseconds),
113074
+ maxSlippageFraction: aiOrderSlippageFraction(config2, input.executionMode),
111953
113075
  ...buildRuntimeSlTpExecutionSettings(settings, config2),
111954
113076
  executionFreshnessMaxAgeSeconds: requirePositiveIntegerField(
111955
113077
  promptKnobs2.execution_decision_max_age_seconds,
@@ -111970,6 +113092,8 @@ ${behaviorJson}
111970
113092
  let _latestPerpDexAccounts = null;
111971
113093
  let latestPositions = [];
111972
113094
  let _accountStateResolvedAtMs = null;
113095
+ let _accountStateFetchedAtMs = null;
113096
+ let _accountStateSource = null;
111973
113097
  const getLatestAccountEquity = () => _latestAccountEquity;
111974
113098
  const getLatestTotalUnrealizedPnl = () => _latestTotalUnrealizedPnl;
111975
113099
  const getAccountStateResolvedAtMs = () => _accountStateResolvedAtMs;
@@ -111983,8 +113107,12 @@ ${behaviorJson}
111983
113107
  tickerPrice: 0,
111984
113108
  leverage: resolveRuntimeLeveragePreference(settings, config2),
111985
113109
  aggregatePerpDexs: true,
113110
+ perpDexScope: serverPerpDexScope(symbols, input.executionMode),
111986
113111
  feeSymbols: symbols,
111987
113112
  includeEffectiveTakerRate: true,
113113
+ // A Server bot's cycle reads the account authoritatively, as the Python
113114
+ // Server loop does: never a cached or rate-limit-stale observation.
113115
+ forceRefresh: input.executionMode === "server",
111988
113116
  sessionId,
111989
113117
  signal: timeoutController.signal
111990
113118
  }).then((state2) => {
@@ -111992,6 +113120,8 @@ ${behaviorJson}
111992
113120
  latestPositions = state2.positions;
111993
113121
  const resolvedEquity = Number(state2.accountSummary?.account_value) || 0;
111994
113122
  _accountStateResolvedAtMs = Date.now();
113123
+ _accountStateFetchedAtMs = state2.evidence?.fetchedAtMs ?? _accountStateResolvedAtMs;
113124
+ _accountStateSource = state2.evidence?.source ?? null;
111995
113125
  if (resolvedEquity > 0) {
111996
113126
  _latestAccountEquity = resolvedEquity;
111997
113127
  _latestPerpDexAccounts = state2.accountSummary?.perp_dex_accounts ?? null;
@@ -112018,7 +113148,8 @@ ${behaviorJson}
112018
113148
  });
112019
113149
  const browserAccountStatePromise = settleRuntimeCyclePromise(browserAccountStateTask);
112020
113150
  const browserUserFillsStartedAtMs = Date.now();
112021
- const browserUserFillsTask = fetchBrowserUserFills({
113151
+ const serverOwnsBehaviorState = input.executionMode === "server";
113152
+ const browserUserFillsTask = serverOwnsBehaviorState ? Promise.resolve(null) : fetchBrowserUserFills({
112022
113153
  publicRequestPriority: "trading_analysis",
112023
113154
  config: config2,
112024
113155
  walletAddress,
@@ -112053,7 +113184,7 @@ ${behaviorJson}
112053
113184
  getLatestAccountEquity,
112054
113185
  getLatestTotalUnrealizedPnl,
112055
113186
  getAccountStateResolvedAtMs,
112056
- async () => {
113187
+ serverOwnsBehaviorState ? void 0 : async () => {
112057
113188
  const result = unwrapRuntimeCycleSettledResult(await browserUserFillsPromise);
112058
113189
  return { fills: result.rawFills, evidence: result.evidence };
112059
113190
  },
@@ -112081,12 +113212,14 @@ ${behaviorJson}
112081
113212
  sortedTimeframes.map(async (marketTimeframe) => [
112082
113213
  marketTimeframe,
112083
113214
  await getRecentCandles(
113215
+ // Indicators warm up on the same history as the Server loop's
113216
+ // (indicator_history.py); the prompt shows its lookback of it.
112084
113217
  Math.max(getPromptLookback(
112085
113218
  lookbackSettings,
112086
113219
  marketTimeframe,
112087
113220
  effectiveDefaultLookbacks,
112088
113221
  config2.max_analysis_lookback
112089
- ), 250),
113222
+ ), Number(config2.indicator_candle_count) || 250),
112090
113223
  "hyperliquid",
112091
113224
  marketSymbol,
112092
113225
  marketTimeframe,
@@ -112183,11 +113316,11 @@ ${behaviorJson}
112183
113316
  walletAddress: String(settings.hyperliquid_wallet_address || "").trim() || void 0,
112184
113317
  lastPrice: toPositiveFinite3(ticker.price) ?? 0,
112185
113318
  unitSizeUsdc: clampNumber(rejectedPromptKnobs.trade_size, config2.default_ai_trade_amount),
112186
- sizeDecimals: Number(config2.default_size_decimals),
112187
113319
  leverage: clampNumber(rejectedPromptKnobs.leverage, config2.default_leverage),
112188
113320
  marginMode: resolveRuntimeMarginModePreference(settings, config2),
112189
113321
  closePositionDelaySeconds: Number(config2.client_runtime_close_position_delay_seconds),
112190
- maxSlippageFraction: clampNumber(void 0, config2.default_max_slippage) / 100,
113322
+ closePositionFreshnessPollMs: Number(config2.close_position_freshness_poll_milliseconds),
113323
+ maxSlippageFraction: aiOrderSlippageFraction(config2, input.executionMode),
112191
113324
  ...buildRuntimeSlTpExecutionSettings(settings, config2),
112192
113325
  executionFreshnessMaxAgeSeconds: requirePositiveIntegerField(
112193
113326
  rejectedPromptKnobs.execution_decision_max_age_seconds,
@@ -112212,8 +113345,8 @@ ${behaviorJson}
112212
113345
  positions
112213
113346
  ) ?? browserAccountState.accountSummary.total_unrealized_pnl
112214
113347
  };
112215
- tradeHistory = browserUserFills.tradeHistory;
112216
- if (input.mode === "trader" && browserUserFills.evidence?.source !== "live") {
113348
+ tradeHistory = browserUserFills?.tradeHistory ?? [];
113349
+ if (input.mode === "trader" && !serverOwnsBehaviorState && browserUserFills?.evidence?.source !== "live") {
112217
113350
  throw new CriticalBehaviorStateError();
112218
113351
  }
112219
113352
  const metadataSymbol = requireNonEmptyStringField(promptMetadata.symbol, "symbol");
@@ -112508,11 +113641,11 @@ ${behaviorJson}
112508
113641
  if (input.mode === "trader" && !behaviorMemoryEnabled) {
112509
113642
  throw new CriticalBehaviorStateError();
112510
113643
  }
112511
- const browserFillEvidence = browserUserFills.evidence;
113644
+ const browserFillEvidence = browserUserFills?.evidence;
112512
113645
  const behaviorFillCoverage = browserFillEvidence?.source === "live" && browserFillEvidence.exactTerminalFillEvidenceComplete === true ? "complete" : "capped";
112513
113646
  let behaviorStateArtifacts;
112514
113647
  try {
112515
- behaviorStateArtifacts = buildPromptBehaviorStateArtifacts({
113648
+ behaviorStateArtifacts = serverOwnsBehaviorState ? serverBehaviorStateArtifacts(derivedContext) : buildPromptBehaviorStateArtifacts({
112516
113649
  fills: tradeHistory,
112517
113650
  positions,
112518
113651
  symbols: promptSymbols,
@@ -112600,11 +113733,11 @@ ${stringifyPromptJson(candlesPayload)}
112600
113733
  walletAddress: walletAddress || void 0,
112601
113734
  lastPrice: 0,
112602
113735
  unitSizeUsdc: metadataTradeSize,
112603
- sizeDecimals: Number(config2.default_size_decimals),
112604
113736
  leverage: metadataLeverage,
112605
113737
  marginMode: resolveRuntimeMarginModePreference(settings, config2),
112606
113738
  closePositionDelaySeconds: Number(config2.client_runtime_close_position_delay_seconds),
112607
- maxSlippageFraction: clampNumber(void 0, config2.default_max_slippage) / 100,
113739
+ closePositionFreshnessPollMs: Number(config2.close_position_freshness_poll_milliseconds),
113740
+ maxSlippageFraction: aiOrderSlippageFraction(config2, input.executionMode),
112608
113741
  ...buildRuntimeSlTpExecutionSettings(settings, config2),
112609
113742
  executionFreshnessMaxAgeSeconds
112610
113743
  }
@@ -112726,11 +113859,11 @@ ${stringifyPromptJson(candlesPayload)}
112726
113859
  walletAddress: String(settings.hyperliquid_wallet_address || "").trim() || void 0,
112727
113860
  lastPrice: executionPrice,
112728
113861
  unitSizeUsdc: metadataTradeSize,
112729
- sizeDecimals: Number(config2.default_size_decimals),
112730
113862
  leverage: metadataLeverage,
112731
113863
  marginMode: resolveRuntimeMarginModePreference(settings, config2),
112732
113864
  closePositionDelaySeconds: Number(config2.client_runtime_close_position_delay_seconds),
112733
- maxSlippageFraction: clampNumber(void 0, config2.default_max_slippage) / 100,
113865
+ closePositionFreshnessPollMs: Number(config2.close_position_freshness_poll_milliseconds),
113866
+ maxSlippageFraction: aiOrderSlippageFraction(config2, input.executionMode),
112734
113867
  ...buildRuntimeSlTpExecutionSettings(settings, config2),
112735
113868
  executionFreshnessMaxAgeSeconds
112736
113869
  }
@@ -112756,11 +113889,11 @@ ${stringifyPromptJson(candlesPayload)}
112756
113889
  walletAddress: String(settings.hyperliquid_wallet_address || "").trim() || void 0,
112757
113890
  lastPrice: planPrice,
112758
113891
  unitSizeUsdc: metadataTradeSize,
112759
- sizeDecimals: Number(config2.default_size_decimals),
112760
113892
  leverage: metadataLeverage,
112761
113893
  marginMode,
112762
113894
  closePositionDelaySeconds: Number(config2.client_runtime_close_position_delay_seconds),
112763
- maxSlippageFraction: clampNumber(void 0, config2.default_max_slippage) / 100,
113895
+ closePositionFreshnessPollMs: Number(config2.close_position_freshness_poll_milliseconds),
113896
+ maxSlippageFraction: aiOrderSlippageFraction(config2, input.executionMode),
112764
113897
  ...buildRuntimeSlTpExecutionSettings(settings, config2),
112765
113898
  executionFreshnessMaxAgeSeconds
112766
113899
  };
@@ -112913,6 +114046,17 @@ ${stringifyPromptJson(candlesPayload)}
112913
114046
  note: `lane=main seconds=${requestTimeoutSeconds}`
112914
114047
  });
112915
114048
  }
114049
+ const dispatchAccountStateAgeMs = _accountStateFetchedAtMs === null ? null : Date.now() - _accountStateFetchedAtMs;
114050
+ appendRuntimeDebugEvent({
114051
+ label: "account_state_dispatch_age",
114052
+ note: `account_state_age_ms=${dispatchAccountStateAgeMs ?? "unresolved"} source=${_accountStateSource ?? "unknown"}`
114053
+ });
114054
+ if (input.executionMode === "server" && !allPromptSymbolsUnavailable && (dispatchAccountStateAgeMs === null || dispatchAccountStateAgeMs > requirePositiveIntegerField(
114055
+ config2.server_dispatch_account_state_max_age_milliseconds,
114056
+ "server_dispatch_account_state_max_age_milliseconds"
114057
+ ))) {
114058
+ throw new ServerDispatchAccountStateStale();
114059
+ }
112916
114060
  const providerStartedAtMs = Date.now();
112917
114061
  observeRuntimeCycle(input, { stage: "model", reason_code: null });
112918
114062
  let selectedPrimaryModel = authoritativeModel;
@@ -113823,7 +114967,7 @@ ${reviewOutputContract}`;
113823
114967
  executionPlans: acceptedExecutionPlans
113824
114968
  });
113825
114969
  } catch (error48) {
113826
- if (isClientRuntimeAgentInstructionEmpty(error48)) {
114970
+ if (isClientRuntimeAgentInstructionEmpty(error48) || isClientRuntimeAiSchedulePaused(error48) || isClientRuntimeAiScheduleStillActive(error48)) {
113827
114971
  throw error48;
113828
114972
  }
113829
114973
  if (error48 instanceof PromptContractFetchError && error48.metadata) {
@@ -113854,8 +114998,8 @@ ${reviewOutputContract}`;
113854
114998
  const detail = error48 instanceof Error ? error48.message : String(error48);
113855
114999
  appendRuntimeTimingEvent("analysis_cycle_failed", cycleStartedAtMs, detail, "error");
113856
115000
  if (isAbortError(error48)) {
113857
- const abortReason = timeoutController.signal.reason;
113858
- if (isRuntimeTimeoutAbortReason(abortReason)) {
115001
+ const abortReason2 = timeoutController.signal.reason;
115002
+ if (isRuntimeTimeoutAbortReason(abortReason2)) {
113859
115003
  const timeoutError = Object.assign(
113860
115004
  new Error("Client runtime analysis timed out before the provider returned a result.", { cause: error48 }),
113861
115005
  error48,
@@ -113863,8 +115007,8 @@ ${reviewOutputContract}`;
113863
115007
  );
113864
115008
  throw cycleErrorProvenance ? attachClientRuntimeErrorProvenance(timeoutError, cycleErrorProvenance) : timeoutError;
113865
115009
  }
113866
- if (abortReason instanceof Error) {
113867
- throw cycleErrorProvenance ? attachClientRuntimeErrorProvenance(abortReason, cycleErrorProvenance) : abortReason;
115010
+ if (abortReason2 instanceof Error) {
115011
+ throw cycleErrorProvenance ? attachClientRuntimeErrorProvenance(abortReason2, cycleErrorProvenance) : abortReason2;
113868
115012
  }
113869
115013
  throw cycleErrorProvenance ? attachClientRuntimeErrorProvenance(error48, cycleErrorProvenance) : error48;
113870
115014
  }
@@ -113880,7 +115024,7 @@ ${reviewOutputContract}`;
113880
115024
  });
113881
115025
 
113882
115026
  // lib/runtime/engine.ts
113883
- var localAnalysis, getExchangeFailureDiagnostics, getRuntimeFallbackAttempts, isProviderFailureDiagnosticsCandidate, getEventBoundProviderLabel, getEventBoundProviderTraceId, getRecentProviderFailureDiagnostics, getClientRuntimeErrorProvenance, getRuntimeProviderSetupDiagnostics, buildProviderSetupErrorDiagnosticFields, buildClientRuntimeErrorProvenanceDiagnosticFields, buildRuntimeRequestErrorDiagnosticFields, hasEventBoundProviderFailureEvidence, classifyRuntimeErrorStage, buildHyperliquidPublicReadDiagnosticFields, buildRuntimeErrorDiagnostics, positiveNumber, resolveRuntimeEngineOptions, CLIENT_KILLSWITCH_BLOCK_STORAGE_PREFIX, getClientKillswitchBlockStorageKey, persistClientRuntimeKillswitchBlock, clearClientRuntimeKillswitchBlock, hashRuntimeDebugText2, createRuntimeUuid2, getRuntimeContractIdentityToken, getRuntimeStatusContractIdentityToken, getRuntimeContractBindingTokenFromCycleResult, getRuntimeContractBindingTupleToken, getRuntimeStatusContractBindingTupleToken, isTransientRuntimeConflictError, createRuntimeStartCancelledError, isRuntimeContractMismatchError, isClientExecutionModeMismatchError, isClientRuntimeSessionStoppedError, isClientRuntimeLeaseAuthError, isClientRuntimeReleasedError, deriveFailedStartCleanupOwnershipLossReason, isRuntimeAbortError, isExplicitClientExecutionMode, createStopAbortError, isRuntimeContractIdentityAdvancedAbort, CLIENT_RUNTIME_NO_DECISION_RECOVERY_REASON, sanitizeSettingsSnapshotForFallback, preflightClientRuntime, ClientExecutionEngine, createStoppedRuntimeSnapshot, ClientRuntimeRegistry, botEngine;
115027
+ var localAnalysis, getExchangeFailureDiagnostics, getRuntimeFallbackAttempts, isProviderFailureDiagnosticsCandidate, getEventBoundProviderLabel, getEventBoundProviderTraceId, getRecentProviderFailureDiagnostics, getClientRuntimeErrorProvenance, getRuntimeProviderSetupDiagnostics, buildProviderSetupErrorDiagnosticFields, buildClientRuntimeErrorProvenanceDiagnosticFields, buildRuntimeRequestErrorDiagnosticFields, hasEventBoundProviderFailureEvidence, classifyRuntimeErrorStage, buildHyperliquidPublicReadDiagnosticFields, buildRuntimeErrorDiagnostics, positiveNumber, resolveRuntimeEngineOptions, withServerPositionEvents, CLIENT_KILLSWITCH_BLOCK_STORAGE_PREFIX, getClientKillswitchBlockStorageKey, persistClientRuntimeKillswitchBlock, clearClientRuntimeKillswitchBlock, hashRuntimeDebugText2, createRuntimeUuid2, getRuntimeContractIdentityToken, getRuntimeStatusContractIdentityToken, getRuntimeContractBindingTokenFromCycleResult, getRuntimeContractBindingTupleToken, getRuntimeStatusContractBindingTupleToken, isTransientRuntimeConflictError, createRuntimeStartCancelledError, isRuntimeContractMismatchError, isClientExecutionModeMismatchError, isClientRuntimeSessionStoppedError, isClientRuntimeLeaseAuthError, isClientRuntimeReleasedError, deriveFailedStartCleanupOwnershipLossReason, isRuntimeAbortError, isExplicitClientExecutionMode, createStopAbortError, isRuntimeContractIdentityAdvancedAbort, CLIENT_RUNTIME_NO_DECISION_RECOVERY_REASON, sanitizeSettingsSnapshotForFallback, preflightClientRuntime, ClientExecutionEngine, createStoppedRuntimeSnapshot, ClientRuntimeRegistry, botEngine;
113884
115028
  var init_engine = __esm({
113885
115029
  "lib/runtime/engine.ts"() {
113886
115030
  "use strict";
@@ -114261,6 +115405,28 @@ var init_engine = __esm({
114261
115405
  }
114262
115406
  return options;
114263
115407
  };
115408
+ withServerPositionEvents = (result) => result.executionReports.map((report) => {
115409
+ const action = String(report.action ?? "").toUpperCase();
115410
+ if (report.status !== "executed" || !["BUY", "SELL", "FLIP_OPEN"].includes(action)) return report;
115411
+ const bySide = (side) => side === "BUY" ? "LONG" : "SHORT";
115412
+ let event = null;
115413
+ let direction = null;
115414
+ if (result.intent === "open" || result.intent === "add") {
115415
+ event = result.intent;
115416
+ direction = bySide(action);
115417
+ } else if (result.intent === "reduce") {
115418
+ event = "reduce";
115419
+ direction = action === "BUY" ? "SHORT" : "LONG";
115420
+ } else if (result.intent === "close" || result.intent === "flip" && action !== "FLIP_OPEN") {
115421
+ event = "close";
115422
+ direction = action === "SELL" ? "LONG" : "SHORT";
115423
+ } else if (result.intent === "flip" && (result.side === "buy" || result.side === "sell")) {
115424
+ event = "open";
115425
+ direction = result.side === "buy" ? "LONG" : "SHORT";
115426
+ }
115427
+ if (!event || !direction) return report;
115428
+ return { ...report, execution_metadata: { ...report.execution_metadata, position_event: event, position_direction: direction } };
115429
+ });
114264
115430
  CLIENT_KILLSWITCH_BLOCK_STORAGE_PREFIX = "vtx_client_runtime_killswitch_block_v1:";
114265
115431
  getClientKillswitchBlockStorageKey = (profileId) => `${CLIENT_KILLSWITCH_BLOCK_STORAGE_PREFIX}${profileId.trim()}`;
114266
115432
  persistClientRuntimeKillswitchBlock = (profileId) => {
@@ -114494,6 +115660,20 @@ var init_engine = __esm({
114494
115660
  this._startupPendingAnalysis = false;
114495
115661
  // True while the previous cycle ended in Agent-instruction polling.
114496
115662
  this._agentInstructionPollActive = false;
115663
+ // The AI schedule (lib/runtime/ai-schedule.ts): paused outside its windows,
115664
+ // and whether a window let a cycle run since (its end then may close
115665
+ // positions, as the Python Server loop's _was_scheduled_running).
115666
+ this._aiSchedulePaused = false;
115667
+ this._aiScheduleWindowActive = false;
115668
+ // When the window that let the last cycle run ends: the engine checks again
115669
+ // then, so a pause (and Close on Stop) starts at the window's end.
115670
+ this._aiScheduleWindowEndsAtMs = null;
115671
+ // Run Now's next cycle runs whatever the schedule says (triggerNow).
115672
+ this._manualRunRequested = false;
115673
+ // The cycle in flight only checks the AI schedule (a window-end or resume check).
115674
+ this._checkOnlyCycleInFlight = false;
115675
+ // The armed timer is a window-end wake: its cycle only applies the schedule.
115676
+ this._aiScheduleCheckPending = false;
114497
115677
  // Cycle whose Agent-instruction claim is currently held open by the server.
114498
115678
  // That idle wait is not analysis, so busy flags exclude it.
114499
115679
  this._agentInstructionClaimWaitRequestId = null;
@@ -114517,6 +115697,8 @@ var init_engine = __esm({
114517
115697
  this._primaryAnalysisDisabled = false;
114518
115698
  this._loopEarlyReturnRetryDelayMs = 5e3;
114519
115699
  this._executionModeMismatchConsecutiveCount = 0;
115700
+ this._expectedExecutionMode = "client";
115701
+ this._settleUnreportedModelCalls = null;
114520
115702
  this._activeRuntimeContractIdentity = null;
114521
115703
  this._contractRebindInFlight = false;
114522
115704
  this._contractRebindExhausted = false;
@@ -114684,6 +115866,57 @@ var init_engine = __esm({
114684
115866
  }
114685
115867
  return pending3.length === 0;
114686
115868
  }
115869
+ /**
115870
+ * Close on Stop: a Trader's schedule window ended with the option on, so
115871
+ * its open positions close, as the Python Server loop's
115872
+ * _handle_schedule_stop does. A failure is reported as a runtime error and
115873
+ * the bot stays paused.
115874
+ */
115875
+ async _closePositionsAtScheduleEnd(profileId, paused, cancelled) {
115876
+ try {
115877
+ if (cancelled()) return;
115878
+ const walletAddress = String(paused.settings.hyperliquid_wallet_address || "").trim();
115879
+ const signingKey = String(this._deviceSecrets?.hyperliquidSigningKey || "").trim();
115880
+ if (!walletAddress || !signingKey) {
115881
+ throw new Error("the wallet or its signing key is unavailable");
115882
+ }
115883
+ const timeoutSeconds = Number(paused.config.client_runtime_killswitch_close_timeout_seconds);
115884
+ if (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0) {
115885
+ throw new Error("Invalid Client Mode position close timeout configuration.");
115886
+ }
115887
+ await this._trailingMaintenancePromise;
115888
+ await this._pendingProtectionRecoveryPromise;
115889
+ await waitForBrowserExchangeMutationSettlement(profileId);
115890
+ const { positions } = await fetchBrowserAccountState2({
115891
+ publicRequestPriority: "trading_reduce",
115892
+ config: paused.config,
115893
+ walletAddress,
115894
+ symbol: firstConfiguredSymbol(paused.settings, paused.config),
115895
+ tickerPrice: 0,
115896
+ leverage: 1,
115897
+ aggregatePerpDexs: true,
115898
+ forceRefresh: true,
115899
+ sessionId: this._sessionId ?? void 0
115900
+ });
115901
+ if (cancelled()) return;
115902
+ await this._assertFreshClientWalletAssignment(profileId, walletAddress, void 0, "scheduled close on stop");
115903
+ if (cancelled()) return;
115904
+ const summary = await closeClientKillswitchPositions({
115905
+ profileId,
115906
+ walletAddress,
115907
+ positions,
115908
+ config: paused.config,
115909
+ signingKey,
115910
+ timeoutSeconds
115911
+ });
115912
+ if (summary.positionCloseFailures > 0) {
115913
+ throw new Error(`${summary.positionCloseFailures} position(s) could not be closed`);
115914
+ }
115915
+ } catch (error48) {
115916
+ const detail = error48 instanceof Error ? error48.message : String(error48);
115917
+ await this.reportError(`\u26A0\uFE0F Scheduled close-on-stop failed: ${detail}`, { fatal: false });
115918
+ }
115919
+ }
114687
115920
  async _assertFreshClientWalletAssignment(profileId, expectedWalletAddress, signal, stage) {
114688
115921
  const expectedWallet = String(expectedWalletAddress || "").trim().toLowerCase();
114689
115922
  if (!expectedWallet) {
@@ -114723,7 +115956,9 @@ var init_engine = __esm({
114723
115956
  const status = await getAiTradingStatus(void 0, Number(this._profileId), {
114724
115957
  runtimeViewer: this._runtimeStatusViewer()
114725
115958
  });
114726
- if (!isExplicitClientExecutionMode(status?.execution_mode)) {
115959
+ const statusMode = status?.execution_mode;
115960
+ const expectedMode = this._expectedExecutionMode === "server" ? String(statusMode ?? "").trim().toLowerCase() === "server" : isExplicitClientExecutionMode(statusMode);
115961
+ if (!expectedMode) {
114727
115962
  this._executionModeMismatchConsecutiveCount += 1;
114728
115963
  return this._executionModeMismatchConsecutiveCount >= 2;
114729
115964
  }
@@ -115265,6 +116500,7 @@ var init_engine = __esm({
115265
116500
  }
115266
116501
  _armExecutionLoopTimer(options) {
115267
116502
  this._clearExecutionLoopTimer();
116503
+ if (options?.reason !== "ai_schedule_window_end") this._aiScheduleCheckPending = false;
115268
116504
  if (this._state !== "running" || this._loopIntervalMs == null) {
115269
116505
  return;
115270
116506
  }
@@ -115286,7 +116522,7 @@ var init_engine = __esm({
115286
116522
  const timerReason = options?.reason || "scheduled";
115287
116523
  const armedAtMs = Date.now();
115288
116524
  const expectedFireAtMs = armedAtMs + delayMs;
115289
- const quietAgentPollTimer = timerReason === "agent_instruction_poll";
116525
+ const quietAgentPollTimer = timerReason === "agent_instruction_poll" || timerReason === "ai_schedule_paused";
115290
116526
  if (!quietAgentPollTimer) this._emitLoopBoundaryTelemetry("client_timer_armed", `reason=${options?.reason || "scheduled"} delay_ms=${delayMs}`, {
115291
116527
  reason: timerReason,
115292
116528
  delay_ms: delayMs,
@@ -115295,7 +116531,13 @@ var init_engine = __esm({
115295
116531
  timer_expected_fire_at_ms: expectedFireAtMs,
115296
116532
  // Terminal cycle evidence already records its next schedule. Retain the
115297
116533
  // initial/repaired schedule too, even if its first cycle never starts.
115298
- ...["cycle_finally", "main_model_disabled_copy_poll", "agent_instruction_poll"].includes(timerReason) ? {} : { cycle_evidence: {
116534
+ ...[
116535
+ "cycle_finally",
116536
+ "main_model_disabled_copy_poll",
116537
+ "agent_instruction_poll",
116538
+ "ai_schedule_paused",
116539
+ "ai_schedule_window_end"
116540
+ ].includes(timerReason) ? {} : { cycle_evidence: {
115299
116541
  version: 1,
115300
116542
  runtime_source: "client",
115301
116543
  mode: this._mode,
@@ -115538,6 +116780,24 @@ var init_engine = __esm({
115538
116780
  return this._instanceId;
115539
116781
  }
115540
116782
  /** Whether this engine runs, starts, or stops a runtime (never claim it again). */
116783
+ /**
116784
+ * Resolves once no cycle is in flight, or after the timeout: a Node runtime
116785
+ * host draining for a restart lets the current cycle finish, as a Python
116786
+ * Server worker drains its in-flight work. Whether it settled in time.
116787
+ */
116788
+ async waitForCycleToSettle(timeoutMs) {
116789
+ const loop = this._executionLoopPromise;
116790
+ if (!loop) return true;
116791
+ let timer;
116792
+ const settled = await Promise.race([
116793
+ loop.then(() => true, () => true),
116794
+ new Promise((resolve14) => {
116795
+ timer = setTimeout(() => resolve14(false), timeoutMs);
116796
+ })
116797
+ ]);
116798
+ clearTimeout(timer);
116799
+ return settled;
116800
+ }
115541
116801
  get active() {
115542
116802
  return this._startPromise !== null || this._isStopping || this._state === "running" || this._state === "stale" || this._state === "offline";
115543
116803
  }
@@ -115564,12 +116824,20 @@ var init_engine = __esm({
115564
116824
  await this.relinquishControl("window");
115565
116825
  }
115566
116826
  async _attachInternal(profileId, grant, options, startController) {
116827
+ this._aiSchedulePaused = false;
116828
+ this._aiScheduleWindowActive = false;
116829
+ this._aiScheduleWindowEndsAtMs = null;
115567
116830
  const lease = grant.lease;
115568
116831
  const grantSessionId = String(lease.runtime_session_id || "").trim();
115569
116832
  const grantDeviceId = String(lease.device_id || "").trim();
115570
116833
  if (String(lease.profile_id) !== String(profileId) || !grantSessionId || !grantDeviceId) {
115571
116834
  throw new Error("The runtime grant does not belong to this profile.");
115572
116835
  }
116836
+ this._expectedExecutionMode = options.executionMode === "server" ? "server" : "client";
116837
+ this._manualRunRequested = false;
116838
+ this._aiScheduleCheckPending = false;
116839
+ this._checkOnlyCycleInFlight = false;
116840
+ this._settleUnreportedModelCalls = options.settleUnreportedModelCalls ?? null;
115573
116841
  const leaseSchedulerInstanceId = String(lease.scheduler_instance_id ?? "").trim();
115574
116842
  if (leaseSchedulerInstanceId !== this._instanceId && !(leaseSchedulerInstanceId === "" && options.unboundSchedulerLease === true)) {
115575
116843
  throw createRuntimeStartCancelledError("scheduler_instance_binding_missing", {
@@ -115589,7 +116857,8 @@ var init_engine = __esm({
115589
116857
  this._sessionId = grantSessionId;
115590
116858
  this._deviceId = grantDeviceId;
115591
116859
  this._mode = lease.mode === "assistant" ? "assistant" : "trader";
115592
- this._lastRunAt = (/* @__PURE__ */ new Date()).toISOString();
116860
+ const grantedLastRunAt = String(grant.runtime?.last_runtime_run_at ?? "").trim();
116861
+ this._lastRunAt = this._expectedExecutionMode === "server" ? Number.isFinite(Date.parse(grantedLastRunAt)) ? new Date(Date.parse(grantedLastRunAt)).toISOString() : null : (/* @__PURE__ */ new Date()).toISOString();
115593
116862
  this._lastAnalysisStartedAtMs = null;
115594
116863
  this._lastError = null;
115595
116864
  this._lastStopReason = null;
@@ -115715,7 +116984,10 @@ var init_engine = __esm({
115715
116984
  return;
115716
116985
  }
115717
116986
  this._assertStartAttemptActive(startController, "before_execution_loop");
115718
- if (waitsForAssignedStartPhase) {
116987
+ if (waitsForAssignedStartPhase && this._expectedExecutionMode === "server" && this._mode === "trader") {
116988
+ this._aiScheduleCheckPending = true;
116989
+ void this._runExecutionLoop();
116990
+ } else if (waitsForAssignedStartPhase) {
115719
116991
  this._armExecutionLoopTimer({ alignToNextRun: true, reason: "assigned_start_phase" });
115720
116992
  } else {
115721
116993
  this._armExecutionLoopTimer({ alignToNextRun: true });
@@ -116371,10 +117643,13 @@ var init_engine = __esm({
116371
117643
  }
116372
117644
  await this.relinquishControl(reason);
116373
117645
  }
116374
- async triggerNow() {
117646
+ async triggerNow(options) {
116375
117647
  if (this._state !== "running") {
116376
117648
  throw new Error("AI runtime is not running on this client.");
116377
117649
  }
117650
+ if ((options?.ignoreAiSchedule ?? true) && (!this._executionLoopPromise || this._aiSchedulePaused || this._checkOnlyCycleInFlight)) {
117651
+ this._manualRunRequested = true;
117652
+ }
116378
117653
  await this._runExecutionLoop();
116379
117654
  }
116380
117655
  _abortTrailingMaintenanceBeforeDispatch() {
@@ -116485,6 +117760,19 @@ var init_engine = __esm({
116485
117760
  this._pendingProtectionRecoveryDispatched = true;
116486
117761
  }
116487
117762
  });
117763
+ const retired = results.flatMap(({ retired: symbolRetired }) => symbolRetired ?? []);
117764
+ const stale = results.flatMap(({ symbol: symbol2, reports }) => reports.filter((report) => report.execution_metadata?.reason_code === "pending_protective_entry_stale").map(() => symbol2));
117765
+ if (retired.length > 0 || stale.length > 0) {
117766
+ const retiredByReason = retired.reduce((counts, { reasonCode }) => ({
117767
+ ...counts,
117768
+ [reasonCode]: (counts[reasonCode] ?? 0) + 1
117769
+ }), {});
117770
+ this.reportLifecycleTelemetry(
117771
+ "client_pending_protection_recovery",
117772
+ `retired=${retired.length} stale=${stale.length}`,
117773
+ { profileId, payload: { retired_by_reason: retiredByReason, stale_symbols: stale } }
117774
+ );
117775
+ }
116488
117776
  if (results.length) {
116489
117777
  appendRuntimeDebugEvent({
116490
117778
  label: "pending_protection_recovery",
@@ -116747,10 +118035,22 @@ var init_engine = __esm({
116747
118035
  const analysisAbortController = new AbortController();
116748
118036
  this._analysisAbortController = analysisAbortController;
116749
118037
  let decisionSubmitted = false;
118038
+ let cycleModelCalls = [];
118039
+ let cycleModelCallsReported = false;
116750
118040
  let executedExchangeOrderInCycle = false;
116751
118041
  let pendingExternalInferenceBindings = [];
116752
118042
  let agentPollDelayMs = null;
118043
+ let aiSchedulePauseMs = null;
118044
+ let aiSchedulePauseHasNext = false;
118045
+ let providerRetryDelayMs = null;
118046
+ const ignoreAiSchedule = this._manualRunRequested;
118047
+ this._manualRunRequested = false;
118048
+ const pausedBeforeSlot = this._aiSchedulePaused && this._nextRunAtMs != null && Date.now() < this._nextRunAtMs;
118049
+ const aiScheduleCheckOnly = (this._aiScheduleCheckPending || pausedBeforeSlot) && !ignoreAiSchedule;
118050
+ this._aiScheduleCheckPending = false;
118051
+ this._checkOnlyCycleInFlight = aiScheduleCheckOnly;
116753
118052
  const agentPollContinuation = this._agentInstructionPollActive;
118053
+ const aiSchedulePauseContinuation = this._aiSchedulePaused || aiScheduleCheckOnly;
116754
118054
  let cycleStartEmitted = false;
116755
118055
  let cycleErrorProvenance = null;
116756
118056
  let cycleWorkStarted = false;
@@ -116825,15 +118125,35 @@ var init_engine = __esm({
116825
118125
  this._notifyListeners();
116826
118126
  void this.sendHeartbeat();
116827
118127
  };
116828
- if (!agentPollContinuation) emitCycleStarted();
118128
+ if (!agentPollContinuation && !aiSchedulePauseContinuation) emitCycleStarted();
116829
118129
  try {
116830
- const savedSecrets = await ClientVault.getSecrets(profileId);
118130
+ let savedSecrets = await ClientVault.getSecrets(profileId);
118131
+ let serverSigningKey = null;
118132
+ if (this._expectedExecutionMode === "server") {
118133
+ try {
118134
+ const fresh = await ClientVault.hydrateFromServer(profileId, {
118135
+ includeAllProviderKeys: true,
118136
+ requireProviderSecret: false
118137
+ });
118138
+ if (fresh) {
118139
+ savedSecrets = fresh;
118140
+ serverSigningKey = String(fresh.hyperliquidSigningKey ?? "").trim() || null;
118141
+ }
118142
+ } catch (error48) {
118143
+ appendRuntimeDebugEvent({
118144
+ label: "server_secrets_refresh_failed",
118145
+ note: getSanitizedRuntimeErrorMessage(error48) || "unknown",
118146
+ outcome: "error"
118147
+ });
118148
+ }
118149
+ }
116831
118150
  if (analysisAbortController.signal.aborted || this._isStopping || this._analysisRequestId !== requestId) {
116832
118151
  throw new DOMException("The operation was aborted.", "AbortError");
116833
118152
  }
116834
118153
  if (savedSecrets) {
116835
118154
  deviceSecrets = {
116836
118155
  ...deviceSecrets,
118156
+ ...serverSigningKey ? { hyperliquidSigningKey: serverSigningKey } : {},
116837
118157
  providerKeys: savedSecrets.providerKeys ?? {},
116838
118158
  providerKeySlots: savedSecrets.providerKeySlots,
116839
118159
  providerBaseUrls: savedSecrets.providerBaseUrls,
@@ -116880,6 +118200,18 @@ var init_engine = __esm({
116880
118200
  }
116881
118201
  },
116882
118202
  onCycleObservation: observeCycle,
118203
+ onAiScheduleWindowActive: (windowEndsAtMs) => {
118204
+ this._aiSchedulePaused = false;
118205
+ this._aiScheduleWindowActive = true;
118206
+ this._aiScheduleWindowEndsAtMs = windowEndsAtMs;
118207
+ },
118208
+ onAiScheduleOff: () => {
118209
+ this._aiSchedulePaused = false;
118210
+ this._aiScheduleWindowEndsAtMs = null;
118211
+ },
118212
+ ignoreAiSchedule,
118213
+ aiScheduleCheckOnly,
118214
+ executionMode: this._expectedExecutionMode,
116883
118215
  onPreparedExecutionContexts: async ({ config: config2, executionContexts }) => {
116884
118216
  if (runtimeMode !== "trader") return;
116885
118217
  const cancelled = () => this._state !== "running" || this._isStopping || this._windowHandoffRequested || this._killswitchLatched || this._profileId !== profileId || this._sessionId !== sessionId || this._deviceId !== deviceId || (getRuntimeContractBindingTupleToken(this._activeRuntimeContractIdentity) ?? getRuntimeStatusContractBindingTupleToken(this._runtimeStatus)) !== loopContractBindingToken;
@@ -116908,10 +118240,74 @@ var init_engine = __esm({
116908
118240
  },
116909
118241
  signal: analysisAbortController.signal
116910
118242
  });
118243
+ const runCycleWithDispatchFreshness = (secrets) => this._expectedExecutionMode !== "server" ? runCycle(secrets) : runCycle(secrets).catch((error48) => {
118244
+ if (!localAnalysis.isServerDispatchAccountStateStale(error48) || analysisAbortController.signal.aborted || this._isStopping || this._analysisRequestId !== requestId) {
118245
+ throw error48;
118246
+ }
118247
+ appendRuntimeDebugEvent({ label: "server_dispatch_context_rebuilt", note: "attempt=2", outcome: "ok" });
118248
+ return runCycle(secrets);
118249
+ });
116911
118250
  let result;
116912
118251
  try {
116913
- result = await runCycle(deviceSecrets);
118252
+ result = await runCycleWithDispatchFreshness(deviceSecrets);
116914
118253
  } catch (error48) {
118254
+ if (localAnalysis.isClientRuntimeAiScheduleStillActive(error48)) {
118255
+ cycleOutcome = "skipped";
118256
+ cycleReason = "ai_schedule_check";
118257
+ this._lastRunAt = previousLastRunAt;
118258
+ this._nextRunAtMs = previousNextRunAtMs;
118259
+ this._lastError = null;
118260
+ this._notifyListeners();
118261
+ return;
118262
+ }
118263
+ if (localAnalysis.isClientRuntimeAiSchedulePaused(error48)) {
118264
+ cycleOutcome = "skipped";
118265
+ cycleReason = "ai_schedule_paused";
118266
+ this._lastRunAt = previousLastRunAt;
118267
+ this._lastError = null;
118268
+ const windowEnded = this._aiScheduleWindowActive;
118269
+ this._aiScheduleWindowActive = false;
118270
+ this._aiScheduleWindowEndsAtMs = null;
118271
+ this._aiSchedulePaused = true;
118272
+ const nowMs2 = Date.now();
118273
+ const windowOpensAtMs = error48.nextChangeAtMs != null ? this._periodicNextSlot(error48.nextChangeAtMs, true) ?? error48.nextChangeAtMs : null;
118274
+ aiSchedulePauseHasNext = windowOpensAtMs != null;
118275
+ aiSchedulePauseMs = windowOpensAtMs != null ? Math.max(1e3, Math.min(windowOpensAtMs - nowMs2, 36e5)) : 6e4;
118276
+ if (runtimeMode === "trader" && this._loopIntervalMs != null) {
118277
+ aiSchedulePauseMs = Math.min(aiSchedulePauseMs, Math.max(1e3, this._loopIntervalMs));
118278
+ }
118279
+ this._nextRunAtMs = windowOpensAtMs;
118280
+ if (!aiSchedulePauseContinuation) {
118281
+ this._emitLoopBoundaryTelemetry("client_ai_schedule_paused", `request_id=${requestId}`, {
118282
+ request_id: requestId,
118283
+ status: error48.message,
118284
+ next_change_ms: error48.nextChangeAtMs
118285
+ });
118286
+ }
118287
+ const cancelled = () => this._state !== "running" || this._isStopping || this._windowHandoffRequested || this._killswitchLatched || analysisAbortController.signal.aborted || this._profileId !== profileId || this._sessionId !== sessionId || this._deviceId !== deviceId;
118288
+ if (windowEnded && runtimeMode === "trader" && error48.closeOnStop) {
118289
+ await this._closePositionsAtScheduleEnd(profileId, error48, cancelled);
118290
+ }
118291
+ if (runtimeMode === "trader" && !cancelled()) {
118292
+ try {
118293
+ await this._processClientCopyTrading({
118294
+ profileId,
118295
+ runtimeSessionId: sessionId,
118296
+ runtimeDeviceId: deviceId,
118297
+ config: await this.getExecutionConfig(profileId),
118298
+ signal: analysisAbortController.signal
118299
+ });
118300
+ } catch (copyTradingError) {
118301
+ appendRuntimeDebugEvent({
118302
+ label: "ai_schedule_paused_copy_poll_failed",
118303
+ note: getSanitizedRuntimeErrorMessage(copyTradingError) || "Copy Trading poll failed.",
118304
+ outcome: "error"
118305
+ });
118306
+ }
118307
+ }
118308
+ this._notifyListeners();
118309
+ return;
118310
+ }
116915
118311
  if (localAnalysis.isClientRuntimeAgentInstructionEmpty(error48)) {
116916
118312
  cycleOutcome = "skipped";
116917
118313
  cycleReason = "agent_instruction_poll_empty";
@@ -116949,7 +118345,7 @@ var init_engine = __esm({
116949
118345
  throw error48;
116950
118346
  }
116951
118347
  try {
116952
- result = await runCycle(refresh.secrets);
118348
+ result = await runCycleWithDispatchFreshness(refresh.secrets);
116953
118349
  } catch (retryError) {
116954
118350
  const retryProviderSetup = getRuntimeProviderSetupDiagnostics(retryError);
116955
118351
  if (retryProviderSetup) {
@@ -116985,6 +118381,7 @@ var init_engine = __esm({
116985
118381
  }
116986
118382
  markCycleWorkStarted();
116987
118383
  decisionSnapshotId = result.decisionSnapshotId;
118384
+ cycleModelCalls = Array.isArray(result.invocations) ? result.invocations : [];
116988
118385
  if (result.runtimeError) cycleFailureStage = cycleObservation.stage;
116989
118386
  observeCycle({ stage: "decision" });
116990
118387
  cycleErrorProvenance = {
@@ -117141,7 +118538,10 @@ var init_engine = __esm({
117141
118538
  promptTokens: result.prompt_tokens,
117142
118539
  completionTokens: result.completion_tokens,
117143
118540
  totalTokens: result.total_tokens,
117144
- settingsSnapshot: result.settingsSnapshot,
118541
+ // A Server bot's row records what started its cycle, as the
118542
+ // Python Server loop's does (a Client row never has, and the key
118543
+ // is part of a row's Insights settings epoch).
118544
+ settingsSnapshot: this._expectedExecutionMode === "server" ? { ...result.settingsSnapshot, analysis_trigger_origin: ignoreAiSchedule ? "manual" : "scheduled" } : result.settingsSnapshot,
117145
118545
  clientExchangeSnapshot: result.clientExchangeSnapshot ?? null,
117146
118546
  invocations: result.invocations,
117147
118547
  externalInferenceBindings: result.externalInferenceBindings ?? [],
@@ -117154,6 +118554,7 @@ var init_engine = __esm({
117154
118554
  reconciliationTimeoutMs: result.decisionReconciliationTimeoutMs
117155
118555
  });
117156
118556
  decisionSubmitted = true;
118557
+ cycleModelCallsReported = true;
117157
118558
  } catch (decisionError) {
117158
118559
  if (isRuntimeContractMismatchError(decisionError)) {
117159
118560
  await this._discardCycleOnContractMismatch("decision", decisionError);
@@ -117226,11 +118627,28 @@ var init_engine = __esm({
117226
118627
  }
117227
118628
  const executionResults = [];
117228
118629
  const executionFailures = [];
117229
- for (let planIndex = 0; planIndex < executionPlans.length; planIndex += 1) {
117230
- if (planIndex > 0 && this._windowHandoffRequested) {
117231
- break;
117232
- }
117233
- const plan = executionPlans[planIndex];
118630
+ const executionLeaseToken = () => {
118631
+ const lease = getPersistedClientRuntimeServerLease(profileId);
118632
+ return lease?.runtimeSessionId === sessionId && lease.deviceId === deviceId && lease.mode === "trader" ? lease.runtimeLeaseToken : null;
118633
+ };
118634
+ const serverCapacityByPlan = /* @__PURE__ */ new Map();
118635
+ if (this._expectedExecutionMode === "server") {
118636
+ const capacityPlans = executionPlans.map((plan, planIndex) => ({ plan, planIndex, decision: String(plan.decision || "").toUpperCase() })).filter(({ plan, decision }) => !plan.executionBlock && (decision === "BUY" || decision === "SELL") && Math.trunc(Number(plan.units)) > 0);
118637
+ const allocations = capacityPlans.length === 0 ? [] : await allocateServerExecutionCapacity({
118638
+ profileId,
118639
+ sessionId,
118640
+ runtimeLeaseToken: executionLeaseToken(),
118641
+ runtimeDeviceId: deviceId,
118642
+ schedulerInstanceId: this._instanceId,
118643
+ signal: analysisAbortController.signal
118644
+ }, capacityPlans.map(({ plan, decision }) => ({
118645
+ symbol: plan.executionContext.symbol,
118646
+ decision,
118647
+ units: Math.trunc(Number(plan.units))
118648
+ })));
118649
+ capacityPlans.forEach(({ planIndex }, index) => serverCapacityByPlan.set(planIndex, allocations[index]));
118650
+ }
118651
+ const runPlan = async (plan, planIndex) => {
117234
118652
  let planEntryOrderDispatched = false;
117235
118653
  const decisionWallet = String(
117236
118654
  plan.executionContext.walletAddress || ""
@@ -117252,7 +118670,7 @@ var init_engine = __esm({
117252
118670
  actionablePlan ? "decision execution" : trailingHoldCanMutate ? "trailing stop maintenance" : "protective order reconciliation"
117253
118671
  );
117254
118672
  if (shouldAbortForContractInvalidation("post_execution_preferences_refresh")) {
117255
- return;
118673
+ return { control: "return" };
117256
118674
  }
117257
118675
  }
117258
118676
  appendRuntimeDebugEvent({
@@ -117304,17 +118722,16 @@ var init_engine = __esm({
117304
118722
  executionResult = await executeClientRuntimeDecision({
117305
118723
  profileId,
117306
118724
  sessionId,
117307
- runtimeLeaseToken: (() => {
117308
- const lease = getPersistedClientRuntimeServerLease(profileId);
117309
- return lease?.runtimeSessionId === sessionId && lease.deviceId === deviceId && lease.mode === "trader" ? lease.runtimeLeaseToken : null;
117310
- })(),
118725
+ runtimeLeaseToken: executionLeaseToken(),
117311
118726
  runtimeDeviceId: deviceId,
117312
118727
  schedulerInstanceId: this._instanceId,
117313
118728
  cycleId: result.cycleId,
118729
+ serverCapacityAllocation: serverCapacityByPlan.get(planIndex),
117314
118730
  signingKey: this._deviceSecrets?.hyperliquidSigningKey ?? null,
117315
118731
  config: config2,
117316
118732
  decision: plan.decision,
117317
118733
  units: plan.units,
118734
+ executionMode: this._expectedExecutionMode,
117318
118735
  executionContext: plan.executionContext,
117319
118736
  skipTrailingMaintenance: this._trailingObservations.some((request) => request.executionContext.decisionSnapshotId === plan.executionContext.decisionSnapshotId),
117320
118737
  signal: analysisAbortController.signal,
@@ -117333,7 +118750,8 @@ var init_engine = __esm({
117333
118750
  if (isClientRuntimeWindowHandoffBeforePlanDispatch(executionError)) {
117334
118751
  const handoffCleanup = getClientRuntimeWindowHandoffCleanup(executionError);
117335
118752
  if (handoffCleanup) {
117336
- executionResults.push({
118753
+ this._executionFinalizationRequired = true;
118754
+ return { control: "break", result: {
117337
118755
  status: "skipped",
117338
118756
  intent: "hold",
117339
118757
  side: null,
@@ -117346,10 +118764,9 @@ var init_engine = __esm({
117346
118764
  handoffCleanup,
117347
118765
  executionSnapshotId: `handoff-cleanup-${planIndex + 1}-${Date.now()}`,
117348
118766
  executionSnapshotCapturedAt: (/* @__PURE__ */ new Date()).toISOString()
117349
- });
117350
- this._executionFinalizationRequired = true;
118767
+ } };
117351
118768
  }
117352
- break;
118769
+ return { control: "break" };
117353
118770
  }
117354
118771
  if (analysisAbortController.signal.aborted || isRuntimeAbortError(executionError) || isRuntimeContractMismatchError(executionError) || isClientExecutionModeMismatchError(executionError) || isClientRuntimeSessionStoppedError(executionError) || isClientRuntimeLeaseAuthError(executionError) || isTransientRuntimeConflictError(executionError)) {
117355
118772
  throw executionError;
@@ -117408,6 +118825,9 @@ var init_engine = __esm({
117408
118825
  };
117409
118826
  }
117410
118827
  }
118828
+ return { control: "continue", result: executionResult };
118829
+ };
118830
+ const recordPlanResult = (executionResult) => {
117411
118831
  executionResults.push(executionResult);
117412
118832
  if (executionResult.handoffCleanup) {
117413
118833
  this._executionFinalizationRequired = true;
@@ -117416,11 +118836,26 @@ var init_engine = __esm({
117416
118836
  executedExchangeOrderInCycle = true;
117417
118837
  this._executionFinalizationRequired = true;
117418
118838
  }
117419
- if (!this._executionFinalizationRequired && (analysisAbortController.signal.aborted || this._isStopping || this._analysisRequestId !== requestId)) {
118839
+ };
118840
+ const cycleSupersededWithoutExecution = () => !this._executionFinalizationRequired && (analysisAbortController.signal.aborted || this._isStopping || this._analysisRequestId !== requestId);
118841
+ for (let planIndex = 0; planIndex < executionPlans.length; planIndex += 1) {
118842
+ if (planIndex > 0 && this._windowHandoffRequested) {
118843
+ break;
118844
+ }
118845
+ const outcome = await runPlan(executionPlans[planIndex], planIndex);
118846
+ if (outcome.control === "return") {
118847
+ return;
118848
+ }
118849
+ if (outcome.control === "break") {
118850
+ if (outcome.result) executionResults.push(outcome.result);
118851
+ break;
118852
+ }
118853
+ recordPlanResult(outcome.result);
118854
+ if (cycleSupersededWithoutExecution()) {
117420
118855
  return;
117421
118856
  }
117422
118857
  }
117423
- const executionReports = executionResults.flatMap((executionResult) => Array.isArray(executionResult.executionReports) ? executionResult.executionReports : []);
118858
+ const executionReports = executionResults.flatMap((executionResult) => Array.isArray(executionResult.executionReports) ? this._expectedExecutionMode === "server" ? withServerPositionEvents(executionResult) : executionResult.executionReports : []);
117424
118859
  const executedOrderReports = executionReports.filter((report) => report.status === "executed" && String(report.order_id || "").trim().length > 0);
117425
118860
  const handoffCleanups = executionResults.flatMap((executionResult) => executionResult.handoffCleanup ? [executionResult.handoffCleanup] : []);
117426
118861
  if (this._windowHandoffRequested && executedOrderReports.length === 0) {
@@ -117606,6 +119041,8 @@ var init_engine = __esm({
117606
119041
  this._notifyListeners();
117607
119042
  }
117608
119043
  } catch (error48) {
119044
+ const errorModelCalls = error48?.runtimeInvocationAttempts;
119045
+ if (Array.isArray(errorModelCalls) && errorModelCalls.length > 0) cycleModelCalls = errorModelCalls;
117609
119046
  const cycleElapsedSeconds = Math.max(0, (performance.now() - runStartedMonotonicMs) / 1e3);
117610
119047
  cycleOutcome = "failed";
117611
119048
  cycleReason = cycleObservation.reason_code ?? "runtime_failed";
@@ -117711,12 +119148,19 @@ var init_engine = __esm({
117711
119148
  model: cycleErrorProvenance?.model ?? null,
117712
119149
  modelSource: cycleErrorProvenance?.modelSource ?? null
117713
119150
  });
119151
+ if (reportedRuntime !== null && Array.isArray(errorModelCalls) && errorModelCalls.length > 0) {
119152
+ cycleModelCallsReported = true;
119153
+ }
117714
119154
  if (reportedRuntime?.runtime_recovery_blocked_source === "terminal_failure") {
117715
119155
  this._scheduleRecoverableSuspendAfterExecutionLoop({
117716
119156
  reason: "runtime_terminal_failure"
117717
119157
  });
117718
119158
  return;
117719
119159
  }
119160
+ if (hasEventBoundProviderFailureEvidence(error48) && this._expectedExecutionMode === "server") {
119161
+ const backoffSeconds = Number((await this.getExecutionConfig(profileId).catch(() => null))?.provider_failure_backoff_seconds);
119162
+ if (Number.isFinite(backoffSeconds) && backoffSeconds > 0) providerRetryDelayMs = backoffSeconds * 1e3;
119163
+ }
117720
119164
  if (hasEventBoundProviderFailureEvidence(error48)) {
117721
119165
  this.scheduleProviderFailureDiagnosticsTelemetry({
117722
119166
  profileId,
@@ -117730,6 +119174,18 @@ var init_engine = __esm({
117730
119174
  });
117731
119175
  }
117732
119176
  } finally {
119177
+ this._checkOnlyCycleInFlight = false;
119178
+ if (!cycleModelCallsReported && cycleModelCalls.length > 0 && this._settleUnreportedModelCalls) {
119179
+ try {
119180
+ await this._settleUnreportedModelCalls(cycleModelCalls);
119181
+ } catch (error48) {
119182
+ appendRuntimeDebugEvent({
119183
+ label: "unreported_model_calls_settle_failed",
119184
+ note: getSanitizedRuntimeErrorMessage(error48) || "unknown",
119185
+ outcome: "error"
119186
+ });
119187
+ }
119188
+ }
117733
119189
  if (!decisionSubmitted && pendingExternalInferenceBindings.length > 0) {
117734
119190
  await Promise.allSettled(
117735
119191
  pendingExternalInferenceBindings.map((binding) => cancelClientRuntimeInferenceJob(profileId, binding.job_id, {
@@ -117756,8 +119212,9 @@ var init_engine = __esm({
117756
119212
  if (this._analysisRequestId === requestId) {
117757
119213
  this._analysisRequestId = null;
117758
119214
  this._analysisStartedAtMs = null;
119215
+ if (this._expectedExecutionMode === "server" && this._state === "running") void this.sendHeartbeat();
117759
119216
  }
117760
- const silentEmptyAgentPoll = cycleOutcome === "skipped" && cycleReason === "agent_instruction_poll_empty" && !cycleStartEmitted;
119217
+ const silentEmptyAgentPoll = cycleOutcome === "skipped" && (cycleReason === "agent_instruction_poll_empty" || cycleReason === "ai_schedule_paused" || cycleReason === "ai_schedule_check") && !cycleStartEmitted;
117761
119218
  if (this._state === "running" && this._sessionId === sessionId) {
117762
119219
  this._agentInstructionPollActive = agentPollDelayMs !== null;
117763
119220
  }
@@ -117775,7 +119232,7 @@ var init_engine = __esm({
117775
119232
  });
117776
119233
  }
117777
119234
  this._notifyListeners();
117778
- if (this._periodicSchedule && agentPollDelayMs === null && !this._primaryAnalysisDisabled) {
119235
+ if (this._periodicSchedule && agentPollDelayMs === null && aiSchedulePauseMs === null && !this._primaryAnalysisDisabled) {
117779
119236
  this._advanceNextRunAnchor();
117780
119237
  }
117781
119238
  if (!silentEmptyAgentPoll) this._emitLoopBoundaryTelemetry("client_timer_rearmed", "reason=cycle_finally", {
@@ -117784,11 +119241,18 @@ var init_engine = __esm({
117784
119241
  primary_analysis_disabled: this._primaryAnalysisDisabled,
117785
119242
  agent_poll_retry_ms: agentPollDelayMs
117786
119243
  });
119244
+ const providerRetryWake = providerRetryDelayMs !== null && aiSchedulePauseMs === null && agentPollDelayMs === null && (this._nextRunAtMs == null || this._nextRunAtMs > Date.now() + providerRetryDelayMs) ? providerRetryDelayMs : null;
119245
+ if (providerRetryWake !== null) this._nextRunAtMs = Date.now() + providerRetryWake;
119246
+ const windowEndsAtMs = this._aiScheduleWindowEndsAtMs;
119247
+ const nextWorkAtMs = this._primaryAnalysisDisabled && this._loopIntervalMs != null ? Date.now() + this._loopIntervalMs : this._nextRunAtMs;
119248
+ const windowEndWake = aiSchedulePauseMs === null && agentPollDelayMs === null && providerRetryWake === null && windowEndsAtMs != null && windowEndsAtMs > Date.now() && (nextWorkAtMs == null || windowEndsAtMs < nextWorkAtMs) ? windowEndsAtMs - Date.now() : null;
119249
+ this._aiScheduleCheckPending = windowEndWake !== null;
119250
+ const manualRunWake = this._manualRunRequested ? 0 : null;
117787
119251
  this._armExecutionLoopTimer({
117788
119252
  alignToNextRun: agentPollDelayMs === null,
117789
- delayOverrideMs: agentPollDelayMs,
117790
- reason: agentPollDelayMs !== null ? "agent_instruction_poll" : this._primaryAnalysisDisabled ? "main_model_disabled_copy_poll" : "cycle_finally",
117791
- suppressNextRunProjection: agentPollDelayMs === null && this._primaryAnalysisDisabled
119253
+ delayOverrideMs: manualRunWake ?? aiSchedulePauseMs ?? agentPollDelayMs ?? providerRetryWake ?? windowEndWake,
119254
+ reason: manualRunWake !== null ? "manual_run_requested" : aiSchedulePauseMs !== null ? "ai_schedule_paused" : agentPollDelayMs !== null ? "agent_instruction_poll" : providerRetryWake !== null ? "provider_failure_retry" : windowEndWake !== null ? "ai_schedule_window_end" : this._primaryAnalysisDisabled ? "main_model_disabled_copy_poll" : "cycle_finally",
119255
+ suppressNextRunProjection: aiSchedulePauseMs !== null && !aiSchedulePauseHasNext || agentPollDelayMs === null && aiSchedulePauseMs === null && this._primaryAnalysisDisabled
117792
119256
  });
117793
119257
  }
117794
119258
  if (cycleOutcome === "unknown" && (analysisAbortController.signal.aborted || this._isStopping || this._state === "stopped")) {
@@ -118188,6 +119652,7 @@ var init_engine = __esm({
118188
119652
  const heartbeatAnalysisRunId = this._primaryAnalysisDisabled || !this._isAnalysisInFlight() ? null : this._analysisRequestId;
118189
119653
  const heartbeatIsAnalyzing = !this._primaryAnalysisDisabled && (this._isAnalysisInFlight() || this._startupPendingAnalysis && options?.confirmGrant !== true || this._isExecuting);
118190
119654
  const heartbeatIsExecuting = this._isExecuting;
119655
+ const heartbeatObservedAtMs = Date.now();
118191
119656
  const priorHeartbeatFailures = this._heartbeatFailures;
118192
119657
  try {
118193
119658
  const response = await sendClientRuntimeHeartbeat(heartbeatProfileId, {
@@ -118202,7 +119667,10 @@ var init_engine = __esm({
118202
119667
  schedulerPhase: heartbeatSchedulerPhase,
118203
119668
  analysisRunId: heartbeatAnalysisRunId,
118204
119669
  isAnalyzing: heartbeatIsAnalyzing,
118205
- isExecuting: heartbeatIsExecuting
119670
+ isExecuting: heartbeatIsExecuting,
119671
+ // Beats may arrive out of order: the server keeps a node bot's newest
119672
+ // analyzing observation, so a cycle's end is never undone by its start.
119673
+ ...this._expectedExecutionMode === "server" ? { analyzingObservedAtMs: heartbeatObservedAtMs } : {}
118206
119674
  });
118207
119675
  if (Number(response.protective_actions_pending ?? 0) > 0) {
118208
119676
  notifyClientProtectiveActionsPending(heartbeatProfileId);
@@ -118386,8 +119854,18 @@ var init_engine = __esm({
118386
119854
  );
118387
119855
  this._killswitchAbortController = null;
118388
119856
  }
119857
+ /**
119858
+ * A Server Mode bot (the Node runtime host, executionMode 'server') has one
119859
+ * killswitch, the Python worker's risk monitor: it reads the bot's account,
119860
+ * stops the bot through its runtime contract and closes its positions even
119861
+ * while this process is down, so the runtime evaluates none here and reads
119862
+ * no account for it.
119863
+ */
119864
+ _ownsKillswitch() {
119865
+ return this._expectedExecutionMode !== "server";
119866
+ }
118389
119867
  async _startClientKillswitchMonitor(startController) {
118390
- if (this._mode !== "trader" || !this._profileId) {
119868
+ if (this._mode !== "trader" || !this._profileId || !this._ownsKillswitch()) {
118391
119869
  return;
118392
119870
  }
118393
119871
  const configPromise = this.getExecutionConfig(this._profileId);
@@ -118414,7 +119892,7 @@ var init_engine = __esm({
118414
119892
  );
118415
119893
  }
118416
119894
  async _runClientKillswitchCheck() {
118417
- if (this._state !== "running" || this._mode !== "trader" || this._killswitchLatched || this._killswitchCheckInFlight || !this._profileId || !this._sessionId || !this._deviceId) {
119895
+ if (!this._ownsKillswitch() || this._state !== "running" || this._mode !== "trader" || this._killswitchLatched || this._killswitchCheckInFlight || !this._profileId || !this._sessionId || !this._deviceId) {
118418
119896
  return;
118419
119897
  }
118420
119898
  const profileId = this._profileId;
@@ -118730,6 +120208,9 @@ var init_engine = __esm({
118730
120208
  return config2;
118731
120209
  }
118732
120210
  async _processClientCopyTrading(input) {
120211
+ if (this._expectedExecutionMode === "server") {
120212
+ return;
120213
+ }
118733
120214
  try {
118734
120215
  const persistedLease = getPersistedClientRuntimeServerLease(input.profileId);
118735
120216
  const runtimeLeaseToken = persistedLease?.runtimeSessionId === input.runtimeSessionId && persistedLease.deviceId === input.runtimeDeviceId && persistedLease.mode === "trader" ? persistedLease.runtimeLeaseToken : null;
@@ -119200,8 +120681,8 @@ var init_engine = __esm({
119200
120681
  if (!normalized) return false;
119201
120682
  return this._getEngine(normalized, false)?.updateLoopInterval(options) ?? false;
119202
120683
  }
119203
- async triggerNow() {
119204
- await this._getSelectedEngine()?.triggerNow();
120684
+ async triggerNow(options) {
120685
+ await this._getSelectedEngine()?.triggerNow(options);
119205
120686
  }
119206
120687
  async triggerProfileNow(profileId) {
119207
120688
  const normalized = this._normalizeProfileId(profileId);
@@ -119620,7 +121101,7 @@ async function runHeadlessRuntime(options) {
119620
121101
  const firstAttached = () => {
119621
121102
  const stopSweep = startServerProtectionSweeper(options, { ...identity2, schedulerInstanceId: engine.schedulerInstanceId });
119622
121103
  if (options.once && engine.state === "running" && !engine.snapshot.isAnalyzing) {
119623
- void engine.triggerNow().catch(() => void 0);
121104
+ void engine.triggerNow({ ignoreAiSchedule: false }).catch(() => void 0);
119624
121105
  }
119625
121106
  return stopSweep;
119626
121107
  };