@mutmutco/hub 4.5.27 → 4.5.29

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.
Files changed (2) hide show
  1. package/dist/index.cjs +609 -305
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -66,6 +66,7 @@ __export(index_exports, {
66
66
  renderNotice: () => renderNotice,
67
67
  renderReport: () => renderReport,
68
68
  reportCounts: () => reportCounts,
69
+ resolvePayloadTarball: () => resolvePayloadTarball,
69
70
  retiredSurfaces: () => retiredSurfaces,
70
71
  retryHint: () => retryHint,
71
72
  runMaintenance: () => runMaintenance2,
@@ -75,6 +76,7 @@ __export(index_exports, {
75
76
  sharedDocLockTimeoutReceipt: () => sharedDocLockTimeoutReceipt,
76
77
  shippedTargetFrom: () => shippedTargetFrom,
77
78
  shouldHandOff: () => shouldHandOff,
79
+ stagePackage: () => stagePackage,
78
80
  statusScreen: () => statusScreen,
79
81
  surfaceArmPlan: () => surfaceArmPlan,
80
82
  systemdServiceUnit: () => systemdServiceUnit,
@@ -87,8 +89,8 @@ __export(index_exports, {
87
89
  });
88
90
  module.exports = __toCommonJS(index_exports);
89
91
  var import_node_child_process9 = require("node:child_process");
90
- var import_node_fs24 = require("node:fs");
91
- var import_node_path16 = require("node:path");
92
+ var import_node_fs27 = require("node:fs");
93
+ var import_node_path18 = require("node:path");
92
94
 
93
95
  // ../installer/face/src/face.ts
94
96
  var import_node_fs = require("node:fs");
@@ -1262,14 +1264,14 @@ async function runMaintenance(product, args, dependencies) {
1262
1264
 
1263
1265
  // ../installer/launcher/src/refresh.ts
1264
1266
  var import_node_child_process = require("node:child_process");
1265
- var import_node_fs6 = require("node:fs");
1267
+ var import_node_fs8 = require("node:fs");
1266
1268
  var import_node_os2 = require("node:os");
1267
- var import_node_path3 = require("node:path");
1269
+ var import_node_path4 = require("node:path");
1268
1270
 
1269
1271
  // ../installer/launcher/src/acquisition.ts
1270
1272
  var import_node_crypto2 = require("node:crypto");
1271
- var import_node_fs5 = require("node:fs");
1272
- var import_node_path2 = require("node:path");
1273
+ var import_node_fs7 = require("node:fs");
1274
+ var import_node_path3 = require("node:path");
1273
1275
 
1274
1276
  // ../installer/launcher/src/download.ts
1275
1277
  async function readDownload(response, onProgress, expectedSize) {
@@ -1290,6 +1292,7 @@ async function readDownload(response, onProgress, expectedSize) {
1290
1292
  }
1291
1293
 
1292
1294
  // ../installer/launcher/src/store.ts
1295
+ var import_node_fs5 = require("node:fs");
1293
1296
  var import_node_os = require("node:os");
1294
1297
  var import_node_path = require("node:path");
1295
1298
  function defaultProductDir(product) {
@@ -1300,9 +1303,40 @@ function defaultProductDir(product) {
1300
1303
  const home = process.env.HOME ?? (0, import_node_os.tmpdir)();
1301
1304
  return (0, import_node_path.join)(home, `.${product}`);
1302
1305
  }
1306
+ function tokensPath(dir) {
1307
+ return (0, import_node_path.join)(dir, "tokens.json");
1308
+ }
1309
+ function readTokens(dir) {
1310
+ try {
1311
+ const data = JSON.parse((0, import_node_fs5.readFileSync)(tokensPath(dir), "utf8"));
1312
+ if (typeof data.accessToken !== "string" || !data.accessToken) return null;
1313
+ if (typeof data.expiresAt !== "number" || !Number.isFinite(data.expiresAt)) return null;
1314
+ const tokens = { accessToken: data.accessToken, expiresAt: data.expiresAt };
1315
+ if (typeof data.refreshToken === "string" && data.refreshToken) tokens.refreshToken = data.refreshToken;
1316
+ if (typeof data.clientId === "string" && data.clientId) tokens.clientId = data.clientId;
1317
+ return tokens;
1318
+ } catch {
1319
+ return null;
1320
+ }
1321
+ }
1322
+ function writeTokens(dir, tokens) {
1323
+ (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
1324
+ try {
1325
+ (0, import_node_fs5.writeFileSync)(tokensPath(dir), `${JSON.stringify(tokens)}
1326
+ `, { mode: 384 });
1327
+ } catch {
1328
+ (0, import_node_fs5.writeFileSync)(tokensPath(dir), `${JSON.stringify(tokens)}
1329
+ `);
1330
+ }
1331
+ }
1332
+ function clearTokens(dir) {
1333
+ (0, import_node_fs5.rmSync)(tokensPath(dir), { force: true });
1334
+ }
1303
1335
 
1304
1336
  // ../installer/launcher/src/payload.ts
1305
1337
  var import_node_crypto = require("node:crypto");
1338
+ var import_node_fs6 = require("node:fs");
1339
+ var import_node_path2 = require("node:path");
1306
1340
 
1307
1341
  // ../installer/launcher/src/canonical.ts
1308
1342
  function canonicalJson(value) {
@@ -1340,6 +1374,18 @@ function publicKeyBytes(config) {
1340
1374
  }
1341
1375
 
1342
1376
  // ../installer/launcher/src/payload.ts
1377
+ var NeedsLoginError = class extends Error {
1378
+ constructor() {
1379
+ super("signed out \u2014 run login first");
1380
+ this.name = "NeedsLoginError";
1381
+ }
1382
+ };
1383
+ var ForbiddenError = class extends Error {
1384
+ constructor() {
1385
+ super("this install is not allowed for your account \u2014 access was revoked or never granted.");
1386
+ this.name = "ForbiddenError";
1387
+ }
1388
+ };
1343
1389
  function canonicalManifestBytes(manifest2) {
1344
1390
  return Buffer.from(
1345
1391
  canonicalJson({
@@ -1370,6 +1416,26 @@ function verifyFileBytes(entry, bytes) {
1370
1416
  if (entry.size !== bytes.length) return false;
1371
1417
  return (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex") === entry.sha256.toLowerCase();
1372
1418
  }
1419
+ async function readErrorCode(response) {
1420
+ try {
1421
+ const data = await response.json();
1422
+ return typeof data.error === "string" ? data.error : "";
1423
+ } catch {
1424
+ return "";
1425
+ }
1426
+ }
1427
+ function throwForStatus(status, errorCode) {
1428
+ if (status === 401) throw new NeedsLoginError();
1429
+ if (status === 403) throw new ForbiddenError();
1430
+ throw new Error(
1431
+ errorCode ? `the release server refused the request (${status}: ${errorCode})` : `the release server refused the request (${status})`
1432
+ );
1433
+ }
1434
+ async function getJson(url, accessToken, fetchImpl) {
1435
+ const response = await fetchImpl(url, { headers: { authorization: `Bearer ${accessToken}` } });
1436
+ if (!response.ok) throwForStatus(response.status, await readErrorCode(response));
1437
+ return { status: response.status, json: await response.json() };
1438
+ }
1373
1439
  function parseManifest(json) {
1374
1440
  if (typeof json !== "object" || json === null) throw new Error("the release manifest is not an object");
1375
1441
  const record = json;
@@ -1399,24 +1465,42 @@ function safeManifestPath(rawPath) {
1399
1465
  }
1400
1466
  return segments.join("/");
1401
1467
  }
1468
+ async function fetchVerifiedManifest(config, accessToken, fetchImpl = fetch) {
1469
+ const { json } = await getJson(`${config.host}/release/manifest`, accessToken, fetchImpl);
1470
+ const manifest2 = parseManifest(json);
1471
+ if (!verifyManifest(manifest2, manifest2.signature, config)) {
1472
+ throw new Error("the release manifest signature is invalid \u2014 refusing to install anything.");
1473
+ }
1474
+ return manifest2;
1475
+ }
1476
+ var VERSION_CACHE_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
1477
+ function versionCacheRoot(dir, version) {
1478
+ return VERSION_CACHE_RE.test(version) ? (0, import_node_path2.join)(dir, "payload-cache", version) : "";
1479
+ }
1480
+ function cachedPayloadForVersion(dir, version) {
1481
+ const root = versionCacheRoot(dir, version);
1482
+ if (!root) return null;
1483
+ const payload = (0, import_node_path2.join)(root, "payload");
1484
+ return (0, import_node_fs6.existsSync)(payload) ? payload : null;
1485
+ }
1402
1486
 
1403
1487
  // ../installer/launcher/src/acquisition.ts
1404
1488
  function lockInstallation(dir) {
1405
- (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
1406
- const path = (0, import_node_path2.join)(dir, "installation.lock");
1489
+ (0, import_node_fs7.mkdirSync)(dir, { recursive: true });
1490
+ const path = (0, import_node_path3.join)(dir, "installation.lock");
1407
1491
  const owner = `${process.pid}:${(0, import_node_crypto2.randomUUID)()}`;
1408
1492
  try {
1409
- (0, import_node_fs5.writeFileSync)(path, owner, { flag: "wx", mode: 384 });
1493
+ (0, import_node_fs7.writeFileSync)(path, owner, { flag: "wx", mode: 384 });
1410
1494
  } catch (error) {
1411
1495
  if (error.code !== "EEXIST") throw error;
1412
1496
  const recovery = `${path}.recovery`;
1413
1497
  try {
1414
- (0, import_node_fs5.writeFileSync)(recovery, owner, { flag: "wx", mode: 384, flush: true });
1498
+ (0, import_node_fs7.writeFileSync)(recovery, owner, { flag: "wx", mode: 384, flush: true });
1415
1499
  } catch {
1416
1500
  throw new Error("installation lock recovery is already pending");
1417
1501
  }
1418
1502
  try {
1419
- const previous = (0, import_node_fs5.readFileSync)(path, "utf8");
1503
+ const previous = (0, import_node_fs7.readFileSync)(path, "utf8");
1420
1504
  const pid = Number(previous.split(":")[0]);
1421
1505
  if (!Number.isInteger(pid) || pid <= 0) throw new Error("installation lock is malformed; recovery required");
1422
1506
  try {
@@ -1425,15 +1509,15 @@ function lockInstallation(dir) {
1425
1509
  } catch (probe) {
1426
1510
  if (probe.code !== "ESRCH") throw probe;
1427
1511
  }
1428
- (0, import_node_fs5.unlinkSync)(path);
1429
- (0, import_node_fs5.writeFileSync)(path, owner, { flag: "wx", mode: 384, flush: true });
1512
+ (0, import_node_fs7.unlinkSync)(path);
1513
+ (0, import_node_fs7.writeFileSync)(path, owner, { flag: "wx", mode: 384, flush: true });
1430
1514
  } finally {
1431
- (0, import_node_fs5.unlinkSync)(recovery);
1515
+ (0, import_node_fs7.unlinkSync)(recovery);
1432
1516
  }
1433
1517
  }
1434
1518
  let released = false;
1435
1519
  return () => {
1436
- if (!released && (0, import_node_fs5.readFileSync)(path, "utf8") === owner) (0, import_node_fs5.unlinkSync)(path);
1520
+ if (!released && (0, import_node_fs7.readFileSync)(path, "utf8") === owner) (0, import_node_fs7.unlinkSync)(path);
1437
1521
  released = true;
1438
1522
  };
1439
1523
  }
@@ -1484,14 +1568,14 @@ function compareVersions(a, b) {
1484
1568
  }
1485
1569
  function recordedPath(productDir) {
1486
1570
  try {
1487
- const saved = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path3.join)(productDir, LAUNCHER_RECORD_FILE), "utf8"));
1571
+ const saved = JSON.parse((0, import_node_fs8.readFileSync)((0, import_node_path4.join)(productDir, LAUNCHER_RECORD_FILE), "utf8"));
1488
1572
  return typeof saved.path === "string" && saved.path ? saved.path : null;
1489
1573
  } catch {
1490
1574
  return null;
1491
1575
  }
1492
1576
  }
1493
1577
  function installedPath(target, productDir, platform) {
1494
- return platform === "win32" ? (0, import_node_path3.join)(productDir, "bin", `${target.bin}.exe`) : (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".local", "bin", target.bin);
1578
+ return platform === "win32" ? (0, import_node_path4.join)(productDir, "bin", `${target.bin}.exe`) : (0, import_node_path4.join)((0, import_node_os2.homedir)(), ".local", "bin", target.bin);
1495
1579
  }
1496
1580
  function parseLauncherVersion(stdout, bin) {
1497
1581
  const text = String(stdout).trim();
@@ -1506,17 +1590,17 @@ function runVersion(path, bin) {
1506
1590
  });
1507
1591
  }
1508
1592
  function removeStale(file) {
1509
- const prefix = `${(0, import_node_path3.basename)(file)}.old-`;
1593
+ const prefix = `${(0, import_node_path4.basename)(file)}.old-`;
1510
1594
  let names;
1511
1595
  try {
1512
- names = (0, import_node_fs6.readdirSync)((0, import_node_path3.dirname)(file));
1596
+ names = (0, import_node_fs8.readdirSync)((0, import_node_path4.dirname)(file));
1513
1597
  } catch {
1514
1598
  return;
1515
1599
  }
1516
1600
  for (const name of names) {
1517
1601
  if (!name.startsWith(prefix)) continue;
1518
1602
  try {
1519
- (0, import_node_fs6.rmSync)((0, import_node_path3.join)((0, import_node_path3.dirname)(file), name), { force: true });
1603
+ (0, import_node_fs8.rmSync)((0, import_node_path4.join)((0, import_node_path4.dirname)(file), name), { force: true });
1520
1604
  } catch {
1521
1605
  }
1522
1606
  }
@@ -1528,8 +1612,8 @@ async function refreshLauncher(target, options = {}) {
1528
1612
  if (!key) return null;
1529
1613
  const productDir = options.productDir ?? defaultProductDir(target.product);
1530
1614
  const recorded = recordedPath(productDir);
1531
- const file = options.path ?? (recorded && (0, import_node_fs6.existsSync)(recorded) ? recorded : installedPath(target, productDir, platform));
1532
- if (!(0, import_node_fs6.existsSync)(file) || (0, import_node_fs6.lstatSync)(file).isSymbolicLink()) return null;
1615
+ const file = options.path ?? (recorded && (0, import_node_fs8.existsSync)(recorded) ? recorded : installedPath(target, productDir, platform));
1616
+ if (!(0, import_node_fs8.existsSync)(file) || (0, import_node_fs8.lstatSync)(file).isSymbolicLink()) return null;
1533
1617
  if (!options.dryRun) removeStale(file);
1534
1618
  const from = await (options.readVersion ?? ((path) => runVersion(path, target.bin)))(file);
1535
1619
  if (!from) return null;
@@ -1565,19 +1649,19 @@ async function refreshLauncher(target, options = {}) {
1565
1649
  }
1566
1650
  if (!verifyFileBytes(entry, bytes)) return arm("fail", from, "The downloaded launcher failed its checksum.");
1567
1651
  try {
1568
- (0, import_node_fs6.writeFileSync)(next, bytes, { mode: 493 });
1569
- if (platform !== "win32") (0, import_node_fs6.chmodSync)(next, 493);
1652
+ (0, import_node_fs8.writeFileSync)(next, bytes, { mode: 493 });
1653
+ if (platform !== "win32") (0, import_node_fs8.chmodSync)(next, 493);
1570
1654
  if (platform === "win32") {
1571
1655
  moved = `${file}.old-${process.pid}-${Date.now()}`;
1572
- (0, import_node_fs6.renameSync)(file, moved);
1656
+ (0, import_node_fs8.renameSync)(file, moved);
1573
1657
  }
1574
- (0, import_node_fs6.renameSync)(next, file);
1658
+ (0, import_node_fs8.renameSync)(next, file);
1575
1659
  } catch {
1576
1660
  try {
1577
- if (moved && !(0, import_node_fs6.existsSync)(file)) (0, import_node_fs6.renameSync)(moved, file);
1661
+ if (moved && !(0, import_node_fs8.existsSync)(file)) (0, import_node_fs8.renameSync)(moved, file);
1578
1662
  } catch {
1579
1663
  }
1580
- (0, import_node_fs6.rmSync)(next, { force: true });
1664
+ (0, import_node_fs8.rmSync)(next, { force: true });
1581
1665
  return arm("fail", from, "The launcher could not be replaced.");
1582
1666
  }
1583
1667
  return arm("ok", record.version, "");
@@ -1604,22 +1688,22 @@ var installer_product_default = {
1604
1688
  };
1605
1689
 
1606
1690
  // src/state.ts
1607
- var import_node_fs7 = require("node:fs");
1691
+ var import_node_fs9 = require("node:fs");
1608
1692
  var import_node_os3 = require("node:os");
1609
- var import_node_path4 = require("node:path");
1693
+ var import_node_path5 = require("node:path");
1610
1694
  function stateRoot(env = process.env) {
1611
- return env.MMI_UPDATER_HOME || (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".mmi", "updater");
1695
+ return env.MMI_UPDATER_HOME || (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".mmi", "updater");
1612
1696
  }
1613
1697
  function statePaths(env = process.env) {
1614
1698
  const root = stateRoot(env);
1615
- const staging = (0, import_node_path4.join)(root, "staging");
1616
- const gitCache = (0, import_node_path4.join)(root, "git-cache", "mmi-hub.git");
1617
- return { root, staging, gitCache, journalPath: (0, import_node_path4.join)(root, "journal.jsonl"), leasePath: (0, import_node_path4.join)(root, "lease.lock") };
1699
+ const staging = (0, import_node_path5.join)(root, "staging");
1700
+ const gitCache = (0, import_node_path5.join)(root, "git-cache", "mmi-hub.git");
1701
+ return { root, staging, gitCache, journalPath: (0, import_node_path5.join)(root, "journal.jsonl"), leasePath: (0, import_node_path5.join)(root, "lease.lock") };
1618
1702
  }
1619
1703
  function ensureState(env = process.env) {
1620
1704
  const paths = statePaths(env);
1621
- (0, import_node_fs7.mkdirSync)(paths.staging, { recursive: true });
1622
- (0, import_node_fs7.mkdirSync)((0, import_node_path4.dirname)(paths.gitCache), { recursive: true });
1705
+ (0, import_node_fs9.mkdirSync)(paths.staging, { recursive: true });
1706
+ (0, import_node_fs9.mkdirSync)((0, import_node_path5.dirname)(paths.gitCache), { recursive: true });
1623
1707
  return paths;
1624
1708
  }
1625
1709
  var UpdaterBusy = class extends Error {
@@ -1629,15 +1713,15 @@ var LEASE_STALE_MS = 10 * 6e4;
1629
1713
  function tryAcquire(path) {
1630
1714
  const token = `${Date.now()}-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
1631
1715
  try {
1632
- const fd = (0, import_node_fs7.openSync)(path, "wx");
1633
- (0, import_node_fs7.writeFileSync)(fd, JSON.stringify({ token, pid: process.pid, ts: Date.now() }) + "\n");
1634
- (0, import_node_fs7.closeSync)(fd);
1716
+ const fd = (0, import_node_fs9.openSync)(path, "wx");
1717
+ (0, import_node_fs9.writeFileSync)(fd, JSON.stringify({ token, pid: process.pid, ts: Date.now() }) + "\n");
1718
+ (0, import_node_fs9.closeSync)(fd);
1635
1719
  return {
1636
1720
  token,
1637
1721
  release() {
1638
1722
  try {
1639
1723
  const current2 = readLease(path);
1640
- if (current2 && current2.token === token) (0, import_node_fs7.unlinkSync)(path);
1724
+ if (current2 && current2.token === token) (0, import_node_fs9.unlinkSync)(path);
1641
1725
  } catch {
1642
1726
  }
1643
1727
  }
@@ -1648,7 +1732,7 @@ function tryAcquire(path) {
1648
1732
  const current = readLease(path);
1649
1733
  if (current && Date.now() - current.ts > LEASE_STALE_MS) {
1650
1734
  try {
1651
- (0, import_node_fs7.renameSync)(path, `${path}.stale-${Date.now()}`);
1735
+ (0, import_node_fs9.renameSync)(path, `${path}.stale-${Date.now()}`);
1652
1736
  return "stolen-stale";
1653
1737
  } catch {
1654
1738
  }
@@ -1657,7 +1741,7 @@ function tryAcquire(path) {
1657
1741
  }
1658
1742
  function readLease(path) {
1659
1743
  try {
1660
- return JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
1744
+ return JSON.parse((0, import_node_fs9.readFileSync)(path, "utf8"));
1661
1745
  } catch {
1662
1746
  return null;
1663
1747
  }
@@ -1682,10 +1766,10 @@ function withLease(path, fn, waitMs = LEASE_WAIT_MS) {
1682
1766
  }
1683
1767
  function appendJournal(path, event) {
1684
1768
  try {
1685
- (0, import_node_fs7.mkdirSync)((0, import_node_path4.dirname)(path), { recursive: true });
1686
- const fd = (0, import_node_fs7.openSync)(path, "a");
1687
- (0, import_node_fs7.writeFileSync)(fd, JSON.stringify(event) + "\n");
1688
- (0, import_node_fs7.closeSync)(fd);
1769
+ (0, import_node_fs9.mkdirSync)((0, import_node_path5.dirname)(path), { recursive: true });
1770
+ const fd = (0, import_node_fs9.openSync)(path, "a");
1771
+ (0, import_node_fs9.writeFileSync)(fd, JSON.stringify(event) + "\n");
1772
+ (0, import_node_fs9.closeSync)(fd);
1689
1773
  return true;
1690
1774
  } catch {
1691
1775
  return false;
@@ -1704,7 +1788,7 @@ function journalHighWater(path, surface, events) {
1704
1788
  function parseJournal(path) {
1705
1789
  const events = [];
1706
1790
  try {
1707
- for (const line of (0, import_node_fs7.readFileSync)(path, "utf8").split("\n")) {
1791
+ for (const line of (0, import_node_fs9.readFileSync)(path, "utf8").split("\n")) {
1708
1792
  if (!line.trim()) continue;
1709
1793
  try {
1710
1794
  events.push(JSON.parse(line));
@@ -1718,7 +1802,7 @@ function parseJournal(path) {
1718
1802
  function journalSurfaceRepeatedFail(path, surface, currentRun) {
1719
1803
  let lastVerdict = null;
1720
1804
  try {
1721
- for (const line of (0, import_node_fs7.readFileSync)(path, "utf8").split("\n")) {
1805
+ for (const line of (0, import_node_fs9.readFileSync)(path, "utf8").split("\n")) {
1722
1806
  if (!line.trim()) continue;
1723
1807
  try {
1724
1808
  const event = JSON.parse(line);
@@ -1761,7 +1845,7 @@ function compareSemver(a, b) {
1761
1845
  return va.pre.join(".") < vb.pre.join(".") ? -1 : va.pre.join(".") > vb.pre.join(".") ? 1 : 0;
1762
1846
  }
1763
1847
  function fileExists(path) {
1764
- return (0, import_node_fs7.existsSync)(path);
1848
+ return (0, import_node_fs9.existsSync)(path);
1765
1849
  }
1766
1850
 
1767
1851
  // src/reconcile.ts
@@ -1769,8 +1853,8 @@ var import_node_perf_hooks2 = require("node:perf_hooks");
1769
1853
 
1770
1854
  // src/npm.ts
1771
1855
  var import_node_child_process2 = require("node:child_process");
1772
- var import_node_fs8 = require("node:fs");
1773
- var import_node_path5 = require("node:path");
1856
+ var import_node_fs10 = require("node:fs");
1857
+ var import_node_path6 = require("node:path");
1774
1858
  var cachedNpm = null;
1775
1859
  function resolveNpm(env = process.env) {
1776
1860
  if (env.MMI_UPDATER_NPM) return { kind: "command", command: env.MMI_UPDATER_NPM };
@@ -1779,8 +1863,8 @@ function resolveNpm(env = process.env) {
1779
1863
  const where = (0, import_node_child_process2.spawnSync)("where.exe", ["npm.cmd"], { encoding: "utf8", windowsHide: true });
1780
1864
  const first = where.stdout.split("\n").map((l) => l.trim()).find(Boolean);
1781
1865
  if (where.status === 0 && first) {
1782
- const script = (0, import_node_path5.join)((0, import_node_path5.dirname)(first), "node_modules", "npm", "bin", "npm-cli.js");
1783
- if ((0, import_node_fs8.existsSync)(script)) {
1866
+ const script = (0, import_node_path6.join)((0, import_node_path6.dirname)(first), "node_modules", "npm", "bin", "npm-cli.js");
1867
+ if ((0, import_node_fs10.existsSync)(script)) {
1784
1868
  cachedNpm = { kind: "node-script", script };
1785
1869
  return cachedNpm;
1786
1870
  }
@@ -1788,14 +1872,14 @@ function resolveNpm(env = process.env) {
1788
1872
  return cachedNpm;
1789
1873
  }
1790
1874
  }
1791
- const bundled = (0, import_node_path5.join)((0, import_node_path5.dirname)(process.execPath), "..", "lib", "node_modules", "npm", "bin", "npm-cli.js");
1792
- if ((0, import_node_fs8.existsSync)(bundled)) {
1875
+ const bundled = (0, import_node_path6.join)((0, import_node_path6.dirname)(process.execPath), "..", "lib", "node_modules", "npm", "bin", "npm-cli.js");
1876
+ if ((0, import_node_fs10.existsSync)(bundled)) {
1793
1877
  cachedNpm = { kind: "node-script", script: bundled };
1794
1878
  return cachedNpm;
1795
1879
  }
1796
1880
  const located = (0, import_node_child_process2.spawnSync)("/bin/sh", ["-lc", "command -v npm"], { encoding: "utf8", windowsHide: true });
1797
1881
  const resolved = (located.stdout ?? "").trim().split("\n").map((line) => line.trim()).find(Boolean);
1798
- if (located.status === 0 && resolved && (0, import_node_fs8.existsSync)(resolved)) {
1882
+ if (located.status === 0 && resolved && (0, import_node_fs10.existsSync)(resolved)) {
1799
1883
  cachedNpm = { kind: "command", command: resolved };
1800
1884
  return cachedNpm;
1801
1885
  }
@@ -1877,7 +1961,7 @@ function npmVersions(packageName, env = process.env) {
1877
1961
 
1878
1962
  // src/gate.ts
1879
1963
  var import_node_child_process3 = require("node:child_process");
1880
- var import_node_fs9 = require("node:fs");
1964
+ var import_node_fs11 = require("node:fs");
1881
1965
  function parseBom(text) {
1882
1966
  const bom = JSON.parse(text);
1883
1967
  if (typeof bom?.version !== "string" || typeof bom?.sourceCommit !== "string" || !Array.isArray(bom?.artifacts)) {
@@ -1899,7 +1983,7 @@ function ensureBareCache(cachePath, repoUrl) {
1899
1983
  if (probe.status !== 0) {
1900
1984
  throw new GateEnvError("git is not available \u2014 the release gate needs a git client");
1901
1985
  }
1902
- if (!(0, import_node_fs9.existsSync)(cachePath)) {
1986
+ if (!(0, import_node_fs11.existsSync)(cachePath)) {
1903
1987
  const init = (0, import_node_child_process3.spawnSync)("git", ["init", "--bare", cachePath], { encoding: "utf8", windowsHide: true });
1904
1988
  if (init.status !== 0) throw new GateEnvError(`cannot create bare cache at ${cachePath}: ${init.stderr}`);
1905
1989
  }
@@ -2006,39 +2090,39 @@ async function checkAtomicity(cachePath, tagCommit, bom, candidate, npm) {
2006
2090
  }
2007
2091
 
2008
2092
  // src/surfaces.ts
2009
- var import_node_fs14 = require("node:fs");
2093
+ var import_node_fs16 = require("node:fs");
2010
2094
  var import_node_os5 = require("node:os");
2011
- var import_node_path10 = require("node:path");
2095
+ var import_node_path11 = require("node:path");
2012
2096
 
2013
2097
  // src/arm-host-plugins.ts
2014
2098
  var import_node_child_process6 = require("node:child_process");
2015
- var import_node_fs13 = require("node:fs");
2099
+ var import_node_fs15 = require("node:fs");
2016
2100
  var import_node_os4 = require("node:os");
2017
- var import_node_path9 = require("node:path");
2101
+ var import_node_path10 = require("node:path");
2018
2102
 
2019
2103
  // src/arm-npm-global.ts
2020
- var import_node_fs11 = require("node:fs");
2104
+ var import_node_fs13 = require("node:fs");
2021
2105
  var import_node_child_process5 = require("node:child_process");
2022
- var import_node_path7 = require("node:path");
2106
+ var import_node_path8 = require("node:path");
2023
2107
 
2024
2108
  // src/pending.ts
2025
2109
  var import_node_child_process4 = require("node:child_process");
2026
- var import_node_fs10 = require("node:fs");
2027
- var import_node_path6 = require("node:path");
2110
+ var import_node_fs12 = require("node:fs");
2111
+ var import_node_path7 = require("node:path");
2028
2112
  function hubDistPath(env) {
2029
2113
  const root = globalRoot(env);
2030
- return root ? (0, import_node_path6.join)(root, "@mutmutco", "hub", "dist", "index.cjs") : null;
2114
+ return root ? (0, import_node_path7.join)(root, "@mutmutco", "hub", "dist", "index.cjs") : null;
2031
2115
  }
2032
2116
  var WATCHER_MAX_WAIT_MS = 4 * 60 * 60 * 1e3;
2033
2117
  function pendingPath(paths) {
2034
- return (0, import_node_path6.join)(paths.root, "pending.json");
2118
+ return (0, import_node_path7.join)(paths.root, "pending.json");
2035
2119
  }
2036
2120
  function watcherLockPath(paths) {
2037
- return (0, import_node_path6.join)(paths.root, "pending-watcher.lock.d");
2121
+ return (0, import_node_path7.join)(paths.root, "pending-watcher.lock.d");
2038
2122
  }
2039
2123
  function readPending(paths) {
2040
2124
  try {
2041
- const parsed = JSON.parse((0, import_node_fs10.readFileSync)(pendingPath(paths), "utf8"));
2125
+ const parsed = JSON.parse((0, import_node_fs12.readFileSync)(pendingPath(paths), "utf8"));
2042
2126
  if (!Array.isArray(parsed)) return [];
2043
2127
  return parsed.filter((row) => Boolean(row) && typeof row === "object" && typeof row.surface === "string" && typeof row.target === "string" && Array.isArray(row.images) && Array.isArray(row.dirs));
2044
2128
  } catch {
@@ -2046,12 +2130,12 @@ function readPending(paths) {
2046
2130
  }
2047
2131
  }
2048
2132
  function writePending(paths, records) {
2049
- (0, import_node_fs10.mkdirSync)(paths.root, { recursive: true });
2133
+ (0, import_node_fs12.mkdirSync)(paths.root, { recursive: true });
2050
2134
  const path = pendingPath(paths);
2051
2135
  const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
2052
- (0, import_node_fs10.writeFileSync)(tmp, `${JSON.stringify(records, null, 2)}
2136
+ (0, import_node_fs12.writeFileSync)(tmp, `${JSON.stringify(records, null, 2)}
2053
2137
  `, "utf8");
2054
- (0, import_node_fs10.renameSync)(tmp, path);
2138
+ (0, import_node_fs12.renameSync)(tmp, path);
2055
2139
  }
2056
2140
  function clearPending(paths, surface) {
2057
2141
  const records = readPending(paths);
@@ -2120,14 +2204,14 @@ function schedulePendingWatcher(paths, env = process.env, seam = {}) {
2120
2204
  const live = records.find((row) => row.watcherPid && pidAlive(row.watcherPid));
2121
2205
  if (live) return { scheduled: false, reason: `watcher pid ${live.watcherPid} is already waiting` };
2122
2206
  const hubDist = seam.hubDist ?? hubDistPath(env);
2123
- if (!hubDist || !(0, import_node_fs10.existsSync)(hubDist)) return { scheduled: false, reason: "the installed hub bundle is unresolvable \u2014 the hourly tick remains the retry" };
2207
+ if (!hubDist || !(0, import_node_fs12.existsSync)(hubDist)) return { scheduled: false, reason: "the installed hub bundle is unresolvable \u2014 the hourly tick remains the retry" };
2124
2208
  const command = buildWatcherCommand({
2125
2209
  images: [...new Set(records.flatMap((row) => row.images))],
2126
2210
  dirs: [...new Set(records.flatMap((row) => row.dirs))],
2127
2211
  node: process.execPath,
2128
2212
  hubDist,
2129
- codePath: (0, import_node_path6.join)(paths.root, "pending-result.code"),
2130
- logPath: (0, import_node_path6.join)(paths.root, "pending-result.log"),
2213
+ codePath: (0, import_node_path7.join)(paths.root, "pending-result.code"),
2214
+ logPath: (0, import_node_path7.join)(paths.root, "pending-result.log"),
2131
2215
  lockPath: watcherLockPath(paths)
2132
2216
  });
2133
2217
  try {
@@ -2166,7 +2250,7 @@ function resumePendingWatcher(paths, env = process.env) {
2166
2250
  // src/arm-npm-global.ts
2167
2251
  function globalDist(env, packageName, distRel) {
2168
2252
  const root = globalRoot(env);
2169
- return root ? (0, import_node_path7.join)(root, ...packageName.split("/"), ...distRel.split("/")) : null;
2253
+ return root ? (0, import_node_path8.join)(root, ...packageName.split("/"), ...distRel.split("/")) : null;
2170
2254
  }
2171
2255
  function probeVersion(distPath) {
2172
2256
  if (!fileExists(distPath)) return null;
@@ -2180,7 +2264,7 @@ function tail(output) {
2180
2264
  function manifestVersion(packageRoot) {
2181
2265
  if (!packageRoot) return null;
2182
2266
  try {
2183
- const version = JSON.parse((0, import_node_fs11.readFileSync)((0, import_node_path7.join)(packageRoot, "package.json"), "utf8")).version;
2267
+ const version = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path8.join)(packageRoot, "package.json"), "utf8")).version;
2184
2268
  return typeof version === "string" ? version : null;
2185
2269
  } catch {
2186
2270
  return null;
@@ -2188,34 +2272,40 @@ function manifestVersion(packageRoot) {
2188
2272
  }
2189
2273
  function stagePackage(options) {
2190
2274
  const { surface, packageName, target, witness, paths, env } = options;
2191
- const stageRoot = (0, import_node_path7.join)(paths.staging, surface, target);
2192
- const packageRoot = (0, import_node_path7.join)(stageRoot, "node_modules", ...packageName.split("/"));
2193
- if (!fileExists((0, import_node_path7.join)(packageRoot, ...witness.split("/")))) {
2194
- (0, import_node_fs11.mkdirSync)(stageRoot, { recursive: true });
2195
- (0, import_node_fs11.writeFileSync)((0, import_node_path7.join)(stageRoot, "package.json"), JSON.stringify({ name: "mmi-updater-stage", private: true }) + "\n");
2196
- const install = runNpm(["install", "--prefix", stageRoot, "--no-audit", "--no-fund", "--no-package-lock", `${packageName}@${target}`], env);
2275
+ const stageRoot = (0, import_node_path8.join)(paths.staging, surface, target);
2276
+ const packageRoot = (0, import_node_path8.join)(stageRoot, "node_modules", ...packageName.split("/"));
2277
+ const sourceTarball = (0, import_node_path8.join)(stageRoot, "source.tgz");
2278
+ const staged = fileExists((0, import_node_path8.join)(packageRoot, ...witness.split("/")));
2279
+ if (options.payload && typeof options.payload !== "string") return options.payload;
2280
+ if (!staged) {
2281
+ (0, import_node_fs13.mkdirSync)(stageRoot, { recursive: true });
2282
+ (0, import_node_fs13.writeFileSync)((0, import_node_path8.join)(stageRoot, "package.json"), JSON.stringify({ name: "mmi-updater-stage", private: true }) + "\n");
2283
+ (0, import_node_fs13.rmSync)(sourceTarball, { force: true });
2284
+ if (typeof options.payload === "string") (0, import_node_fs13.copyFileSync)(options.payload, sourceTarball);
2285
+ const install = runNpm(["install", "--prefix", stageRoot, "--no-audit", "--no-fund", "--no-package-lock", typeof options.payload === "string" ? sourceTarball : `${packageName}@${target}`], env);
2197
2286
  if (install.status !== 0) {
2198
2287
  return { defer: `staging install failed: ${tail(install.stderr || install.stdout)}` };
2199
2288
  }
2200
2289
  }
2201
2290
  let stagedManifestVersion;
2202
2291
  try {
2203
- stagedManifestVersion = JSON.parse((0, import_node_fs11.readFileSync)((0, import_node_path7.join)(packageRoot, "package.json"), "utf8")).version;
2292
+ stagedManifestVersion = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path8.join)(packageRoot, "package.json"), "utf8")).version;
2204
2293
  } catch {
2205
2294
  }
2206
2295
  if (stagedManifestVersion !== target) {
2207
2296
  return { defer: `staged manifest is ${stagedManifestVersion ?? "unreadable"}, expected ${target}` };
2208
2297
  }
2209
- return { packageRoot };
2298
+ return { packageRoot, source: fileExists(sourceTarball) ? "payload" : "npm", ...fileExists(sourceTarball) ? { tarball: sourceTarball } : {} };
2210
2299
  }
2211
2300
  function npmGlobalArm(options) {
2212
2301
  const env = options.env ?? process.env;
2213
2302
  const { surface, packageName, distRel, target, dryRun, paths } = options;
2214
2303
  const spec = `${packageName}@${target}`;
2215
- const result = (from, to, verdict, detail) => ({ surface, from, to, verdict, detail });
2304
+ let source;
2305
+ const result = (from, to, verdict, detail) => ({ surface, from, to, verdict, detail, ...source ? { source } : {} });
2216
2306
  const highWater = journalHighWater(paths.journalPath, surface, options.journalEvents);
2217
2307
  const localRoot = globalRoot(env);
2218
- const localVersion = localRoot ? manifestVersion((0, import_node_path7.join)(localRoot, ...packageName.split("/"))) : null;
2308
+ const localVersion = localRoot ? manifestVersion((0, import_node_path8.join)(localRoot, ...packageName.split("/"))) : null;
2219
2309
  if (localVersion === target && highWater === target) {
2220
2310
  return result(localVersion, target, "ok", `already at target ${target} (installed manifest + journal high-water)`);
2221
2311
  }
@@ -2233,16 +2323,17 @@ function npmGlobalArm(options) {
2233
2323
  if (dryRun) {
2234
2324
  return result(installed, target, "ok", `dry-run: would converge ${installed ?? "absent"} -> ${target}`);
2235
2325
  }
2236
- const staged = stagePackage({ surface, packageName, target, witness: distRel, paths, env });
2326
+ const staged = stagePackage({ surface, packageName, target, witness: distRel, paths, env, payload: options.payload });
2237
2327
  if ("defer" in staged) {
2238
2328
  return result(installed, target, "defer", staged.defer);
2239
2329
  }
2240
- const stageDist = (0, import_node_path7.join)(staged.packageRoot, ...distRel.split("/"));
2330
+ source = staged.source;
2331
+ const stageDist = (0, import_node_path8.join)(staged.packageRoot, ...distRel.split("/"));
2241
2332
  const stagedVersion = probeVersion(stageDist);
2242
2333
  if (stagedVersion !== target) {
2243
2334
  return result(installed, target, "defer", `staged binary probed ${stagedVersion ?? "dead"}, expected ${target}`);
2244
2335
  }
2245
- const globalInstall = runNpm(["install", "-g", "--no-audit", "--no-fund", spec], env);
2336
+ const globalInstall = runNpm(["install", "-g", "--no-audit", "--no-fund", staged.tarball ?? spec], env);
2246
2337
  if (globalInstall.status !== 0) {
2247
2338
  const reason = `global install failed: ${tail(globalInstall.stderr || globalInstall.stdout)}`;
2248
2339
  const root = globalRoot(env);
@@ -2258,11 +2349,11 @@ function npmGlobalArm(options) {
2258
2349
  }
2259
2350
 
2260
2351
  // src/launch-staging.ts
2261
- var import_node_fs12 = require("node:fs");
2262
- var import_node_path8 = require("node:path");
2352
+ var import_node_fs14 = require("node:fs");
2353
+ var import_node_path9 = require("node:path");
2263
2354
  function readLaunchTarget(path) {
2264
2355
  try {
2265
- const parsed = JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
2356
+ const parsed = JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8"));
2266
2357
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
2267
2358
  const row = parsed;
2268
2359
  if (typeof row.surface !== "string" || typeof row.target !== "string" || typeof row.since !== "string" || typeof row.incoming !== "string") return null;
@@ -2272,15 +2363,15 @@ function readLaunchTarget(path) {
2272
2363
  }
2273
2364
  }
2274
2365
  function writeLaunchTarget(path, record) {
2275
- (0, import_node_fs12.mkdirSync)((0, import_node_path8.join)(path, ".."), { recursive: true });
2366
+ (0, import_node_fs14.mkdirSync)((0, import_node_path9.join)(path, ".."), { recursive: true });
2276
2367
  const tmp = `${path}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
2277
- (0, import_node_fs12.writeFileSync)(tmp, `${JSON.stringify(record, null, 2)}
2368
+ (0, import_node_fs14.writeFileSync)(tmp, `${JSON.stringify(record, null, 2)}
2278
2369
  `, "utf8");
2279
- (0, import_node_fs12.renameSync)(tmp, path);
2370
+ (0, import_node_fs14.renameSync)(tmp, path);
2280
2371
  }
2281
2372
  function clearLaunchTarget(path) {
2282
2373
  try {
2283
- (0, import_node_fs12.rmSync)(path, { force: true });
2374
+ (0, import_node_fs14.rmSync)(path, { force: true });
2284
2375
  } catch {
2285
2376
  }
2286
2377
  }
@@ -2301,7 +2392,7 @@ function noteLaunchStaged(paths, env, options, seam = {}) {
2301
2392
  }
2302
2393
  function probeLaunchTargetVersion(launchTargetPath, versionAt) {
2303
2394
  const record = readLaunchTarget(launchTargetPath);
2304
- if (!record || !(0, import_node_fs12.existsSync)(record.incoming)) return null;
2395
+ if (!record || !(0, import_node_fs14.existsSync)(record.incoming)) return null;
2305
2396
  const version = versionAt(record.incoming);
2306
2397
  return version === record.target ? record.target : null;
2307
2398
  }
@@ -2350,16 +2441,16 @@ function claudeMmi(runner, env) {
2350
2441
  }
2351
2442
  function claudeHomeDir(env) {
2352
2443
  const home = env.HOME?.trim() || env.USERPROFILE?.trim() || (0, import_node_os4.homedir)();
2353
- return (0, import_node_path9.join)(home, ".claude");
2444
+ return (0, import_node_path10.join)(home, ".claude");
2354
2445
  }
2355
2446
  function claudeMarketplacesPath(env) {
2356
- return env.MMI_UPDATER_CLAUDE_MARKETPLACES || (0, import_node_path9.join)(claudeHomeDir(env), "plugins", "known_marketplaces.json");
2447
+ return env.MMI_UPDATER_CLAUDE_MARKETPLACES || (0, import_node_path10.join)(claudeHomeDir(env), "plugins", "known_marketplaces.json");
2357
2448
  }
2358
2449
  function ensureClaudeMarketplace(env) {
2359
2450
  const path = claudeMarketplacesPath(env);
2360
2451
  let body;
2361
2452
  try {
2362
- body = JSON.parse((0, import_node_fs13.readFileSync)(path, "utf8"));
2453
+ body = JSON.parse((0, import_node_fs15.readFileSync)(path, "utf8"));
2363
2454
  } catch (error) {
2364
2455
  if (error?.code === "ENOENT") return { ok: false, detail: `${path} does not exist \u2014 mutmutco marketplace is not registered`, unregistered: true };
2365
2456
  return { ok: false, detail: `cannot read ${path}` };
@@ -2383,24 +2474,24 @@ var CLAUDE_PACKAGE = "@mutmutco/claude-plugin";
2383
2474
  var CLAUDE_MANIFEST = ".claude-plugin/plugin.json";
2384
2475
  var CLAUDE_TREE_MARKERS = [".claude-plugin/plugin.json"];
2385
2476
  function claudePluginsRoot(env) {
2386
- return (0, import_node_path9.join)(claudeHomeDir(env), "plugins");
2477
+ return (0, import_node_path10.join)(claudeHomeDir(env), "plugins");
2387
2478
  }
2388
2479
  function claudeMarkerVersion(root) {
2389
2480
  try {
2390
- const version = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path9.join)(root, ...CLAUDE_MANIFEST.split("/")), "utf8")).version;
2481
+ const version = JSON.parse((0, import_node_fs15.readFileSync)((0, import_node_path10.join)(root, ...CLAUDE_MANIFEST.split("/")), "utf8")).version;
2391
2482
  return typeof version === "string" ? version : null;
2392
2483
  } catch {
2393
2484
  return null;
2394
2485
  }
2395
2486
  }
2396
2487
  function claudeTreeHealthy(root) {
2397
- return CLAUDE_TREE_MARKERS.every((rel) => fileExists((0, import_node_path9.join)(root, ...rel.split("/"))));
2488
+ return CLAUDE_TREE_MARKERS.every((rel) => fileExists((0, import_node_path10.join)(root, ...rel.split("/"))));
2398
2489
  }
2399
2490
  function claudeNpmEnv(env) {
2400
2491
  return { ...env, npm_config_allow_remote: "all" };
2401
2492
  }
2402
2493
  function probeClaudeLaunchStaging(env = process.env) {
2403
- return probeLaunchTargetVersion((0, import_node_path9.join)(claudePluginsRoot(env), "staging", "launch-target.json"), claudeMarkerVersion);
2494
+ return probeLaunchTargetVersion((0, import_node_path10.join)(claudePluginsRoot(env), "staging", "launch-target.json"), claudeMarkerVersion);
2404
2495
  }
2405
2496
  function claudeArm(options) {
2406
2497
  const env = options.env ?? process.env;
@@ -2408,12 +2499,14 @@ function claudeArm(options) {
2408
2499
  const paths = options.paths ?? ensureState(env);
2409
2500
  const target = options.target;
2410
2501
  const repoUrl = options.repoUrl ?? (env.MMI_UPDATER_REPO || REPO_URL_DEFAULT);
2502
+ let source;
2411
2503
  const result = (from2, to, verdict, detail) => ({
2412
2504
  surface: "claude",
2413
2505
  from: from2,
2414
2506
  to,
2415
2507
  verdict,
2416
- detail
2508
+ detail,
2509
+ ...source ? { source } : {}
2417
2510
  });
2418
2511
  const before = claudeMmi(runner, env);
2419
2512
  if (before.error) return result(null, target, "defer", before.error);
@@ -2433,7 +2526,7 @@ function claudeArm(options) {
2433
2526
  }
2434
2527
  if (!marketplaceTrust.ok) return result(from, target, "defer", marketplaceTrust.detail ?? "cannot trust the mutmutco marketplace registration");
2435
2528
  const pluginsRoot = claudePluginsRoot(env);
2436
- const launchTargetPath = (0, import_node_path9.join)(pluginsRoot, "staging", "launch-target.json");
2529
+ const launchTargetPath = (0, import_node_path10.join)(pluginsRoot, "staging", "launch-target.json");
2437
2530
  if (options.dryRun) {
2438
2531
  return result(from, target, "ok", `dry-run: would refresh mutmutco, stage ${target} on the Claude volume, and converge mmi@mutmutco ${from ?? "absent"} -> ${target}`);
2439
2532
  }
@@ -2447,34 +2540,35 @@ function claudeArm(options) {
2447
2540
  clearLaunchTarget(launchTargetPath);
2448
2541
  return result(from, target, "ok", `catalog refreshed; installed+enabled at target ${target}`);
2449
2542
  }
2450
- const incomingRoot = (0, import_node_path9.join)(pluginsRoot, "staging", "incoming");
2451
- const incoming = (0, import_node_path9.join)(incomingRoot, target);
2543
+ const incomingRoot = (0, import_node_path10.join)(pluginsRoot, "staging", "incoming");
2544
+ const incoming = (0, import_node_path10.join)(incomingRoot, target);
2452
2545
  const priorLaunch = readLaunchTarget(launchTargetPath);
2453
2546
  const reuseIncoming = priorLaunch?.target === target && priorLaunch.incoming === incoming && claudeMarkerVersion(incoming) === target && claudeTreeHealthy(incoming);
2454
2547
  if (!reuseIncoming) {
2455
- const staged = stagePackage({ surface: "claude", packageName: CLAUDE_PACKAGE, target, witness: CLAUDE_MANIFEST, paths, env });
2548
+ const staged = stagePackage({ surface: "claude", packageName: CLAUDE_PACKAGE, target, witness: CLAUDE_MANIFEST, paths, env, payload: options.payload });
2456
2549
  if ("defer" in staged) return result(from, target, "defer", staged.defer);
2550
+ source = staged.source;
2457
2551
  if (claudeMarkerVersion(staged.packageRoot) !== target || !claudeTreeHealthy(staged.packageRoot)) {
2458
2552
  return result(from, target, "defer", `staged Claude manifest is ${claudeMarkerVersion(staged.packageRoot) ?? "unreadable"} or its tree is incomplete (expected ${target})`);
2459
2553
  }
2460
2554
  try {
2461
- (0, import_node_fs13.mkdirSync)((0, import_node_path9.join)(pluginsRoot, "staging"), { recursive: true });
2462
- (0, import_node_fs13.rmSync)(incomingRoot, { recursive: true, force: true });
2463
- (0, import_node_fs13.cpSync)(staged.packageRoot, incoming, { recursive: true });
2555
+ (0, import_node_fs15.mkdirSync)((0, import_node_path10.join)(pluginsRoot, "staging"), { recursive: true });
2556
+ (0, import_node_fs15.rmSync)(incomingRoot, { recursive: true, force: true });
2557
+ (0, import_node_fs15.cpSync)(staged.packageRoot, incoming, { recursive: true });
2464
2558
  } catch (error) {
2465
2559
  return result(from, target, "defer", `cannot place incoming Claude generation: ${error?.message ?? error}`);
2466
2560
  }
2467
2561
  if (claudeMarkerVersion(incoming) !== target || !claudeTreeHealthy(incoming)) {
2468
- (0, import_node_fs13.rmSync)(incomingRoot, { recursive: true, force: true });
2562
+ (0, import_node_fs15.rmSync)(incomingRoot, { recursive: true, force: true });
2469
2563
  return result(from, target, "defer", "incoming Claude generation did not reproduce the verified payload");
2470
2564
  }
2471
2565
  }
2472
- const cacheTarget = (0, import_node_path9.join)(pluginsRoot, "cache", "mutmutco", "mmi", target);
2566
+ const cacheTarget = (0, import_node_path10.join)(pluginsRoot, "cache", "mutmutco", "mmi", target);
2473
2567
  try {
2474
- if (!(0, import_node_fs13.existsSync)(cacheTarget) || claudeMarkerVersion(cacheTarget) !== target || !claudeTreeHealthy(cacheTarget)) {
2475
- (0, import_node_fs13.rmSync)(cacheTarget, { recursive: true, force: true });
2476
- (0, import_node_fs13.mkdirSync)((0, import_node_path9.join)(cacheTarget, ".."), { recursive: true });
2477
- (0, import_node_fs13.cpSync)(incoming, cacheTarget, { recursive: true });
2568
+ if (!(0, import_node_fs15.existsSync)(cacheTarget) || claudeMarkerVersion(cacheTarget) !== target || !claudeTreeHealthy(cacheTarget)) {
2569
+ (0, import_node_fs15.rmSync)(cacheTarget, { recursive: true, force: true });
2570
+ (0, import_node_fs15.mkdirSync)((0, import_node_path10.join)(cacheTarget, ".."), { recursive: true });
2571
+ (0, import_node_fs15.cpSync)(incoming, cacheTarget, { recursive: true });
2478
2572
  }
2479
2573
  } catch (error) {
2480
2574
  return result(from, target, "defer", `cannot populate Claude plugin cache: ${error?.message ?? error}`);
@@ -2502,7 +2596,7 @@ function claudeArm(options) {
2502
2596
  }
2503
2597
  clearLaunchTarget(launchTargetPath);
2504
2598
  try {
2505
- (0, import_node_fs13.rmSync)(incomingRoot, { recursive: true, force: true });
2599
+ (0, import_node_fs15.rmSync)(incomingRoot, { recursive: true, force: true });
2506
2600
  } catch {
2507
2601
  }
2508
2602
  return result(from, target, "ok", `catalog refreshed; converged and verified ${from ?? "absent"} -> ${target}`);
@@ -2581,12 +2675,12 @@ function probeNativeHostInstallation(surface, env = process.env, runner = runHos
2581
2675
 
2582
2676
  // src/surfaces.ts
2583
2677
  function jervcodeAgentDir(env = process.env) {
2584
- return env.MMI_UPDATER_JERVCODE_AGENT_DIR?.trim() || env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path10.join)((0, import_node_os5.homedir)(), ".jerv", "agent");
2678
+ return env.MMI_UPDATER_JERVCODE_AGENT_DIR?.trim() || env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path11.join)((0, import_node_os5.homedir)(), ".jerv", "agent");
2585
2679
  }
2586
2680
  function hermesHome(env = process.env, platform = process.platform) {
2587
2681
  if (env.HERMES_HOME?.trim()) return env.HERMES_HOME.trim();
2588
- if (platform === "win32") return (0, import_node_path10.join)(env.LOCALAPPDATA?.trim() || (0, import_node_path10.join)((0, import_node_os5.homedir)(), "AppData", "Local"), "hermes");
2589
- return (0, import_node_path10.join)((0, import_node_os5.homedir)(), ".hermes");
2682
+ if (platform === "win32") return (0, import_node_path11.join)(env.LOCALAPPDATA?.trim() || (0, import_node_path11.join)((0, import_node_os5.homedir)(), "AppData", "Local"), "hermes");
2683
+ return (0, import_node_path11.join)((0, import_node_os5.homedir)(), ".hermes");
2590
2684
  }
2591
2685
  function hermesHostCommand(env = process.env) {
2592
2686
  return env.MMI_UPDATER_HERMES?.trim() || "hermes";
@@ -2600,36 +2694,36 @@ function surfaceArmPlan(token, managedSurfaces) {
2600
2694
  }
2601
2695
  function enumerateSurfaces(env = process.env) {
2602
2696
  const home = env.HOME?.trim() || env.USERPROFILE?.trim() || (0, import_node_os5.homedir)();
2603
- const codexHome = env.CODEX_HOME || (0, import_node_path10.join)(home, ".codex");
2697
+ const codexHome = env.CODEX_HOME || (0, import_node_path11.join)(home, ".codex");
2604
2698
  return [
2605
- { id: "claude", marker: (0, import_node_path10.join)(home, ".claude", "plugins", "installed_plugins.json") },
2606
- { id: "codex", marker: (0, import_node_path10.join)(codexHome, "plugins", "installed_plugins.json") },
2699
+ { id: "claude", marker: (0, import_node_path11.join)(home, ".claude", "plugins", "installed_plugins.json") },
2700
+ { id: "codex", marker: (0, import_node_path11.join)(codexHome, "plugins", "installed_plugins.json") },
2607
2701
  // The host, not the payload (#4951, #5356): this marker used to be plugins/local/mmi — the MMI
2608
2702
  // plugin tree itself — so a machine running Cursor WITHOUT the plugin enumerated as "no Cursor"
2609
2703
  // and the arm could never make the first install. The plugin's absence is a converge action, not
2610
2704
  // a skip. The host root mirrors surfaceConfigRoot('cursor') in cli/src/plugin-guard-io.ts.
2611
- { id: "cursor", marker: (0, import_node_path10.join)(home, ".cursor") },
2612
- { id: "jervcode", marker: (0, import_node_path10.join)(jervcodeAgentDir(env), "settings.json") },
2705
+ { id: "cursor", marker: (0, import_node_path11.join)(home, ".cursor") },
2706
+ { id: "jervcode", marker: (0, import_node_path11.join)(jervcodeAgentDir(env), "settings.json") },
2613
2707
  // Host CLI, not HERMES_HOME (#5673): the config tree can survive an uninstall and still carry
2614
2708
  // leftover plugin manifests — that residue must not enumerate as an installed host.
2615
2709
  { id: "hermes", marker: `${hermesHostCommand(env)} --version` }
2616
2710
  ].map((probe) => ({
2617
2711
  ...probe,
2618
- present: probe.id === "hermes" ? hermesHostPresent(env) : (0, import_node_fs14.existsSync)(probe.marker)
2712
+ present: probe.id === "hermes" ? hermesHostPresent(env) : (0, import_node_fs16.existsSync)(probe.marker)
2619
2713
  }));
2620
2714
  }
2621
2715
 
2622
2716
  // src/arm-cursor.ts
2623
- var import_node_fs17 = require("node:fs");
2717
+ var import_node_fs19 = require("node:fs");
2624
2718
  var import_node_child_process7 = require("node:child_process");
2625
2719
  var import_node_os7 = require("node:os");
2626
- var import_node_path11 = require("node:path");
2720
+ var import_node_path12 = require("node:path");
2627
2721
 
2628
2722
  // src/compat.ts
2629
- var import_node_fs15 = require("node:fs");
2723
+ var import_node_fs17 = require("node:fs");
2630
2724
  function readManifestCompat(manifestPath) {
2631
2725
  try {
2632
- const parsed = JSON.parse((0, import_node_fs15.readFileSync)(manifestPath, "utf8"));
2726
+ const parsed = JSON.parse((0, import_node_fs17.readFileSync)(manifestPath, "utf8"));
2633
2727
  return typeof parsed.mmiCompat === "string" ? parsed.mmiCompat : void 0;
2634
2728
  } catch {
2635
2729
  return void 0;
@@ -2637,7 +2731,7 @@ function readManifestCompat(manifestPath) {
2637
2731
  }
2638
2732
 
2639
2733
  // src/host-doc-lock.ts
2640
- var import_node_fs16 = require("node:fs");
2734
+ var import_node_fs18 = require("node:fs");
2641
2735
  var import_node_os6 = require("node:os");
2642
2736
  var SHARED_DOC_LOCK_STALE_MS = 3e4;
2643
2737
  var SHARED_DOC_LOCK_ATTEMPTS = 50;
@@ -2651,7 +2745,7 @@ function lockContent(options) {
2651
2745
  }
2652
2746
  function readHolder(lockPath) {
2653
2747
  try {
2654
- const parsed = JSON.parse((0, import_node_fs16.readFileSync)(lockPath, "utf8"));
2748
+ const parsed = JSON.parse((0, import_node_fs18.readFileSync)(lockPath, "utf8"));
2655
2749
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
2656
2750
  return parsed;
2657
2751
  } catch {
@@ -2663,7 +2757,7 @@ function lockAgeMs(lockPath, now) {
2663
2757
  const declared = typeof holder?.acquiredAt === "string" ? Date.parse(holder.acquiredAt) : Number.NaN;
2664
2758
  if (!Number.isNaN(declared)) return Math.max(0, now - declared);
2665
2759
  try {
2666
- return Math.max(0, now - (0, import_node_fs16.statSync)(lockPath).mtimeMs);
2760
+ return Math.max(0, now - (0, import_node_fs18.statSync)(lockPath).mtimeMs);
2667
2761
  } catch {
2668
2762
  return 0;
2669
2763
  }
@@ -2686,9 +2780,9 @@ function acquireSharedDocLock(documentPath, options) {
2686
2780
  for (let attempt = 0; attempt < attempts; attempt += 1) {
2687
2781
  let fd;
2688
2782
  try {
2689
- fd = (0, import_node_fs16.openSync)(lockPath, "wx");
2690
- (0, import_node_fs16.writeSync)(fd, content);
2691
- (0, import_node_fs16.closeSync)(fd);
2783
+ fd = (0, import_node_fs18.openSync)(lockPath, "wx");
2784
+ (0, import_node_fs18.writeSync)(fd, content);
2785
+ (0, import_node_fs18.closeSync)(fd);
2692
2786
  return {
2693
2787
  documentPath,
2694
2788
  lockPath,
@@ -2701,11 +2795,11 @@ function acquireSharedDocLock(documentPath, options) {
2701
2795
  } catch (error) {
2702
2796
  if (fd !== void 0) {
2703
2797
  try {
2704
- (0, import_node_fs16.closeSync)(fd);
2798
+ (0, import_node_fs18.closeSync)(fd);
2705
2799
  } catch {
2706
2800
  }
2707
2801
  try {
2708
- (0, import_node_fs16.unlinkSync)(lockPath);
2802
+ (0, import_node_fs18.unlinkSync)(lockPath);
2709
2803
  } catch {
2710
2804
  }
2711
2805
  }
@@ -2714,12 +2808,12 @@ function acquireSharedDocLock(documentPath, options) {
2714
2808
  if (lockAgeMs(lockPath, Date.now()) >= staleAfterMs) {
2715
2809
  const aside = `${lockPath}.stale-${Date.now()}`;
2716
2810
  try {
2717
- (0, import_node_fs16.renameSync)(lockPath, aside);
2811
+ (0, import_node_fs18.renameSync)(lockPath, aside);
2718
2812
  } catch {
2719
2813
  continue;
2720
2814
  }
2721
2815
  try {
2722
- (0, import_node_fs16.rmSync)(aside, { force: true });
2816
+ (0, import_node_fs18.rmSync)(aside, { force: true });
2723
2817
  } catch {
2724
2818
  }
2725
2819
  continue;
@@ -2732,7 +2826,7 @@ function releaseSharedDocLock(handle) {
2732
2826
  try {
2733
2827
  const holder = readHolder(handle.lockPath);
2734
2828
  if (holder && holder.owner === handle.owner && Number(holder.pid) === handle.pid) {
2735
- (0, import_node_fs16.unlinkSync)(handle.lockPath);
2829
+ (0, import_node_fs18.unlinkSync)(handle.lockPath);
2736
2830
  }
2737
2831
  } catch {
2738
2832
  }
@@ -2754,14 +2848,14 @@ var KEEP_GENERATIONS = 2;
2754
2848
  var STRANDED_TMP_AGE_MS = 24 * 60 * 6e4;
2755
2849
  var TREE_FILES = [MANIFEST, "skills/bootstrap/SKILL.md"];
2756
2850
  function cursorPluginsRoot() {
2757
- return (0, import_node_path11.join)((0, import_node_os7.homedir)(), ".cursor", "plugins");
2851
+ return (0, import_node_path12.join)((0, import_node_os7.homedir)(), ".cursor", "plugins");
2758
2852
  }
2759
2853
  function treeHealthy(root) {
2760
- return TREE_FILES.every((rel) => (0, import_node_fs17.existsSync)((0, import_node_path11.join)(root, ...rel.split("/"))));
2854
+ return TREE_FILES.every((rel) => (0, import_node_fs19.existsSync)((0, import_node_path12.join)(root, ...rel.split("/"))));
2761
2855
  }
2762
2856
  function readJson(root, rel) {
2763
2857
  try {
2764
- return JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path11.join)(root, ...rel.split("/")), "utf8"));
2858
+ return JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path12.join)(root, ...rel.split("/")), "utf8"));
2765
2859
  } catch {
2766
2860
  return null;
2767
2861
  }
@@ -2770,7 +2864,7 @@ function manifest(root) {
2770
2864
  return readJson(root, MANIFEST);
2771
2865
  }
2772
2866
  function probeCursorInstallation() {
2773
- const location = (0, import_node_path11.join)(cursorPluginsRoot(), "local", "mmi");
2867
+ const location = (0, import_node_path12.join)(cursorPluginsRoot(), "local", "mmi");
2774
2868
  const version = manifest(location)?.version ?? null;
2775
2869
  return { version, location, detail: version ? "installed Cursor plugin manifest" : "installed Cursor plugin manifest was unreadable" };
2776
2870
  }
@@ -2785,7 +2879,7 @@ function message(error) {
2785
2879
  }
2786
2880
  function discard(path) {
2787
2881
  try {
2788
- (0, import_node_fs17.rmSync)(path, { recursive: true, force: true });
2882
+ (0, import_node_fs19.rmSync)(path, { recursive: true, force: true });
2789
2883
  } catch {
2790
2884
  }
2791
2885
  }
@@ -2813,7 +2907,7 @@ function cursorHostEvidence(env) {
2813
2907
  return null;
2814
2908
  }
2815
2909
  function resolvedPluginRoot(root) {
2816
- return (0, import_node_path11.join)(root).replace(/\\/g, "/");
2910
+ return (0, import_node_path12.join)(root).replace(/\\/g, "/");
2817
2911
  }
2818
2912
  function isMmiEntry(entry, pluginRoot) {
2819
2913
  if (typeof entry !== "object" || entry === null || typeof entry.command !== "string") return false;
@@ -2837,12 +2931,12 @@ function stripUserHooks(existing, pluginRoot) {
2837
2931
  }
2838
2932
  var CURSOR_HOOKS_LOCK_OWNER = "mmi-hub:cursor-hooks";
2839
2933
  function reconcileCursorUserHooks(pluginRoot, homeDir, lock = {}) {
2840
- const path = (0, import_node_path11.join)(homeDir, ".cursor", USER_HOOKS_FILE);
2934
+ const path = (0, import_node_path12.join)(homeDir, ".cursor", USER_HOOKS_FILE);
2841
2935
  return withSharedDocLock(path, { owner: CURSOR_HOOKS_LOCK_OWNER, ...lock }, () => {
2842
- if (!(0, import_node_fs17.existsSync)(path)) return "current";
2936
+ if (!(0, import_node_fs19.existsSync)(path)) return "current";
2843
2937
  let existing;
2844
2938
  try {
2845
- existing = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
2939
+ existing = JSON.parse((0, import_node_fs19.readFileSync)(path, "utf8"));
2846
2940
  } catch {
2847
2941
  return "user-conflict";
2848
2942
  }
@@ -2850,8 +2944,8 @@ function reconcileCursorUserHooks(pluginRoot, homeDir, lock = {}) {
2850
2944
  if (!stripped) return "user-conflict";
2851
2945
  if (JSON.stringify(stripped) === JSON.stringify(existing)) return "current";
2852
2946
  const tmp = `${path}.tmp-${process.pid}`;
2853
- (0, import_node_fs17.writeFileSync)(tmp, JSON.stringify(stripped, null, 2) + "\n", "utf8");
2854
- (0, import_node_fs17.renameSync)(tmp, path);
2947
+ (0, import_node_fs19.writeFileSync)(tmp, JSON.stringify(stripped, null, 2) + "\n", "utf8");
2948
+ (0, import_node_fs19.renameSync)(tmp, path);
2855
2949
  return "updated";
2856
2950
  });
2857
2951
  }
@@ -2866,41 +2960,41 @@ function userHooksDetail(pluginRoot, homeDir) {
2866
2960
  case "updated":
2867
2961
  return "; user hooks legacy entries stripped";
2868
2962
  case "user-conflict":
2869
- return `; USER HOOKS CONFLICT at ${(0, import_node_path11.join)(homeDir, ".cursor", USER_HOOKS_FILE)} \u2014 legacy entries were not changed`;
2963
+ return `; USER HOOKS CONFLICT at ${(0, import_node_path12.join)(homeDir, ".cursor", USER_HOOKS_FILE)} \u2014 legacy entries were not changed`;
2870
2964
  default:
2871
2965
  return "";
2872
2966
  }
2873
2967
  }
2874
2968
  function writeRollbackPointer(root, entry) {
2875
- const path = (0, import_node_path11.join)(root, "quarantine", "rollback.json");
2969
+ const path = (0, import_node_path12.join)(root, "quarantine", "rollback.json");
2876
2970
  const tmp = `${path}.tmp-${process.pid}`;
2877
2971
  try {
2878
- (0, import_node_fs17.writeFileSync)(tmp, JSON.stringify({ surface: "cursor", ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }, null, 2) + "\n", "utf8");
2879
- (0, import_node_fs17.renameSync)(tmp, path);
2972
+ (0, import_node_fs19.writeFileSync)(tmp, JSON.stringify({ surface: "cursor", ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }, null, 2) + "\n", "utf8");
2973
+ (0, import_node_fs19.renameSync)(tmp, path);
2880
2974
  } catch {
2881
2975
  discard(tmp);
2882
2976
  }
2883
2977
  }
2884
2978
  function mtimeMs(path) {
2885
2979
  try {
2886
- return (0, import_node_fs17.statSync)(path).mtimeMs;
2980
+ return (0, import_node_fs19.statSync)(path).mtimeMs;
2887
2981
  } catch {
2888
2982
  return 0;
2889
2983
  }
2890
2984
  }
2891
2985
  function pruneQuarantine(root, keep) {
2892
- const dir = (0, import_node_path11.join)(root, "quarantine");
2986
+ const dir = (0, import_node_path12.join)(root, "quarantine");
2893
2987
  let generations;
2894
2988
  try {
2895
- generations = (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("mmi-")).map((entry) => (0, import_node_path11.join)(dir, entry.name)).sort((a, b) => mtimeMs(b) - mtimeMs(a));
2989
+ generations = (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("mmi-")).map((entry) => (0, import_node_path12.join)(dir, entry.name)).sort((a, b) => mtimeMs(b) - mtimeMs(a));
2896
2990
  } catch {
2897
2991
  return 0;
2898
2992
  }
2899
2993
  let stranded = 0;
2900
2994
  try {
2901
- for (const entry of (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true })) {
2995
+ for (const entry of (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true })) {
2902
2996
  if (!entry.isFile() || !/^rollback\.json\.tmp-\d+$/.test(entry.name)) continue;
2903
- const path = (0, import_node_path11.join)(dir, entry.name);
2997
+ const path = (0, import_node_path12.join)(dir, entry.name);
2904
2998
  if (Date.now() - mtimeMs(path) < STRANDED_TMP_AGE_MS) continue;
2905
2999
  discard(path);
2906
3000
  stranded += 1;
@@ -2918,16 +3012,16 @@ function pruneQuarantine(root, keep) {
2918
3012
  }
2919
3013
  function restorePrevious(live, quarantined, broken) {
2920
3014
  try {
2921
- (0, import_node_fs17.renameSync)(live, broken);
3015
+ (0, import_node_fs19.renameSync)(live, broken);
2922
3016
  } catch {
2923
3017
  return "kept-broken";
2924
3018
  }
2925
3019
  try {
2926
- (0, import_node_fs17.renameSync)(quarantined, live);
3020
+ (0, import_node_fs19.renameSync)(quarantined, live);
2927
3021
  return "restored";
2928
3022
  } catch {
2929
3023
  try {
2930
- (0, import_node_fs17.renameSync)(broken, live);
3024
+ (0, import_node_fs19.renameSync)(broken, live);
2931
3025
  return "kept-broken";
2932
3026
  } catch {
2933
3027
  return "lost";
@@ -2938,9 +3032,11 @@ function cursorArm(options) {
2938
3032
  const env = options.env ?? process.env;
2939
3033
  const { target, dryRun, paths } = options;
2940
3034
  const root = cursorPluginsRoot();
2941
- const live = (0, import_node_path11.join)(root, "local", "mmi");
3035
+ const live = (0, import_node_path12.join)(root, "local", "mmi");
3036
+ let source;
2942
3037
  const result = (from, to, verdict, detail, launchStaged = false) => ({
2943
3038
  surface: "cursor",
3039
+ ...source ? { source } : {},
2944
3040
  from,
2945
3041
  to,
2946
3042
  verdict,
@@ -2948,7 +3044,7 @@ function cursorArm(options) {
2948
3044
  launchStaged: launchStaged || void 0,
2949
3045
  // C11: the constraint of the generation LEFT at `live` — read at result time, so a failed
2950
3046
  // switch reports the restored generation's declaration, not the rejected one's (#4973).
2951
- compat: readManifestCompat((0, import_node_path11.join)(live, MANIFEST))
3047
+ compat: readManifestCompat((0, import_node_path12.join)(live, MANIFEST))
2952
3048
  });
2953
3049
  const current = manifest(live);
2954
3050
  const installed = current?.version ?? null;
@@ -2962,30 +3058,31 @@ function cursorArm(options) {
2962
3058
  if (installed === target && treeHealthy(live)) {
2963
3059
  return result(installed, target, "ok", `already at target ${target}${userHooksDetail(live, (0, import_node_os7.homedir)())}`);
2964
3060
  }
2965
- if ((0, import_node_fs17.existsSync)(live) && !mmiOwned(live)) {
3061
+ if ((0, import_node_fs19.existsSync)(live) && !mmiOwned(live)) {
2966
3062
  return result(installed, target, "defer", `${live} carries no MMI ownership marker (plugin manifest name, or a ${PACKAGE} package.json) \u2014 refusing to displace an unmanaged directory (mmi-cli plugin heal adopts it)`);
2967
3063
  }
2968
3064
  if (dryRun) {
2969
3065
  return result(installed, target, "ok", `dry-run: would stage ${PACKAGE}@${target} and switch ${installed ?? "absent"} -> ${target} while Cursor is absent`);
2970
3066
  }
2971
- const staged = stagePackage({ surface: "cursor", packageName: PACKAGE, target, witness: MANIFEST, paths, env });
3067
+ const staged = stagePackage({ surface: "cursor", packageName: PACKAGE, target, witness: MANIFEST, paths, env, payload: options.payload });
2972
3068
  if ("defer" in staged) {
2973
3069
  return result(installed, target, "defer", staged.defer);
2974
3070
  }
3071
+ source = staged.source;
2975
3072
  const stagedMarker = manifest(staged.packageRoot)?.version;
2976
3073
  if (stagedMarker !== target || !treeHealthy(staged.packageRoot)) {
2977
3074
  return result(installed, target, "defer", `staged tree marker is ${stagedMarker ?? "unreadable"} and the tree is ${treeHealthy(staged.packageRoot) ? "complete" : "incomplete"}, expected ${target} and complete`);
2978
3075
  }
2979
- const launchTargetPath = (0, import_node_path11.join)(root, "staging", "launch-target.json");
3076
+ const launchTargetPath = (0, import_node_path12.join)(root, "staging", "launch-target.json");
2980
3077
  const priorLaunch = readLaunchTarget(launchTargetPath);
2981
- let incoming = priorLaunch?.target === target && priorLaunch.incoming.startsWith((0, import_node_path11.join)(root, "staging")) && manifest(priorLaunch.incoming)?.version === target && treeHealthy(priorLaunch.incoming) ? priorLaunch.incoming : (0, import_node_path11.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
3078
+ let incoming = priorLaunch?.target === target && priorLaunch.incoming.startsWith((0, import_node_path12.join)(root, "staging")) && manifest(priorLaunch.incoming)?.version === target && treeHealthy(priorLaunch.incoming) ? priorLaunch.incoming : (0, import_node_path12.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
2982
3079
  const reuseIncoming = incoming === priorLaunch?.incoming;
2983
- if (!reuseIncoming || !(0, import_node_fs17.existsSync)(incoming)) {
2984
- incoming = (0, import_node_path11.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
2985
- for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs17.mkdirSync)((0, import_node_path11.join)(root, dir), { recursive: true });
3080
+ if (!reuseIncoming || !(0, import_node_fs19.existsSync)(incoming)) {
3081
+ incoming = (0, import_node_path12.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
3082
+ for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs19.mkdirSync)((0, import_node_path12.join)(root, dir), { recursive: true });
2986
3083
  try {
2987
3084
  discard(incoming);
2988
- (0, import_node_fs17.cpSync)(staged.packageRoot, incoming, { recursive: true });
3085
+ (0, import_node_fs19.cpSync)(staged.packageRoot, incoming, { recursive: true });
2989
3086
  } catch (error) {
2990
3087
  discard(incoming);
2991
3088
  return result(installed, target, "defer", `copy into ${root} failed: ${message(error)}`);
@@ -3008,8 +3105,8 @@ function cursorArm(options) {
3008
3105
  return result(installed, target, "ok", `staged ${target} for next launch while Cursor is running (${busy}) \u2014 ${pending}`, true);
3009
3106
  }
3010
3107
  const stamp = Date.now();
3011
- const quarantined = (0, import_node_path11.join)(root, "quarantine", `mmi-${safeSegment(installed ?? "unknown")}-${stamp}`);
3012
- for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs17.mkdirSync)((0, import_node_path11.join)(root, dir), { recursive: true });
3108
+ const quarantined = (0, import_node_path12.join)(root, "quarantine", `mmi-${safeSegment(installed ?? "unknown")}-${stamp}`);
3109
+ for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs19.mkdirSync)((0, import_node_path12.join)(root, dir), { recursive: true });
3013
3110
  const started = cursorHostEvidence(env);
3014
3111
  if (started) {
3015
3112
  const pending = noteLaunchStaged(paths, env, {
@@ -3024,15 +3121,15 @@ function cursorArm(options) {
3024
3121
  }
3025
3122
  let displaced = false;
3026
3123
  try {
3027
- if ((0, import_node_fs17.existsSync)(live)) {
3028
- (0, import_node_fs17.renameSync)(live, quarantined);
3124
+ if ((0, import_node_fs19.existsSync)(live)) {
3125
+ (0, import_node_fs19.renameSync)(live, quarantined);
3029
3126
  displaced = true;
3030
3127
  }
3031
- (0, import_node_fs17.renameSync)(incoming, live);
3128
+ (0, import_node_fs19.renameSync)(incoming, live);
3032
3129
  } catch (error) {
3033
- if (displaced && !(0, import_node_fs17.existsSync)(live)) {
3130
+ if (displaced && !(0, import_node_fs19.existsSync)(live)) {
3034
3131
  try {
3035
- (0, import_node_fs17.renameSync)(quarantined, live);
3132
+ (0, import_node_fs19.renameSync)(quarantined, live);
3036
3133
  } catch {
3037
3134
  }
3038
3135
  }
@@ -3043,7 +3140,7 @@ function cursorArm(options) {
3043
3140
  }
3044
3141
  const evidence = manifest(live)?.version;
3045
3142
  if (evidence !== target || !treeHealthy(live)) {
3046
- const broken = `${(0, import_node_path11.join)(root, "quarantine", `mmi-${safeSegment(evidence ?? "broken")}-${stamp}`)}-failed`;
3143
+ const broken = `${(0, import_node_path12.join)(root, "quarantine", `mmi-${safeSegment(evidence ?? "broken")}-${stamp}`)}-failed`;
3047
3144
  const outcome = displaced ? restorePrevious(live, quarantined, broken) : "none";
3048
3145
  const detail = outcome === "restored" ? `restored the previous generation ${installed ?? "unknown"}, unverified tree kept at ${broken}` : outcome === "lost" ? `restore failed and ${live} is missing \u2014 the previous generation is at ${quarantined}` : displaced ? `restore failed, the unverified tree is still live and the previous generation is at ${quarantined}` : "nothing was displaced \u2014 there is no previous generation to restore";
3049
3146
  writeRollbackPointer(root, outcome === "restored" ? { installed: installed ?? "unknown", previous: null, generation: null } : { installed: evidence ?? "unknown", previous: installed, generation: displaced ? quarantined : null });
@@ -3056,12 +3153,12 @@ function cursorArm(options) {
3056
3153
  return result(installed, target, "ok", `switched ${installed ?? "absent"} -> ${target}; ${previous}${pruned ? `; pruned ${pruned} older generation${pruned === 1 ? "" : "s"}` : ""}${userHooksDetail(live, (0, import_node_os7.homedir)())}`);
3057
3154
  }
3058
3155
  function probeCursorLaunchStaging() {
3059
- return probeLaunchTargetVersion((0, import_node_path11.join)(cursorPluginsRoot(), "staging", "launch-target.json"), (root) => manifest(root)?.version ?? null);
3156
+ return probeLaunchTargetVersion((0, import_node_path12.join)(cursorPluginsRoot(), "staging", "launch-target.json"), (root) => manifest(root)?.version ?? null);
3060
3157
  }
3061
3158
 
3062
3159
  // src/arm-jervcode.ts
3063
- var import_node_fs18 = require("node:fs");
3064
- var import_node_path12 = require("node:path");
3160
+ var import_node_fs20 = require("node:fs");
3161
+ var import_node_path13 = require("node:path");
3065
3162
  var PI_PACKAGE = "@mutmutco/pi-plugin";
3066
3163
  function hostEnv(env) {
3067
3164
  const dir = jervcodeAgentDir(env);
@@ -3072,7 +3169,7 @@ function hostCommands(_env) {
3072
3169
  }
3073
3170
  function readPackageSpecs(env) {
3074
3171
  try {
3075
- const settings = JSON.parse((0, import_node_fs18.readFileSync)((0, import_node_path12.join)(jervcodeAgentDir(env), "settings.json"), "utf8"));
3172
+ const settings = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path13.join)(jervcodeAgentDir(env), "settings.json"), "utf8"));
3076
3173
  return Array.isArray(settings.packages) ? settings.packages.filter((entry) => typeof entry === "string") : [];
3077
3174
  } catch {
3078
3175
  return null;
@@ -3080,14 +3177,14 @@ function readPackageSpecs(env) {
3080
3177
  }
3081
3178
  function installedVersion(env) {
3082
3179
  try {
3083
- const manifest2 = JSON.parse((0, import_node_fs18.readFileSync)((0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"), "utf8"));
3180
+ const manifest2 = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"), "utf8"));
3084
3181
  return typeof manifest2.version === "string" ? manifest2.version : null;
3085
3182
  } catch {
3086
3183
  return null;
3087
3184
  }
3088
3185
  }
3089
3186
  function materializedManifestLocation(env) {
3090
- return (0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"));
3187
+ return (0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"));
3091
3188
  }
3092
3189
  var PI_LIST_SPEC = new RegExp(`npm:${PI_PACKAGE.replace("/", "\\/")}@(\\S+)`);
3093
3190
  function parseListText(stdout) {
@@ -3146,32 +3243,32 @@ function jervcodeArm(options) {
3146
3243
  detail,
3147
3244
  // C11: the constraint of the package pi LEFT materialised — read at result time, so defer/fail
3148
3245
  // carry the previous payload's declaration (#4973 reconsult ruling).
3149
- compat: readManifestCompat((0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"))
3246
+ compat: readManifestCompat((0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"))
3150
3247
  });
3151
3248
  const before = readPackageSpecs(env);
3152
- if (!before) return result(null, options.target, "defer", `cannot read ${(0, import_node_path12.join)(jervcodeAgentDir(env), "settings.json")}`);
3249
+ if (!before) return result(null, options.target, "defer", `cannot read ${(0, import_node_path13.join)(jervcodeAgentDir(env), "settings.json")}`);
3153
3250
  const from = installedVersion(env);
3154
3251
  const legacy = before.filter(isLegacyMmiPiPath);
3155
3252
  const highWater = journalHighWater(options.paths.journalPath, "jervcode", options.journalEvents);
3156
3253
  const floor = from && compareSemver(from, options.target) > 0 ? `installed ${from} is above candidate ${options.target} (monotonic)` : highWater && compareSemver(highWater, options.target) > 0 ? `journal high-water ${highWater} is above candidate ${options.target} (monotonic)` : null;
3157
3254
  if (options.dryRun) {
3158
3255
  const action = floor ? `hold ${from ?? "the install"} and skip the install (${floor})` : before.includes(exact) && from === options.target ? "keep exact pin" : `install ${exact}`;
3159
- return { surface: "jervcode", from, to: options.target, verdict: "ok", detail: `dry-run: would ${action}${legacy.length ? ` and retire ${legacy.length} legacy claude-cache path registration${legacy.length === 1 ? "" : "s"}` : ""}`, compat: readManifestCompat((0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3256
+ return { surface: "jervcode", from, to: options.target, verdict: "ok", detail: `dry-run: would ${action}${legacy.length ? ` and retire ${legacy.length} legacy claude-cache path registration${legacy.length === 1 ? "" : "s"}` : ""}`, compat: readManifestCompat((0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3160
3257
  }
3161
3258
  const hosted = hostEnv(env);
3162
3259
  const commands = hostCommands(env);
3163
3260
  const command = commands.find((bin) => runner(bin, ["--version"], hosted).status === 0);
3164
- if (!command) return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: "neither `jervcode` nor `pi` answered --version \u2014 the host CLI is not on PATH", compat: readManifestCompat((0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3261
+ if (!command) return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: "neither `jervcode` nor `pi` answered --version \u2014 the host CLI is not on PATH", compat: readManifestCompat((0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3165
3262
  if (!floor && (!before.includes(exact) || from !== options.target)) {
3166
3263
  const install = runner(command, ["install", exact], hosted);
3167
3264
  if (install.status !== 0) {
3168
- return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} install ${exact} failed: ${failure2(install)}`, compat: readManifestCompat((0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3265
+ return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} install ${exact} failed: ${failure2(install)}`, compat: readManifestCompat((0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3169
3266
  }
3170
3267
  }
3171
3268
  for (const stale of legacy) {
3172
3269
  const removed = runner(command, ["remove", stale], hosted);
3173
3270
  if (removed.status !== 0) {
3174
- return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} remove of the legacy registration failed: ${failure2(removed)}`, compat: readManifestCompat((0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3271
+ return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} remove of the legacy registration failed: ${failure2(removed)}`, compat: readManifestCompat((0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3175
3272
  }
3176
3273
  }
3177
3274
  const after = readPackageSpecs(env);
@@ -3179,7 +3276,7 @@ function jervcodeArm(options) {
3179
3276
  const legacyAfter = after?.filter(isLegacyMmiPiPath) ?? [];
3180
3277
  const retired = legacy.length ? `; retired ${legacy.length} legacy claude-cache path registration${legacy.length === 1 ? "" : "s"}` : "";
3181
3278
  if (floor && !legacyAfter.length) {
3182
- return { surface: "jervcode", from, to: converged ?? highWater ?? options.target, verdict: "skip", detail: `${floor}${retired}`, compat: readManifestCompat((0, import_node_path12.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3279
+ return { surface: "jervcode", from, to: converged ?? highWater ?? options.target, verdict: "skip", detail: `${floor}${retired}`, compat: readManifestCompat((0, import_node_path13.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
3183
3280
  }
3184
3281
  if (!after?.includes(exact) || converged !== options.target || legacyAfter.length) {
3185
3282
  return {
@@ -3200,14 +3297,14 @@ function jervcodeArm(options) {
3200
3297
  }
3201
3298
 
3202
3299
  // src/arm-hermes.ts
3203
- var import_node_fs19 = require("node:fs");
3204
- var import_node_path13 = require("node:path");
3300
+ var import_node_fs21 = require("node:fs");
3301
+ var import_node_path14 = require("node:path");
3205
3302
  var PACKAGE2 = "@mutmutco/hermes-plugin";
3206
3303
  var MANIFEST2 = "plugin.yaml";
3207
3304
  var TREE_MARKERS_FALLBACK = [MANIFEST2, "__init__.py", "skills"];
3208
3305
  function yamlVersion(root) {
3209
3306
  try {
3210
- const text = (0, import_node_fs19.readFileSync)((0, import_node_path13.join)(root, MANIFEST2), "utf8");
3307
+ const text = (0, import_node_fs21.readFileSync)((0, import_node_path14.join)(root, MANIFEST2), "utf8");
3211
3308
  try {
3212
3309
  const version = JSON.parse(text).version;
3213
3310
  if (typeof version === "string" && version.trim()) return version.trim();
@@ -3221,7 +3318,7 @@ function yamlVersion(root) {
3221
3318
  }
3222
3319
  function packageTreeMarkers(root) {
3223
3320
  try {
3224
- const files = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path13.join)(root, "package.json"), "utf8")).files;
3321
+ const files = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path14.join)(root, "package.json"), "utf8")).files;
3225
3322
  if (Array.isArray(files) && files.length && files.every((entry) => typeof entry === "string" && entry.trim())) {
3226
3323
  return files.map((entry) => entry.trim());
3227
3324
  }
@@ -3230,10 +3327,10 @@ function packageTreeMarkers(root) {
3230
3327
  return TREE_MARKERS_FALLBACK;
3231
3328
  }
3232
3329
  function markerPresent(root, rel) {
3233
- const path = (0, import_node_path13.join)(root, ...rel.split("/"));
3234
- if (!(0, import_node_fs19.existsSync)(path)) return false;
3330
+ const path = (0, import_node_path14.join)(root, ...rel.split("/"));
3331
+ if (!(0, import_node_fs21.existsSync)(path)) return false;
3235
3332
  try {
3236
- const stat = (0, import_node_fs19.statSync)(path);
3333
+ const stat = (0, import_node_fs21.statSync)(path);
3237
3334
  return stat.isFile() || stat.isDirectory();
3238
3335
  } catch {
3239
3336
  return false;
@@ -3252,13 +3349,13 @@ function treeIncompleteDetail(root, label) {
3252
3349
  }
3253
3350
  function packageIdentity(root) {
3254
3351
  try {
3255
- return JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path13.join)(root, "package.json"), "utf8")).name === PACKAGE2;
3352
+ return JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path14.join)(root, "package.json"), "utf8")).name === PACKAGE2;
3256
3353
  } catch {
3257
3354
  return false;
3258
3355
  }
3259
3356
  }
3260
3357
  function probeHermesInstallation(env = process.env) {
3261
- const location = (0, import_node_path13.join)(hermesHome(env), "plugins", "mmi");
3358
+ const location = (0, import_node_path14.join)(hermesHome(env), "plugins", "mmi");
3262
3359
  const version = yamlVersion(location);
3263
3360
  return { version, location, detail: version ? "installed Hermes plugin manifest" : "installed Hermes plugin manifest was unreadable" };
3264
3361
  }
@@ -3267,7 +3364,7 @@ function mmiOwned2(root) {
3267
3364
  }
3268
3365
  function discard2(path) {
3269
3366
  try {
3270
- (0, import_node_fs19.rmSync)(path, { recursive: true, force: true });
3367
+ (0, import_node_fs21.rmSync)(path, { recursive: true, force: true });
3271
3368
  } catch {
3272
3369
  }
3273
3370
  }
@@ -3275,19 +3372,19 @@ function message2(error) {
3275
3372
  return String(error?.message ?? error).replace(/\s+/g, " ").slice(0, 200);
3276
3373
  }
3277
3374
  function materializeHermesSkills(home) {
3278
- const pluginSkills = (0, import_node_path13.join)(home, "plugins", "mmi", "skills");
3279
- const skillsRoot = (0, import_node_path13.join)(home, "skills");
3280
- const targetRoot = (0, import_node_path13.join)(skillsRoot, "mmi");
3375
+ const pluginSkills = (0, import_node_path14.join)(home, "plugins", "mmi", "skills");
3376
+ const skillsRoot = (0, import_node_path14.join)(home, "skills");
3377
+ const targetRoot = (0, import_node_path14.join)(skillsRoot, "mmi");
3281
3378
  try {
3282
- if (!(0, import_node_fs19.existsSync)(pluginSkills)) return { ok: false, detail: `plugin skills tree missing at ${pluginSkills}` };
3283
- const names = (0, import_node_fs19.readdirSync)(pluginSkills, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name);
3379
+ if (!(0, import_node_fs21.existsSync)(pluginSkills)) return { ok: false, detail: `plugin skills tree missing at ${pluginSkills}` };
3380
+ const names = (0, import_node_fs21.readdirSync)(pluginSkills, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name);
3284
3381
  if (!names.length) return { ok: false, detail: `plugin skills tree is empty at ${pluginSkills}` };
3285
- (0, import_node_fs19.mkdirSync)(skillsRoot, { recursive: true });
3286
- const incoming = (0, import_node_path13.join)(skillsRoot, ".mmi-incoming");
3382
+ (0, import_node_fs21.mkdirSync)(skillsRoot, { recursive: true });
3383
+ const incoming = (0, import_node_path14.join)(skillsRoot, ".mmi-incoming");
3287
3384
  discard2(incoming);
3288
- (0, import_node_fs19.cpSync)(pluginSkills, incoming, { recursive: true });
3385
+ (0, import_node_fs21.cpSync)(pluginSkills, incoming, { recursive: true });
3289
3386
  discard2(targetRoot);
3290
- (0, import_node_fs19.renameSync)(incoming, targetRoot);
3387
+ (0, import_node_fs21.renameSync)(incoming, targetRoot);
3291
3388
  return { ok: true, detail: `provisioned ${names.length} skills to ${targetRoot}` };
3292
3389
  } catch (error) {
3293
3390
  return { ok: false, detail: message2(error) };
@@ -3309,8 +3406,8 @@ function hermesHomes(env = process.env) {
3309
3406
  const root = hermesHome(env);
3310
3407
  const homes = [root];
3311
3408
  try {
3312
- for (const entry of (0, import_node_fs19.readdirSync)((0, import_node_path13.join)(root, "profiles"), { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
3313
- if (entry.isDirectory() && !entry.name.startsWith(".")) homes.push((0, import_node_path13.join)(root, "profiles", entry.name));
3409
+ for (const entry of (0, import_node_fs21.readdirSync)((0, import_node_path14.join)(root, "profiles"), { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
3410
+ if (entry.isDirectory() && !entry.name.startsWith(".")) homes.push((0, import_node_path14.join)(root, "profiles", entry.name));
3314
3411
  }
3315
3412
  } catch {
3316
3413
  }
@@ -3336,29 +3433,32 @@ function hermesArm(options) {
3336
3433
  const primary = results[0].result;
3337
3434
  if (results.length === 1) return primary;
3338
3435
  const worst = results.reduce((a, b) => VERDICT_RANK[b.result.verdict] > VERDICT_RANK[a.result.verdict] ? b : a);
3339
- const detail = results.map(({ home, result }, index) => `${index === 0 ? "home" : `profile ${(0, import_node_path13.basename)(home)}`}: ${result.detail}`).join(" | ");
3436
+ const detail = results.map(({ home, result }, index) => `${index === 0 ? "home" : `profile ${(0, import_node_path14.basename)(home)}`}: ${result.detail}`).join(" | ");
3340
3437
  return {
3341
3438
  surface: "hermes",
3342
3439
  from: primary.from,
3343
3440
  to: primary.to,
3344
3441
  verdict: worst.result.verdict,
3345
3442
  detail: `${homes.length} Hermes homes \u2014 ${detail}`,
3346
- launchStaged: results.some(({ result }) => result.launchStaged) || void 0
3443
+ launchStaged: results.some(({ result }) => result.launchStaged) || void 0,
3444
+ source: primary.source
3347
3445
  };
3348
3446
  }
3349
3447
  function armHermesHome(home, env, options, primary) {
3350
- const parent = (0, import_node_path13.join)(home, "plugins");
3351
- const live = (0, import_node_path13.join)(parent, "mmi");
3448
+ const parent = (0, import_node_path14.join)(home, "plugins");
3449
+ const live = (0, import_node_path14.join)(parent, "mmi");
3352
3450
  const installed = yamlVersion(live);
3451
+ let source;
3353
3452
  const result = (from, to, verdict, detail, launchStaged = false) => ({
3354
3453
  surface: "hermes",
3355
3454
  from,
3356
3455
  to,
3357
3456
  verdict,
3358
3457
  detail,
3359
- launchStaged: launchStaged || void 0
3458
+ launchStaged: launchStaged || void 0,
3459
+ ...source ? { source } : {}
3360
3460
  });
3361
- if ((0, import_node_fs19.existsSync)(live) && !mmiOwned2(live)) {
3461
+ if ((0, import_node_fs21.existsSync)(live) && !mmiOwned2(live)) {
3362
3462
  return result(installed, options.target, "defer", `${live} carries no ${PACKAGE2} package identity \u2014 refusing to displace an unmanaged Hermes mmi plugin`);
3363
3463
  }
3364
3464
  if (installed && compareSemver(installed, options.target) > 0) return result(installed, installed, "skip", `installed ${installed} is above candidate ${options.target} (monotonic)`);
@@ -3372,28 +3472,29 @@ function armHermesHome(home, env, options, primary) {
3372
3472
  if (!enabled2.ok) return result(installed, options.target, "fail", `plugin at target ${options.target}, but ${enabled2.detail}`);
3373
3473
  return result(installed, options.target, "ok", `already at target ${options.target}; ${skills2.detail}; ${enabled2.detail}`);
3374
3474
  }
3375
- if (options.dryRun) return result(installed, options.target, "ok", `dry-run: would stage ${PACKAGE2}@${options.target}, atomically switch ${installed ?? "absent"} -> ${options.target}, provision skills into ${(0, import_node_path13.join)(home, "skills", "mmi")}, then enable mmi in plugins.enabled`);
3376
- const staged = stagePackage({ surface: "hermes", packageName: PACKAGE2, target: options.target, witness: MANIFEST2, paths: options.paths, env });
3475
+ if (options.dryRun) return result(installed, options.target, "ok", `dry-run: would stage ${PACKAGE2}@${options.target}, atomically switch ${installed ?? "absent"} -> ${options.target}, provision skills into ${(0, import_node_path14.join)(home, "skills", "mmi")}, then enable mmi in plugins.enabled`);
3476
+ const staged = stagePackage({ surface: "hermes", packageName: PACKAGE2, target: options.target, witness: MANIFEST2, paths: options.paths, env, payload: options.payload });
3377
3477
  if ("defer" in staged) return result(installed, options.target, "defer", staged.defer);
3478
+ source = staged.source;
3378
3479
  const stagedVersion = yamlVersion(staged.packageRoot);
3379
3480
  if (stagedVersion !== options.target) {
3380
3481
  return result(installed, options.target, "defer", `staged Hermes manifest is ${stagedVersion ?? "unreadable"}, expected ${options.target}`);
3381
3482
  }
3382
3483
  const stagedTree = treeIncompleteDetail(staged.packageRoot, "staged Hermes");
3383
3484
  if (stagedTree) return result(installed, options.target, "defer", stagedTree);
3384
- const scratch = (0, import_node_path13.join)(home, ".mmi-updater");
3385
- const launchTargetPath = (0, import_node_path13.join)(scratch, "launch-target.json");
3386
- const incomingRoot = (0, import_node_path13.join)(scratch, "incoming");
3387
- const incoming = (0, import_node_path13.join)(incomingRoot, options.target);
3388
- const quarantine = (0, import_node_path13.join)(scratch, "quarantine", `${installed ?? "unknown"}-${Date.now()}`);
3485
+ const scratch = (0, import_node_path14.join)(home, ".mmi-updater");
3486
+ const launchTargetPath = (0, import_node_path14.join)(scratch, "launch-target.json");
3487
+ const incomingRoot = (0, import_node_path14.join)(scratch, "incoming");
3488
+ const incoming = (0, import_node_path14.join)(incomingRoot, options.target);
3489
+ const quarantine = (0, import_node_path14.join)(scratch, "quarantine", `${installed ?? "unknown"}-${Date.now()}`);
3389
3490
  const priorLaunch = readLaunchTarget(launchTargetPath);
3390
3491
  const reuseIncoming = priorLaunch?.target === options.target && priorLaunch.incoming === incoming && yamlVersion(incoming) === options.target && treeHealthy2(incoming);
3391
3492
  if (!reuseIncoming) {
3392
3493
  try {
3393
- (0, import_node_fs19.mkdirSync)(parent, { recursive: true });
3394
- (0, import_node_fs19.mkdirSync)((0, import_node_path13.join)(scratch, "quarantine"), { recursive: true });
3494
+ (0, import_node_fs21.mkdirSync)(parent, { recursive: true });
3495
+ (0, import_node_fs21.mkdirSync)((0, import_node_path14.join)(scratch, "quarantine"), { recursive: true });
3395
3496
  discard2(incomingRoot);
3396
- (0, import_node_fs19.cpSync)(staged.packageRoot, incoming, { recursive: true });
3497
+ (0, import_node_fs21.cpSync)(staged.packageRoot, incoming, { recursive: true });
3397
3498
  } catch (error) {
3398
3499
  return result(installed, options.target, "defer", `cannot place incoming Hermes generation: ${message2(error)}`);
3399
3500
  }
@@ -3408,14 +3509,14 @@ function armHermesHome(home, env, options, primary) {
3408
3509
  return result(installed, options.target, "defer", incomingTree);
3409
3510
  }
3410
3511
  }
3411
- const displaced = (0, import_node_fs19.existsSync)(live);
3512
+ const displaced = (0, import_node_fs21.existsSync)(live);
3412
3513
  try {
3413
- (0, import_node_fs19.mkdirSync)((0, import_node_path13.join)(scratch, "quarantine"), { recursive: true });
3414
- if (displaced) (0, import_node_fs19.renameSync)(live, quarantine);
3415
- (0, import_node_fs19.renameSync)(incoming, live);
3514
+ (0, import_node_fs21.mkdirSync)((0, import_node_path14.join)(scratch, "quarantine"), { recursive: true });
3515
+ if (displaced) (0, import_node_fs21.renameSync)(live, quarantine);
3516
+ (0, import_node_fs21.renameSync)(incoming, live);
3416
3517
  } catch (error) {
3417
- if (displaced && !(0, import_node_fs19.existsSync)(live)) try {
3418
- (0, import_node_fs19.renameSync)(quarantine, live);
3518
+ if (displaced && !(0, import_node_fs21.existsSync)(live)) try {
3519
+ (0, import_node_fs21.renameSync)(quarantine, live);
3419
3520
  } catch {
3420
3521
  }
3421
3522
  discard2(incomingRoot);
@@ -3426,12 +3527,12 @@ function armHermesHome(home, env, options, primary) {
3426
3527
  const liveVersion = yamlVersion(live);
3427
3528
  const liveTree = treeIncompleteDetail(live, "live Hermes");
3428
3529
  if (liveVersion !== options.target || liveTree) {
3429
- const broken = (0, import_node_path13.join)(scratch, "rejected", `${options.target}-${Date.now()}`);
3530
+ const broken = (0, import_node_path14.join)(scratch, "rejected", `${options.target}-${Date.now()}`);
3430
3531
  const verifyDetail = liveVersion !== options.target ? `manifest is ${liveVersion ?? "unreadable"}, expected ${options.target}` : liveTree;
3431
3532
  try {
3432
- (0, import_node_fs19.mkdirSync)((0, import_node_path13.join)(scratch, "rejected"), { recursive: true });
3433
- (0, import_node_fs19.renameSync)(live, broken);
3434
- if (displaced) (0, import_node_fs19.renameSync)(quarantine, live);
3533
+ (0, import_node_fs21.mkdirSync)((0, import_node_path14.join)(scratch, "rejected"), { recursive: true });
3534
+ (0, import_node_fs21.renameSync)(live, broken);
3535
+ if (displaced) (0, import_node_fs21.renameSync)(quarantine, live);
3435
3536
  } catch (error) {
3436
3537
  return result(installed, liveVersion ?? "unknown", "fail", `post-switch Hermes verification failed and recovery failed: ${message2(error)}`);
3437
3538
  }
@@ -3446,12 +3547,199 @@ function armHermesHome(home, env, options, primary) {
3446
3547
  return result(installed, options.target, "ok", `converged ${installed ?? "absent"} -> ${options.target} (staged, verified, switched${displaced ? `; previous generation quarantined at ${quarantine}` : ""}); ${skills.detail}; ${enabled.detail}`);
3447
3548
  }
3448
3549
  function probeHermesLaunchStaging(env = process.env) {
3449
- return probeLaunchTargetVersion((0, import_node_path13.join)(hermesHome(env), ".mmi-updater", "launch-target.json"), yamlVersion);
3550
+ return probeLaunchTargetVersion((0, import_node_path14.join)(hermesHome(env), ".mmi-updater", "launch-target.json"), yamlVersion);
3551
+ }
3552
+
3553
+ // src/payload-source.ts
3554
+ var import_node_fs22 = require("node:fs");
3555
+ var import_node_path15 = require("node:path");
3556
+
3557
+ // ../installer/launcher/src/login-github.ts
3558
+ async function postJson(url, body, fetchImpl) {
3559
+ return fetchImpl(url, {
3560
+ method: "POST",
3561
+ headers: { "content-type": "application/json" },
3562
+ body: JSON.stringify(body)
3563
+ });
3564
+ }
3565
+ async function readBody(response) {
3566
+ try {
3567
+ return await response.text();
3568
+ } catch {
3569
+ return "";
3570
+ }
3571
+ }
3572
+ function gateRefusal(method, url, status, body) {
3573
+ const head = body.replace(/\s+/g, " ").trim().slice(0, 200);
3574
+ return `the sign-in server refused the request \u2014 ${method} ${url} \u2192 ${status}${head ? `: ${head}` : ""}`;
3575
+ }
3576
+ async function refreshAccessToken(config, refreshToken, fetchImpl = fetch) {
3577
+ const url = `${config.host}/gate/refresh`;
3578
+ const response = await postJson(url, { refresh_token: refreshToken }, fetchImpl);
3579
+ if (response.status === 403) return null;
3580
+ if (!response.ok) {
3581
+ throw new Error(gateRefusal("POST", url, response.status, await readBody(response)));
3582
+ }
3583
+ const data = await response.json();
3584
+ if (typeof data.access_token !== "string" || typeof data.expires_in !== "number") {
3585
+ throw new Error("the sign-in server returned a malformed refresh");
3586
+ }
3587
+ return {
3588
+ accessToken: data.access_token,
3589
+ expiresIn: data.expires_in,
3590
+ ...typeof data.refresh_token === "string" ? { refreshToken: data.refresh_token } : {}
3591
+ };
3592
+ }
3593
+
3594
+ // ../installer/launcher/src/login-google.ts
3595
+ async function refreshGoogleToken(host, clientId, refreshToken, fetchImpl = fetch) {
3596
+ const server = host.replace(/\/+$/, "");
3597
+ const response = await fetchImpl(`${server}/oauth/token`, {
3598
+ method: "POST",
3599
+ headers: { "content-type": "application/x-www-form-urlencoded" },
3600
+ body: new URLSearchParams({
3601
+ grant_type: "refresh_token",
3602
+ refresh_token: refreshToken,
3603
+ client_id: clientId
3604
+ }).toString()
3605
+ });
3606
+ if (!response.ok) return null;
3607
+ const tokens = await response.json();
3608
+ if (typeof tokens.access_token !== "string" || typeof tokens.expires_in !== "number") return null;
3609
+ return {
3610
+ accessToken: tokens.access_token,
3611
+ refreshToken: typeof tokens.refresh_token === "string" ? tokens.refresh_token : refreshToken,
3612
+ expiresIn: tokens.expires_in
3613
+ };
3614
+ }
3615
+
3616
+ // ../installer/launcher/src/tokens.ts
3617
+ async function ensureFreshToken(config, dir, fetchImpl = fetch) {
3618
+ const stored = readTokens(dir);
3619
+ if (!stored) return null;
3620
+ if (stored.expiresAt - Date.now() > 6e4) return stored.accessToken;
3621
+ if (!stored.refreshToken) return null;
3622
+ if (config.loginKind === "github") {
3623
+ const refreshed2 = await refreshAccessToken(config, stored.refreshToken, fetchImpl);
3624
+ if (!refreshed2) {
3625
+ clearTokens(dir);
3626
+ return null;
3627
+ }
3628
+ writeTokens(dir, {
3629
+ accessToken: refreshed2.accessToken,
3630
+ refreshToken: refreshed2.refreshToken ?? stored.refreshToken,
3631
+ expiresAt: Date.now() + refreshed2.expiresIn * 1e3
3632
+ });
3633
+ return refreshed2.accessToken;
3634
+ }
3635
+ if (!stored.clientId) {
3636
+ clearTokens(dir);
3637
+ return null;
3638
+ }
3639
+ const refreshed = await refreshGoogleToken(config.host, stored.clientId, stored.refreshToken, fetchImpl);
3640
+ if (!refreshed) {
3641
+ clearTokens(dir);
3642
+ return null;
3643
+ }
3644
+ writeTokens(dir, {
3645
+ accessToken: refreshed.accessToken,
3646
+ refreshToken: refreshed.refreshToken,
3647
+ expiresAt: Date.now() + refreshed.expiresIn * 1e3,
3648
+ clientId: stored.clientId
3649
+ });
3650
+ return refreshed.accessToken;
3651
+ }
3652
+
3653
+ // src/payload-source.ts
3654
+ var PayloadIntegrityError = class extends Error {
3655
+ };
3656
+ function tarballName(name, version) {
3657
+ return `${name.replace("@", "").replace("/", "-")}-${version}.tgz`;
3658
+ }
3659
+ var mmiConfig = {
3660
+ product: installer_product_default.launcher.product,
3661
+ host: installer_product_default.launcher.host,
3662
+ publicKey: installer_product_default.launcher.key,
3663
+ binName: installer_product_default.launcher.bin,
3664
+ loginKind: "github"
3665
+ };
3666
+ async function resolvePayloadTarball(options) {
3667
+ const { packageName, version, paths } = options;
3668
+ if (!/^\d+\.\d+\.\d+[A-Za-z0-9._-]*$/.test(version)) return null;
3669
+ const file = tarballName(packageName, version);
3670
+ const dir = options.productDir ?? (process.env.LAUNCHER_DIR || defaultProductDir("mmi"));
3671
+ const launcherCache = cachedPayloadForVersion(dir, version);
3672
+ if (launcherCache) {
3673
+ try {
3674
+ const metadata = JSON.parse((0, import_node_fs22.readFileSync)((0, import_node_path15.join)(launcherCache, "payload.json"), "utf8"));
3675
+ if (metadata.version === version && (0, import_node_fs22.existsSync)((0, import_node_path15.join)(launcherCache, file))) return (0, import_node_path15.join)(launcherCache, file);
3676
+ } catch {
3677
+ }
3678
+ }
3679
+ const config = options.config ?? mmiConfig;
3680
+ const cache = (0, import_node_path15.join)(paths.root, "payload-cache", version);
3681
+ const manifestFile = (0, import_node_path15.join)(cache, "manifest.json");
3682
+ let manifest2 = null;
3683
+ try {
3684
+ manifest2 = parseManifest(JSON.parse((0, import_node_fs22.readFileSync)(manifestFile, "utf8")));
3685
+ if (!verifyManifest(manifest2, manifest2.signature, config)) throw new PayloadIntegrityError("cached release manifest signature is invalid");
3686
+ if (manifest2.version !== version) throw new PayloadIntegrityError("cached release manifest version is wrong");
3687
+ } catch (error) {
3688
+ if (error instanceof PayloadIntegrityError) throw error;
3689
+ if ((0, import_node_fs22.existsSync)(manifestFile)) throw new PayloadIntegrityError("cached release manifest is malformed");
3690
+ manifest2 = null;
3691
+ }
3692
+ const cachedEntry = manifest2?.files.find((entry2) => entry2.path === file);
3693
+ if (cachedEntry && (0, import_node_fs22.existsSync)((0, import_node_path15.join)(cache, file))) {
3694
+ if (!verifyFileBytes(cachedEntry, (0, import_node_fs22.readFileSync)((0, import_node_path15.join)(cache, file)))) throw new PayloadIntegrityError(`cached ${file} failed its checksum`);
3695
+ return (0, import_node_path15.join)(cache, file);
3696
+ }
3697
+ if (!(0, import_node_fs22.existsSync)(dir)) return null;
3698
+ let token;
3699
+ try {
3700
+ token = await ensureFreshToken(config, dir, options.fetchImpl);
3701
+ } catch {
3702
+ return null;
3703
+ }
3704
+ if (!token) return null;
3705
+ const fetchImpl = options.fetchImpl ?? fetch;
3706
+ try {
3707
+ manifest2 = await fetchVerifiedManifest(config, token, (url, init) => fetchImpl(url, { ...init, signal: AbortSignal.timeout(1e4) }));
3708
+ } catch (error) {
3709
+ if (error instanceof NeedsLoginError || error instanceof ForbiddenError || error instanceof TypeError || error.name === "AbortError") return null;
3710
+ if (String(error.message).startsWith("the release server refused")) return null;
3711
+ throw new PayloadIntegrityError(`release manifest verification failed: ${error.message}`);
3712
+ }
3713
+ if (manifest2.version !== version) return null;
3714
+ const entry = manifest2.files.find((candidate) => candidate.path === file);
3715
+ if (!entry) return null;
3716
+ let bytes;
3717
+ try {
3718
+ const encoded = entry.path.split("/").map(encodeURIComponent).join("/");
3719
+ const response = await fetchImpl(`${config.host}/release/${encoded}`, { headers: { authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(3e5) });
3720
+ if (!response.ok) return null;
3721
+ bytes = Buffer.from(await response.arrayBuffer());
3722
+ } catch {
3723
+ return null;
3724
+ }
3725
+ if (!verifyFileBytes(entry, bytes)) throw new PayloadIntegrityError(`${file} failed its checksum`);
3726
+ (0, import_node_fs22.mkdirSync)(cache, { recursive: true });
3727
+ const temporary = (0, import_node_path15.join)(cache, `${file}.${process.pid}.tmp`);
3728
+ try {
3729
+ (0, import_node_fs22.writeFileSync)(temporary, bytes);
3730
+ (0, import_node_fs22.renameSync)(temporary, (0, import_node_path15.join)(cache, file));
3731
+ const signed = `${manifestFile}.${process.pid}.tmp`;
3732
+ (0, import_node_fs22.writeFileSync)(signed, JSON.stringify(manifest2));
3733
+ (0, import_node_fs22.renameSync)(signed, manifestFile);
3734
+ } finally {
3735
+ (0, import_node_fs22.rmSync)(temporary, { force: true });
3736
+ }
3737
+ return (0, import_node_path15.join)(cache, file);
3450
3738
  }
3451
3739
 
3452
3740
  // src/reap.ts
3453
- var import_node_fs20 = require("node:fs");
3454
- var import_node_path14 = require("node:path");
3741
+ var import_node_fs23 = require("node:fs");
3742
+ var import_node_path16 = require("node:path");
3455
3743
  var import_node_perf_hooks = require("node:perf_hooks");
3456
3744
  function elapsedMs(startedAt) {
3457
3745
  return Math.round((import_node_perf_hooks.performance.now() - startedAt) * 10) / 10;
@@ -3460,7 +3748,7 @@ var KEEP_GENERATIONS2 = 2;
3460
3748
  var SCRATCH_AGE_MS = 24 * 60 * 6e4;
3461
3749
  function listDirs(path) {
3462
3750
  try {
3463
- return (0, import_node_fs20.readdirSync)(path, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
3751
+ return (0, import_node_fs23.readdirSync)(path, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
3464
3752
  } catch {
3465
3753
  return [];
3466
3754
  }
@@ -3468,7 +3756,7 @@ function listDirs(path) {
3468
3756
  function generationSets(root) {
3469
3757
  const children = listDirs(root);
3470
3758
  if (children.some((name) => parseSemver(name))) return [root];
3471
- return children.map((name) => (0, import_node_path14.join)(root, name)).filter((path) => listDirs(path).some((name) => parseSemver(name)));
3759
+ return children.map((name) => (0, import_node_path16.join)(root, name)).filter((path) => listDirs(path).some((name) => parseSemver(name)));
3472
3760
  }
3473
3761
  function pruneGenerations(root, category, dryRun) {
3474
3762
  let reaped = 0;
@@ -3481,7 +3769,7 @@ function pruneGenerations(root, category, dryRun) {
3481
3769
  continue;
3482
3770
  }
3483
3771
  try {
3484
- (0, import_node_fs20.rmSync)((0, import_node_path14.join)(set, version), { recursive: true, force: true });
3772
+ (0, import_node_fs23.rmSync)((0, import_node_path16.join)(set, version), { recursive: true, force: true });
3485
3773
  reaped += 1;
3486
3774
  } catch (error) {
3487
3775
  failures.push(`${version}: ${error?.code ?? error?.message ?? error}`);
@@ -3495,8 +3783,8 @@ function pruneGenerations(root, category, dryRun) {
3495
3783
  }
3496
3784
  var LEASE_STEAL_SCRATCH = /^lease\.lock\.stale-\d+$/;
3497
3785
  function atomicWriteScratch(path) {
3498
- const literal = (0, import_node_path14.basename)(path).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3499
- return { dir: (0, import_node_path14.dirname)(path), pattern: new RegExp(`^${literal}\\.tmp-\\d+$`) };
3786
+ const literal = (0, import_node_path16.basename)(path).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3787
+ return { dir: (0, import_node_path16.dirname)(path), pattern: new RegExp(`^${literal}\\.tmp-\\d+$`) };
3500
3788
  }
3501
3789
  function reapScratch(context, dryRun) {
3502
3790
  const category = "scratch";
@@ -3514,7 +3802,7 @@ function reapScratch(context, dryRun) {
3514
3802
  for (const [dir, patterns] of scanned) {
3515
3803
  let entries;
3516
3804
  try {
3517
- entries = (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true });
3805
+ entries = (0, import_node_fs23.readdirSync)(dir, { withFileTypes: true });
3518
3806
  } catch {
3519
3807
  unreadable.push(dir);
3520
3808
  continue;
@@ -3522,10 +3810,10 @@ function reapScratch(context, dryRun) {
3522
3810
  for (const entry of entries) {
3523
3811
  if (!patterns.some((pattern) => pattern.test(entry.name))) continue;
3524
3812
  if (!entry.isFile()) continue;
3525
- const path = (0, import_node_path14.join)(dir, entry.name);
3813
+ const path = (0, import_node_path16.join)(dir, entry.name);
3526
3814
  let ageMs;
3527
3815
  try {
3528
- ageMs = now - (0, import_node_fs20.statSync)(path).mtimeMs;
3816
+ ageMs = now - (0, import_node_fs23.statSync)(path).mtimeMs;
3529
3817
  } catch {
3530
3818
  continue;
3531
3819
  }
@@ -3535,7 +3823,7 @@ function reapScratch(context, dryRun) {
3535
3823
  continue;
3536
3824
  }
3537
3825
  try {
3538
- (0, import_node_fs20.rmSync)(path, { force: true });
3826
+ (0, import_node_fs23.rmSync)(path, { force: true });
3539
3827
  reaped += 1;
3540
3828
  } catch (error) {
3541
3829
  failures.push(`${entry.name}: ${error?.code ?? error?.message ?? error}`);
@@ -3594,7 +3882,8 @@ async function reconcile(options) {
3594
3882
  const summary = { run, target: null, gate: null, managedSurfaces: null, atomicity: null, cli: null, updater: null, plugins: [], reap: [], surfaces: [], journalOk: true, reexec: null, exit: 0 };
3595
3883
  const recordArm = (arm, durationMs) => {
3596
3884
  if (arm.verdict === "fail") arm.repeatFailure = journalSurfaceRepeatedFail(paths.journalPath, arm.surface, run);
3597
- journal({ kind: "arm", surface: arm.surface, from: arm.from, to: arm.to, verdict: arm.verdict, detail: arm.detail, compat: arm.compat, durationMs });
3885
+ if (arm.source && !arm.detail.includes(`source: ${arm.source}`)) arm.detail += ` (source: ${arm.source})`;
3886
+ journal({ kind: "arm", surface: arm.surface, from: arm.from, to: arm.to, verdict: arm.verdict, detail: arm.detail, source: arm.source, compat: arm.compat, durationMs });
3598
3887
  options.onArm?.({ ...arm, ...durationMs === void 0 ? {} : { durationMs } });
3599
3888
  if (arm.verdict === "ok" && !options.dryRun && !arm.launchStaged) clearPending(paths, arm.surface);
3600
3889
  if (arm.verdict === "defer") summary.exit = Math.max(summary.exit, 2);
@@ -3679,10 +3968,20 @@ async function reconcile(options) {
3679
3968
  phase("resolve", "ok");
3680
3969
  options.onTargetResolved?.(summary.target, summary.gate);
3681
3970
  phase("check", "running");
3971
+ const payloadFor = async (packageName) => {
3972
+ if (options.dryRun) return null;
3973
+ try {
3974
+ return await resolvePayloadTarball({ packageName, version: summary.target, paths });
3975
+ } catch (error) {
3976
+ if (error instanceof PayloadIntegrityError) return { defer: `payload integrity refusal: ${error.message}` };
3977
+ return null;
3978
+ }
3979
+ };
3682
3980
  say("updater: self-bootstrap");
3683
3981
  const selfStartedAt = import_node_perf_hooks2.performance.now();
3684
3982
  const self = npmGlobalArm({
3685
3983
  surface: "updater",
3984
+ payload: await payloadFor("@mutmutco/hub"),
3686
3985
  packageName: "@mutmutco/hub",
3687
3986
  distRel: "dist/index.cjs",
3688
3987
  target: summary.target,
@@ -3705,6 +4004,7 @@ async function reconcile(options) {
3705
4004
  const cliStartedAt = import_node_perf_hooks2.performance.now();
3706
4005
  const cli = npmGlobalArm({
3707
4006
  surface: "cli",
4007
+ payload: await payloadFor("@mutmutco/cli"),
3708
4008
  packageName: "@mutmutco/cli",
3709
4009
  distRel: "dist/index.cjs",
3710
4010
  target: summary.target,
@@ -3730,7 +4030,9 @@ async function reconcile(options) {
3730
4030
  }
3731
4031
  say(`${probe.id}: converging to v${summary.target}`);
3732
4032
  const armStartedAt = import_node_perf_hooks2.performance.now();
3733
- const arm = probe.id === "claude" ? claudeArm({ target: summary.target, dryRun: options.dryRun, paths, env, repoUrl, journalEvents }) : probe.id === "codex" ? codexArm({ target: summary.target, dryRun: options.dryRun, env, repoUrl }) : probe.id === "cursor" ? cursorArm({ target: summary.target, dryRun: options.dryRun, paths, env, journalEvents }) : probe.id === "jervcode" ? jervcodeArm({ target: summary.target, dryRun: options.dryRun, paths, env, journalEvents }) : probe.id === "hermes" ? hermesArm({ target: summary.target, dryRun: options.dryRun, paths, env, hostPresent: probe.present, journalEvents }) : null;
4033
+ const packageName = probe.id === "claude" ? "@mutmutco/claude-plugin" : probe.id === "cursor" ? "@mutmutco/cursor-plugin" : probe.id === "hermes" ? "@mutmutco/hermes-plugin" : null;
4034
+ const payload = packageName ? await payloadFor(packageName) : null;
4035
+ const arm = probe.id === "claude" ? claudeArm({ target: summary.target, dryRun: options.dryRun, paths, env, repoUrl, journalEvents, payload }) : probe.id === "codex" ? codexArm({ target: summary.target, dryRun: options.dryRun, env, repoUrl }) : probe.id === "cursor" ? cursorArm({ target: summary.target, dryRun: options.dryRun, paths, env, journalEvents, payload }) : probe.id === "jervcode" ? jervcodeArm({ target: summary.target, dryRun: options.dryRun, paths, env, journalEvents }) : probe.id === "hermes" ? hermesArm({ target: summary.target, dryRun: options.dryRun, paths, env, hostPresent: probe.present, journalEvents, payload }) : null;
3734
4036
  if (arm) {
3735
4037
  summary.plugins.push(arm);
3736
4038
  summary.surfaces.push({ id: probe.id, present: true, action: `arm-${arm.verdict}` });
@@ -3766,9 +4068,9 @@ async function reconcile(options) {
3766
4068
 
3767
4069
  // src/scheduler.ts
3768
4070
  var import_node_child_process8 = require("node:child_process");
3769
- var import_node_fs21 = require("node:fs");
4071
+ var import_node_fs24 = require("node:fs");
3770
4072
  var import_node_os8 = require("node:os");
3771
- var import_node_path15 = require("node:path");
4073
+ var import_node_path17 = require("node:path");
3772
4074
  var TASK_NAME = "MMI Fleet Updater";
3773
4075
  var LAUNCHER_FILE = "reconcile-hidden.vbs";
3774
4076
  var RUN_BOUND = "PT15M";
@@ -3926,7 +4228,7 @@ WantedBy=timers.target
3926
4228
  }
3927
4229
  function readFileOrNull(path) {
3928
4230
  try {
3929
- return (0, import_node_fs21.readFileSync)(path, "utf8");
4231
+ return (0, import_node_fs24.readFileSync)(path, "utf8");
3930
4232
  } catch {
3931
4233
  return null;
3932
4234
  }
@@ -3975,7 +4277,7 @@ function windowsSchedulerStatus(env) {
3975
4277
  return { ok: false, supported: true, enabled: false, ...EMPTY_RUN_INFO, detail: `"${TASK_NAME}" is not registered \u2014 run \`mmi-hub autoupdate on\`` };
3976
4278
  }
3977
4279
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
3978
- const launcherPath = (0, import_node_path15.join)(statePaths(env).root, LAUNCHER_FILE);
4280
+ const launcherPath = (0, import_node_path17.join)(statePaths(env).root, LAUNCHER_FILE);
3979
4281
  const info = taskRunInfo();
3980
4282
  const runInfo = info ?? EMPTY_RUN_INFO;
3981
4283
  const fail2 = (detail) => ({ ok: false, supported: true, enabled: true, ...runInfo, detail });
@@ -4000,13 +4302,13 @@ function windowsSchedulerStatus(env) {
4000
4302
  return { ok: true, supported: true, enabled: true, ...runInfo, detail: `"${TASK_NAME}" registered ${CADENCE}; ${points}; ${ran}; next ${runInfo.nextRunTime ?? "unscheduled"}` };
4001
4303
  }
4002
4304
  function darwinSchedulerStatus(env) {
4003
- const plistPath = (0, import_node_path15.join)((0, import_node_os8.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
4305
+ const plistPath = (0, import_node_path17.join)((0, import_node_os8.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
4004
4306
  const plist = readFileOrNull(plistPath);
4005
4307
  if (!plist) {
4006
4308
  return { ok: false, supported: true, enabled: false, ...EMPTY_RUN_INFO, detail: `"${LAUNCHD_LABEL}" is not registered \u2014 run \`mmi-hub autoupdate on\`` };
4007
4309
  }
4008
4310
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
4009
- const launcherPath = (0, import_node_path15.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
4311
+ const launcherPath = (0, import_node_path17.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
4010
4312
  const fail2 = (detail) => ({ ok: false, supported: true, enabled: true, ...EMPTY_RUN_INFO, detail });
4011
4313
  if (!plist.includes(launcherPath)) {
4012
4314
  return fail2(`"${LAUNCHD_LABEL}" does not run the reconcile launcher ${launcherPath} \u2014 run \`mmi-hub autoupdate on\``);
@@ -4026,15 +4328,15 @@ function darwinSchedulerStatus(env) {
4026
4328
  return { ok: true, supported: true, enabled: true, ...EMPTY_RUN_INFO, detail: `"${LAUNCHD_LABEL}" registered ${POSIX_CADENCE}; ${points}` };
4027
4329
  }
4028
4330
  function linuxSchedulerStatus(env) {
4029
- const unitDir = (0, import_node_path15.join)((0, import_node_os8.homedir)(), ".config", "systemd", "user");
4030
- const timerPath = (0, import_node_path15.join)(unitDir, SYSTEMD_TIMER_NAME);
4331
+ const unitDir = (0, import_node_path17.join)((0, import_node_os8.homedir)(), ".config", "systemd", "user");
4332
+ const timerPath = (0, import_node_path17.join)(unitDir, SYSTEMD_TIMER_NAME);
4031
4333
  const timer = readFileOrNull(timerPath);
4032
- const service = readFileOrNull((0, import_node_path15.join)(unitDir, SYSTEMD_SERVICE_NAME));
4334
+ const service = readFileOrNull((0, import_node_path17.join)(unitDir, SYSTEMD_SERVICE_NAME));
4033
4335
  if (!timer || !service) {
4034
4336
  return { ok: false, supported: true, enabled: false, ...EMPTY_RUN_INFO, detail: `"${SYSTEMD_TIMER_NAME}" is not registered \u2014 run \`mmi-hub autoupdate on\`` };
4035
4337
  }
4036
4338
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
4037
- const launcherPath = (0, import_node_path15.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
4339
+ const launcherPath = (0, import_node_path17.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
4038
4340
  const fail2 = (detail) => ({ ok: false, supported: true, enabled: true, ...EMPTY_RUN_INFO, detail });
4039
4341
  if (!service.includes(launcherPath)) {
4040
4342
  return fail2(`"${SYSTEMD_SERVICE_NAME}" does not run the reconcile launcher ${launcherPath} \u2014 run \`mmi-hub autoupdate on\``);
@@ -4073,10 +4375,10 @@ function installWindowsTask(env) {
4073
4375
  const paths = ensureState(env);
4074
4376
  const userId = `${env.USERDOMAIN || env.COMPUTERNAME || ""}\\${env.USERNAME || ""}`.replace(/^\\/, "");
4075
4377
  if (!env.USERNAME) return { ok: false, detail: "cannot resolve the registering user (USERNAME unset) \u2014 the task principal must be explicit" };
4076
- const launcherPath = (0, import_node_path15.join)(paths.root, LAUNCHER_FILE);
4077
- (0, import_node_fs21.writeFileSync)(launcherPath, launcherVbs(process.execPath, hubDist), "utf8");
4078
- const xmlPath = (0, import_node_path15.join)(paths.root, "task.xml");
4079
- (0, import_node_fs21.writeFileSync)(xmlPath, "\uFEFF" + taskXml(launcherPath, paths.root, userId, localStartBoundary(/* @__PURE__ */ new Date())), "utf16le");
4378
+ const launcherPath = (0, import_node_path17.join)(paths.root, LAUNCHER_FILE);
4379
+ (0, import_node_fs24.writeFileSync)(launcherPath, launcherVbs(process.execPath, hubDist), "utf8");
4380
+ const xmlPath = (0, import_node_path17.join)(paths.root, "task.xml");
4381
+ (0, import_node_fs24.writeFileSync)(xmlPath, "\uFEFF" + taskXml(launcherPath, paths.root, userId, localStartBoundary(/* @__PURE__ */ new Date())), "utf16le");
4080
4382
  const create = schtasks(["/create", "/tn", TASK_NAME, "/xml", xmlPath, "/f"]);
4081
4383
  if (create.status !== 0) {
4082
4384
  const denied = /access is denied/i.test(create.stderr + create.stdout);
@@ -4092,11 +4394,11 @@ function refreshPosixLauncher(env) {
4092
4394
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
4093
4395
  if (!hubDist) return null;
4094
4396
  const paths = ensureState(env);
4095
- const launcherPath = (0, import_node_path15.join)(paths.root, POSIX_LAUNCHER_FILE);
4397
+ const launcherPath = (0, import_node_path17.join)(paths.root, POSIX_LAUNCHER_FILE);
4096
4398
  const desired = launcherSh(process.execPath, hubDist);
4097
4399
  if (readFileOrNull(launcherPath) === desired) return null;
4098
- (0, import_node_fs21.writeFileSync)(launcherPath, desired, "utf8");
4099
- (0, import_node_fs21.chmodSync)(launcherPath, 493);
4400
+ (0, import_node_fs24.writeFileSync)(launcherPath, desired, "utf8");
4401
+ (0, import_node_fs24.chmodSync)(launcherPath, 493);
4100
4402
  return launcherPath;
4101
4403
  }
4102
4404
  function installLaunchd(env) {
@@ -4108,13 +4410,13 @@ function installLaunchd(env) {
4108
4410
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
4109
4411
  if (!hubDist) return { ok: false, detail: "cannot resolve the global @mutmutco/hub dist \u2014 run `npm install -g @mutmutco/hub` first" };
4110
4412
  const paths = ensureState(env);
4111
- const launcherPath = (0, import_node_path15.join)(paths.root, POSIX_LAUNCHER_FILE);
4112
- (0, import_node_fs21.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
4113
- (0, import_node_fs21.chmodSync)(launcherPath, 493);
4114
- const agentsDir = (0, import_node_path15.join)((0, import_node_os8.homedir)(), "Library", "LaunchAgents");
4115
- (0, import_node_fs21.mkdirSync)(agentsDir, { recursive: true });
4116
- const plistPath = (0, import_node_path15.join)(agentsDir, LAUNCHD_PLIST_NAME);
4117
- (0, import_node_fs21.writeFileSync)(plistPath, launchdPlist(launcherPath, paths.root), "utf8");
4413
+ const launcherPath = (0, import_node_path17.join)(paths.root, POSIX_LAUNCHER_FILE);
4414
+ (0, import_node_fs24.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
4415
+ (0, import_node_fs24.chmodSync)(launcherPath, 493);
4416
+ const agentsDir = (0, import_node_path17.join)((0, import_node_os8.homedir)(), "Library", "LaunchAgents");
4417
+ (0, import_node_fs24.mkdirSync)(agentsDir, { recursive: true });
4418
+ const plistPath = (0, import_node_path17.join)(agentsDir, LAUNCHD_PLIST_NAME);
4419
+ (0, import_node_fs24.writeFileSync)(plistPath, launchdPlist(launcherPath, paths.root), "utf8");
4118
4420
  launchctl(["bootout", `gui/${uid()}/${LAUNCHD_LABEL}`]);
4119
4421
  const load = launchctl(["bootstrap", `gui/${uid()}`, plistPath]);
4120
4422
  if (load.status !== 0) {
@@ -4132,13 +4434,13 @@ function installSystemdTimer(env) {
4132
4434
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
4133
4435
  if (!hubDist) return { ok: false, detail: "cannot resolve the global @mutmutco/hub dist \u2014 run `npm install -g @mutmutco/hub` first" };
4134
4436
  const paths = ensureState(env);
4135
- const launcherPath = (0, import_node_path15.join)(paths.root, POSIX_LAUNCHER_FILE);
4136
- (0, import_node_fs21.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
4137
- (0, import_node_fs21.chmodSync)(launcherPath, 493);
4138
- const unitDir = (0, import_node_path15.join)((0, import_node_os8.homedir)(), ".config", "systemd", "user");
4139
- (0, import_node_fs21.mkdirSync)(unitDir, { recursive: true });
4140
- (0, import_node_fs21.writeFileSync)((0, import_node_path15.join)(unitDir, SYSTEMD_SERVICE_NAME), systemdServiceUnit(launcherPath, paths.root), "utf8");
4141
- (0, import_node_fs21.writeFileSync)((0, import_node_path15.join)(unitDir, SYSTEMD_TIMER_NAME), systemdTimerUnit(), "utf8");
4437
+ const launcherPath = (0, import_node_path17.join)(paths.root, POSIX_LAUNCHER_FILE);
4438
+ (0, import_node_fs24.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
4439
+ (0, import_node_fs24.chmodSync)(launcherPath, 493);
4440
+ const unitDir = (0, import_node_path17.join)((0, import_node_os8.homedir)(), ".config", "systemd", "user");
4441
+ (0, import_node_fs24.mkdirSync)(unitDir, { recursive: true });
4442
+ (0, import_node_fs24.writeFileSync)((0, import_node_path17.join)(unitDir, SYSTEMD_SERVICE_NAME), systemdServiceUnit(launcherPath, paths.root), "utf8");
4443
+ (0, import_node_fs24.writeFileSync)((0, import_node_path17.join)(unitDir, SYSTEMD_TIMER_NAME), systemdTimerUnit(), "utf8");
4142
4444
  const reload = systemctlUser(["daemon-reload"]);
4143
4445
  if (reload.status !== 0) {
4144
4446
  return { ok: false, detail: `systemctl --user daemon-reload failed: ${(reload.stderr || reload.stdout).trim() || "unknown error \u2014 is a user systemd instance running?"}` };
@@ -4176,28 +4478,28 @@ function uninstallWindowsTask(env) {
4176
4478
  return { ok: true, detail: `automatic updates off \u2014 removed "${TASK_NAME}"; installed tooling was kept` };
4177
4479
  }
4178
4480
  function uninstallLaunchd(env) {
4179
- const plistPath = (0, import_node_path15.join)((0, import_node_os8.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
4481
+ const plistPath = (0, import_node_path17.join)((0, import_node_os8.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
4180
4482
  const boot = launchctl(["bootout", `gui/${uid()}/${LAUNCHD_LABEL}`]);
4181
- if (boot.status !== 0 && (0, import_node_fs21.existsSync)(plistPath)) {
4483
+ if (boot.status !== 0 && (0, import_node_fs24.existsSync)(plistPath)) {
4182
4484
  return { ok: false, detail: `launchctl bootout failed: ${(boot.stderr || boot.stdout).trim() || "unknown error"}` };
4183
4485
  }
4184
4486
  try {
4185
- (0, import_node_fs21.rmSync)(plistPath, { force: true });
4487
+ (0, import_node_fs24.rmSync)(plistPath, { force: true });
4186
4488
  } catch {
4187
4489
  }
4188
4490
  dropLauncher(env, POSIX_LAUNCHER_FILE);
4189
4491
  return { ok: true, detail: `automatic updates off \u2014 removed "${LAUNCHD_LABEL}"; installed tooling was kept` };
4190
4492
  }
4191
4493
  function uninstallSystemdTimer(env) {
4192
- const unitDir = (0, import_node_path15.join)((0, import_node_os8.homedir)(), ".config", "systemd", "user");
4193
- const timerPath = (0, import_node_path15.join)(unitDir, SYSTEMD_TIMER_NAME);
4494
+ const unitDir = (0, import_node_path17.join)((0, import_node_os8.homedir)(), ".config", "systemd", "user");
4495
+ const timerPath = (0, import_node_path17.join)(unitDir, SYSTEMD_TIMER_NAME);
4194
4496
  const disable = systemctlUser(["disable", "--now", SYSTEMD_TIMER_NAME]);
4195
- if (disable.status !== 0 && (0, import_node_fs21.existsSync)(timerPath)) {
4497
+ if (disable.status !== 0 && (0, import_node_fs24.existsSync)(timerPath)) {
4196
4498
  return { ok: false, detail: `systemctl --user disable --now ${SYSTEMD_TIMER_NAME} failed: ${(disable.stderr || disable.stdout).trim() || "unknown error"}` };
4197
4499
  }
4198
4500
  try {
4199
- (0, import_node_fs21.rmSync)(timerPath, { force: true });
4200
- (0, import_node_fs21.rmSync)((0, import_node_path15.join)(unitDir, SYSTEMD_SERVICE_NAME), { force: true });
4501
+ (0, import_node_fs24.rmSync)(timerPath, { force: true });
4502
+ (0, import_node_fs24.rmSync)((0, import_node_path17.join)(unitDir, SYSTEMD_SERVICE_NAME), { force: true });
4201
4503
  } catch {
4202
4504
  }
4203
4505
  systemctlUser(["daemon-reload"]);
@@ -4212,16 +4514,16 @@ function uninstallTask(env = process.env) {
4212
4514
  }
4213
4515
  function dropLauncher(env, file) {
4214
4516
  try {
4215
- (0, import_node_fs21.rmSync)((0, import_node_path15.join)(statePaths(env).root, file), { force: true });
4517
+ (0, import_node_fs24.rmSync)((0, import_node_path17.join)(statePaths(env).root, file), { force: true });
4216
4518
  } catch {
4217
4519
  }
4218
4520
  }
4219
4521
 
4220
4522
  // src/status.ts
4221
- var import_node_fs22 = require("node:fs");
4523
+ var import_node_fs25 = require("node:fs");
4222
4524
  function readJournal(path) {
4223
4525
  try {
4224
- const events = (0, import_node_fs22.readFileSync)(path, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
4526
+ const events = (0, import_node_fs25.readFileSync)(path, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
4225
4527
  try {
4226
4528
  return JSON.parse(line);
4227
4529
  } catch {
@@ -4430,14 +4732,14 @@ function reportCounts(summary) {
4430
4732
  }
4431
4733
 
4432
4734
  // src/stamp.ts
4433
- var import_node_fs23 = require("node:fs");
4735
+ var import_node_fs26 = require("node:fs");
4434
4736
  var ALWAYS_ARMED = ["cli", "updater"];
4435
4737
  var PLUGIN_ARMS = /* @__PURE__ */ new Set(["claude", "codex", "jervcode", "cursor", "hermes"]);
4436
4738
  function fleetStamp(env = process.env) {
4437
4739
  const paths = statePaths(env);
4438
4740
  let events = [];
4439
4741
  try {
4440
- events = (0, import_node_fs23.readFileSync)(paths.journalPath, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
4742
+ events = (0, import_node_fs26.readFileSync)(paths.journalPath, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
4441
4743
  try {
4442
4744
  return JSON.parse(line);
4443
4745
  } catch {
@@ -4487,7 +4789,7 @@ function fleetStamp(env = process.env) {
4487
4789
  // src/index.ts
4488
4790
  function ownVersion() {
4489
4791
  try {
4490
- return JSON.parse((0, import_node_fs24.readFileSync)((0, import_node_path16.join)(__dirname, "..", "package.json"), "utf8")).version;
4792
+ return JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path18.join)(__dirname, "..", "package.json"), "utf8")).version;
4491
4793
  } catch {
4492
4794
  return "0.0.0";
4493
4795
  }
@@ -4650,6 +4952,7 @@ if (typeof require !== "undefined" && require.main === module) {
4650
4952
  renderNotice,
4651
4953
  renderReport,
4652
4954
  reportCounts,
4955
+ resolvePayloadTarball,
4653
4956
  retiredSurfaces,
4654
4957
  retryHint,
4655
4958
  runMaintenance,
@@ -4659,6 +4962,7 @@ if (typeof require !== "undefined" && require.main === module) {
4659
4962
  sharedDocLockTimeoutReceipt,
4660
4963
  shippedTargetFrom,
4661
4964
  shouldHandOff,
4965
+ stagePackage,
4662
4966
  statusScreen,
4663
4967
  surfaceArmPlan,
4664
4968
  systemdServiceUnit,