@vtxmacro/cli 2026.8.18 → 2026.8.20
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 +21 -7
- package/bin/vtx.js +1535 -220
- package/package.json +2 -2
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.20",
|
|
42
42
|
codex_package_name: "@openai/codex",
|
|
43
43
|
codex_version: "0.147.0",
|
|
44
44
|
platforms: {
|
|
@@ -16080,10 +16080,11 @@ var init_external_inference_contract = __esm({
|
|
|
16080
16080
|
|
|
16081
16081
|
// lib/inference-host/config.ts
|
|
16082
16082
|
import { randomBytes } from "node:crypto";
|
|
16083
|
+
import { spawn } from "node:child_process";
|
|
16083
16084
|
import { constants } from "node:fs";
|
|
16084
16085
|
import { lstat, mkdir, open, readFile, realpath, rename, rm } from "node:fs/promises";
|
|
16085
16086
|
import { homedir } from "node:os";
|
|
16086
|
-
import { dirname, join, resolve } from "node:path";
|
|
16087
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
16087
16088
|
function inferenceBaseDir(env) {
|
|
16088
16089
|
const configured = String(env.VTX_INFERENCE_HOST_HOME || "").trim();
|
|
16089
16090
|
return configured || join(homedir(), ".vtx", "inference-host");
|
|
@@ -16132,6 +16133,7 @@ function assertLocalState(value) {
|
|
|
16132
16133
|
return record2;
|
|
16133
16134
|
}
|
|
16134
16135
|
async function ensureInferencePrivateDirectory(path) {
|
|
16136
|
+
let created = false;
|
|
16135
16137
|
try {
|
|
16136
16138
|
const before = await lstat(path);
|
|
16137
16139
|
if (before.isSymbolicLink() || !before.isDirectory()) {
|
|
@@ -16140,22 +16142,26 @@ async function ensureInferencePrivateDirectory(path) {
|
|
|
16140
16142
|
} catch (error48) {
|
|
16141
16143
|
if (error48.code !== "ENOENT") throw error48;
|
|
16142
16144
|
await mkdir(path, { recursive: true, mode: 448 });
|
|
16145
|
+
created = true;
|
|
16143
16146
|
}
|
|
16144
16147
|
const after = await lstat(path);
|
|
16145
16148
|
if (after.isSymbolicLink() || !after.isDirectory()) {
|
|
16146
16149
|
throw new Error("Inference host state directory is unsafe.");
|
|
16147
16150
|
}
|
|
16148
|
-
if (process.platform
|
|
16149
|
-
if (
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16151
|
+
if (process.platform === "win32") {
|
|
16152
|
+
if (created) await secureWindowsPrivatePath(path, "directory", "harden");
|
|
16153
|
+
else await secureExistingWindowsPath(path, "directory");
|
|
16154
|
+
return;
|
|
16155
|
+
}
|
|
16156
|
+
if ((after.mode & 63) !== 0) {
|
|
16157
|
+
throw new Error("Inference host state directory must have mode 0700.");
|
|
16158
|
+
}
|
|
16159
|
+
if (typeof process.getuid === "function" && after.uid !== process.getuid()) {
|
|
16160
|
+
throw new Error("Inference host state directory must be owned by the current user.");
|
|
16161
|
+
}
|
|
16162
|
+
const canonical = await realpath(path);
|
|
16163
|
+
if (canonical !== resolve(path)) {
|
|
16164
|
+
throw new Error("Inference host state directory may not traverse symbolic links.");
|
|
16159
16165
|
}
|
|
16160
16166
|
}
|
|
16161
16167
|
async function syncInferenceDirectory(path, platform = process.platform) {
|
|
@@ -16188,8 +16194,12 @@ async function writeAtomicInferencePrivateFile(path, contents) {
|
|
|
16188
16194
|
throw error48;
|
|
16189
16195
|
}
|
|
16190
16196
|
await handle.close();
|
|
16197
|
+
await secureWindowsPrivatePath(temporary, "file", "harden");
|
|
16191
16198
|
try {
|
|
16199
|
+
invalidateWindowsAclCache(path);
|
|
16192
16200
|
await rename(temporary, path);
|
|
16201
|
+
invalidateWindowsAclCache(temporary);
|
|
16202
|
+
await secureWindowsPrivatePath(path, "file", "verify");
|
|
16193
16203
|
await syncInferenceDirectory(directory);
|
|
16194
16204
|
} catch (error48) {
|
|
16195
16205
|
await rm(temporary, { force: true }).catch(() => void 0);
|
|
@@ -16207,6 +16217,8 @@ async function readInferencePrivateFile(path, label) {
|
|
|
16207
16217
|
if (before.isSymbolicLink() || !before.isFile()) {
|
|
16208
16218
|
throw new Error(`${label} is unsafe.`);
|
|
16209
16219
|
}
|
|
16220
|
+
await secureExistingWindowsPath(dirname(path), "directory");
|
|
16221
|
+
await secureExistingWindowsPath(path, "file");
|
|
16210
16222
|
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
16211
16223
|
try {
|
|
16212
16224
|
const opened = await handle.stat();
|
|
@@ -16227,7 +16239,10 @@ async function clearInferencePrivateFile(path, label) {
|
|
|
16227
16239
|
if (metadata.isSymbolicLink() || !metadata.isFile()) {
|
|
16228
16240
|
throw new Error(`${label} is unsafe.`);
|
|
16229
16241
|
}
|
|
16242
|
+
await secureExistingWindowsPath(dirname(path), "directory");
|
|
16243
|
+
await secureExistingWindowsPath(path, "file");
|
|
16230
16244
|
await rm(path);
|
|
16245
|
+
invalidateWindowsAclCache(path);
|
|
16231
16246
|
await syncInferenceDirectory(dirname(path));
|
|
16232
16247
|
} catch (error48) {
|
|
16233
16248
|
if (error48.code !== "ENOENT") throw error48;
|
|
@@ -16257,10 +16272,21 @@ async function writeInferenceHostLocalState(path, state) {
|
|
|
16257
16272
|
async function clearInferenceHostLocalState(path) {
|
|
16258
16273
|
await clearInferencePrivateFile(path, "Inference host local state file");
|
|
16259
16274
|
}
|
|
16260
|
-
async function acquireInferenceHostProcessLock(path) {
|
|
16275
|
+
async function acquireInferenceHostProcessLock(path, dependencies = {}) {
|
|
16261
16276
|
const directory = dirname(path);
|
|
16262
16277
|
await ensureInferencePrivateDirectory(directory);
|
|
16263
16278
|
const ownerToken = randomBytes(24).toString("base64url");
|
|
16279
|
+
const observeIdentity = dependencies.processIdentity ?? defaultProcessIdentity;
|
|
16280
|
+
const currentBootIdentity = dependencies.currentBootIdentity ?? (() => readInferenceSystemBootIdentity());
|
|
16281
|
+
const isProcessAlive = dependencies.processAlive ?? ((pid) => {
|
|
16282
|
+
try {
|
|
16283
|
+
process.kill(pid, 0);
|
|
16284
|
+
return true;
|
|
16285
|
+
} catch (error48) {
|
|
16286
|
+
if (error48.code === "ESRCH") return false;
|
|
16287
|
+
throw error48;
|
|
16288
|
+
}
|
|
16289
|
+
});
|
|
16264
16290
|
let handle;
|
|
16265
16291
|
for (let acquisition = 0; acquisition < 2; acquisition += 1) {
|
|
16266
16292
|
try {
|
|
@@ -16275,41 +16301,123 @@ async function acquireInferenceHostProcessLock(path) {
|
|
|
16275
16301
|
if (acquisition > 0) {
|
|
16276
16302
|
throw new Error("Another inference host process already owns this local host.");
|
|
16277
16303
|
}
|
|
16278
|
-
|
|
16304
|
+
let before;
|
|
16305
|
+
try {
|
|
16306
|
+
before = await lstat(path);
|
|
16307
|
+
} catch (error49) {
|
|
16308
|
+
if (error49.code === "ENOENT") continue;
|
|
16309
|
+
throw error49;
|
|
16310
|
+
}
|
|
16279
16311
|
if (before.isSymbolicLink() || !before.isFile() || process.platform !== "win32" && (before.mode & 63) !== 0 || typeof process.getuid === "function" && before.uid !== process.getuid()) {
|
|
16280
16312
|
throw new Error("Inference host process lock is unsafe.");
|
|
16281
16313
|
}
|
|
16314
|
+
const reclaimPublicationResidue = async () => {
|
|
16315
|
+
let current2;
|
|
16316
|
+
try {
|
|
16317
|
+
current2 = await lstat(path);
|
|
16318
|
+
} catch (error49) {
|
|
16319
|
+
if (error49.code === "ENOENT") return false;
|
|
16320
|
+
throw error49;
|
|
16321
|
+
}
|
|
16322
|
+
if (current2.isSymbolicLink() || !current2.isFile() || current2.dev !== before.dev || current2.ino !== before.ino || process.platform !== "win32" && (current2.mode & 63) !== 0 || typeof process.getuid === "function" && current2.uid !== process.getuid()) {
|
|
16323
|
+
throw new Error("Inference host process lock publication residue changed or is unsafe.");
|
|
16324
|
+
}
|
|
16325
|
+
try {
|
|
16326
|
+
await rm(path);
|
|
16327
|
+
} catch (error49) {
|
|
16328
|
+
if (error49.code === "ENOENT") return false;
|
|
16329
|
+
throw error49;
|
|
16330
|
+
}
|
|
16331
|
+
processLockObservationCache.delete(resolve(path));
|
|
16332
|
+
await syncInferenceDirectory(directory);
|
|
16333
|
+
return true;
|
|
16334
|
+
};
|
|
16335
|
+
try {
|
|
16336
|
+
await secureExistingWindowsPath(path, "file");
|
|
16337
|
+
} catch (error49) {
|
|
16338
|
+
if (error49.code === "ENOENT") continue;
|
|
16339
|
+
throw error49;
|
|
16340
|
+
}
|
|
16282
16341
|
let staleOwner;
|
|
16283
16342
|
try {
|
|
16284
16343
|
staleOwner = JSON.parse(await readFile(path, "utf8"));
|
|
16285
|
-
} catch {
|
|
16286
|
-
|
|
16344
|
+
} catch (error49) {
|
|
16345
|
+
if (error49.code === "ENOENT") continue;
|
|
16346
|
+
if (Date.now() - before.mtimeMs < 1e4) {
|
|
16347
|
+
throw new Error("Another inference host process already owns this local host.");
|
|
16348
|
+
}
|
|
16349
|
+
await reclaimPublicationResidue();
|
|
16350
|
+
continue;
|
|
16287
16351
|
}
|
|
16288
|
-
if (staleOwner.schema_version !==
|
|
16289
|
-
|
|
16352
|
+
if (staleOwner.schema_version !== 2 || !Number.isSafeInteger(staleOwner.pid) || Number(staleOwner.pid) < 1 || typeof staleOwner.owner_token !== "string" || !staleOwner.owner_token || typeof staleOwner.process_identity !== "string" || !staleOwner.process_identity || typeof staleOwner.boot_identity !== "string" || !staleOwner.boot_identity) {
|
|
16353
|
+
if (Date.now() - before.mtimeMs < 1e4) {
|
|
16354
|
+
throw new Error("Another inference host process already owns this local host.");
|
|
16355
|
+
}
|
|
16356
|
+
await reclaimPublicationResidue();
|
|
16357
|
+
continue;
|
|
16290
16358
|
}
|
|
16359
|
+
const stalePid = Number(staleOwner.pid);
|
|
16360
|
+
const bootIdentity2 = await currentBootIdentity();
|
|
16361
|
+
if (bootIdentity2 === staleOwner.boot_identity && isProcessAlive(stalePid)) {
|
|
16362
|
+
const cached2 = processLockObservationCache.get(resolve(path));
|
|
16363
|
+
const observedIdentity = cached2 && cached2.dev === before.dev && cached2.ino === before.ino && cached2.pid === stalePid && cached2.storedIdentity === staleOwner.process_identity && Date.now() - cached2.observedAtMs < 5e3 ? cached2.observedIdentity : await observeIdentity(stalePid);
|
|
16364
|
+
if (!observedIdentity) {
|
|
16365
|
+
throw new Error("Inference host could not verify the existing lock owner identity.");
|
|
16366
|
+
}
|
|
16367
|
+
processLockObservationCache.set(resolve(path), {
|
|
16368
|
+
dev: before.dev,
|
|
16369
|
+
ino: before.ino,
|
|
16370
|
+
pid: stalePid,
|
|
16371
|
+
storedIdentity: staleOwner.process_identity,
|
|
16372
|
+
observedIdentity,
|
|
16373
|
+
observedAtMs: Date.now()
|
|
16374
|
+
});
|
|
16375
|
+
if (inferenceProcessIdentitiesMatch(staleOwner.process_identity, observedIdentity)) {
|
|
16376
|
+
throw new Error("Another inference host process already owns this local host.");
|
|
16377
|
+
}
|
|
16378
|
+
}
|
|
16379
|
+
let current;
|
|
16291
16380
|
try {
|
|
16292
|
-
|
|
16293
|
-
|
|
16294
|
-
|
|
16295
|
-
|
|
16381
|
+
current = await lstat(path);
|
|
16382
|
+
} catch (error49) {
|
|
16383
|
+
if (error49.code === "ENOENT") continue;
|
|
16384
|
+
throw error49;
|
|
16296
16385
|
}
|
|
16297
|
-
const current = await lstat(path);
|
|
16298
16386
|
if (current.dev !== before.dev || current.ino !== before.ino) {
|
|
16299
16387
|
throw new Error("Inference host process lock ownership changed.");
|
|
16300
16388
|
}
|
|
16301
16389
|
await rm(path);
|
|
16390
|
+
processLockObservationCache.delete(resolve(path));
|
|
16302
16391
|
await syncInferenceDirectory(directory);
|
|
16303
16392
|
}
|
|
16304
16393
|
}
|
|
16305
16394
|
if (!handle) throw new Error("Inference host process lock could not be acquired.");
|
|
16395
|
+
let ownerIdentity;
|
|
16396
|
+
let bootIdentity;
|
|
16397
|
+
try {
|
|
16398
|
+
[ownerIdentity, bootIdentity] = await Promise.all([
|
|
16399
|
+
(dependencies.currentProcessIdentity ?? defaultCurrentProcessIdentity)(),
|
|
16400
|
+
currentBootIdentity()
|
|
16401
|
+
]);
|
|
16402
|
+
} catch (error48) {
|
|
16403
|
+
await handle.close().catch(() => void 0);
|
|
16404
|
+
await rm(path, { force: true }).catch(() => void 0);
|
|
16405
|
+
throw error48;
|
|
16406
|
+
}
|
|
16306
16407
|
await handle.writeFile(
|
|
16307
|
-
`${JSON.stringify({
|
|
16408
|
+
`${JSON.stringify({
|
|
16409
|
+
schema_version: 2,
|
|
16410
|
+
pid: process.pid,
|
|
16411
|
+
owner_token: ownerToken,
|
|
16412
|
+
process_identity: ownerIdentity,
|
|
16413
|
+
boot_identity: bootIdentity
|
|
16414
|
+
})}
|
|
16308
16415
|
`,
|
|
16309
16416
|
"utf8"
|
|
16310
16417
|
);
|
|
16311
16418
|
await handle.sync();
|
|
16312
16419
|
await handle.close();
|
|
16420
|
+
await secureWindowsPrivatePath(path, "file", "harden");
|
|
16313
16421
|
await syncInferenceDirectory(directory);
|
|
16314
16422
|
let released = false;
|
|
16315
16423
|
return {
|
|
@@ -16326,17 +16434,342 @@ async function acquireInferenceHostProcessLock(path) {
|
|
|
16326
16434
|
throw new Error("Inference host process lock ownership changed.");
|
|
16327
16435
|
}
|
|
16328
16436
|
await rm(path);
|
|
16437
|
+
processLockObservationCache.delete(resolve(path));
|
|
16329
16438
|
await syncInferenceDirectory(directory);
|
|
16330
16439
|
released = true;
|
|
16331
16440
|
}
|
|
16332
16441
|
};
|
|
16333
16442
|
}
|
|
16334
|
-
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, credentialStoreIdentity;
|
|
16443
|
+
var INFERENCE_CREDENTIAL_NAMESPACE, MAX_INFERENCE_PRIVATE_FILE_BYTES, WINDOWS_PRIVATE_ACL_SCRIPT, windowsPrivateAclInvocation, runWindowsPrivateAcl, windowsAclCache, windowsAclIdentity, aclCacheKey, secureWindowsPrivatePath, invalidateWindowsAclCache, isDefaultWindowsPrivatePath, secureExistingWindowsPath, linuxProcessIdentity, windowsProcessIdentity, darwinProcessIdentity, runSmallIdentityCommand, cachedSystemBootIdentity, readInferenceSystemBootIdentity, defaultProcessIdentity, defaultCurrentProcessIdentity, processLockObservationCache, inferenceProcessIdentitiesMatch, credentialStoreIdentity;
|
|
16335
16444
|
var init_config = __esm({
|
|
16336
16445
|
"lib/inference-host/config.ts"() {
|
|
16337
16446
|
"use strict";
|
|
16338
16447
|
INFERENCE_CREDENTIAL_NAMESPACE = "vtxmacro-insights-inference";
|
|
16339
16448
|
MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
|
|
16449
|
+
WINDOWS_PRIVATE_ACL_SCRIPT = `$ErrorActionPreference='Stop'
|
|
16450
|
+
$path=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($env:VTX_PRIVATE_PATH_B64))
|
|
16451
|
+
$kind=$env:VTX_PRIVATE_PATH_KIND
|
|
16452
|
+
$mode=$env:VTX_PRIVATE_ACL_MODE
|
|
16453
|
+
if(-not (Test-Path -LiteralPath $path)) { [Console]::Out.Write('missing'); exit 3 }
|
|
16454
|
+
$current=[Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
16455
|
+
$system=New-Object Security.Principal.SecurityIdentifier('S-1-5-18')
|
|
16456
|
+
$admins=New-Object Security.Principal.SecurityIdentifier('S-1-5-32-544')
|
|
16457
|
+
$allowed=@($current.Value,$system.Value,$admins.Value)
|
|
16458
|
+
if($mode -eq 'harden') {
|
|
16459
|
+
$acl=Get-Acl -LiteralPath $path
|
|
16460
|
+
$existingOwner=(New-Object Security.Principal.NTAccount($acl.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
16461
|
+
if($existingOwner -ne $current.Value) { throw 'private ACL owner is invalid' }
|
|
16462
|
+
$acl.SetAccessRuleProtection($true,$false)
|
|
16463
|
+
foreach($existingRule in @($acl.Access)) {
|
|
16464
|
+
[void]$acl.RemoveAccessRuleSpecific($existingRule)
|
|
16465
|
+
}
|
|
16466
|
+
$inherit=if($kind -eq 'directory') {
|
|
16467
|
+
[Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit'
|
|
16468
|
+
} else { [Security.AccessControl.InheritanceFlags]::None }
|
|
16469
|
+
foreach($sid in @($current,$system,$admins)) {
|
|
16470
|
+
$rule=New-Object Security.AccessControl.FileSystemAccessRule(
|
|
16471
|
+
$sid,
|
|
16472
|
+
[Security.AccessControl.FileSystemRights]::FullControl,
|
|
16473
|
+
$inherit,
|
|
16474
|
+
[Security.AccessControl.PropagationFlags]::None,
|
|
16475
|
+
[Security.AccessControl.AccessControlType]::Allow
|
|
16476
|
+
)
|
|
16477
|
+
[void]$acl.AddAccessRule($rule)
|
|
16478
|
+
}
|
|
16479
|
+
(Get-Item -LiteralPath $path).SetAccessControl($acl)
|
|
16480
|
+
}
|
|
16481
|
+
$actual=Get-Acl -LiteralPath $path
|
|
16482
|
+
$owner=(New-Object Security.Principal.NTAccount($actual.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value
|
|
16483
|
+
if($owner -ne $current.Value) { throw 'private ACL owner is invalid' }
|
|
16484
|
+
if($mode -eq 'verify-owner') { [Console]::Out.Write('ok'); exit 0 }
|
|
16485
|
+
if(-not $actual.AreAccessRulesProtected) { throw 'private ACL inheritance is invalid' }
|
|
16486
|
+
$userFull=$false
|
|
16487
|
+
foreach($rule in $actual.Access) {
|
|
16488
|
+
$sid=$rule.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value
|
|
16489
|
+
if($rule.IsInherited -or $allowed -notcontains $sid -or $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow) {
|
|
16490
|
+
throw 'private ACL contains an unauthorized access rule'
|
|
16491
|
+
}
|
|
16492
|
+
if($sid -eq $current.Value -and (($rule.FileSystemRights -band [Security.AccessControl.FileSystemRights]::FullControl) -eq [Security.AccessControl.FileSystemRights]::FullControl)) { $userFull=$true }
|
|
16493
|
+
}
|
|
16494
|
+
if(-not $userFull) { throw 'private ACL does not grant the current user full control' }
|
|
16495
|
+
[Console]::Out.Write('ok')`;
|
|
16496
|
+
windowsPrivateAclInvocation = (path, kind, mode) => ({
|
|
16497
|
+
args: [
|
|
16498
|
+
"-NoLogo",
|
|
16499
|
+
"-NoProfile",
|
|
16500
|
+
"-NonInteractive",
|
|
16501
|
+
"-EncodedCommand",
|
|
16502
|
+
Buffer.from(WINDOWS_PRIVATE_ACL_SCRIPT, "utf16le").toString("base64")
|
|
16503
|
+
],
|
|
16504
|
+
env: {
|
|
16505
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
16506
|
+
SystemRoot: process.env.SystemRoot,
|
|
16507
|
+
WINDIR: process.env.WINDIR,
|
|
16508
|
+
ComSpec: process.env.ComSpec,
|
|
16509
|
+
PATHEXT: process.env.PATHEXT,
|
|
16510
|
+
PSModulePath: process.env.PSModulePath,
|
|
16511
|
+
TEMP: process.env.TEMP,
|
|
16512
|
+
TMP: process.env.TMP,
|
|
16513
|
+
VTX_PRIVATE_PATH_B64: Buffer.from(path, "utf8").toString("base64"),
|
|
16514
|
+
VTX_PRIVATE_PATH_KIND: kind,
|
|
16515
|
+
VTX_PRIVATE_ACL_MODE: mode
|
|
16516
|
+
}
|
|
16517
|
+
});
|
|
16518
|
+
runWindowsPrivateAcl = async (path, kind, mode) => await new Promise((resolvePromise, reject) => {
|
|
16519
|
+
const invocation = windowsPrivateAclInvocation(path, kind, mode);
|
|
16520
|
+
const child = spawn("powershell.exe", [...invocation.args], {
|
|
16521
|
+
env: invocation.env,
|
|
16522
|
+
windowsHide: true,
|
|
16523
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
16524
|
+
});
|
|
16525
|
+
const stdout = [];
|
|
16526
|
+
const stderr = [];
|
|
16527
|
+
let settled = false;
|
|
16528
|
+
const timer = setTimeout(() => child.kill("SIGKILL"), 15e3);
|
|
16529
|
+
child.stdout.on("data", (chunk) => stdout.push(Buffer.from(chunk)));
|
|
16530
|
+
child.stderr.on("data", (chunk) => stderr.push(Buffer.from(chunk)));
|
|
16531
|
+
const settle = (error48) => {
|
|
16532
|
+
if (settled) return;
|
|
16533
|
+
settled = true;
|
|
16534
|
+
clearTimeout(timer);
|
|
16535
|
+
if (error48) reject(error48);
|
|
16536
|
+
else resolvePromise();
|
|
16537
|
+
};
|
|
16538
|
+
child.once("error", (error48) => settle(error48));
|
|
16539
|
+
child.once("exit", (code) => {
|
|
16540
|
+
const output3 = Buffer.concat(stdout).toString("utf8").trim();
|
|
16541
|
+
if (code === 0 && output3 === "ok") {
|
|
16542
|
+
settle();
|
|
16543
|
+
return;
|
|
16544
|
+
}
|
|
16545
|
+
const detail = Buffer.concat(stderr).toString("utf8").trim();
|
|
16546
|
+
if (code === 3 && output3 === "missing" || /GetAcl_PathNotFound|Cannot find path .* because it does not exist/iu.test(detail)) {
|
|
16547
|
+
const error48 = new Error("Windows private path no longer exists.");
|
|
16548
|
+
error48.code = "ENOENT";
|
|
16549
|
+
settle(error48);
|
|
16550
|
+
return;
|
|
16551
|
+
}
|
|
16552
|
+
settle(new Error(`Windows private ACL ${mode} failed${detail ? `: ${detail}` : "."}`));
|
|
16553
|
+
});
|
|
16554
|
+
});
|
|
16555
|
+
windowsAclCache = /* @__PURE__ */ new Map();
|
|
16556
|
+
windowsAclIdentity = async (path) => {
|
|
16557
|
+
const metadata = await lstat(path, { bigint: true });
|
|
16558
|
+
return {
|
|
16559
|
+
dev: metadata.dev,
|
|
16560
|
+
ino: metadata.ino,
|
|
16561
|
+
ctimeNs: metadata.ctimeNs,
|
|
16562
|
+
mtimeNs: metadata.mtimeNs,
|
|
16563
|
+
mode: metadata.mode,
|
|
16564
|
+
size: metadata.size
|
|
16565
|
+
};
|
|
16566
|
+
};
|
|
16567
|
+
aclCacheKey = (path, kind, mode) => `${kind}:${mode}:${resolve(path)}`;
|
|
16568
|
+
secureWindowsPrivatePath = async (path, kind, mode, platform = process.platform, runner = runWindowsPrivateAcl) => {
|
|
16569
|
+
if (platform !== "win32") return;
|
|
16570
|
+
const key = aclCacheKey(path, kind, mode);
|
|
16571
|
+
const before = await windowsAclIdentity(path);
|
|
16572
|
+
const cached2 = windowsAclCache.get(key);
|
|
16573
|
+
if (cached2 && cached2.dev === before.dev && cached2.ino === before.ino && cached2.ctimeNs === before.ctimeNs && cached2.mtimeNs === before.mtimeNs && cached2.mode === before.mode && cached2.size === before.size) return;
|
|
16574
|
+
await runner(path, kind, mode);
|
|
16575
|
+
windowsAclCache.set(key, await windowsAclIdentity(path));
|
|
16576
|
+
};
|
|
16577
|
+
invalidateWindowsAclCache = (path) => {
|
|
16578
|
+
for (const kind of ["file", "directory"]) {
|
|
16579
|
+
for (const mode of ["harden", "verify", "verify-owner"]) {
|
|
16580
|
+
windowsAclCache.delete(aclCacheKey(path, kind, mode));
|
|
16581
|
+
}
|
|
16582
|
+
}
|
|
16583
|
+
};
|
|
16584
|
+
isDefaultWindowsPrivatePath = (path, root = resolve(homedir(), ".vtx", "inference-host")) => {
|
|
16585
|
+
const child = relative(root, resolve(path));
|
|
16586
|
+
return child === "" || !child.startsWith("..") && !child.includes(":");
|
|
16587
|
+
};
|
|
16588
|
+
secureExistingWindowsPath = async (path, kind, platform = process.platform, runner = runWindowsPrivateAcl, defaultRoot = resolve(homedir(), ".vtx", "inference-host")) => {
|
|
16589
|
+
if (platform !== "win32") return;
|
|
16590
|
+
if (!isDefaultWindowsPrivatePath(path, defaultRoot)) {
|
|
16591
|
+
await secureWindowsPrivatePath(path, kind, "verify", platform, runner);
|
|
16592
|
+
return;
|
|
16593
|
+
}
|
|
16594
|
+
await secureWindowsPrivatePath(path, kind, "verify-owner", platform, runner);
|
|
16595
|
+
invalidateWindowsAclCache(path);
|
|
16596
|
+
await secureWindowsPrivatePath(path, kind, "harden", platform, runner);
|
|
16597
|
+
};
|
|
16598
|
+
linuxProcessIdentity = async (pid) => {
|
|
16599
|
+
try {
|
|
16600
|
+
const [bootId, statLine] = await Promise.all([
|
|
16601
|
+
readFile("/proc/sys/kernel/random/boot_id", "utf8"),
|
|
16602
|
+
readFile(`/proc/${pid}/stat`, "utf8")
|
|
16603
|
+
]);
|
|
16604
|
+
const fields = statLine.slice(statLine.lastIndexOf(")") + 2).trim().split(/\s+/u);
|
|
16605
|
+
const startTicks = fields[19];
|
|
16606
|
+
return startTicks ? `linux:${bootId.trim()}:${startTicks}` : null;
|
|
16607
|
+
} catch {
|
|
16608
|
+
return null;
|
|
16609
|
+
}
|
|
16610
|
+
};
|
|
16611
|
+
windowsProcessIdentity = async (pid) => await new Promise((resolvePromise) => {
|
|
16612
|
+
const script = `$ErrorActionPreference='Stop';$p=Get-Process -Id ([int]$env:VTX_PROCESS_PID);[Console]::Out.Write($p.StartTime.ToUniversalTime().ToFileTimeUtc())`;
|
|
16613
|
+
const child = spawn("powershell.exe", [
|
|
16614
|
+
"-NoLogo",
|
|
16615
|
+
"-NoProfile",
|
|
16616
|
+
"-NonInteractive",
|
|
16617
|
+
"-EncodedCommand",
|
|
16618
|
+
Buffer.from(script, "utf16le").toString("base64")
|
|
16619
|
+
], {
|
|
16620
|
+
windowsHide: true,
|
|
16621
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
16622
|
+
env: {
|
|
16623
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
16624
|
+
SystemRoot: process.env.SystemRoot,
|
|
16625
|
+
WINDIR: process.env.WINDIR,
|
|
16626
|
+
ComSpec: process.env.ComSpec,
|
|
16627
|
+
PATHEXT: process.env.PATHEXT,
|
|
16628
|
+
PSModulePath: process.env.PSModulePath,
|
|
16629
|
+
VTX_PROCESS_PID: String(pid)
|
|
16630
|
+
}
|
|
16631
|
+
});
|
|
16632
|
+
const output3 = [];
|
|
16633
|
+
let settled = false;
|
|
16634
|
+
const settle = (value) => {
|
|
16635
|
+
if (settled) return;
|
|
16636
|
+
settled = true;
|
|
16637
|
+
clearTimeout(timer);
|
|
16638
|
+
resolvePromise(value);
|
|
16639
|
+
};
|
|
16640
|
+
const timer = setTimeout(() => {
|
|
16641
|
+
child.kill("SIGKILL");
|
|
16642
|
+
settle(null);
|
|
16643
|
+
}, 5e3);
|
|
16644
|
+
child.stdout.on("data", (chunk) => {
|
|
16645
|
+
if (output3.reduce((total, item) => total + item.byteLength, 0) + Buffer.byteLength(chunk) > 1024) {
|
|
16646
|
+
child.kill("SIGKILL");
|
|
16647
|
+
settle(null);
|
|
16648
|
+
return;
|
|
16649
|
+
}
|
|
16650
|
+
output3.push(Buffer.from(chunk));
|
|
16651
|
+
});
|
|
16652
|
+
child.once("error", () => settle(null));
|
|
16653
|
+
child.once("exit", (code) => {
|
|
16654
|
+
const started = Buffer.concat(output3).toString("utf8").trim();
|
|
16655
|
+
settle(code === 0 && /^\d+$/u.test(started) ? `win32:${started}` : null);
|
|
16656
|
+
});
|
|
16657
|
+
});
|
|
16658
|
+
darwinProcessIdentity = async (pid) => await new Promise((resolvePromise) => {
|
|
16659
|
+
const child = spawn("ps", ["-p", String(pid), "-o", "lstart="], {
|
|
16660
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
16661
|
+
});
|
|
16662
|
+
const output3 = [];
|
|
16663
|
+
let settled = false;
|
|
16664
|
+
const settle = (value) => {
|
|
16665
|
+
if (settled) return;
|
|
16666
|
+
settled = true;
|
|
16667
|
+
clearTimeout(timer);
|
|
16668
|
+
resolvePromise(value);
|
|
16669
|
+
};
|
|
16670
|
+
const timer = setTimeout(() => {
|
|
16671
|
+
child.kill("SIGKILL");
|
|
16672
|
+
settle(null);
|
|
16673
|
+
}, 5e3);
|
|
16674
|
+
child.stdout.on("data", (chunk) => output3.push(Buffer.from(chunk)));
|
|
16675
|
+
child.once("error", () => settle(null));
|
|
16676
|
+
child.once("exit", (code) => {
|
|
16677
|
+
const started = Date.parse(Buffer.concat(output3).toString("utf8").trim());
|
|
16678
|
+
settle(code === 0 && Number.isFinite(started) ? `darwin:${Math.floor(started / 1e3)}` : null);
|
|
16679
|
+
});
|
|
16680
|
+
});
|
|
16681
|
+
runSmallIdentityCommand = async (command, args, env) => await new Promise((resolvePromise) => {
|
|
16682
|
+
const child = spawn(command, [...args], {
|
|
16683
|
+
windowsHide: true,
|
|
16684
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
16685
|
+
env
|
|
16686
|
+
});
|
|
16687
|
+
const output3 = [];
|
|
16688
|
+
let bytes3 = 0;
|
|
16689
|
+
let settled = false;
|
|
16690
|
+
const settle = (value) => {
|
|
16691
|
+
if (settled) return;
|
|
16692
|
+
settled = true;
|
|
16693
|
+
clearTimeout(timer);
|
|
16694
|
+
resolvePromise(value);
|
|
16695
|
+
};
|
|
16696
|
+
const timer = setTimeout(() => {
|
|
16697
|
+
child.kill("SIGKILL");
|
|
16698
|
+
settle(null);
|
|
16699
|
+
}, 5e3);
|
|
16700
|
+
child.stdout.on("data", (chunk) => {
|
|
16701
|
+
bytes3 += Buffer.byteLength(chunk);
|
|
16702
|
+
if (bytes3 > 4096) {
|
|
16703
|
+
child.kill("SIGKILL");
|
|
16704
|
+
settle(null);
|
|
16705
|
+
return;
|
|
16706
|
+
}
|
|
16707
|
+
output3.push(Buffer.from(chunk));
|
|
16708
|
+
});
|
|
16709
|
+
child.once("error", () => settle(null));
|
|
16710
|
+
child.once("exit", (code) => settle(
|
|
16711
|
+
code === 0 ? Buffer.concat(output3).toString("utf8").trim() || null : null
|
|
16712
|
+
));
|
|
16713
|
+
});
|
|
16714
|
+
cachedSystemBootIdentity = null;
|
|
16715
|
+
readInferenceSystemBootIdentity = async (platform = process.platform) => {
|
|
16716
|
+
if (platform === process.platform && cachedSystemBootIdentity) {
|
|
16717
|
+
return await cachedSystemBootIdentity;
|
|
16718
|
+
}
|
|
16719
|
+
const read = async () => {
|
|
16720
|
+
let identity = null;
|
|
16721
|
+
if (platform === "linux") {
|
|
16722
|
+
try {
|
|
16723
|
+
identity = (await readFile("/proc/sys/kernel/random/boot_id", "utf8")).trim();
|
|
16724
|
+
} catch {
|
|
16725
|
+
identity = null;
|
|
16726
|
+
}
|
|
16727
|
+
} else if (platform === "win32") {
|
|
16728
|
+
const script = `$ErrorActionPreference='Stop';$v=(Get-CimInstance Win32_OperatingSystem).LastBootUpTime.ToUniversalTime().ToFileTimeUtc();[Console]::Out.Write($v)`;
|
|
16729
|
+
identity = await runSmallIdentityCommand("powershell.exe", [
|
|
16730
|
+
"-NoLogo",
|
|
16731
|
+
"-NoProfile",
|
|
16732
|
+
"-NonInteractive",
|
|
16733
|
+
"-EncodedCommand",
|
|
16734
|
+
Buffer.from(script, "utf16le").toString("base64")
|
|
16735
|
+
], {
|
|
16736
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
16737
|
+
SystemRoot: process.env.SystemRoot,
|
|
16738
|
+
WINDIR: process.env.WINDIR,
|
|
16739
|
+
ComSpec: process.env.ComSpec,
|
|
16740
|
+
PATHEXT: process.env.PATHEXT,
|
|
16741
|
+
PSModulePath: process.env.PSModulePath
|
|
16742
|
+
});
|
|
16743
|
+
} else if (platform === "darwin") {
|
|
16744
|
+
identity = await runSmallIdentityCommand("sysctl", ["-n", "kern.boottime"], void 0);
|
|
16745
|
+
}
|
|
16746
|
+
if (!identity || /[\r\n\0]/u.test(identity)) {
|
|
16747
|
+
throw new Error("Inference host could not establish the current system boot identity.");
|
|
16748
|
+
}
|
|
16749
|
+
return `${platform}:${identity}`;
|
|
16750
|
+
};
|
|
16751
|
+
const pending = read();
|
|
16752
|
+
if (platform === process.platform) cachedSystemBootIdentity = pending;
|
|
16753
|
+
try {
|
|
16754
|
+
return await pending;
|
|
16755
|
+
} catch (error48) {
|
|
16756
|
+
if (platform === process.platform) cachedSystemBootIdentity = null;
|
|
16757
|
+
throw error48;
|
|
16758
|
+
}
|
|
16759
|
+
};
|
|
16760
|
+
defaultProcessIdentity = async (pid) => {
|
|
16761
|
+
if (process.platform === "linux") return await linuxProcessIdentity(pid);
|
|
16762
|
+
if (process.platform === "win32") return await windowsProcessIdentity(pid);
|
|
16763
|
+
if (process.platform === "darwin") return await darwinProcessIdentity(pid);
|
|
16764
|
+
return null;
|
|
16765
|
+
};
|
|
16766
|
+
defaultCurrentProcessIdentity = async () => {
|
|
16767
|
+
const identity = await defaultProcessIdentity(process.pid);
|
|
16768
|
+
if (!identity) throw new Error("Inference host could not establish its process-start identity.");
|
|
16769
|
+
return identity;
|
|
16770
|
+
};
|
|
16771
|
+
processLockObservationCache = /* @__PURE__ */ new Map();
|
|
16772
|
+
inferenceProcessIdentitiesMatch = (stored, observed) => stored === observed;
|
|
16340
16773
|
credentialStoreIdentity = (mode, filePath, env) => {
|
|
16341
16774
|
if (mode === "file") {
|
|
16342
16775
|
if (!filePath) throw new Error("Inference credential fallback path is unavailable.");
|
|
@@ -16354,7 +16787,7 @@ var init_config = __esm({
|
|
|
16354
16787
|
|
|
16355
16788
|
// lib/inference-host/credential-store.ts
|
|
16356
16789
|
import { createHash } from "node:crypto";
|
|
16357
|
-
import { spawn } from "node:child_process";
|
|
16790
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
16358
16791
|
function canonicalUrl(raw, label) {
|
|
16359
16792
|
let parsed;
|
|
16360
16793
|
try {
|
|
@@ -16520,8 +16953,8 @@ var init_credential_store = __esm({
|
|
|
16520
16953
|
}
|
|
16521
16954
|
return;
|
|
16522
16955
|
}
|
|
16523
|
-
await new Promise((
|
|
16524
|
-
const terminator =
|
|
16956
|
+
await new Promise((resolve6) => {
|
|
16957
|
+
const terminator = spawn2(
|
|
16525
16958
|
"taskkill.exe",
|
|
16526
16959
|
["/PID", String(pid), "/T", "/F"],
|
|
16527
16960
|
{
|
|
@@ -16538,21 +16971,21 @@ var init_credential_store = __esm({
|
|
|
16538
16971
|
const timer = setTimeout(() => {
|
|
16539
16972
|
terminator.kill("SIGKILL");
|
|
16540
16973
|
child.kill("SIGKILL");
|
|
16541
|
-
|
|
16974
|
+
resolve6();
|
|
16542
16975
|
}, CREDENTIAL_COMMAND_TERMINATION_TIMEOUT_MS);
|
|
16543
16976
|
terminator.once("error", () => {
|
|
16544
16977
|
clearTimeout(timer);
|
|
16545
16978
|
child.kill("SIGKILL");
|
|
16546
|
-
|
|
16979
|
+
resolve6();
|
|
16547
16980
|
});
|
|
16548
16981
|
terminator.once("close", () => {
|
|
16549
16982
|
clearTimeout(timer);
|
|
16550
16983
|
if (child.exitCode === null) child.kill("SIGKILL");
|
|
16551
|
-
|
|
16984
|
+
resolve6();
|
|
16552
16985
|
});
|
|
16553
16986
|
});
|
|
16554
16987
|
};
|
|
16555
|
-
runCredentialCommand = async (command, options) => await new Promise((
|
|
16988
|
+
runCredentialCommand = async (command, options) => await new Promise((resolve6, reject) => {
|
|
16556
16989
|
const timeoutMs = options.timeoutMs ?? DEFAULT_CREDENTIAL_COMMAND_TIMEOUT_MS;
|
|
16557
16990
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1) {
|
|
16558
16991
|
reject(new Error("OS credential command timeout must be a positive integer."));
|
|
@@ -16562,7 +16995,7 @@ var init_credential_store = __esm({
|
|
|
16562
16995
|
reject(new Error("OS credential command was aborted."));
|
|
16563
16996
|
return;
|
|
16564
16997
|
}
|
|
16565
|
-
const child =
|
|
16998
|
+
const child = spawn2(command.command, command.args, {
|
|
16566
16999
|
detached: true,
|
|
16567
17000
|
shell: false,
|
|
16568
17001
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -16611,7 +17044,7 @@ var init_credential_store = __esm({
|
|
|
16611
17044
|
const transformedStdout = normalizedExitCode === 0 ? command.transformStdout?.(stdout) ?? stdout : stdout;
|
|
16612
17045
|
settled = true;
|
|
16613
17046
|
cleanup();
|
|
16614
|
-
|
|
17047
|
+
resolve6({
|
|
16615
17048
|
exitCode: normalizedExitCode,
|
|
16616
17049
|
stdout: transformedStdout
|
|
16617
17050
|
});
|
|
@@ -17825,7 +18258,7 @@ async function registerInferenceOAuthClient(metadata, redirectUri, fetchImpl = f
|
|
|
17825
18258
|
grant_types: ["authorization_code", "refresh_token"],
|
|
17826
18259
|
response_types: ["code"],
|
|
17827
18260
|
application_type: "native",
|
|
17828
|
-
client_name: "VTX
|
|
18261
|
+
client_name: "VTX inference host",
|
|
17829
18262
|
scope: INFERENCE_SCOPE
|
|
17830
18263
|
})
|
|
17831
18264
|
}, requestOptions);
|
|
@@ -18072,11 +18505,11 @@ async function revokeInferenceCredential(options) {
|
|
|
18072
18505
|
}
|
|
18073
18506
|
}
|
|
18074
18507
|
async function listenLoopback(server) {
|
|
18075
|
-
await new Promise((
|
|
18508
|
+
await new Promise((resolve6, reject) => {
|
|
18076
18509
|
server.once("error", reject);
|
|
18077
18510
|
server.listen(0, CALLBACK_HOST, () => {
|
|
18078
18511
|
server.off("error", reject);
|
|
18079
|
-
|
|
18512
|
+
resolve6();
|
|
18080
18513
|
});
|
|
18081
18514
|
});
|
|
18082
18515
|
const address = server.address();
|
|
@@ -18087,7 +18520,7 @@ async function listenLoopback(server) {
|
|
|
18087
18520
|
}
|
|
18088
18521
|
async function closeServer(server) {
|
|
18089
18522
|
if (!server.listening) return;
|
|
18090
|
-
await new Promise((
|
|
18523
|
+
await new Promise((resolve6) => server.close(() => resolve6()));
|
|
18091
18524
|
}
|
|
18092
18525
|
async function beginInferenceOAuthLogin(options) {
|
|
18093
18526
|
const loginTimeoutMs = options.timeoutMs ?? 6e5;
|
|
@@ -18143,7 +18576,7 @@ async function beginInferenceOAuthLogin(options) {
|
|
|
18143
18576
|
});
|
|
18144
18577
|
let settled = false;
|
|
18145
18578
|
let rejectCompletion;
|
|
18146
|
-
const completion = new Promise((
|
|
18579
|
+
const completion = new Promise((resolve6, reject) => {
|
|
18147
18580
|
rejectCompletion = reject;
|
|
18148
18581
|
handler = async (requestUrl, method, writeResponse) => {
|
|
18149
18582
|
if (settled) {
|
|
@@ -18218,7 +18651,7 @@ async function beginInferenceOAuthLogin(options) {
|
|
|
18218
18651
|
'<!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>'
|
|
18219
18652
|
);
|
|
18220
18653
|
await closeServer(server);
|
|
18221
|
-
|
|
18654
|
+
resolve6({
|
|
18222
18655
|
accessToken: tokens.accessToken,
|
|
18223
18656
|
expiresIn: tokens.expiresIn,
|
|
18224
18657
|
credential,
|
|
@@ -18332,7 +18765,7 @@ async function createInferenceAgentMcpSession(options) {
|
|
|
18332
18765
|
options.fetchImpl,
|
|
18333
18766
|
{ signal: options.signal, timeoutMs: options.requestTimeoutMs }
|
|
18334
18767
|
);
|
|
18335
|
-
let
|
|
18768
|
+
let access4 = null;
|
|
18336
18769
|
let accessExpiresAt = 0;
|
|
18337
18770
|
let refreshPromise = null;
|
|
18338
18771
|
const refreshAccessToken = async (requestOptions = {}) => {
|
|
@@ -18349,7 +18782,7 @@ async function createInferenceAgentMcpSession(options) {
|
|
|
18349
18782
|
});
|
|
18350
18783
|
assertCredentialMatchesState(localState, refreshed.credential);
|
|
18351
18784
|
credential = refreshed.credential;
|
|
18352
|
-
|
|
18785
|
+
access4 = refreshed;
|
|
18353
18786
|
accessExpiresAt = Date.now() + refreshed.expiresIn * 1e3;
|
|
18354
18787
|
return refreshed.accessToken;
|
|
18355
18788
|
})();
|
|
@@ -18362,10 +18795,10 @@ async function createInferenceAgentMcpSession(options) {
|
|
|
18362
18795
|
await refreshAccessToken({ signal: options.signal });
|
|
18363
18796
|
const tokenSource = {
|
|
18364
18797
|
accessToken: async (requestOptions) => {
|
|
18365
|
-
if (!
|
|
18798
|
+
if (!access4 || accessExpiresAt - Date.now() <= 5e3) {
|
|
18366
18799
|
return refreshAccessToken(requestOptions);
|
|
18367
18800
|
}
|
|
18368
|
-
return
|
|
18801
|
+
return access4.accessToken;
|
|
18369
18802
|
},
|
|
18370
18803
|
refreshAccessToken
|
|
18371
18804
|
};
|
|
@@ -18518,10 +18951,10 @@ var init_agent_state = __esm({
|
|
|
18518
18951
|
});
|
|
18519
18952
|
|
|
18520
18953
|
// lib/inference-host/codex-app-server.ts
|
|
18521
|
-
import { spawn as
|
|
18522
|
-
import { chmod, lstat as lstat2, readFile as readFile2, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
|
|
18954
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
18955
|
+
import { chmod, lstat as lstat2, open as open2, readFile as readFile2, rename as rename2, rm as rm2, writeFile } from "node:fs/promises";
|
|
18523
18956
|
import { tmpdir } from "node:os";
|
|
18524
|
-
import { isAbsolute, join as join2, resolve as resolve2, sep } from "node:path";
|
|
18957
|
+
import { dirname as dirname2, isAbsolute, join as join2, resolve as resolve2, sep } from "node:path";
|
|
18525
18958
|
import { createInterface } from "node:readline";
|
|
18526
18959
|
async function loginCodexSubscription(options) {
|
|
18527
18960
|
const session = await CodexAppServerSession.start(options);
|
|
@@ -18587,6 +19020,7 @@ var CODEX_INFERENCE_PERMISSION_PROFILE, CODEX_ACCOUNT_PLAN_TYPES, CodexAppServer
|
|
|
18587
19020
|
var init_codex_app_server = __esm({
|
|
18588
19021
|
"lib/inference-host/codex-app-server.ts"() {
|
|
18589
19022
|
"use strict";
|
|
19023
|
+
init_config();
|
|
18590
19024
|
CODEX_INFERENCE_PERMISSION_PROFILE = "vtx_inference_readonly";
|
|
18591
19025
|
CODEX_ACCOUNT_PLAN_TYPES = [
|
|
18592
19026
|
"free",
|
|
@@ -18820,8 +19254,8 @@ var init_codex_app_server = __esm({
|
|
|
18820
19254
|
};
|
|
18821
19255
|
};
|
|
18822
19256
|
killWindowsProcessTree = async (pid) => {
|
|
18823
|
-
await new Promise((
|
|
18824
|
-
const child =
|
|
19257
|
+
await new Promise((resolve6, reject) => {
|
|
19258
|
+
const child = spawn3(
|
|
18825
19259
|
"taskkill.exe",
|
|
18826
19260
|
["/PID", String(pid), "/T", "/F"],
|
|
18827
19261
|
{
|
|
@@ -18845,7 +19279,7 @@ var init_codex_app_server = __esm({
|
|
|
18845
19279
|
});
|
|
18846
19280
|
child.once("close", (code) => {
|
|
18847
19281
|
clearTimeout(timer);
|
|
18848
|
-
if (code === 0 || code === 128)
|
|
19282
|
+
if (code === 0 || code === 128) resolve6();
|
|
18849
19283
|
else reject(new Error("Windows Codex process-tree cleanup failed."));
|
|
18850
19284
|
});
|
|
18851
19285
|
});
|
|
@@ -18879,7 +19313,8 @@ var init_codex_app_server = __esm({
|
|
|
18879
19313
|
};
|
|
18880
19314
|
GUARDIAN_SCRIPT = String.raw`
|
|
18881
19315
|
import { spawn } from 'node:child_process';
|
|
18882
|
-
import { chmod, rename, rm, writeFile } from 'node:fs/promises';
|
|
19316
|
+
import { chmod, open, rename, rm, writeFile } from 'node:fs/promises';
|
|
19317
|
+
import { dirname } from 'node:path';
|
|
18883
19318
|
const input = JSON.parse(Buffer.from(process.argv[1], 'base64url').toString('utf8'));
|
|
18884
19319
|
// The guardian owns the process boundary for every attempt. Apply a private
|
|
18885
19320
|
// umask before writing receipts or starting Codex so a lost thread/start reply
|
|
@@ -18916,6 +19351,7 @@ const writeReceipt = (state, childPid) => {
|
|
|
18916
19351
|
state,
|
|
18917
19352
|
guardian_pid: process.pid,
|
|
18918
19353
|
child_pid: childPid ?? null,
|
|
19354
|
+
boot_identity: input.bootIdentity,
|
|
18919
19355
|
updated_at: new Date().toISOString(),
|
|
18920
19356
|
}) + '\n';
|
|
18921
19357
|
receiptWriteSequence += 1;
|
|
@@ -18923,7 +19359,13 @@ const writeReceipt = (state, childPid) => {
|
|
|
18923
19359
|
try {
|
|
18924
19360
|
await writeFile(temporary, body, { mode: 0o600 });
|
|
18925
19361
|
await chmod(temporary, 0o600).catch(() => undefined);
|
|
19362
|
+
const file = await open(temporary, 'r+');
|
|
19363
|
+
try { await file.sync(); } finally { await file.close(); }
|
|
18926
19364
|
await replaceReceipt(temporary);
|
|
19365
|
+
if (process.platform !== 'win32') {
|
|
19366
|
+
const directory = await open(dirname(input.receiptPath), 'r');
|
|
19367
|
+
try { await directory.sync(); } finally { await directory.close(); }
|
|
19368
|
+
}
|
|
18927
19369
|
} finally {
|
|
18928
19370
|
await rm(temporary, { force: true }).catch(() => undefined);
|
|
18929
19371
|
}
|
|
@@ -18960,6 +19402,7 @@ child = spawn(input.binary, input.args, {
|
|
|
18960
19402
|
windowsHide: true,
|
|
18961
19403
|
detached: false,
|
|
18962
19404
|
});
|
|
19405
|
+
child.stdin.on('error', () => undefined);
|
|
18963
19406
|
process.stdin.pipe(child.stdin, { end: false });
|
|
18964
19407
|
child.stdout.pipe(process.stdout);
|
|
18965
19408
|
child.stderr.pipe(process.stderr);
|
|
@@ -18973,9 +19416,14 @@ child.once('spawn', async () => {
|
|
|
18973
19416
|
child.once('error', shutdown);
|
|
18974
19417
|
child.once('close', async () => {
|
|
18975
19418
|
if (forceTimer) clearTimeout(forceTimer);
|
|
19419
|
+
// A pending promise alone does not keep Node's event loop alive after the
|
|
19420
|
+
// child and parent stdin have both closed. Hold one local handle until the
|
|
19421
|
+
// serialized terminal tombstone is durably replaced.
|
|
19422
|
+
const receiptKeepAlive = setInterval(() => undefined, 1_000);
|
|
18976
19423
|
try {
|
|
18977
19424
|
await writeReceipt('terminated', child.pid ?? null);
|
|
18978
19425
|
} finally {
|
|
19426
|
+
clearInterval(receiptKeepAlive);
|
|
18979
19427
|
process.exit(0);
|
|
18980
19428
|
}
|
|
18981
19429
|
});
|
|
@@ -18991,7 +19439,7 @@ child.once('close', async () => {
|
|
|
18991
19439
|
const platform = options.platform ?? process.platform;
|
|
18992
19440
|
const renameFile = options.renameFile ?? rename2;
|
|
18993
19441
|
const removeFile = options.removeFile ?? ((path) => rm2(path, { force: true }));
|
|
18994
|
-
const sleep4 = options.sleep ?? ((milliseconds) => new Promise((
|
|
19442
|
+
const sleep4 = options.sleep ?? ((milliseconds) => new Promise((resolve6) => setTimeout(resolve6, milliseconds)));
|
|
18995
19443
|
const maxAttempts = Math.max(1, options.maxAttempts ?? 40);
|
|
18996
19444
|
const retryDelayMs = Math.max(0, options.retryDelayMs ?? 25);
|
|
18997
19445
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
@@ -19022,20 +19470,38 @@ child.once('close', async () => {
|
|
|
19022
19470
|
state: "spawn_intent",
|
|
19023
19471
|
guardian_pid: null,
|
|
19024
19472
|
child_pid: null,
|
|
19473
|
+
boot_identity: guardian.bootIdentity ?? null,
|
|
19025
19474
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
19026
19475
|
})}
|
|
19027
19476
|
`;
|
|
19028
19477
|
const temporary = `${guardian.receiptPath}.intent-${process.pid}`;
|
|
19029
19478
|
await writeFile(temporary, body, { mode: 384 });
|
|
19030
19479
|
await chmod(temporary, 384).catch(() => void 0);
|
|
19480
|
+
const handle = await open2(temporary, "r+");
|
|
19481
|
+
try {
|
|
19482
|
+
await handle.sync();
|
|
19483
|
+
} finally {
|
|
19484
|
+
await handle.close();
|
|
19485
|
+
}
|
|
19031
19486
|
await replaceCodexGuardianReceiptFile(temporary, guardian.receiptPath);
|
|
19487
|
+
if (process.platform !== "win32") {
|
|
19488
|
+
const directory = await open2(dirname2(guardian.receiptPath), "r");
|
|
19489
|
+
try {
|
|
19490
|
+
await directory.sync();
|
|
19491
|
+
} finally {
|
|
19492
|
+
await directory.close();
|
|
19493
|
+
}
|
|
19494
|
+
}
|
|
19032
19495
|
};
|
|
19033
19496
|
parseGuardianReceipt = (raw) => {
|
|
19034
19497
|
const value = JSON.parse(raw);
|
|
19035
|
-
if (value.schema_version !== "vtx_codex_guardian_v1" || typeof value.process_token !== "string" || !/^[0-9a-f]{64}$/u.test(value.process_token) || !["spawn_intent", "starting", "running", "terminated"].includes(String(value.state)) || value.guardian_pid !== null && !Number.isSafeInteger(value.guardian_pid) || value.state === "spawn_intent" && value.guardian_pid !== null || value.state !== "spawn_intent" && !Number.isSafeInteger(value.guardian_pid) || value.child_pid !== null && !Number.isSafeInteger(value.child_pid) || typeof value.updated_at !== "string" || !Number.isFinite(Date.parse(value.updated_at))) {
|
|
19498
|
+
if (value.schema_version !== "vtx_codex_guardian_v1" || typeof value.process_token !== "string" || !/^[0-9a-f]{64}$/u.test(value.process_token) || !["spawn_intent", "starting", "running", "terminated"].includes(String(value.state)) || value.guardian_pid !== null && !Number.isSafeInteger(value.guardian_pid) || value.state === "spawn_intent" && value.guardian_pid !== null || value.state !== "spawn_intent" && !Number.isSafeInteger(value.guardian_pid) || value.child_pid !== null && !Number.isSafeInteger(value.child_pid) || value.boot_identity !== null && value.boot_identity !== void 0 && typeof value.boot_identity !== "string" || typeof value.updated_at !== "string" || !Number.isFinite(Date.parse(value.updated_at))) {
|
|
19036
19499
|
throw new Error("Codex guardian receipt is invalid.");
|
|
19037
19500
|
}
|
|
19038
|
-
return
|
|
19501
|
+
return {
|
|
19502
|
+
...value,
|
|
19503
|
+
boot_identity: typeof value.boot_identity === "string" ? value.boot_identity : null
|
|
19504
|
+
};
|
|
19039
19505
|
};
|
|
19040
19506
|
readCodexGuardianReceipt = async (path) => {
|
|
19041
19507
|
try {
|
|
@@ -19061,14 +19527,14 @@ child.once('close', async () => {
|
|
|
19061
19527
|
throw new Error("Codex guardian terminated before app-server initialization.");
|
|
19062
19528
|
}
|
|
19063
19529
|
}
|
|
19064
|
-
await new Promise((
|
|
19530
|
+
await new Promise((resolve6) => setTimeout(resolve6, 25));
|
|
19065
19531
|
}
|
|
19066
19532
|
throw new Error(`Codex guardian ${expectedState} state was not confirmed.`);
|
|
19067
19533
|
};
|
|
19068
19534
|
defaultSpawn = (binary, args, options) => {
|
|
19069
19535
|
if (!options.guardian) {
|
|
19070
19536
|
const { guardian: _guardian, ...spawnOptions } = options;
|
|
19071
|
-
return
|
|
19537
|
+
return spawn3(binary, args, {
|
|
19072
19538
|
...spawnOptions,
|
|
19073
19539
|
detached: options.detached
|
|
19074
19540
|
});
|
|
@@ -19078,9 +19544,10 @@ child.once('close', async () => {
|
|
|
19078
19544
|
args,
|
|
19079
19545
|
processToken: options.guardian.processToken,
|
|
19080
19546
|
receiptPath: options.guardian.receiptPath,
|
|
19081
|
-
shutdownGraceMs: Math.max(25, options.guardian.shutdownGraceMs ?? 2e3)
|
|
19547
|
+
shutdownGraceMs: Math.max(25, options.guardian.shutdownGraceMs ?? 2e3),
|
|
19548
|
+
bootIdentity: options.guardian.bootIdentity
|
|
19082
19549
|
}), "utf8").toString("base64url");
|
|
19083
|
-
return
|
|
19550
|
+
return spawn3(process.execPath, ["--input-type=module", "--eval", GUARDIAN_SCRIPT, payload], {
|
|
19084
19551
|
env: options.env,
|
|
19085
19552
|
stdio: options.stdio,
|
|
19086
19553
|
windowsHide: options.windowsHide,
|
|
@@ -19107,9 +19574,13 @@ child.once('close', async () => {
|
|
|
19107
19574
|
}
|
|
19108
19575
|
static async start(options) {
|
|
19109
19576
|
const spawnProcess = options.spawnProcess ?? defaultSpawn;
|
|
19110
|
-
|
|
19577
|
+
const guardian = options.guardian ? {
|
|
19578
|
+
...options.guardian,
|
|
19579
|
+
bootIdentity: options.guardian.bootIdentity ?? await readInferenceSystemBootIdentity()
|
|
19580
|
+
} : void 0;
|
|
19581
|
+
if (guardian) {
|
|
19111
19582
|
try {
|
|
19112
|
-
await writeCodexGuardianSpawnIntent(
|
|
19583
|
+
await writeCodexGuardianSpawnIntent(guardian);
|
|
19113
19584
|
} catch (error48) {
|
|
19114
19585
|
throw new CodexAppServerError({
|
|
19115
19586
|
message: "Codex guardian spawn intent could not be persisted.",
|
|
@@ -19125,17 +19596,32 @@ child.once('close', async () => {
|
|
|
19125
19596
|
stdio: ["pipe", "pipe", "pipe"],
|
|
19126
19597
|
windowsHide: true,
|
|
19127
19598
|
detached: true,
|
|
19128
|
-
guardian
|
|
19599
|
+
guardian
|
|
19129
19600
|
});
|
|
19130
|
-
if (
|
|
19601
|
+
if (guardian) {
|
|
19131
19602
|
try {
|
|
19132
19603
|
await waitForCodexGuardianState(
|
|
19133
|
-
|
|
19604
|
+
guardian,
|
|
19134
19605
|
"running",
|
|
19135
19606
|
Math.min(options.deadlineAtMs, Date.now() + 1e4)
|
|
19136
19607
|
);
|
|
19137
19608
|
} catch (error48) {
|
|
19138
19609
|
child.stdin.end();
|
|
19610
|
+
try {
|
|
19611
|
+
await waitForCodexGuardianState(
|
|
19612
|
+
guardian,
|
|
19613
|
+
"terminated",
|
|
19614
|
+
Date.now() + 5e3
|
|
19615
|
+
);
|
|
19616
|
+
} catch (terminationError) {
|
|
19617
|
+
throw new CodexAppServerError({
|
|
19618
|
+
message: "Codex guardian startup failed and termination was not confirmed.",
|
|
19619
|
+
category: "transport",
|
|
19620
|
+
code: "codex_guardian_termination_unconfirmed",
|
|
19621
|
+
retryable: false,
|
|
19622
|
+
cause: terminationError
|
|
19623
|
+
});
|
|
19624
|
+
}
|
|
19139
19625
|
throw new CodexAppServerError({
|
|
19140
19626
|
message: "Codex guardian startup could not be confirmed.",
|
|
19141
19627
|
category: "transport",
|
|
@@ -19170,6 +19656,23 @@ child.once('close', async () => {
|
|
|
19170
19656
|
return session;
|
|
19171
19657
|
} catch (error48) {
|
|
19172
19658
|
await session.close().catch(() => void 0);
|
|
19659
|
+
if (guardian) {
|
|
19660
|
+
try {
|
|
19661
|
+
await waitForCodexGuardianState(
|
|
19662
|
+
guardian,
|
|
19663
|
+
"terminated",
|
|
19664
|
+
Date.now() + 5e3
|
|
19665
|
+
);
|
|
19666
|
+
} catch (terminationError) {
|
|
19667
|
+
throw new CodexAppServerError({
|
|
19668
|
+
message: "Codex app-server failed and guardian termination was not confirmed.",
|
|
19669
|
+
category: "transport",
|
|
19670
|
+
code: "codex_guardian_termination_unconfirmed",
|
|
19671
|
+
retryable: false,
|
|
19672
|
+
cause: terminationError
|
|
19673
|
+
});
|
|
19674
|
+
}
|
|
19675
|
+
}
|
|
19173
19676
|
throw error48;
|
|
19174
19677
|
}
|
|
19175
19678
|
}
|
|
@@ -19287,8 +19790,8 @@ child.once('close', async () => {
|
|
|
19287
19790
|
retryable: false
|
|
19288
19791
|
});
|
|
19289
19792
|
}
|
|
19290
|
-
return await new Promise((
|
|
19291
|
-
const pending = { resolve:
|
|
19793
|
+
return await new Promise((resolve6, reject) => {
|
|
19794
|
+
const pending = { resolve: resolve6, reject, timer: null, abortCleanup: null };
|
|
19292
19795
|
pending.timer = setTimeout(() => {
|
|
19293
19796
|
this.pending.delete(id2);
|
|
19294
19797
|
pending.abortCleanup?.();
|
|
@@ -19676,8 +20179,8 @@ child.once('close', async () => {
|
|
|
19676
20179
|
let terminal = null;
|
|
19677
20180
|
let terminalResolve;
|
|
19678
20181
|
let terminalReject;
|
|
19679
|
-
const terminalPromise = new Promise((
|
|
19680
|
-
terminalResolve =
|
|
20182
|
+
const terminalPromise = new Promise((resolve6, reject) => {
|
|
20183
|
+
terminalResolve = resolve6;
|
|
19681
20184
|
terminalReject = reject;
|
|
19682
20185
|
});
|
|
19683
20186
|
void terminalPromise.catch(() => void 0);
|
|
@@ -20098,15 +20601,15 @@ child.once('close', async () => {
|
|
|
20098
20601
|
if (this.closed) return;
|
|
20099
20602
|
this.closed = true;
|
|
20100
20603
|
this.process.stdin.end();
|
|
20101
|
-
const exited = await new Promise((
|
|
20604
|
+
const exited = await new Promise((resolve6) => {
|
|
20102
20605
|
if (this.process.exitCode !== null) {
|
|
20103
|
-
|
|
20606
|
+
resolve6(true);
|
|
20104
20607
|
return;
|
|
20105
20608
|
}
|
|
20106
|
-
const timer = setTimeout(() =>
|
|
20609
|
+
const timer = setTimeout(() => resolve6(false), 5e3);
|
|
20107
20610
|
this.process.once("close", () => {
|
|
20108
20611
|
clearTimeout(timer);
|
|
20109
|
-
|
|
20612
|
+
resolve6(true);
|
|
20110
20613
|
});
|
|
20111
20614
|
});
|
|
20112
20615
|
if (exited) return;
|
|
@@ -20117,11 +20620,11 @@ child.once('close', async () => {
|
|
|
20117
20620
|
else this.process.kill("SIGTERM");
|
|
20118
20621
|
} catch {
|
|
20119
20622
|
}
|
|
20120
|
-
const terminated = await new Promise((
|
|
20121
|
-
const timer = setTimeout(() =>
|
|
20623
|
+
const terminated = await new Promise((resolve6) => {
|
|
20624
|
+
const timer = setTimeout(() => resolve6(false), 1e3);
|
|
20122
20625
|
this.process.once("close", () => {
|
|
20123
20626
|
clearTimeout(timer);
|
|
20124
|
-
|
|
20627
|
+
resolve6(true);
|
|
20125
20628
|
});
|
|
20126
20629
|
});
|
|
20127
20630
|
if (!terminated) {
|
|
@@ -20131,15 +20634,15 @@ child.once('close', async () => {
|
|
|
20131
20634
|
else this.process.kill("SIGKILL");
|
|
20132
20635
|
} catch {
|
|
20133
20636
|
}
|
|
20134
|
-
await new Promise((
|
|
20637
|
+
await new Promise((resolve6) => {
|
|
20135
20638
|
if (this.process.exitCode !== null) {
|
|
20136
|
-
|
|
20639
|
+
resolve6();
|
|
20137
20640
|
return;
|
|
20138
20641
|
}
|
|
20139
|
-
const timer = setTimeout(
|
|
20642
|
+
const timer = setTimeout(resolve6, 1e3);
|
|
20140
20643
|
this.process.once("close", () => {
|
|
20141
20644
|
clearTimeout(timer);
|
|
20142
|
-
|
|
20645
|
+
resolve6();
|
|
20143
20646
|
});
|
|
20144
20647
|
});
|
|
20145
20648
|
if (this.process.exitCode === null) {
|
|
@@ -20161,8 +20664,8 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
20161
20664
|
import { constants as fsConstants } from "node:fs";
|
|
20162
20665
|
import { access, readFile as readFile3, realpath as realpath2 } from "node:fs/promises";
|
|
20163
20666
|
import { createRequire } from "node:module";
|
|
20164
|
-
import { dirname as
|
|
20165
|
-
import { spawn as
|
|
20667
|
+
import { dirname as dirname3, join as join3 } from "node:path";
|
|
20668
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
20166
20669
|
var PINNED_CODEX_CLI_VERSION, PINNED_CODEX_LINUX_X64_SHA256, PINNED_CODEX_WINDOWS_X64_SHA256, pinnedShaForPlatform, pinnedPackageForPlatform, resolvePinnedCodexPackageBinaryPath, readCodexVersion, verifyPinnedCodexBinary, resolvePinnedCodexBinary;
|
|
20167
20670
|
var init_codex_binary = __esm({
|
|
20168
20671
|
"lib/inference-host/codex-binary.ts"() {
|
|
@@ -20199,15 +20702,15 @@ var init_codex_binary = __esm({
|
|
|
20199
20702
|
const spec = pinnedPackageForPlatform(platform, architecture);
|
|
20200
20703
|
const packageJsonPath = resolvePackage(`${spec.packageName}/package.json`);
|
|
20201
20704
|
return join3(
|
|
20202
|
-
|
|
20705
|
+
dirname3(packageJsonPath),
|
|
20203
20706
|
"vendor",
|
|
20204
20707
|
spec.target,
|
|
20205
20708
|
"bin",
|
|
20206
20709
|
spec.binaryName
|
|
20207
20710
|
);
|
|
20208
20711
|
};
|
|
20209
|
-
readCodexVersion = async (binaryPath) => await new Promise((
|
|
20210
|
-
const child =
|
|
20712
|
+
readCodexVersion = async (binaryPath) => await new Promise((resolve6, reject) => {
|
|
20713
|
+
const child = spawn4(binaryPath, ["--version"], {
|
|
20211
20714
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20212
20715
|
windowsHide: true,
|
|
20213
20716
|
env: {
|
|
@@ -20244,7 +20747,7 @@ var init_codex_binary = __esm({
|
|
|
20244
20747
|
reject(new Error("Codex version probe failed."));
|
|
20245
20748
|
return;
|
|
20246
20749
|
}
|
|
20247
|
-
|
|
20750
|
+
resolve6(stdout.trim());
|
|
20248
20751
|
});
|
|
20249
20752
|
});
|
|
20250
20753
|
verifyPinnedCodexBinary = async (candidatePath, dependencies = {}) => {
|
|
@@ -20304,7 +20807,7 @@ import {
|
|
|
20304
20807
|
} from "node:fs/promises";
|
|
20305
20808
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
20306
20809
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
20307
|
-
import { isAbsolute as isAbsolute2, join as join4, relative, resolve as resolve3, sep as sep2 } from "node:path";
|
|
20810
|
+
import { isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
20308
20811
|
var INITIAL_CODEX_INFERENCE_MODEL, SUPPORTED_CODEX_REASONING_EFFORTS, MAX_PROMPT_BYTES2, tokenUsageReceiptSchema, turnResultReceiptSchema, terminalReceiptSchema, recoveryCheckpointSchema, recoveryFileSchema, FileCodexAttemptRecoveryStore, utf8Bytes, tomlString, permissionConfig, ensureDedicatedCodexHome, createIsolatedCodexAttemptResources, createIsolatedCodexHostResources, validateAttemptInput, isStrictDescendant, assertRecoveryResourceScope, removeRecoveredThread, confirmGuardianTerminatedForRecovery, reconcileCodexAttemptRecovery, CodexSubscriptionAdapter;
|
|
20309
20812
|
var init_codex_adapter = __esm({
|
|
20310
20813
|
"lib/inference-host/codex-adapter.ts"() {
|
|
@@ -20370,6 +20873,7 @@ var init_codex_adapter = __esm({
|
|
|
20370
20873
|
processToken: external_exports.string().regex(/^[0-9a-f]{64}$/u).nullable(),
|
|
20371
20874
|
processReceiptPath: external_exports.string().min(1).max(4096).nullable(),
|
|
20372
20875
|
processState: external_exports.enum(["unmanaged", "spawn_intent", "running", "terminated"]),
|
|
20876
|
+
bootIdentity: external_exports.string().min(1).max(4096).nullable().optional(),
|
|
20373
20877
|
cleanupConfirmed: external_exports.boolean(),
|
|
20374
20878
|
adapterRequestId: external_exports.string().min(1).max(512).nullable(),
|
|
20375
20879
|
adapterResponseId: external_exports.string().min(1).max(512).nullable(),
|
|
@@ -20613,7 +21117,7 @@ var init_codex_adapter = __esm({
|
|
|
20613
21117
|
isStrictDescendant = (candidate, parent) => {
|
|
20614
21118
|
const parentPath = resolve3(parent);
|
|
20615
21119
|
const candidatePath = resolve3(candidate);
|
|
20616
|
-
const scoped =
|
|
21120
|
+
const scoped = relative2(parentPath, candidatePath);
|
|
20617
21121
|
return scoped.length > 0 && !scoped.startsWith(`..${sep2}`) && scoped !== ".." && !isAbsolute2(scoped);
|
|
20618
21122
|
};
|
|
20619
21123
|
assertRecoveryResourceScope = (checkpoint) => {
|
|
@@ -20623,7 +21127,7 @@ var init_codex_adapter = __esm({
|
|
|
20623
21127
|
if (!isStrictDescendant(resourceRoot, temporaryRoot)) {
|
|
20624
21128
|
throw new Error("Codex recovery resource root crossed temporary scope.");
|
|
20625
21129
|
}
|
|
20626
|
-
const parts =
|
|
21130
|
+
const parts = relative2(temporaryRoot, resourceRoot).split(sep2);
|
|
20627
21131
|
const standalone = parts.length === 1 && parts[0].startsWith("vtx-codex-attempt-") && workspacePath === join4(resourceRoot, "workspace");
|
|
20628
21132
|
const hosted = parts.length === 3 && parts[0].startsWith("vtx-codex-host-") && parts[1] === "workspaces" && parts[2].startsWith("attempt-") && workspacePath === resourceRoot;
|
|
20629
21133
|
if (!standalone && !hosted) {
|
|
@@ -20747,6 +21251,7 @@ var init_codex_adapter = __esm({
|
|
|
20747
21251
|
};
|
|
20748
21252
|
reconcileCodexAttemptRecovery = async (options) => {
|
|
20749
21253
|
const attempts = await options.recoveryHooks.loadAll?.() ?? {};
|
|
21254
|
+
const currentBootIdentity = options.bootIdentity ?? await readInferenceSystemBootIdentity();
|
|
20750
21255
|
let reconciled = 0;
|
|
20751
21256
|
for (const checkpoint of Object.values(attempts)) {
|
|
20752
21257
|
if (checkpoint.cleanupConfirmed) continue;
|
|
@@ -20757,18 +21262,29 @@ var init_codex_adapter = __esm({
|
|
|
20757
21262
|
processToken: checkpoint.processToken,
|
|
20758
21263
|
receiptPath: checkpoint.processReceiptPath
|
|
20759
21264
|
};
|
|
20760
|
-
|
|
20761
|
-
checkpoint
|
|
20762
|
-
guardian,
|
|
20763
|
-
options.deadlineMs ?? 5e3
|
|
21265
|
+
const crossedBoot = Boolean(
|
|
21266
|
+
checkpoint.bootIdentity && checkpoint.bootIdentity !== currentBootIdentity
|
|
20764
21267
|
);
|
|
21268
|
+
if (crossedBoot) {
|
|
21269
|
+
const receipt = await readCodexGuardianReceipt(guardian.receiptPath);
|
|
21270
|
+
if (receipt && (receipt.process_token !== checkpoint.processToken || receipt.boot_identity !== checkpoint.bootIdentity)) {
|
|
21271
|
+
throw new Error("Codex cross-boot recovery receipt ownership is unconfirmed.");
|
|
21272
|
+
}
|
|
21273
|
+
} else {
|
|
21274
|
+
await confirmGuardianTerminatedForRecovery(
|
|
21275
|
+
checkpoint,
|
|
21276
|
+
guardian,
|
|
21277
|
+
options.deadlineMs ?? 5e3
|
|
21278
|
+
);
|
|
21279
|
+
}
|
|
20765
21280
|
assertRecoveryResourceScope(checkpoint);
|
|
20766
21281
|
await removeRecoveredThread(checkpoint, options.codexHome);
|
|
20767
21282
|
await rm3(checkpoint.resourceRoot, { recursive: true, force: true });
|
|
20768
21283
|
await options.recoveryHooks.save({
|
|
20769
21284
|
...checkpoint,
|
|
20770
21285
|
processState: "terminated",
|
|
20771
|
-
cleanupConfirmed: true
|
|
21286
|
+
cleanupConfirmed: true,
|
|
21287
|
+
dispatchOutcome: crossedBoot ? "outcome_unknown" : checkpoint.dispatchOutcome
|
|
20772
21288
|
});
|
|
20773
21289
|
reconciled += 1;
|
|
20774
21290
|
}
|
|
@@ -20906,6 +21422,7 @@ var init_codex_adapter = __esm({
|
|
|
20906
21422
|
await access2(resources.codexHome, fsConstants2.R_OK | fsConstants2.W_OK);
|
|
20907
21423
|
await access2(resources.workspacePath, fsConstants2.R_OK);
|
|
20908
21424
|
const guardianManaged = Boolean(recoveryHooks && !this.dependencies.spawnProcess);
|
|
21425
|
+
const bootIdentity = guardianManaged ? await (this.dependencies.readBootIdentity ?? readInferenceSystemBootIdentity)() : null;
|
|
20909
21426
|
const processToken = guardianManaged ? randomBytes3(32).toString("hex") : null;
|
|
20910
21427
|
const guardianReceiptRoot = guardianManaged ? this.dependencies.guardianReceiptRoot ?? join4(tmpdir2(), "vtx-codex-guardian-receipts") : null;
|
|
20911
21428
|
if (guardianReceiptRoot) {
|
|
@@ -20924,6 +21441,7 @@ var init_codex_adapter = __esm({
|
|
|
20924
21441
|
processToken,
|
|
20925
21442
|
processReceiptPath,
|
|
20926
21443
|
processState: guardianManaged ? "spawn_intent" : "unmanaged",
|
|
21444
|
+
bootIdentity,
|
|
20927
21445
|
cleanupConfirmed: false,
|
|
20928
21446
|
adapterRequestId: null,
|
|
20929
21447
|
adapterResponseId: null,
|
|
@@ -20938,7 +21456,7 @@ var init_codex_adapter = __esm({
|
|
|
20938
21456
|
deadlineAtMs: input.deadlineAtMs,
|
|
20939
21457
|
signal: input.signal,
|
|
20940
21458
|
spawnProcess: this.dependencies.spawnProcess,
|
|
20941
|
-
guardian: processToken && processReceiptPath ? { processToken, receiptPath: processReceiptPath } : void 0
|
|
21459
|
+
guardian: processToken && processReceiptPath ? { processToken, receiptPath: processReceiptPath, bootIdentity: bootIdentity ?? void 0 } : void 0
|
|
20942
21460
|
});
|
|
20943
21461
|
if (guardianManaged) {
|
|
20944
21462
|
baseCheckpoint = { ...baseCheckpoint, processState: "running" };
|
|
@@ -22137,51 +22655,51 @@ var require_uri_all = __commonJS({
|
|
|
22137
22655
|
}
|
|
22138
22656
|
return uriTokens.join("");
|
|
22139
22657
|
}
|
|
22140
|
-
function resolveComponents(base2,
|
|
22658
|
+
function resolveComponents(base2, relative3) {
|
|
22141
22659
|
var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
|
|
22142
22660
|
var skipNormalization = arguments[3];
|
|
22143
22661
|
var target = {};
|
|
22144
22662
|
if (!skipNormalization) {
|
|
22145
22663
|
base2 = parse3(serialize(base2, options), options);
|
|
22146
|
-
|
|
22664
|
+
relative3 = parse3(serialize(relative3, options), options);
|
|
22147
22665
|
}
|
|
22148
22666
|
options = options || {};
|
|
22149
|
-
if (!options.tolerant &&
|
|
22150
|
-
target.scheme =
|
|
22151
|
-
target.userinfo =
|
|
22152
|
-
target.host =
|
|
22153
|
-
target.port =
|
|
22154
|
-
target.path = removeDotSegments(
|
|
22155
|
-
target.query =
|
|
22667
|
+
if (!options.tolerant && relative3.scheme) {
|
|
22668
|
+
target.scheme = relative3.scheme;
|
|
22669
|
+
target.userinfo = relative3.userinfo;
|
|
22670
|
+
target.host = relative3.host;
|
|
22671
|
+
target.port = relative3.port;
|
|
22672
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
22673
|
+
target.query = relative3.query;
|
|
22156
22674
|
} else {
|
|
22157
|
-
if (
|
|
22158
|
-
target.userinfo =
|
|
22159
|
-
target.host =
|
|
22160
|
-
target.port =
|
|
22161
|
-
target.path = removeDotSegments(
|
|
22162
|
-
target.query =
|
|
22675
|
+
if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
|
|
22676
|
+
target.userinfo = relative3.userinfo;
|
|
22677
|
+
target.host = relative3.host;
|
|
22678
|
+
target.port = relative3.port;
|
|
22679
|
+
target.path = removeDotSegments(relative3.path || "");
|
|
22680
|
+
target.query = relative3.query;
|
|
22163
22681
|
} else {
|
|
22164
|
-
if (!
|
|
22682
|
+
if (!relative3.path) {
|
|
22165
22683
|
target.path = base2.path;
|
|
22166
|
-
if (
|
|
22167
|
-
target.query =
|
|
22684
|
+
if (relative3.query !== void 0) {
|
|
22685
|
+
target.query = relative3.query;
|
|
22168
22686
|
} else {
|
|
22169
22687
|
target.query = base2.query;
|
|
22170
22688
|
}
|
|
22171
22689
|
} else {
|
|
22172
|
-
if (
|
|
22173
|
-
target.path = removeDotSegments(
|
|
22690
|
+
if (relative3.path.charAt(0) === "/") {
|
|
22691
|
+
target.path = removeDotSegments(relative3.path);
|
|
22174
22692
|
} else {
|
|
22175
22693
|
if ((base2.userinfo !== void 0 || base2.host !== void 0 || base2.port !== void 0) && !base2.path) {
|
|
22176
|
-
target.path = "/" +
|
|
22694
|
+
target.path = "/" + relative3.path;
|
|
22177
22695
|
} else if (!base2.path) {
|
|
22178
|
-
target.path =
|
|
22696
|
+
target.path = relative3.path;
|
|
22179
22697
|
} else {
|
|
22180
|
-
target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) +
|
|
22698
|
+
target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) + relative3.path;
|
|
22181
22699
|
}
|
|
22182
22700
|
target.path = removeDotSegments(target.path);
|
|
22183
22701
|
}
|
|
22184
|
-
target.query =
|
|
22702
|
+
target.query = relative3.query;
|
|
22185
22703
|
}
|
|
22186
22704
|
target.userinfo = base2.userinfo;
|
|
22187
22705
|
target.host = base2.host;
|
|
@@ -22189,10 +22707,10 @@ var require_uri_all = __commonJS({
|
|
|
22189
22707
|
}
|
|
22190
22708
|
target.scheme = base2.scheme;
|
|
22191
22709
|
}
|
|
22192
|
-
target.fragment =
|
|
22710
|
+
target.fragment = relative3.fragment;
|
|
22193
22711
|
return target;
|
|
22194
22712
|
}
|
|
22195
|
-
function
|
|
22713
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
22196
22714
|
var schemelessOptions = assign({ scheme: "null" }, options);
|
|
22197
22715
|
return serialize(resolveComponents(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true), schemelessOptions);
|
|
22198
22716
|
}
|
|
@@ -22457,7 +22975,7 @@ var require_uri_all = __commonJS({
|
|
|
22457
22975
|
exports2.removeDotSegments = removeDotSegments;
|
|
22458
22976
|
exports2.serialize = serialize;
|
|
22459
22977
|
exports2.resolveComponents = resolveComponents;
|
|
22460
|
-
exports2.resolve =
|
|
22978
|
+
exports2.resolve = resolve6;
|
|
22461
22979
|
exports2.normalize = normalize;
|
|
22462
22980
|
exports2.equal = equal;
|
|
22463
22981
|
exports2.escapeComponent = escapeComponent;
|
|
@@ -22810,18 +23328,18 @@ var require_resolve = __commonJS({
|
|
|
22810
23328
|
var util = require_util();
|
|
22811
23329
|
var SchemaObject = require_schema_obj();
|
|
22812
23330
|
var traverse = require_json_schema_traverse();
|
|
22813
|
-
module.exports =
|
|
22814
|
-
|
|
22815
|
-
|
|
22816
|
-
|
|
22817
|
-
|
|
22818
|
-
|
|
22819
|
-
|
|
22820
|
-
function
|
|
23331
|
+
module.exports = resolve6;
|
|
23332
|
+
resolve6.normalizeId = normalizeId;
|
|
23333
|
+
resolve6.fullPath = getFullPath;
|
|
23334
|
+
resolve6.url = resolveUrl;
|
|
23335
|
+
resolve6.ids = resolveIds;
|
|
23336
|
+
resolve6.inlineRef = inlineRef;
|
|
23337
|
+
resolve6.schema = resolveSchema;
|
|
23338
|
+
function resolve6(compile, root, ref) {
|
|
22821
23339
|
var refVal = this._refs[ref];
|
|
22822
23340
|
if (typeof refVal == "string") {
|
|
22823
23341
|
if (this._refs[refVal]) refVal = this._refs[refVal];
|
|
22824
|
-
else return
|
|
23342
|
+
else return resolve6.call(this, compile, root, refVal);
|
|
22825
23343
|
}
|
|
22826
23344
|
refVal = refVal || this._schemas[ref];
|
|
22827
23345
|
if (refVal instanceof SchemaObject) {
|
|
@@ -23026,7 +23544,7 @@ var require_resolve = __commonJS({
|
|
|
23026
23544
|
var require_error_classes = __commonJS({
|
|
23027
23545
|
"node_modules/ajv/lib/compile/error_classes.js"(exports, module) {
|
|
23028
23546
|
"use strict";
|
|
23029
|
-
var
|
|
23547
|
+
var resolve6 = require_resolve();
|
|
23030
23548
|
module.exports = {
|
|
23031
23549
|
Validation: errorSubclass(ValidationError),
|
|
23032
23550
|
MissingRef: errorSubclass(MissingRefError)
|
|
@@ -23041,8 +23559,8 @@ var require_error_classes = __commonJS({
|
|
|
23041
23559
|
};
|
|
23042
23560
|
function MissingRefError(baseId, ref, message) {
|
|
23043
23561
|
this.message = message || MissingRefError.message(baseId, ref);
|
|
23044
|
-
this.missingRef =
|
|
23045
|
-
this.missingSchema =
|
|
23562
|
+
this.missingRef = resolve6.url(baseId, ref);
|
|
23563
|
+
this.missingSchema = resolve6.normalizeId(resolve6.fullPath(this.missingRef));
|
|
23046
23564
|
}
|
|
23047
23565
|
function errorSubclass(Subclass) {
|
|
23048
23566
|
Subclass.prototype = Object.create(Error.prototype);
|
|
@@ -23570,7 +24088,7 @@ var require_validate = __commonJS({
|
|
|
23570
24088
|
var require_compile = __commonJS({
|
|
23571
24089
|
"node_modules/ajv/lib/compile/index.js"(exports, module) {
|
|
23572
24090
|
"use strict";
|
|
23573
|
-
var
|
|
24091
|
+
var resolve6 = require_resolve();
|
|
23574
24092
|
var util = require_util();
|
|
23575
24093
|
var errorClasses = require_error_classes();
|
|
23576
24094
|
var stableStringify = require_fast_json_stable_stringify();
|
|
@@ -23632,7 +24150,7 @@ var require_compile = __commonJS({
|
|
|
23632
24150
|
RULES,
|
|
23633
24151
|
validate: validateGenerator,
|
|
23634
24152
|
util,
|
|
23635
|
-
resolve:
|
|
24153
|
+
resolve: resolve6,
|
|
23636
24154
|
resolveRef: resolveRef2,
|
|
23637
24155
|
usePattern,
|
|
23638
24156
|
useDefault,
|
|
@@ -23694,7 +24212,7 @@ var require_compile = __commonJS({
|
|
|
23694
24212
|
return validate;
|
|
23695
24213
|
}
|
|
23696
24214
|
function resolveRef2(baseId2, ref, isRoot) {
|
|
23697
|
-
ref =
|
|
24215
|
+
ref = resolve6.url(baseId2, ref);
|
|
23698
24216
|
var refIndex = refs[ref];
|
|
23699
24217
|
var _refVal, refCode;
|
|
23700
24218
|
if (refIndex !== void 0) {
|
|
@@ -23711,11 +24229,11 @@ var require_compile = __commonJS({
|
|
|
23711
24229
|
}
|
|
23712
24230
|
}
|
|
23713
24231
|
refCode = addLocalRef(ref);
|
|
23714
|
-
var v2 =
|
|
24232
|
+
var v2 = resolve6.call(self2, localCompile, root, ref);
|
|
23715
24233
|
if (v2 === void 0) {
|
|
23716
24234
|
var localSchema = localRefs && localRefs[ref];
|
|
23717
24235
|
if (localSchema) {
|
|
23718
|
-
v2 =
|
|
24236
|
+
v2 = resolve6.inlineRef(localSchema, opts.inlineRefs) ? localSchema : compile.call(self2, localSchema, root, localRefs, baseId2);
|
|
23719
24237
|
}
|
|
23720
24238
|
}
|
|
23721
24239
|
if (v2 === void 0) {
|
|
@@ -27332,7 +27850,7 @@ var require_ajv = __commonJS({
|
|
|
27332
27850
|
"node_modules/ajv/lib/ajv.js"(exports, module) {
|
|
27333
27851
|
"use strict";
|
|
27334
27852
|
var compileSchema = require_compile();
|
|
27335
|
-
var
|
|
27853
|
+
var resolve6 = require_resolve();
|
|
27336
27854
|
var Cache = require_cache();
|
|
27337
27855
|
var SchemaObject = require_schema_obj();
|
|
27338
27856
|
var stableStringify = require_fast_json_stable_stringify();
|
|
@@ -27414,7 +27932,7 @@ var require_ajv = __commonJS({
|
|
|
27414
27932
|
var id2 = this._getId(schema);
|
|
27415
27933
|
if (id2 !== void 0 && typeof id2 != "string")
|
|
27416
27934
|
throw new Error("schema id must be string");
|
|
27417
|
-
key =
|
|
27935
|
+
key = resolve6.normalizeId(key || id2);
|
|
27418
27936
|
checkUnique(this, key);
|
|
27419
27937
|
this._schemas[key] = this._addSchema(schema, _skipValidation, _meta, true);
|
|
27420
27938
|
return this;
|
|
@@ -27458,7 +27976,7 @@ var require_ajv = __commonJS({
|
|
|
27458
27976
|
}
|
|
27459
27977
|
}
|
|
27460
27978
|
function _getSchemaFragment(self2, ref) {
|
|
27461
|
-
var res =
|
|
27979
|
+
var res = resolve6.schema.call(self2, { schema: {} }, ref);
|
|
27462
27980
|
if (res) {
|
|
27463
27981
|
var schema = res.schema, root = res.root, baseId = res.baseId;
|
|
27464
27982
|
var v = compileSchema.call(self2, schema, root, void 0, baseId);
|
|
@@ -27474,7 +27992,7 @@ var require_ajv = __commonJS({
|
|
|
27474
27992
|
}
|
|
27475
27993
|
}
|
|
27476
27994
|
function _getSchemaObj(self2, keyRef) {
|
|
27477
|
-
keyRef =
|
|
27995
|
+
keyRef = resolve6.normalizeId(keyRef);
|
|
27478
27996
|
return self2._schemas[keyRef] || self2._refs[keyRef] || self2._fragments[keyRef];
|
|
27479
27997
|
}
|
|
27480
27998
|
function removeSchema(schemaKeyRef) {
|
|
@@ -27501,7 +28019,7 @@ var require_ajv = __commonJS({
|
|
|
27501
28019
|
this._cache.del(cacheKey);
|
|
27502
28020
|
var id2 = this._getId(schemaKeyRef);
|
|
27503
28021
|
if (id2) {
|
|
27504
|
-
id2 =
|
|
28022
|
+
id2 = resolve6.normalizeId(id2);
|
|
27505
28023
|
delete this._schemas[id2];
|
|
27506
28024
|
delete this._refs[id2];
|
|
27507
28025
|
}
|
|
@@ -27525,13 +28043,13 @@ var require_ajv = __commonJS({
|
|
|
27525
28043
|
var cached2 = this._cache.get(cacheKey);
|
|
27526
28044
|
if (cached2) return cached2;
|
|
27527
28045
|
shouldAddSchema = shouldAddSchema || this._opts.addUsedSchema !== false;
|
|
27528
|
-
var id2 =
|
|
28046
|
+
var id2 = resolve6.normalizeId(this._getId(schema));
|
|
27529
28047
|
if (id2 && shouldAddSchema) checkUnique(this, id2);
|
|
27530
28048
|
var willValidate = this._opts.validateSchema !== false && !skipValidation;
|
|
27531
28049
|
var recursiveMeta;
|
|
27532
|
-
if (willValidate && !(recursiveMeta = id2 && id2 ==
|
|
28050
|
+
if (willValidate && !(recursiveMeta = id2 && id2 == resolve6.normalizeId(schema.$schema)))
|
|
27533
28051
|
this.validateSchema(schema, true);
|
|
27534
|
-
var localRefs =
|
|
28052
|
+
var localRefs = resolve6.ids.call(this, schema);
|
|
27535
28053
|
var schemaObj = new SchemaObject({
|
|
27536
28054
|
id: id2,
|
|
27537
28055
|
schema,
|
|
@@ -27797,13 +28315,13 @@ var init_runner = __esm({
|
|
|
27797
28315
|
};
|
|
27798
28316
|
defaultSleep = async (milliseconds, signal) => {
|
|
27799
28317
|
if (signal?.aborted) throw abortError();
|
|
27800
|
-
await new Promise((
|
|
28318
|
+
await new Promise((resolve6, reject) => {
|
|
27801
28319
|
const finish = (callback) => {
|
|
27802
28320
|
signal?.removeEventListener("abort", onAbort);
|
|
27803
28321
|
callback();
|
|
27804
28322
|
};
|
|
27805
28323
|
const timer = setTimeout(
|
|
27806
|
-
() => finish(
|
|
28324
|
+
() => finish(resolve6),
|
|
27807
28325
|
Math.max(MIN_SLEEP_MS, milliseconds)
|
|
27808
28326
|
);
|
|
27809
28327
|
const onAbort = () => {
|
|
@@ -28286,8 +28804,8 @@ var init_runner = __esm({
|
|
|
28286
28804
|
let failed = 0;
|
|
28287
28805
|
let acceptAttemptUpdates = true;
|
|
28288
28806
|
let wakeDrain;
|
|
28289
|
-
const drainSignal = new Promise((
|
|
28290
|
-
wakeDrain =
|
|
28807
|
+
const drainSignal = new Promise((resolve6) => {
|
|
28808
|
+
wakeDrain = resolve6;
|
|
28291
28809
|
});
|
|
28292
28810
|
const requestDrain = (reason) => {
|
|
28293
28811
|
const priority = (value) => {
|
|
@@ -28336,7 +28854,7 @@ var init_runner = __esm({
|
|
|
28336
28854
|
const metadata = await this.dependencies.discoverOAuth({
|
|
28337
28855
|
signal: this.options.signal
|
|
28338
28856
|
});
|
|
28339
|
-
let
|
|
28857
|
+
let access4 = null;
|
|
28340
28858
|
let accessExpiresAt = 0;
|
|
28341
28859
|
let refreshPromise = null;
|
|
28342
28860
|
const refreshAccessToken = async (requestOptions = {}) => {
|
|
@@ -28349,7 +28867,7 @@ var init_runner = __esm({
|
|
|
28349
28867
|
);
|
|
28350
28868
|
assertLocalCredentialIdentity(localState, refreshed.credential);
|
|
28351
28869
|
credential = refreshed.credential;
|
|
28352
|
-
|
|
28870
|
+
access4 = refreshed;
|
|
28353
28871
|
accessExpiresAt = now() + refreshed.expiresIn * 1e3;
|
|
28354
28872
|
return refreshed.accessToken;
|
|
28355
28873
|
})();
|
|
@@ -28362,10 +28880,10 @@ var init_runner = __esm({
|
|
|
28362
28880
|
await refreshAccessToken({ signal: this.options.signal });
|
|
28363
28881
|
const tokenSource = {
|
|
28364
28882
|
accessToken: async (requestOptions) => {
|
|
28365
|
-
if (!
|
|
28883
|
+
if (!access4 || accessExpiresAt - now() <= 5e3) {
|
|
28366
28884
|
return refreshAccessToken(requestOptions);
|
|
28367
28885
|
}
|
|
28368
|
-
return
|
|
28886
|
+
return access4.accessToken;
|
|
28369
28887
|
},
|
|
28370
28888
|
refreshAccessToken
|
|
28371
28889
|
};
|
|
@@ -29301,6 +29819,653 @@ var init_runner = __esm({
|
|
|
29301
29819
|
}
|
|
29302
29820
|
});
|
|
29303
29821
|
|
|
29822
|
+
// lib/inference-host/service.ts
|
|
29823
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
29824
|
+
import { createWriteStream, readFileSync } from "node:fs";
|
|
29825
|
+
import { access as access3, chmod as chmod3, mkdir as mkdir3, readFile as readFile5, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
|
|
29826
|
+
import { homedir as homedir2 } from "node:os";
|
|
29827
|
+
import { dirname as dirname4, join as join5, resolve as resolve4 } from "node:path";
|
|
29828
|
+
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;
|
|
29829
|
+
var init_service = __esm({
|
|
29830
|
+
"lib/inference-host/service.ts"() {
|
|
29831
|
+
"use strict";
|
|
29832
|
+
init_config();
|
|
29833
|
+
SERVICE_NAME = "VTX Macro Inference Host";
|
|
29834
|
+
SYSTEMD_UNIT = "vtx-inference-host.service";
|
|
29835
|
+
LAUNCHD_LABEL = "com.vtxmacro.inference-host";
|
|
29836
|
+
SERVICE_COOPERATIVE_STOP_SECONDS = 75;
|
|
29837
|
+
isWindowsSubsystemForLinux = (env = process.env, kernelRelease) => Boolean(
|
|
29838
|
+
String(env.WSL_INTEROP || "").trim() || String(env.WSL_DISTRO_NAME || "").trim() || /microsoft/iu.test(kernelRelease ?? (() => {
|
|
29839
|
+
try {
|
|
29840
|
+
return readFileSync("/proc/sys/kernel/osrelease", "utf8");
|
|
29841
|
+
} catch {
|
|
29842
|
+
return "";
|
|
29843
|
+
}
|
|
29844
|
+
})())
|
|
29845
|
+
);
|
|
29846
|
+
inferenceHostServiceManifestPath = (config2) => `${config2.statePath}.service.json`;
|
|
29847
|
+
inferenceHostServiceDesiredPath = (config2) => `${config2.statePath}.service-desired.json`;
|
|
29848
|
+
inferenceHostServiceLogPath = (config2) => `${config2.statePath}.service.log`;
|
|
29849
|
+
xmlEscape = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29850
|
+
plistEscape = xmlEscape;
|
|
29851
|
+
systemdQuote = (value) => `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("%", "%%")}"`;
|
|
29852
|
+
defaultRunCommand = async (command, args) => await new Promise((resolvePromise) => {
|
|
29853
|
+
const child = spawn5(command, [...args], {
|
|
29854
|
+
windowsHide: true,
|
|
29855
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
29856
|
+
});
|
|
29857
|
+
const stdout = [];
|
|
29858
|
+
const stderr = [];
|
|
29859
|
+
child.stdout.on("data", (chunk) => stdout.push(Buffer.from(chunk)));
|
|
29860
|
+
child.stderr.on("data", (chunk) => stderr.push(Buffer.from(chunk)));
|
|
29861
|
+
child.once("error", (error48) => resolvePromise({
|
|
29862
|
+
exitCode: 1,
|
|
29863
|
+
stdout: "",
|
|
29864
|
+
stderr: error48.message
|
|
29865
|
+
}));
|
|
29866
|
+
child.once("exit", (code) => resolvePromise({
|
|
29867
|
+
exitCode: code ?? 1,
|
|
29868
|
+
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
29869
|
+
stderr: Buffer.concat(stderr).toString("utf8")
|
|
29870
|
+
}));
|
|
29871
|
+
});
|
|
29872
|
+
managerName = (platform) => {
|
|
29873
|
+
if (platform === "win32") return "windows-task-scheduler";
|
|
29874
|
+
if (platform === "darwin") return "launch-agent";
|
|
29875
|
+
if (platform === "linux") return "systemd-user";
|
|
29876
|
+
throw new Error(`Inference-host background service is unsupported on ${platform}.`);
|
|
29877
|
+
};
|
|
29878
|
+
assertManifest = (value) => {
|
|
29879
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
29880
|
+
throw new Error("Inference-host service manifest is invalid.");
|
|
29881
|
+
}
|
|
29882
|
+
const record2 = value;
|
|
29883
|
+
if (record2.schema_version !== "vtx_inference_service_v1" || record2.adapter !== "codex" || 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.display_name !== "string" || !record2.display_name || typeof record2.log_path !== "string" || !record2.log_path || !record2.runtime_environment || typeof record2.runtime_environment !== "object" || Array.isArray(record2.runtime_environment)) {
|
|
29884
|
+
throw new Error("Inference-host service manifest is invalid.");
|
|
29885
|
+
}
|
|
29886
|
+
for (const value2 of [
|
|
29887
|
+
record2.executable,
|
|
29888
|
+
record2.script,
|
|
29889
|
+
record2.log_path
|
|
29890
|
+
]) {
|
|
29891
|
+
if (typeof value2 === "string" && /[\r\n\0]/u.test(value2)) {
|
|
29892
|
+
throw new Error("Inference-host service manifest paths contain control characters.");
|
|
29893
|
+
}
|
|
29894
|
+
}
|
|
29895
|
+
for (const [key, entry] of Object.entries(record2.runtime_environment)) {
|
|
29896
|
+
if (!key.startsWith("VTX_") || typeof entry !== "string") {
|
|
29897
|
+
throw new Error("Inference-host service runtime environment is invalid.");
|
|
29898
|
+
}
|
|
29899
|
+
}
|
|
29900
|
+
return record2;
|
|
29901
|
+
};
|
|
29902
|
+
assertDesiredState = (value) => {
|
|
29903
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
29904
|
+
throw new Error("Inference-host service desired state is invalid.");
|
|
29905
|
+
}
|
|
29906
|
+
const record2 = value;
|
|
29907
|
+
if (record2.schema_version !== "vtx_inference_service_desired_v1" || typeof record2.desired_running !== "boolean" || typeof record2.updated_at !== "string" || !Number.isFinite(Date.parse(record2.updated_at))) {
|
|
29908
|
+
throw new Error("Inference-host service desired state is invalid.");
|
|
29909
|
+
}
|
|
29910
|
+
return record2;
|
|
29911
|
+
};
|
|
29912
|
+
readInferenceHostServiceManifest = async (path) => {
|
|
29913
|
+
const raw = await readInferencePrivateFile(path, "Inference-host service manifest");
|
|
29914
|
+
if (raw === null) return null;
|
|
29915
|
+
try {
|
|
29916
|
+
return assertManifest(JSON.parse(raw));
|
|
29917
|
+
} catch (error48) {
|
|
29918
|
+
if (error48 instanceof SyntaxError) throw new Error("Inference-host service manifest is not valid JSON.");
|
|
29919
|
+
throw error48;
|
|
29920
|
+
}
|
|
29921
|
+
};
|
|
29922
|
+
readInferenceHostServiceDesired = async (path) => {
|
|
29923
|
+
const raw = await readInferencePrivateFile(path, "Inference-host service desired state");
|
|
29924
|
+
if (raw === null) return false;
|
|
29925
|
+
try {
|
|
29926
|
+
return assertDesiredState(JSON.parse(raw)).desired_running;
|
|
29927
|
+
} catch (error48) {
|
|
29928
|
+
if (error48 instanceof SyntaxError) throw new Error("Inference-host service desired state is not valid JSON.");
|
|
29929
|
+
throw error48;
|
|
29930
|
+
}
|
|
29931
|
+
};
|
|
29932
|
+
readDesiredAcrossAtomicReplacement = async (path) => {
|
|
29933
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
29934
|
+
try {
|
|
29935
|
+
return await readInferenceHostServiceDesired(path);
|
|
29936
|
+
} catch (error48) {
|
|
29937
|
+
if (!(error48 instanceof Error) || !error48.message.includes("changed while it was opened")) {
|
|
29938
|
+
throw error48;
|
|
29939
|
+
}
|
|
29940
|
+
}
|
|
29941
|
+
}
|
|
29942
|
+
return await readInferenceHostServiceDesired(path);
|
|
29943
|
+
};
|
|
29944
|
+
writeDesired = async (path, desired, now) => {
|
|
29945
|
+
await writeAtomicInferencePrivateFile(path, `${JSON.stringify({
|
|
29946
|
+
schema_version: "vtx_inference_service_desired_v1",
|
|
29947
|
+
desired_running: desired,
|
|
29948
|
+
updated_at: now.toISOString()
|
|
29949
|
+
}, null, 2)}
|
|
29950
|
+
`);
|
|
29951
|
+
};
|
|
29952
|
+
runtimeEnvironment = (config2) => {
|
|
29953
|
+
const result2 = {
|
|
29954
|
+
VTX_API_URL: config2.apiUrl,
|
|
29955
|
+
VTX_INFERENCE_HOST_HOME: dirname4(config2.codexHomePath),
|
|
29956
|
+
VTX_INFERENCE_HOST_CREDENTIAL_STORE: config2.credentialStoreMode,
|
|
29957
|
+
VTX_INFERENCE_HOST_STATE_PATH: config2.statePath,
|
|
29958
|
+
VTX_INFERENCE_HOST_LOCK_PATH: config2.processLockPath
|
|
29959
|
+
};
|
|
29960
|
+
if (config2.credentialFilePath) {
|
|
29961
|
+
result2.VTX_INFERENCE_HOST_CREDENTIAL_FILE = config2.credentialFilePath;
|
|
29962
|
+
}
|
|
29963
|
+
return result2;
|
|
29964
|
+
};
|
|
29965
|
+
serviceArguments = (script, manifestPath) => [
|
|
29966
|
+
script,
|
|
29967
|
+
"inference-host",
|
|
29968
|
+
"service",
|
|
29969
|
+
"run-internal",
|
|
29970
|
+
"--service-manifest",
|
|
29971
|
+
manifestPath
|
|
29972
|
+
];
|
|
29973
|
+
windowsOwnedCommandLine = (values) => {
|
|
29974
|
+
if (values.some((value) => value.includes('"') || value.includes("\0"))) {
|
|
29975
|
+
throw new Error("Windows inference-host service paths contain unsupported characters.");
|
|
29976
|
+
}
|
|
29977
|
+
return values.map((value) => `"${value}"`).join(" ");
|
|
29978
|
+
};
|
|
29979
|
+
vbScriptString = (value) => `"${value.replaceAll('"', '""')}"`;
|
|
29980
|
+
windowsServiceLauncher = (executable, args) => `Option Explicit\r
|
|
29981
|
+
Dim shell, exitCode\r
|
|
29982
|
+
Set shell = CreateObject("WScript.Shell")\r
|
|
29983
|
+
exitCode = shell.Run(${vbScriptString(windowsOwnedCommandLine([executable, ...args]))}, 0, True)\r
|
|
29984
|
+
WScript.Quit exitCode\r
|
|
29985
|
+
`;
|
|
29986
|
+
windowsTaskXml = (launcherPath, windowsDirectory, username) => `<?xml version="1.0" encoding="UTF-16"?>
|
|
29987
|
+
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
29988
|
+
<RegistrationInfo><Description>${xmlEscape(SERVICE_NAME)}</Description></RegistrationInfo>
|
|
29989
|
+
<Triggers>
|
|
29990
|
+
<LogonTrigger><Enabled>true</Enabled><UserId>${xmlEscape(username)}</UserId></LogonTrigger>
|
|
29991
|
+
<TimeTrigger>
|
|
29992
|
+
<StartBoundary>2020-01-01T00:00:00</StartBoundary>
|
|
29993
|
+
<Enabled>true</Enabled>
|
|
29994
|
+
<Repetition><Interval>PT1M</Interval><StopAtDurationEnd>false</StopAtDurationEnd></Repetition>
|
|
29995
|
+
</TimeTrigger>
|
|
29996
|
+
</Triggers>
|
|
29997
|
+
<Principals><Principal id="Author"><UserId>${xmlEscape(username)}</UserId><LogonType>InteractiveToken</LogonType><RunLevel>LeastPrivilege</RunLevel></Principal></Principals>
|
|
29998
|
+
<Settings>
|
|
29999
|
+
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
|
30000
|
+
<Hidden>true</Hidden>
|
|
30001
|
+
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
|
|
30002
|
+
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
|
|
30003
|
+
<StartWhenAvailable>true</StartWhenAvailable>
|
|
30004
|
+
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
|
30005
|
+
<RestartOnFailure><Interval>PT1M</Interval><Count>255</Count></RestartOnFailure>
|
|
30006
|
+
</Settings>
|
|
30007
|
+
<Actions Context="Author"><Exec><Command>${xmlEscape(`${windowsDirectory}\\System32\\wscript.exe`)}</Command><Arguments>${xmlEscape(`//B //NoLogo "${launcherPath}"`)}</Arguments></Exec></Actions>
|
|
30008
|
+
</Task>
|
|
30009
|
+
`;
|
|
30010
|
+
systemdUnit = (executable, args) => `[Unit]
|
|
30011
|
+
Description=${SERVICE_NAME}
|
|
30012
|
+
After=network-online.target
|
|
30013
|
+
Wants=network-online.target
|
|
30014
|
+
StartLimitIntervalSec=0
|
|
30015
|
+
|
|
30016
|
+
[Service]
|
|
30017
|
+
Type=simple
|
|
30018
|
+
ExecStart=${[executable, ...args].map(systemdQuote).join(" ")}
|
|
30019
|
+
Restart=on-failure
|
|
30020
|
+
RestartSec=5s
|
|
30021
|
+
TimeoutStopSec=${SERVICE_COOPERATIVE_STOP_SECONDS}s
|
|
30022
|
+
|
|
30023
|
+
[Install]
|
|
30024
|
+
WantedBy=default.target
|
|
30025
|
+
`;
|
|
30026
|
+
launchAgentPlist = (executable, args, logPath) => `<?xml version="1.0" encoding="UTF-8"?>
|
|
30027
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
30028
|
+
<plist version="1.0"><dict>
|
|
30029
|
+
<key>Label</key><string>${LAUNCHD_LABEL}</string>
|
|
30030
|
+
<key>ProgramArguments</key><array>${[executable, ...args].map((arg) => `<string>${plistEscape(arg)}</string>`).join("")}</array>
|
|
30031
|
+
<key>RunAtLoad</key><true/>
|
|
30032
|
+
<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>
|
|
30033
|
+
<key>ProcessType</key><string>Background</string>
|
|
30034
|
+
<key>ThrottleInterval</key><integer>5</integer>
|
|
30035
|
+
<key>ExitTimeOut</key><integer>${SERVICE_COOPERATIVE_STOP_SECONDS}</integer>
|
|
30036
|
+
<key>StandardOutPath</key><string>${plistEscape(logPath)}</string>
|
|
30037
|
+
<key>StandardErrorPath</key><string>${plistEscape(logPath)}</string>
|
|
30038
|
+
</dict></plist>
|
|
30039
|
+
`;
|
|
30040
|
+
InferenceHostServiceManager = class {
|
|
30041
|
+
constructor(config2, dependencies = {}) {
|
|
30042
|
+
this.config = config2;
|
|
30043
|
+
this.platform = dependencies.platform ?? process.platform;
|
|
30044
|
+
this.home = dependencies.homedir ?? homedir2();
|
|
30045
|
+
this.executable = resolve4(dependencies.executable ?? process.execPath);
|
|
30046
|
+
this.script = resolve4(dependencies.script ?? process.argv[1] ?? "");
|
|
30047
|
+
this.username = dependencies.username ?? ([process.env.USERDOMAIN, process.env.USERNAME].filter(Boolean).join("\\") || process.env.USER || "");
|
|
30048
|
+
this.windowsDirectory = (dependencies.windowsDirectory ?? process.env.SystemRoot ?? process.env.WINDIR ?? "C:\\Windows").replace(/[\\/]+$/u, "");
|
|
30049
|
+
this.runCommand = dependencies.runCommand ?? defaultRunCommand;
|
|
30050
|
+
this.now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
30051
|
+
this.sleep = dependencies.sleep ?? (async (milliseconds) => {
|
|
30052
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
|
|
30053
|
+
});
|
|
30054
|
+
this.stopWaitAttempts = dependencies.stopWaitAttempts ?? SERVICE_COOPERATIVE_STOP_SECONDS * 4;
|
|
30055
|
+
this.startWaitAttempts = dependencies.startWaitAttempts ?? 40;
|
|
30056
|
+
this.acquireProcessLock = dependencies.acquireProcessLock ?? acquireInferenceHostProcessLock;
|
|
30057
|
+
managerName(this.platform);
|
|
30058
|
+
if (dependencies.platform === void 0 && this.platform === "linux" && isWindowsSubsystemForLinux()) {
|
|
30059
|
+
throw new Error(
|
|
30060
|
+
"Windows-login auto-start requires the native Windows VTX CLI. A WSL-only service cannot start the WSL virtual machine at login."
|
|
30061
|
+
);
|
|
30062
|
+
}
|
|
30063
|
+
}
|
|
30064
|
+
manifestPath() {
|
|
30065
|
+
return inferenceHostServiceManifestPath(this.config);
|
|
30066
|
+
}
|
|
30067
|
+
desiredPath() {
|
|
30068
|
+
return inferenceHostServiceDesiredPath(this.config);
|
|
30069
|
+
}
|
|
30070
|
+
logPath() {
|
|
30071
|
+
return inferenceHostServiceLogPath(this.config);
|
|
30072
|
+
}
|
|
30073
|
+
controlLockPath() {
|
|
30074
|
+
return `${this.config.processLockPath}.service-control`;
|
|
30075
|
+
}
|
|
30076
|
+
async withControlLock(operation) {
|
|
30077
|
+
let lock2 = null;
|
|
30078
|
+
for (let attempt = 0; attempt < 400; attempt += 1) {
|
|
30079
|
+
try {
|
|
30080
|
+
lock2 = await this.acquireProcessLock(this.controlLockPath());
|
|
30081
|
+
break;
|
|
30082
|
+
} catch (error48) {
|
|
30083
|
+
if (!/already owns/iu.test(error48 instanceof Error ? error48.message : "")) throw error48;
|
|
30084
|
+
await this.sleep(250);
|
|
30085
|
+
}
|
|
30086
|
+
}
|
|
30087
|
+
if (!lock2) {
|
|
30088
|
+
throw new Error("Another inference-host service control operation did not finish within 100 seconds.");
|
|
30089
|
+
}
|
|
30090
|
+
try {
|
|
30091
|
+
return await operation();
|
|
30092
|
+
} finally {
|
|
30093
|
+
await lock2.release();
|
|
30094
|
+
}
|
|
30095
|
+
}
|
|
30096
|
+
windowsTaskName() {
|
|
30097
|
+
const identity = this.username.replaceAll(/[^A-Za-z0-9_.@-]+/gu, "_").slice(-80) || "current-user";
|
|
30098
|
+
return `VTX Macro Inference Host (${identity})`;
|
|
30099
|
+
}
|
|
30100
|
+
windowsPowerShell(script) {
|
|
30101
|
+
return [
|
|
30102
|
+
"-NoLogo",
|
|
30103
|
+
"-NoProfile",
|
|
30104
|
+
"-NonInteractive",
|
|
30105
|
+
"-EncodedCommand",
|
|
30106
|
+
Buffer.from(script, "utf16le").toString("base64")
|
|
30107
|
+
];
|
|
30108
|
+
}
|
|
30109
|
+
definitionPath() {
|
|
30110
|
+
if (this.platform === "win32") return `${this.config.statePath}.service-task.xml`;
|
|
30111
|
+
if (this.platform === "darwin") return join5(this.home, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
30112
|
+
return join5(this.home, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
30113
|
+
}
|
|
30114
|
+
windowsLauncherPath() {
|
|
30115
|
+
return `${this.config.statePath}.service-launcher.vbs`;
|
|
30116
|
+
}
|
|
30117
|
+
async managerCommand(action) {
|
|
30118
|
+
const definition = this.definitionPath();
|
|
30119
|
+
if (this.platform === "win32") {
|
|
30120
|
+
const taskName = this.windowsTaskName();
|
|
30121
|
+
if (action === "install") return await this.runCommand("schtasks.exe", ["/Create", "/F", "/TN", taskName, "/XML", definition]);
|
|
30122
|
+
const quotedName = taskName.replaceAll("'", "''");
|
|
30123
|
+
if (action === "start") return await this.runCommand("powershell.exe", this.windowsPowerShell(
|
|
30124
|
+
`$ErrorActionPreference='Stop'; $task=Get-ScheduledTask -TaskName '${quotedName}' -ErrorAction Stop; Enable-ScheduledTask -InputObject $task -ErrorAction Stop | Out-Null; Start-ScheduledTask -TaskName '${quotedName}'`
|
|
30125
|
+
));
|
|
30126
|
+
if (action === "stop") return await this.runCommand("powershell.exe", this.windowsPowerShell(
|
|
30127
|
+
`$ErrorActionPreference='Stop'; $task=Get-ScheduledTask -TaskName '${quotedName}' -ErrorAction SilentlyContinue; if($null -ne $task) { Stop-ScheduledTask -InputObject $task -ErrorAction Stop; Disable-ScheduledTask -InputObject $task -ErrorAction Stop | Out-Null }`
|
|
30128
|
+
));
|
|
30129
|
+
if (action === "status") return await this.runCommand("powershell.exe", this.windowsPowerShell(
|
|
30130
|
+
`$ErrorActionPreference='Stop'; [Console]::Out.Write([int](Get-ScheduledTask -TaskName '${quotedName}').State)`
|
|
30131
|
+
));
|
|
30132
|
+
return await this.runCommand("powershell.exe", this.windowsPowerShell(
|
|
30133
|
+
`$ErrorActionPreference='Stop'; $task=Get-ScheduledTask -TaskName '${quotedName}' -ErrorAction SilentlyContinue; if($null -ne $task) { Unregister-ScheduledTask -InputObject $task -Confirm:$false -ErrorAction Stop }; if($null -ne (Get-ScheduledTask -TaskName '${quotedName}' -ErrorAction SilentlyContinue)) { throw 'scheduled task still exists after unregister' }`
|
|
30134
|
+
));
|
|
30135
|
+
}
|
|
30136
|
+
if (this.platform === "darwin") {
|
|
30137
|
+
const domain2 = `gui/${typeof process.getuid === "function" ? process.getuid() : 0}`;
|
|
30138
|
+
if (action === "install") return { exitCode: 0, stdout: "definition-written", stderr: "" };
|
|
30139
|
+
if (action === "start") return await this.runCommand("launchctl", ["bootstrap", domain2, definition]);
|
|
30140
|
+
if (action === "stop") return await this.runCommand("launchctl", ["bootout", domain2, definition]);
|
|
30141
|
+
if (action === "status") return await this.runCommand("launchctl", ["print", `${domain2}/${LAUNCHD_LABEL}`]);
|
|
30142
|
+
return await this.runCommand("launchctl", ["bootout", domain2, definition]);
|
|
30143
|
+
}
|
|
30144
|
+
if (action === "install") return await this.runCommand("systemctl", ["--user", "enable", SYSTEMD_UNIT]);
|
|
30145
|
+
if (action === "start") return await this.runCommand("systemctl", ["--user", "start", SYSTEMD_UNIT]);
|
|
30146
|
+
if (action === "stop") return await this.runCommand("systemctl", ["--user", "stop", SYSTEMD_UNIT]);
|
|
30147
|
+
if (action === "status") return await this.runCommand("systemctl", ["--user", "show", SYSTEMD_UNIT, "--property=ActiveState,SubState,UnitFileState", "--no-pager"]);
|
|
30148
|
+
return await this.runCommand("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT]);
|
|
30149
|
+
}
|
|
30150
|
+
async waitForManagerActive() {
|
|
30151
|
+
for (let attempt = 0; attempt < this.startWaitAttempts; attempt += 1) {
|
|
30152
|
+
const status = await this.status();
|
|
30153
|
+
if (status.manager_active) return status;
|
|
30154
|
+
await this.sleep(250);
|
|
30155
|
+
}
|
|
30156
|
+
throw new Error("Background service did not reach an active state within 10 seconds.");
|
|
30157
|
+
}
|
|
30158
|
+
async install(options) {
|
|
30159
|
+
return await this.withControlLock(async () => await this.installUnlocked(options));
|
|
30160
|
+
}
|
|
30161
|
+
async installUnlocked(options) {
|
|
30162
|
+
if (await readInferenceHostServiceManifest(this.manifestPath())) {
|
|
30163
|
+
await this.uninstallUnlocked();
|
|
30164
|
+
}
|
|
30165
|
+
await access3(this.executable);
|
|
30166
|
+
await access3(this.script);
|
|
30167
|
+
const manifest = assertManifest({
|
|
30168
|
+
schema_version: "vtx_inference_service_v1",
|
|
30169
|
+
installed_at: this.now().toISOString(),
|
|
30170
|
+
adapter: options.adapter,
|
|
30171
|
+
executable: this.executable,
|
|
30172
|
+
script: this.script,
|
|
30173
|
+
display_name: options.displayName,
|
|
30174
|
+
log_path: this.logPath(),
|
|
30175
|
+
runtime_environment: runtimeEnvironment(this.config)
|
|
30176
|
+
});
|
|
30177
|
+
const args = serviceArguments(this.script, this.manifestPath());
|
|
30178
|
+
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);
|
|
30179
|
+
let managerInstallAttempted = false;
|
|
30180
|
+
try {
|
|
30181
|
+
await writeAtomicInferencePrivateFile(this.manifestPath(), `${JSON.stringify(manifest, null, 2)}
|
|
30182
|
+
`);
|
|
30183
|
+
await writeDesired(this.desiredPath(), options.startImmediately !== false, this.now());
|
|
30184
|
+
await mkdir3(dirname4(this.definitionPath()), { recursive: true, mode: 448 });
|
|
30185
|
+
if (this.platform === "win32") {
|
|
30186
|
+
await writeAtomicInferencePrivateFile(
|
|
30187
|
+
this.windowsLauncherPath(),
|
|
30188
|
+
windowsServiceLauncher(this.executable, args)
|
|
30189
|
+
);
|
|
30190
|
+
await writeFile2(this.definitionPath(), `\uFEFF${definition}`, {
|
|
30191
|
+
encoding: "utf16le",
|
|
30192
|
+
mode: 384
|
|
30193
|
+
});
|
|
30194
|
+
} else {
|
|
30195
|
+
await writeFile2(this.definitionPath(), definition, { encoding: "utf8", mode: 384 });
|
|
30196
|
+
await chmod3(this.definitionPath(), 384);
|
|
30197
|
+
}
|
|
30198
|
+
if (this.platform === "linux") {
|
|
30199
|
+
const reload = await this.runCommand("systemctl", ["--user", "daemon-reload"]);
|
|
30200
|
+
if (reload.exitCode !== 0) throw new Error(`systemd user daemon reload failed: ${reload.stderr.trim()}`);
|
|
30201
|
+
}
|
|
30202
|
+
managerInstallAttempted = true;
|
|
30203
|
+
const installed = await this.managerCommand("install");
|
|
30204
|
+
if (installed.exitCode !== 0) throw new Error(`Background service installation failed: ${installed.stderr.trim()}`);
|
|
30205
|
+
if (options.startImmediately !== false) {
|
|
30206
|
+
const started = await this.managerCommand("start");
|
|
30207
|
+
if (started.exitCode !== 0 && !/already running|in progress/iu.test(`${started.stdout}
|
|
30208
|
+
${started.stderr}`)) {
|
|
30209
|
+
throw new Error(`Background service start failed: ${started.stderr.trim()}`);
|
|
30210
|
+
}
|
|
30211
|
+
await this.waitForManagerActive();
|
|
30212
|
+
}
|
|
30213
|
+
} catch (error48) {
|
|
30214
|
+
await writeDesired(this.desiredPath(), false, this.now()).catch(() => void 0);
|
|
30215
|
+
if (managerInstallAttempted) {
|
|
30216
|
+
const cleanup = await this.managerCommand("uninstall").catch((cleanupError) => ({
|
|
30217
|
+
exitCode: 1,
|
|
30218
|
+
stdout: "",
|
|
30219
|
+
stderr: cleanupError instanceof Error ? cleanupError.message : "unknown cleanup error"
|
|
30220
|
+
}));
|
|
30221
|
+
if (cleanup.exitCode !== 0 && !/not found|does not exist|not loaded|no such process|cannot find/iu.test(`${cleanup.stdout}
|
|
30222
|
+
${cleanup.stderr}`)) {
|
|
30223
|
+
throw new Error(
|
|
30224
|
+
`Background service setup failed and manager cleanup was not confirmed: ${cleanup.stderr.trim()}`,
|
|
30225
|
+
{ cause: error48 }
|
|
30226
|
+
);
|
|
30227
|
+
}
|
|
30228
|
+
}
|
|
30229
|
+
await rm4(this.definitionPath(), { force: true }).catch(() => void 0);
|
|
30230
|
+
if (this.platform === "win32") {
|
|
30231
|
+
await rm4(this.windowsLauncherPath(), { force: true }).catch(() => void 0);
|
|
30232
|
+
}
|
|
30233
|
+
await rm4(this.manifestPath(), { force: true }).catch(() => void 0);
|
|
30234
|
+
await rm4(this.desiredPath(), { force: true }).catch(() => void 0);
|
|
30235
|
+
if (this.platform === "linux") {
|
|
30236
|
+
await this.runCommand("systemctl", ["--user", "daemon-reload"]).catch(() => void 0);
|
|
30237
|
+
}
|
|
30238
|
+
throw error48;
|
|
30239
|
+
}
|
|
30240
|
+
return await this.status();
|
|
30241
|
+
}
|
|
30242
|
+
async start() {
|
|
30243
|
+
return await this.withControlLock(async () => await this.startUnlocked());
|
|
30244
|
+
}
|
|
30245
|
+
async startUnlocked() {
|
|
30246
|
+
if (!await readInferenceHostServiceManifest(this.manifestPath())) {
|
|
30247
|
+
throw new Error("Inference-host service is not installed.");
|
|
30248
|
+
}
|
|
30249
|
+
await writeDesired(this.desiredPath(), true, this.now());
|
|
30250
|
+
const result2 = await this.managerCommand("start");
|
|
30251
|
+
if (result2.exitCode !== 0 && !/already running|in progress/iu.test(`${result2.stdout}
|
|
30252
|
+
${result2.stderr}`)) {
|
|
30253
|
+
throw new Error(`Background service start failed: ${result2.stderr.trim()}`);
|
|
30254
|
+
}
|
|
30255
|
+
try {
|
|
30256
|
+
return await this.waitForManagerActive();
|
|
30257
|
+
} catch (error48) {
|
|
30258
|
+
await writeDesired(this.desiredPath(), false, this.now());
|
|
30259
|
+
await this.managerCommand("stop").catch(() => void 0);
|
|
30260
|
+
throw error48;
|
|
30261
|
+
}
|
|
30262
|
+
}
|
|
30263
|
+
async stop() {
|
|
30264
|
+
return await this.withControlLock(async () => await this.stopUnlocked());
|
|
30265
|
+
}
|
|
30266
|
+
async stopUnlocked() {
|
|
30267
|
+
if (!await readInferenceHostServiceManifest(this.manifestPath())) {
|
|
30268
|
+
throw new Error("Inference-host service is not installed.");
|
|
30269
|
+
}
|
|
30270
|
+
await writeDesired(this.desiredPath(), false, this.now());
|
|
30271
|
+
const serviceLockPath = `${this.config.processLockPath}.service`;
|
|
30272
|
+
let serviceReleased = false;
|
|
30273
|
+
for (let attempt = 0; attempt < this.stopWaitAttempts; attempt += 1) {
|
|
30274
|
+
try {
|
|
30275
|
+
const probe = await this.acquireProcessLock(serviceLockPath);
|
|
30276
|
+
await probe.release();
|
|
30277
|
+
serviceReleased = true;
|
|
30278
|
+
break;
|
|
30279
|
+
} catch (error48) {
|
|
30280
|
+
if (error48 instanceof Error && error48.message.includes("Another inference host process already owns")) {
|
|
30281
|
+
await this.sleep(250);
|
|
30282
|
+
continue;
|
|
30283
|
+
}
|
|
30284
|
+
throw error48;
|
|
30285
|
+
}
|
|
30286
|
+
}
|
|
30287
|
+
if (!serviceReleased) {
|
|
30288
|
+
throw new Error(
|
|
30289
|
+
`Inference-host worker did not stop cooperatively within ${SERVICE_COOPERATIVE_STOP_SECONDS} seconds; refusing forced termination while cleanup may be pending.`
|
|
30290
|
+
);
|
|
30291
|
+
}
|
|
30292
|
+
const result2 = await this.managerCommand("stop");
|
|
30293
|
+
if (result2.exitCode !== 0 && !/not running|not found|does not exist|not loaded|cannot find|no such process/iu.test(`${result2.stdout}
|
|
30294
|
+
${result2.stderr}`)) {
|
|
30295
|
+
throw new Error(`Background service stop failed: ${result2.stderr.trim()}`);
|
|
30296
|
+
}
|
|
30297
|
+
const status = await this.status();
|
|
30298
|
+
if (status.manager_active) {
|
|
30299
|
+
throw new Error("Background service manager still reports the service active after stop.");
|
|
30300
|
+
}
|
|
30301
|
+
return status;
|
|
30302
|
+
}
|
|
30303
|
+
async status() {
|
|
30304
|
+
const manifest = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30305
|
+
const desired = await readInferenceHostServiceDesired(this.desiredPath());
|
|
30306
|
+
const result2 = await this.managerCommand("status");
|
|
30307
|
+
const output3 = result2.stdout.trim();
|
|
30308
|
+
const managerActive = result2.exitCode === 0 && (this.platform === "linux" ? /(?:^|\n)ActiveState=active(?:\n|$)/u.test(output3) : this.platform === "win32" ? output3.trim() === "4" : /\bstate\s*=\s*running\b/iu.test(output3));
|
|
30309
|
+
return {
|
|
30310
|
+
installed: manifest !== null,
|
|
30311
|
+
desired_running: desired,
|
|
30312
|
+
manager_active: managerActive,
|
|
30313
|
+
manager: managerName(this.platform),
|
|
30314
|
+
manager_state: result2.exitCode === 0 ? output3 || "installed" : "not-installed",
|
|
30315
|
+
adapter: manifest?.adapter ?? null,
|
|
30316
|
+
log_path: manifest?.log_path ?? this.logPath()
|
|
30317
|
+
};
|
|
30318
|
+
}
|
|
30319
|
+
async logs(lines = 100) {
|
|
30320
|
+
const manifest = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30321
|
+
const path = manifest?.log_path ?? this.logPath();
|
|
30322
|
+
try {
|
|
30323
|
+
const contents = await readFile5(path, "utf8");
|
|
30324
|
+
return `${contents.trimEnd().split(/\r?\n/u).slice(-lines).join("\n")}
|
|
30325
|
+
`;
|
|
30326
|
+
} catch (error48) {
|
|
30327
|
+
if (error48.code === "ENOENT") return "";
|
|
30328
|
+
throw error48;
|
|
30329
|
+
}
|
|
30330
|
+
}
|
|
30331
|
+
async uninstall() {
|
|
30332
|
+
return await this.withControlLock(async () => await this.uninstallUnlocked());
|
|
30333
|
+
}
|
|
30334
|
+
async uninstallUnlocked() {
|
|
30335
|
+
const manifest = await readInferenceHostServiceManifest(this.manifestPath());
|
|
30336
|
+
if (!manifest) throw new Error("Inference-host service is not installed.");
|
|
30337
|
+
const current = await this.status();
|
|
30338
|
+
if (current.desired_running || current.manager_active) {
|
|
30339
|
+
await this.stopUnlocked();
|
|
30340
|
+
} else {
|
|
30341
|
+
await writeDesired(this.desiredPath(), false, this.now());
|
|
30342
|
+
}
|
|
30343
|
+
const result2 = await this.managerCommand("uninstall");
|
|
30344
|
+
if (result2.exitCode !== 0 && !/not found|does not exist|not loaded|no such process|cannot find/iu.test(`${result2.stdout}
|
|
30345
|
+
${result2.stderr}`)) {
|
|
30346
|
+
throw new Error(`Background service uninstall failed: ${result2.stderr.trim()}`);
|
|
30347
|
+
}
|
|
30348
|
+
await rm4(this.definitionPath(), { force: true });
|
|
30349
|
+
if (this.platform === "win32") await rm4(this.windowsLauncherPath(), { force: true });
|
|
30350
|
+
if (this.platform === "linux") await this.runCommand("systemctl", ["--user", "daemon-reload"]);
|
|
30351
|
+
await rm4(this.manifestPath(), { force: true });
|
|
30352
|
+
await rm4(this.desiredPath(), { force: true });
|
|
30353
|
+
return {
|
|
30354
|
+
installed: false,
|
|
30355
|
+
desired_running: false,
|
|
30356
|
+
manager_active: false,
|
|
30357
|
+
manager: managerName(this.platform),
|
|
30358
|
+
manager_state: "not-installed",
|
|
30359
|
+
adapter: null,
|
|
30360
|
+
log_path: manifest.log_path
|
|
30361
|
+
};
|
|
30362
|
+
}
|
|
30363
|
+
};
|
|
30364
|
+
appendServiceLog = async (path, event, fields = {}) => {
|
|
30365
|
+
await mkdir3(dirname4(path), { recursive: true, mode: 448 });
|
|
30366
|
+
const stream = createWriteStream(path, { flags: "a", mode: 384 });
|
|
30367
|
+
await new Promise((resolvePromise, reject) => {
|
|
30368
|
+
stream.once("error", reject);
|
|
30369
|
+
stream.end(`${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), event, ...fields })}
|
|
30370
|
+
`, resolvePromise);
|
|
30371
|
+
});
|
|
30372
|
+
};
|
|
30373
|
+
spawnServiceChild = async (manifest, signal) => {
|
|
30374
|
+
const args = [
|
|
30375
|
+
manifest.script,
|
|
30376
|
+
"inference-host",
|
|
30377
|
+
"run",
|
|
30378
|
+
"--json",
|
|
30379
|
+
"--display-name",
|
|
30380
|
+
manifest.display_name
|
|
30381
|
+
];
|
|
30382
|
+
const startedAt = Date.now();
|
|
30383
|
+
const log = createWriteStream(manifest.log_path, { flags: "a", mode: 384 });
|
|
30384
|
+
return await new Promise((resolvePromise, reject) => {
|
|
30385
|
+
const child = spawn5(manifest.executable, args, {
|
|
30386
|
+
env: { ...process.env, ...manifest.runtime_environment },
|
|
30387
|
+
windowsHide: true,
|
|
30388
|
+
stdio: ["ignore", log, log]
|
|
30389
|
+
});
|
|
30390
|
+
const onAbort = () => child.kill("SIGTERM");
|
|
30391
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
30392
|
+
child.once("error", (error48) => {
|
|
30393
|
+
signal.removeEventListener("abort", onAbort);
|
|
30394
|
+
log.end();
|
|
30395
|
+
reject(error48);
|
|
30396
|
+
});
|
|
30397
|
+
child.once("exit", (code) => {
|
|
30398
|
+
signal.removeEventListener("abort", onAbort);
|
|
30399
|
+
log.end();
|
|
30400
|
+
resolvePromise({ exitCode: code ?? 1, uptimeMs: Date.now() - startedAt });
|
|
30401
|
+
});
|
|
30402
|
+
});
|
|
30403
|
+
};
|
|
30404
|
+
runInferenceHostServiceSupervisor = async (manifestPath, options = {}) => {
|
|
30405
|
+
const manifest = await readInferenceHostServiceManifest(manifestPath);
|
|
30406
|
+
if (!manifest) throw new Error("Inference-host service manifest is missing.");
|
|
30407
|
+
const desiredPath = `${manifest.runtime_environment.VTX_INFERENCE_HOST_STATE_PATH}.service-desired.json`;
|
|
30408
|
+
const signal = options.signal ?? new AbortController().signal;
|
|
30409
|
+
const sleep4 = options.sleep ?? (async (milliseconds) => {
|
|
30410
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
|
|
30411
|
+
});
|
|
30412
|
+
const launch = options.runWorker ?? options.spawnChild ?? spawnServiceChild;
|
|
30413
|
+
let failures = 0;
|
|
30414
|
+
await appendServiceLog(manifest.log_path, "service_supervisor_started", { adapter: manifest.adapter });
|
|
30415
|
+
while (!signal.aborted && await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
30416
|
+
try {
|
|
30417
|
+
const workerController = new AbortController();
|
|
30418
|
+
const forwardAbort = () => workerController.abort();
|
|
30419
|
+
signal.addEventListener("abort", forwardAbort, { once: true });
|
|
30420
|
+
let workerComplete = false;
|
|
30421
|
+
let monitorError = null;
|
|
30422
|
+
const desiredMonitor = (async () => {
|
|
30423
|
+
while (!workerComplete && !workerController.signal.aborted) {
|
|
30424
|
+
await sleep4(500);
|
|
30425
|
+
if (!await readDesiredAcrossAtomicReplacement(desiredPath)) {
|
|
30426
|
+
workerController.abort();
|
|
30427
|
+
break;
|
|
30428
|
+
}
|
|
30429
|
+
}
|
|
30430
|
+
})().catch((error48) => {
|
|
30431
|
+
monitorError = error48;
|
|
30432
|
+
workerController.abort();
|
|
30433
|
+
});
|
|
30434
|
+
let result2;
|
|
30435
|
+
try {
|
|
30436
|
+
result2 = await launch(manifest, workerController.signal);
|
|
30437
|
+
} finally {
|
|
30438
|
+
workerComplete = true;
|
|
30439
|
+
workerController.abort();
|
|
30440
|
+
signal.removeEventListener("abort", forwardAbort);
|
|
30441
|
+
await desiredMonitor;
|
|
30442
|
+
}
|
|
30443
|
+
if (monitorError) throw monitorError;
|
|
30444
|
+
if (signal.aborted || !await readDesiredAcrossAtomicReplacement(desiredPath)) break;
|
|
30445
|
+
failures = result2.uptimeMs >= 6e4 ? 0 : failures + 1;
|
|
30446
|
+
const retryAfterMs = Math.min(1e3 * 2 ** Math.min(failures, 5), 3e4);
|
|
30447
|
+
await appendServiceLog(manifest.log_path, "worker_exited", {
|
|
30448
|
+
exit_code: result2.exitCode,
|
|
30449
|
+
uptime_ms: result2.uptimeMs,
|
|
30450
|
+
retry_after_ms: retryAfterMs
|
|
30451
|
+
});
|
|
30452
|
+
await sleep4(retryAfterMs);
|
|
30453
|
+
} catch (error48) {
|
|
30454
|
+
if (signal.aborted) break;
|
|
30455
|
+
failures += 1;
|
|
30456
|
+
const retryAfterMs = Math.min(1e3 * 2 ** Math.min(failures, 5), 3e4);
|
|
30457
|
+
await appendServiceLog(manifest.log_path, "worker_launch_failed", {
|
|
30458
|
+
error: error48 instanceof Error ? error48.message : "unknown",
|
|
30459
|
+
retry_after_ms: retryAfterMs
|
|
30460
|
+
});
|
|
30461
|
+
await sleep4(retryAfterMs);
|
|
30462
|
+
}
|
|
30463
|
+
}
|
|
30464
|
+
await appendServiceLog(manifest.log_path, "service_supervisor_stopped");
|
|
30465
|
+
};
|
|
30466
|
+
}
|
|
30467
|
+
});
|
|
30468
|
+
|
|
29304
30469
|
// lib/inference-host/cli.ts
|
|
29305
30470
|
var cli_exports = {};
|
|
29306
30471
|
__export(cli_exports, {
|
|
@@ -29308,9 +30473,9 @@ __export(cli_exports, {
|
|
|
29308
30473
|
runInferenceHostCli: () => runInferenceHostCli
|
|
29309
30474
|
});
|
|
29310
30475
|
import { randomUUID } from "node:crypto";
|
|
29311
|
-
import { spawn as
|
|
29312
|
-
import { lstat as lstat4, realpath as realpath4, rm as
|
|
29313
|
-
import { join as
|
|
30476
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
30477
|
+
import { lstat as lstat4, realpath as realpath4, rm as rm5 } from "node:fs/promises";
|
|
30478
|
+
import { join as join6, resolve as resolve5 } from "node:path";
|
|
29314
30479
|
async function runInferenceHostCli(argv2, env = process.env, dependencies = {}) {
|
|
29315
30480
|
const warnings = [];
|
|
29316
30481
|
try {
|
|
@@ -29355,6 +30520,9 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
29355
30520
|
async () => await agentFail(config2, parsed, dependencies, warnings)
|
|
29356
30521
|
);
|
|
29357
30522
|
}
|
|
30523
|
+
if (parsed.command === "service") {
|
|
30524
|
+
return await serviceCommand(config2, parsed, env, dependencies, warnings);
|
|
30525
|
+
}
|
|
29358
30526
|
if (parsed.command === "status") {
|
|
29359
30527
|
return await localStatus(config2, parsed, dependencies, warnings);
|
|
29360
30528
|
}
|
|
@@ -29371,7 +30539,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
29371
30539
|
return await cleanupLogin(config2, parsed, dependencies, warnings, true);
|
|
29372
30540
|
}
|
|
29373
30541
|
throw new Error(
|
|
29374
|
-
"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]"
|
|
30542
|
+
"Usage: vtx inference-host <login|codex-login|run|agent-connect|agent-run|agent-next|agent-complete|agent-fail|service|status|doctor|logout|codex-logout|revoke> [--json]"
|
|
29375
30543
|
);
|
|
29376
30544
|
} catch (error48) {
|
|
29377
30545
|
return {
|
|
@@ -29382,7 +30550,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
29382
30550
|
};
|
|
29383
30551
|
}
|
|
29384
30552
|
}
|
|
29385
|
-
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;
|
|
30553
|
+
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, assertDurableServiceUninstalled, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, agentOperationId, agentSession, agentConnect, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock, serviceCommand;
|
|
29386
30554
|
var init_cli = __esm({
|
|
29387
30555
|
"lib/inference-host/cli.ts"() {
|
|
29388
30556
|
"use strict";
|
|
@@ -29399,6 +30567,7 @@ var init_cli = __esm({
|
|
|
29399
30567
|
init_oauth();
|
|
29400
30568
|
init_runner();
|
|
29401
30569
|
init_mcp_client();
|
|
30570
|
+
init_service();
|
|
29402
30571
|
INFERENCE_HOST_CLI_VERSION = agent_cli_release_default.package_version;
|
|
29403
30572
|
runtimeReceiptPath = (config2) => `${config2.statePath}.runtime.json`;
|
|
29404
30573
|
codexRecoveryPath = (config2) => `${config2.statePath}.codex-recovery.json`;
|
|
@@ -29476,6 +30645,7 @@ Commands:
|
|
|
29476
30645
|
agent-next Claim the next exact VTX inference request
|
|
29477
30646
|
agent-complete Submit one completed agent result from stdin
|
|
29478
30647
|
agent-fail Submit one truthful agent failure from stdin
|
|
30648
|
+
service Install and control the durable background host
|
|
29479
30649
|
status Inspect local host and credential state
|
|
29480
30650
|
doctor Verify credentials, Codex, and private runtime state
|
|
29481
30651
|
logout Remove local VTX host state without revoking the grant
|
|
@@ -29489,6 +30659,10 @@ Common options:
|
|
|
29489
30659
|
If the OS credential store cannot retain the VTX grant, set
|
|
29490
30660
|
VTX_INFERENCE_HOST_CREDENTIAL_STORE=file before login to use the supported
|
|
29491
30661
|
private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
30662
|
+
|
|
30663
|
+
Durable service:
|
|
30664
|
+
vtx inference-host service install
|
|
30665
|
+
vtx inference-host service <start|stop|status|logs|uninstall>
|
|
29492
30666
|
`;
|
|
29493
30667
|
parsePositiveInteger = (raw, label) => {
|
|
29494
30668
|
const value = Number(raw);
|
|
@@ -29511,6 +30685,8 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29511
30685
|
let modelLabel = null;
|
|
29512
30686
|
let reasoningEffort = null;
|
|
29513
30687
|
let waitSeconds = 50;
|
|
30688
|
+
let lines = 100;
|
|
30689
|
+
let serviceManifestPath = null;
|
|
29514
30690
|
const positionals = [];
|
|
29515
30691
|
for (let index = 0; index < argv2.length; index += 1) {
|
|
29516
30692
|
const argument = argv2[index];
|
|
@@ -29537,7 +30713,7 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29537
30713
|
index += 1;
|
|
29538
30714
|
continue;
|
|
29539
30715
|
}
|
|
29540
|
-
if (["--adapter", "--model", "--model-label", "--effort", "--wait-seconds"].includes(argument)) {
|
|
30716
|
+
if (["--adapter", "--model", "--model-label", "--effort", "--wait-seconds", "--lines", "--service-manifest"].includes(argument)) {
|
|
29541
30717
|
const raw = argv2[index + 1];
|
|
29542
30718
|
if (!raw?.trim()) throw new Error(`${argument} requires a value.`);
|
|
29543
30719
|
if (argument === "--adapter") adapter = raw.trim();
|
|
@@ -29550,6 +30726,13 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29550
30726
|
throw new Error("--wait-seconds must be an integer from 0 through 300.");
|
|
29551
30727
|
}
|
|
29552
30728
|
}
|
|
30729
|
+
if (argument === "--lines") {
|
|
30730
|
+
lines = Number(raw);
|
|
30731
|
+
if (!Number.isInteger(lines) || lines < 1 || lines > 1e4) {
|
|
30732
|
+
throw new Error("--lines must be an integer from 1 through 10000.");
|
|
30733
|
+
}
|
|
30734
|
+
}
|
|
30735
|
+
if (argument === "--service-manifest") serviceManifestPath = resolve5(raw.trim());
|
|
29553
30736
|
index += 1;
|
|
29554
30737
|
continue;
|
|
29555
30738
|
}
|
|
@@ -29561,10 +30744,14 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29561
30744
|
if (positionals[0] !== "inference-host") {
|
|
29562
30745
|
throw new Error("Inference-host command routing is invalid.");
|
|
29563
30746
|
}
|
|
29564
|
-
if (positionals.length >
|
|
30747
|
+
if (positionals.length > 3) {
|
|
29565
30748
|
throw new Error("Inference-host commands do not accept positional arguments.");
|
|
29566
30749
|
}
|
|
29567
30750
|
const command = positionals[1] || null;
|
|
30751
|
+
const serviceAction = command === "service" ? positionals[2] ?? null : null;
|
|
30752
|
+
if (command !== "service" && positionals.length > 2) {
|
|
30753
|
+
throw new Error("Inference-host commands do not accept positional arguments.");
|
|
30754
|
+
}
|
|
29568
30755
|
if (command === "agent-connect" && !displayNameExplicit) {
|
|
29569
30756
|
displayName = "Agent-driven inference host";
|
|
29570
30757
|
}
|
|
@@ -29578,13 +30765,16 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29578
30765
|
modelId,
|
|
29579
30766
|
modelLabel,
|
|
29580
30767
|
reasoningEffort,
|
|
29581
|
-
waitSeconds
|
|
30768
|
+
waitSeconds,
|
|
30769
|
+
lines,
|
|
30770
|
+
serviceAction,
|
|
30771
|
+
serviceManifestPath
|
|
29582
30772
|
};
|
|
29583
30773
|
};
|
|
29584
30774
|
defaultOpenBrowser = (url2) => {
|
|
29585
30775
|
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
29586
30776
|
const args = process.platform === "win32" ? ["/c", "start", "", url2] : [url2];
|
|
29587
|
-
const child =
|
|
30777
|
+
const child = spawn6(command, args, {
|
|
29588
30778
|
detached: true,
|
|
29589
30779
|
stdio: "ignore",
|
|
29590
30780
|
windowsHide: true
|
|
@@ -29653,11 +30843,11 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29653
30843
|
return raw !== null;
|
|
29654
30844
|
};
|
|
29655
30845
|
inspectCodexAuthentication = async (config2) => {
|
|
29656
|
-
const path =
|
|
30846
|
+
const path = join6(config2.codexHomePath, "auth.json");
|
|
29657
30847
|
try {
|
|
29658
30848
|
const before = await lstat4(path);
|
|
29659
30849
|
const canonical = await realpath4(path);
|
|
29660
|
-
const isPrivate = before.isFile() && !before.isSymbolicLink() && canonical ===
|
|
30850
|
+
const isPrivate = before.isFile() && !before.isSymbolicLink() && canonical === resolve5(path) && before.size <= 8 * 1024 * 1024 && (process.platform === "win32" || (before.mode & 63) === 0 && (typeof process.getuid !== "function" || before.uid === process.getuid()));
|
|
29661
30851
|
return { present: true, private: isPrivate };
|
|
29662
30852
|
} catch (error48) {
|
|
29663
30853
|
if (error48.code === "ENOENT") {
|
|
@@ -29671,7 +30861,7 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29671
30861
|
runtimeReceiptPath(config2),
|
|
29672
30862
|
"Inference host runtime receipt file"
|
|
29673
30863
|
);
|
|
29674
|
-
await
|
|
30864
|
+
await rm5(codexGuardianReceiptRoot(config2), { recursive: true, force: true });
|
|
29675
30865
|
await clearInferencePrivateFile(
|
|
29676
30866
|
codexRecoveryPath(config2),
|
|
29677
30867
|
"Codex attempt recovery file"
|
|
@@ -29680,6 +30870,13 @@ private-file fallback. See https://vtxmacro.com/insights#subscription-inference.
|
|
|
29680
30870
|
await clearInferenceAgentNextState(config2.statePath);
|
|
29681
30871
|
await clearInferenceHostLocalState(config2.statePath);
|
|
29682
30872
|
};
|
|
30873
|
+
assertDurableServiceUninstalled = async (config2) => {
|
|
30874
|
+
if (await readInferenceHostServiceManifest(`${config2.statePath}.service.json`)) {
|
|
30875
|
+
throw new Error(
|
|
30876
|
+
"Uninstall the durable inference-host service before logout, revoke, or Codex logout."
|
|
30877
|
+
);
|
|
30878
|
+
}
|
|
30879
|
+
};
|
|
29683
30880
|
assertLocalRuntimeArtifactsMayBeDiscarded = async (config2) => {
|
|
29684
30881
|
const receipt = await new FileInferenceHostRuntimeReceiptStore(
|
|
29685
30882
|
runtimeReceiptPath(config2)
|
|
@@ -29778,20 +30975,20 @@ Waiting for approval...
|
|
|
29778
30975
|
} catch {
|
|
29779
30976
|
}
|
|
29780
30977
|
}
|
|
29781
|
-
let
|
|
30978
|
+
let access4;
|
|
29782
30979
|
try {
|
|
29783
|
-
|
|
30980
|
+
access4 = await pending.completion;
|
|
29784
30981
|
} catch (error48) {
|
|
29785
30982
|
await pending.cancel().catch(() => void 0);
|
|
29786
30983
|
throw error48;
|
|
29787
30984
|
}
|
|
29788
30985
|
const state = {
|
|
29789
30986
|
schema_version: 1,
|
|
29790
|
-
issuer:
|
|
29791
|
-
client_id:
|
|
29792
|
-
host_id:
|
|
30987
|
+
issuer: access4.credential.issuer,
|
|
30988
|
+
client_id: access4.credential.client_id,
|
|
30989
|
+
host_id: access4.credential.host_id,
|
|
29793
30990
|
host_generation: 1,
|
|
29794
|
-
key_generation:
|
|
30991
|
+
key_generation: access4.credential.key_generation
|
|
29795
30992
|
};
|
|
29796
30993
|
try {
|
|
29797
30994
|
await writeInferenceHostLocalState(config2.statePath, state);
|
|
@@ -29801,7 +30998,7 @@ Waiting for approval...
|
|
|
29801
30998
|
const metadata = await (dependencies.discoverOAuth ?? discoverInferenceOAuth)(config2.apiUrl);
|
|
29802
30999
|
await (dependencies.revokeCredential ?? revokeInferenceCredential)({
|
|
29803
31000
|
metadata,
|
|
29804
|
-
credential:
|
|
31001
|
+
credential: access4.credential,
|
|
29805
31002
|
store
|
|
29806
31003
|
});
|
|
29807
31004
|
remoteCleanupConfirmed = true;
|
|
@@ -29812,8 +31009,8 @@ Waiting for approval...
|
|
|
29812
31009
|
{ cause: stateError }
|
|
29813
31010
|
);
|
|
29814
31011
|
}
|
|
29815
|
-
await store.writeRecovery(
|
|
29816
|
-
await store.remove(
|
|
31012
|
+
await store.writeRecovery(access4.accountKey, access4.credential);
|
|
31013
|
+
await store.remove(access4.accountKey).catch(() => void 0);
|
|
29817
31014
|
}
|
|
29818
31015
|
if (!remoteCleanupConfirmed) {
|
|
29819
31016
|
throw new Error(
|
|
@@ -29892,6 +31089,7 @@ Waiting for approval...
|
|
|
29892
31089
|
}
|
|
29893
31090
|
};
|
|
29894
31091
|
codexLogout = async (config2, parsed, env, dependencies) => {
|
|
31092
|
+
await assertDurableServiceUninstalled(config2);
|
|
29895
31093
|
const cancellation = lifecycleCancellation(dependencies);
|
|
29896
31094
|
let lock2 = null;
|
|
29897
31095
|
try {
|
|
@@ -30068,6 +31266,7 @@ Waiting for approval...
|
|
|
30068
31266
|
};
|
|
30069
31267
|
};
|
|
30070
31268
|
cleanupLogin = async (config2, parsed, dependencies, warnings, revoke) => {
|
|
31269
|
+
await assertDurableServiceUninstalled(config2);
|
|
30071
31270
|
const lock2 = await acquireInferenceHostProcessLock(config2.processLockPath);
|
|
30072
31271
|
let keeperLock = null;
|
|
30073
31272
|
try {
|
|
@@ -30436,7 +31635,7 @@ Waiting for approval...
|
|
|
30436
31635
|
}
|
|
30437
31636
|
if (parsed.once && !commandLock) break;
|
|
30438
31637
|
await (dependencies.sleep ?? (async (milliseconds) => {
|
|
30439
|
-
await new Promise((
|
|
31638
|
+
await new Promise((resolve6) => setTimeout(resolve6, milliseconds));
|
|
30440
31639
|
}))(retryDelayMs);
|
|
30441
31640
|
}
|
|
30442
31641
|
return {
|
|
@@ -30461,7 +31660,7 @@ Waiting for approval...
|
|
|
30461
31660
|
const session = await agentSession(config2, dependencies, warnings);
|
|
30462
31661
|
const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
30463
31662
|
const sleep4 = dependencies.sleep ?? (async (milliseconds) => {
|
|
30464
|
-
await new Promise((
|
|
31663
|
+
await new Promise((resolve6) => setTimeout(resolve6, milliseconds));
|
|
30465
31664
|
});
|
|
30466
31665
|
const stopAt = now().getTime() + parsed.waitSeconds * 1e3;
|
|
30467
31666
|
while (true) {
|
|
@@ -30645,6 +31844,8 @@ Waiting for approval...
|
|
|
30645
31844
|
throw new Error("agent-fail requires a boolean retryable field.");
|
|
30646
31845
|
}
|
|
30647
31846
|
const dispatched = dispatchOutcome !== "not_dispatched";
|
|
31847
|
+
const effectiveModel = dispatched && Object.hasOwn(input, "effective_model") ? input.effective_model : null;
|
|
31848
|
+
const effectiveEffort = dispatched && Object.hasOwn(input, "effective_reasoning_effort") ? input.effective_reasoning_effort : null;
|
|
30648
31849
|
request = agentFailRequestSchema.parse({
|
|
30649
31850
|
operation_id: state.failure_operation_id,
|
|
30650
31851
|
host_id: state.host_id,
|
|
@@ -30652,8 +31853,8 @@ Waiting for approval...
|
|
|
30652
31853
|
attempt_id: state.attempt_id,
|
|
30653
31854
|
claim_handle: state.claim_handle,
|
|
30654
31855
|
dispatch_outcome: dispatchOutcome,
|
|
30655
|
-
effective_model:
|
|
30656
|
-
effective_reasoning_effort:
|
|
31856
|
+
effective_model: effectiveModel == null ? null : String(effectiveModel),
|
|
31857
|
+
effective_reasoning_effort: effectiveEffort == null ? null : String(effectiveEffort),
|
|
30657
31858
|
adapter_request_id: input.adapter_request_id == null ? null : String(input.adapter_request_id),
|
|
30658
31859
|
adapter_response_id: input.adapter_response_id == null ? null : String(input.adapter_response_id),
|
|
30659
31860
|
usage: input.usage ?? (dispatched ? {
|
|
@@ -30689,15 +31890,127 @@ Waiting for approval...
|
|
|
30689
31890
|
await lock2.release();
|
|
30690
31891
|
}
|
|
30691
31892
|
};
|
|
31893
|
+
serviceCommand = async (config2, parsed, env, dependencies, warnings) => {
|
|
31894
|
+
const action = parsed.serviceAction;
|
|
31895
|
+
if (!action) {
|
|
31896
|
+
throw new Error("Usage: vtx inference-host service <install|start|stop|status|logs|uninstall>.");
|
|
31897
|
+
}
|
|
31898
|
+
if (action === "run-internal") {
|
|
31899
|
+
if (!parsed.serviceManifestPath) throw new Error("Internal service manifest path is required.");
|
|
31900
|
+
const serviceManifest = await readInferenceHostServiceManifest(parsed.serviceManifestPath);
|
|
31901
|
+
if (!serviceManifest) throw new Error("Inference-host service manifest is missing.");
|
|
31902
|
+
const serviceConfig = resolveInferenceHostConfig({
|
|
31903
|
+
...env,
|
|
31904
|
+
...serviceManifest.runtime_environment
|
|
31905
|
+
});
|
|
31906
|
+
const serviceLock = await acquireInferenceHostProcessLock(
|
|
31907
|
+
`${serviceConfig.processLockPath}.service`
|
|
31908
|
+
);
|
|
31909
|
+
const cancellation = lifecycleCancellation(dependencies);
|
|
31910
|
+
try {
|
|
31911
|
+
await (dependencies.runServiceSupervisor ?? runInferenceHostServiceSupervisor)(
|
|
31912
|
+
parsed.serviceManifestPath,
|
|
31913
|
+
{
|
|
31914
|
+
signal: cancellation.signal,
|
|
31915
|
+
runWorker: async (manifest, signal) => {
|
|
31916
|
+
const startedAt = Date.now();
|
|
31917
|
+
const serviceEnv = { ...env, ...manifest.runtime_environment };
|
|
31918
|
+
const serviceConfig2 = resolveInferenceHostConfig(serviceEnv);
|
|
31919
|
+
const unregister = (abort) => {
|
|
31920
|
+
const onAbort = () => abort("SIGTERM");
|
|
31921
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
31922
|
+
return () => signal.removeEventListener("abort", onAbort);
|
|
31923
|
+
};
|
|
31924
|
+
const result2 = await runHost(serviceConfig2, {
|
|
31925
|
+
...parsed,
|
|
31926
|
+
command: "run",
|
|
31927
|
+
serviceAction: null,
|
|
31928
|
+
serviceManifestPath: null,
|
|
31929
|
+
displayName: manifest.display_name,
|
|
31930
|
+
once: false
|
|
31931
|
+
}, serviceEnv, {
|
|
31932
|
+
...dependencies,
|
|
31933
|
+
registerLifecycleSignalHandlers: unregister
|
|
31934
|
+
}, warnings);
|
|
31935
|
+
return { exitCode: result2.exitCode, uptimeMs: Date.now() - startedAt };
|
|
31936
|
+
}
|
|
31937
|
+
}
|
|
31938
|
+
);
|
|
31939
|
+
return { exitCode: 0, stdout: "", stderr: "" };
|
|
31940
|
+
} finally {
|
|
31941
|
+
cancellation.unregister();
|
|
31942
|
+
await serviceLock.release();
|
|
31943
|
+
}
|
|
31944
|
+
}
|
|
31945
|
+
const manager = dependencies.createServiceManager?.(
|
|
31946
|
+
config2,
|
|
31947
|
+
dependencies.serviceDependencies
|
|
31948
|
+
) ?? new InferenceHostServiceManager(config2, dependencies.serviceDependencies);
|
|
31949
|
+
if (action === "install") {
|
|
31950
|
+
const adapter = parsed.adapter || "codex";
|
|
31951
|
+
if (adapter !== "codex") {
|
|
31952
|
+
throw new Error(
|
|
31953
|
+
`Adapter ${adapter} does not have a supported durable service integration. Use foreground agent-run instead.`
|
|
31954
|
+
);
|
|
31955
|
+
}
|
|
31956
|
+
const state = await readInferenceHostLocalState(config2.statePath);
|
|
31957
|
+
if (!state) throw new Error("Run vtx inference-host login before installing the service.");
|
|
31958
|
+
const store = configuredCredentialStore(config2, dependencies, (message) => warnings.push(message));
|
|
31959
|
+
const credential = await store.read(accountKeyForState(state));
|
|
31960
|
+
if (!credential) throw new Error("Inference-host credential is missing. Run login again.");
|
|
31961
|
+
assertCredentialMatchesState2(state, credential);
|
|
31962
|
+
if (parsed.modelId || parsed.modelLabel || parsed.reasoningEffort) {
|
|
31963
|
+
throw new Error("Automated Codex service does not accept agent model or effort options.");
|
|
31964
|
+
}
|
|
31965
|
+
const auth = await inspectCodexAuthentication(config2);
|
|
31966
|
+
if (!auth.present || !auth.private) {
|
|
31967
|
+
throw new Error("Run vtx inference-host codex-login before installing the automated Codex service.");
|
|
31968
|
+
}
|
|
31969
|
+
const binary = await (dependencies.resolveBinary ?? resolvePinnedCodexBinary)(env);
|
|
31970
|
+
await (dependencies.preflightCodex ?? preflightCodexSubscription)({
|
|
31971
|
+
binary,
|
|
31972
|
+
codexHome: config2.codexHomePath,
|
|
31973
|
+
deadlineAtMs: Date.now() + 3e4
|
|
31974
|
+
});
|
|
31975
|
+
const status = await manager.install({ adapter: "codex", displayName: parsed.displayName });
|
|
31976
|
+
return {
|
|
31977
|
+
exitCode: 0,
|
|
31978
|
+
stdout: render({ status: "service_installed", ...status }, parsed.json),
|
|
31979
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
31980
|
+
` : ""
|
|
31981
|
+
};
|
|
31982
|
+
}
|
|
31983
|
+
if (parsed.adapter || parsed.modelId || parsed.modelLabel || parsed.reasoningEffort) {
|
|
31984
|
+
throw new Error("Service adapter and model options are accepted only by service install.");
|
|
31985
|
+
}
|
|
31986
|
+
if (action === "logs") {
|
|
31987
|
+
return { exitCode: 0, stdout: await manager.logs(parsed.lines), stderr: "" };
|
|
31988
|
+
}
|
|
31989
|
+
if (action === "start") {
|
|
31990
|
+
return { exitCode: 0, stdout: render({ status: "service_started", ...await manager.start() }, parsed.json), stderr: "" };
|
|
31991
|
+
}
|
|
31992
|
+
if (action === "stop") {
|
|
31993
|
+
return { exitCode: 0, stdout: render({ status: "service_stopped", ...await manager.stop() }, parsed.json), stderr: "" };
|
|
31994
|
+
}
|
|
31995
|
+
if (action === "status") {
|
|
31996
|
+
const status = await manager.status();
|
|
31997
|
+
const lifecycleMatches = status.installed && (status.desired_running ? status.manager_active : !status.manager_active);
|
|
31998
|
+
return { exitCode: lifecycleMatches ? 0 : 1, stdout: render(status, parsed.json), stderr: "" };
|
|
31999
|
+
}
|
|
32000
|
+
if (action === "uninstall") {
|
|
32001
|
+
return { exitCode: 0, stdout: render({ status: "service_uninstalled", ...await manager.uninstall() }, parsed.json), stderr: "" };
|
|
32002
|
+
}
|
|
32003
|
+
throw new Error("Usage: vtx inference-host service <install|start|stop|status|logs|uninstall>.");
|
|
32004
|
+
};
|
|
30692
32005
|
}
|
|
30693
32006
|
});
|
|
30694
32007
|
|
|
30695
32008
|
// lib/agent-core/config.ts
|
|
30696
|
-
import { mkdir as
|
|
30697
|
-
import { dirname as
|
|
30698
|
-
import { homedir as
|
|
32009
|
+
import { mkdir as mkdir5, readFile as readFile6, rm as rm6, writeFile as writeFile3 } from "node:fs/promises";
|
|
32010
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
32011
|
+
import { homedir as homedir3 } from "node:os";
|
|
30699
32012
|
function defaultBaseDir() {
|
|
30700
|
-
return
|
|
32013
|
+
return join7(homedir3(), ".vtx");
|
|
30701
32014
|
}
|
|
30702
32015
|
function resolveAgentCliConfig(env = process.env) {
|
|
30703
32016
|
const baseDir = String(env.VTX_HOME || "").trim() || defaultBaseDir();
|
|
@@ -30705,8 +32018,8 @@ function resolveAgentCliConfig(env = process.env) {
|
|
|
30705
32018
|
const parsedProfile = rawProfile ? Number(rawProfile) : NaN;
|
|
30706
32019
|
return {
|
|
30707
32020
|
apiUrl: String(env.VTX_API_URL || "http://localhost:8000").replace(/\/+$/, ""),
|
|
30708
|
-
tokenPath: String(env.VTX_TOKEN_PATH || "").trim() ||
|
|
30709
|
-
statePath: String(env.VTX_RUNTIME_STATE_PATH || "").trim() ||
|
|
32021
|
+
tokenPath: String(env.VTX_TOKEN_PATH || "").trim() || join7(baseDir, "token.json"),
|
|
32022
|
+
statePath: String(env.VTX_RUNTIME_STATE_PATH || "").trim() || join7(baseDir, "runtime-state.json"),
|
|
30710
32023
|
runtimeDeviceId: String(env.VTX_RUNTIME_DEVICE_ID || "").trim() || null,
|
|
30711
32024
|
activeProfileId: Number.isFinite(parsedProfile) && parsedProfile > 0 ? parsedProfile : null,
|
|
30712
32025
|
outputJson: String(env.VTX_OUTPUT || "").trim().toLowerCase() === "json"
|
|
@@ -30714,7 +32027,7 @@ function resolveAgentCliConfig(env = process.env) {
|
|
|
30714
32027
|
}
|
|
30715
32028
|
async function readStoredAgentAuth(path) {
|
|
30716
32029
|
try {
|
|
30717
|
-
const raw = await
|
|
32030
|
+
const raw = await readFile6(path, "utf8");
|
|
30718
32031
|
if (!raw.trim()) {
|
|
30719
32032
|
throw new Error(`VTX token file is empty at ${path}. Run "vtx auth login" or remove the file and retry.`);
|
|
30720
32033
|
}
|
|
@@ -30732,16 +32045,16 @@ async function readStoredAgentAuth(path) {
|
|
|
30732
32045
|
}
|
|
30733
32046
|
}
|
|
30734
32047
|
async function writeStoredAgentAuth(path, auth) {
|
|
30735
|
-
await
|
|
30736
|
-
await
|
|
32048
|
+
await mkdir5(dirname5(path), { recursive: true });
|
|
32049
|
+
await writeFile3(path, `${JSON.stringify(auth, null, 2)}
|
|
30737
32050
|
`, { encoding: "utf8", mode: 384 });
|
|
30738
32051
|
}
|
|
30739
32052
|
async function clearStoredAgentAuth(path) {
|
|
30740
|
-
await
|
|
32053
|
+
await rm6(path, { force: true });
|
|
30741
32054
|
}
|
|
30742
32055
|
async function readRuntimeState(path) {
|
|
30743
32056
|
try {
|
|
30744
|
-
const raw = await
|
|
32057
|
+
const raw = await readFile6(path, "utf8");
|
|
30745
32058
|
const parsed = JSON.parse(raw);
|
|
30746
32059
|
const profileId = Number(parsed.profileId);
|
|
30747
32060
|
const runtimeSessionId = String(parsed.runtimeSessionId || "").trim();
|
|
@@ -30765,12 +32078,12 @@ async function readRuntimeState(path) {
|
|
|
30765
32078
|
}
|
|
30766
32079
|
}
|
|
30767
32080
|
async function writeRuntimeState(path, state) {
|
|
30768
|
-
await
|
|
30769
|
-
await
|
|
32081
|
+
await mkdir5(dirname5(path), { recursive: true });
|
|
32082
|
+
await writeFile3(path, `${JSON.stringify(state, null, 2)}
|
|
30770
32083
|
`, { encoding: "utf8", mode: 384 });
|
|
30771
32084
|
}
|
|
30772
32085
|
async function clearRuntimeState(path) {
|
|
30773
|
-
await
|
|
32086
|
+
await rm6(path, { force: true });
|
|
30774
32087
|
}
|
|
30775
32088
|
var init_config2 = __esm({
|
|
30776
32089
|
"lib/agent-core/config.ts"() {
|
|
@@ -32595,12 +33908,12 @@ var init_hyperliquid_account_state_adapter = __esm({
|
|
|
32595
33908
|
if (signal.aborted) {
|
|
32596
33909
|
throw createAbortError(abortMessage);
|
|
32597
33910
|
}
|
|
32598
|
-
return new Promise((
|
|
33911
|
+
return new Promise((resolve6, reject) => {
|
|
32599
33912
|
const onAbort = () => {
|
|
32600
33913
|
reject(createAbortError(abortMessage));
|
|
32601
33914
|
};
|
|
32602
33915
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
32603
|
-
promise2.then(
|
|
33916
|
+
promise2.then(resolve6, reject).finally(() => {
|
|
32604
33917
|
signal.removeEventListener("abort", onAbort);
|
|
32605
33918
|
});
|
|
32606
33919
|
});
|
|
@@ -34011,7 +35324,7 @@ var init_api2 = __esm({
|
|
|
34011
35324
|
}
|
|
34012
35325
|
};
|
|
34013
35326
|
API_URL = getApiUrl();
|
|
34014
|
-
sleep2 = (ms) => new Promise((
|
|
35327
|
+
sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
34015
35328
|
isTransientNetworkFetchError = (error48) => {
|
|
34016
35329
|
const message = error48 instanceof Error ? error48.message : String(error48 || "");
|
|
34017
35330
|
const normalized = message.toLowerCase();
|
|
@@ -42246,9 +43559,9 @@ function decryptKeystoreJsonSync(json2, _password) {
|
|
|
42246
43559
|
return getAccount(data, key);
|
|
42247
43560
|
}
|
|
42248
43561
|
function stall(duration3) {
|
|
42249
|
-
return new Promise((
|
|
43562
|
+
return new Promise((resolve6) => {
|
|
42250
43563
|
setTimeout(() => {
|
|
42251
|
-
|
|
43564
|
+
resolve6();
|
|
42252
43565
|
}, duration3);
|
|
42253
43566
|
});
|
|
42254
43567
|
}
|
|
@@ -42858,9 +44171,9 @@ var init_json_crowdsale = __esm({
|
|
|
42858
44171
|
|
|
42859
44172
|
// node_modules/ethers/lib.esm/wallet/wallet.js
|
|
42860
44173
|
function stall2(duration3) {
|
|
42861
|
-
return new Promise((
|
|
44174
|
+
return new Promise((resolve6) => {
|
|
42862
44175
|
setTimeout(() => {
|
|
42863
|
-
|
|
44176
|
+
resolve6();
|
|
42864
44177
|
}, duration3);
|
|
42865
44178
|
});
|
|
42866
44179
|
}
|
|
@@ -43955,8 +45268,8 @@ var init_exchange_mutation_fence = __esm({
|
|
|
43955
45268
|
return operation();
|
|
43956
45269
|
}
|
|
43957
45270
|
let markSettled;
|
|
43958
|
-
const settlement = new Promise((
|
|
43959
|
-
markSettled =
|
|
45271
|
+
const settlement = new Promise((resolve6) => {
|
|
45272
|
+
markSettled = resolve6;
|
|
43960
45273
|
});
|
|
43961
45274
|
const activeSettlements = activeSettlementsByScope.get(normalizedScope) ?? /* @__PURE__ */ new Set();
|
|
43962
45275
|
activeSettlements.add(settlement);
|
|
@@ -45213,12 +46526,12 @@ var init_hyperliquid_client = __esm({
|
|
|
45213
46526
|
},
|
|
45214
46527
|
captureController.signal
|
|
45215
46528
|
).then(() => void 0).catch(() => void 0);
|
|
45216
|
-
const captureDeadline = new Promise((
|
|
46529
|
+
const captureDeadline = new Promise((resolve6) => {
|
|
45217
46530
|
captureTimeout = globalThis.setTimeout(() => {
|
|
45218
46531
|
captureController.abort(
|
|
45219
46532
|
new DOMException("Execution attempt capture timed out.", "TimeoutError")
|
|
45220
46533
|
);
|
|
45221
|
-
|
|
46534
|
+
resolve6();
|
|
45222
46535
|
}, remainingBudgetMs);
|
|
45223
46536
|
});
|
|
45224
46537
|
await Promise.race([captureRequest, captureDeadline]);
|
|
@@ -45652,7 +46965,7 @@ var init_vault = __esm({
|
|
|
45652
46965
|
}
|
|
45653
46966
|
return output3.buffer.slice(output3.byteOffset, output3.byteOffset + output3.byteLength);
|
|
45654
46967
|
};
|
|
45655
|
-
openVaultDb = async () => new Promise((
|
|
46968
|
+
openVaultDb = async () => new Promise((resolve6, reject) => {
|
|
45656
46969
|
const request = indexedDB.open(VAULT_DB_NAME, VAULT_DB_VERSION);
|
|
45657
46970
|
request.onerror = () => reject(request.error ?? new Error("Failed to open client vault database."));
|
|
45658
46971
|
request.onupgradeneeded = () => {
|
|
@@ -45661,7 +46974,7 @@ var init_vault = __esm({
|
|
|
45661
46974
|
database.createObjectStore(VAULT_KEY_STORE);
|
|
45662
46975
|
}
|
|
45663
46976
|
};
|
|
45664
|
-
request.onsuccess = () =>
|
|
46977
|
+
request.onsuccess = () => resolve6(request.result);
|
|
45665
46978
|
});
|
|
45666
46979
|
withVaultStore = async (mode, fn) => {
|
|
45667
46980
|
const database = await openVaultDb();
|
|
@@ -45669,8 +46982,8 @@ var init_vault = __esm({
|
|
|
45669
46982
|
const transaction = database.transaction(VAULT_KEY_STORE, mode);
|
|
45670
46983
|
const store = transaction.objectStore(VAULT_KEY_STORE);
|
|
45671
46984
|
const result2 = await fn(store);
|
|
45672
|
-
await new Promise((
|
|
45673
|
-
transaction.oncomplete = () =>
|
|
46985
|
+
await new Promise((resolve6, reject) => {
|
|
46986
|
+
transaction.oncomplete = () => resolve6();
|
|
45674
46987
|
transaction.onerror = () => reject(transaction.error ?? new Error("Client vault transaction failed."));
|
|
45675
46988
|
transaction.onabort = () => reject(transaction.error ?? new Error("Client vault transaction aborted."));
|
|
45676
46989
|
});
|
|
@@ -45685,9 +46998,9 @@ var init_vault = __esm({
|
|
|
45685
46998
|
}
|
|
45686
46999
|
return withVaultStore("readonly", async (store) => {
|
|
45687
47000
|
const request = store.get(profileId);
|
|
45688
|
-
return await new Promise((
|
|
47001
|
+
return await new Promise((resolve6, reject) => {
|
|
45689
47002
|
request.onerror = () => reject(request.error ?? new Error("Failed to read client vault key."));
|
|
45690
|
-
request.onsuccess = () =>
|
|
47003
|
+
request.onsuccess = () => resolve6(request.result ?? null);
|
|
45691
47004
|
});
|
|
45692
47005
|
});
|
|
45693
47006
|
};
|
|
@@ -45709,9 +47022,9 @@ var init_vault = __esm({
|
|
|
45709
47022
|
);
|
|
45710
47023
|
await withVaultStore("readwrite", async (store) => {
|
|
45711
47024
|
const request = store.put(createdKey, profileId);
|
|
45712
|
-
await new Promise((
|
|
47025
|
+
await new Promise((resolve6, reject) => {
|
|
45713
47026
|
request.onerror = () => reject(request.error ?? new Error("Failed to persist client vault key."));
|
|
45714
|
-
request.onsuccess = () =>
|
|
47027
|
+
request.onsuccess = () => resolve6();
|
|
45715
47028
|
});
|
|
45716
47029
|
});
|
|
45717
47030
|
return createdKey;
|
|
@@ -45722,9 +47035,9 @@ var init_vault = __esm({
|
|
|
45722
47035
|
}
|
|
45723
47036
|
await withVaultStore("readwrite", async (store) => {
|
|
45724
47037
|
const request = store.delete(profileId);
|
|
45725
|
-
await new Promise((
|
|
47038
|
+
await new Promise((resolve6, reject) => {
|
|
45726
47039
|
request.onerror = () => reject(request.error ?? new Error("Failed to remove client vault key."));
|
|
45727
|
-
request.onsuccess = () =>
|
|
47040
|
+
request.onsuccess = () => resolve6();
|
|
45728
47041
|
});
|
|
45729
47042
|
});
|
|
45730
47043
|
};
|
|
@@ -46939,10 +48252,10 @@ var init_runtime_execution = __esm({
|
|
|
46939
48252
|
}
|
|
46940
48253
|
};
|
|
46941
48254
|
sleep3 = async (ms, signal) => {
|
|
46942
|
-
await new Promise((
|
|
48255
|
+
await new Promise((resolve6, reject) => {
|
|
46943
48256
|
const timer = setTimeout(() => {
|
|
46944
48257
|
cleanup();
|
|
46945
|
-
|
|
48258
|
+
resolve6(void 0);
|
|
46946
48259
|
}, ms);
|
|
46947
48260
|
const cleanup = () => {
|
|
46948
48261
|
clearTimeout(timer);
|
|
@@ -48580,7 +49893,7 @@ __export(vtx_exports, {
|
|
|
48580
49893
|
runVtxCli: () => runVtxCli
|
|
48581
49894
|
});
|
|
48582
49895
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
48583
|
-
import { spawn as
|
|
49896
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
48584
49897
|
function render2(value, json2) {
|
|
48585
49898
|
if (json2) {
|
|
48586
49899
|
return `${JSON.stringify(value, null, 2)}
|
|
@@ -48610,7 +49923,7 @@ function openBrowser(url2) {
|
|
|
48610
49923
|
const platform = process.platform;
|
|
48611
49924
|
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
48612
49925
|
const args = platform === "win32" ? ["/c", "start", "", url2] : [url2];
|
|
48613
|
-
const child =
|
|
49926
|
+
const child = spawn7(command, args, { detached: true, stdio: "ignore" });
|
|
48614
49927
|
child.unref();
|
|
48615
49928
|
}
|
|
48616
49929
|
function parseFlags(args) {
|
|
@@ -49140,7 +50453,7 @@ Global options:
|
|
|
49140
50453
|
"alibaba_cloud_model_studio_api_key",
|
|
49141
50454
|
"lightning_api_key"
|
|
49142
50455
|
]);
|
|
49143
|
-
delay = (ms) => new Promise((
|
|
50456
|
+
delay = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
49144
50457
|
}
|
|
49145
50458
|
});
|
|
49146
50459
|
|
|
@@ -49152,7 +50465,9 @@ var INFERENCE_HOST_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
49152
50465
|
"--model",
|
|
49153
50466
|
"--model-label",
|
|
49154
50467
|
"--effort",
|
|
49155
|
-
"--wait-seconds"
|
|
50468
|
+
"--wait-seconds",
|
|
50469
|
+
"--lines",
|
|
50470
|
+
"--service-manifest"
|
|
49156
50471
|
]);
|
|
49157
50472
|
var isInferenceHostCliInvocation = (argv2) => {
|
|
49158
50473
|
for (let index = 0; index < argv2.length; index += 1) {
|