@vtxmacro/cli 2026.8.11 → 2026.8.13

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.
Files changed (3) hide show
  1. package/README.md +42 -3
  2. package/bin/vtx.js +667 -100
  3. package/package.json +1 -1
package/bin/vtx.js CHANGED
@@ -38,7 +38,7 @@ var init_agent_cli_release = __esm({
38
38
  "agent-cli-release.json"() {
39
39
  agent_cli_release_default = {
40
40
  package_name: "@vtxmacro/cli",
41
- package_version: "2026.8.11",
41
+ package_version: "2026.8.13",
42
42
  codex_package_name: "@openai/codex",
43
43
  codex_version: "0.147.0",
44
44
  platforms: {
@@ -14375,7 +14375,7 @@ var init_zod = __esm({
14375
14375
  });
14376
14376
 
14377
14377
  // lib/external-inference-contract.ts
14378
- var EXTERNAL_INFERENCE_CONTRACT_VERSION, EXTERNAL_INFERENCE_CONTROLLER_SCHEMA_VERSION, EXTERNAL_INFERENCE_ADVERTISEMENT_SCHEMA_VERSION, EXTERNAL_INFERENCE_ENVELOPE_SCHEMA_VERSION, EXTERNAL_INFERENCE_JOB_INPUT_SCHEMA_VERSION, EXTERNAL_INFERENCE_USAGE_SCHEMA_VERSION, EXTERNAL_INFERENCE_INPUT_HASH_DOMAIN, MAX_EXTERNAL_INFERENCE_STATUS_HOSTS, MAX_GENERATION, MAX_SAFE_INTEGER, MAX_PROMPT_BYTES, MAX_IMMUTABLE_JOB_INPUT_BYTES, MAX_CANDIDATE_PLAINTEXT_BYTES, MAX_CIPHERTEXT_CHARS, SHA256_INITIAL_STATE, SHA256_ROUND_CONSTANTS, rotateRight, sha256BytesHex, sha256Utf8Hex, computeImmutableJobInputSha256, identifierSchema, operationIdentifierSchema, sha256HexSchema, generationSchema, zeroBasedGenerationSchema, nonNegativeSafeIntegerSchema, positiveSafeIntegerSchema, sqlIntegerTokenCountSchema, timestampSchema, safeCodeSchema, externalInferenceAdapterIdSchema, reasoningEffortSchema, modelNameSchema, displayNameSchema, protocolVersionSchema, base64UrlAlphabet, isCanonicalBase64Url, base64Url32BytesSchema, base64UrlNonceSchema, base64UrlCiphertextSchema, claimHandleSchema, boundedJsonTextSchema, boundedPromptTextSchema, laneSchema, botModeSchema, executionModeSchema, responseModeSchema, dispatchOutcomeSchema, responseOutcomeSchema, nativeModelControllerSchema, externalAgentModelControllerSchema, externalAgentUnboundControllerSchema, liveModelControllerSchema, snapshotModelControllerSchema, modelIdentityMappingSchema, advertisedModelSchema, hostAdvertisementSchema, envelopeAadSchema, validateEnvelopeAad, commonEnvelopeShape, sealedKeyWrapEnvelopeSchema, sealedInputEnvelopeSchema, sealedCandidateEnvelopeSchema, sealedEnvelopeSchema, screenerCandidateRuntimeBindingSchema, screenerClientLeaseBindingSchema, screenerRuntimeBindingSchema, serverRuntimeBindingSchema, clientRuntimeBindingSchema, runtimeBindingSchema, immutableJobInputSchema, canonicalizeJsonValue, serializeImmutableJobInput, reportedTokenUsageSchema, unavailableTokenUsageSchema, tokenUsageSchema, agentConnectRequestSchema, agentNextRequestSchema, emptyAgentNextResultSchema, claimedAgentNextResultSchema, agentNextResultSchema, agentCompleteRequestSchema, agentFailRequestSchema, requestedModelSelectionSchema, completedModelProvenanceSchema, attemptModelProvenanceSchema, hostHeartbeatRequestSchema, jobClaimRequestSchema, emptyJobClaimSchema, claimedJobSchema, jobClaimResultSchema, attemptStartRequestSchema, jobHeartbeatRequestSchema, continueHeartbeatDirectiveSchema, cancelHeartbeatDirectiveSchema, jobHeartbeatResultSchema, adapterOutcomeEvidenceSchema, completionBaseShape, validateCompletion, providerResponseCompletionSchema, decisionCandidateCompletionSchema, jobCompleteRequestSchema, jobFailRequestSchema, jobCancelRequestSchema, jobCancellationReceiptSchema, jobDeliveryRequestSchema, deliveryBaseShape, validateDeliveryCandidate, providerResponseDeliverySchema, decisionCandidateDeliverySchema, jobDeliveryResultSchema, jobConsumptionRequestSchema, jobConsumptionReceiptSchema, jobStateSchema, jobStatusReadSchema, hostStatusReadSchema, controllerBindingStatusReadSchema, queueStatusReadSchema, outcomeStatusReadSchema, externalInferenceStatusReadSchema, nativeResearchEvidenceSourceSchema, externalAgentResearchEvidenceSourceSchema, researchEvidenceSourceSchema, reportedResearchTokenUsageSchema, unavailableResearchTokenUsageSchema, researchTokenUsageSchema, externalInferenceProductLineageBaseShape, traderExternalInferenceProductLineageSchema, decisionChatExternalInferenceProductLineageSchema, screenerExternalInferenceProductLineageSchema, externalInferenceProductLineageSchema, normalProductLinkageSchema, evidenceMaterializationMarkerSchema, deliveredExternalAgentSourceIdentitySchema, deliveredRequestEvidenceSchema, researchEvidenceBaseShape, researchEvidenceBaseSchema, validateExactUtf8, validateResearchEvidence, providerResponseResearchEvidenceSchema, decisionCandidateResearchEvidenceSchema, researchEvidenceSchema;
14378
+ var EXTERNAL_INFERENCE_CONTRACT_VERSION, EXTERNAL_INFERENCE_CONTROLLER_SCHEMA_VERSION, EXTERNAL_INFERENCE_ADVERTISEMENT_SCHEMA_VERSION, EXTERNAL_INFERENCE_ENVELOPE_SCHEMA_VERSION, EXTERNAL_INFERENCE_JOB_INPUT_SCHEMA_VERSION, EXTERNAL_INFERENCE_USAGE_SCHEMA_VERSION, EXTERNAL_INFERENCE_INPUT_HASH_DOMAIN, MAX_EXTERNAL_INFERENCE_STATUS_HOSTS, MAX_GENERATION, MAX_SAFE_INTEGER, MAX_PROMPT_BYTES, MAX_IMMUTABLE_JOB_INPUT_BYTES, MAX_CANDIDATE_PLAINTEXT_BYTES, MAX_CIPHERTEXT_CHARS, SHA256_INITIAL_STATE, SHA256_ROUND_CONSTANTS, rotateRight, sha256BytesHex, sha256Utf8Hex, computeImmutableJobInputSha256, identifierSchema, operationIdentifierSchema, sha256HexSchema, generationSchema, zeroBasedGenerationSchema, nonNegativeSafeIntegerSchema, positiveSafeIntegerSchema, sqlIntegerTokenCountSchema, timestampSchema, safeCodeSchema, externalInferenceAdapterIdSchema, reasoningEffortSchema, modelNameSchema, displayNameSchema, authenticatedAccountEmailSchema, protocolVersionSchema, base64UrlAlphabet, isCanonicalBase64Url, base64Url32BytesSchema, base64UrlNonceSchema, base64UrlCiphertextSchema, claimHandleSchema, boundedJsonTextSchema, boundedPromptTextSchema, laneSchema, botModeSchema, executionModeSchema, responseModeSchema, dispatchOutcomeSchema, responseOutcomeSchema, nativeModelControllerSchema, externalAgentModelControllerSchema, externalAgentUnboundControllerSchema, liveModelControllerSchema, snapshotModelControllerSchema, modelIdentityMappingSchema, advertisedModelSchema, hostAdvertisementSchema, envelopeAadSchema, validateEnvelopeAad, commonEnvelopeShape, sealedKeyWrapEnvelopeSchema, sealedInputEnvelopeSchema, sealedCandidateEnvelopeSchema, sealedEnvelopeSchema, screenerCandidateRuntimeBindingSchema, screenerClientLeaseBindingSchema, screenerRuntimeBindingSchema, serverRuntimeBindingSchema, clientRuntimeBindingSchema, runtimeBindingSchema, immutableJobInputSchema, canonicalizeJsonValue, serializeImmutableJobInput, reportedTokenUsageSchema, unavailableTokenUsageSchema, tokenUsageSchema, agentConnectRequestSchema, agentNextRequestSchema, agentHeartbeatRequestSchema, emptyAgentNextResultSchema, claimedAgentNextResultSchema, agentNextResultSchema, agentCompleteRequestSchema, agentFailRequestSchema, requestedModelSelectionSchema, completedModelProvenanceSchema, attemptModelProvenanceSchema, hostHeartbeatRequestSchema, jobClaimRequestSchema, emptyJobClaimSchema, claimedJobSchema, jobClaimResultSchema, attemptStartRequestSchema, jobHeartbeatRequestSchema, continueHeartbeatDirectiveSchema, cancelHeartbeatDirectiveSchema, jobHeartbeatResultSchema, adapterOutcomeEvidenceSchema, completionBaseShape, validateCompletion, providerResponseCompletionSchema, decisionCandidateCompletionSchema, jobCompleteRequestSchema, jobFailRequestSchema, jobCancelRequestSchema, jobCancellationReceiptSchema, jobDeliveryRequestSchema, deliveryBaseShape, validateDeliveryCandidate, providerResponseDeliverySchema, decisionCandidateDeliverySchema, jobDeliveryResultSchema, jobConsumptionRequestSchema, jobConsumptionReceiptSchema, jobStateSchema, jobStatusReadSchema, hostStatusReadSchema, controllerBindingStatusReadSchema, queueStatusReadSchema, outcomeStatusReadSchema, externalInferenceStatusReadSchema, nativeResearchEvidenceSourceSchema, externalAgentResearchEvidenceSourceSchema, researchEvidenceSourceSchema, reportedResearchTokenUsageSchema, unavailableResearchTokenUsageSchema, researchTokenUsageSchema, externalInferenceProductLineageBaseShape, traderExternalInferenceProductLineageSchema, decisionChatExternalInferenceProductLineageSchema, screenerExternalInferenceProductLineageSchema, externalInferenceProductLineageSchema, normalProductLinkageSchema, evidenceMaterializationMarkerSchema, deliveredExternalAgentSourceIdentitySchema, deliveredRequestEvidenceSchema, researchEvidenceBaseShape, researchEvidenceBaseSchema, validateExactUtf8, validateResearchEvidence, providerResponseResearchEvidenceSchema, decisionCandidateResearchEvidenceSchema, researchEvidenceSchema;
14379
14379
  var init_external_inference_contract = __esm({
14380
14380
  "lib/external-inference-contract.ts"() {
14381
14381
  "use strict";
@@ -14580,6 +14580,7 @@ var init_external_inference_contract = __esm({
14580
14580
  reasoningEffortSchema = external_exports.string().min(1).max(32).regex(/^[a-z][a-z0-9_-]{0,31}$/);
14581
14581
  modelNameSchema = external_exports.string().min(1).max(256);
14582
14582
  displayNameSchema = external_exports.string().min(1).max(128);
14583
+ authenticatedAccountEmailSchema = external_exports.string().max(320).email();
14583
14584
  protocolVersionSchema = external_exports.string().min(1).max(64);
14584
14585
  base64UrlAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
14585
14586
  isCanonicalBase64Url = (value, exactBytes) => {
@@ -14713,6 +14714,8 @@ var init_external_inference_contract = __esm({
14713
14714
  key_generation: generationSchema,
14714
14715
  adapter: externalInferenceAdapterIdSchema,
14715
14716
  display_name: displayNameSchema,
14717
+ authenticated_account_email: authenticatedAccountEmailSchema.nullable().optional(),
14718
+ authenticated_account_plan: safeCodeSchema.nullable().optional(),
14716
14719
  protocol_version: protocolVersionSchema,
14717
14720
  envelope_public_key: base64Url32BytesSchema,
14718
14721
  health: external_exports.enum(["healthy", "degraded", "draining"]),
@@ -15051,6 +15054,12 @@ var init_external_inference_contract = __esm({
15051
15054
  host_id: identifierSchema,
15052
15055
  requested_at: timestampSchema
15053
15056
  });
15057
+ agentHeartbeatRequestSchema = external_exports.strictObject({
15058
+ operation_id: operationIdentifierSchema,
15059
+ host_id: identifierSchema,
15060
+ attempt_id: identifierSchema.nullable().optional(),
15061
+ requested_at: timestampSchema
15062
+ });
15054
15063
  emptyAgentNextResultSchema = external_exports.strictObject({
15055
15064
  claim_state: external_exports.literal("empty"),
15056
15065
  retry_after_ms: nonNegativeSafeIntegerSchema
@@ -15570,6 +15579,8 @@ var init_external_inference_contract = __esm({
15570
15579
  hostStatusReadSchema = external_exports.strictObject({
15571
15580
  host_id: identifierSchema,
15572
15581
  display_name: displayNameSchema,
15582
+ authenticated_account_email: authenticatedAccountEmailSchema.nullable().optional(),
15583
+ authenticated_account_plan: safeCodeSchema.nullable().optional(),
15573
15584
  adapter: externalInferenceAdapterIdSchema,
15574
15585
  status: external_exports.enum(["online", "degraded", "offline", "draining", "revoked"]),
15575
15586
  host_generation: generationSchema,
@@ -16647,6 +16658,10 @@ var init_credential_store = __esm({
16647
16658
  }
16648
16659
  const result2 = await this.runner(command, { stdin: serialized, ...options });
16649
16660
  if (result2.exitCode !== 0) throw new Error("OS credential write failed.");
16661
+ const retained = await this.read(accountKey, options);
16662
+ if (!retained || JSON.stringify(retained) !== JSON.stringify(validated)) {
16663
+ throw new Error("OS credential write could not be verified.");
16664
+ }
16650
16665
  }
16651
16666
  async remove(accountKey, options = {}) {
16652
16667
  const command = this.commands.remove(INFERENCE_CREDENTIAL_NAMESPACE, accountKey);
@@ -16864,7 +16879,7 @@ public static class VtxInferenceCredential {
16864
16879
  }`;
16865
16880
  powershellCredentialCommand = (operation, namespace, accountKey) => {
16866
16881
  const target = JSON.stringify(`${namespace}:${accountKey}`);
16867
- const body = operation === "read" ? `try { [Console]::Out.Write([VtxInferenceCredential]::Read(${target})) } catch [System.ComponentModel.Win32Exception] { if ($_.Exception.NativeErrorCode -eq 1168) { exit 4 }; exit 1 }` : operation === "write" ? `[VtxInferenceCredential]::Write(${target}, [Console]::In.ReadToEnd())` : `try { [VtxInferenceCredential]::Delete(${target}) } catch [System.ComponentModel.Win32Exception] { if ($_.Exception.NativeErrorCode -eq 1168) { exit 4 }; exit 1 }`;
16882
+ const body = operation === "read" ? `try { [Console]::Out.Write([VtxInferenceCredential]::Read(${target})) } catch [System.ComponentModel.Win32Exception] { if ($_.Exception.NativeErrorCode -eq 1168) { exit 4 }; exit 1 }` : operation === "write" ? `try { [VtxInferenceCredential]::Write(${target}, [Console]::In.ReadToEnd()); exit 0 } catch { exit 1 }` : `try { [VtxInferenceCredential]::Delete(${target}) } catch [System.ComponentModel.Win32Exception] { if ($_.Exception.NativeErrorCode -eq 1168) { exit 4 }; exit 1 }`;
16868
16883
  const script = `Add-Type -TypeDefinition @'
16869
16884
  ${windowsCredentialInterop}
16870
16885
  '@
@@ -16979,7 +16994,7 @@ ${body}`;
16979
16994
  });
16980
16995
 
16981
16996
  // lib/inference-host/mcp-client.ts
16982
- var EXTERNAL_INFERENCE_MCP_PROTOCOL_VERSION, EXTERNAL_INFERENCE_AUTOMATED_HOST_TOOLS, EXTERNAL_INFERENCE_OPERATIONAL_TOOLS, ExternalInferenceMcpError, DEFAULT_REQUEST_TIMEOUT_MS, identifierSchema2, safeCodeSchema2, hostMutationResultSchema, attemptStartResultSchema, agentConnectResultSchema, jobCompletionResultSchema, jobFailureResultSchema, toolContracts, discoveryResultSchema, toolListResultSchema, inlineStructuredContentSchema, protocolMeta, parseJsonDocument, parseSseDocuments, parseResponseDocuments, exactOperationalInventory, exactJson, invalidBoundResult, verifyToolResult, ExternalInferenceMcpClient;
16997
+ var EXTERNAL_INFERENCE_MCP_PROTOCOL_VERSION, EXTERNAL_INFERENCE_AUTOMATED_HOST_TOOLS, EXTERNAL_INFERENCE_OPERATIONAL_TOOLS, ExternalInferenceMcpError, DEFAULT_REQUEST_TIMEOUT_MS, MAX_RETRY_AFTER_MS, parseRetryAfterMs, identifierSchema2, safeCodeSchema2, hostMutationResultSchema, attemptStartResultSchema, agentConnectResultSchema, agentHeartbeatResultSchema, jobCompletionResultSchema, jobFailureResultSchema, toolContracts, discoveryResultSchema, toolListResultSchema, inlineStructuredContentSchema, protocolMeta, parseJsonDocument, parseSseDocuments, parseResponseDocuments, exactOperationalInventory, exactJson, invalidBoundResult, verifyToolResult, ExternalInferenceMcpClient;
16983
16998
  var init_mcp_client = __esm({
16984
16999
  "lib/inference-host/mcp-client.ts"() {
16985
17000
  "use strict";
@@ -16999,6 +17014,7 @@ var init_mcp_client = __esm({
16999
17014
  EXTERNAL_INFERENCE_OPERATIONAL_TOOLS = [
17000
17015
  ...EXTERNAL_INFERENCE_AUTOMATED_HOST_TOOLS,
17001
17016
  "inference.agent.connect",
17017
+ "inference.agent.heartbeat",
17002
17018
  "inference.agent.next",
17003
17019
  "inference.agent.complete",
17004
17020
  "inference.agent.fail"
@@ -17009,9 +17025,29 @@ var init_mcp_client = __esm({
17009
17025
  this.name = "ExternalInferenceMcpError";
17010
17026
  this.code = code;
17011
17027
  this.definitivelyNotApplied = options.definitivelyNotApplied ?? false;
17028
+ this.httpStatusCode = options.httpStatusCode ?? null;
17029
+ this.retryAfterMs = options.retryAfterMs ?? null;
17030
+ this.retryable = options.retryable ?? [
17031
+ "network_error",
17032
+ "transport_rejected",
17033
+ "server_rejected",
17034
+ "rate_limited",
17035
+ "invalid_response",
17036
+ "request_timeout",
17037
+ "authentication_timeout"
17038
+ ].includes(code);
17012
17039
  }
17013
17040
  };
17014
17041
  DEFAULT_REQUEST_TIMEOUT_MS = 15e3;
17042
+ MAX_RETRY_AFTER_MS = 24 * 60 * 60 * 1e3;
17043
+ parseRetryAfterMs = (response, observedAtMs = Date.now()) => {
17044
+ const value = response.headers.get("retry-after")?.trim();
17045
+ if (!value) return null;
17046
+ const seconds = Number(value);
17047
+ const milliseconds = Number.isFinite(seconds) && seconds >= 0 ? Math.ceil(seconds * 1e3) : Math.max(0, Date.parse(value) - observedAtMs);
17048
+ if (!Number.isSafeInteger(milliseconds)) return null;
17049
+ return Math.min(milliseconds, MAX_RETRY_AFTER_MS);
17050
+ };
17015
17051
  identifierSchema2 = external_exports.string().min(1).max(128);
17016
17052
  safeCodeSchema2 = external_exports.string().min(1).max(96);
17017
17053
  hostMutationResultSchema = external_exports.strictObject({
@@ -17030,6 +17066,20 @@ var init_mcp_client = __esm({
17030
17066
  reasoning_effort: safeCodeSchema2,
17031
17067
  replayed: external_exports.boolean()
17032
17068
  });
17069
+ agentHeartbeatResultSchema = external_exports.strictObject({
17070
+ host: hostStatusReadSchema,
17071
+ active_attempts: external_exports.number().int().min(0).max(1),
17072
+ available_slots: external_exports.number().int().min(0).max(1),
17073
+ replayed: external_exports.boolean()
17074
+ }).superRefine((value, context) => {
17075
+ if (value.active_attempts + value.available_slots !== 1) {
17076
+ context.addIssue({
17077
+ code: "custom",
17078
+ message: "Agent heartbeat capacity must describe exactly one slot.",
17079
+ path: ["available_slots"]
17080
+ });
17081
+ }
17082
+ });
17033
17083
  jobCompletionResultSchema = external_exports.strictObject({
17034
17084
  job_id: identifierSchema2,
17035
17085
  attempt_id: identifierSchema2,
@@ -17099,6 +17149,10 @@ var init_mcp_client = __esm({
17099
17149
  arguments: agentConnectRequestSchema,
17100
17150
  result: agentConnectResultSchema
17101
17151
  },
17152
+ "inference.agent.heartbeat": {
17153
+ arguments: agentHeartbeatRequestSchema,
17154
+ result: agentHeartbeatResultSchema
17155
+ },
17102
17156
  "inference.agent.next": {
17103
17157
  arguments: agentNextRequestSchema,
17104
17158
  result: agentNextResultSchema
@@ -17213,11 +17267,11 @@ var init_mcp_client = __esm({
17213
17267
  if (!host) return invalidBoundResult(name);
17214
17268
  if (host.host_id !== request.host_id || host.host_generation !== request.host_generation || host.advertisement_generation !== request.advertisement_generation || host.key_generation !== request.key_generation || request.adapter !== void 0 && host.adapter !== request.adapter) invalidBoundResult(name);
17215
17269
  if (name !== "inference.host.heartbeat") {
17216
- if (host.display_name !== request.display_name || !exactJson(host.models, request.models) || host.status === "revoked") invalidBoundResult(name);
17270
+ if (host.display_name !== request.display_name || (host.authenticated_account_email ?? null) !== (request.authenticated_account_email ?? null) || (host.authenticated_account_plan ?? null) !== (request.authenticated_account_plan ?? null) || !exactJson(host.models, request.models) || host.status === "revoked") invalidBoundResult(name);
17217
17271
  return;
17218
17272
  }
17219
17273
  const expectedStatus = request.status === "healthy" ? "online" : request.status;
17220
- if (host.status !== expectedStatus) invalidBoundResult(name);
17274
+ if (host.status !== expectedStatus && !(request.status === "healthy" && host.status === "offline")) invalidBoundResult(name);
17221
17275
  return;
17222
17276
  }
17223
17277
  if (name === "inference.agent.connect") {
@@ -17225,6 +17279,12 @@ var init_mcp_client = __esm({
17225
17279
  if (!host || host.host_id !== request.host_id || host.adapter !== request.adapter || result2.model_id !== request.model_id || result2.reasoning_effort !== request.reasoning_effort) invalidBoundResult(name);
17226
17280
  return;
17227
17281
  }
17282
+ if (name === "inference.agent.heartbeat") {
17283
+ const host = result2.host;
17284
+ const expectedActive = request.attempt_id == null ? 0 : 1;
17285
+ if (!host || host.host_id !== request.host_id || host.status !== "online" || result2.active_attempts !== expectedActive || result2.available_slots !== 1 - expectedActive) invalidBoundResult(name);
17286
+ return;
17287
+ }
17228
17288
  if (name === "inference.agent.next") {
17229
17289
  if (result2.claim_state === "claimed" && !result2.job_id) invalidBoundResult(name);
17230
17290
  return;
@@ -17343,7 +17403,7 @@ var init_mcp_client = __esm({
17343
17403
  }).passthrough().parse(rawResult);
17344
17404
  if (callResult.isError === true) {
17345
17405
  const errorText = (callResult.content ?? []).filter((block) => block.type === "text").map((block) => block.text ?? "").join("\n");
17346
- const definitivelyNotApplied = (name === "inference.host.register" || name === "inference.host.advertise") && errorText.includes("Advertisement is already expired.") || name === "inference.agent.next" && (errorText.includes("Advertisement time is outside the allowed clock skew.") || errorText.includes("Advertisement is already expired.") || errorText.includes("Heartbeat time is outside the allowed clock skew."));
17406
+ const definitivelyNotApplied = (name === "inference.host.register" || name === "inference.host.advertise") && errorText.includes("Advertisement is already expired.") || (name === "inference.agent.next" || name === "inference.agent.heartbeat") && (errorText.includes("Advertisement time is outside the allowed clock skew.") || errorText.includes("Advertisement is already expired.") || errorText.includes("Heartbeat time is outside the allowed clock skew."));
17347
17407
  throw new ExternalInferenceMcpError(
17348
17408
  "tool_rejected",
17349
17409
  `Insights MCP rejected ${name}.`,
@@ -17423,9 +17483,14 @@ var init_mcp_client = __esm({
17423
17483
  );
17424
17484
  }
17425
17485
  if (!response.ok) {
17486
+ const httpStatusCode = response.status;
17487
+ const retryAfterMs = parseRetryAfterMs(response);
17488
+ await response.body?.cancel().catch(() => void 0);
17489
+ const retryable = httpStatusCode === 408 || httpStatusCode === 425 || httpStatusCode === 429 || httpStatusCode >= 500;
17426
17490
  throw new ExternalInferenceMcpError(
17427
- response.status === 401 ? "authentication_rejected" : "transport_rejected",
17428
- `Insights MCP request failed with HTTP ${response.status}.`
17491
+ httpStatusCode === 401 ? "authentication_rejected" : httpStatusCode === 429 ? "rate_limited" : httpStatusCode >= 500 ? "server_rejected" : retryable ? "transport_rejected" : "http_rejected",
17492
+ `Insights MCP request failed with HTTP ${httpStatusCode}.`,
17493
+ { httpStatusCode, retryAfterMs, retryable }
17429
17494
  );
17430
17495
  }
17431
17496
  let documents;
@@ -18021,13 +18086,13 @@ async function beginInferenceOAuthLogin(options) {
18021
18086
  );
18022
18087
  }
18023
18088
  const fetchImpl = options.fetchImpl || fetch;
18024
- const callbackPath = `/oauth/callback/${randomBytes2(16).toString("hex")}`;
18089
+ const callbackPath = `/vtx-inference-authorized/${randomBytes2(16).toString("hex")}`;
18025
18090
  let handler = null;
18026
18091
  const server = createServer((request, response) => {
18027
18092
  response.setHeader("Cache-Control", "no-store");
18028
18093
  response.setHeader("Pragma", "no-cache");
18029
18094
  response.setHeader("Referrer-Policy", "no-referrer");
18030
- response.setHeader("Content-Type", "text/plain; charset=utf-8");
18095
+ response.setHeader("Content-Type", "text/html; charset=utf-8");
18031
18096
  const writeResponse = (status, body) => {
18032
18097
  response.statusCode = status;
18033
18098
  response.end(body);
@@ -18131,9 +18196,12 @@ async function beginInferenceOAuthLogin(options) {
18131
18196
  cause: error48
18132
18197
  });
18133
18198
  }
18134
- throw error48;
18199
+ throw new InferenceOAuthCredentialStoreError({ cause: error48 });
18135
18200
  }
18136
- writeResponse(200, "Authorization complete. Return to VTX CLI.");
18201
+ writeResponse(
18202
+ 200,
18203
+ '<!doctype html><html><head><meta charset="utf-8"><title>VTX authorization complete</title></head><body><main><h1>VTX authorization complete</h1><p>The VTX CLI received your approval. You can close this tab and return to the terminal.</p></main></body></html>'
18204
+ );
18137
18205
  await closeServer(server);
18138
18206
  resolve5({
18139
18207
  accessToken: tokens.accessToken,
@@ -18142,9 +18210,12 @@ async function beginInferenceOAuthLogin(options) {
18142
18210
  accountKey
18143
18211
  });
18144
18212
  } catch (error48) {
18145
- writeResponse(400, "Authorization failed. Return to VTX CLI.");
18213
+ writeResponse(
18214
+ 400,
18215
+ '<!doctype html><html><head><meta charset="utf-8"><title>VTX authorization failed</title></head><body><main><h1>VTX authorization failed</h1><p>Return to the VTX CLI for the actionable error.</p></main></body></html>'
18216
+ );
18146
18217
  await closeServer(server);
18147
- reject(error48 instanceof InferenceOAuthRequestError ? error48 : new Error("Inference OAuth authorization failed."));
18218
+ reject(error48 instanceof InferenceOAuthRequestError || error48 instanceof InferenceOAuthCredentialStoreError ? error48 : new Error("Inference OAuth authorization failed."));
18148
18219
  }
18149
18220
  };
18150
18221
  });
@@ -18194,7 +18265,7 @@ async function beginInferenceOAuthLogin(options) {
18194
18265
  throw error48;
18195
18266
  }
18196
18267
  }
18197
- var INFERENCE_SCOPE, CALLBACK_HOST, TOKEN_PREFIX, DEFAULT_OAUTH_REQUEST_TIMEOUT_MS, InferenceOAuthRequestError;
18268
+ var INFERENCE_SCOPE, CALLBACK_HOST, TOKEN_PREFIX, DEFAULT_OAUTH_REQUEST_TIMEOUT_MS, InferenceOAuthRequestError, InferenceOAuthCredentialStoreError;
18198
18269
  var init_oauth = __esm({
18199
18270
  "lib/inference-host/oauth.ts"() {
18200
18271
  "use strict";
@@ -18210,6 +18281,15 @@ var init_oauth = __esm({
18210
18281
  this.code = code;
18211
18282
  }
18212
18283
  };
18284
+ InferenceOAuthCredentialStoreError = class extends Error {
18285
+ constructor(options = {}) {
18286
+ super(
18287
+ "VTX authorization succeeded, but the credential store did not retain the grant. VTX revoked the new remote grant. Set VTX_INFERENCE_HOST_CREDENTIAL_STORE=file and run vtx inference-host login again to use the secure private-file fallback.",
18288
+ { cause: options.cause }
18289
+ );
18290
+ this.name = "InferenceOAuthCredentialStoreError";
18291
+ }
18292
+ };
18213
18293
  }
18214
18294
  });
18215
18295
 
@@ -18457,7 +18537,25 @@ async function loginCodexSubscription(options) {
18457
18537
  async function preflightCodexSubscription(options) {
18458
18538
  const session = await CodexAppServerSession.start(options);
18459
18539
  try {
18460
- await session.requireManagedChatGptAuth(options.deadlineAtMs, options.signal, true);
18540
+ const account = await session.readAccountSnapshot(
18541
+ options.deadlineAtMs,
18542
+ options.signal,
18543
+ true
18544
+ );
18545
+ if (!account.requiresOpenaiAuth || account.authenticatedChatGptAccount === null) {
18546
+ throw new CodexAppServerError({
18547
+ message: "Codex managed ChatGPT authentication is required.",
18548
+ category: "auth",
18549
+ code: "managed_chatgpt_auth_required",
18550
+ retryable: false
18551
+ });
18552
+ }
18553
+ const rateLimits = await session.readAccountRateLimits(options.deadlineAtMs, options.signal);
18554
+ return {
18555
+ authenticated_account_email: account.authenticatedChatGptAccount.email,
18556
+ authenticated_account_plan: account.authenticatedChatGptAccount.planType,
18557
+ rate_limits: rateLimits
18558
+ };
18461
18559
  } finally {
18462
18560
  await session.close();
18463
18561
  }
@@ -18470,11 +18568,28 @@ async function logoutCodexSubscription(options) {
18470
18568
  await session.close();
18471
18569
  }
18472
18570
  }
18473
- var CODEX_INFERENCE_PERMISSION_PROFILE, CodexAppServerError, objectOrNull, finiteToken, tokenUsageFromBreakdown, usageFromNotification, forbiddenMethod, forbiddenTerminalItem, classifyCodexTurnFailure, scrubbedCodexEnvironment, killWindowsProcessTree, appServerArgs, GUARDIAN_SCRIPT, writeCodexGuardianSpawnIntent, parseGuardianReceipt, readCodexGuardianReceipt, waitForCodexGuardianState, defaultSpawn, CodexAppServerSession;
18571
+ var CODEX_INFERENCE_PERMISSION_PROFILE, CODEX_ACCOUNT_PLAN_TYPES, CodexAppServerError, objectOrNull, finiteToken, tokenUsageFromBreakdown, usageFromNotification, validPlanType, nonnegativeSafeIntegerOrNull, nonnegativeFiniteNumberOrNull, parseRateLimitWindow, RATE_LIMIT_REACHED_TYPES, DEFAULT_CODEX_QUOTA_COOLDOWN_MS, MAX_CODEX_QUOTA_COOLDOWN_MS, CODEX_TRANSIENT_RATE_LIMIT_COOLDOWN_MS, parseRateLimitSnapshot, codexRateLimitRetryAtMs, codexAccountRateLimitReached, forbiddenMethod, forbiddenTerminalItem, classifyCodexTurnFailure, scrubbedCodexEnvironment, killWindowsProcessTree, appServerArgs, GUARDIAN_SCRIPT, writeCodexGuardianSpawnIntent, parseGuardianReceipt, readCodexGuardianReceipt, waitForCodexGuardianState, defaultSpawn, CodexAppServerSession;
18474
18572
  var init_codex_app_server = __esm({
18475
18573
  "lib/inference-host/codex-app-server.ts"() {
18476
18574
  "use strict";
18477
18575
  CODEX_INFERENCE_PERMISSION_PROFILE = "vtx_inference_readonly";
18576
+ CODEX_ACCOUNT_PLAN_TYPES = [
18577
+ "free",
18578
+ "go",
18579
+ "plus",
18580
+ "pro",
18581
+ "prolite",
18582
+ "team",
18583
+ "self_serve_business_prolite",
18584
+ "self_serve_business_usage_based",
18585
+ "business",
18586
+ "ent26",
18587
+ "enterprise_cbp_automation",
18588
+ "enterprise_cbp_usage_based",
18589
+ "enterprise",
18590
+ "edu",
18591
+ "unknown"
18592
+ ];
18478
18593
  CodexAppServerError = class extends Error {
18479
18594
  constructor(options) {
18480
18595
  super(options.message, { cause: options.cause });
@@ -18483,6 +18598,9 @@ var init_codex_app_server = __esm({
18483
18598
  this.code = options.code;
18484
18599
  this.retryable = options.retryable;
18485
18600
  this.dispatchOutcome = options.dispatchOutcome ?? "not_dispatched";
18601
+ this.httpStatusCode = options.httpStatusCode ?? null;
18602
+ this.retryAtMs = options.retryAtMs ?? null;
18603
+ this.usage = options.usage ?? null;
18486
18604
  }
18487
18605
  };
18488
18606
  objectOrNull = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -18523,6 +18641,72 @@ var init_codex_app_server = __esm({
18523
18641
  }
18524
18642
  return null;
18525
18643
  };
18644
+ validPlanType = (value) => typeof value === "string" && CODEX_ACCOUNT_PLAN_TYPES.includes(value);
18645
+ nonnegativeSafeIntegerOrNull = (value) => Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : null;
18646
+ nonnegativeFiniteNumberOrNull = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
18647
+ parseRateLimitWindow = (value) => {
18648
+ if (value === null) return null;
18649
+ const candidate = objectOrNull(value);
18650
+ if (!candidate) throw new Error("invalid rate-limit window");
18651
+ const usedPercent = nonnegativeFiniteNumberOrNull(candidate.usedPercent);
18652
+ const windowDurationMins = candidate.windowDurationMins == null ? null : nonnegativeSafeIntegerOrNull(candidate.windowDurationMins);
18653
+ const resetsAt = candidate.resetsAt == null ? null : nonnegativeSafeIntegerOrNull(candidate.resetsAt);
18654
+ if (usedPercent === null || windowDurationMins === null && candidate.windowDurationMins != null || resetsAt === null && candidate.resetsAt != null) {
18655
+ throw new Error("invalid rate-limit window");
18656
+ }
18657
+ return { usedPercent, windowDurationMins, resetsAt };
18658
+ };
18659
+ RATE_LIMIT_REACHED_TYPES = [
18660
+ "rate_limit_reached",
18661
+ "workspace_owner_credits_depleted",
18662
+ "workspace_member_credits_depleted",
18663
+ "workspace_owner_usage_limit_reached",
18664
+ "workspace_member_usage_limit_reached"
18665
+ ];
18666
+ DEFAULT_CODEX_QUOTA_COOLDOWN_MS = 5 * 60 * 1e3;
18667
+ MAX_CODEX_QUOTA_COOLDOWN_MS = 8 * 24 * 60 * 60 * 1e3;
18668
+ CODEX_TRANSIENT_RATE_LIMIT_COOLDOWN_MS = 30 * 1e3;
18669
+ parseRateLimitSnapshot = (value) => {
18670
+ const candidate = objectOrNull(value);
18671
+ if (!candidate) throw new Error("invalid rate-limit snapshot");
18672
+ const limitId = candidate.limitId === null || candidate.limitId === void 0 ? null : typeof candidate.limitId === "string" && candidate.limitId.trim() ? candidate.limitId.trim() : void 0;
18673
+ const limitName = candidate.limitName === null || candidate.limitName === void 0 ? null : typeof candidate.limitName === "string" && candidate.limitName.trim() ? candidate.limitName.trim() : void 0;
18674
+ const planType = candidate.planType === null || candidate.planType === void 0 ? null : validPlanType(candidate.planType) ? candidate.planType : void 0;
18675
+ const reached = candidate.rateLimitReachedType === null || candidate.rateLimitReachedType === void 0 ? null : typeof candidate.rateLimitReachedType === "string" && RATE_LIMIT_REACHED_TYPES.includes(candidate.rateLimitReachedType) ? candidate.rateLimitReachedType : void 0;
18676
+ const spendControlReached = candidate.spendControlReached === null || candidate.spendControlReached === void 0 ? null : typeof candidate.spendControlReached === "boolean" ? candidate.spendControlReached : void 0;
18677
+ if (limitId === void 0 || limitName === void 0 || planType === void 0 || reached === void 0 || spendControlReached === void 0) throw new Error("invalid rate-limit snapshot");
18678
+ return {
18679
+ limitId,
18680
+ limitName,
18681
+ planType,
18682
+ primary: parseRateLimitWindow(candidate.primary ?? null),
18683
+ secondary: parseRateLimitWindow(candidate.secondary ?? null),
18684
+ rateLimitReachedType: reached,
18685
+ spendControlReached
18686
+ };
18687
+ };
18688
+ codexRateLimitRetryAtMs = (accountRateLimits) => {
18689
+ const snapshots = [accountRateLimits.rateLimits];
18690
+ const exhaustedResets = [];
18691
+ const reachedResets = [];
18692
+ for (const snapshot of snapshots) {
18693
+ const windows = [snapshot.primary, snapshot.secondary].filter(
18694
+ (window2) => window2 !== null
18695
+ );
18696
+ for (const window2 of windows) {
18697
+ if (window2.resetsAt === null) continue;
18698
+ const resetAtMs = window2.resetsAt * 1e3;
18699
+ if (!Number.isSafeInteger(resetAtMs)) continue;
18700
+ if (window2.usedPercent >= 100) exhaustedResets.push(resetAtMs);
18701
+ if (snapshot.rateLimitReachedType !== null || snapshot.spendControlReached === true) {
18702
+ reachedResets.push(resetAtMs);
18703
+ }
18704
+ }
18705
+ }
18706
+ const candidates = exhaustedResets.length > 0 ? exhaustedResets : reachedResets.length > 0 ? reachedResets : [];
18707
+ return candidates.length > 0 ? Math.max(...candidates) : null;
18708
+ };
18709
+ codexAccountRateLimitReached = (accountRateLimits) => [accountRateLimits.rateLimits].some((snapshot) => snapshot.rateLimitReachedType !== null || snapshot.spendControlReached === true || snapshot.primary?.usedPercent !== void 0 && snapshot.primary.usedPercent >= 100 || snapshot.secondary?.usedPercent !== void 0 && snapshot.secondary.usedPercent >= 100);
18526
18710
  forbiddenMethod = (method) => method.startsWith("mcpServer/") || method.startsWith("serverRequest/") || method.startsWith("item/mcpToolCall") || method.startsWith("item/commandExecution") || method.startsWith("item/fileChange") || method.startsWith("item/dynamicToolCall") || method.startsWith("item/collabAgentToolCall");
18527
18711
  forbiddenTerminalItem = (item) => ![
18528
18712
  "userMessage",
@@ -18531,13 +18715,13 @@ var init_codex_app_server = __esm({
18531
18715
  ].includes(String(item.type || ""));
18532
18716
  classifyCodexTurnFailure = (codexErrorInfo, terminalStatus) => {
18533
18717
  if (terminalStatus === "interrupted") {
18534
- return { code: "cancelled", category: "cancelled", retryable: false };
18718
+ return { code: "cancelled", category: "cancelled", retryable: false, httpStatusCode: null };
18535
18719
  }
18536
18720
  if (codexErrorInfo === "usageLimitExceeded") {
18537
- return { code: "quota_exceeded", category: "model", retryable: false };
18721
+ return { code: "quota_exceeded", category: "model", retryable: false, httpStatusCode: null };
18538
18722
  }
18539
18723
  if (codexErrorInfo === "unauthorized") {
18540
- return { code: "auth_expired", category: "auth", retryable: false };
18724
+ return { code: "auth_expired", category: "auth", retryable: false, httpStatusCode: null };
18541
18725
  }
18542
18726
  const stableStringCodes = {
18543
18727
  badRequest: "codex_bad_request",
@@ -18554,22 +18738,40 @@ var init_codex_app_server = __esm({
18554
18738
  return {
18555
18739
  code,
18556
18740
  category: "adapter",
18557
- retryable: code === "codex_internal_error" || code === "codex_server_overloaded"
18741
+ retryable: code === "codex_internal_error" || code === "codex_server_overloaded",
18742
+ httpStatusCode: null
18558
18743
  };
18559
18744
  }
18560
18745
  const structured = objectOrNull(codexErrorInfo);
18561
18746
  if (structured) {
18562
- if ("httpConnectionFailed" in structured) {
18563
- return { code: "codex_http_connection_failed", category: "adapter", retryable: true };
18564
- }
18565
- if ("responseStreamConnectionFailed" in structured) {
18566
- return { code: "codex_response_stream_connection_failed", category: "adapter", retryable: true };
18567
- }
18568
- if ("responseStreamDisconnected" in structured) {
18569
- return { code: "codex_response_stream_disconnected", category: "adapter", retryable: true };
18747
+ const variants = [
18748
+ ["httpConnectionFailed", "codex_http_connection_failed"],
18749
+ ["responseStreamConnectionFailed", "codex_response_stream_connection_failed"],
18750
+ ["responseStreamDisconnected", "codex_response_stream_disconnected"],
18751
+ ["responseTooManyFailedAttempts", "codex_provider_retry_exhausted"]
18752
+ ];
18753
+ for (const [variant, code] of variants) {
18754
+ if (!(variant in structured)) continue;
18755
+ const details = objectOrNull(structured[variant]);
18756
+ const rawStatus = details?.httpStatusCode;
18757
+ const httpStatusCode = Number.isSafeInteger(rawStatus) && Number(rawStatus) >= 100 && Number(rawStatus) <= 599 ? Number(rawStatus) : null;
18758
+ if (httpStatusCode === 429) {
18759
+ return {
18760
+ code: "codex_rate_limited",
18761
+ category: "adapter",
18762
+ retryable: true,
18763
+ httpStatusCode
18764
+ };
18765
+ }
18766
+ return {
18767
+ code,
18768
+ category: "adapter",
18769
+ retryable: httpStatusCode === null ? variant !== "responseTooManyFailedAttempts" : httpStatusCode === 408 || httpStatusCode === 425 || httpStatusCode >= 500,
18770
+ httpStatusCode
18771
+ };
18570
18772
  }
18571
18773
  }
18572
- return { code: "turn_failed", category: "adapter", retryable: false };
18774
+ return { code: "turn_failed", category: "adapter", retryable: false, httpStatusCode: null };
18573
18775
  };
18574
18776
  scrubbedCodexEnvironment = (codexHome) => {
18575
18777
  if (process.platform === "win32") {
@@ -19049,13 +19251,80 @@ child.once('close', async () => {
19049
19251
  this.fatalListeners.add(listener);
19050
19252
  return () => this.fatalListeners.delete(listener);
19051
19253
  }
19052
- async hasManagedChatGptAuth(deadlineAtMs, signal, refreshToken = false) {
19254
+ async readAccountSnapshot(deadlineAtMs, signal, refreshToken = false) {
19053
19255
  const result2 = await this.request("account/read", { refreshToken }, {
19054
19256
  timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
19055
19257
  signal
19056
19258
  });
19057
19259
  const account = objectOrNull(result2.account);
19058
- return account?.type === "chatgpt" && result2.requiresOpenaiAuth === true;
19260
+ if (typeof result2.requiresOpenaiAuth !== "boolean") {
19261
+ throw new CodexAppServerError({
19262
+ message: "Codex returned invalid account metadata.",
19263
+ category: "auth",
19264
+ code: "invalid_account_metadata",
19265
+ retryable: false
19266
+ });
19267
+ }
19268
+ if (account?.type === "chatgpt") {
19269
+ const email3 = account.email === null ? null : typeof account.email === "string" && account.email.trim() ? account.email.trim() : void 0;
19270
+ if (email3 === void 0 || !validPlanType(account.planType)) {
19271
+ throw new CodexAppServerError({
19272
+ message: "Codex returned invalid managed ChatGPT account metadata.",
19273
+ category: "auth",
19274
+ code: "invalid_account_metadata",
19275
+ retryable: false
19276
+ });
19277
+ }
19278
+ return {
19279
+ requiresOpenaiAuth: result2.requiresOpenaiAuth,
19280
+ authenticatedChatGptAccount: { email: email3, planType: account.planType }
19281
+ };
19282
+ }
19283
+ if (account !== null && account?.type !== "apiKey" && account?.type !== "amazonBedrock") {
19284
+ throw new CodexAppServerError({
19285
+ message: "Codex returned an unsupported account type.",
19286
+ category: "auth",
19287
+ code: "invalid_account_metadata",
19288
+ retryable: false
19289
+ });
19290
+ }
19291
+ return {
19292
+ requiresOpenaiAuth: result2.requiresOpenaiAuth,
19293
+ authenticatedChatGptAccount: null
19294
+ };
19295
+ }
19296
+ async hasManagedChatGptAuth(deadlineAtMs, signal, refreshToken = false) {
19297
+ const snapshot = await this.readAccountSnapshot(deadlineAtMs, signal, refreshToken);
19298
+ return snapshot.authenticatedChatGptAccount !== null && snapshot.requiresOpenaiAuth;
19299
+ }
19300
+ async readAccountRateLimits(deadlineAtMs, signal) {
19301
+ const result2 = await this.request("account/rateLimits/read", void 0, {
19302
+ timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
19303
+ signal
19304
+ });
19305
+ try {
19306
+ const rateLimits = parseRateLimitSnapshot(result2.rateLimits);
19307
+ const rawByLimitId = result2.rateLimitsByLimitId;
19308
+ let rateLimitsByLimitId = null;
19309
+ if (rawByLimitId !== null && rawByLimitId !== void 0) {
19310
+ const byLimitId = objectOrNull(rawByLimitId);
19311
+ if (!byLimitId) throw new Error("invalid rate-limit bucket map");
19312
+ rateLimitsByLimitId = {};
19313
+ for (const [limitId, snapshot] of Object.entries(byLimitId)) {
19314
+ if (!limitId.trim()) throw new Error("invalid rate-limit bucket identity");
19315
+ rateLimitsByLimitId[limitId] = parseRateLimitSnapshot(snapshot);
19316
+ }
19317
+ }
19318
+ return { rateLimits, rateLimitsByLimitId };
19319
+ } catch (error48) {
19320
+ throw new CodexAppServerError({
19321
+ message: "Codex returned invalid account rate-limit metadata.",
19322
+ category: "adapter",
19323
+ code: "invalid_rate_limit_metadata",
19324
+ retryable: false,
19325
+ cause: error48
19326
+ });
19327
+ }
19059
19328
  }
19060
19329
  async requireManagedChatGptAuth(deadlineAtMs, signal, refreshToken = false) {
19061
19330
  if (!await this.hasManagedChatGptAuth(deadlineAtMs, signal, refreshToken)) {
@@ -19592,13 +19861,54 @@ child.once('close', async () => {
19592
19861
  }
19593
19862
  if (terminal.status !== "completed") {
19594
19863
  const turnError = objectOrNull(terminal.error);
19595
- const failure = classifyCodexTurnFailure(turnError?.codexErrorInfo, String(terminal.status));
19864
+ let failure = classifyCodexTurnFailure(
19865
+ turnError?.codexErrorInfo,
19866
+ String(terminal.status)
19867
+ );
19868
+ const observedUsage = threadUsage ?? rawResponseUsage;
19869
+ let retryAtMs = null;
19870
+ if (failure.code === "quota_exceeded" || failure.httpStatusCode === 429) {
19871
+ const observedAtMs = Date.now();
19872
+ let accountLimitReached = failure.code === "quota_exceeded";
19873
+ try {
19874
+ const metadataDeadlineAtMs = Math.min(
19875
+ request.deadlineAtMs,
19876
+ observedAtMs + 5e3
19877
+ );
19878
+ if (metadataDeadlineAtMs <= observedAtMs) throw new Error("rate-limit deadline elapsed");
19879
+ const rateLimits = await this.readAccountRateLimits(metadataDeadlineAtMs, request.signal);
19880
+ accountLimitReached = accountLimitReached || codexAccountRateLimitReached(rateLimits);
19881
+ retryAtMs = codexRateLimitRetryAtMs(rateLimits);
19882
+ } catch {
19883
+ }
19884
+ if (accountLimitReached) {
19885
+ failure = {
19886
+ ...failure,
19887
+ code: "quota_exceeded",
19888
+ category: "model",
19889
+ retryable: false
19890
+ };
19891
+ if (retryAtMs === null || retryAtMs <= observedAtMs) {
19892
+ retryAtMs = observedAtMs + DEFAULT_CODEX_QUOTA_COOLDOWN_MS;
19893
+ } else {
19894
+ retryAtMs = Math.min(
19895
+ retryAtMs,
19896
+ observedAtMs + MAX_CODEX_QUOTA_COOLDOWN_MS
19897
+ );
19898
+ }
19899
+ } else {
19900
+ retryAtMs = observedAtMs + CODEX_TRANSIENT_RATE_LIMIT_COOLDOWN_MS;
19901
+ }
19902
+ }
19596
19903
  throw new CodexAppServerError({
19597
19904
  message: "Codex turn did not complete successfully.",
19598
19905
  category: failure.category,
19599
19906
  code: failure.code,
19600
19907
  retryable: failure.retryable,
19601
- dispatchOutcome: "confirmed_dispatched"
19908
+ dispatchOutcome: "confirmed_dispatched",
19909
+ httpStatusCode: failure.httpStatusCode,
19910
+ retryAtMs,
19911
+ usage: observedUsage
19602
19912
  });
19603
19913
  }
19604
19914
  const items = Array.isArray(terminal.items) ? terminal.items.map(objectOrNull) : [];
@@ -19958,7 +20268,10 @@ var init_codex_adapter = __esm({
19958
20268
  category: external_exports.enum(["auth", "model", "schema", "timeout", "cancelled", "transport", "adapter"]),
19959
20269
  code: external_exports.string().min(1).max(96),
19960
20270
  retryable: external_exports.boolean(),
19961
- dispatchOutcome: external_exports.enum(["not_dispatched", "confirmed_dispatched", "outcome_unknown"])
20271
+ dispatchOutcome: external_exports.enum(["not_dispatched", "confirmed_dispatched", "outcome_unknown"]),
20272
+ httpStatusCode: external_exports.number().int().min(100).max(599).nullable().optional(),
20273
+ retryAtMs: external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).nullable().optional(),
20274
+ usage: tokenUsageReceiptSchema.nullable().optional()
19962
20275
  })
19963
20276
  })
19964
20277
  ]);
@@ -20479,7 +20792,10 @@ var init_codex_adapter = __esm({
20479
20792
  category: recovered.category,
20480
20793
  code: recovered.code,
20481
20794
  retryable: recovered.retryable,
20482
- dispatchOutcome: recovered.dispatchOutcome
20795
+ dispatchOutcome: recovered.dispatchOutcome,
20796
+ httpStatusCode: recovered.httpStatusCode,
20797
+ retryAtMs: recovered.retryAtMs,
20798
+ usage: recovered.usage
20483
20799
  });
20484
20800
  }
20485
20801
  throw new CodexAppServerError({
@@ -20618,7 +20934,10 @@ var init_codex_adapter = __esm({
20618
20934
  category: error48.category,
20619
20935
  code: error48.code,
20620
20936
  retryable: error48.retryable,
20621
- dispatchOutcome
20937
+ dispatchOutcome,
20938
+ httpStatusCode: error48.httpStatusCode,
20939
+ retryAtMs: error48.retryAtMs,
20940
+ usage: error48.usage
20622
20941
  }
20623
20942
  }
20624
20943
  };
@@ -20631,6 +20950,9 @@ var init_codex_adapter = __esm({
20631
20950
  code: error48.code,
20632
20951
  retryable: error48.retryable,
20633
20952
  dispatchOutcome,
20953
+ httpStatusCode: error48.httpStatusCode,
20954
+ retryAtMs: error48.retryAtMs,
20955
+ usage: error48.usage,
20634
20956
  cause: error48
20635
20957
  });
20636
20958
  }
@@ -27310,7 +27632,7 @@ function createDefaultInferenceHostRunnerDependencies(options) {
27310
27632
  envelopePublicKey: options.envelopePublicKey
27311
27633
  };
27312
27634
  }
27313
- var import_ajv, RUNTIME_RECEIPT_SCHEMA_VERSION, ATTEMPT_RECEIPT_SCHEMA_VERSION, DEFAULT_ADVERTISEMENT_TTL_MS, DEFAULT_ADVERTISEMENT_REFRESH_LEAD_MS, DEFAULT_HOST_HEARTBEAT_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, DEFAULT_MAX_CONCURRENCY, MIN_SLEEP_MS, CODEX_INFERENCE_ADVERTISED_MODEL, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, safeFailureCode, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedUsage, InferenceHostRunner;
27635
+ var import_ajv, RUNTIME_RECEIPT_SCHEMA_VERSION, ATTEMPT_RECEIPT_SCHEMA_VERSION, DEFAULT_ADVERTISEMENT_TTL_MS, DEFAULT_ADVERTISEMENT_REFRESH_LEAD_MS, DEFAULT_HOST_HEARTBEAT_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, DEFAULT_MAX_CONCURRENCY, MIN_SLEEP_MS, DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS, CODEX_INFERENCE_ADVERTISED_MODEL, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, remoteRetryAfterMs, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, safeFailureCode, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedTokenUsage, reportedUsage, InferenceHostRunner;
27314
27636
  var init_runner = __esm({
27315
27637
  "lib/inference-host/runner.ts"() {
27316
27638
  "use strict";
@@ -27333,6 +27655,7 @@ var init_runner = __esm({
27333
27655
  DEFAULT_REMOTE_RETRY_LIMIT = 3;
27334
27656
  DEFAULT_MAX_CONCURRENCY = 1;
27335
27657
  MIN_SLEEP_MS = 10;
27658
+ DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS = 5 * 60 * 1e3;
27336
27659
  CODEX_INFERENCE_ADVERTISED_MODEL = Object.freeze({
27337
27660
  model_id: INITIAL_CODEX_INFERENCE_MODEL,
27338
27661
  label: "Codex GPT-5.6 Sol",
@@ -27622,19 +27945,14 @@ var init_runner = __esm({
27622
27945
  };
27623
27946
  retryableRemoteError = (error48) => {
27624
27947
  if (error48 instanceof ExternalInferenceMcpError) {
27625
- return [
27626
- "network_error",
27627
- "transport_rejected",
27628
- "invalid_response",
27629
- "request_timeout",
27630
- "authentication_timeout"
27631
- ].includes(error48.code);
27948
+ return error48.retryable;
27632
27949
  }
27633
27950
  if (error48 && typeof error48 === "object" && "retryable" in error48) {
27634
27951
  return error48.retryable === true;
27635
27952
  }
27636
27953
  return false;
27637
27954
  };
27955
+ remoteRetryAfterMs = (error48, fallbackMs) => error48 instanceof ExternalInferenceMcpError && error48.retryAfterMs !== null && Number.isSafeInteger(error48.retryAfterMs) && error48.retryAfterMs >= 0 ? Math.max(fallbackMs, error48.retryAfterMs) : fallbackMs;
27638
27956
  controlPlaneFatal = (error48) => {
27639
27957
  const code = error48 && typeof error48 === "object" && "code" in error48 ? String(error48.code) : "";
27640
27958
  return [
@@ -27757,11 +28075,12 @@ var init_runner = __esm({
27757
28075
  };
27758
28076
  assertAdvertisementResult = (advertisement, result2) => {
27759
28077
  const host = result2.host;
27760
- if (host.host_id !== advertisement.host_id || host.host_generation !== advertisement.host_generation || host.advertisement_generation !== advertisement.advertisement_generation || host.key_generation !== advertisement.key_generation || host.display_name !== advertisement.display_name || host.adapter !== advertisement.adapter || host.status === "revoked" || !exactJson2(host.models, advertisement.models)) runnerIdentityMismatch("Host advertisement");
28078
+ if (host.host_id !== advertisement.host_id || host.host_generation !== advertisement.host_generation || host.advertisement_generation !== advertisement.advertisement_generation || host.key_generation !== advertisement.key_generation || host.display_name !== advertisement.display_name || (host.authenticated_account_email ?? null) !== (advertisement.authenticated_account_email ?? null) || (host.authenticated_account_plan ?? null) !== (advertisement.authenticated_account_plan ?? null) || host.adapter !== advertisement.adapter || host.status === "revoked" || !exactJson2(host.models, advertisement.models)) runnerIdentityMismatch("Host advertisement");
27761
28079
  };
27762
- assertHostHeartbeatResult = (request, result2) => {
28080
+ assertHostHeartbeatResult = (request, result2, allowOfflineProjection = false) => {
27763
28081
  const expectedStatus = request.status === "healthy" ? "online" : request.status;
27764
- if (result2.host.host_id !== request.host_id || result2.host.host_generation !== request.host_generation || result2.host.advertisement_generation !== request.advertisement_generation || result2.host.key_generation !== request.key_generation || result2.host.adapter !== "codex" || result2.host.status !== expectedStatus) runnerIdentityMismatch("Host heartbeat");
28082
+ const expectedTemporaryOffline = allowOfflineProjection && request.status === "healthy" && result2.host.status === "offline";
28083
+ if (result2.host.host_id !== request.host_id || result2.host.host_generation !== request.host_generation || result2.host.advertisement_generation !== request.advertisement_generation || result2.host.key_generation !== request.key_generation || result2.host.adapter !== "codex" || result2.host.status !== expectedStatus && !expectedTemporaryOffline) runnerIdentityMismatch("Host heartbeat");
27765
28084
  };
27766
28085
  assertClaimResult = (request, result2) => {
27767
28086
  if (result2.claim_request_id !== request.claim_request_id) {
@@ -27797,7 +28116,13 @@ var init_runner = __esm({
27797
28116
  };
27798
28117
  }
27799
28118
  if (error48 instanceof ExternalInferenceMcpError) {
27800
- const category2 = error48.code.startsWith("authentication") ? "auth" : ["network_error", "transport_rejected", "request_timeout"].includes(error48.code) ? "network" : "transport";
28119
+ const category2 = error48.code.startsWith("authentication") ? "auth" : [
28120
+ "network_error",
28121
+ "transport_rejected",
28122
+ "server_rejected",
28123
+ "rate_limited",
28124
+ "request_timeout"
28125
+ ].includes(error48.code) ? "network" : "transport";
27801
28126
  return {
27802
28127
  category: category2,
27803
28128
  code: safeFailureCode(error48.code, "transport_failure"),
@@ -27823,24 +28148,27 @@ var init_runner = __esm({
27823
28148
  return [
27824
28149
  "network_error",
27825
28150
  "transport_rejected",
28151
+ "server_rejected",
28152
+ "rate_limited",
27826
28153
  "invalid_response",
27827
28154
  "identity_mismatch",
27828
28155
  "request_timeout",
27829
28156
  "authentication_timeout"
27830
28157
  ].includes(code);
27831
28158
  };
27832
- reportedUsage = (result2) => ({
28159
+ reportedTokenUsage = (usage) => ({
27833
28160
  schema_version: EXTERNAL_INFERENCE_USAGE_SCHEMA_VERSION,
27834
28161
  availability: "reported",
27835
28162
  source: "codex_app_server",
27836
- input_tokens: result2.usage.inputTokens,
27837
- cached_input_tokens: result2.usage.cachedInputTokens,
27838
- output_tokens: result2.usage.outputTokens,
27839
- reasoning_output_tokens: result2.usage.reasoningOutputTokens,
27840
- total_tokens: result2.usage.totalTokens,
27841
- cache_write_input_tokens: result2.usage.cacheWriteInputTokens,
27842
- cache_write_support: result2.usage.cacheWriteSupported ? "reported" : "unsupported"
27843
- });
28163
+ input_tokens: usage.inputTokens,
28164
+ cached_input_tokens: usage.cachedInputTokens,
28165
+ output_tokens: usage.outputTokens,
28166
+ reasoning_output_tokens: usage.reasoningOutputTokens,
28167
+ total_tokens: usage.totalTokens,
28168
+ cache_write_input_tokens: usage.cacheWriteInputTokens,
28169
+ cache_write_support: usage.cacheWriteSupported ? "reported" : "unsupported"
28170
+ });
28171
+ reportedUsage = (result2) => reportedTokenUsage(result2.usage);
27844
28172
  InferenceHostRunner = class {
27845
28173
  constructor(dependencies, options) {
27846
28174
  this.receiptWriteChain = Promise.resolve();
@@ -28003,24 +28331,24 @@ var init_runner = __esm({
28003
28331
  } catch (error48) {
28004
28332
  lastError = error48;
28005
28333
  if (!retryableRemoteError(error48) || attempt === settings.remoteRetryLimit) throw error48;
28006
- const retryDelay = Math.min(
28007
- 250 * attempt,
28008
- 1e3,
28009
- boundary.deadlineAtMs === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, boundary.deadlineAtMs - now())
28334
+ const requestedRetryDelay = remoteRetryAfterMs(
28335
+ error48,
28336
+ Math.min(250 * attempt, 1e3)
28010
28337
  );
28011
- if (retryDelay < 1) {
28338
+ const remaining = boundary.deadlineAtMs === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, boundary.deadlineAtMs - now());
28339
+ if (requestedRetryDelay < 1 || requestedRetryDelay >= remaining) {
28012
28340
  throw new ExternalInferenceMcpError(
28013
28341
  "request_timeout",
28014
28342
  "Insights MCP retry deadline elapsed.",
28015
28343
  { cause: error48 }
28016
28344
  );
28017
28345
  }
28018
- await sleep4(retryDelay, boundary.signal);
28346
+ await sleep4(requestedRetryDelay, boundary.signal);
28019
28347
  }
28020
28348
  }
28021
28349
  throw lastError;
28022
28350
  };
28023
- const publishAdvertisement = async (health, forceAdvance) => {
28351
+ const publishAdvertisement = async (health, forceAdvance, retryRemote = true) => {
28024
28352
  let advertisement = receipt.pending_advertisement;
28025
28353
  if (!advertisement) {
28026
28354
  const generation = receipt.registered && forceAdvance ? receipt.advertisement_generation + 1 : receipt.advertisement_generation;
@@ -28041,6 +28369,8 @@ var init_runner = __esm({
28041
28369
  key_generation: localState.key_generation,
28042
28370
  adapter: "codex",
28043
28371
  display_name: this.options.displayName.trim(),
28372
+ authenticated_account_email: this.options.authenticatedAccountEmail ?? null,
28373
+ authenticated_account_plan: this.options.authenticatedAccountPlan ?? null,
28044
28374
  protocol_version: this.options.protocolVersion,
28045
28375
  envelope_public_key: envelopePublicKey,
28046
28376
  health,
@@ -28063,15 +28393,12 @@ var init_runner = __esm({
28063
28393
  const tool = receipt.registered ? "inference.host.advertise" : "inference.host.register";
28064
28394
  let result2;
28065
28395
  try {
28066
- result2 = tool === "inference.host.register" ? await retryExact(() => mcp.callTool(
28396
+ const advertiseOperation = () => mcp.callTool(
28067
28397
  tool,
28068
28398
  advertisement,
28069
28399
  { signal: this.options.signal }
28070
- ), { signal: this.options.signal }) : await retryExact(() => mcp.callTool(
28071
- tool,
28072
- advertisement,
28073
- { signal: this.options.signal }
28074
- ), { signal: this.options.signal });
28400
+ );
28401
+ result2 = retryRemote ? await retryExact(advertiseOperation, { signal: this.options.signal }) : await advertiseOperation();
28075
28402
  } catch (error48) {
28076
28403
  const definitivelyNotApplied = error48 instanceof ExternalInferenceMcpError ? error48.definitivelyNotApplied : Boolean(error48 && typeof error48 === "object" && error48.definitivelyNotApplied === true);
28077
28404
  const expectedGeneration = receipt.registered ? receipt.advertisement_generation + 1 : receipt.advertisement_generation;
@@ -28082,7 +28409,7 @@ var init_runner = __esm({
28082
28409
  updated_at: isoAt(now())
28083
28410
  };
28084
28411
  await this.persistReceipt(receipt, now);
28085
- return await publishAdvertisement(health, forceAdvance);
28412
+ return await publishAdvertisement(health, forceAdvance, retryRemote);
28086
28413
  }
28087
28414
  throw error48;
28088
28415
  }
@@ -28104,7 +28431,7 @@ var init_runner = __esm({
28104
28431
  }
28105
28432
  const hostHeartbeat = async (status, requestOptions = {
28106
28433
  signal: this.options.signal
28107
- }) => {
28434
+ }, retryRemote = true, allowOfflineProjection = false) => {
28108
28435
  const sequence = receipt.host_heartbeat_sequence + 1;
28109
28436
  const request = {
28110
28437
  schema_version: "external_inference_host_heartbeat_v1",
@@ -28130,9 +28457,9 @@ var init_runner = __esm({
28130
28457
  request,
28131
28458
  requestOptions
28132
28459
  );
28133
- const result2 = status === "draining" ? await heartbeatOperation() : await retryExact(heartbeatOperation, requestOptions);
28134
- assertHostHeartbeatResult(request, result2);
28135
- if (["revoked", "offline"].includes(result2.host.status)) {
28460
+ const result2 = status === "draining" || !retryRemote ? await heartbeatOperation() : await retryExact(heartbeatOperation, requestOptions);
28461
+ assertHostHeartbeatResult(request, result2, allowOfflineProjection);
28462
+ if (result2.host.status === "revoked" || result2.host.status === "offline" && !allowOfflineProjection) {
28136
28463
  const error48 = new InferenceHostRunnerError(
28137
28464
  result2.host.status === "revoked" ? "host_revoked" : "host_offline",
28138
28465
  "The external inference host is no longer active."
@@ -28142,7 +28469,9 @@ var init_runner = __esm({
28142
28469
  };
28143
28470
  await hostHeartbeat("healthy");
28144
28471
  let nextHostHeartbeatAt = now() + settings.hostHeartbeatMs;
28145
- let nextClaimAt = now();
28472
+ let nextAdvertisementAttemptAt = 0;
28473
+ let providerRetryAtMs = this.options.codexRateLimits && codexAccountRateLimitReached(this.options.codexRateLimits) ? codexRateLimitRetryAtMs(this.options.codexRateLimits) ?? now() + DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS : null;
28474
+ let nextClaimAt = Math.max(now(), providerRetryAtMs ?? 0);
28146
28475
  let onceClaimed = false;
28147
28476
  const launchClaim = (claim, recovery) => {
28148
28477
  if (!recovery) {
@@ -28180,6 +28509,11 @@ var init_runner = __esm({
28180
28509
  attemptHeartbeatMs: settings.attemptHeartbeatMs,
28181
28510
  sleep: sleep4,
28182
28511
  now,
28512
+ onProviderCooldown: (retryAtMs) => {
28513
+ if (!Number.isSafeInteger(retryAtMs) || retryAtMs <= now()) return;
28514
+ providerRetryAtMs = Math.max(providerRetryAtMs ?? 0, retryAtMs);
28515
+ nextClaimAt = Math.max(nextClaimAt, providerRetryAtMs);
28516
+ },
28183
28517
  resumeReceipt: recovery
28184
28518
  }).then((outcome) => {
28185
28519
  if (outcome === "completed") completed += 1;
@@ -28239,22 +28573,46 @@ var init_runner = __esm({
28239
28573
  while (!drainRequested) {
28240
28574
  const currentTime = now();
28241
28575
  const expiresAt = receipt.advertisement_expires_at ? Date.parse(receipt.advertisement_expires_at) : 0;
28242
- if (expiresAt - currentTime <= settings.advertisementRefreshLeadMs) {
28576
+ if (currentTime >= nextAdvertisementAttemptAt && expiresAt - currentTime <= settings.advertisementRefreshLeadMs) {
28243
28577
  try {
28244
- await publishAdvertisement("healthy", true);
28578
+ await publishAdvertisement("healthy", true, false);
28579
+ nextAdvertisementAttemptAt = 0;
28245
28580
  } catch (error48) {
28246
- requestDrain(controlPlaneFatal(error48) ? "authority_lost" : "advertisement_failed");
28247
- break;
28581
+ if (controlPlaneFatal(error48)) {
28582
+ requestDrain("authority_lost");
28583
+ break;
28584
+ }
28585
+ if (!retryableRemoteError(error48)) {
28586
+ requestDrain("advertisement_failed");
28587
+ break;
28588
+ }
28589
+ nextAdvertisementAttemptAt = now() + remoteRetryAfterMs(error48, 1e3);
28590
+ nextClaimAt = Math.max(nextClaimAt, nextAdvertisementAttemptAt);
28248
28591
  }
28249
28592
  }
28250
28593
  if (currentTime >= nextHostHeartbeatAt) {
28251
28594
  try {
28252
- await hostHeartbeat("healthy");
28595
+ const refreshPendingAcrossExpiry = receipt.pending_advertisement !== null && expiresAt <= currentTime && nextAdvertisementAttemptAt > currentTime;
28596
+ await hostHeartbeat(
28597
+ "healthy",
28598
+ { signal: this.options.signal },
28599
+ false,
28600
+ refreshPendingAcrossExpiry
28601
+ );
28253
28602
  } catch (error48) {
28254
- requestDrain(controlPlaneFatal(error48) ? "authority_lost" : "host_heartbeat_failed");
28255
- break;
28603
+ if (controlPlaneFatal(error48)) {
28604
+ requestDrain("authority_lost");
28605
+ break;
28606
+ }
28607
+ if (!retryableRemoteError(error48)) {
28608
+ requestDrain("host_heartbeat_failed");
28609
+ break;
28610
+ }
28611
+ nextHostHeartbeatAt = now() + remoteRetryAfterMs(error48, settings.hostHeartbeatMs);
28612
+ }
28613
+ if (!drainRequested && currentTime >= nextHostHeartbeatAt) {
28614
+ nextHostHeartbeatAt = now() + settings.hostHeartbeatMs;
28256
28615
  }
28257
- nextHostHeartbeatAt = now() + settings.hostHeartbeatMs;
28258
28616
  }
28259
28617
  while (recoveryQueue.length > 0 && active.size < settings.maxConcurrency) {
28260
28618
  const recovery = recoveryQueue.shift();
@@ -28285,15 +28643,19 @@ var init_runner = __esm({
28285
28643
  await this.persistReceipt(receipt, now);
28286
28644
  let claim;
28287
28645
  try {
28288
- claim = await retryExact(() => mcp.callTool(
28646
+ claim = await mcp.callTool(
28289
28647
  "inference.job.claim",
28290
28648
  request,
28291
28649
  { signal: this.options.signal }
28292
- ), { signal: this.options.signal });
28650
+ );
28293
28651
  assertClaimResult(request, claim);
28294
28652
  } catch (error48) {
28295
- if (!this.options.signal?.aborted) {
28296
- requestDrain(controlPlaneFatal(error48) ? "authority_lost" : "claim_failed");
28653
+ if (!this.options.signal?.aborted && controlPlaneFatal(error48)) {
28654
+ requestDrain("authority_lost");
28655
+ } else if (!this.options.signal?.aborted && retryableRemoteError(error48)) {
28656
+ nextClaimAt = now() + remoteRetryAfterMs(error48, 1e3);
28657
+ } else if (!this.options.signal?.aborted) {
28658
+ requestDrain("claim_failed");
28297
28659
  }
28298
28660
  break;
28299
28661
  }
@@ -28306,10 +28668,12 @@ var init_runner = __esm({
28306
28668
  if (this.options.once) requestDrain("once_complete");
28307
28669
  }
28308
28670
  if (drainRequested) break;
28309
- const wakeAt = Math.min(nextClaimAt, nextHostHeartbeatAt, Math.max(
28310
- now() + MIN_SLEEP_MS,
28311
- receipt.advertisement_expires_at ? Date.parse(receipt.advertisement_expires_at) - settings.advertisementRefreshLeadMs : now() + MIN_SLEEP_MS
28312
- ));
28671
+ const advertisementDueAt = nextAdvertisementAttemptAt > now() ? nextAdvertisementAttemptAt : receipt.advertisement_expires_at ? Date.parse(receipt.advertisement_expires_at) - settings.advertisementRefreshLeadMs : now() + MIN_SLEEP_MS;
28672
+ const wakeAt = Math.min(
28673
+ nextClaimAt,
28674
+ nextHostHeartbeatAt,
28675
+ Math.max(now() + MIN_SLEEP_MS, advertisementDueAt)
28676
+ );
28313
28677
  await Promise.race([
28314
28678
  sleep4(Math.max(MIN_SLEEP_MS, wakeAt - now())),
28315
28679
  drainSignal,
@@ -28653,6 +29017,9 @@ var init_runner = __esm({
28653
29017
  if (error48 instanceof InferenceHostRunnerError && error48.code === "terminal_outcome_unconfirmed") {
28654
29018
  throw error48;
28655
29019
  }
29020
+ if (error48 instanceof CodexAppServerError && error48.retryAtMs !== null && ["quota_exceeded", "codex_rate_limited"].includes(error48.code)) {
29021
+ options.onProviderCooldown?.(error48.retryAtMs);
29022
+ }
28656
29023
  const classified = classifyFailure(heartbeatFailure ?? error48, adapterResult);
28657
29024
  const heartbeatAmbiguous = ambiguousHeartbeatTransport(heartbeatFailure);
28658
29025
  const failure = heartbeatAmbiguous ? {
@@ -28703,7 +29070,7 @@ var init_runner = __esm({
28703
29070
  adapter_request_id: canReportEffective ? adapterResult?.adapterRequestId ?? null : null,
28704
29071
  adapter_response_id: canReportEffective ? adapterResult?.adapterResponseId ?? null : null
28705
29072
  },
28706
- usage: adapterResult ? reportedUsage(adapterResult) : null,
29073
+ usage: adapterResult ? reportedUsage(adapterResult) : error48 instanceof CodexAppServerError && error48.usage ? reportedTokenUsage(error48.usage) : null,
28707
29074
  failure_category: failure.category,
28708
29075
  failure_code: failure.code,
28709
29076
  retryable: failure.retryable,
@@ -28777,6 +29144,9 @@ import { join as join5, resolve as resolve4 } from "node:path";
28777
29144
  async function runInferenceHostCli(argv2, env = process.env, dependencies = {}) {
28778
29145
  const warnings = [];
28779
29146
  try {
29147
+ if (argv2.includes("--help") || argv2.includes("-h") || argv2[1] === "help") {
29148
+ return { exitCode: 0, stdout: INFERENCE_HOST_HELP, stderr: "" };
29149
+ }
28780
29150
  const parsed = parseInferenceHostArgs(argv2, env);
28781
29151
  const config2 = resolveInferenceHostConfig(env);
28782
29152
  if (parsed.command === "login") {
@@ -28794,6 +29164,9 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
28794
29164
  async () => await agentConnect(config2, parsed, dependencies, warnings)
28795
29165
  );
28796
29166
  }
29167
+ if (parsed.command === "agent-run") {
29168
+ return await agentRun(config2, parsed, dependencies, warnings);
29169
+ }
28797
29170
  if (parsed.command === "agent-next") {
28798
29171
  return await withAgentCommandLock(
28799
29172
  config2,
@@ -28828,7 +29201,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
28828
29201
  return await cleanupLogin(config2, parsed, dependencies, warnings, true);
28829
29202
  }
28830
29203
  throw new Error(
28831
- "Usage: vtx inference-host <login|codex-login|run|agent-connect|agent-next|agent-complete|agent-fail|status|doctor|logout|codex-logout|revoke> [--json]"
29204
+ "Usage: vtx inference-host <login|codex-login|run|agent-connect|agent-run|agent-next|agent-complete|agent-fail|status|doctor|logout|codex-logout|revoke> [--json]"
28832
29205
  );
28833
29206
  } catch (error48) {
28834
29207
  return {
@@ -28839,7 +29212,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
28839
29212
  };
28840
29213
  }
28841
29214
  }
28842
- var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, parsePositiveInteger, parseInferenceHostArgs, defaultOpenBrowser, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, agentOperationId, agentSession, agentConnect, agentNext, agentComplete, agentFail, withAgentCommandLock;
29215
+ var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, foregroundHostLockPath, AGENT_HEARTBEAT_INTERVAL_MS, AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS, retryableAgentHeartbeatError, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, INFERENCE_HOST_HELP, parsePositiveInteger, parseInferenceHostArgs, defaultOpenBrowser, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, agentOperationId, agentSession, agentConnect, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock;
28843
29216
  var init_cli = __esm({
28844
29217
  "lib/inference-host/cli.ts"() {
28845
29218
  "use strict";
@@ -28855,11 +29228,20 @@ var init_cli = __esm({
28855
29228
  init_crypto();
28856
29229
  init_oauth();
28857
29230
  init_runner();
29231
+ init_mcp_client();
28858
29232
  INFERENCE_HOST_CLI_VERSION = agent_cli_release_default.package_version;
28859
29233
  runtimeReceiptPath = (config2) => `${config2.statePath}.runtime.json`;
28860
29234
  codexRecoveryPath = (config2) => `${config2.statePath}.codex-recovery.json`;
28861
29235
  codexGuardianReceiptRoot = (config2) => `${config2.statePath}.codex-processes`;
28862
29236
  revocationCheckpointPath = (config2) => `${config2.statePath}.revoke.json`;
29237
+ foregroundHostLockPath = (config2) => `${config2.processLockPath}.foreground`;
29238
+ AGENT_HEARTBEAT_INTERVAL_MS = 3e3;
29239
+ AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS = 9e3;
29240
+ retryableAgentHeartbeatError = (error48) => {
29241
+ if (!(error48 instanceof ExternalInferenceMcpError)) return false;
29242
+ if (error48.code === "network_error" || error48.code === "request_timeout") return true;
29243
+ return error48.code === "transport_rejected" && /HTTP (?:408|425|429|5\d\d)\b/u.test(error48.message);
29244
+ };
28863
29245
  assertRevocationCheckpoint = (value) => {
28864
29246
  if (!value || typeof value !== "object" || Array.isArray(value)) {
28865
29247
  throw new Error("Inference host revocation checkpoint is invalid.");
@@ -28912,6 +29294,31 @@ var init_cli = __esm({
28912
29294
  render = (value, json2) => json2 ? `${JSON.stringify(value, null, 2)}
28913
29295
  ` : typeof value === "string" ? `${value}
28914
29296
  ` : `${JSON.stringify(value, null, 2)}
29297
+ `;
29298
+ INFERENCE_HOST_HELP = `Usage: vtx inference-host <command> [options]
29299
+
29300
+ Commands:
29301
+ login Authorize the isolated VTX insights:inference grant
29302
+ codex-login Sign the automated Codex host into a ChatGPT subscription
29303
+ run Run the automated Codex inference host in the foreground
29304
+ agent-connect Advertise a model from a compatible agent harness
29305
+ agent-run Keep an agent-driven host online in the foreground
29306
+ agent-next Claim the next exact VTX inference request
29307
+ agent-complete Submit one completed agent result from stdin
29308
+ agent-fail Submit one truthful agent failure from stdin
29309
+ status Inspect local host and credential state
29310
+ doctor Verify credentials, Codex, and private runtime state
29311
+ logout Remove local VTX host state without revoking the grant
29312
+ revoke Revoke the VTX grant and remove local host state
29313
+ codex-logout Remove the automated host's dedicated Codex login
29314
+
29315
+ Common options:
29316
+ --json Emit machine-readable JSON
29317
+ --help, -h Show this help
29318
+
29319
+ If the OS credential store cannot retain the VTX grant, set
29320
+ VTX_INFERENCE_HOST_CREDENTIAL_STORE=file before login to use the supported
29321
+ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
28915
29322
  `;
28916
29323
  parsePositiveInteger = (raw, label) => {
28917
29324
  const value = Number(raw);
@@ -29151,6 +29558,9 @@ var init_cli = __esm({
29151
29558
  acquireProcessLock: async () => borrowedProcessLock
29152
29559
  }, {
29153
29560
  displayName: options.displayName,
29561
+ authenticatedAccountEmail: options.authenticatedAccountEmail,
29562
+ authenticatedAccountPlan: options.authenticatedAccountPlan,
29563
+ codexRateLimits: options.codexRateLimits,
29154
29564
  protocolVersion: EXTERNAL_INFERENCE_CONTRACT_VERSION,
29155
29565
  adapterRuntimeVersion: INFERENCE_HOST_CLI_VERSION,
29156
29566
  maxConcurrency: options.maxConcurrency,
@@ -29489,7 +29899,18 @@ Waiting for approval...
29489
29899
  };
29490
29900
  cleanupLogin = async (config2, parsed, dependencies, warnings, revoke) => {
29491
29901
  const lock2 = await acquireInferenceHostProcessLock(config2.processLockPath);
29902
+ let keeperLock = null;
29492
29903
  try {
29904
+ try {
29905
+ keeperLock = await acquireInferenceHostProcessLock(foregroundHostLockPath(config2));
29906
+ } catch (error48) {
29907
+ if (error48 instanceof Error && error48.message.includes("Another inference host process already owns")) {
29908
+ throw new Error(
29909
+ "Stop vtx inference-host agent-run before logging out or revoking this host."
29910
+ );
29911
+ }
29912
+ throw error48;
29913
+ }
29493
29914
  if (!revoke) {
29494
29915
  await assertLocalRuntimeArtifactsMayBeDiscarded(config2);
29495
29916
  }
@@ -29592,13 +30013,16 @@ Waiting for approval...
29592
30013
  ` : ""
29593
30014
  };
29594
30015
  } finally {
30016
+ await keeperLock?.release();
29595
30017
  await lock2.release();
29596
30018
  }
29597
30019
  };
29598
30020
  runHost = async (config2, parsed, env, dependencies, warnings) => {
29599
30021
  const cancellation = lifecycleCancellation(dependencies);
30022
+ let foregroundLock = null;
29600
30023
  let processLock = null;
29601
30024
  try {
30025
+ foregroundLock = await acquireInferenceHostProcessLock(foregroundHostLockPath(config2));
29602
30026
  processLock = await acquireInferenceHostProcessLock(config2.processLockPath);
29603
30027
  cancellation.signal.throwIfAborted();
29604
30028
  if (await readRevocationCheckpoint(config2)) {
@@ -29620,7 +30044,7 @@ Waiting for approval...
29620
30044
  cancellation.signal.throwIfAborted();
29621
30045
  const hostResources = await (dependencies.createHostResources ?? createIsolatedCodexHostResources)(config2.codexHomePath);
29622
30046
  try {
29623
- await (dependencies.preflightCodex ?? preflightCodexSubscription)({
30047
+ const preflight = await (dependencies.preflightCodex ?? preflightCodexSubscription)({
29624
30048
  binary: verifiedBinary,
29625
30049
  codexHome: config2.codexHomePath,
29626
30050
  deadlineAtMs: Date.now() + 3e4,
@@ -29632,6 +30056,9 @@ Waiting for approval...
29632
30056
  verifiedBinary,
29633
30057
  hostResources,
29634
30058
  displayName: parsed.displayName,
30059
+ authenticatedAccountEmail: preflight?.authenticated_account_email ?? null,
30060
+ authenticatedAccountPlan: preflight?.authenticated_account_plan ?? null,
30061
+ codexRateLimits: preflight?.rate_limits ?? null,
29635
30062
  maxConcurrency: parsed.maxConcurrency,
29636
30063
  once: parsed.once,
29637
30064
  env,
@@ -29649,6 +30076,7 @@ Waiting for approval...
29649
30076
  }
29650
30077
  } finally {
29651
30078
  await processLock?.release();
30079
+ await foregroundLock?.release();
29652
30080
  cancellation.unregister();
29653
30081
  }
29654
30082
  };
@@ -29728,12 +30156,130 @@ Waiting for approval...
29728
30156
  lanes: ["main", "review", "screener"],
29729
30157
  response_modes: ["provider_response", "decision_candidate"],
29730
30158
  execution_modes: ["client", "server"],
29731
- next_command: "vtx inference-host agent-next --wait-seconds 50 --json"
30159
+ next_command: "vtx inference-host agent-next --wait-seconds 50 --json",
30160
+ keeper_command: "vtx inference-host agent-run"
29732
30161
  }, parsed.json),
29733
30162
  stderr: warnings.length > 0 ? `${warnings.join("\n")}
29734
30163
  ` : ""
29735
30164
  };
29736
30165
  };
30166
+ agentRun = async (config2, parsed, dependencies, warnings) => {
30167
+ const cancellation = lifecycleCancellation(dependencies);
30168
+ let keeperLock = null;
30169
+ let heartbeatCount = 0;
30170
+ try {
30171
+ keeperLock = await acquireInferenceHostProcessLock(foregroundHostLockPath(config2));
30172
+ const store = configuredCredentialStore(config2, dependencies, (message) => {
30173
+ warnings.push(message);
30174
+ });
30175
+ const session = await (dependencies.createAgentSession ?? createInferenceAgentMcpSession)({
30176
+ config: config2,
30177
+ credentialStore: store,
30178
+ clientVersion: INFERENCE_HOST_CLI_VERSION,
30179
+ signal: cancellation.signal
30180
+ });
30181
+ const emitStdout = dependencies.emitStdout ?? ((text) => {
30182
+ process.stdout.write(text);
30183
+ });
30184
+ const emitStderr = dependencies.emitStderr ?? ((text) => {
30185
+ process.stderr.write(text);
30186
+ });
30187
+ let consecutiveHeartbeatFailures = 0;
30188
+ let retryDelayMs = AGENT_HEARTBEAT_INTERVAL_MS;
30189
+ let pendingHeartbeatRequest = null;
30190
+ emitStdout(parsed.json ? `${JSON.stringify({ status: "running", host_id: session.localState.host_id })}
30191
+ ` : "Agent-driven inference host keeper is running.\n");
30192
+ while (!cancellation.signal.aborted) {
30193
+ let commandLock = null;
30194
+ try {
30195
+ commandLock = await acquireInferenceHostProcessLock(config2.processLockPath);
30196
+ } catch (error48) {
30197
+ if (!(error48 instanceof Error) || !error48.message.includes("Another inference host process already owns")) {
30198
+ throw error48;
30199
+ }
30200
+ }
30201
+ if (commandLock) {
30202
+ let heartbeatSuppressed = false;
30203
+ try {
30204
+ const active = await readInferenceAgentAttemptState(config2.statePath);
30205
+ const pendingNext = await readInferenceAgentNextState(config2.statePath);
30206
+ heartbeatSuppressed = Boolean(pendingNext && !active);
30207
+ if (heartbeatSuppressed) pendingHeartbeatRequest = null;
30208
+ if (!heartbeatSuppressed) {
30209
+ if (active && active.host_id !== session.localState.host_id) {
30210
+ throw new Error("Active agent-driven attempt belongs to another inference host.");
30211
+ }
30212
+ const activeAttemptId = active?.attempt_id ?? null;
30213
+ if (pendingHeartbeatRequest?.attempt_id !== activeAttemptId) {
30214
+ pendingHeartbeatRequest = null;
30215
+ }
30216
+ const heartbeatRequest = pendingHeartbeatRequest ?? {
30217
+ operation_id: agentOperationId("agent-heartbeat"),
30218
+ host_id: session.localState.host_id,
30219
+ attempt_id: activeAttemptId,
30220
+ requested_at: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
30221
+ };
30222
+ try {
30223
+ await session.client.callTool(
30224
+ "inference.agent.heartbeat",
30225
+ heartbeatRequest,
30226
+ { signal: cancellation.signal }
30227
+ );
30228
+ heartbeatCount += 1;
30229
+ pendingHeartbeatRequest = null;
30230
+ consecutiveHeartbeatFailures = 0;
30231
+ retryDelayMs = AGENT_HEARTBEAT_INTERVAL_MS;
30232
+ } catch (error48) {
30233
+ if (cancellation.signal.aborted) break;
30234
+ if (error48 instanceof ExternalInferenceMcpError && error48.definitivelyNotApplied) {
30235
+ pendingHeartbeatRequest = null;
30236
+ consecutiveHeartbeatFailures = 0;
30237
+ retryDelayMs = AGENT_HEARTBEAT_INTERVAL_MS;
30238
+ emitStderr(parsed.json ? `${JSON.stringify({
30239
+ status: "heartbeat_retry",
30240
+ retry_after_ms: retryDelayMs
30241
+ })}
30242
+ ` : `Agent-driven inference heartbeat was not applied; retrying in ${retryDelayMs}ms.
30243
+ `);
30244
+ } else {
30245
+ if (!retryableAgentHeartbeatError(error48)) throw error48;
30246
+ pendingHeartbeatRequest = heartbeatRequest;
30247
+ consecutiveHeartbeatFailures += 1;
30248
+ retryDelayMs = Math.min(
30249
+ AGENT_HEARTBEAT_INTERVAL_MS * 2 ** Math.max(0, consecutiveHeartbeatFailures - 1),
30250
+ AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS
30251
+ );
30252
+ const message = `Agent-driven inference heartbeat was temporarily unavailable; retrying in ${retryDelayMs}ms.
30253
+ `;
30254
+ emitStderr(parsed.json ? `${JSON.stringify({
30255
+ status: "heartbeat_retry",
30256
+ retry_after_ms: retryDelayMs
30257
+ })}
30258
+ ` : message);
30259
+ }
30260
+ }
30261
+ }
30262
+ } finally {
30263
+ await commandLock.release();
30264
+ }
30265
+ if (parsed.once && (heartbeatCount > 0 || heartbeatSuppressed)) break;
30266
+ }
30267
+ if (parsed.once && !commandLock) break;
30268
+ await (dependencies.sleep ?? (async (milliseconds) => {
30269
+ await new Promise((resolve5) => setTimeout(resolve5, milliseconds));
30270
+ }))(retryDelayMs);
30271
+ }
30272
+ return {
30273
+ exitCode: 0,
30274
+ stdout: render({ status: "stopped", heartbeats: heartbeatCount }, parsed.json),
30275
+ stderr: warnings.length > 0 ? `${warnings.join("\n")}
30276
+ ` : ""
30277
+ };
30278
+ } finally {
30279
+ await keeperLock?.release();
30280
+ cancellation.unregister();
30281
+ }
30282
+ };
29737
30283
  agentNext = async (config2, parsed, dependencies, warnings) => {
29738
30284
  const active = await readInferenceAgentAttemptState(config2.statePath);
29739
30285
  const recoveredNext = await readInferenceAgentNextState(config2.statePath);
@@ -48127,6 +48673,9 @@ Waiting for approval...
48127
48673
  }
48128
48674
  async function runVtxCli(argv2, env = process.env) {
48129
48675
  try {
48676
+ if (argv2.length === 0 || argv2.includes("--help") || argv2.includes("-h") || argv2[0] === "help") {
48677
+ return { exitCode: 0, stdout: VTX_CLI_HELP, stderr: "" };
48678
+ }
48130
48679
  const parsed = parseFlags(argv2);
48131
48680
  const [group, command, ...args] = parsed.rest;
48132
48681
  const config2 = resolveAgentCliConfig(env);
@@ -48374,7 +48923,7 @@ async function runVtxCli(argv2, env = process.env) {
48374
48923
  ` };
48375
48924
  }
48376
48925
  }
48377
- var WRITABLE_SECRET_FIELDS, delay;
48926
+ var VTX_CLI_HELP, WRITABLE_SECRET_FIELDS, delay;
48378
48927
  var init_vtx = __esm({
48379
48928
  "lib/agent-cli/vtx.ts"() {
48380
48929
  "use strict";
@@ -48383,6 +48932,24 @@ var init_vtx = __esm({
48383
48932
  init_headless_runtime();
48384
48933
  init_types();
48385
48934
  init_hyperliquid_market_symbol();
48935
+ VTX_CLI_HELP = `Usage: vtx [--json] [--profile <id>] <command>
48936
+
48937
+ Common commands:
48938
+ auth login Authorize the normal VTX CLI
48939
+ auth whoami Show the current VTX CLI identity
48940
+ profiles list List accessible profiles
48941
+ bots status Read the selected profile's Trader state
48942
+ bots start Start the normal VTX Trader
48943
+ bots stop Stop the normal VTX Trader
48944
+ runtime events Read recent runtime events and errors
48945
+ inference-host --help Set up an automated or agent-driven inference host
48946
+
48947
+ Global options:
48948
+ --json Emit machine-readable JSON
48949
+ --profile <id> Select one VTX profile
48950
+ --version, -v Show the installed CLI version
48951
+ --help, -h Show this help
48952
+ `;
48386
48953
  WRITABLE_SECRET_FIELDS = /* @__PURE__ */ new Set([
48387
48954
  "hyperliquid_signing_key",
48388
48955
  "local_ai_api_key",