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