@vtxmacro/cli 2026.8.30 → 2026.8.31
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/README.md +16 -0
- package/bin/vtx.js +403 -189
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,6 +71,22 @@ vtx inference-host codex-logout
|
|
|
71
71
|
vtx inference-host revoke
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
To connect another Codex subscription to the same VTX account, repeat the
|
|
75
|
+
login and service-install commands with a stable local name such as
|
|
76
|
+
`--instance codex-2`. Each named instance has an isolated VTX grant, Codex
|
|
77
|
+
home, credential file, runtime state, recovery state, and worker; one per-user
|
|
78
|
+
OS supervisor runs all installed instances. Use `service status --json` to
|
|
79
|
+
inspect the installed workers. The installer rejects duplicate authenticated
|
|
80
|
+
ChatGPT emails and fails closed when it cannot prove multiple subscriptions are
|
|
81
|
+
distinct. Use `service uninstall --instance <name>` to remove one worker;
|
|
82
|
+
unqualified `service uninstall` removes the whole supervisor. The legacy
|
|
83
|
+
unqualified host commands continue to target `default`.
|
|
84
|
+
|
|
85
|
+
Automated hosts use three concurrent slots per subscription by default. Set a
|
|
86
|
+
bounded value from 1 through 8 with `--max-concurrency`. Slots share the live
|
|
87
|
+
subscription rate-limit gate and cooldown; this does not guarantee capacity
|
|
88
|
+
beyond the authenticated account's current entitlement.
|
|
89
|
+
|
|
74
90
|
This durable host uses a separate least-privilege `insights:inference`
|
|
75
91
|
OAuth grant. It also keeps its ChatGPT subscription login in a dedicated private
|
|
76
92
|
Codex home. Neither credential is copied from or widens the ordinary CLI or Codex
|
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.
|
|
41
|
+
package_version: "2026.8.31",
|
|
42
42
|
codex_package_name: "@openai/codex",
|
|
43
43
|
codex_version: "0.147.0",
|
|
44
44
|
platforms: {
|
|
@@ -16084,13 +16084,26 @@ import { spawn } from "node:child_process";
|
|
|
16084
16084
|
import { constants } from "node:fs";
|
|
16085
16085
|
import { lstat, mkdir, open, readFile, realpath, rename, rm } from "node:fs/promises";
|
|
16086
16086
|
import { homedir } from "node:os";
|
|
16087
|
-
import { dirname, join, relative, resolve } from "node:path";
|
|
16087
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
16088
16088
|
function inferenceBaseDir(env) {
|
|
16089
16089
|
const configured = String(env.VTX_INFERENCE_HOST_HOME || "").trim();
|
|
16090
16090
|
return configured || join(homedir(), ".vtx", "inference-host");
|
|
16091
16091
|
}
|
|
16092
|
+
function normalizeInferenceHostInstanceName(raw) {
|
|
16093
|
+
const value = raw.trim().toLowerCase();
|
|
16094
|
+
if (!SAFE_INFERENCE_HOST_INSTANCE.test(value)) {
|
|
16095
|
+
throw new Error(
|
|
16096
|
+
"Inference host instance must be 1-48 lowercase letters, numbers, or hyphens, and cannot start or end with a hyphen."
|
|
16097
|
+
);
|
|
16098
|
+
}
|
|
16099
|
+
return value;
|
|
16100
|
+
}
|
|
16092
16101
|
function resolveInferenceHostConfig(env = process.env) {
|
|
16093
16102
|
const baseDir = inferenceBaseDir(env);
|
|
16103
|
+
const instanceName = normalizeInferenceHostInstanceName(
|
|
16104
|
+
String(env.VTX_INFERENCE_HOST_INSTANCE || DEFAULT_INFERENCE_HOST_INSTANCE)
|
|
16105
|
+
);
|
|
16106
|
+
const instanceDir = instanceName === DEFAULT_INFERENCE_HOST_INSTANCE ? baseDir : join(baseDir, "instances", instanceName);
|
|
16094
16107
|
const rawMode = String(env.VTX_INFERENCE_HOST_CREDENTIAL_STORE || "os").trim().toLowerCase();
|
|
16095
16108
|
if (rawMode !== "os" && rawMode !== "file") {
|
|
16096
16109
|
throw new Error("VTX_INFERENCE_HOST_CREDENTIAL_STORE must be os or file.");
|
|
@@ -16103,15 +16116,36 @@ function resolveInferenceHostConfig(env = process.env) {
|
|
|
16103
16116
|
"VTX_INFERENCE_HOST_CREDENTIAL_FILE requires explicit file credential-store mode."
|
|
16104
16117
|
);
|
|
16105
16118
|
}
|
|
16106
|
-
const credentialFilePath = rawMode === "file" ?
|
|
16119
|
+
const credentialFilePath = rawMode === "file" ? requireNamedInstancePath(
|
|
16120
|
+
instanceName,
|
|
16121
|
+
instanceDir,
|
|
16122
|
+
explicitCredentialPath,
|
|
16123
|
+
"VTX_INFERENCE_HOST_CREDENTIAL_FILE"
|
|
16124
|
+
) || join(instanceDir, "credentials.json") : null;
|
|
16125
|
+
const explicitStatePath = requireNamedInstancePath(
|
|
16126
|
+
instanceName,
|
|
16127
|
+
instanceDir,
|
|
16128
|
+
String(env.VTX_INFERENCE_HOST_STATE_PATH || "").trim(),
|
|
16129
|
+
"VTX_INFERENCE_HOST_STATE_PATH"
|
|
16130
|
+
);
|
|
16131
|
+
const explicitLockPath = requireNamedInstancePath(
|
|
16132
|
+
instanceName,
|
|
16133
|
+
instanceDir,
|
|
16134
|
+
String(env.VTX_INFERENCE_HOST_LOCK_PATH || "").trim(),
|
|
16135
|
+
"VTX_INFERENCE_HOST_LOCK_PATH"
|
|
16136
|
+
);
|
|
16107
16137
|
return {
|
|
16108
16138
|
apiUrl: String(env.VTX_API_URL || "https://api.vtxmacro.com").replace(/\/+$/, ""),
|
|
16139
|
+
baseDir,
|
|
16140
|
+
instanceName,
|
|
16109
16141
|
credentialStoreMode: rawMode,
|
|
16110
16142
|
credentialFilePath,
|
|
16111
16143
|
credentialStoreIdentity: credentialStoreIdentity(rawMode, credentialFilePath, env),
|
|
16112
|
-
codexHomePath: join(
|
|
16113
|
-
statePath:
|
|
16114
|
-
processLockPath:
|
|
16144
|
+
codexHomePath: join(instanceDir, "codex-home"),
|
|
16145
|
+
statePath: explicitStatePath || join(instanceDir, "state.json"),
|
|
16146
|
+
processLockPath: explicitLockPath || join(instanceDir, "host.lock"),
|
|
16147
|
+
supervisorStatePath: join(baseDir, "state.json"),
|
|
16148
|
+
supervisorProcessLockPath: join(baseDir, "host.lock")
|
|
16115
16149
|
};
|
|
16116
16150
|
}
|
|
16117
16151
|
function assertLocalState(value) {
|
|
@@ -16488,12 +16522,14 @@ async function acquireInferenceHostProcessLock(path, dependencies = {}) {
|
|
|
16488
16522
|
}
|
|
16489
16523
|
};
|
|
16490
16524
|
}
|
|
16491
|
-
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, WINDOWS_PRIVATE_ACL_SCRIPT, windowsPrivateAclInvocation, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, rebindHardenedWindowsAclAfterRename, rebindHardenedWindowsDirectoryAfterOwnedMutation, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, defaultCurrentProcessIdentity, processLockObservationCache, inferenceProcessIdentitiesMatch, credentialStoreIdentity;
|
|
16525
|
+
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, DEFAULT_CODEX_HOST_CONCURRENCY, MAX_CODEX_HOST_CONCURRENCY, WINDOWS_PRIVATE_ACL_SCRIPT, windowsPrivateAclInvocation, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, rebindHardenedWindowsAclAfterRename, rebindHardenedWindowsDirectoryAfterOwnedMutation, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, defaultCurrentProcessIdentity, processLockObservationCache, inferenceProcessIdentitiesMatch, DEFAULT_INFERENCE_HOST_INSTANCE, SAFE_INFERENCE_HOST_INSTANCE, requireNamedInstancePath, credentialStoreIdentity;
|
|
16492
16526
|
var init_config = __esm({
|
|
16493
16527
|
"lib/inference-host/config.ts"() {
|
|
16494
16528
|
"use strict";
|
|
16495
16529
|
INFERENCE_CREDENTIAL_NAMESPACE = "vtxmacro-insights-inference";
|
|
16496
16530
|
MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
|
|
16531
|
+
DEFAULT_CODEX_HOST_CONCURRENCY = 3;
|
|
16532
|
+
MAX_CODEX_HOST_CONCURRENCY = 8;
|
|
16497
16533
|
WINDOWS_PRIVATE_ACL_SCRIPT = `$ErrorActionPreference='Stop'
|
|
16498
16534
|
$path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($env:VTX_PRIVATE_PATH_B64))
|
|
16499
16535
|
$kind=$env:VTX_PRIVATE_PATH_KIND
|
|
@@ -16845,6 +16881,16 @@ if(-not $userFull) { throw 'private ACL does not grant the current user full con
|
|
|
16845
16881
|
};
|
|
16846
16882
|
processLockObservationCache = /* @__PURE__ */ new Map();
|
|
16847
16883
|
inferenceProcessIdentitiesMatch = (stored, observed) => stored === observed;
|
|
16884
|
+
DEFAULT_INFERENCE_HOST_INSTANCE = "default";
|
|
16885
|
+
SAFE_INFERENCE_HOST_INSTANCE = /^[a-z0-9](?:[a-z0-9-]{0,46}[a-z0-9])?$/u;
|
|
16886
|
+
requireNamedInstancePath = (instanceName, instanceDir, rawPath, label) => {
|
|
16887
|
+
if (!rawPath || instanceName === DEFAULT_INFERENCE_HOST_INSTANCE) return rawPath;
|
|
16888
|
+
const relativePath = relative(resolve(instanceDir), resolve(rawPath));
|
|
16889
|
+
if (relativePath === ".." || relativePath.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute(relativePath)) {
|
|
16890
|
+
throw new Error(`${label} for a named instance must stay inside its isolated instance directory.`);
|
|
16891
|
+
}
|
|
16892
|
+
return rawPath;
|
|
16893
|
+
};
|
|
16848
16894
|
credentialStoreIdentity = (mode, filePath, env) => {
|
|
16849
16895
|
if (mode === "file") {
|
|
16850
16896
|
if (!filePath) throw new Error("Inference credential fallback path is unavailable.");
|
|
@@ -19029,7 +19075,7 @@ var init_agent_state = __esm({
|
|
|
19029
19075
|
import { spawn as spawn3 } from "node:child_process";
|
|
19030
19076
|
import { chmod, lstat as lstat2, open as open2, readFile as readFile2, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
|
|
19031
19077
|
import { tmpdir } from "node:os";
|
|
19032
|
-
import { dirname as dirname2, isAbsolute, join as join2, resolve as resolve2, sep } from "node:path";
|
|
19078
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, resolve as resolve2, sep } from "node:path";
|
|
19033
19079
|
import { createInterface } from "node:readline";
|
|
19034
19080
|
async function loginCodexSubscription(options) {
|
|
19035
19081
|
const session = await CodexAppServerSession.start(options);
|
|
@@ -19726,7 +19772,10 @@ child.once('close', async () => {
|
|
|
19726
19772
|
title: "VTX External Inference Host",
|
|
19727
19773
|
version: "external_inference.v1"
|
|
19728
19774
|
},
|
|
19729
|
-
capabilities: {
|
|
19775
|
+
capabilities: {
|
|
19776
|
+
experimentalApi: true,
|
|
19777
|
+
optOutNotificationMethods: ["thread/started"]
|
|
19778
|
+
}
|
|
19730
19779
|
}, {
|
|
19731
19780
|
timeoutMs: Math.max(1, options.deadlineAtMs - Date.now()),
|
|
19732
19781
|
signal: options.signal
|
|
@@ -20297,7 +20346,7 @@ child.once('close', async () => {
|
|
|
20297
20346
|
const resolvedHome = resolve2(this.codexHome);
|
|
20298
20347
|
const resolvedThreadPath = resolve2(threadPath);
|
|
20299
20348
|
const resolvedSessionsRoot = join2(resolvedHome, "sessions");
|
|
20300
|
-
if (!threadId || !threadPath || !
|
|
20349
|
+
if (!threadId || !threadPath || !isAbsolute2(threadPath) || !resolvedThreadPath.startsWith(`${resolvedSessionsRoot}${sep}`) || !resolvedThreadPath.endsWith(".jsonl") || thread?.ephemeral !== false || thread?.modelProvider !== "openai" || !Array.isArray(thread?.turns) || thread.turns.length !== 0 || result2.model !== options.requestedModel || result2.modelProvider !== "openai" || result2.serviceTier !== "default" || result2.reasoningEffort !== options.requestedReasoningEffort || String(result2.cwd || "") !== options.workspacePath || !Array.isArray(result2.runtimeWorkspaceRoots) || result2.runtimeWorkspaceRoots.length !== 0 || !Array.isArray(result2.instructionSources) || result2.instructionSources.length !== 0 || result2.approvalPolicy !== "never" || result2.approvalsReviewer !== "user" || sandbox?.type !== "readOnly" || sandbox.networkAccess !== false || permission?.id !== CODEX_INFERENCE_PERMISSION_PROFILE || permission.extends !== null) {
|
|
20301
20350
|
throw new CodexAppServerError({
|
|
20302
20351
|
message: "Codex thread isolation or effective settings were invalid.",
|
|
20303
20352
|
category: "adapter",
|
|
@@ -20353,6 +20402,19 @@ child.once('close', async () => {
|
|
|
20353
20402
|
});
|
|
20354
20403
|
const startedAt = Date.now();
|
|
20355
20404
|
const unsubscribe = this.subscribe(({ method, params }) => {
|
|
20405
|
+
if (method === "thread/started") {
|
|
20406
|
+
const startedThread = objectOrNull(params.thread);
|
|
20407
|
+
if (!String(startedThread?.id || "")) {
|
|
20408
|
+
terminalReject(new CodexAppServerError({
|
|
20409
|
+
message: "Codex returned an invalid thread lifecycle notification.",
|
|
20410
|
+
category: "adapter",
|
|
20411
|
+
code: "invalid_thread_started_notification",
|
|
20412
|
+
retryable: false,
|
|
20413
|
+
dispatchOutcome: requestWritten ? turnId ? "confirmed_dispatched" : "outcome_unknown" : "not_dispatched"
|
|
20414
|
+
}));
|
|
20415
|
+
}
|
|
20416
|
+
return;
|
|
20417
|
+
}
|
|
20356
20418
|
const eventThreadId = String(params.threadId || "");
|
|
20357
20419
|
const scopedMethod = method.startsWith("thread/") || method.startsWith("turn/") || method.startsWith("item/") || method.startsWith("rawResponse") || method === "model/rerouted";
|
|
20358
20420
|
if (scopedMethod && !eventThreadId) {
|
|
@@ -20992,7 +21054,7 @@ import {
|
|
|
20992
21054
|
} from "node:fs/promises";
|
|
20993
21055
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
20994
21056
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
20995
|
-
import { isAbsolute as
|
|
21057
|
+
import { isAbsolute as isAbsolute3, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
20996
21058
|
var MAX_PROMPT_BYTES2, CODEX_MODEL_NAME_PATTERN, CODEX_REASONING_EFFORT_PATTERN, tokenUsageReceiptSchema, turnResultReceiptSchema, terminalReceiptSchema, recoveryCheckpointSchema, recoveryFileSchema, FileCodexAttemptRecoveryStore, utf8Bytes, assertAttemptActive, tomlString, permissionConfig, ensureDedicatedCodexHome, createIsolatedCodexAttemptResources, createIsolatedCodexHostResources, validateAttemptInput, isStrictDescendant, assertRecoveryResourceScope, removeRecoveredThread, confirmGuardianTerminatedForRecovery, reconcileCodexAttemptRecovery, CodexSubscriptionAdapter;
|
|
20997
21059
|
var init_codex_adapter = __esm({
|
|
20998
21060
|
"lib/inference-host/codex-adapter.ts"() {
|
|
@@ -21323,7 +21385,7 @@ var init_codex_adapter = __esm({
|
|
|
21323
21385
|
const parentPath = resolve3(parent);
|
|
21324
21386
|
const candidatePath = resolve3(candidate);
|
|
21325
21387
|
const scoped = relative2(parentPath, candidatePath);
|
|
21326
|
-
return scoped.length > 0 && !scoped.startsWith(`..${sep2}`) && scoped !== ".." && !
|
|
21388
|
+
return scoped.length > 0 && !scoped.startsWith(`..${sep2}`) && scoped !== ".." && !isAbsolute3(scoped);
|
|
21327
21389
|
};
|
|
21328
21390
|
assertRecoveryResourceScope = (checkpoint) => {
|
|
21329
21391
|
const temporaryRoot = resolve3(tmpdir2());
|
|
@@ -21413,7 +21475,7 @@ var init_codex_adapter = __esm({
|
|
|
21413
21475
|
}
|
|
21414
21476
|
}
|
|
21415
21477
|
if (checkpoint.threadPath !== null) {
|
|
21416
|
-
if (!
|
|
21478
|
+
if (!isAbsolute3(checkpoint.threadPath) || !isStrictDescendant(
|
|
21417
21479
|
checkpoint.threadPath,
|
|
21418
21480
|
sessionsRoot
|
|
21419
21481
|
) || !checkpoint.threadPath.endsWith(".jsonl")) {
|
|
@@ -28992,11 +29054,20 @@ var init_runner = __esm({
|
|
|
28992
29054
|
options.codexModelCapabilities,
|
|
28993
29055
|
options.adapterRuntimeVersion
|
|
28994
29056
|
),
|
|
28995
|
-
maxConcurrency:
|
|
28996
|
-
|
|
28997
|
-
|
|
28998
|
-
|
|
28999
|
-
|
|
29057
|
+
maxConcurrency: (() => {
|
|
29058
|
+
const value = finitePositiveOption(
|
|
29059
|
+
options.maxConcurrency,
|
|
29060
|
+
DEFAULT_MAX_CONCURRENCY,
|
|
29061
|
+
"Maximum concurrency"
|
|
29062
|
+
);
|
|
29063
|
+
if (value > MAX_CODEX_HOST_CONCURRENCY) {
|
|
29064
|
+
throw new InferenceHostRunnerError(
|
|
29065
|
+
"invalid_configuration",
|
|
29066
|
+
`Maximum concurrency must not exceed ${MAX_CODEX_HOST_CONCURRENCY}.`
|
|
29067
|
+
);
|
|
29068
|
+
}
|
|
29069
|
+
return value;
|
|
29070
|
+
})(),
|
|
29000
29071
|
advertisementTtlMs,
|
|
29001
29072
|
advertisementRefreshLeadMs,
|
|
29002
29073
|
hostHeartbeatMs: finitePositiveOption(
|
|
@@ -30335,7 +30406,7 @@ import { createWriteStream, readFileSync } from "node:fs";
|
|
|
30335
30406
|
import { access as access3, chmod as chmod3, mkdir as mkdir3, readFile as readFile5, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
|
|
30336
30407
|
import { homedir as homedir2 } from "node:os";
|
|
30337
30408
|
import { dirname as dirname4, join as join5, resolve as resolve4 } from "node:path";
|
|
30338
|
-
var SERVICE_NAME, SYSTEMD_UNIT, LAUNCHD_LABEL, SERVICE_COOPERATIVE_STOP_SECONDS, isWindowsSubsystemForLinux, inferenceHostServiceManifestPath, inferenceHostServiceDesiredPath, inferenceHostServiceLogPath, xmlEscape, plistEscape, systemdQuote, defaultRunCommand, managerName, assertManifest, assertDesiredState, readInferenceHostServiceManifest, readInferenceHostServiceDesired, readDesiredAcrossAtomicReplacement, writeDesired, runtimeEnvironment, serviceArguments, windowsOwnedCommandLine, vbScriptString, windowsServiceLauncher, windowsTaskXml, systemdUnit, launchAgentPlist, InferenceHostServiceManager, appendServiceLog, spawnServiceChild, runInferenceHostServiceSupervisor;
|
|
30409
|
+
var SERVICE_NAME, SYSTEMD_UNIT, LAUNCHD_LABEL, SERVICE_COOPERATIVE_STOP_SECONDS, isWindowsSubsystemForLinux, inferenceHostServiceManifestPath, inferenceHostServiceDesiredPath, inferenceHostServiceLogPath, xmlEscape, plistEscape, systemdQuote, defaultRunCommand, managerName, assertRuntimeEnvironment, assertServicePath, assertWorker, assertManifest, assertDesiredState, readInferenceHostServiceManifest, readInferenceHostServiceDesired, readDesiredAcrossAtomicReplacement, writeDesired, runtimeEnvironment, serviceArguments, windowsOwnedCommandLine, vbScriptString, windowsServiceLauncher, windowsTaskXml, systemdUnit, launchAgentPlist, InferenceHostServiceManager, appendServiceLog, spawnServiceChild, runInferenceHostServiceSupervisor;
|
|
30339
30410
|
var init_service = __esm({
|
|
30340
30411
|
"lib/inference-host/service.ts"() {
|
|
30341
30412
|
"use strict";
|
|
@@ -30353,9 +30424,9 @@ var init_service = __esm({
|
|
|
30353
30424
|
}
|
|
30354
30425
|
})())
|
|
30355
30426
|
);
|
|
30356
|
-
inferenceHostServiceManifestPath = (config2) => `${config2.
|
|
30357
|
-
inferenceHostServiceDesiredPath = (config2) => `${config2.
|
|
30358
|
-
inferenceHostServiceLogPath = (config2) => `${config2.
|
|
30427
|
+
inferenceHostServiceManifestPath = (config2) => `${config2.supervisorStatePath}.service.json`;
|
|
30428
|
+
inferenceHostServiceDesiredPath = (config2) => `${config2.supervisorStatePath}.service-desired.json`;
|
|
30429
|
+
inferenceHostServiceLogPath = (config2) => `${config2.supervisorStatePath}.service.log`;
|
|
30359
30430
|
xmlEscape = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30360
30431
|
plistEscape = xmlEscape;
|
|
30361
30432
|
systemdQuote = (value) => `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("%", "%%")}"`;
|
|
@@ -30385,29 +30456,79 @@ var init_service = __esm({
|
|
|
30385
30456
|
if (platform === "linux") return "systemd-user";
|
|
30386
30457
|
throw new Error(`Inference-host background service is unsupported on ${platform}.`);
|
|
30387
30458
|
};
|
|
30459
|
+
assertRuntimeEnvironment = (value) => {
|
|
30460
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30461
|
+
throw new Error("Inference-host service runtime environment is invalid.");
|
|
30462
|
+
}
|
|
30463
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
30464
|
+
if (!key.startsWith("VTX_") || typeof entry !== "string") {
|
|
30465
|
+
throw new Error("Inference-host service runtime environment is invalid.");
|
|
30466
|
+
}
|
|
30467
|
+
}
|
|
30468
|
+
return value;
|
|
30469
|
+
};
|
|
30470
|
+
assertServicePath = (value) => {
|
|
30471
|
+
if (typeof value !== "string" || !value || /[\r\n\0]/u.test(value)) {
|
|
30472
|
+
throw new Error("Inference-host service manifest paths contain control characters.");
|
|
30473
|
+
}
|
|
30474
|
+
return value;
|
|
30475
|
+
};
|
|
30476
|
+
assertWorker = (value) => {
|
|
30477
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30478
|
+
throw new Error("Inference-host service worker is invalid.");
|
|
30479
|
+
}
|
|
30480
|
+
const record2 = value;
|
|
30481
|
+
if (typeof record2.instance_name !== "string" || !/^[a-z0-9](?:[a-z0-9-]{0,46}[a-z0-9])?$/u.test(record2.instance_name) || record2.adapter !== "codex" || typeof record2.display_name !== "string" || !record2.display_name || !Number.isSafeInteger(record2.max_concurrency) || Number(record2.max_concurrency) < 1 || Number(record2.max_concurrency) > MAX_CODEX_HOST_CONCURRENCY || record2.authenticated_account_email !== null && typeof record2.authenticated_account_email !== "string" || record2.authenticated_account_plan !== null && typeof record2.authenticated_account_plan !== "string") {
|
|
30482
|
+
throw new Error("Inference-host service worker is invalid.");
|
|
30483
|
+
}
|
|
30484
|
+
return {
|
|
30485
|
+
instance_name: record2.instance_name,
|
|
30486
|
+
adapter: "codex",
|
|
30487
|
+
display_name: record2.display_name,
|
|
30488
|
+
max_concurrency: Number(record2.max_concurrency),
|
|
30489
|
+
authenticated_account_email: record2.authenticated_account_email,
|
|
30490
|
+
authenticated_account_plan: record2.authenticated_account_plan,
|
|
30491
|
+
runtime_environment: assertRuntimeEnvironment(record2.runtime_environment)
|
|
30492
|
+
};
|
|
30493
|
+
};
|
|
30388
30494
|
assertManifest = (value) => {
|
|
30389
30495
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30390
30496
|
throw new Error("Inference-host service manifest is invalid.");
|
|
30391
30497
|
}
|
|
30392
30498
|
const record2 = value;
|
|
30393
|
-
if (record2.schema_version
|
|
30394
|
-
|
|
30499
|
+
if (record2.schema_version === "vtx_inference_service_v1") {
|
|
30500
|
+
const legacy = record2;
|
|
30501
|
+
if (legacy.adapter !== "codex" || typeof legacy.installed_at !== "string" || !Number.isFinite(Date.parse(legacy.installed_at)) || typeof legacy.executable !== "string" || !legacy.executable || typeof legacy.script !== "string" || !legacy.script || typeof legacy.display_name !== "string" || !legacy.display_name || typeof legacy.log_path !== "string" || !legacy.log_path) throw new Error("Inference-host service manifest is invalid.");
|
|
30502
|
+
const runtime_environment = assertRuntimeEnvironment(legacy.runtime_environment);
|
|
30503
|
+
const worker = assertWorker({
|
|
30504
|
+
instance_name: "default",
|
|
30505
|
+
adapter: "codex",
|
|
30506
|
+
display_name: legacy.display_name,
|
|
30507
|
+
max_concurrency: Number(runtime_environment.VTX_INFERENCE_HOST_MAX_CONCURRENCY || 1),
|
|
30508
|
+
authenticated_account_email: null,
|
|
30509
|
+
authenticated_account_plan: null,
|
|
30510
|
+
runtime_environment
|
|
30511
|
+
});
|
|
30512
|
+
return {
|
|
30513
|
+
schema_version: "vtx_inference_service_v2",
|
|
30514
|
+
installed_at: legacy.installed_at,
|
|
30515
|
+
executable: assertServicePath(legacy.executable),
|
|
30516
|
+
script: assertServicePath(legacy.script),
|
|
30517
|
+
log_path: assertServicePath(legacy.log_path),
|
|
30518
|
+
workers: [worker]
|
|
30519
|
+
};
|
|
30395
30520
|
}
|
|
30396
|
-
|
|
30397
|
-
|
|
30398
|
-
record2.script,
|
|
30399
|
-
record2.log_path
|
|
30400
|
-
]) {
|
|
30401
|
-
if (typeof value2 === "string" && /[\r\n\0]/u.test(value2)) {
|
|
30402
|
-
throw new Error("Inference-host service manifest paths contain control characters.");
|
|
30403
|
-
}
|
|
30521
|
+
if (record2.schema_version !== "vtx_inference_service_v2" || typeof record2.installed_at !== "string" || !Number.isFinite(Date.parse(record2.installed_at)) || typeof record2.executable !== "string" || !record2.executable || typeof record2.script !== "string" || !record2.script || typeof record2.log_path !== "string" || !record2.log_path || !Array.isArray(record2.workers) || record2.workers.length < 1) {
|
|
30522
|
+
throw new Error("Inference-host service manifest is invalid.");
|
|
30404
30523
|
}
|
|
30405
|
-
|
|
30406
|
-
|
|
30407
|
-
|
|
30408
|
-
|
|
30524
|
+
assertServicePath(record2.executable);
|
|
30525
|
+
assertServicePath(record2.script);
|
|
30526
|
+
assertServicePath(record2.log_path);
|
|
30527
|
+
const workers = record2.workers.map(assertWorker);
|
|
30528
|
+
if (new Set(workers.map((worker) => worker.instance_name)).size !== workers.length) {
|
|
30529
|
+
throw new Error("Inference-host service worker names must be unique.");
|
|
30409
30530
|
}
|
|
30410
|
-
return record2;
|
|
30531
|
+
return { ...record2, workers };
|
|
30411
30532
|
};
|
|
30412
30533
|
assertDesiredState = (value) => {
|
|
30413
30534
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -30459,13 +30580,15 @@ var init_service = __esm({
|
|
|
30459
30580
|
}, null, 2)}
|
|
30460
30581
|
`);
|
|
30461
30582
|
};
|
|
30462
|
-
runtimeEnvironment = (config2) => {
|
|
30583
|
+
runtimeEnvironment = (config2, maxConcurrency) => {
|
|
30463
30584
|
const result2 = {
|
|
30464
30585
|
VTX_API_URL: config2.apiUrl,
|
|
30465
|
-
VTX_INFERENCE_HOST_HOME:
|
|
30586
|
+
VTX_INFERENCE_HOST_HOME: config2.baseDir,
|
|
30587
|
+
VTX_INFERENCE_HOST_INSTANCE: config2.instanceName,
|
|
30466
30588
|
VTX_INFERENCE_HOST_CREDENTIAL_STORE: config2.credentialStoreMode,
|
|
30467
30589
|
VTX_INFERENCE_HOST_STATE_PATH: config2.statePath,
|
|
30468
|
-
VTX_INFERENCE_HOST_LOCK_PATH: config2.processLockPath
|
|
30590
|
+
VTX_INFERENCE_HOST_LOCK_PATH: config2.processLockPath,
|
|
30591
|
+
VTX_INFERENCE_HOST_MAX_CONCURRENCY: String(maxConcurrency)
|
|
30469
30592
|
};
|
|
30470
30593
|
if (config2.credentialFilePath) {
|
|
30471
30594
|
result2.VTX_INFERENCE_HOST_CREDENTIAL_FILE = config2.credentialFilePath;
|
|
@@ -30581,7 +30704,7 @@ WantedBy=default.target
|
|
|
30581
30704
|
return inferenceHostServiceLogPath(this.config);
|
|
30582
30705
|
}
|
|
30583
30706
|
controlLockPath() {
|
|
30584
|
-
return `${this.config.
|
|
30707
|
+
return `${this.config.supervisorProcessLockPath}.service-control`;
|
|
30585
30708
|
}
|
|
30586
30709
|
async withControlLock(operation) {
|
|
30587
30710
|
let lock2 = null;
|
|
@@ -30617,12 +30740,12 @@ WantedBy=default.target
|
|
|
30617
30740
|
];
|
|
30618
30741
|
}
|
|
30619
30742
|
definitionPath() {
|
|
30620
|
-
if (this.platform === "win32") return `${this.config.
|
|
30743
|
+
if (this.platform === "win32") return `${this.config.supervisorStatePath}.service-task.xml`;
|
|
30621
30744
|
if (this.platform === "darwin") return join5(this.home, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
30622
30745
|
return join5(this.home, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
30623
30746
|
}
|
|
30624
30747
|
windowsLauncherPath() {
|
|
30625
|
-
return `${this.config.
|
|
30748
|
+
return `${this.config.supervisorStatePath}.service-launcher.vbs`;
|
|
30626
30749
|
}
|
|
30627
30750
|
async managerCommand(action) {
|
|
30628
30751
|
const definition = this.definitionPath();
|
|
@@ -30665,37 +30788,19 @@ WantedBy=default.target
|
|
|
30665
30788
|
}
|
|
30666
30789
|
throw new Error("Background service did not reach an active state within 10 seconds.");
|
|
30667
30790
|
}
|
|
30668
|
-
async
|
|
30669
|
-
|
|
30670
|
-
|
|
30671
|
-
async installUnlocked(options) {
|
|
30672
|
-
if (await readInferenceHostServiceManifest(this.manifestPath())) {
|
|
30673
|
-
await this.uninstallUnlocked();
|
|
30674
|
-
}
|
|
30675
|
-
await access3(this.executable);
|
|
30676
|
-
await access3(this.script);
|
|
30677
|
-
const manifest = assertManifest({
|
|
30678
|
-
schema_version: "vtx_inference_service_v1",
|
|
30679
|
-
installed_at: this.now().toISOString(),
|
|
30680
|
-
adapter: options.adapter,
|
|
30681
|
-
executable: this.executable,
|
|
30682
|
-
script: this.script,
|
|
30683
|
-
display_name: options.displayName,
|
|
30684
|
-
log_path: this.logPath(),
|
|
30685
|
-
runtime_environment: runtimeEnvironment(this.config)
|
|
30686
|
-
});
|
|
30687
|
-
const args = serviceArguments(this.script, this.manifestPath());
|
|
30688
|
-
const definition = this.platform === "win32" ? windowsTaskXml(this.windowsLauncherPath(), this.windowsDirectory, this.username) : this.platform === "darwin" ? launchAgentPlist(this.executable, args, this.logPath()) : systemdUnit(this.executable, args);
|
|
30791
|
+
async registerManifestUnlocked(manifest, desiredRunning) {
|
|
30792
|
+
const args = serviceArguments(manifest.script, this.manifestPath());
|
|
30793
|
+
const definition = this.platform === "win32" ? windowsTaskXml(this.windowsLauncherPath(), this.windowsDirectory, this.username) : this.platform === "darwin" ? launchAgentPlist(manifest.executable, args, manifest.log_path) : systemdUnit(manifest.executable, args);
|
|
30689
30794
|
let managerInstallAttempted = false;
|
|
30690
30795
|
try {
|
|
30691
30796
|
await writeAtomicInferencePrivateFile(this.manifestPath(), `${JSON.stringify(manifest, null, 2)}
|
|
30692
30797
|
`);
|
|
30693
|
-
await writeDesired(this.desiredPath(),
|
|
30798
|
+
await writeDesired(this.desiredPath(), desiredRunning, this.now());
|
|
30694
30799
|
await mkdir3(dirname4(this.definitionPath()), { recursive: true, mode: 448 });
|
|
30695
30800
|
if (this.platform === "win32") {
|
|
30696
30801
|
await writeAtomicInferencePrivateFile(
|
|
30697
30802
|
this.windowsLauncherPath(),
|
|
30698
|
-
windowsServiceLauncher(
|
|
30803
|
+
windowsServiceLauncher(manifest.executable, args)
|
|
30699
30804
|
);
|
|
30700
30805
|
await writeFile2(this.definitionPath(), `\uFEFF${definition}`, {
|
|
30701
30806
|
encoding: "utf16le",
|
|
@@ -30712,7 +30817,7 @@ WantedBy=default.target
|
|
|
30712
30817
|
managerInstallAttempted = true;
|
|
30713
30818
|
const installed = await this.managerCommand("install");
|
|
30714
30819
|
if (installed.exitCode !== 0) throw new Error(`Background service installation failed: ${installed.stderr.trim()}`);
|
|
30715
|
-
if (
|
|
30820
|
+
if (desiredRunning) {
|
|
30716
30821
|
const started = await this.managerCommand("start");
|
|
30717
30822
|
if (started.exitCode !== 0 && !/already running|in progress/iu.test(`${started.stdout}
|
|
30718
30823
|
${started.stderr}`)) {
|
|
@@ -30720,6 +30825,7 @@ ${started.stderr}`)) {
|
|
|
30720
30825
|
}
|
|
30721
30826
|
await this.waitForManagerActive();
|
|
30722
30827
|
}
|
|
30828
|
+
return await this.status();
|
|
30723
30829
|
} catch (error48) {
|
|
30724
30830
|
await writeDesired(this.desiredPath(), false, this.now()).catch(() => void 0);
|
|
30725
30831
|
if (managerInstallAttempted) {
|
|
@@ -30747,7 +30853,83 @@ ${cleanup.stderr}`)) {
|
|
|
30747
30853
|
}
|
|
30748
30854
|
throw error48;
|
|
30749
30855
|
}
|
|
30750
|
-
|
|
30856
|
+
}
|
|
30857
|
+
async replaceManifestUnlocked(next, desiredRunning) {
|
|
30858
|
+
const previous = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30859
|
+
const previousDesired = previous ? await readInferenceHostServiceDesired(this.desiredPath()) : false;
|
|
30860
|
+
if (previous) await this.uninstallUnlocked();
|
|
30861
|
+
try {
|
|
30862
|
+
return await this.registerManifestUnlocked(next, desiredRunning);
|
|
30863
|
+
} catch (error48) {
|
|
30864
|
+
if (!previous) throw error48;
|
|
30865
|
+
try {
|
|
30866
|
+
await this.registerManifestUnlocked(previous, previousDesired);
|
|
30867
|
+
} catch (rollbackError) {
|
|
30868
|
+
throw new Error(
|
|
30869
|
+
"Inference-host service reconfiguration failed and the previous supervisor could not be restored.",
|
|
30870
|
+
{ cause: new AggregateError([error48, rollbackError]) }
|
|
30871
|
+
);
|
|
30872
|
+
}
|
|
30873
|
+
throw new Error(
|
|
30874
|
+
"Inference-host service reconfiguration failed; the previous supervisor was restored.",
|
|
30875
|
+
{ cause: error48 }
|
|
30876
|
+
);
|
|
30877
|
+
}
|
|
30878
|
+
}
|
|
30879
|
+
async install(options) {
|
|
30880
|
+
return await this.withControlLock(async () => await this.installUnlocked(options));
|
|
30881
|
+
}
|
|
30882
|
+
async installUnlocked(options) {
|
|
30883
|
+
const existing = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30884
|
+
const normalizedEmail = options.authenticatedAccountEmail?.trim().toLowerCase() || null;
|
|
30885
|
+
const otherWorkers = existing?.workers.filter(
|
|
30886
|
+
(worker) => worker.instance_name !== this.config.instanceName
|
|
30887
|
+
) ?? [];
|
|
30888
|
+
if (otherWorkers.length > 0 && (!normalizedEmail || otherWorkers.some((worker) => !worker.authenticated_account_email))) {
|
|
30889
|
+
throw new Error(
|
|
30890
|
+
"Cannot prove that every installed instance uses a distinct ChatGPT subscription. Reinstall instances with live account identity before adding another."
|
|
30891
|
+
);
|
|
30892
|
+
}
|
|
30893
|
+
if (normalizedEmail && otherWorkers.some((worker) => worker.authenticated_account_email?.trim().toLowerCase() === normalizedEmail)) {
|
|
30894
|
+
throw new Error(
|
|
30895
|
+
"This ChatGPT subscription is already installed under another inference-host instance."
|
|
30896
|
+
);
|
|
30897
|
+
}
|
|
30898
|
+
if (this.config.credentialFilePath && otherWorkers.some((worker) => {
|
|
30899
|
+
const otherPath = worker.runtime_environment.VTX_INFERENCE_HOST_CREDENTIAL_FILE;
|
|
30900
|
+
return otherPath && resolve4(otherPath) === resolve4(this.config.credentialFilePath);
|
|
30901
|
+
})) {
|
|
30902
|
+
throw new Error(
|
|
30903
|
+
"Each inference-host instance must use a different private credential file."
|
|
30904
|
+
);
|
|
30905
|
+
}
|
|
30906
|
+
await access3(this.executable);
|
|
30907
|
+
await access3(this.script);
|
|
30908
|
+
const maxConcurrency = options.maxConcurrency ?? 1;
|
|
30909
|
+
const workers = [
|
|
30910
|
+
...existing?.workers.filter((worker) => worker.instance_name !== this.config.instanceName) ?? [],
|
|
30911
|
+
{
|
|
30912
|
+
instance_name: this.config.instanceName,
|
|
30913
|
+
adapter: options.adapter,
|
|
30914
|
+
display_name: options.displayName,
|
|
30915
|
+
max_concurrency: maxConcurrency,
|
|
30916
|
+
authenticated_account_email: normalizedEmail,
|
|
30917
|
+
authenticated_account_plan: options.authenticatedAccountPlan ?? null,
|
|
30918
|
+
runtime_environment: runtimeEnvironment(this.config, maxConcurrency)
|
|
30919
|
+
}
|
|
30920
|
+
].sort((left, right) => left.instance_name.localeCompare(right.instance_name));
|
|
30921
|
+
const manifest = assertManifest({
|
|
30922
|
+
schema_version: "vtx_inference_service_v2",
|
|
30923
|
+
installed_at: this.now().toISOString(),
|
|
30924
|
+
executable: this.executable,
|
|
30925
|
+
script: this.script,
|
|
30926
|
+
log_path: this.logPath(),
|
|
30927
|
+
workers
|
|
30928
|
+
});
|
|
30929
|
+
return await this.replaceManifestUnlocked(
|
|
30930
|
+
manifest,
|
|
30931
|
+
options.startImmediately !== false
|
|
30932
|
+
);
|
|
30751
30933
|
}
|
|
30752
30934
|
async start() {
|
|
30753
30935
|
return await this.withControlLock(async () => await this.startUnlocked());
|
|
@@ -30774,11 +30956,12 @@ ${result2.stderr}`)) {
|
|
|
30774
30956
|
return await this.withControlLock(async () => await this.stopUnlocked());
|
|
30775
30957
|
}
|
|
30776
30958
|
async stopUnlocked() {
|
|
30777
|
-
|
|
30959
|
+
const manifest = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30960
|
+
if (!manifest) {
|
|
30778
30961
|
throw new Error("Inference-host service is not installed.");
|
|
30779
30962
|
}
|
|
30780
30963
|
await writeDesired(this.desiredPath(), false, this.now());
|
|
30781
|
-
const serviceLockPath = `${this.config.
|
|
30964
|
+
const serviceLockPath = `${this.config.supervisorProcessLockPath}.service`;
|
|
30782
30965
|
let serviceReleased = false;
|
|
30783
30966
|
for (let attempt = 0; attempt < this.stopWaitAttempts; attempt += 1) {
|
|
30784
30967
|
try {
|
|
@@ -30796,7 +30979,7 @@ ${result2.stderr}`)) {
|
|
|
30796
30979
|
}
|
|
30797
30980
|
if (!serviceReleased) {
|
|
30798
30981
|
throw new Error(
|
|
30799
|
-
`Inference-host
|
|
30982
|
+
`Inference-host workers did not stop cooperatively within ${SERVICE_COOPERATIVE_STOP_SECONDS} seconds; refusing forced termination while cleanup may be pending.`
|
|
30800
30983
|
);
|
|
30801
30984
|
}
|
|
30802
30985
|
const result2 = await this.managerCommand("stop");
|
|
@@ -30822,8 +31005,15 @@ ${result2.stderr}`)) {
|
|
|
30822
31005
|
manager_active: managerActive,
|
|
30823
31006
|
manager: managerName(this.platform),
|
|
30824
31007
|
manager_state: result2.exitCode === 0 ? output3 || "installed" : "not-installed",
|
|
30825
|
-
adapter: manifest
|
|
30826
|
-
log_path: manifest?.log_path ?? this.logPath()
|
|
31008
|
+
adapter: manifest ? "codex" : null,
|
|
31009
|
+
log_path: manifest?.log_path ?? this.logPath(),
|
|
31010
|
+
workers: manifest?.workers.map((worker) => ({
|
|
31011
|
+
instance_name: worker.instance_name,
|
|
31012
|
+
display_name: worker.display_name,
|
|
31013
|
+
max_concurrency: worker.max_concurrency,
|
|
31014
|
+
authenticated_account_email: worker.authenticated_account_email,
|
|
31015
|
+
authenticated_account_plan: worker.authenticated_account_plan
|
|
31016
|
+
})) ?? []
|
|
30827
31017
|
};
|
|
30828
31018
|
}
|
|
30829
31019
|
async logs(lines = 100) {
|
|
@@ -30838,6 +31028,24 @@ ${result2.stderr}`)) {
|
|
|
30838
31028
|
throw error48;
|
|
30839
31029
|
}
|
|
30840
31030
|
}
|
|
31031
|
+
async uninstallInstance(instanceName) {
|
|
31032
|
+
return await this.withControlLock(async () => {
|
|
31033
|
+
const manifest = await readInferenceHostServiceManifest(this.manifestPath());
|
|
31034
|
+
if (!manifest) throw new Error("Inference-host service is not installed.");
|
|
31035
|
+
if (!manifest.workers.some((worker) => worker.instance_name === instanceName)) {
|
|
31036
|
+
throw new Error(`Inference-host instance ${instanceName} is not installed.`);
|
|
31037
|
+
}
|
|
31038
|
+
const remaining = manifest.workers.filter(
|
|
31039
|
+
(worker) => worker.instance_name !== instanceName
|
|
31040
|
+
);
|
|
31041
|
+
if (remaining.length === 0) return await this.uninstallUnlocked();
|
|
31042
|
+
return await this.replaceManifestUnlocked({
|
|
31043
|
+
...manifest,
|
|
31044
|
+
installed_at: this.now().toISOString(),
|
|
31045
|
+
workers: remaining
|
|
31046
|
+
}, await readInferenceHostServiceDesired(this.desiredPath()));
|
|
31047
|
+
});
|
|
31048
|
+
}
|
|
30841
31049
|
async uninstall() {
|
|
30842
31050
|
return await this.withControlLock(async () => await this.uninstallUnlocked());
|
|
30843
31051
|
}
|
|
@@ -30867,7 +31075,8 @@ ${result2.stderr}`)) {
|
|
|
30867
31075
|
manager: managerName(this.platform),
|
|
30868
31076
|
manager_state: "not-installed",
|
|
30869
31077
|
adapter: null,
|
|
30870
|
-
log_path: manifest.log_path
|
|
31078
|
+
log_path: manifest.log_path,
|
|
31079
|
+
workers: []
|
|
30871
31080
|
};
|
|
30872
31081
|
}
|
|
30873
31082
|
};
|
|
@@ -30880,21 +31089,21 @@ ${result2.stderr}`)) {
|
|
|
30880
31089
|
`, resolvePromise);
|
|
30881
31090
|
});
|
|
30882
31091
|
};
|
|
30883
|
-
spawnServiceChild = async (manifest, signal) => {
|
|
31092
|
+
spawnServiceChild = async (manifest, worker, signal) => {
|
|
30884
31093
|
const args = [
|
|
30885
31094
|
manifest.script,
|
|
30886
31095
|
"inference-host",
|
|
30887
31096
|
"run",
|
|
30888
31097
|
"--json",
|
|
30889
31098
|
"--display-name",
|
|
30890
|
-
|
|
31099
|
+
worker.display_name
|
|
30891
31100
|
];
|
|
30892
31101
|
const startedAt = Date.now();
|
|
30893
31102
|
const log = createWriteStream(manifest.log_path, { flags: "a", mode: 384 });
|
|
30894
31103
|
return await new Promise((resolvePromise, reject) => {
|
|
30895
31104
|
let stdout = "";
|
|
30896
31105
|
const child = spawn5(manifest.executable, args, {
|
|
30897
|
-
env: { ...process.env, ...
|
|
31106
|
+
env: { ...process.env, ...worker.runtime_environment },
|
|
30898
31107
|
windowsHide: true,
|
|
30899
31108
|
stdio: ["ignore", "pipe", "pipe"]
|
|
30900
31109
|
});
|
|
@@ -30938,64 +31147,72 @@ ${result2.stderr}`)) {
|
|
|
30938
31147
|
runInferenceHostServiceSupervisor = async (manifestPath, options = {}) => {
|
|
30939
31148
|
const manifest = await readInferenceHostServiceManifest(manifestPath);
|
|
30940
31149
|
if (!manifest) throw new Error("Inference-host service manifest is missing.");
|
|
30941
|
-
const desiredPath =
|
|
31150
|
+
const desiredPath = manifestPath.replace(/\.service\.json$/u, ".service-desired.json");
|
|
30942
31151
|
const signal = options.signal ?? new AbortController().signal;
|
|
30943
31152
|
const sleep4 = options.sleep ?? (async (milliseconds) => {
|
|
30944
31153
|
await new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
|
|
30945
31154
|
});
|
|
30946
31155
|
const launch = options.runWorker ?? options.spawnChild ?? spawnServiceChild;
|
|
30947
|
-
|
|
30948
|
-
|
|
30949
|
-
|
|
30950
|
-
|
|
30951
|
-
|
|
30952
|
-
|
|
30953
|
-
|
|
30954
|
-
let workerComplete = false;
|
|
30955
|
-
let monitorError = null;
|
|
30956
|
-
const desiredMonitor = (async () => {
|
|
30957
|
-
while (!workerComplete && !workerController.signal.aborted) {
|
|
30958
|
-
await sleep4(500);
|
|
30959
|
-
if (!await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
30960
|
-
workerController.abort();
|
|
30961
|
-
break;
|
|
30962
|
-
}
|
|
30963
|
-
}
|
|
30964
|
-
})().catch((error48) => {
|
|
30965
|
-
monitorError = error48;
|
|
30966
|
-
workerController.abort();
|
|
30967
|
-
});
|
|
30968
|
-
let result2;
|
|
31156
|
+
await appendServiceLog(manifest.log_path, "service_supervisor_started", {
|
|
31157
|
+
adapter: "codex",
|
|
31158
|
+
instances: manifest.workers.map((worker) => worker.instance_name)
|
|
31159
|
+
});
|
|
31160
|
+
const superviseWorker = async (worker) => {
|
|
31161
|
+
let failures = 0;
|
|
31162
|
+
while (!signal.aborted && await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
30969
31163
|
try {
|
|
30970
|
-
|
|
30971
|
-
|
|
30972
|
-
|
|
30973
|
-
|
|
30974
|
-
|
|
30975
|
-
|
|
30976
|
-
|
|
30977
|
-
|
|
30978
|
-
|
|
30979
|
-
|
|
30980
|
-
|
|
30981
|
-
|
|
30982
|
-
|
|
30983
|
-
|
|
30984
|
-
|
|
30985
|
-
|
|
30986
|
-
|
|
30987
|
-
|
|
30988
|
-
|
|
30989
|
-
|
|
30990
|
-
|
|
30991
|
-
|
|
30992
|
-
|
|
30993
|
-
|
|
30994
|
-
|
|
30995
|
-
|
|
30996
|
-
|
|
31164
|
+
const workerController = new AbortController();
|
|
31165
|
+
const forwardAbort = () => workerController.abort();
|
|
31166
|
+
signal.addEventListener("abort", forwardAbort, { once: true });
|
|
31167
|
+
let workerComplete = false;
|
|
31168
|
+
let monitorError = null;
|
|
31169
|
+
const desiredMonitor = (async () => {
|
|
31170
|
+
while (!workerComplete && !workerController.signal.aborted) {
|
|
31171
|
+
await sleep4(500);
|
|
31172
|
+
if (!await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
31173
|
+
workerController.abort();
|
|
31174
|
+
break;
|
|
31175
|
+
}
|
|
31176
|
+
}
|
|
31177
|
+
})().catch((error48) => {
|
|
31178
|
+
monitorError = error48;
|
|
31179
|
+
workerController.abort();
|
|
31180
|
+
});
|
|
31181
|
+
let result2;
|
|
31182
|
+
try {
|
|
31183
|
+
result2 = await launch(manifest, worker, workerController.signal);
|
|
31184
|
+
} finally {
|
|
31185
|
+
workerComplete = true;
|
|
31186
|
+
workerController.abort();
|
|
31187
|
+
signal.removeEventListener("abort", forwardAbort);
|
|
31188
|
+
await desiredMonitor;
|
|
31189
|
+
}
|
|
31190
|
+
if (monitorError) throw monitorError;
|
|
31191
|
+
if (signal.aborted || !await readDesiredAcrossAtomicReplacement(desiredPath)) break;
|
|
31192
|
+
failures = result2.uptimeMs >= 6e4 ? 0 : failures + 1;
|
|
31193
|
+
const retryAfterMs = Math.min(1e3 * 2 ** Math.min(failures, 5), 3e4);
|
|
31194
|
+
await appendServiceLog(manifest.log_path, "worker_exited", {
|
|
31195
|
+
instance_name: worker.instance_name,
|
|
31196
|
+
exit_code: result2.exitCode,
|
|
31197
|
+
uptime_ms: result2.uptimeMs,
|
|
31198
|
+
drain_reason: result2.drainReason ?? null,
|
|
31199
|
+
retry_after_ms: retryAfterMs
|
|
31200
|
+
});
|
|
31201
|
+
await sleep4(retryAfterMs);
|
|
31202
|
+
} catch (error48) {
|
|
31203
|
+
if (signal.aborted) break;
|
|
31204
|
+
failures += 1;
|
|
31205
|
+
const retryAfterMs = Math.min(1e3 * 2 ** Math.min(failures, 5), 3e4);
|
|
31206
|
+
await appendServiceLog(manifest.log_path, "worker_launch_failed", {
|
|
31207
|
+
instance_name: worker.instance_name,
|
|
31208
|
+
error: error48 instanceof Error ? error48.message : "unknown",
|
|
31209
|
+
retry_after_ms: retryAfterMs
|
|
31210
|
+
});
|
|
31211
|
+
await sleep4(retryAfterMs);
|
|
31212
|
+
}
|
|
30997
31213
|
}
|
|
30998
|
-
}
|
|
31214
|
+
};
|
|
31215
|
+
await Promise.all(manifest.workers.map(superviseWorker));
|
|
30999
31216
|
await appendServiceLog(manifest.log_path, "service_supervisor_stopped");
|
|
31000
31217
|
};
|
|
31001
31218
|
}
|
|
@@ -31085,7 +31302,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
31085
31302
|
};
|
|
31086
31303
|
}
|
|
31087
31304
|
}
|
|
31088
|
-
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,
|
|
31305
|
+
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, parseHostConcurrency, parseInferenceHostArgs, defaultOpenBrowser, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertDurableServiceUninstalled, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, agentOperationId, agentSession, agentConnect, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock, serviceCommand, hasExplicitCredentialStoreConfiguration, commandUsesInstalledServiceCredentials, resolveInferenceHostCommandConfig;
|
|
31089
31306
|
var init_cli = __esm({
|
|
31090
31307
|
"lib/inference-host/cli.ts"() {
|
|
31091
31308
|
"use strict";
|
|
@@ -31189,6 +31406,8 @@ Commands:
|
|
|
31189
31406
|
|
|
31190
31407
|
Common options:
|
|
31191
31408
|
--json Emit machine-readable JSON
|
|
31409
|
+
--instance NAME Target an isolated local subscription instance (default: default)
|
|
31410
|
+
--max-concurrency N Automated Codex slots for this subscription (1-8; default: 3)
|
|
31192
31411
|
--help, -h Show this help
|
|
31193
31412
|
|
|
31194
31413
|
If the OS credential store cannot retain the VTX grant, set
|
|
@@ -31196,23 +31415,31 @@ VTX_INFERENCE_HOST_CREDENTIAL_STORE=file before login to use the supported
|
|
|
31196
31415
|
private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
31197
31416
|
|
|
31198
31417
|
Durable service:
|
|
31199
|
-
vtx inference-host
|
|
31418
|
+
vtx inference-host login --instance codex-1
|
|
31419
|
+
vtx inference-host codex-login --instance codex-1
|
|
31420
|
+
vtx inference-host service install --instance codex-1
|
|
31421
|
+
vtx inference-host login --instance codex-2
|
|
31422
|
+
vtx inference-host codex-login --instance codex-2
|
|
31423
|
+
vtx inference-host service install --instance codex-2
|
|
31424
|
+
vtx inference-host service uninstall --instance codex-2
|
|
31200
31425
|
vtx inference-host service <start|stop|status|logs|uninstall>
|
|
31201
31426
|
`;
|
|
31202
|
-
|
|
31427
|
+
parseHostConcurrency = (raw, label) => {
|
|
31203
31428
|
const value = Number(raw);
|
|
31204
|
-
if (value
|
|
31205
|
-
throw new Error(`${label} must be
|
|
31429
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_CODEX_HOST_CONCURRENCY) {
|
|
31430
|
+
throw new Error(`${label} must be an integer from 1 through ${MAX_CODEX_HOST_CONCURRENCY}.`);
|
|
31206
31431
|
}
|
|
31207
31432
|
return value;
|
|
31208
31433
|
};
|
|
31209
31434
|
parseInferenceHostArgs = (argv2, env) => {
|
|
31210
31435
|
let json2 = String(env.VTX_OUTPUT_JSON || "").trim().toLowerCase() === "true";
|
|
31211
31436
|
let once = false;
|
|
31212
|
-
let maxConcurrency =
|
|
31213
|
-
String(env.VTX_INFERENCE_HOST_MAX_CONCURRENCY ||
|
|
31437
|
+
let maxConcurrency = parseHostConcurrency(
|
|
31438
|
+
String(env.VTX_INFERENCE_HOST_MAX_CONCURRENCY || DEFAULT_CODEX_HOST_CONCURRENCY),
|
|
31214
31439
|
"VTX_INFERENCE_HOST_MAX_CONCURRENCY"
|
|
31215
31440
|
);
|
|
31441
|
+
let instanceName = String(env.VTX_INFERENCE_HOST_INSTANCE || "default").trim();
|
|
31442
|
+
let instanceExplicit = Boolean(String(env.VTX_INFERENCE_HOST_INSTANCE || "").trim());
|
|
31216
31443
|
let displayName = String(env.VTX_INFERENCE_HOST_DISPLAY_NAME || "").trim() || "Codex subscription host";
|
|
31217
31444
|
let displayNameExplicit = Boolean(String(env.VTX_INFERENCE_HOST_DISPLAY_NAME || "").trim());
|
|
31218
31445
|
let adapter = null;
|
|
@@ -31236,7 +31463,7 @@ Durable service:
|
|
|
31236
31463
|
if (argument === "--max-concurrency") {
|
|
31237
31464
|
const raw = argv2[index + 1];
|
|
31238
31465
|
if (!raw) throw new Error("--max-concurrency requires a value.");
|
|
31239
|
-
maxConcurrency =
|
|
31466
|
+
maxConcurrency = parseHostConcurrency(raw, "--max-concurrency");
|
|
31240
31467
|
index += 1;
|
|
31241
31468
|
continue;
|
|
31242
31469
|
}
|
|
@@ -31248,7 +31475,7 @@ Durable service:
|
|
|
31248
31475
|
index += 1;
|
|
31249
31476
|
continue;
|
|
31250
31477
|
}
|
|
31251
|
-
if (["--adapter", "--model", "--model-label", "--effort", "--wait-seconds", "--lines", "--service-manifest"].includes(argument)) {
|
|
31478
|
+
if (["--adapter", "--model", "--model-label", "--effort", "--wait-seconds", "--lines", "--service-manifest", "--instance"].includes(argument)) {
|
|
31252
31479
|
const raw = argv2[index + 1];
|
|
31253
31480
|
if (!raw?.trim()) throw new Error(`${argument} requires a value.`);
|
|
31254
31481
|
if (argument === "--adapter") adapter = raw.trim();
|
|
@@ -31268,6 +31495,10 @@ Durable service:
|
|
|
31268
31495
|
}
|
|
31269
31496
|
}
|
|
31270
31497
|
if (argument === "--service-manifest") serviceManifestPath = resolve5(raw.trim());
|
|
31498
|
+
if (argument === "--instance") {
|
|
31499
|
+
instanceName = raw.trim();
|
|
31500
|
+
instanceExplicit = true;
|
|
31501
|
+
}
|
|
31271
31502
|
index += 1;
|
|
31272
31503
|
continue;
|
|
31273
31504
|
}
|
|
@@ -31295,6 +31526,8 @@ Durable service:
|
|
|
31295
31526
|
json: json2,
|
|
31296
31527
|
once,
|
|
31297
31528
|
maxConcurrency,
|
|
31529
|
+
instanceName,
|
|
31530
|
+
instanceExplicit,
|
|
31298
31531
|
displayName,
|
|
31299
31532
|
adapter,
|
|
31300
31533
|
modelId,
|
|
@@ -31406,9 +31639,10 @@ Durable service:
|
|
|
31406
31639
|
await clearInferenceHostLocalState(config2.statePath);
|
|
31407
31640
|
};
|
|
31408
31641
|
assertDurableServiceUninstalled = async (config2) => {
|
|
31409
|
-
|
|
31642
|
+
const manifest = await readInferenceHostServiceManifest(`${config2.supervisorStatePath}.service.json`);
|
|
31643
|
+
if (manifest?.workers.some((worker) => worker.instance_name === config2.instanceName)) {
|
|
31410
31644
|
throw new Error(
|
|
31411
|
-
|
|
31645
|
+
`Uninstall the durable inference-host service before changing credentials for instance ${config2.instanceName}.`
|
|
31412
31646
|
);
|
|
31413
31647
|
}
|
|
31414
31648
|
};
|
|
@@ -32436,55 +32670,19 @@ Waiting for approval...
|
|
|
32436
32670
|
if (!parsed.serviceManifestPath) throw new Error("Internal service manifest path is required.");
|
|
32437
32671
|
const serviceManifest = await readInferenceHostServiceManifest(parsed.serviceManifestPath);
|
|
32438
32672
|
if (!serviceManifest) throw new Error("Inference-host service manifest is missing.");
|
|
32439
|
-
const
|
|
32673
|
+
const supervisorConfig = resolveInferenceHostConfig({
|
|
32440
32674
|
...env,
|
|
32441
|
-
...serviceManifest.runtime_environment
|
|
32675
|
+
...serviceManifest.workers[0].runtime_environment
|
|
32442
32676
|
});
|
|
32443
32677
|
const serviceLock = await acquireInferenceHostProcessLock(
|
|
32444
|
-
`${
|
|
32678
|
+
`${supervisorConfig.supervisorProcessLockPath}.service`
|
|
32445
32679
|
);
|
|
32446
32680
|
const cancellation = lifecycleCancellation(dependencies);
|
|
32447
32681
|
try {
|
|
32448
32682
|
await (dependencies.runServiceSupervisor ?? runInferenceHostServiceSupervisor)(
|
|
32449
32683
|
parsed.serviceManifestPath,
|
|
32450
32684
|
{
|
|
32451
|
-
signal: cancellation.signal
|
|
32452
|
-
runWorker: async (manifest, signal) => {
|
|
32453
|
-
const startedAt = Date.now();
|
|
32454
|
-
const serviceEnv = { ...env, ...manifest.runtime_environment };
|
|
32455
|
-
const serviceConfig2 = resolveInferenceHostConfig(serviceEnv);
|
|
32456
|
-
const unregister = (abort) => {
|
|
32457
|
-
const onAbort = () => abort("SIGTERM");
|
|
32458
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
32459
|
-
return () => signal.removeEventListener("abort", onAbort);
|
|
32460
|
-
};
|
|
32461
|
-
const result2 = await runHost(serviceConfig2, {
|
|
32462
|
-
...parsed,
|
|
32463
|
-
command: "run",
|
|
32464
|
-
serviceAction: null,
|
|
32465
|
-
serviceManifestPath: null,
|
|
32466
|
-
displayName: manifest.display_name,
|
|
32467
|
-
once: false
|
|
32468
|
-
}, serviceEnv, {
|
|
32469
|
-
...dependencies,
|
|
32470
|
-
registerLifecycleSignalHandlers: unregister
|
|
32471
|
-
}, warnings);
|
|
32472
|
-
let drainReason = null;
|
|
32473
|
-
try {
|
|
32474
|
-
const summary = JSON.parse(result2.stdout);
|
|
32475
|
-
if (summary && typeof summary === "object" && !Array.isArray(summary) && typeof summary.drain_reason === "string" && /^[a-z0-9_]{1,96}$/u.test(
|
|
32476
|
-
summary.drain_reason
|
|
32477
|
-
)) {
|
|
32478
|
-
drainReason = summary.drain_reason;
|
|
32479
|
-
}
|
|
32480
|
-
} catch {
|
|
32481
|
-
}
|
|
32482
|
-
return {
|
|
32483
|
-
exitCode: result2.exitCode,
|
|
32484
|
-
uptimeMs: Date.now() - startedAt,
|
|
32485
|
-
drainReason
|
|
32486
|
-
};
|
|
32487
|
-
}
|
|
32685
|
+
signal: cancellation.signal
|
|
32488
32686
|
}
|
|
32489
32687
|
);
|
|
32490
32688
|
return { exitCode: 0, stdout: "", stderr: "" };
|
|
@@ -32518,12 +32716,18 @@ Waiting for approval...
|
|
|
32518
32716
|
throw new Error("Run vtx inference-host codex-login before installing the automated Codex service.");
|
|
32519
32717
|
}
|
|
32520
32718
|
const binary = await (dependencies.resolveBinary ?? resolvePinnedCodexBinary)(env);
|
|
32521
|
-
await (dependencies.preflightCodex ?? preflightCodexSubscription)({
|
|
32719
|
+
const preflight = await (dependencies.preflightCodex ?? preflightCodexSubscription)({
|
|
32522
32720
|
binary,
|
|
32523
32721
|
codexHome: config2.codexHomePath,
|
|
32524
32722
|
deadlineAtMs: Date.now() + 3e4
|
|
32525
32723
|
});
|
|
32526
|
-
const status = await manager.install({
|
|
32724
|
+
const status = await manager.install({
|
|
32725
|
+
adapter: "codex",
|
|
32726
|
+
displayName: parsed.displayName,
|
|
32727
|
+
maxConcurrency: parsed.maxConcurrency,
|
|
32728
|
+
authenticatedAccountEmail: preflight?.authenticated_account_email ?? null,
|
|
32729
|
+
authenticatedAccountPlan: preflight?.authenticated_account_plan ?? null
|
|
32730
|
+
});
|
|
32527
32731
|
return {
|
|
32528
32732
|
exitCode: 0,
|
|
32529
32733
|
stdout: render({ status: "service_installed", ...status }, parsed.json),
|
|
@@ -32549,7 +32753,8 @@ Waiting for approval...
|
|
|
32549
32753
|
return { exitCode: lifecycleMatches ? 0 : 1, stdout: render(status, parsed.json), stderr: "" };
|
|
32550
32754
|
}
|
|
32551
32755
|
if (action === "uninstall") {
|
|
32552
|
-
|
|
32756
|
+
const status = parsed.instanceExplicit ? await manager.uninstallInstance(config2.instanceName) : await manager.uninstall();
|
|
32757
|
+
return { exitCode: 0, stdout: render({ status: "service_uninstalled", ...status }, parsed.json), stderr: "" };
|
|
32553
32758
|
}
|
|
32554
32759
|
throw new Error("Usage: vtx inference-host service <install|start|stop|status|logs|uninstall>.");
|
|
32555
32760
|
};
|
|
@@ -32558,16 +32763,20 @@ Waiting for approval...
|
|
|
32558
32763
|
);
|
|
32559
32764
|
commandUsesInstalledServiceCredentials = (parsed) => parsed.command === "status" || parsed.command === "doctor" || parsed.command === "service" && parsed.serviceAction === "install";
|
|
32560
32765
|
resolveInferenceHostCommandConfig = async (parsed, env) => {
|
|
32561
|
-
const
|
|
32766
|
+
const selectedEnv = {
|
|
32767
|
+
...env,
|
|
32768
|
+
VTX_INFERENCE_HOST_INSTANCE: parsed.instanceName
|
|
32769
|
+
};
|
|
32770
|
+
const baseConfig = resolveInferenceHostConfig(selectedEnv);
|
|
32562
32771
|
if (!commandUsesInstalledServiceCredentials(parsed) || hasExplicitCredentialStoreConfiguration(env)) {
|
|
32563
32772
|
return baseConfig;
|
|
32564
32773
|
}
|
|
32565
|
-
const manifestPath = `${baseConfig.
|
|
32774
|
+
const manifestPath = `${baseConfig.supervisorStatePath}.service.json`;
|
|
32566
32775
|
const manifest = await readInferenceHostServiceManifest(manifestPath);
|
|
32567
32776
|
if (!manifest) return baseConfig;
|
|
32568
32777
|
const installedConfig = resolveInferenceHostConfig({
|
|
32569
|
-
...
|
|
32570
|
-
...manifest.runtime_environment
|
|
32778
|
+
...selectedEnv,
|
|
32779
|
+
...manifest.workers.find((worker) => worker.instance_name === baseConfig.instanceName)?.runtime_environment
|
|
32571
32780
|
});
|
|
32572
32781
|
if (resolve5(installedConfig.statePath) !== resolve5(baseConfig.statePath)) {
|
|
32573
32782
|
throw new Error(
|
|
@@ -49994,7 +50203,11 @@ function buildHeadlessExchangeConfig(input) {
|
|
|
49994
50203
|
user_fills_ttl_seconds: readCacheNumberField("user_fills_ttl_seconds"),
|
|
49995
50204
|
stale_if_429_max_age_seconds: readCacheNumberField("stale_if_429_max_age_seconds")
|
|
49996
50205
|
},
|
|
49997
|
-
client_runtime_hyperliquid_case_sensitive_symbols: Array.isArray(input.client_runtime_hyperliquid_case_sensitive_symbols) ? input.client_runtime_hyperliquid_case_sensitive_symbols : null
|
|
50206
|
+
client_runtime_hyperliquid_case_sensitive_symbols: Array.isArray(input.client_runtime_hyperliquid_case_sensitive_symbols) ? input.client_runtime_hyperliquid_case_sensitive_symbols : null,
|
|
50207
|
+
client_runtime_hyperliquid_perp_dexs: input.client_runtime_hyperliquid_perp_dexs ? {
|
|
50208
|
+
enabled: input.client_runtime_hyperliquid_perp_dexs.enabled === true,
|
|
50209
|
+
allowed_dexes: Array.isArray(input.client_runtime_hyperliquid_perp_dexs.allowed_dexes) ? input.client_runtime_hyperliquid_perp_dexs.allowed_dexes.map((dex) => String(dex).trim()).filter(Boolean) : []
|
|
50210
|
+
} : void 0
|
|
49998
50211
|
};
|
|
49999
50212
|
}
|
|
50000
50213
|
async function fetchLocalHyperliquidSnapshot(input) {
|
|
@@ -50010,7 +50223,7 @@ async function fetchLocalHyperliquidSnapshot(input) {
|
|
|
50010
50223
|
symbol: input.symbol,
|
|
50011
50224
|
tickerPrice: 0,
|
|
50012
50225
|
leverage,
|
|
50013
|
-
aggregatePerpDexs:
|
|
50226
|
+
aggregatePerpDexs: true
|
|
50014
50227
|
});
|
|
50015
50228
|
const clientExchangeSnapshot = buildClientExchangeSnapshot({
|
|
50016
50229
|
walletAddress,
|
|
@@ -51041,7 +51254,8 @@ var INFERENCE_HOST_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
51041
51254
|
"--effort",
|
|
51042
51255
|
"--wait-seconds",
|
|
51043
51256
|
"--lines",
|
|
51044
|
-
"--service-manifest"
|
|
51257
|
+
"--service-manifest",
|
|
51258
|
+
"--instance"
|
|
51045
51259
|
]);
|
|
51046
51260
|
var isInferenceHostCliInvocation = (argv2) => {
|
|
51047
51261
|
for (let index = 0; index < argv2.length; index += 1) {
|