@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 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
- failed candidate is rejected and the last working runtime resumes. The service
26
- keeps only the active release and one rollback release. If the update check is
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 readFile2,
8
+ readFile as readFile3,
9
9
  readdir,
10
10
  rename as rename2,
11
- rm as rm2
11
+ rm as rm3
12
12
  } from "node:fs/promises";
13
- import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2, win32 as windowsPath2 } from "node:path";
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.51",
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: 900,
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((resolve3) => setTimeout(resolve3, milliseconds)));
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 = 10 * 60 * 1e3;
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 resolve2(value);
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 readFile2(desiredPathFor(manifestPath), "utf8"));
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 = relative2(resolve2(parent), resolve2(child));
1235
- return childRelative !== "" && !childRelative.startsWith("..") && !isAbsolute2(childRelative);
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 readFile2(selectionPathFor(manifestPath), "utf8"));
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 access(script);
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 readFile2(rejectionPathFor(manifestPath), "utf8"));
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(join2(dirname2(executable), "npm"), args);
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(dirname2(path), { recursive: true, mode: 448 });
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 readFile2(tarballPath)).digest("base64");
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 = resolve2(rootResult.stdout.trim(), PACKAGE_NAME);
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 readFile2(join2(packagePath, "package.json"), "utf8"));
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 = resolve2(packagePath, binPath);
1451
+ const script = resolve3(packagePath, binPath);
1397
1452
  if (!isPathWithin(packagePath, script)) throw new Error("release_install_invalid");
1398
- await access(script);
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 rm2(resolve2(releasesPath, entry.name), { recursive: true, force: true });
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 = join2(releasesPath, target.version);
1416
- const stagingPath = join2(releasesPath, `.staging-${target.version}-${randomUUID()}`);
1417
- const downloadPath = join2(releasesPath, `.download-${target.version}-${randomUUID()}`);
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 access(finalPath);
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 = resolve2(downloadPath, filename);
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 = resolve2(finalPath, relative2(stagingPath, stagedScript));
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 rm2(stagingPath, { recursive: true, force: true }).catch(() => void 0);
1503
- await rm2(downloadPath, { recursive: true, force: true }).catch(() => void 0);
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 readFile2(manifestPath, "utf8")));
1550
- const value = JSON.parse(await readFile2(runtimePathFor(manifestPath), "utf8"));
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
- keep.filter((item) => item !== null).map((item) => resolve2(item.script)).filter((script) => isPathWithin(releasesPath, script)).map((script) => resolve2(releasesPath, relative2(releasesPath, script).split(/[\\/]/u)[0]))
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 = resolve2(releasesPath, entry.name);
1635
+ const releasePath = resolve3(releasesPath, entry.name);
1579
1636
  if (!keepPaths.has(releasePath)) {
1580
- await rm2(releasePath, { recursive: true, force: true });
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 = resolve2(manifestPathValue);
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 readFile2(manifestPath, "utf8")));
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 readFile2(manifestPath, "utf8")));
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 readFile2(manifestPath, "utf8")));
1720
+ manifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
1658
1721
  const script = selection?.script ?? manifest.script;
1659
- await access(manifest.executable);
1660
- await access(script);
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 rm2(runtimePathFor(manifestPath), { force: true });
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 rm2(rejectionPathFor(manifestPath), { force: true }).catch(() => void 0);
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] ? resolve2(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");