@vtxmacro/cli 2026.9.50 → 2026.9.52

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.50",
19
+ package_version: "2026.9.52",
20
20
  codex_package_name: "@openai/codex",
21
21
  codex_version: "0.153.3",
22
22
  copilot_sdk_package_name: "@github/copilot-sdk",
@@ -207,6 +207,8 @@ var runtime_policy_generated_default = {
207
207
  service: {
208
208
  update_check_interval_ms: 3e5,
209
209
  update_registry_timeout_ms: 15e3,
210
+ bootstrap_readiness_timeout_ms: 6e5,
211
+ bootstrap_stop_timeout_ms: 1e4,
210
212
  startup_max_attempts: 40,
211
213
  startup_poll_interval_ms: 250,
212
214
  restart_stable_uptime_ms: 6e4,
@@ -289,6 +291,10 @@ var runtime_policy_generated_default = {
289
291
  }
290
292
  };
291
293
 
294
+ // lib/inference-host/service-launcher-state.ts
295
+ import { access, readFile as readFile2, rm as rm2 } from "node:fs/promises";
296
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2 } from "node:path";
297
+
292
298
  // lib/inference-host/config.ts
293
299
  import { randomBytes } from "node:crypto";
294
300
  import { spawn } from "node:child_process";
@@ -296,11 +302,6 @@ import { constants } from "node:fs";
296
302
  import { lstat, mkdir, open, readFile, realpath, rename, rm } from "node:fs/promises";
297
303
  import { homedir } from "node:os";
298
304
  import { dirname, isAbsolute, join, relative, resolve, win32 as windowsPath } from "node:path";
299
-
300
- // lib/inference-host/mcp-transport.ts
301
- import { Agent, fetch as undiciFetch } from "undici";
302
-
303
- // lib/inference-host/config.ts
304
305
  var MAX_INFERENCE_PRIVATE_FILE_BYTES = 16 * 1024 * 1024;
