@vtxmacro/cli 2026.9.51 → 2026.9.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/bin/vtx-service-bootstrap.js +130 -46
- package/bin/vtx-service-launcher.js +1399 -0
- package/bin/vtx.js +819 -565
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,9 +21,11 @@ service start, and periodically while running, it checks the official npm regist
|
|
|
21
21
|
and verifies the exact release integrity and installed CLI version in a new
|
|
22
22
|
versioned directory. Before switching, it stops new admission and lets active
|
|
23
23
|
Provider calls and Agent turns finish while keeping heartbeats alive. It selects
|
|
24
|
-
the candidate only after every configured worker reports ready. A
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
the candidate only after every configured worker reports ready. A stable recovery
|
|
25
|
+
launcher starts the versioned updater and keeps the previous working release.
|
|
26
|
+
Routine updates do not replace this recovery launcher. If activation fails or
|
|
27
|
+
the updated process exits unexpectedly, it rejects that release and restores the
|
|
28
|
+
previous runtime. The service keeps the active release and its recovery release. If the update check is
|
|
27
29
|
unavailable, it keeps the last verified runtime. An intentionally stopped
|
|
28
30
|
service stays stopped and makes no update request. Hosts installed before this
|
|
29
31
|
private launcher need one final normal npm update and service reinstall to
|
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
import { spawn as spawn2 } from "node:child_process";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import {
|
|
5
|
-
access,
|
|
5
|
+
access as access2,
|
|
6
6
|
appendFile,
|
|
7
7
|
mkdir as mkdir2,
|
|
8
|
-
readFile as
|
|
8
|
+
readFile as readFile3,
|
|
9
9
|
readdir,
|
|
10
10
|
rename as rename2,
|
|
11
|
-
rm as
|
|
11
|
+
rm as rm3
|
|
12
12
|
} from "node:fs/promises";
|
|
13
|
-
import { dirname as
|
|
13
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join3, relative as relative3, resolve as resolve3, win32 as windowsPath2 } from "node:path";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
|
|
16
16
|
// agent-cli-release.json
|
|
17
17
|
var agent_cli_release_default = {
|
|
18
18
|
package_name: "@vtxmacro/cli",
|
|
19
|
-
package_version: "2026.9.
|
|
19
|
+
package_version: "2026.9.53",
|
|
20
20
|
codex_package_name: "@openai/codex",
|
|
21
21
|
codex_version: "0.153.3",
|
|
22
22
|
copilot_sdk_package_name: "@github/copilot-sdk",
|
|
@@ -200,6 +200,14 @@ var runtime_policy_generated_default = {
|
|
|
200
200
|
host_liveness_heartbeat_interval_ms: 3e4,
|
|
201
201
|
host_liveness_recovery_nudge_ttl_ms: 1e4
|
|
202
202
|
}
|
|
203
|
+
},
|
|
204
|
+
server_runtime: {
|
|
205
|
+
prompt_rescue: {
|
|
206
|
+
client_long_poll_seconds: 20,
|
|
207
|
+
client_claim_http_timeout_milliseconds: 25e3,
|
|
208
|
+
client_presence_heartbeat_interval_milliseconds: 3e4,
|
|
209
|
+
client_presence_http_timeout_milliseconds: 5e3
|
|
210
|
+
}
|
|
203
211
|
}
|
|
204
212
|
}
|
|
205
213
|
},
|
|
@@ -207,6 +215,8 @@ var runtime_policy_generated_default = {
|
|
|
207
215
|
service: {
|
|
208
216
|
update_check_interval_ms: 3e5,
|
|
209
217
|
update_registry_timeout_ms: 15e3,
|
|
218
|
+
bootstrap_readiness_timeout_ms: 6e5,
|
|
219
|
+
bootstrap_stop_timeout_ms: 1e4,
|
|
210
220
|
startup_max_attempts: 40,
|
|
211
221
|
startup_poll_interval_ms: 250,
|
|
212
222
|
restart_stable_uptime_ms: 6e4,
|
|
@@ -242,7 +252,7 @@ var runtime_policy_generated_default = {
|
|
|
242
252
|
exchange: {
|
|
243
253
|
hyperliquid: {
|
|
244
254
|
client_public_read_budget: {
|
|
245
|
-
max_weight:
|
|
255
|
+
max_weight: 1200,
|
|
246
256
|
window_seconds: 60,
|
|
247
257
|
cooldown_seconds: 60,
|
|
248
258
|
metadata_ttl_seconds: 300,
|
|
@@ -253,6 +263,7 @@ var runtime_policy_generated_default = {
|
|
|
253
263
|
},
|
|
254
264
|
read_budget: {
|
|
255
265
|
weights: {
|
|
266
|
+
exchange: 1,
|
|
256
267
|
exchangeStatus: 2,
|
|
257
268
|
clearinghouseState: 2,
|
|
258
269
|
spotClearinghouseState: 2,
|
|
@@ -283,12 +294,17 @@ var runtime_policy_generated_default = {
|
|
|
283
294
|
authorizedAgents: 20,
|
|
284
295
|
agents: 20,
|
|
285
296
|
apiWallets: 20
|
|
286
|
-
}
|
|
297
|
+
},
|
|
298
|
+
exchange_action_batch_size: 40
|
|
287
299
|
}
|
|
288
300
|
}
|
|
289
301
|
}
|
|
290
302
|
};
|
|
291
303
|
|
|
304
|
+
// lib/inference-host/service-launcher-state.ts
|
|
305
|
+
import { access, readFile as readFile2, rm as rm2 } from "node:fs/promises";
|
|
306
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2 } from "node:path";
|
|
307
|
+
|
|
292
308
|
// lib/inference-host/config.ts
|
|
293
309
|
import { randomBytes } from "node:crypto";
|
|
294
310
|
import { spawn } from "node:child_process";
|
|
@@ -899,7 +915,7 @@ var WINDOWS_PRIVATE_FILE_REPLACE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
899
915
|
async function replaceAtomicInferencePrivateFile(temporaryPath, destinationPath, options = {}) {
|
|
900
916
|
const platform = options.platform ?? process.platform;
|
|
901
917
|
const renameFile = options.renameFile ?? rename;
|
|
902
|
-
const sleep = options.sleep ?? ((milliseconds) => new Promise((
|
|
918
|
+
const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve4) => setTimeout(resolve4, milliseconds)));
|
|
903
919
|
const maxAttempts = Math.max(1, options.maxAttempts ?? 40);
|
|
904
920
|
const retryDelayMs = Math.max(0, options.retryDelayMs ?? 25);
|
|
905
921
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
@@ -1150,19 +1166,58 @@ async function acquireInferenceHostProcessLock(path, dependencies = {}) {
|
|
|
1150
1166
|
};
|
|
1151
1167
|
}
|
|
1152
1168
|
|
|
1169
|
+
// lib/inference-host/service-launcher-state.ts
|
|
1170
|
+
var launcherSibling = (manifest, suffix) => {
|
|
1171
|
+
if (!manifest.endsWith(".service.json")) throw new Error("Invalid service manifest path.");
|
|
1172
|
+
return `${manifest.slice(0, -".service.json".length)}${suffix}`;
|
|
1173
|
+
};
|
|
1174
|
+
var within = (parent, child) => {
|
|
1175
|
+
const part = relative2(resolve2(parent), resolve2(child));
|
|
1176
|
+
return Boolean(part) && !part.startsWith("..") && !isAbsolute2(part);
|
|
1177
|
+
};
|
|
1178
|
+
var launcherSelection = (manifest, value) => {
|
|
1179
|
+
if (!value || typeof value !== "object") return null;
|
|
1180
|
+
const r = value;
|
|
1181
|
+
if (r.schema_version !== "vtx_inference_service_release_v1" || r.package_name !== "@vtxmacro/cli" || typeof r.package_version !== "string" || !/^\d{4}\.\d{1,2}\.\d{1,3}$/u.test(r.package_version) || typeof r.integrity !== "string" || typeof r.selected_at !== "string" || !Number.isFinite(Date.parse(r.selected_at)) || typeof r.script !== "string" || !isAbsolute2(r.script) || /[\r\n\0]/u.test(r.script) || !within(launcherSibling(manifest, ".service-releases"), r.script)) return null;
|
|
1182
|
+
return r;
|
|
1183
|
+
};
|
|
1184
|
+
var readLauncherState = async (manifest) => {
|
|
1185
|
+
let value;
|
|
1186
|
+
try {
|
|
1187
|
+
value = JSON.parse(await readFile2(launcherSibling(manifest, ".service-launcher.json"), "utf8"));
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
if (error.code === "ENOENT") return null;
|
|
1190
|
+
throw error;
|
|
1191
|
+
}
|
|
1192
|
+
if (!value || typeof value !== "object") throw new Error("Invalid service launcher state.");
|
|
1193
|
+
const r = value;
|
|
1194
|
+
const target = (v) => {
|
|
1195
|
+
if (!v || typeof v !== "object") return false;
|
|
1196
|
+
const t = v;
|
|
1197
|
+
return typeof t.package_version === "string" && /^\d{4}\.\d{1,2}\.\d{1,3}$/u.test(t.package_version) && typeof t.script === "string" && isAbsolute2(t.script) && !/[\r\n\0]/u.test(t.script) && (within(launcherSibling(manifest, ".service-releases"), t.script) || resolve2(t.script) === resolve2(launcherSibling(manifest, ".service-bootstrap.previous.js"))) && (t.selection === null || (() => {
|
|
1198
|
+
const selected = launcherSelection(manifest, t.selection);
|
|
1199
|
+
return Boolean(selected && selected.package_version === t.package_version && (resolve2(t.script) === resolve2(join2(dirname2(selected.script), "vtx-service-bootstrap.js")) || resolve2(t.script) === resolve2(launcherSibling(manifest, ".service-bootstrap.previous.js"))));
|
|
1200
|
+
})());
|
|
1201
|
+
};
|
|
1202
|
+
if (r.schema_version !== "vtx_inference_service_launcher_v1" || !target(r.active) || r.previous !== null && !target(r.previous) || typeof r.pending !== "boolean") {
|
|
1203
|
+
throw new Error("Invalid service launcher recovery targets.");
|
|
1204
|
+
}
|
|
1205
|
+
return r;
|
|
1206
|
+
};
|
|
1207
|
+
|
|
1153
1208
|
// lib/inference-host/service-bootstrap.ts
|
|
1154
1209
|
var OFFICIAL_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
1155
1210
|
var PACKAGE_NAME = "@vtxmacro/cli";
|
|
1156
1211
|
var UPDATE_ATTEMPTS = 3;
|
|
1157
1212
|
var UPDATE_RETRY_MS = 2e3;
|
|
1158
|
-
var CANDIDATE_READINESS_TIMEOUT_MS =
|
|
1213
|
+
var CANDIDATE_READINESS_TIMEOUT_MS = runtime_policy_generated_default.external_inference.service.bootstrap_readiness_timeout_ms;
|
|
1159
1214
|
var SERVICE_DRAIN_COMMAND = "vtx-inference-host-service-drain-v1";
|
|
1160
1215
|
var SERVICE_QUIESCE_COMMAND = "vtx-inference-host-service-quiesce-v1";
|
|
1161
1216
|
var safePath = (value, label) => {
|
|
1162
1217
|
if (typeof value !== "string" || !value || /[\r\n\0]/u.test(value)) {
|
|
1163
1218
|
throw new Error(`Inference-host bootstrap ${label} is invalid.`);
|
|
1164
1219
|
}
|
|
1165
|
-
return
|
|
1220
|
+
return resolve3(value);
|
|
1166
1221
|
};
|
|
1167
1222
|
var parseManifest = (value) => {
|
|
1168
1223
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -1201,7 +1256,7 @@ var releasesPathFor = (manifestPath) => serviceSiblingPath(manifestPath, ".servi
|
|
|
1201
1256
|
var rejectionPathFor = (manifestPath) => serviceSiblingPath(manifestPath, ".service-release-rejection.json");
|
|
1202
1257
|
var runtimePathFor = (manifestPath) => serviceSiblingPath(manifestPath, ".service-runtime.json");
|
|
1203
1258
|
var readDesired = async (manifestPath) => {
|
|
1204
|
-
const value = JSON.parse(await
|
|
1259
|
+
const value = JSON.parse(await readFile3(desiredPathFor(manifestPath), "utf8"));
|
|
1205
1260
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1206
1261
|
throw new Error("Inference-host bootstrap desired state is invalid.");
|
|
1207
1262
|
}
|
|
@@ -1231,17 +1286,17 @@ var compareInferenceHostReleaseVersions = (left, right) => {
|
|
|
1231
1286
|
return 0;
|
|
1232
1287
|
};
|
|
1233
1288
|
var isPathWithin = (parent, child) => {
|
|
1234
|
-
const childRelative =
|
|
1235
|
-
return childRelative !== "" && !childRelative.startsWith("..") && !
|
|
1289
|
+
const childRelative = relative3(resolve3(parent), resolve3(child));
|
|
1290
|
+
return childRelative !== "" && !childRelative.startsWith("..") && !isAbsolute3(childRelative);
|
|
1236
1291
|
};
|
|
1237
1292
|
var parseSelection = async (manifestPath) => {
|
|
1238
1293
|
try {
|
|
1239
|
-
const value = JSON.parse(await
|
|
1294
|
+
const value = JSON.parse(await readFile3(selectionPathFor(manifestPath), "utf8"));
|
|
1240
1295
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1241
1296
|
const record = value;
|
|
1242
1297
|
const script = safePath(record.script, "selected script");
|
|
1243
1298
|
if (record.schema_version !== "vtx_inference_service_release_v1" || record.package_name !== PACKAGE_NAME || typeof record.package_version !== "string" || !parseVersion(record.package_version) || typeof record.integrity !== "string" || typeof record.selected_at !== "string" || !Number.isFinite(Date.parse(record.selected_at)) || !isPathWithin(releasesPathFor(manifestPath), script)) return null;
|
|
1244
|
-
await
|
|
1299
|
+
await access2(script);
|
|
1245
1300
|
return record;
|
|
1246
1301
|
} catch (error) {
|
|
1247
1302
|
if (error.code === "ENOENT") return null;
|
|
@@ -1250,7 +1305,7 @@ var parseSelection = async (manifestPath) => {
|
|
|
1250
1305
|
};
|
|
1251
1306
|
var parseRejection = async (manifestPath) => {
|
|
1252
1307
|
try {
|
|
1253
|
-
const value = JSON.parse(await
|
|
1308
|
+
const value = JSON.parse(await readFile3(rejectionPathFor(manifestPath), "utf8"));
|
|
1254
1309
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1255
1310
|
const record = value;
|
|
1256
1311
|
if (record.schema_version !== "vtx_inference_service_release_rejection_v1" || typeof record.package_version !== "string" || !parseVersion(record.package_version) || typeof record.rejected_at !== "string" || !Number.isFinite(Date.parse(record.rejected_at)) || typeof record.reason !== "string" || !/^[a-z0-9_]{1,96}$/u.test(record.reason)) return null;
|
|
@@ -1289,7 +1344,7 @@ var defaultRunCommand = async (command, args) => await new Promise((resolvePromi
|
|
|
1289
1344
|
}));
|
|
1290
1345
|
});
|
|
1291
1346
|
var runInferenceHostBootstrapNpmCommand = async (executable, args, platform = process.platform, runCommand = defaultRunCommand) => {
|
|
1292
|
-
if (platform !== "win32") return await runCommand(
|
|
1347
|
+
if (platform !== "win32") return await runCommand(join3(dirname3(executable), "npm"), args);
|
|
1293
1348
|
const npmScript = windowsPath2.join(
|
|
1294
1349
|
windowsPath2.dirname(executable),
|
|
1295
1350
|
"node_modules",
|
|
@@ -1328,7 +1383,7 @@ var defaultRunSupervisor = (executable, args) => {
|
|
|
1328
1383
|
};
|
|
1329
1384
|
};
|
|
1330
1385
|
var appendBootstrapLog = async (path, event, fields = {}) => {
|
|
1331
|
-
await mkdir2(
|
|
1386
|
+
await mkdir2(dirname3(path), { recursive: true, mode: 448 });
|
|
1332
1387
|
await appendFile(
|
|
1333
1388
|
path,
|
|
1334
1389
|
`${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), event, ...fields })}
|
|
@@ -1363,7 +1418,7 @@ var verifyIntegrity = async (tarballPath, integrity) => {
|
|
|
1363
1418
|
}).filter((entry) => entry !== null);
|
|
1364
1419
|
const supported = ["sha512", "sha384", "sha256"].map((algorithm) => candidates.find((candidate) => candidate.algorithm === algorithm)).find(Boolean);
|
|
1365
1420
|
if (!supported) throw new Error("release_integrity_unsupported");
|
|
1366
|
-
const actual = createHash(supported.algorithm).update(await
|
|
1421
|
+
const actual = createHash(supported.algorithm).update(await readFile3(tarballPath)).digest("base64");
|
|
1367
1422
|
if (actual !== supported.digest) throw new Error("release_integrity_mismatch");
|
|
1368
1423
|
};
|
|
1369
1424
|
var atomicWriteSelection = async (manifestPath, selection) => {
|
|
@@ -1383,9 +1438,9 @@ var verifyInstalledRelease = async (prefix, targetVersion, executable, platform,
|
|
|
1383
1438
|
if (rootResult.exitCode !== 0 || !rootResult.stdout.trim()) {
|
|
1384
1439
|
throw new Error("release_install_invalid");
|
|
1385
1440
|
}
|
|
1386
|
-
const packagePath =
|
|
1441
|
+
const packagePath = resolve3(rootResult.stdout.trim(), PACKAGE_NAME);
|
|
1387
1442
|
if (!isPathWithin(prefix, packagePath)) throw new Error("release_install_invalid");
|
|
1388
|
-
const packageJson = JSON.parse(await
|
|
1443
|
+
const packageJson = JSON.parse(await readFile3(join3(packagePath, "package.json"), "utf8"));
|
|
1389
1444
|
if (!packageJson || typeof packageJson !== "object" || Array.isArray(packageJson)) {
|
|
1390
1445
|
throw new Error("release_install_invalid");
|
|
1391
1446
|
}
|
|
@@ -1393,9 +1448,9 @@ var verifyInstalledRelease = async (prefix, targetVersion, executable, platform,
|
|
|
1393
1448
|
const bin = packageRecord.bin;
|
|
1394
1449
|
const binPath = bin && typeof bin === "object" && !Array.isArray(bin) ? bin.vtx : null;
|
|
1395
1450
|
if (packageRecord.name !== PACKAGE_NAME || packageRecord.version !== targetVersion || typeof binPath !== "string") throw new Error("release_install_invalid");
|
|
1396
|
-
const script =
|
|
1451
|
+
const script = resolve3(packagePath, binPath);
|
|
1397
1452
|
if (!isPathWithin(packagePath, script)) throw new Error("release_install_invalid");
|
|
1398
|
-
await
|
|
1453
|
+
await access2(script);
|
|
1399
1454
|
const verified = await runCommand(executable, [script, "--version"]);
|
|
1400
1455
|
if (verified.exitCode !== 0 || verified.stdout.trim() !== targetVersion) {
|
|
1401
1456
|
throw new Error("release_version_verification_failed");
|
|
@@ -1406,19 +1461,19 @@ var cleanupInterruptedReleaseStaging = async (releasesPath) => {
|
|
|
1406
1461
|
const entries = await readdir(releasesPath, { withFileTypes: true });
|
|
1407
1462
|
for (const entry of entries) {
|
|
1408
1463
|
if (entry.isDirectory() && /^\.(?:staging|download)-\d{4}\.\d{1,2}\.\d{1,3}-[0-9a-f-]{36}$/u.test(entry.name)) {
|
|
1409
|
-
await
|
|
1464
|
+
await rm3(resolve3(releasesPath, entry.name), { recursive: true, force: true });
|
|
1410
1465
|
}
|
|
1411
1466
|
}
|
|
1412
1467
|
};
|
|
1413
1468
|
var stageRelease = async (manifestPath, target, executable, platform, runCommand, now) => {
|
|
1414
1469
|
const releasesPath = releasesPathFor(manifestPath);
|
|
1415
|
-
const finalPath =
|
|
1416
|
-
const stagingPath =
|
|
1417
|
-
const downloadPath =
|
|
1470
|
+
const finalPath = join3(releasesPath, target.version);
|
|
1471
|
+
const stagingPath = join3(releasesPath, `.staging-${target.version}-${randomUUID()}`);
|
|
1472
|
+
const downloadPath = join3(releasesPath, `.download-${target.version}-${randomUUID()}`);
|
|
1418
1473
|
await mkdir2(releasesPath, { recursive: true, mode: 448 });
|
|
1419
1474
|
await cleanupInterruptedReleaseStaging(releasesPath);
|
|
1420
1475
|
try {
|
|
1421
|
-
await
|
|
1476
|
+
await access2(finalPath);
|
|
1422
1477
|
const existingScript = await verifyInstalledRelease(
|
|
1423
1478
|
finalPath,
|
|
1424
1479
|
target.version,
|
|
@@ -1458,7 +1513,7 @@ var stageRelease = async (manifestPath, target, executable, platform, runCommand
|
|
|
1458
1513
|
} catch {
|
|
1459
1514
|
throw new Error("release_download_invalid");
|
|
1460
1515
|
}
|
|
1461
|
-
const tarballPath =
|
|
1516
|
+
const tarballPath = resolve3(downloadPath, filename);
|
|
1462
1517
|
if (!filename || !isPathWithin(downloadPath, tarballPath)) {
|
|
1463
1518
|
throw new Error("release_download_invalid");
|
|
1464
1519
|
}
|
|
@@ -1488,7 +1543,7 @@ var stageRelease = async (manifestPath, target, executable, platform, runCommand
|
|
|
1488
1543
|
if (error.code !== "EEXIST") throw error;
|
|
1489
1544
|
throw new Error("release_path_already_exists");
|
|
1490
1545
|
}
|
|
1491
|
-
const finalScript =
|
|
1546
|
+
const finalScript = resolve3(finalPath, relative3(stagingPath, stagedScript));
|
|
1492
1547
|
const selection = {
|
|
1493
1548
|
schema_version: "vtx_inference_service_release_v1",
|
|
1494
1549
|
package_name: PACKAGE_NAME,
|
|
@@ -1499,8 +1554,8 @@ var stageRelease = async (manifestPath, target, executable, platform, runCommand
|
|
|
1499
1554
|
};
|
|
1500
1555
|
return selection;
|
|
1501
1556
|
} finally {
|
|
1502
|
-
await
|
|
1503
|
-
await
|
|
1557
|
+
await rm3(stagingPath, { recursive: true, force: true }).catch(() => void 0);
|
|
1558
|
+
await rm3(downloadPath, { recursive: true, force: true }).catch(() => void 0);
|
|
1504
1559
|
}
|
|
1505
1560
|
};
|
|
1506
1561
|
var updateSelection = async (manifestPath, manifest, dependencies) => {
|
|
@@ -1546,8 +1601,8 @@ var waitForCandidateReadiness = async (manifestPath, candidate, signal, timeoutM
|
|
|
1546
1601
|
while (!signal.aborted && Date.now() < deadline) {
|
|
1547
1602
|
if (!await readDesired(manifestPath)) return "aborted";
|
|
1548
1603
|
try {
|
|
1549
|
-
const currentManifest = parseManifest(JSON.parse(await
|
|
1550
|
-
const value = JSON.parse(await
|
|
1604
|
+
const currentManifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
|
|
1605
|
+
const value = JSON.parse(await readFile3(runtimePathFor(manifestPath), "utf8"));
|
|
1551
1606
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1552
1607
|
const runtime = value;
|
|
1553
1608
|
const workers = Array.isArray(runtime.workers) ? runtime.workers : [];
|
|
@@ -1563,8 +1618,10 @@ var waitForCandidateReadiness = async (manifestPath, candidate, signal, timeoutM
|
|
|
1563
1618
|
};
|
|
1564
1619
|
var prunePrivateReleases = async (manifestPath, keep) => {
|
|
1565
1620
|
const releasesPath = releasesPathFor(manifestPath);
|
|
1621
|
+
const recovery = await readLauncherState(manifestPath);
|
|
1622
|
+
const retained = [...keep, recovery?.active.selection ?? null, recovery?.previous?.selection ?? null];
|
|
1566
1623
|
const keepPaths = new Set(
|
|
1567
|
-
|
|
1624
|
+
retained.filter((item) => item !== null).map((item) => resolve3(item.script)).filter((script) => isPathWithin(releasesPath, script)).map((script) => resolve3(releasesPath, relative3(releasesPath, script).split(/[\\/]/u)[0]))
|
|
1568
1625
|
);
|
|
1569
1626
|
let entries;
|
|
1570
1627
|
try {
|
|
@@ -1575,9 +1632,9 @@ var prunePrivateReleases = async (manifestPath, keep) => {
|
|
|
1575
1632
|
}
|
|
1576
1633
|
for (const entry of entries) {
|
|
1577
1634
|
if (!entry.isDirectory() || !parseVersion(entry.name)) continue;
|
|
1578
|
-
const releasePath =
|
|
1635
|
+
const releasePath = resolve3(releasesPath, entry.name);
|
|
1579
1636
|
if (!keepPaths.has(releasePath)) {
|
|
1580
|
-
await
|
|
1637
|
+
await rm3(releasePath, { recursive: true, force: true });
|
|
1581
1638
|
}
|
|
1582
1639
|
}
|
|
1583
1640
|
};
|
|
@@ -1602,7 +1659,7 @@ var waitForUpdateCheck = async (milliseconds, signal) => {
|
|
|
1602
1659
|
});
|
|
1603
1660
|
};
|
|
1604
1661
|
var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies = {}, lockPathValue) => {
|
|
1605
|
-
const manifestPath =
|
|
1662
|
+
const manifestPath = resolve3(manifestPathValue);
|
|
1606
1663
|
const lockPath = safePath(
|
|
1607
1664
|
lockPathValue ?? serviceSiblingPath(manifestPath, ".service-bootstrap.lock"),
|
|
1608
1665
|
"lock path"
|
|
@@ -1618,11 +1675,16 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
|
|
|
1618
1675
|
}
|
|
1619
1676
|
};
|
|
1620
1677
|
dependencies.signal?.addEventListener("abort", stop, { once: true });
|
|
1678
|
+
const launcherStop = (message) => {
|
|
1679
|
+
if (message && typeof message === "object" && message.type === "vtx-inference-host-launcher-stop-v1") stop();
|
|
1680
|
+
};
|
|
1681
|
+
process.on("message", launcherStop);
|
|
1682
|
+
if (process.env.VTX_INFERENCE_HOST_LAUNCHER_PROTOCOL === "1") process.on("disconnect", stop);
|
|
1621
1683
|
process.on("SIGTERM", stop);
|
|
1622
1684
|
process.on("SIGINT", stop);
|
|
1623
1685
|
if (dependencies.signal?.aborted) stop();
|
|
1624
1686
|
try {
|
|
1625
|
-
let manifest = parseManifest(JSON.parse(await
|
|
1687
|
+
let manifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
|
|
1626
1688
|
const shouldRun = async () => !lifetime.signal.aborted && await readDesired(manifestPath);
|
|
1627
1689
|
if (!await shouldRun()) {
|
|
1628
1690
|
await appendBootstrapLog(manifest.log_path, "service_bootstrap_stopped");
|
|
@@ -1642,7 +1704,7 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
|
|
|
1642
1704
|
signal: lifetime.signal
|
|
1643
1705
|
};
|
|
1644
1706
|
const checkUpdate = async () => {
|
|
1645
|
-
manifest = parseManifest(JSON.parse(await
|
|
1707
|
+
manifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
|
|
1646
1708
|
const active = await parseSelection(manifestPath);
|
|
1647
1709
|
try {
|
|
1648
1710
|
return await updateSelection(manifestPath, manifest, updateDependencies);
|
|
@@ -1653,16 +1715,18 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
|
|
|
1653
1715
|
return { active, candidate: null };
|
|
1654
1716
|
}
|
|
1655
1717
|
};
|
|
1718
|
+
let launchedAt = now().toISOString();
|
|
1656
1719
|
const launch = async (selection) => {
|
|
1657
|
-
manifest = parseManifest(JSON.parse(await
|
|
1720
|
+
manifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
|
|
1658
1721
|
const script = selection?.script ?? manifest.script;
|
|
1659
|
-
await
|
|
1660
|
-
await
|
|
1722
|
+
await access2(manifest.executable);
|
|
1723
|
+
await access2(script);
|
|
1661
1724
|
if (!await shouldRun()) return null;
|
|
1662
1725
|
await appendBootstrapLog(manifest.log_path, "service_bootstrap_launch", {
|
|
1663
1726
|
package_version: selection?.package_version ?? agent_cli_release_default.package_version
|
|
1664
1727
|
});
|
|
1665
1728
|
if (!await shouldRun()) return null;
|
|
1729
|
+
launchedAt = now().toISOString();
|
|
1666
1730
|
live.supervisor = runSupervisor(manifest.executable, supervisorArguments(script, manifestPath));
|
|
1667
1731
|
return live.supervisor;
|
|
1668
1732
|
};
|
|
@@ -1670,7 +1734,7 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
|
|
|
1670
1734
|
while (await shouldRun()) {
|
|
1671
1735
|
if (updatePlan.candidate) {
|
|
1672
1736
|
const candidate = { ...updatePlan.candidate, selected_at: now().toISOString() };
|
|
1673
|
-
await
|
|
1737
|
+
await rm3(runtimePathFor(manifestPath), { force: true });
|
|
1674
1738
|
await appendBootstrapLog(manifest.log_path, "service_release_candidate_started", {
|
|
1675
1739
|
package_version: candidate.package_version
|
|
1676
1740
|
});
|
|
@@ -1696,7 +1760,7 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
|
|
|
1696
1760
|
]);
|
|
1697
1761
|
if (first.kind === "ready" && await shouldRun()) {
|
|
1698
1762
|
await atomicWriteSelection(manifestPath, candidate);
|
|
1699
|
-
await
|
|
1763
|
+
await rm3(rejectionPathFor(manifestPath), { force: true }).catch(() => void 0);
|
|
1700
1764
|
await prunePrivateReleases(manifestPath, [candidate, updatePlan.active]).catch(
|
|
1701
1765
|
async () => await appendBootstrapLog(
|
|
1702
1766
|
manifest.log_path,
|
|
@@ -1750,6 +1814,24 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
|
|
|
1750
1814
|
}
|
|
1751
1815
|
const supervisor = live.supervisor ?? await launch(updatePlan.active);
|
|
1752
1816
|
if (!supervisor) return 0;
|
|
1817
|
+
if (process.env.VTX_INFERENCE_HOST_LAUNCHER_PROTOCOL === "1" && process.send) {
|
|
1818
|
+
const readiness = new AbortController();
|
|
1819
|
+
const cancel = () => readiness.abort();
|
|
1820
|
+
lifetime.signal.addEventListener("abort", cancel, { once: true });
|
|
1821
|
+
void waitForCandidateReadiness(manifestPath, {
|
|
1822
|
+
...updatePlan.active ?? {
|
|
1823
|
+
schema_version: "vtx_inference_service_release_v1",
|
|
1824
|
+
package_name: PACKAGE_NAME,
|
|
1825
|
+
package_version: agent_cli_release_default.package_version,
|
|
1826
|
+
integrity: "",
|
|
1827
|
+
script: manifest.script
|
|
1828
|
+
},
|
|
1829
|
+
selected_at: launchedAt
|
|
1830
|
+
}, readiness.signal, dependencies.readinessTimeoutMs ?? CANDIDATE_READINESS_TIMEOUT_MS).then((status) => {
|
|
1831
|
+
if (status === "ready" && process.connected) process.send?.({ type: "vtx-inference-host-bootstrap-ready-v1", package_version: agent_cli_release_default.package_version }, () => void 0);
|
|
1832
|
+
}).catch(() => void 0).finally(() => lifetime.signal.removeEventListener("abort", cancel));
|
|
1833
|
+
void supervisor.completion.finally(cancel).catch(() => void 0);
|
|
1834
|
+
}
|
|
1753
1835
|
let exited = false;
|
|
1754
1836
|
const completion = supervisor.completion.then(
|
|
1755
1837
|
(exitCode) => {
|
|
@@ -1817,12 +1899,14 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
|
|
|
1817
1899
|
await live.supervisor.completion.catch(() => 1);
|
|
1818
1900
|
}
|
|
1819
1901
|
dependencies.signal?.removeEventListener("abort", stop);
|
|
1902
|
+
process.removeListener("message", launcherStop);
|
|
1903
|
+
process.removeListener("disconnect", stop);
|
|
1820
1904
|
process.removeListener("SIGTERM", stop);
|
|
1821
1905
|
process.removeListener("SIGINT", stop);
|
|
1822
1906
|
await lock.release();
|
|
1823
1907
|
}
|
|
1824
1908
|
};
|
|
1825
|
-
var invokedPath = process.argv[1] ?
|
|
1909
|
+
var invokedPath = process.argv[1] ? resolve3(process.argv[1]) : "";
|
|
1826
1910
|
if (invokedPath === fileURLToPath(import.meta.url)) {
|
|
1827
1911
|
const manifestIndex = process.argv.indexOf("--service-manifest");
|
|
1828
1912
|
const lockIndex = process.argv.indexOf("--service-lock");
|