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