305
306
  var WINDOWS_PRIVATE_ACL_BROKER_SCRIPT = `$ErrorActionPreference='Stop'
306
307
  $ProgressPreference='SilentlyContinue'
@@ -904,7 +905,7 @@ var WINDOWS_PRIVATE_FILE_REPLACE_ERROR_CODES = /* @__PURE__ */ new Set([
904
905
  async function replaceAtomicInferencePrivateFile(temporaryPath, destinationPath, options = {}) {
905
906
  const platform = options.platform ?? process.platform;
906
907
  const renameFile = options.renameFile ?? rename;
907
- const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve3) => setTimeout(resolve3, milliseconds)));
908
+ const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve4) => setTimeout(resolve4, milliseconds)));
908
909
  const maxAttempts = Math.max(1, options.maxAttempts ?? 40);
909
910
  const retryDelayMs = Math.max(0, options.retryDelayMs ?? 25);
910
911
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
@@ -1155,19 +1156,58 @@ async function acquireInferenceHostProcessLock(path, dependencies = {}) {
1155
1156
  };
1156
1157
  }
1157
1158
 
1159
+ // lib/inference-host/service-launcher-state.ts
1160
+ var launcherSibling = (manifest, suffix) => {
1161
+ if (!manifest.endsWith(".service.json")) throw new Error("Invalid service manifest path.");
1162
+ return `${manifest.slice(0, -".service.json".length)}${suffix}`;
1163
+ };
1164
+ var within = (parent, child) => {
1165
+ const part = relative2(resolve2(parent), resolve2(child));
1166
+ return Boolean(part) && !part.startsWith("..") && !isAbsolute2(part);
1167
+ };
1168
+ var launcherSelection = (manifest, value) => {
1169
+ if (!value || typeof value !== "object") return null;
1170
+ const r = value;
1171
+ 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;
1172
+ return r;
1173
+ };
1174
+ var readLauncherState = async (manifest) => {
1175
+ let value;
1176
+ try {
1177
+ value = JSON.parse(await readFile2(launcherSibling(manifest, ".service-launcher.json"), "utf8"));
1178
+ } catch (error) {
1179
+ if (error.code === "ENOENT") return null;
1180
+ throw error;
1181
+ }
1182
+ if (!value || typeof value !== "object") throw new Error("Invalid service launcher state.");
1183
+ const r = value;
1184
+ const target = (v) => {
1185
+ if (!v || typeof v !== "object") return false;
1186
+ const t = v;
1187
+ 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 || (() => {
1188
+ const selected = launcherSelection(manifest, t.selection);
1189
+ 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"))));
1190
+ })());
1191
+ };
1192
+ if (r.schema_version !== "vtx_inference_service_launcher_v1" || !target(r.active) || r.previous !== null && !target(r.previous) || typeof r.pending !== "boolean") {
1193
+ throw new Error("Invalid service launcher recovery targets.");
1194
+ }
1195
+ return r;
1196
+ };
1197
+
1158
1198
  // lib/inference-host/service-bootstrap.ts
1159
1199
  var OFFICIAL_NPM_REGISTRY = "https://registry.npmjs.org";
1160
1200
  var PACKAGE_NAME = "@vtxmacro/cli";
1161
1201
  var UPDATE_ATTEMPTS = 3;
1162
1202
  var UPDATE_RETRY_MS = 2e3;
1163
- var CANDIDATE_READINESS_TIMEOUT_MS = 10 * 60 * 1e3;
1203
+ var CANDIDATE_READINESS_TIMEOUT_MS = runtime_policy_generated_default.external_inference.service.bootstrap_readiness_timeout_ms;
1164
1204
  var SERVICE_DRAIN_COMMAND = "vtx-inference-host-service-drain-v1";
1165
1205
  var SERVICE_QUIESCE_COMMAND = "vtx-inference-host-service-quiesce-v1";
1166
1206
  var safePath = (value, label) => {
1167
1207
  if (typeof value !== "string" || !value || /[\r\n\0]/u.test(value)) {
1168
1208
  throw new Error(`Inference-host bootstrap ${label} is invalid.`);
1169
1209
  }
1170
- return resolve2(value);
1210
+ return resolve3(value);
1171
1211
  };
1172
1212
  var parseManifest = (value) => {
1173
1213
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -1206,7 +1246,7 @@ var releasesPathFor = (manifestPath) => serviceSiblingPath(manifestPath, ".servi
1206
1246
  var rejectionPathFor = (manifestPath) => serviceSiblingPath(manifestPath, ".service-release-rejection.json");
1207
1247
  var runtimePathFor = (manifestPath) => serviceSiblingPath(manifestPath, ".service-runtime.json");
1208
1248
  var readDesired = async (manifestPath) => {
1209
- const value = JSON.parse(await readFile2(desiredPathFor(manifestPath), "utf8"));
1249
+ const value = JSON.parse(await readFile3(desiredPathFor(manifestPath), "utf8"));
1210
1250
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1211
1251
  throw new Error("Inference-host bootstrap desired state is invalid.");
1212
1252
  }
@@ -1236,17 +1276,17 @@ var compareInferenceHostReleaseVersions = (left, right) => {
1236
1276
  return 0;
1237
1277
  };
1238
1278
  var isPathWithin = (parent, child) => {
1239
- const childRelative = relative2(resolve2(parent), resolve2(child));
1240
- return childRelative !== "" && !childRelative.startsWith("..") && !isAbsolute2(childRelative);
1279
+ const childRelative = relative3(resolve3(parent), resolve3(child));
1280
+ return childRelative !== "" && !childRelative.startsWith("..") && !isAbsolute3(childRelative);
1241
1281
  };
1242
1282
  var parseSelection = async (manifestPath) => {
1243
1283
  try {
1244
- const value = JSON.parse(await readFile2(selectionPathFor(manifestPath), "utf8"));
1284
+ const value = JSON.parse(await readFile3(selectionPathFor(manifestPath), "utf8"));
1245
1285
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1246
1286
  const record = value;
1247
1287
  const script = safePath(record.script, "selected script");
1248
1288
  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;
1249
- await access(script);
1289
+ await access2(script);
1250
1290
  return record;
1251
1291
  } catch (error) {
1252
1292
  if (error.code === "ENOENT") return null;
@@ -1255,7 +1295,7 @@ var parseSelection = async (manifestPath) => {
1255
1295
  };
1256
1296
  var parseRejection = async (manifestPath) => {
1257
1297
  try {
1258
- const value = JSON.parse(await readFile2(rejectionPathFor(manifestPath), "utf8"));
1298
+ const value = JSON.parse(await readFile3(rejectionPathFor(manifestPath), "utf8"));
1259
1299
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1260
1300
  const record = value;
1261
1301
  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;
@@ -1294,7 +1334,7 @@ var defaultRunCommand = async (command, args) => await new Promise((resolvePromi
1294
1334
  }));
1295
1335
  });
1296
1336
  var runInferenceHostBootstrapNpmCommand = async (executable, args, platform = process.platform, runCommand = defaultRunCommand) => {
1297
- if (platform !== "win32") return await runCommand(join2(dirname2(executable), "npm"), args);
1337
+ if (platform !== "win32") return await runCommand(join3(dirname3(executable), "npm"), args);
1298
1338
  const npmScript = windowsPath2.join(
1299
1339
  windowsPath2.dirname(executable),
1300
1340
  "node_modules",
@@ -1333,7 +1373,7 @@ var defaultRunSupervisor = (executable, args) => {
1333
1373
  };
1334
1374
  };
1335
1375
  var appendBootstrapLog = async (path, event, fields = {}) => {
1336
- await mkdir2(dirname2(path), { recursive: true, mode: 448 });
1376
+ await mkdir2(dirname3(path), { recursive: true, mode: 448 });
1337
1377
  await appendFile(
1338
1378
  path,
1339
1379
  `${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), event, ...fields })}
