@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.
- package/dist/index.cjs +609 -305
- 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
|
|
91
|
-
var
|
|
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
|
|
1267
|
+
var import_node_fs8 = require("node:fs");
|
|
1266
1268
|
var import_node_os2 = require("node:os");
|
|
1267
|
-
var
|
|
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
|
|
1272
|
-
var
|
|
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,
|
|
1406
|
-
const path = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1429
|
-
(0,
|
|
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,
|
|
1515
|
+
(0, import_node_fs7.unlinkSync)(recovery);
|
|
1432
1516
|
}
|
|
1433
1517
|
}
|
|
1434
1518
|
let released = false;
|
|
1435
1519
|
return () => {
|
|
1436
|
-
if (!released && (0,
|
|
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,
|
|
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,
|
|
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,
|
|
1593
|
+
const prefix = `${(0, import_node_path4.basename)(file)}.old-`;
|
|
1510
1594
|
let names;
|
|
1511
1595
|
try {
|
|
1512
|
-
names = (0,
|
|
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,
|
|
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,
|
|
1532
|
-
if (!(0,
|
|
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,
|
|
1569
|
-
if (platform !== "win32") (0,
|
|
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,
|
|
1656
|
+
(0, import_node_fs8.renameSync)(file, moved);
|
|
1573
1657
|
}
|
|
1574
|
-
(0,
|
|
1658
|
+
(0, import_node_fs8.renameSync)(next, file);
|
|
1575
1659
|
} catch {
|
|
1576
1660
|
try {
|
|
1577
|
-
if (moved && !(0,
|
|
1661
|
+
if (moved && !(0, import_node_fs8.existsSync)(file)) (0, import_node_fs8.renameSync)(moved, file);
|
|
1578
1662
|
} catch {
|
|
1579
1663
|
}
|
|
1580
|
-
(0,
|
|
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
|
|
1691
|
+
var import_node_fs9 = require("node:fs");
|
|
1608
1692
|
var import_node_os3 = require("node:os");
|
|
1609
|
-
var
|
|
1693
|
+
var import_node_path5 = require("node:path");
|
|
1610
1694
|
function stateRoot(env = process.env) {
|
|
1611
|
-
return env.MMI_UPDATER_HOME || (0,
|
|
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,
|
|
1616
|
-
const gitCache = (0,
|
|
1617
|
-
return { root, staging, gitCache, journalPath: (0,
|
|
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,
|
|
1622
|
-
(0,
|
|
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,
|
|
1633
|
-
(0,
|
|
1634
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1686
|
-
const fd = (0,
|
|
1687
|
-
(0,
|
|
1688
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
1773
|
-
var
|
|
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,
|
|
1783
|
-
if ((0,
|
|
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,
|
|
1792
|
-
if ((0,
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
2093
|
+
var import_node_fs16 = require("node:fs");
|
|
2010
2094
|
var import_node_os5 = require("node:os");
|
|
2011
|
-
var
|
|
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
|
|
2099
|
+
var import_node_fs15 = require("node:fs");
|
|
2016
2100
|
var import_node_os4 = require("node:os");
|
|
2017
|
-
var
|
|
2101
|
+
var import_node_path10 = require("node:path");
|
|
2018
2102
|
|
|
2019
2103
|
// src/arm-npm-global.ts
|
|
2020
|
-
var
|
|
2104
|
+
var import_node_fs13 = require("node:fs");
|
|
2021
2105
|
var import_node_child_process5 = require("node:child_process");
|
|
2022
|
-
var
|
|
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
|
|
2027
|
-
var
|
|
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,
|
|
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,
|
|
2118
|
+
return (0, import_node_path7.join)(paths.root, "pending.json");
|
|
2035
2119
|
}
|
|
2036
2120
|
function watcherLockPath(paths) {
|
|
2037
|
-
return (0,
|
|
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,
|
|
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,
|
|
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,
|
|
2136
|
+
(0, import_node_fs12.writeFileSync)(tmp, `${JSON.stringify(records, null, 2)}
|
|
2053
2137
|
`, "utf8");
|
|
2054
|
-
(0,
|
|
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,
|
|
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,
|
|
2130
|
-
logPath: (0,
|
|
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,
|
|
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,
|
|
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,
|
|
2192
|
-
const packageRoot = (0,
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
2262
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
2368
|
+
(0, import_node_fs14.writeFileSync)(tmp, `${JSON.stringify(record, null, 2)}
|
|
2278
2369
|
`, "utf8");
|
|
2279
|
-
(0,
|
|
2370
|
+
(0, import_node_fs14.renameSync)(tmp, path);
|
|
2280
2371
|
}
|
|
2281
2372
|
function clearLaunchTarget(path) {
|
|
2282
2373
|
try {
|
|
2283
|
-
(0,
|
|
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,
|
|
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,
|
|
2444
|
+
return (0, import_node_path10.join)(home, ".claude");
|
|
2354
2445
|
}
|
|
2355
2446
|
function claudeMarketplacesPath(env) {
|
|
2356
|
-
return env.MMI_UPDATER_CLAUDE_MARKETPLACES || (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
2451
|
-
const incoming = (0,
|
|
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,
|
|
2462
|
-
(0,
|
|
2463
|
-
(0,
|
|
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,
|
|
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,
|
|
2566
|
+
const cacheTarget = (0, import_node_path10.join)(pluginsRoot, "cache", "mutmutco", "mmi", target);
|
|
2473
2567
|
try {
|
|
2474
|
-
if (!(0,
|
|
2475
|
-
(0,
|
|
2476
|
-
(0,
|
|
2477
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
2589
|
-
return (0,
|
|
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,
|
|
2697
|
+
const codexHome = env.CODEX_HOME || (0, import_node_path11.join)(home, ".codex");
|
|
2604
2698
|
return [
|
|
2605
|
-
{ id: "claude", marker: (0,
|
|
2606
|
-
{ id: "codex", marker: (0,
|
|
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,
|
|
2612
|
-
{ id: "jervcode", marker: (0,
|
|
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,
|
|
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
|
|
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
|
|
2720
|
+
var import_node_path12 = require("node:path");
|
|
2627
2721
|
|
|
2628
2722
|
// src/compat.ts
|
|
2629
|
-
var
|
|
2723
|
+
var import_node_fs17 = require("node:fs");
|
|
2630
2724
|
function readManifestCompat(manifestPath) {
|
|
2631
2725
|
try {
|
|
2632
|
-
const parsed = JSON.parse((0,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
2690
|
-
(0,
|
|
2691
|
-
(0,
|
|
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,
|
|
2798
|
+
(0, import_node_fs18.closeSync)(fd);
|
|
2705
2799
|
} catch {
|
|
2706
2800
|
}
|
|
2707
2801
|
try {
|
|
2708
|
-
(0,
|
|
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,
|
|
2811
|
+
(0, import_node_fs18.renameSync)(lockPath, aside);
|
|
2718
2812
|
} catch {
|
|
2719
2813
|
continue;
|
|
2720
2814
|
}
|
|
2721
2815
|
try {
|
|
2722
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
2936
|
+
if (!(0, import_node_fs19.existsSync)(path)) return "current";
|
|
2843
2937
|
let existing;
|
|
2844
2938
|
try {
|
|
2845
|
-
existing = JSON.parse((0,
|
|
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,
|
|
2854
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
2879
|
-
(0,
|
|
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,
|
|
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,
|
|
2986
|
+
const dir = (0, import_node_path12.join)(root, "quarantine");
|
|
2893
2987
|
let generations;
|
|
2894
2988
|
try {
|
|
2895
|
-
generations = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
3015
|
+
(0, import_node_fs19.renameSync)(live, broken);
|
|
2922
3016
|
} catch {
|
|
2923
3017
|
return "kept-broken";
|
|
2924
3018
|
}
|
|
2925
3019
|
try {
|
|
2926
|
-
(0,
|
|
3020
|
+
(0, import_node_fs19.renameSync)(quarantined, live);
|
|
2927
3021
|
return "restored";
|
|
2928
3022
|
} catch {
|
|
2929
3023
|
try {
|
|
2930
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
2984
|
-
incoming = (0,
|
|
2985
|
-
for (const dir of ["local", "staging", "quarantine"]) (0,
|
|
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,
|
|
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,
|
|
3012
|
-
for (const dir of ["local", "staging", "quarantine"]) (0,
|
|
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,
|
|
3028
|
-
(0,
|
|
3124
|
+
if ((0, import_node_fs19.existsSync)(live)) {
|
|
3125
|
+
(0, import_node_fs19.renameSync)(live, quarantined);
|
|
3029
3126
|
displaced = true;
|
|
3030
3127
|
}
|
|
3031
|
-
(0,
|
|
3128
|
+
(0, import_node_fs19.renameSync)(incoming, live);
|
|
3032
3129
|
} catch (error) {
|
|
3033
|
-
if (displaced && !(0,
|
|
3130
|
+
if (displaced && !(0, import_node_fs19.existsSync)(live)) {
|
|
3034
3131
|
try {
|
|
3035
|
-
(0,
|
|
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,
|
|
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,
|
|
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
|
|
3064
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
3204
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
3234
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
3279
|
-
const skillsRoot = (0,
|
|
3280
|
-
const targetRoot = (0,
|
|
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,
|
|
3283
|
-
const names = (0,
|
|
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,
|
|
3286
|
-
const incoming = (0,
|
|
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,
|
|
3385
|
+
(0, import_node_fs21.cpSync)(pluginSkills, incoming, { recursive: true });
|
|
3289
3386
|
discard2(targetRoot);
|
|
3290
|
-
(0,
|
|
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,
|
|
3313
|
-
if (entry.isDirectory() && !entry.name.startsWith(".")) homes.push((0,
|
|
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,
|
|
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,
|
|
3351
|
-
const live = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
3385
|
-
const launchTargetPath = (0,
|
|
3386
|
-
const incomingRoot = (0,
|
|
3387
|
-
const incoming = (0,
|
|
3388
|
-
const quarantine = (0,
|
|
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,
|
|
3394
|
-
(0,
|
|
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,
|
|
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,
|
|
3512
|
+
const displaced = (0, import_node_fs21.existsSync)(live);
|
|
3412
3513
|
try {
|
|
3413
|
-
(0,
|
|
3414
|
-
if (displaced) (0,
|
|
3415
|
-
(0,
|
|
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,
|
|
3418
|
-
(0,
|
|
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,
|
|
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,
|
|
3433
|
-
(0,
|
|
3434
|
-
if (displaced) (0,
|
|
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,
|
|
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
|
|
3454
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
3499
|
-
return { dir: (0,
|
|
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,
|
|
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,
|
|
3813
|
+
const path = (0, import_node_path16.join)(dir, entry.name);
|
|
3526
3814
|
let ageMs;
|
|
3527
3815
|
try {
|
|
3528
|
-
ageMs = now - (0,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
4071
|
+
var import_node_fs24 = require("node:fs");
|
|
3770
4072
|
var import_node_os8 = require("node:os");
|
|
3771
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
4030
|
-
const timerPath = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
4077
|
-
(0,
|
|
4078
|
-
const xmlPath = (0,
|
|
4079
|
-
(0,
|
|
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,
|
|
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,
|
|
4099
|
-
(0,
|
|
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,
|
|
4112
|
-
(0,
|
|
4113
|
-
(0,
|
|
4114
|
-
const agentsDir = (0,
|
|
4115
|
-
(0,
|
|
4116
|
-
const plistPath = (0,
|
|
4117
|
-
(0,
|
|
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,
|
|
4136
|
-
(0,
|
|
4137
|
-
(0,
|
|
4138
|
-
const unitDir = (0,
|
|
4139
|
-
(0,
|
|
4140
|
-
(0,
|
|
4141
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
4193
|
-
const timerPath = (0,
|
|
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,
|
|
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,
|
|
4200
|
-
(0,
|
|
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,
|
|
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
|
|
4523
|
+
var import_node_fs25 = require("node:fs");
|
|
4222
4524
|
function readJournal(path) {
|
|
4223
4525
|
try {
|
|
4224
|
-
const events = (0,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|