@@ -1368,7 +1408,7 @@ var verifyIntegrity = async (tarballPath, integrity) => {
1368
1408
  }).filter((entry) => entry !== null);
1369
1409
  const supported = ["sha512", "sha384", "sha256"].map((algorithm) => candidates.find((candidate) => candidate.algorithm === algorithm)).find(Boolean);
1370
1410
  if (!supported) throw new Error("release_integrity_unsupported");
1371
- const actual = createHash(supported.algorithm).update(await readFile2(tarballPath)).digest("base64");
1411
+ const actual = createHash(supported.algorithm).update(await readFile3(tarballPath)).digest("base64");
1372
1412
  if (actual !== supported.digest) throw new Error("release_integrity_mismatch");
1373
1413
  };
1374
1414
  var atomicWriteSelection = async (manifestPath, selection) => {
@@ -1388,9 +1428,9 @@ var verifyInstalledRelease = async (prefix, targetVersion, executable, platform,
1388
1428
  if (rootResult.exitCode !== 0 || !rootResult.stdout.trim()) {
1389
1429
  throw new Error("release_install_invalid");
1390
1430
  }
1391
- const packagePath = resolve2(rootResult.stdout.trim(), PACKAGE_NAME);
1431
+ const packagePath = resolve3(rootResult.stdout.trim(), PACKAGE_NAME);
1392
1432
  if (!isPathWithin(prefix, packagePath)) throw new Error("release_install_invalid");
1393
- const packageJson = JSON.parse(await readFile2(join2(packagePath, "package.json"), "utf8"));
1433
+ const packageJson = JSON.parse(await readFile3(join3(packagePath, "package.json"), "utf8"));
1394
1434
  if (!packageJson || typeof packageJson !== "object" || Array.isArray(packageJson)) {
1395
1435
  throw new Error("release_install_invalid");
1396
1436
  }
@@ -1398,9 +1438,9 @@ var verifyInstalledRelease = async (prefix, targetVersion, executable, platform,
1398
1438
  const bin = packageRecord.bin;
1399
1439
  const binPath = bin && typeof bin === "object" && !Array.isArray(bin) ? bin.vtx : null;
1400
1440
  if (packageRecord.name !== PACKAGE_NAME || packageRecord.version !== targetVersion || typeof binPath !== "string") throw new Error("release_install_invalid");
1401
- const script = resolve2(packagePath, binPath);
1441
+ const script = resolve3(packagePath, binPath);
1402
1442
  if (!isPathWithin(packagePath, script)) throw new Error("release_install_invalid");
1403
- await access(script);
1443
+ await access2(script);
1404
1444
  const verified = await runCommand(executable, [script, "--version"]);
1405
1445
  if (verified.exitCode !== 0 || verified.stdout.trim() !== targetVersion) {
1406
1446
  throw new Error("release_version_verification_failed");
@@ -1411,19 +1451,19 @@ var cleanupInterruptedReleaseStaging = async (releasesPath) => {
1411
1451
  const entries = await readdir(releasesPath, { withFileTypes: true });
1412
1452
  for (const entry of entries) {
1413
1453
  if (entry.isDirectory() && /^\.(?:staging|download)-\d{4}\.\d{1,2}\.\d{1,3}-[0-9a-f-]{36}$/u.test(entry.name)) {
1414
- await rm2(resolve2(releasesPath, entry.name), { recursive: true, force: true });
1454
+ await rm3(resolve3(releasesPath, entry.name), { recursive: true, force: true });
1415
1455
  }
1416
1456
  }
1417
1457
  };
1418
1458
  var stageRelease = async (manifestPath, target, executable, platform, runCommand, now) => {
1419
1459
  const releasesPath = releasesPathFor(manifestPath);
1420
- const finalPath = join2(releasesPath, target.version);
1421
- const stagingPath = join2(releasesPath, `.staging-${target.version}-${randomUUID()}`);
1422
- const downloadPath = join2(releasesPath, `.download-${target.version}-${randomUUID()}`);
1460
+ const finalPath = join3(releasesPath, target.version);
1461
+ const stagingPath = join3(releasesPath, `.staging-${target.version}-${randomUUID()}`);
1462
+ const downloadPath = join3(releasesPath, `.download-${target.version}-${randomUUID()}`);
1423
1463
  await mkdir2(releasesPath, { recursive: true, mode: 448 });
1424
1464
  await cleanupInterruptedReleaseStaging(releasesPath);
1425
1465
  try {
1426
- await access(finalPath);
1466
+ await access2(finalPath);
1427
1467
  const existingScript = await verifyInstalledRelease(
1428
1468
  finalPath,
1429
1469
  target.version,
@@ -1463,7 +1503,7 @@ var stageRelease = async (manifestPath, target, executable, platform, runCommand
1463
1503
  } catch {
1464
1504
  throw new Error("release_download_invalid");
1465
1505
  }
1466
- const tarballPath = resolve2(downloadPath, filename);
1506
+ const tarballPath = resolve3(downloadPath, filename);
1467
1507
  if (!filename || !isPathWithin(downloadPath, tarballPath)) {
1468
1508
  throw new Error("release_download_invalid");
1469
1509
  }
@@ -1493,7 +1533,7 @@ var stageRelease = async (manifestPath, target, executable, platform, runCommand
1493
1533
  if (error.code !== "EEXIST") throw error;
1494
1534
  throw new Error("release_path_already_exists");
1495
1535
  }
1496
- const finalScript = resolve2(finalPath, relative2(stagingPath, stagedScript));
1536
+ const finalScript = resolve3(finalPath, relative3(stagingPath, stagedScript));
1497
1537
  const selection = {
1498
1538
  schema_version: "vtx_inference_service_release_v1",
1499
1539
  package_name: PACKAGE_NAME,
@@ -1504,8 +1544,8 @@ var stageRelease = async (manifestPath, target, executable, platform, runCommand
1504
1544
  };
1505
1545
  return selection;
1506
1546
  } finally {
1507
- await rm2(stagingPath, { recursive: true, force: true }).catch(() => void 0);
1508
- await rm2(downloadPath, { recursive: true, force: true }).catch(() => void 0);
1547
+ await rm3(stagingPath, { recursive: true, force: true }).catch(() => void 0);
1548
+ await rm3(downloadPath, { recursive: true, force: true }).catch(() => void 0);
1509
1549
  }
1510
1550
  };
1511
1551
  var updateSelection = async (manifestPath, manifest, dependencies) => {
@@ -1551,8 +1591,8 @@ var waitForCandidateReadiness = async (manifestPath, candidate, signal, timeoutM
1551
1591
  while (!signal.aborted && Date.now() < deadline) {
1552
1592
  if (!await readDesired(manifestPath)) return "aborted";
1553
1593
  try {
1554
- const currentManifest = parseManifest(JSON.parse(await readFile2(manifestPath, "utf8")));
1555
- const value = JSON.parse(await readFile2(runtimePathFor(manifestPath), "utf8"));
1594
+ const currentManifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
1595
+ const value = JSON.parse(await readFile3(runtimePathFor(manifestPath), "utf8"));
1556
1596
  if (value && typeof value === "object" && !Array.isArray(value)) {
1557
1597
  const runtime = value;
1558
1598
  const workers = Array.isArray(runtime.workers) ? runtime.workers : [];
@@ -1568,8 +1608,10 @@ var waitForCandidateReadiness = async (manifestPath, candidate, signal, timeoutM
1568
1608
  };
1569
1609
  var prunePrivateReleases = async (manifestPath, keep) => {
1570
1610
  const releasesPath = releasesPathFor(manifestPath);
1611
+ const recovery = await readLauncherState(manifestPath);
1612
+ const retained = [...keep, recovery?.active.selection ?? null, recovery?.previous?.selection ?? null];
1571
1613
  const keepPaths = new Set(
1572
- 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]))
1614
+ 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]))
1573
1615
  );
1574
1616
  let entries;
1575
1617
  try {
@@ -1580,9 +1622,9 @@ var prunePrivateReleases = async (manifestPath, keep) => {
1580
1622
  }
1581
1623
  for (const entry of entries) {
1582
1624
  if (!entry.isDirectory() || !parseVersion(entry.name)) continue;
1583
- const releasePath = resolve2(releasesPath, entry.name);
1625
+ const releasePath = resolve3(releasesPath, entry.name);
1584
1626
  if (!keepPaths.has(releasePath)) {
1585
- await rm2(releasePath, { recursive: true, force: true });
1627
+ await rm3(releasePath, { recursive: true, force: true });
1586
1628
  }
1587
1629
  }
1588
1630
  };
@@ -1607,7 +1649,7 @@ var waitForUpdateCheck = async (milliseconds, signal) => {
1607
1649
  });
1608
1650
  };
1609
1651
  var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies = {}, lockPathValue) => {
1610
- const manifestPath = resolve2(manifestPathValue);
1652
+ const manifestPath = resolve3(manifestPathValue);
1611
1653
  const lockPath = safePath(
1612
1654
  lockPathValue ?? serviceSiblingPath(manifestPath, ".service-bootstrap.lock"),
1613
1655
  "lock path"
@@ -1623,11 +1665,16 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
1623
1665
  }
1624
1666
  };
1625
1667
  dependencies.signal?.addEventListener("abort", stop, { once: true });
1668
+ const launcherStop = (message) => {
1669
+ if (message && typeof message === "object" && message.type === "vtx-inference-host-launcher-stop-v1") stop();
1670
+ };
1671
+ process.on("message", launcherStop);
1672
+ if (process.env.VTX_INFERENCE_HOST_LAUNCHER_PROTOCOL === "1") process.on("disconnect", stop);
1626
1673
  process.on("SIGTERM", stop);
1627
1674
  process.on("SIGINT", stop);
1628
1675
  if (dependencies.signal?.aborted) stop();
1629
1676
  try {
1630
- let manifest = parseManifest(JSON.parse(await readFile2(manifestPath, "utf8")));
1677
+ let manifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
1631
1678
  const shouldRun = async () => !lifetime.signal.aborted && await readDesired(manifestPath);
1632
1679
  if (!await shouldRun()) {
1633
1680
  await appendBootstrapLog(manifest.log_path, "service_bootstrap_stopped");
@@ -1647,7 +1694,7 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
1647
1694
  signal: lifetime.signal
1648
1695
  };
1649
1696
  const checkUpdate = async () => {
1650
- manifest = parseManifest(JSON.parse(await readFile2(manifestPath, "utf8")));
1697
+ manifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
1651
1698
  const active = await parseSelection(manifestPath);
1652
1699
  try {
1653
1700
  return await updateSelection(manifestPath, manifest, updateDependencies);
@@ -1658,16 +1705,18 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
1658
1705
  return { active, candidate: null };
1659
1706
  }
1660
1707
  };
1708
+ let launchedAt = now().toISOString();
1661
1709
  const launch = async (selection) => {
1662
- manifest = parseManifest(JSON.parse(await readFile2(manifestPath, "utf8")));
1710
+ manifest = parseManifest(JSON.parse(await readFile3(manifestPath, "utf8")));
1663
1711
  const script = selection?.script ?? manifest.script;
1664
- await access(manifest.executable);
1665
- await access(script);
1712
+ await access2(manifest.executable);
1713
+ await access2(script);
1666
1714
  if (!await shouldRun()) return null;
1667
1715
  await appendBootstrapLog(manifest.log_path, "service_bootstrap_launch", {
1668
1716
  package_version: selection?.package_version ?? agent_cli_release_default.package_version
1669
1717
  });
1670
1718
  if (!await shouldRun()) return null;
1719
+ launchedAt = now().toISOString();
1671
1720
  live.supervisor = runSupervisor(manifest.executable, supervisorArguments(script, manifestPath));
1672
1721
  return live.supervisor;
1673
1722
  };
@@ -1675,7 +1724,7 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
1675
1724
  while (await shouldRun()) {
1676
1725
  if (updatePlan.candidate) {
1677
1726
  const candidate = { ...updatePlan.candidate, selected_at: now().toISOString() };
1678
- await rm2(runtimePathFor(manifestPath), { force: true });
1727
+ await rm3(runtimePathFor(manifestPath), { force: true });
1679
1728
  await appendBootstrapLog(manifest.log_path, "service_release_candidate_started", {
1680
1729
  package_version: candidate.package_version
1681
1730
  });
@@ -1701,7 +1750,7 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
1701
1750
  ]);
1702
1751
  if (first.kind === "ready" && await shouldRun()) {
1703
1752
  await atomicWriteSelection(manifestPath, candidate);
1704
- await rm2(rejectionPathFor(manifestPath), { force: true }).catch(() => void 0);
1753
+ await rm3(rejectionPathFor(manifestPath), { force: true }).catch(() => void 0);
1705
1754
  await prunePrivateReleases(manifestPath, [candidate, updatePlan.active]).catch(
1706
1755
  async () => await appendBootstrapLog(
1707
1756
  manifest.log_path,
@@ -1755,6 +1804,24 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
1755
1804
  }
1756
1805
  const supervisor = live.supervisor ?? await launch(updatePlan.active);
1757
1806
  if (!supervisor) return 0;
1807
+ if (process.env.VTX_INFERENCE_HOST_LAUNCHER_PROTOCOL === "1" && process.send) {
1808
+ const readiness = new AbortController();
1809
+ const cancel = () => readiness.abort();
1810
+ lifetime.signal.addEventListener("abort", cancel, { once: true });
1811
+ void waitForCandidateReadiness(manifestPath, {
1812
+ ...updatePlan.active ?? {
1813
+ schema_version: "vtx_inference_service_release_v1",
1814
+ package_name: PACKAGE_NAME,
1815
+ package_version: agent_cli_release_default.package_version,
1816
+ integrity: "",
1817
+ script: manifest.script
1818
+ },
1819
+ selected_at: launchedAt
1820
+ }, readiness.signal, dependencies.readinessTimeoutMs ?? CANDIDATE_READINESS_TIMEOUT_MS).then((status) => {
1821
+ if (status === "ready" && process.connected) process.send?.({ type: "vtx-inference-host-bootstrap-ready-v1", package_version: agent_cli_release_default.package_version }, () => void 0);
1822
+ }).catch(() => void 0).finally(() => lifetime.signal.removeEventListener("abort", cancel));
1823
+ void supervisor.completion.finally(cancel).catch(() => void 0);
1824
+ }
1758
1825
  let exited = false;
1759
1826
  const completion = supervisor.completion.then(
1760
1827
  (exitCode) => {
@@ -1822,12 +1889,14 @@ var runInferenceHostServiceBootstrap = async (manifestPathValue, dependencies =
1822
1889
  await live.supervisor.completion.catch(() => 1);
1823
1890
  }
1824
1891
  dependencies.signal?.removeEventListener("abort", stop);
1892
+ process.removeListener("message", launcherStop);
1893
+ process.removeListener("disconnect", stop);
1825
1894
  process.removeListener("SIGTERM", stop);
1826
1895
  process.removeListener("SIGINT", stop);
1827
1896
  await lock.release();
1828
1897
  }
1829
1898
  };
1830
- var invokedPath = process.argv[1] ? resolve2(process.argv[1]) : "";
1899
+ var invokedPath = process.argv[1] ? resolve3(process.argv[1]) : "";
1831
1900
  if (invokedPath === fileURLToPath(import.meta.url)) {
1832
1901
  const manifestIndex = process.argv.indexOf("--service-manifest");
1833
1902
  const lockIndex = process.argv.indexOf("--service-lock");