@mutmutco/hub 4.3.6 → 4.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.cjs +207 -276
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -66,7 +66,6 @@ __export(index_exports, {
66
66
  retryHint: () => retryHint,
67
67
  schedulePendingWatcher: () => schedulePendingWatcher,
68
68
  schedulerStatus: () => schedulerStatus,
69
- selfDist: () => selfDist,
70
69
  sharedDocLockPath: () => sharedDocLockPath,
71
70
  sharedDocLockTimeoutReceipt: () => sharedDocLockTimeoutReceipt,
72
71
  shouldHandOff: () => shouldHandOff,
@@ -83,9 +82,9 @@ __export(index_exports, {
83
82
  writePending: () => writePending
84
83
  });
85
84
  module.exports = __toCommonJS(index_exports);
86
- var import_node_child_process10 = require("node:child_process");
87
- var import_node_fs19 = require("node:fs");
88
- var import_node_path14 = require("node:path");
85
+ var import_node_child_process9 = require("node:child_process");
86
+ var import_node_fs18 = require("node:fs");
87
+ var import_node_path13 = require("node:path");
89
88
 
90
89
  // src/state.ts
91
90
  var import_node_fs = require("node:fs");
@@ -1072,106 +1071,17 @@ function enumerateSurfaces(env = process.env) {
1072
1071
  }));
1073
1072
  }
1074
1073
 
1075
- // src/arm-cli.ts
1076
- var import_node_fs9 = require("node:fs");
1077
- var import_node_child_process6 = require("node:child_process");
1078
- var import_node_path8 = require("node:path");
1079
- function globalCliDist(env) {
1080
- const root = globalRoot(env);
1081
- return root ? (0, import_node_path8.join)(root, "@mutmutco", "cli", "dist", "index.cjs") : null;
1082
- }
1083
- function probeCliVersion(distPath) {
1084
- if (!fileExists(distPath)) return null;
1085
- const probe = (0, import_node_child_process6.spawnSync)(process.execPath, [distPath, "--version"], { encoding: "utf8", windowsHide: true });
1086
- const version = (probe.stdout || "").trim();
1087
- return probe.status === 0 && /^\d+\.\d+\.\d+/.test(version) ? version : null;
1088
- }
1089
- function probeCliInstallation(env = process.env) {
1090
- const location = globalCliDist(env);
1091
- const version = location ? probeCliVersion(location) : null;
1092
- return { version, location, detail: version ? `absolute binary reported ${version}` : "global @mutmutco/cli binary was not readable" };
1093
- }
1094
- function cliArm(options) {
1095
- const env = options.env ?? process.env;
1096
- const { target, dryRun, paths } = options;
1097
- const dist = globalCliDist(env);
1098
- const installed = dist ? probeCliVersion(dist) : null;
1099
- if (installed && compareSemver(installed, target) > 0) {
1100
- return { surface: "cli", from: installed, to: installed, verdict: "skip", detail: `installed ${installed} is above candidate ${target} (monotonic)` };
1101
- }
1102
- const highWater = journalHighWater(paths.journalPath, "cli");
1103
- if (highWater && compareSemver(highWater, target) > 0) {
1104
- return { surface: "cli", from: installed, to: highWater, verdict: "skip", detail: `journal high-water ${highWater} is above candidate ${target} (monotonic)` };
1105
- }
1106
- if (installed === target) {
1107
- return { surface: "cli", from: installed, to: target, verdict: "ok", detail: `already at target ${target}` };
1108
- }
1109
- if (dryRun) {
1110
- return { surface: "cli", from: installed, to: target, verdict: "ok", detail: `dry-run: would converge ${installed ?? "absent"} -> ${target}` };
1111
- }
1112
- const stageRoot = (0, import_node_path8.join)(paths.staging, "cli", target);
1113
- const stageDist = (0, import_node_path8.join)(stageRoot, "node_modules", "@mutmutco", "cli", "dist", "index.cjs");
1114
- if (!fileExists(stageDist)) {
1115
- (0, import_node_fs9.mkdirSync)(stageRoot, { recursive: true });
1116
- (0, import_node_fs9.writeFileSync)((0, import_node_path8.join)(stageRoot, "package.json"), JSON.stringify({ name: "mmi-updater-stage", private: true }) + "\n");
1117
- const install = runNpm(["install", "--prefix", stageRoot, "--no-audit", "--no-fund", "--no-package-lock", `@mutmutco/cli@${target}`], env);
1118
- if (install.status !== 0) {
1119
- return { surface: "cli", from: installed, to: target, verdict: "defer", detail: `staging install failed: ${(install.stderr || install.stdout).split("\n").filter(Boolean).slice(-3).join(" | ")}` };
1120
- }
1121
- }
1122
- let stagedManifestVersion;
1123
- try {
1124
- stagedManifestVersion = JSON.parse((0, import_node_fs9.readFileSync)((0, import_node_path8.join)(stageRoot, "node_modules", "@mutmutco", "cli", "package.json"), "utf8")).version;
1125
- } catch {
1126
- }
1127
- if (stagedManifestVersion !== target) {
1128
- return { surface: "cli", from: installed, to: target, verdict: "defer", detail: `staged manifest is ${stagedManifestVersion ?? "unreadable"}, expected ${target}` };
1129
- }
1130
- const stagedVersion = probeCliVersion(stageDist);
1131
- if (stagedVersion !== target) {
1132
- return { surface: "cli", from: installed, to: target, verdict: "defer", detail: `staged binary probed ${stagedVersion ?? "dead"}, expected ${target}` };
1133
- }
1134
- const globalInstall = runNpm(["install", "-g", "--no-audit", "--no-fund", `@mutmutco/cli@${target}`], env);
1135
- if (globalInstall.status !== 0) {
1136
- const reason = `global install failed: ${(globalInstall.stderr || globalInstall.stdout).split("\n").filter(Boolean).slice(-3).join(" | ")}`;
1137
- const root = globalRoot(env);
1138
- const pending = lockShaped(reason) && root ? ` \u2014 ${noteBusyDefer(paths, env, { surface: "cli", target, reason, dirs: [root] })}` : "";
1139
- return { surface: "cli", from: installed, to: target, verdict: "defer", detail: `${reason}${pending}` };
1140
- }
1141
- const switchedDist = globalCliDist(env);
1142
- const switched = probeCliVersion(switchedDist ?? "");
1143
- if (switched !== target) {
1144
- return { surface: "cli", from: installed, to: switched ?? installed ?? "unknown", verdict: "fail", detail: `post-switch probe returned ${switched ?? "dead"} at ${switchedDist ?? "an unresolvable path"}, expected ${target}; the global install already ran \u2014 nothing was rolled back` };
1145
- }
1146
- return { surface: "cli", from: installed, to: target, verdict: "ok", detail: `converged ${installed ?? "absent"} -> ${target} (staged, verified, switched)` };
1147
- }
1148
-
1149
- // src/arm-self.ts
1150
- var SELF_PACKAGE = "@mutmutco/hub";
1151
- var SELF_DIST_REL = "dist/index.cjs";
1152
- function selfDist(env) {
1153
- return globalDist(env, SELF_PACKAGE, SELF_DIST_REL);
1154
- }
1155
- function selfArm(options) {
1156
- return npmGlobalArm({
1157
- surface: "updater",
1158
- packageName: SELF_PACKAGE,
1159
- distRel: SELF_DIST_REL,
1160
- ...options
1161
- });
1162
- }
1163
-
1164
1074
  // src/arm-cursor.ts
1165
- var import_node_fs12 = require("node:fs");
1166
- var import_node_child_process7 = require("node:child_process");
1075
+ var import_node_fs11 = require("node:fs");
1076
+ var import_node_child_process6 = require("node:child_process");
1167
1077
  var import_node_os5 = require("node:os");
1168
- var import_node_path9 = require("node:path");
1078
+ var import_node_path8 = require("node:path");
1169
1079
 
1170
1080
  // src/compat.ts
1171
- var import_node_fs10 = require("node:fs");
1081
+ var import_node_fs9 = require("node:fs");
1172
1082
  function readManifestCompat(manifestPath) {
1173
1083
  try {
1174
- const parsed = JSON.parse((0, import_node_fs10.readFileSync)(manifestPath, "utf8"));
1084
+ const parsed = JSON.parse((0, import_node_fs9.readFileSync)(manifestPath, "utf8"));
1175
1085
  return typeof parsed.mmiCompat === "string" ? parsed.mmiCompat : void 0;
1176
1086
  } catch {
1177
1087
  return void 0;
@@ -1179,7 +1089,7 @@ function readManifestCompat(manifestPath) {
1179
1089
  }
1180
1090
 
1181
1091
  // src/host-doc-lock.ts
1182
- var import_node_fs11 = require("node:fs");
1092
+ var import_node_fs10 = require("node:fs");
1183
1093
  var import_node_os4 = require("node:os");
1184
1094
  var SHARED_DOC_LOCK_STALE_MS = 3e4;
1185
1095
  var SHARED_DOC_LOCK_ATTEMPTS = 50;
@@ -1193,7 +1103,7 @@ function lockContent(options) {
1193
1103
  }
1194
1104
  function readHolder(lockPath) {
1195
1105
  try {
1196
- const parsed = JSON.parse((0, import_node_fs11.readFileSync)(lockPath, "utf8"));
1106
+ const parsed = JSON.parse((0, import_node_fs10.readFileSync)(lockPath, "utf8"));
1197
1107
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
1198
1108
  return parsed;
1199
1109
  } catch {
@@ -1205,7 +1115,7 @@ function lockAgeMs(lockPath, now) {
1205
1115
  const declared = typeof holder?.acquiredAt === "string" ? Date.parse(holder.acquiredAt) : Number.NaN;
1206
1116
  if (!Number.isNaN(declared)) return Math.max(0, now - declared);
1207
1117
  try {
1208
- return Math.max(0, now - (0, import_node_fs11.statSync)(lockPath).mtimeMs);
1118
+ return Math.max(0, now - (0, import_node_fs10.statSync)(lockPath).mtimeMs);
1209
1119
  } catch {
1210
1120
  return 0;
1211
1121
  }
@@ -1228,9 +1138,9 @@ function acquireSharedDocLock(documentPath, options) {
1228
1138
  for (let attempt = 0; attempt < attempts; attempt += 1) {
1229
1139
  let fd;
1230
1140
  try {
1231
- fd = (0, import_node_fs11.openSync)(lockPath, "wx");
1232
- (0, import_node_fs11.writeSync)(fd, content);
1233
- (0, import_node_fs11.closeSync)(fd);
1141
+ fd = (0, import_node_fs10.openSync)(lockPath, "wx");
1142
+ (0, import_node_fs10.writeSync)(fd, content);
1143
+ (0, import_node_fs10.closeSync)(fd);
1234
1144
  return {
1235
1145
  documentPath,
1236
1146
  lockPath,
@@ -1243,11 +1153,11 @@ function acquireSharedDocLock(documentPath, options) {
1243
1153
  } catch (error) {
1244
1154
  if (fd !== void 0) {
1245
1155
  try {
1246
- (0, import_node_fs11.closeSync)(fd);
1156
+ (0, import_node_fs10.closeSync)(fd);
1247
1157
  } catch {
1248
1158
  }
1249
1159
  try {
1250
- (0, import_node_fs11.unlinkSync)(lockPath);
1160
+ (0, import_node_fs10.unlinkSync)(lockPath);
1251
1161
  } catch {
1252
1162
  }
1253
1163
  }
@@ -1256,12 +1166,12 @@ function acquireSharedDocLock(documentPath, options) {
1256
1166
  if (lockAgeMs(lockPath, Date.now()) >= staleAfterMs) {
1257
1167
  const aside = `${lockPath}.stale-${Date.now()}`;
1258
1168
  try {
1259
- (0, import_node_fs11.renameSync)(lockPath, aside);
1169
+ (0, import_node_fs10.renameSync)(lockPath, aside);
1260
1170
  } catch {
1261
1171
  continue;
1262
1172
  }
1263
1173
  try {
1264
- (0, import_node_fs11.rmSync)(aside, { force: true });
1174
+ (0, import_node_fs10.rmSync)(aside, { force: true });
1265
1175
  } catch {
1266
1176
  }
1267
1177
  continue;
@@ -1274,7 +1184,7 @@ function releaseSharedDocLock(handle) {
1274
1184
  try {
1275
1185
  const holder = readHolder(handle.lockPath);
1276
1186
  if (holder && holder.owner === handle.owner && Number(holder.pid) === handle.pid) {
1277
- (0, import_node_fs11.unlinkSync)(handle.lockPath);
1187
+ (0, import_node_fs10.unlinkSync)(handle.lockPath);
1278
1188
  }
1279
1189
  } catch {
1280
1190
  }
@@ -1296,14 +1206,14 @@ var KEEP_GENERATIONS = 2;
1296
1206
  var STRANDED_TMP_AGE_MS = 24 * 60 * 6e4;
1297
1207
  var TREE_FILES = [MANIFEST, "skills/bootstrap/SKILL.md"];
1298
1208
  function cursorPluginsRoot() {
1299
- return (0, import_node_path9.join)((0, import_node_os5.homedir)(), ".cursor", "plugins");
1209
+ return (0, import_node_path8.join)((0, import_node_os5.homedir)(), ".cursor", "plugins");
1300
1210
  }
1301
1211
  function treeHealthy(root) {
1302
- return TREE_FILES.every((rel) => (0, import_node_fs12.existsSync)((0, import_node_path9.join)(root, ...rel.split("/"))));
1212
+ return TREE_FILES.every((rel) => (0, import_node_fs11.existsSync)((0, import_node_path8.join)(root, ...rel.split("/"))));
1303
1213
  }
1304
1214
  function readJson(root, rel) {
1305
1215
  try {
1306
- return JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path9.join)(root, ...rel.split("/")), "utf8"));
1216
+ return JSON.parse((0, import_node_fs11.readFileSync)((0, import_node_path8.join)(root, ...rel.split("/")), "utf8"));
1307
1217
  } catch {
1308
1218
  return null;
1309
1219
  }
@@ -1312,7 +1222,7 @@ function manifest(root) {
1312
1222
  return readJson(root, MANIFEST);
1313
1223
  }
1314
1224
  function probeCursorInstallation() {
1315
- const location = (0, import_node_path9.join)(cursorPluginsRoot(), "local", "mmi");
1225
+ const location = (0, import_node_path8.join)(cursorPluginsRoot(), "local", "mmi");
1316
1226
  const version = manifest(location)?.version ?? null;
1317
1227
  return { version, location, detail: version ? "installed Cursor plugin manifest" : "installed Cursor plugin manifest was unreadable" };
1318
1228
  }
@@ -1327,7 +1237,7 @@ function message(error) {
1327
1237
  }
1328
1238
  function discard(path) {
1329
1239
  try {
1330
- (0, import_node_fs12.rmSync)(path, { recursive: true, force: true });
1240
+ (0, import_node_fs11.rmSync)(path, { recursive: true, force: true });
1331
1241
  } catch {
1332
1242
  }
1333
1243
  }
@@ -1346,7 +1256,7 @@ function cursorHostEvidence(env) {
1346
1256
  if (env[marker]?.trim()) return `env marker ${marker}`;
1347
1257
  }
1348
1258
  if (env.CURSOR_AGENT === "1") return "env marker CURSOR_AGENT=1";
1349
- const result = process.platform === "win32" ? (0, import_node_child_process7.spawnSync)("powershell.exe", ["-NoProfile", "-Command", "Get-CimInstance Win32_Process | ForEach-Object { $_.CommandLine }"], { encoding: "utf8", windowsHide: true, timeout: 15e3 }) : (0, import_node_child_process7.spawnSync)("ps", ["-eo", "args="], { encoding: "utf8", windowsHide: true, timeout: 15e3 });
1259
+ const result = process.platform === "win32" ? (0, import_node_child_process6.spawnSync)("powershell.exe", ["-NoProfile", "-Command", "Get-CimInstance Win32_Process | ForEach-Object { $_.CommandLine }"], { encoding: "utf8", windowsHide: true, timeout: 15e3 }) : (0, import_node_child_process6.spawnSync)("ps", ["-eo", "args="], { encoding: "utf8", windowsHide: true, timeout: 15e3 });
1350
1260
  if (result.status !== 0 || !(result.stdout ?? "").trim()) return "the process table is unreadable (unsafe to write)";
1351
1261
  for (const line of result.stdout.split(/\r?\n/)) {
1352
1262
  const executable = cursorExecutable(line);
@@ -1355,7 +1265,7 @@ function cursorHostEvidence(env) {
1355
1265
  return null;
1356
1266
  }
1357
1267
  function resolvedPluginRoot(root) {
1358
- return (0, import_node_path9.join)(root).replace(/\\/g, "/");
1268
+ return (0, import_node_path8.join)(root).replace(/\\/g, "/");
1359
1269
  }
1360
1270
  function isMmiEntry(entry, pluginRoot) {
1361
1271
  if (typeof entry !== "object" || entry === null || typeof entry.command !== "string") return false;
@@ -1379,12 +1289,12 @@ function stripUserHooks(existing, pluginRoot) {
1379
1289
  }
1380
1290
  var CURSOR_HOOKS_LOCK_OWNER = "mmi-hub:cursor-hooks";
1381
1291
  function reconcileCursorUserHooks(pluginRoot, homeDir, lock = {}) {
1382
- const path = (0, import_node_path9.join)(homeDir, ".cursor", USER_HOOKS_FILE);
1292
+ const path = (0, import_node_path8.join)(homeDir, ".cursor", USER_HOOKS_FILE);
1383
1293
  return withSharedDocLock(path, { owner: CURSOR_HOOKS_LOCK_OWNER, ...lock }, () => {
1384
- if (!(0, import_node_fs12.existsSync)(path)) return "current";
1294
+ if (!(0, import_node_fs11.existsSync)(path)) return "current";
1385
1295
  let existing;
1386
1296
  try {
1387
- existing = JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
1297
+ existing = JSON.parse((0, import_node_fs11.readFileSync)(path, "utf8"));
1388
1298
  } catch {
1389
1299
  return "user-conflict";
1390
1300
  }
@@ -1392,8 +1302,8 @@ function reconcileCursorUserHooks(pluginRoot, homeDir, lock = {}) {
1392
1302
  if (!stripped) return "user-conflict";
1393
1303
  if (JSON.stringify(stripped) === JSON.stringify(existing)) return "current";
1394
1304
  const tmp = `${path}.tmp-${process.pid}`;
1395
- (0, import_node_fs12.writeFileSync)(tmp, JSON.stringify(stripped, null, 2) + "\n", "utf8");
1396
- (0, import_node_fs12.renameSync)(tmp, path);
1305
+ (0, import_node_fs11.writeFileSync)(tmp, JSON.stringify(stripped, null, 2) + "\n", "utf8");
1306
+ (0, import_node_fs11.renameSync)(tmp, path);
1397
1307
  return "updated";
1398
1308
  });
1399
1309
  }
@@ -1408,41 +1318,41 @@ function userHooksDetail(pluginRoot, homeDir) {
1408
1318
  case "updated":
1409
1319
  return "; user hooks legacy entries stripped";
1410
1320
  case "user-conflict":
1411
- return `; USER HOOKS CONFLICT at ${(0, import_node_path9.join)(homeDir, ".cursor", USER_HOOKS_FILE)} \u2014 legacy entries were not changed`;
1321
+ return `; USER HOOKS CONFLICT at ${(0, import_node_path8.join)(homeDir, ".cursor", USER_HOOKS_FILE)} \u2014 legacy entries were not changed`;
1412
1322
  default:
1413
1323
  return "";
1414
1324
  }
1415
1325
  }
1416
1326
  function writeRollbackPointer(root, entry) {
1417
- const path = (0, import_node_path9.join)(root, "quarantine", "rollback.json");
1327
+ const path = (0, import_node_path8.join)(root, "quarantine", "rollback.json");
1418
1328
  const tmp = `${path}.tmp-${process.pid}`;
1419
1329
  try {
1420
- (0, import_node_fs12.writeFileSync)(tmp, JSON.stringify({ surface: "cursor", ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }, null, 2) + "\n", "utf8");
1421
- (0, import_node_fs12.renameSync)(tmp, path);
1330
+ (0, import_node_fs11.writeFileSync)(tmp, JSON.stringify({ surface: "cursor", ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }, null, 2) + "\n", "utf8");
1331
+ (0, import_node_fs11.renameSync)(tmp, path);
1422
1332
  } catch {
1423
1333
  discard(tmp);
1424
1334
  }
1425
1335
  }
1426
1336
  function mtimeMs(path) {
1427
1337
  try {
1428
- return (0, import_node_fs12.statSync)(path).mtimeMs;
1338
+ return (0, import_node_fs11.statSync)(path).mtimeMs;
1429
1339
  } catch {
1430
1340
  return 0;
1431
1341
  }
1432
1342
  }
1433
1343
  function pruneQuarantine(root, keep) {
1434
- const dir = (0, import_node_path9.join)(root, "quarantine");
1344
+ const dir = (0, import_node_path8.join)(root, "quarantine");
1435
1345
  let generations;
1436
1346
  try {
1437
- generations = (0, import_node_fs12.readdirSync)(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("mmi-")).map((entry) => (0, import_node_path9.join)(dir, entry.name)).sort((a, b) => mtimeMs(b) - mtimeMs(a));
1347
+ generations = (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("mmi-")).map((entry) => (0, import_node_path8.join)(dir, entry.name)).sort((a, b) => mtimeMs(b) - mtimeMs(a));
1438
1348
  } catch {
1439
1349
  return 0;
1440
1350
  }
1441
1351
  let stranded = 0;
1442
1352
  try {
1443
- for (const entry of (0, import_node_fs12.readdirSync)(dir, { withFileTypes: true })) {
1353
+ for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
1444
1354
  if (!entry.isFile() || !/^rollback\.json\.tmp-\d+$/.test(entry.name)) continue;
1445
- const path = (0, import_node_path9.join)(dir, entry.name);
1355
+ const path = (0, import_node_path8.join)(dir, entry.name);
1446
1356
  if (Date.now() - mtimeMs(path) < STRANDED_TMP_AGE_MS) continue;
1447
1357
  discard(path);
1448
1358
  stranded += 1;
@@ -1460,16 +1370,16 @@ function pruneQuarantine(root, keep) {
1460
1370
  }
1461
1371
  function restorePrevious(live, quarantined, broken) {
1462
1372
  try {
1463
- (0, import_node_fs12.renameSync)(live, broken);
1373
+ (0, import_node_fs11.renameSync)(live, broken);
1464
1374
  } catch {
1465
1375
  return "kept-broken";
1466
1376
  }
1467
1377
  try {
1468
- (0, import_node_fs12.renameSync)(quarantined, live);
1378
+ (0, import_node_fs11.renameSync)(quarantined, live);
1469
1379
  return "restored";
1470
1380
  } catch {
1471
1381
  try {
1472
- (0, import_node_fs12.renameSync)(broken, live);
1382
+ (0, import_node_fs11.renameSync)(broken, live);
1473
1383
  return "kept-broken";
1474
1384
  } catch {
1475
1385
  return "lost";
@@ -1480,7 +1390,7 @@ function cursorArm(options) {
1480
1390
  const env = options.env ?? process.env;
1481
1391
  const { target, dryRun, paths } = options;
1482
1392
  const root = cursorPluginsRoot();
1483
- const live = (0, import_node_path9.join)(root, "local", "mmi");
1393
+ const live = (0, import_node_path8.join)(root, "local", "mmi");
1484
1394
  const result = (from, to, verdict, detail, launchStaged = false) => ({
1485
1395
  surface: "cursor",
1486
1396
  from,
@@ -1490,7 +1400,7 @@ function cursorArm(options) {
1490
1400
  launchStaged: launchStaged || void 0,
1491
1401
  // C11: the constraint of the generation LEFT at `live` — read at result time, so a failed
1492
1402
  // switch reports the restored generation's declaration, not the rejected one's (#4973).
1493
- compat: readManifestCompat((0, import_node_path9.join)(live, MANIFEST))
1403
+ compat: readManifestCompat((0, import_node_path8.join)(live, MANIFEST))
1494
1404
  });
1495
1405
  const current = manifest(live);
1496
1406
  const installed = current?.version ?? null;
@@ -1504,7 +1414,7 @@ function cursorArm(options) {
1504
1414
  if (installed === target && treeHealthy(live)) {
1505
1415
  return result(installed, target, "ok", `already at target ${target}${userHooksDetail(live, (0, import_node_os5.homedir)())}`);
1506
1416
  }
1507
- if ((0, import_node_fs12.existsSync)(live) && !mmiOwned(live)) {
1417
+ if ((0, import_node_fs11.existsSync)(live) && !mmiOwned(live)) {
1508
1418
  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)`);
1509
1419
  }
1510
1420
  if (dryRun) {
@@ -1518,16 +1428,16 @@ function cursorArm(options) {
1518
1428
  if (stagedMarker !== target || !treeHealthy(staged.packageRoot)) {
1519
1429
  return result(installed, target, "defer", `staged tree marker is ${stagedMarker ?? "unreadable"} and the tree is ${treeHealthy(staged.packageRoot) ? "complete" : "incomplete"}, expected ${target} and complete`);
1520
1430
  }
1521
- const launchTargetPath = (0, import_node_path9.join)(root, "staging", "launch-target.json");
1431
+ const launchTargetPath = (0, import_node_path8.join)(root, "staging", "launch-target.json");
1522
1432
  const priorLaunch = readLaunchTarget(launchTargetPath);
1523
- let incoming = priorLaunch?.target === target && priorLaunch.incoming.startsWith((0, import_node_path9.join)(root, "staging")) && manifest(priorLaunch.incoming)?.version === target && treeHealthy(priorLaunch.incoming) ? priorLaunch.incoming : (0, import_node_path9.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
1433
+ let incoming = priorLaunch?.target === target && priorLaunch.incoming.startsWith((0, import_node_path8.join)(root, "staging")) && manifest(priorLaunch.incoming)?.version === target && treeHealthy(priorLaunch.incoming) ? priorLaunch.incoming : (0, import_node_path8.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
1524
1434
  const reuseIncoming = incoming === priorLaunch?.incoming;
1525
- if (!reuseIncoming || !(0, import_node_fs12.existsSync)(incoming)) {
1526
- incoming = (0, import_node_path9.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
1527
- for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs12.mkdirSync)((0, import_node_path9.join)(root, dir), { recursive: true });
1435
+ if (!reuseIncoming || !(0, import_node_fs11.existsSync)(incoming)) {
1436
+ incoming = (0, import_node_path8.join)(root, "staging", `mmi-${safeSegment(target)}-${Date.now()}`);
1437
+ for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs11.mkdirSync)((0, import_node_path8.join)(root, dir), { recursive: true });
1528
1438
  try {
1529
1439
  discard(incoming);
1530
- (0, import_node_fs12.cpSync)(staged.packageRoot, incoming, { recursive: true });
1440
+ (0, import_node_fs11.cpSync)(staged.packageRoot, incoming, { recursive: true });
1531
1441
  } catch (error) {
1532
1442
  discard(incoming);
1533
1443
  return result(installed, target, "defer", `copy into ${root} failed: ${message(error)}`);
@@ -1550,8 +1460,8 @@ function cursorArm(options) {
1550
1460
  return result(installed, target, "ok", `staged ${target} for next launch while Cursor is running (${busy}) \u2014 ${pending}`, true);
1551
1461
  }
1552
1462
  const stamp = Date.now();
1553
- const quarantined = (0, import_node_path9.join)(root, "quarantine", `mmi-${safeSegment(installed ?? "unknown")}-${stamp}`);
1554
- for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs12.mkdirSync)((0, import_node_path9.join)(root, dir), { recursive: true });
1463
+ const quarantined = (0, import_node_path8.join)(root, "quarantine", `mmi-${safeSegment(installed ?? "unknown")}-${stamp}`);
1464
+ for (const dir of ["local", "staging", "quarantine"]) (0, import_node_fs11.mkdirSync)((0, import_node_path8.join)(root, dir), { recursive: true });
1555
1465
  const started = cursorHostEvidence(env);
1556
1466
  if (started) {
1557
1467
  const pending = noteLaunchStaged(paths, env, {
@@ -1566,15 +1476,15 @@ function cursorArm(options) {
1566
1476
  }
1567
1477
  let displaced = false;
1568
1478
  try {
1569
- if ((0, import_node_fs12.existsSync)(live)) {
1570
- (0, import_node_fs12.renameSync)(live, quarantined);
1479
+ if ((0, import_node_fs11.existsSync)(live)) {
1480
+ (0, import_node_fs11.renameSync)(live, quarantined);
1571
1481
  displaced = true;
1572
1482
  }
1573
- (0, import_node_fs12.renameSync)(incoming, live);
1483
+ (0, import_node_fs11.renameSync)(incoming, live);
1574
1484
  } catch (error) {
1575
- if (displaced && !(0, import_node_fs12.existsSync)(live)) {
1485
+ if (displaced && !(0, import_node_fs11.existsSync)(live)) {
1576
1486
  try {
1577
- (0, import_node_fs12.renameSync)(quarantined, live);
1487
+ (0, import_node_fs11.renameSync)(quarantined, live);
1578
1488
  } catch {
1579
1489
  }
1580
1490
  }
@@ -1585,7 +1495,7 @@ function cursorArm(options) {
1585
1495
  }
1586
1496
  const evidence = manifest(live)?.version;
1587
1497
  if (evidence !== target || !treeHealthy(live)) {
1588
- const broken = `${(0, import_node_path9.join)(root, "quarantine", `mmi-${safeSegment(evidence ?? "broken")}-${stamp}`)}-failed`;
1498
+ const broken = `${(0, import_node_path8.join)(root, "quarantine", `mmi-${safeSegment(evidence ?? "broken")}-${stamp}`)}-failed`;
1589
1499
  const outcome = displaced ? restorePrevious(live, quarantined, broken) : "none";
1590
1500
  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";
1591
1501
  writeRollbackPointer(root, outcome === "restored" ? { installed: installed ?? "unknown", previous: null, generation: null } : { installed: evidence ?? "unknown", previous: installed, generation: displaced ? quarantined : null });
@@ -1598,12 +1508,12 @@ function cursorArm(options) {
1598
1508
  return result(installed, target, "ok", `switched ${installed ?? "absent"} -> ${target}; ${previous}${pruned ? `; pruned ${pruned} older generation${pruned === 1 ? "" : "s"}` : ""}${userHooksDetail(live, (0, import_node_os5.homedir)())}`);
1599
1509
  }
1600
1510
  function probeCursorLaunchStaging() {
1601
- return probeLaunchTargetVersion((0, import_node_path9.join)(cursorPluginsRoot(), "staging", "launch-target.json"), (root) => manifest(root)?.version ?? null);
1511
+ return probeLaunchTargetVersion((0, import_node_path8.join)(cursorPluginsRoot(), "staging", "launch-target.json"), (root) => manifest(root)?.version ?? null);
1602
1512
  }
1603
1513
 
1604
1514
  // src/arm-jervcode.ts
1605
- var import_node_fs13 = require("node:fs");
1606
- var import_node_path10 = require("node:path");
1515
+ var import_node_fs12 = require("node:fs");
1516
+ var import_node_path9 = require("node:path");
1607
1517
  var PI_PACKAGE = "@mutmutco/pi-plugin";
1608
1518
  function hostEnv(env) {
1609
1519
  const dir = jervcodeAgentDir(env);
@@ -1614,7 +1524,7 @@ function hostCommands(_env) {
1614
1524
  }
1615
1525
  function readPackageSpecs(env) {
1616
1526
  try {
1617
- const settings = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path10.join)(jervcodeAgentDir(env), "settings.json"), "utf8"));
1527
+ const settings = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path9.join)(jervcodeAgentDir(env), "settings.json"), "utf8"));
1618
1528
  return Array.isArray(settings.packages) ? settings.packages.filter((entry) => typeof entry === "string") : [];
1619
1529
  } catch {
1620
1530
  return null;
@@ -1622,14 +1532,14 @@ function readPackageSpecs(env) {
1622
1532
  }
1623
1533
  function installedVersion(env) {
1624
1534
  try {
1625
- const manifest2 = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"), "utf8"));
1535
+ const manifest2 = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"), "utf8"));
1626
1536
  return typeof manifest2.version === "string" ? manifest2.version : null;
1627
1537
  } catch {
1628
1538
  return null;
1629
1539
  }
1630
1540
  }
1631
1541
  function materializedManifestLocation(env) {
1632
- return (0, import_node_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"));
1542
+ return (0, import_node_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"));
1633
1543
  }
1634
1544
  var PI_LIST_SPEC = new RegExp(`npm:${PI_PACKAGE.replace("/", "\\/")}@(\\S+)`);
1635
1545
  function parseListText(stdout) {
@@ -1688,32 +1598,32 @@ function jervcodeArm(options) {
1688
1598
  detail,
1689
1599
  // C11: the constraint of the package pi LEFT materialised — read at result time, so defer/fail
1690
1600
  // carry the previous payload's declaration (#4973 reconsult ruling).
1691
- compat: readManifestCompat((0, import_node_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"))
1601
+ compat: readManifestCompat((0, import_node_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json"))
1692
1602
  });
1693
1603
  const before = readPackageSpecs(env);
1694
- if (!before) return result(null, options.target, "defer", `cannot read ${(0, import_node_path10.join)(jervcodeAgentDir(env), "settings.json")}`);
1604
+ if (!before) return result(null, options.target, "defer", `cannot read ${(0, import_node_path9.join)(jervcodeAgentDir(env), "settings.json")}`);
1695
1605
  const from = installedVersion(env);
1696
1606
  const legacy = before.filter(isLegacyMmiPiPath);
1697
1607
  const highWater = journalHighWater(options.paths.journalPath, "jervcode");
1698
1608
  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;
1699
1609
  if (options.dryRun) {
1700
1610
  const action = floor ? `hold ${from ?? "the install"} and skip the install (${floor})` : before.includes(exact) && from === options.target ? "keep exact pin" : `install ${exact}`;
1701
- 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_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1611
+ 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_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1702
1612
  }
1703
1613
  const hosted = hostEnv(env);
1704
1614
  const commands = hostCommands(env);
1705
1615
  const command = commands.find((bin) => runner(bin, ["--version"], hosted).status === 0);
1706
- 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_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1616
+ 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_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1707
1617
  if (!floor && (!before.includes(exact) || from !== options.target)) {
1708
1618
  const install = runner(command, ["install", exact], hosted);
1709
1619
  if (install.status !== 0) {
1710
- return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} install ${exact} failed: ${failure2(install)}`, compat: readManifestCompat((0, import_node_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1620
+ return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} install ${exact} failed: ${failure2(install)}`, compat: readManifestCompat((0, import_node_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1711
1621
  }
1712
1622
  }
1713
1623
  for (const stale of legacy) {
1714
1624
  const removed = runner(command, ["remove", stale], hosted);
1715
1625
  if (removed.status !== 0) {
1716
- return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} remove of the legacy registration failed: ${failure2(removed)}`, compat: readManifestCompat((0, import_node_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1626
+ return { surface: "jervcode", from, to: options.target, verdict: "defer", detail: `${command} remove of the legacy registration failed: ${failure2(removed)}`, compat: readManifestCompat((0, import_node_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1717
1627
  }
1718
1628
  }
1719
1629
  const after = readPackageSpecs(env);
@@ -1721,7 +1631,7 @@ function jervcodeArm(options) {
1721
1631
  const legacyAfter = after?.filter(isLegacyMmiPiPath) ?? [];
1722
1632
  const retired = legacy.length ? `; retired ${legacy.length} legacy claude-cache path registration${legacy.length === 1 ? "" : "s"}` : "";
1723
1633
  if (floor && !legacyAfter.length) {
1724
- return { surface: "jervcode", from, to: converged ?? highWater ?? options.target, verdict: "skip", detail: `${floor}${retired}`, compat: readManifestCompat((0, import_node_path10.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1634
+ return { surface: "jervcode", from, to: converged ?? highWater ?? options.target, verdict: "skip", detail: `${floor}${retired}`, compat: readManifestCompat((0, import_node_path9.join)(jervcodeAgentDir(env), "npm", "node_modules", ...PI_PACKAGE.split("/"), "package.json")) };
1725
1635
  }
1726
1636
  if (!after?.includes(exact) || converged !== options.target || legacyAfter.length) {
1727
1637
  return {
@@ -1742,15 +1652,15 @@ function jervcodeArm(options) {
1742
1652
  }
1743
1653
 
1744
1654
  // src/arm-hermes.ts
1745
- var import_node_fs14 = require("node:fs");
1746
- var import_node_child_process8 = require("node:child_process");
1747
- var import_node_path11 = require("node:path");
1655
+ var import_node_fs13 = require("node:fs");
1656
+ var import_node_child_process7 = require("node:child_process");
1657
+ var import_node_path10 = require("node:path");
1748
1658
  var PACKAGE2 = "@mutmutco/hermes-plugin";
1749
1659
  var MANIFEST2 = "plugin.yaml";
1750
1660
  var TREE_MARKERS_FALLBACK = [MANIFEST2, "__init__.py", "skills"];
1751
1661
  function yamlVersion(root) {
1752
1662
  try {
1753
- const text = (0, import_node_fs14.readFileSync)((0, import_node_path11.join)(root, MANIFEST2), "utf8");
1663
+ const text = (0, import_node_fs13.readFileSync)((0, import_node_path10.join)(root, MANIFEST2), "utf8");
1754
1664
  try {
1755
1665
  const version = JSON.parse(text).version;
1756
1666
  if (typeof version === "string" && version.trim()) return version.trim();
@@ -1764,7 +1674,7 @@ function yamlVersion(root) {
1764
1674
  }
1765
1675
  function packageTreeMarkers(root) {
1766
1676
  try {
1767
- const files = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path11.join)(root, "package.json"), "utf8")).files;
1677
+ const files = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path10.join)(root, "package.json"), "utf8")).files;
1768
1678
  if (Array.isArray(files) && files.length && files.every((entry) => typeof entry === "string" && entry.trim())) {
1769
1679
  return files.map((entry) => entry.trim());
1770
1680
  }
@@ -1773,10 +1683,10 @@ function packageTreeMarkers(root) {
1773
1683
  return TREE_MARKERS_FALLBACK;
1774
1684
  }
1775
1685
  function markerPresent(root, rel) {
1776
- const path = (0, import_node_path11.join)(root, ...rel.split("/"));
1777
- if (!(0, import_node_fs14.existsSync)(path)) return false;
1686
+ const path = (0, import_node_path10.join)(root, ...rel.split("/"));
1687
+ if (!(0, import_node_fs13.existsSync)(path)) return false;
1778
1688
  try {
1779
- const stat = (0, import_node_fs14.statSync)(path);
1689
+ const stat = (0, import_node_fs13.statSync)(path);
1780
1690
  return stat.isFile() || stat.isDirectory();
1781
1691
  } catch {
1782
1692
  return false;
@@ -1795,13 +1705,13 @@ function treeIncompleteDetail(root, label) {
1795
1705
  }
1796
1706
  function packageIdentity(root) {
1797
1707
  try {
1798
- return JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path11.join)(root, "package.json"), "utf8")).name === PACKAGE2;
1708
+ return JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path10.join)(root, "package.json"), "utf8")).name === PACKAGE2;
1799
1709
  } catch {
1800
1710
  return false;
1801
1711
  }
1802
1712
  }
1803
1713
  function probeHermesInstallation(env = process.env) {
1804
- const location = (0, import_node_path11.join)(hermesHome(env), "plugins", "mmi");
1714
+ const location = (0, import_node_path10.join)(hermesHome(env), "plugins", "mmi");
1805
1715
  const version = yamlVersion(location);
1806
1716
  return { version, location, detail: version ? "installed Hermes plugin manifest" : "installed Hermes plugin manifest was unreadable" };
1807
1717
  }
@@ -1810,7 +1720,7 @@ function mmiOwned2(root) {
1810
1720
  }
1811
1721
  function discard2(path) {
1812
1722
  try {
1813
- (0, import_node_fs14.rmSync)(path, { recursive: true, force: true });
1723
+ (0, import_node_fs13.rmSync)(path, { recursive: true, force: true });
1814
1724
  } catch {
1815
1725
  }
1816
1726
  }
@@ -1829,7 +1739,7 @@ function hermesProcessToken(line, home) {
1829
1739
  return hermesToken(tokens) ?? (home && normalized.toLowerCase().includes(home.toLowerCase()) ? home : null);
1830
1740
  }
1831
1741
  function realProcessListing() {
1832
- const result = process.platform === "win32" ? (0, import_node_child_process8.spawnSync)("powershell.exe", ["-NoProfile", "-Command", "Get-CimInstance Win32_Process | ForEach-Object { $_.Name + ' ' + $_.CommandLine }"], { encoding: "utf8", windowsHide: true, timeout: 15e3 }) : (0, import_node_child_process8.spawnSync)("ps", ["-eo", "args="], { encoding: "utf8", windowsHide: true, timeout: 15e3 });
1742
+ const result = process.platform === "win32" ? (0, import_node_child_process7.spawnSync)("powershell.exe", ["-NoProfile", "-Command", "Get-CimInstance Win32_Process | ForEach-Object { $_.Name + ' ' + $_.CommandLine }"], { encoding: "utf8", windowsHide: true, timeout: 15e3 }) : (0, import_node_child_process7.spawnSync)("ps", ["-eo", "args="], { encoding: "utf8", windowsHide: true, timeout: 15e3 });
1833
1743
  return result.status === 0 ? result.stdout ?? "" : null;
1834
1744
  }
1835
1745
  function hermesHostEvidence(env, home, processListProvider) {
@@ -1842,19 +1752,19 @@ function hermesHostEvidence(env, home, processListProvider) {
1842
1752
  return null;
1843
1753
  }
1844
1754
  function materializeHermesSkills(home) {
1845
- const pluginSkills = (0, import_node_path11.join)(home, "plugins", "mmi", "skills");
1846
- const skillsRoot = (0, import_node_path11.join)(home, "skills");
1847
- const targetRoot = (0, import_node_path11.join)(skillsRoot, "mmi");
1755
+ const pluginSkills = (0, import_node_path10.join)(home, "plugins", "mmi", "skills");
1756
+ const skillsRoot = (0, import_node_path10.join)(home, "skills");
1757
+ const targetRoot = (0, import_node_path10.join)(skillsRoot, "mmi");
1848
1758
  try {
1849
- if (!(0, import_node_fs14.existsSync)(pluginSkills)) return { ok: false, detail: `plugin skills tree missing at ${pluginSkills}` };
1850
- const names = (0, import_node_fs14.readdirSync)(pluginSkills, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name);
1759
+ if (!(0, import_node_fs13.existsSync)(pluginSkills)) return { ok: false, detail: `plugin skills tree missing at ${pluginSkills}` };
1760
+ const names = (0, import_node_fs13.readdirSync)(pluginSkills, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name);
1851
1761
  if (!names.length) return { ok: false, detail: `plugin skills tree is empty at ${pluginSkills}` };
1852
- (0, import_node_fs14.mkdirSync)(skillsRoot, { recursive: true });
1853
- const incoming = (0, import_node_path11.join)(skillsRoot, ".mmi-incoming");
1762
+ (0, import_node_fs13.mkdirSync)(skillsRoot, { recursive: true });
1763
+ const incoming = (0, import_node_path10.join)(skillsRoot, ".mmi-incoming");
1854
1764
  discard2(incoming);
1855
- (0, import_node_fs14.cpSync)(pluginSkills, incoming, { recursive: true });
1765
+ (0, import_node_fs13.cpSync)(pluginSkills, incoming, { recursive: true });
1856
1766
  discard2(targetRoot);
1857
- (0, import_node_fs14.renameSync)(incoming, targetRoot);
1767
+ (0, import_node_fs13.renameSync)(incoming, targetRoot);
1858
1768
  return { ok: true, detail: `provisioned ${names.length} skills to ${targetRoot}` };
1859
1769
  } catch (error) {
1860
1770
  return { ok: false, detail: message2(error) };
@@ -1863,8 +1773,8 @@ function materializeHermesSkills(home) {
1863
1773
  function hermesArm(options) {
1864
1774
  const env = options.env ?? process.env;
1865
1775
  const home = hermesHome(env);
1866
- const parent = (0, import_node_path11.join)(home, "plugins");
1867
- const live = (0, import_node_path11.join)(parent, "mmi");
1776
+ const parent = (0, import_node_path10.join)(home, "plugins");
1777
+ const live = (0, import_node_path10.join)(parent, "mmi");
1868
1778
  const installed = yamlVersion(live);
1869
1779
  const result = (from, to, verdict, detail, launchStaged = false) => ({
1870
1780
  surface: "hermes",
@@ -1877,7 +1787,7 @@ function hermesArm(options) {
1877
1787
  if (!hermesHostPresent(env, options.hostCommandRunner)) {
1878
1788
  return result(null, options.target, "skip", `host absent (${hermesHostCommand(env)} CLI not on PATH) \u2014 skipped without writes`);
1879
1789
  }
1880
- if ((0, import_node_fs14.existsSync)(live) && !mmiOwned2(live)) {
1790
+ if ((0, import_node_fs13.existsSync)(live) && !mmiOwned2(live)) {
1881
1791
  return result(installed, options.target, "defer", `${live} carries no ${PACKAGE2} package identity \u2014 refusing to displace an unmanaged Hermes mmi plugin`);
1882
1792
  }
1883
1793
  if (installed && compareSemver(installed, options.target) > 0) return result(installed, installed, "skip", `installed ${installed} is above candidate ${options.target} (monotonic)`);
@@ -1888,7 +1798,7 @@ function hermesArm(options) {
1888
1798
  if (!skills2.ok) return result(installed, options.target, "fail", `plugin at target ${options.target}, but skills provisioning failed: ${skills2.detail}`);
1889
1799
  return result(installed, options.target, "ok", `already at target ${options.target}; ${skills2.detail}`);
1890
1800
  }
1891
- if (options.dryRun) return result(installed, options.target, "ok", `dry-run: would stage ${PACKAGE2}@${options.target}, atomically switch ${installed ?? "absent"} -> ${options.target}, then provision skills into ${(0, import_node_path11.join)(home, "skills", "mmi")}`);
1801
+ if (options.dryRun) return result(installed, options.target, "ok", `dry-run: would stage ${PACKAGE2}@${options.target}, atomically switch ${installed ?? "absent"} -> ${options.target}, then provision skills into ${(0, import_node_path10.join)(home, "skills", "mmi")}`);
1892
1802
  const staged = stagePackage({ surface: "hermes", packageName: PACKAGE2, target: options.target, witness: MANIFEST2, paths: options.paths, env });
1893
1803
  if ("defer" in staged) return result(installed, options.target, "defer", staged.defer);
1894
1804
  const stagedVersion = yamlVersion(staged.packageRoot);
@@ -1897,19 +1807,19 @@ function hermesArm(options) {
1897
1807
  }
1898
1808
  const stagedTree = treeIncompleteDetail(staged.packageRoot, "staged Hermes");
1899
1809
  if (stagedTree) return result(installed, options.target, "defer", stagedTree);
1900
- const scratch = (0, import_node_path11.join)(home, ".mmi-updater");
1901
- const launchTargetPath = (0, import_node_path11.join)(scratch, "launch-target.json");
1902
- const incomingRoot = (0, import_node_path11.join)(scratch, "incoming");
1903
- const incoming = (0, import_node_path11.join)(incomingRoot, options.target);
1904
- const quarantine = (0, import_node_path11.join)(scratch, "quarantine", `${installed ?? "unknown"}-${Date.now()}`);
1810
+ const scratch = (0, import_node_path10.join)(home, ".mmi-updater");
1811
+ const launchTargetPath = (0, import_node_path10.join)(scratch, "launch-target.json");
1812
+ const incomingRoot = (0, import_node_path10.join)(scratch, "incoming");
1813
+ const incoming = (0, import_node_path10.join)(incomingRoot, options.target);
1814
+ const quarantine = (0, import_node_path10.join)(scratch, "quarantine", `${installed ?? "unknown"}-${Date.now()}`);
1905
1815
  const priorLaunch = readLaunchTarget(launchTargetPath);
1906
1816
  const reuseIncoming = priorLaunch?.target === options.target && priorLaunch.incoming === incoming && yamlVersion(incoming) === options.target && treeHealthy2(incoming);
1907
1817
  if (!reuseIncoming) {
1908
1818
  try {
1909
- (0, import_node_fs14.mkdirSync)(parent, { recursive: true });
1910
- (0, import_node_fs14.mkdirSync)((0, import_node_path11.join)(scratch, "quarantine"), { recursive: true });
1819
+ (0, import_node_fs13.mkdirSync)(parent, { recursive: true });
1820
+ (0, import_node_fs13.mkdirSync)((0, import_node_path10.join)(scratch, "quarantine"), { recursive: true });
1911
1821
  discard2(incomingRoot);
1912
- (0, import_node_fs14.cpSync)(staged.packageRoot, incoming, { recursive: true });
1822
+ (0, import_node_fs13.cpSync)(staged.packageRoot, incoming, { recursive: true });
1913
1823
  } catch (error) {
1914
1824
  return result(installed, options.target, "defer", `cannot place incoming Hermes generation: ${message2(error)}`);
1915
1825
  }
@@ -1937,13 +1847,13 @@ function hermesArm(options) {
1937
1847
  });
1938
1848
  return result(installed, options.target, "ok", `staged ${options.target} for next launch while Hermes is running (${busy}) \u2014 ${pending}`, true);
1939
1849
  }
1940
- const displaced = (0, import_node_fs14.existsSync)(live);
1850
+ const displaced = (0, import_node_fs13.existsSync)(live);
1941
1851
  try {
1942
- if (displaced) (0, import_node_fs14.renameSync)(live, quarantine);
1943
- (0, import_node_fs14.renameSync)(incoming, live);
1852
+ if (displaced) (0, import_node_fs13.renameSync)(live, quarantine);
1853
+ (0, import_node_fs13.renameSync)(incoming, live);
1944
1854
  } catch (error) {
1945
- if (displaced && !(0, import_node_fs14.existsSync)(live)) try {
1946
- (0, import_node_fs14.renameSync)(quarantine, live);
1855
+ if (displaced && !(0, import_node_fs13.existsSync)(live)) try {
1856
+ (0, import_node_fs13.renameSync)(quarantine, live);
1947
1857
  } catch {
1948
1858
  }
1949
1859
  discard2(incomingRoot);
@@ -1954,12 +1864,12 @@ function hermesArm(options) {
1954
1864
  const liveVersion = yamlVersion(live);
1955
1865
  const liveTree = treeIncompleteDetail(live, "live Hermes");
1956
1866
  if (liveVersion !== options.target || liveTree) {
1957
- const broken = (0, import_node_path11.join)(scratch, "rejected", `${options.target}-${Date.now()}`);
1867
+ const broken = (0, import_node_path10.join)(scratch, "rejected", `${options.target}-${Date.now()}`);
1958
1868
  const verifyDetail = liveVersion !== options.target ? `manifest is ${liveVersion ?? "unreadable"}, expected ${options.target}` : liveTree;
1959
1869
  try {
1960
- (0, import_node_fs14.mkdirSync)((0, import_node_path11.join)(scratch, "rejected"), { recursive: true });
1961
- (0, import_node_fs14.renameSync)(live, broken);
1962
- if (displaced) (0, import_node_fs14.renameSync)(quarantine, live);
1870
+ (0, import_node_fs13.mkdirSync)((0, import_node_path10.join)(scratch, "rejected"), { recursive: true });
1871
+ (0, import_node_fs13.renameSync)(live, broken);
1872
+ if (displaced) (0, import_node_fs13.renameSync)(quarantine, live);
1963
1873
  } catch (error) {
1964
1874
  return result(installed, liveVersion ?? "unknown", "fail", `post-switch Hermes verification failed and recovery failed: ${message2(error)}`);
1965
1875
  }
@@ -1972,17 +1882,17 @@ function hermesArm(options) {
1972
1882
  return result(installed, options.target, "ok", `converged ${installed ?? "absent"} -> ${options.target} (staged, verified, atomically switched${displaced ? `; previous generation quarantined at ${quarantine}` : ""}); ${skills.detail}`);
1973
1883
  }
1974
1884
  function probeHermesLaunchStaging(env = process.env) {
1975
- return probeLaunchTargetVersion((0, import_node_path11.join)(hermesHome(env), ".mmi-updater", "launch-target.json"), yamlVersion);
1885
+ return probeLaunchTargetVersion((0, import_node_path10.join)(hermesHome(env), ".mmi-updater", "launch-target.json"), yamlVersion);
1976
1886
  }
1977
1887
 
1978
1888
  // src/reap.ts
1979
- var import_node_fs15 = require("node:fs");
1980
- var import_node_path12 = require("node:path");
1889
+ var import_node_fs14 = require("node:fs");
1890
+ var import_node_path11 = require("node:path");
1981
1891
  var KEEP_GENERATIONS2 = 2;
1982
1892
  var SCRATCH_AGE_MS = 24 * 60 * 6e4;
1983
1893
  function listDirs(path) {
1984
1894
  try {
1985
- return (0, import_node_fs15.readdirSync)(path, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
1895
+ return (0, import_node_fs14.readdirSync)(path, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
1986
1896
  } catch {
1987
1897
  return [];
1988
1898
  }
@@ -1990,7 +1900,7 @@ function listDirs(path) {
1990
1900
  function generationSets(root) {
1991
1901
  const children = listDirs(root);
1992
1902
  if (children.some((name) => parseSemver(name))) return [root];
1993
- return children.map((name) => (0, import_node_path12.join)(root, name)).filter((path) => listDirs(path).some((name) => parseSemver(name)));
1903
+ return children.map((name) => (0, import_node_path11.join)(root, name)).filter((path) => listDirs(path).some((name) => parseSemver(name)));
1994
1904
  }
1995
1905
  function pruneGenerations(root, category, dryRun) {
1996
1906
  let reaped = 0;
@@ -2003,7 +1913,7 @@ function pruneGenerations(root, category, dryRun) {
2003
1913
  continue;
2004
1914
  }
2005
1915
  try {
2006
- (0, import_node_fs15.rmSync)((0, import_node_path12.join)(set, version), { recursive: true, force: true });
1916
+ (0, import_node_fs14.rmSync)((0, import_node_path11.join)(set, version), { recursive: true, force: true });
2007
1917
  reaped += 1;
2008
1918
  } catch (error) {
2009
1919
  failures.push(`${version}: ${error?.code ?? error?.message ?? error}`);
@@ -2017,8 +1927,8 @@ function pruneGenerations(root, category, dryRun) {
2017
1927
  }
2018
1928
  var LEASE_STEAL_SCRATCH = /^lease\.lock\.stale-\d+$/;
2019
1929
  function atomicWriteScratch(path) {
2020
- const literal = (0, import_node_path12.basename)(path).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2021
- return { dir: (0, import_node_path12.dirname)(path), pattern: new RegExp(`^${literal}\\.tmp-\\d+$`) };
1930
+ const literal = (0, import_node_path11.basename)(path).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1931
+ return { dir: (0, import_node_path11.dirname)(path), pattern: new RegExp(`^${literal}\\.tmp-\\d+$`) };
2022
1932
  }
2023
1933
  function reapScratch(context, dryRun) {
2024
1934
  const category = "scratch";
@@ -2036,7 +1946,7 @@ function reapScratch(context, dryRun) {
2036
1946
  for (const [dir, patterns] of scanned) {
2037
1947
  let entries;
2038
1948
  try {
2039
- entries = (0, import_node_fs15.readdirSync)(dir, { withFileTypes: true });
1949
+ entries = (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true });
2040
1950
  } catch {
2041
1951
  unreadable.push(dir);
2042
1952
  continue;
@@ -2044,10 +1954,10 @@ function reapScratch(context, dryRun) {
2044
1954
  for (const entry of entries) {
2045
1955
  if (!patterns.some((pattern) => pattern.test(entry.name))) continue;
2046
1956
  if (!entry.isFile()) continue;
2047
- const path = (0, import_node_path12.join)(dir, entry.name);
1957
+ const path = (0, import_node_path11.join)(dir, entry.name);
2048
1958
  let ageMs;
2049
1959
  try {
2050
- ageMs = now - (0, import_node_fs15.statSync)(path).mtimeMs;
1960
+ ageMs = now - (0, import_node_fs14.statSync)(path).mtimeMs;
2051
1961
  } catch {
2052
1962
  continue;
2053
1963
  }
@@ -2057,7 +1967,7 @@ function reapScratch(context, dryRun) {
2057
1967
  continue;
2058
1968
  }
2059
1969
  try {
2060
- (0, import_node_fs15.rmSync)(path, { force: true });
1970
+ (0, import_node_fs14.rmSync)(path, { force: true });
2061
1971
  reaped += 1;
2062
1972
  } catch (error) {
2063
1973
  failures.push(`${entry.name}: ${error?.code ?? error?.message ?? error}`);
@@ -2175,11 +2085,19 @@ function reconcile(options) {
2175
2085
  say(`target v${summary.target} (${summary.gate})`);
2176
2086
  options.onTargetResolved?.(summary.target, summary.gate);
2177
2087
  say("updater: self-bootstrap");
2178
- const self = selfArm({ target: summary.target, dryRun: options.dryRun, paths, env });
2088
+ const self = npmGlobalArm({
2089
+ surface: "updater",
2090
+ packageName: "@mutmutco/hub",
2091
+ distRel: "dist/index.cjs",
2092
+ target: summary.target,
2093
+ dryRun: options.dryRun,
2094
+ paths,
2095
+ env
2096
+ });
2179
2097
  summary.updater = self;
2180
2098
  recordArm(self);
2181
2099
  say(`updater: ${self.verdict}${self.detail ? " \u2014 " + self.detail : ""}`);
2182
- const handoffDist = selfDist(env);
2100
+ const handoffDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2183
2101
  if (shouldHandOff(self, { dryRun: options.dryRun, dist: handoffDist, guard: env.MMI_UPDATER_REEXEC })) {
2184
2102
  summary.reexec = { dist: handoffDist, target: summary.target, from: self.from };
2185
2103
  journal({ kind: "reexec", surface: "updater", from: self.from, to: summary.target, verdict: "ok", detail: `handing off to ${handoffDist} \u2014 the remaining surfaces converge under ${summary.target}` });
@@ -2187,7 +2105,15 @@ function reconcile(options) {
2187
2105
  return summary;
2188
2106
  }
2189
2107
  say(`cli: converging to v${summary.target}`);
2190
- const cli = cliArm({ target: summary.target, dryRun: options.dryRun, paths, env });
2108
+ const cli = npmGlobalArm({
2109
+ surface: "cli",
2110
+ packageName: "@mutmutco/cli",
2111
+ distRel: "dist/index.cjs",
2112
+ target: summary.target,
2113
+ dryRun: options.dryRun,
2114
+ paths,
2115
+ env
2116
+ });
2191
2117
  summary.cli = cli;
2192
2118
  recordArm(cli);
2193
2119
  say(`cli: ${cli.verdict}${cli.detail ? " \u2014 " + cli.detail : ""}`);
@@ -2231,10 +2157,10 @@ function reconcile(options) {
2231
2157
  }
2232
2158
 
2233
2159
  // src/scheduler.ts
2234
- var import_node_child_process9 = require("node:child_process");
2235
- var import_node_fs16 = require("node:fs");
2160
+ var import_node_child_process8 = require("node:child_process");
2161
+ var import_node_fs15 = require("node:fs");
2236
2162
  var import_node_os6 = require("node:os");
2237
- var import_node_path13 = require("node:path");
2163
+ var import_node_path12 = require("node:path");
2238
2164
  var TASK_NAME = "MMI Fleet Updater";
2239
2165
  var LAUNCHER_FILE = "reconcile-hidden.vbs";
2240
2166
  var RUN_BOUND = "PT15M";
@@ -2250,15 +2176,15 @@ var SYSTEMD_UNIT = "mmi-hub-updater";
2250
2176
  var SYSTEMD_SERVICE_NAME = `${SYSTEMD_UNIT}.service`;
2251
2177
  var SYSTEMD_TIMER_NAME = `${SYSTEMD_UNIT}.timer`;
2252
2178
  function schtasks(args) {
2253
- const result = (0, import_node_child_process9.spawnSync)("schtasks.exe", args, { encoding: "utf8", windowsHide: true });
2179
+ const result = (0, import_node_child_process8.spawnSync)("schtasks.exe", args, { encoding: "utf8", windowsHide: true });
2254
2180
  return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
2255
2181
  }
2256
2182
  function launchctl(args) {
2257
- const result = (0, import_node_child_process9.spawnSync)("launchctl", args, { encoding: "utf8", windowsHide: true });
2183
+ const result = (0, import_node_child_process8.spawnSync)("launchctl", args, { encoding: "utf8", windowsHide: true });
2258
2184
  return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
2259
2185
  }
2260
2186
  function systemctlUser(args) {
2261
- const result = (0, import_node_child_process9.spawnSync)("systemctl", ["--user", ...args], { encoding: "utf8", windowsHide: true });
2187
+ const result = (0, import_node_child_process8.spawnSync)("systemctl", ["--user", ...args], { encoding: "utf8", windowsHide: true });
2262
2188
  return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
2263
2189
  }
2264
2190
  function uid() {
@@ -2283,7 +2209,7 @@ WScript.Quit code
2283
2209
  `;
2284
2210
  }
2285
2211
  function loginPath(fallback = process.env.PATH ?? "") {
2286
- const probe = (0, import_node_child_process9.spawnSync)("/bin/sh", ["-lc", 'printf %s "$PATH"'], { encoding: "utf8", windowsHide: true, timeout: 1e4 });
2212
+ const probe = (0, import_node_child_process8.spawnSync)("/bin/sh", ["-lc", 'printf %s "$PATH"'], { encoding: "utf8", windowsHide: true, timeout: 1e4 });
2287
2213
  const captured = (probe.status === 0 ? probe.stdout ?? "" : "").trim();
2288
2214
  const source = captured || fallback;
2289
2215
  const durable = source.split(":").filter((entry) => entry && !/^\/(?:private\/)?(?:tmp|var\/folders)\//.test(entry));
@@ -2392,7 +2318,7 @@ WantedBy=timers.target
2392
2318
  }
2393
2319
  function readFileOrNull(path) {
2394
2320
  try {
2395
- return (0, import_node_fs16.readFileSync)(path, "utf8");
2321
+ return (0, import_node_fs15.readFileSync)(path, "utf8");
2396
2322
  } catch {
2397
2323
  return null;
2398
2324
  }
@@ -2404,7 +2330,7 @@ function elevatedRelaunch(mode, env) {
2404
2330
  if (env.MMI_UPDATER_ELEVATED_RETRY === "1") return false;
2405
2331
  const self = process.argv[1];
2406
2332
  const command = self ? `"${process.execPath}" "${self}" autoupdate ${mode}` : `mmi-hub autoupdate ${mode}`;
2407
- const relaunch = (0, import_node_child_process9.spawnSync)(
2333
+ const relaunch = (0, import_node_child_process8.spawnSync)(
2408
2334
  "powershell.exe",
2409
2335
  ["-NoProfile", "-Command", `Start-Process -Verb RunAs -Wait -WindowStyle Hidden -FilePath 'cmd.exe' -ArgumentList '/c',${psQuote(`set MMI_UPDATER_ELEVATED_RETRY=1&& ${command}`)}`],
2410
2336
  { encoding: "utf8", windowsHide: true }
@@ -2415,7 +2341,7 @@ var NEVER_RUN_RESULT = 267011;
2415
2341
  var NEVER_RUN_YEAR = 1999;
2416
2342
  var EMPTY_RUN_INFO = { lastRunTime: null, lastTaskResult: null, nextRunTime: null };
2417
2343
  function taskRunInfo() {
2418
- const result = (0, import_node_child_process9.spawnSync)(
2344
+ const result = (0, import_node_child_process8.spawnSync)(
2419
2345
  "powershell.exe",
2420
2346
  ["-NoProfile", "-Command", `$stamp = { param($t) if ($t) { $t.ToString('yyyy-MM-dd HH:mm:ss') } }; Get-ScheduledTaskInfo -TaskName '${TASK_NAME}' | Select-Object @{n='LastRunTime';e={& $stamp $_.LastRunTime}},LastTaskResult,@{n='NextRunTime';e={& $stamp $_.NextRunTime}} | ConvertTo-Json -Compress`],
2421
2347
  { encoding: "utf8", windowsHide: true, timeout: 3e4 }
@@ -2441,7 +2367,7 @@ function windowsSchedulerStatus(env) {
2441
2367
  return { ok: false, supported: true, enabled: false, ...EMPTY_RUN_INFO, detail: `"${TASK_NAME}" is not registered \u2014 run \`mmi-hub autoupdate on\`` };
2442
2368
  }
2443
2369
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2444
- const launcherPath = (0, import_node_path13.join)(statePaths(env).root, LAUNCHER_FILE);
2370
+ const launcherPath = (0, import_node_path12.join)(statePaths(env).root, LAUNCHER_FILE);
2445
2371
  const info = taskRunInfo();
2446
2372
  const runInfo = info ?? EMPTY_RUN_INFO;
2447
2373
  const fail = (detail) => ({ ok: false, supported: true, enabled: true, ...runInfo, detail });
@@ -2466,13 +2392,13 @@ function windowsSchedulerStatus(env) {
2466
2392
  return { ok: true, supported: true, enabled: true, ...runInfo, detail: `"${TASK_NAME}" registered ${CADENCE}; ${points}; ${ran}; next ${runInfo.nextRunTime ?? "unscheduled"}` };
2467
2393
  }
2468
2394
  function darwinSchedulerStatus(env) {
2469
- const plistPath = (0, import_node_path13.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
2395
+ const plistPath = (0, import_node_path12.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
2470
2396
  const plist = readFileOrNull(plistPath);
2471
2397
  if (!plist) {
2472
2398
  return { ok: false, supported: true, enabled: false, ...EMPTY_RUN_INFO, detail: `"${LAUNCHD_LABEL}" is not registered \u2014 run \`mmi-hub autoupdate on\`` };
2473
2399
  }
2474
2400
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2475
- const launcherPath = (0, import_node_path13.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
2401
+ const launcherPath = (0, import_node_path12.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
2476
2402
  const fail = (detail) => ({ ok: false, supported: true, enabled: true, ...EMPTY_RUN_INFO, detail });
2477
2403
  if (!plist.includes(launcherPath)) {
2478
2404
  return fail(`"${LAUNCHD_LABEL}" does not run the reconcile launcher ${launcherPath} \u2014 run \`mmi-hub autoupdate on\``);
@@ -2492,15 +2418,15 @@ function darwinSchedulerStatus(env) {
2492
2418
  return { ok: true, supported: true, enabled: true, ...EMPTY_RUN_INFO, detail: `"${LAUNCHD_LABEL}" registered ${POSIX_CADENCE}; ${points}` };
2493
2419
  }
2494
2420
  function linuxSchedulerStatus(env) {
2495
- const unitDir = (0, import_node_path13.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
2496
- const timerPath = (0, import_node_path13.join)(unitDir, SYSTEMD_TIMER_NAME);
2421
+ const unitDir = (0, import_node_path12.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
2422
+ const timerPath = (0, import_node_path12.join)(unitDir, SYSTEMD_TIMER_NAME);
2497
2423
  const timer = readFileOrNull(timerPath);
2498
- const service = readFileOrNull((0, import_node_path13.join)(unitDir, SYSTEMD_SERVICE_NAME));
2424
+ const service = readFileOrNull((0, import_node_path12.join)(unitDir, SYSTEMD_SERVICE_NAME));
2499
2425
  if (!timer || !service) {
2500
2426
  return { ok: false, supported: true, enabled: false, ...EMPTY_RUN_INFO, detail: `"${SYSTEMD_TIMER_NAME}" is not registered \u2014 run \`mmi-hub autoupdate on\`` };
2501
2427
  }
2502
2428
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2503
- const launcherPath = (0, import_node_path13.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
2429
+ const launcherPath = (0, import_node_path12.join)(statePaths(env).root, POSIX_LAUNCHER_FILE);
2504
2430
  const fail = (detail) => ({ ok: false, supported: true, enabled: true, ...EMPTY_RUN_INFO, detail });
2505
2431
  if (!service.includes(launcherPath)) {
2506
2432
  return fail(`"${SYSTEMD_SERVICE_NAME}" does not run the reconcile launcher ${launcherPath} \u2014 run \`mmi-hub autoupdate on\``);
@@ -2539,10 +2465,10 @@ function installWindowsTask(env) {
2539
2465
  const paths = ensureState(env);
2540
2466
  const userId = `${env.USERDOMAIN || env.COMPUTERNAME || ""}\\${env.USERNAME || ""}`.replace(/^\\/, "");
2541
2467
  if (!env.USERNAME) return { ok: false, detail: "cannot resolve the registering user (USERNAME unset) \u2014 the task principal must be explicit" };
2542
- const launcherPath = (0, import_node_path13.join)(paths.root, LAUNCHER_FILE);
2543
- (0, import_node_fs16.writeFileSync)(launcherPath, launcherVbs(process.execPath, hubDist), "utf8");
2544
- const xmlPath = (0, import_node_path13.join)(paths.root, "task.xml");
2545
- (0, import_node_fs16.writeFileSync)(xmlPath, "\uFEFF" + taskXml(launcherPath, paths.root, userId, localStartBoundary(/* @__PURE__ */ new Date())), "utf16le");
2468
+ const launcherPath = (0, import_node_path12.join)(paths.root, LAUNCHER_FILE);
2469
+ (0, import_node_fs15.writeFileSync)(launcherPath, launcherVbs(process.execPath, hubDist), "utf8");
2470
+ const xmlPath = (0, import_node_path12.join)(paths.root, "task.xml");
2471
+ (0, import_node_fs15.writeFileSync)(xmlPath, "\uFEFF" + taskXml(launcherPath, paths.root, userId, localStartBoundary(/* @__PURE__ */ new Date())), "utf16le");
2546
2472
  const create = schtasks(["/create", "/tn", TASK_NAME, "/xml", xmlPath, "/f"]);
2547
2473
  if (create.status !== 0) {
2548
2474
  const denied = /access is denied/i.test(create.stderr + create.stdout);
@@ -2558,11 +2484,11 @@ function refreshPosixLauncher(env) {
2558
2484
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2559
2485
  if (!hubDist) return null;
2560
2486
  const paths = ensureState(env);
2561
- const launcherPath = (0, import_node_path13.join)(paths.root, POSIX_LAUNCHER_FILE);
2487
+ const launcherPath = (0, import_node_path12.join)(paths.root, POSIX_LAUNCHER_FILE);
2562
2488
  const desired = launcherSh(process.execPath, hubDist);
2563
2489
  if (readFileOrNull(launcherPath) === desired) return null;
2564
- (0, import_node_fs16.writeFileSync)(launcherPath, desired, "utf8");
2565
- (0, import_node_fs16.chmodSync)(launcherPath, 493);
2490
+ (0, import_node_fs15.writeFileSync)(launcherPath, desired, "utf8");
2491
+ (0, import_node_fs15.chmodSync)(launcherPath, 493);
2566
2492
  return launcherPath;
2567
2493
  }
2568
2494
  function installLaunchd(env) {
@@ -2574,13 +2500,13 @@ function installLaunchd(env) {
2574
2500
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2575
2501
  if (!hubDist) return { ok: false, detail: "cannot resolve the global @mutmutco/hub dist \u2014 run `npm install -g @mutmutco/hub` first" };
2576
2502
  const paths = ensureState(env);
2577
- const launcherPath = (0, import_node_path13.join)(paths.root, POSIX_LAUNCHER_FILE);
2578
- (0, import_node_fs16.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
2579
- (0, import_node_fs16.chmodSync)(launcherPath, 493);
2580
- const agentsDir = (0, import_node_path13.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents");
2581
- (0, import_node_fs16.mkdirSync)(agentsDir, { recursive: true });
2582
- const plistPath = (0, import_node_path13.join)(agentsDir, LAUNCHD_PLIST_NAME);
2583
- (0, import_node_fs16.writeFileSync)(plistPath, launchdPlist(launcherPath, paths.root), "utf8");
2503
+ const launcherPath = (0, import_node_path12.join)(paths.root, POSIX_LAUNCHER_FILE);
2504
+ (0, import_node_fs15.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
2505
+ (0, import_node_fs15.chmodSync)(launcherPath, 493);
2506
+ const agentsDir = (0, import_node_path12.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents");
2507
+ (0, import_node_fs15.mkdirSync)(agentsDir, { recursive: true });
2508
+ const plistPath = (0, import_node_path12.join)(agentsDir, LAUNCHD_PLIST_NAME);
2509
+ (0, import_node_fs15.writeFileSync)(plistPath, launchdPlist(launcherPath, paths.root), "utf8");
2584
2510
  launchctl(["bootout", `gui/${uid()}/${LAUNCHD_LABEL}`]);
2585
2511
  const load = launchctl(["bootstrap", `gui/${uid()}`, plistPath]);
2586
2512
  if (load.status !== 0) {
@@ -2598,13 +2524,13 @@ function installSystemdTimer(env) {
2598
2524
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2599
2525
  if (!hubDist) return { ok: false, detail: "cannot resolve the global @mutmutco/hub dist \u2014 run `npm install -g @mutmutco/hub` first" };
2600
2526
  const paths = ensureState(env);
2601
- const launcherPath = (0, import_node_path13.join)(paths.root, POSIX_LAUNCHER_FILE);
2602
- (0, import_node_fs16.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
2603
- (0, import_node_fs16.chmodSync)(launcherPath, 493);
2604
- const unitDir = (0, import_node_path13.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
2605
- (0, import_node_fs16.mkdirSync)(unitDir, { recursive: true });
2606
- (0, import_node_fs16.writeFileSync)((0, import_node_path13.join)(unitDir, SYSTEMD_SERVICE_NAME), systemdServiceUnit(launcherPath, paths.root), "utf8");
2607
- (0, import_node_fs16.writeFileSync)((0, import_node_path13.join)(unitDir, SYSTEMD_TIMER_NAME), systemdTimerUnit(), "utf8");
2527
+ const launcherPath = (0, import_node_path12.join)(paths.root, POSIX_LAUNCHER_FILE);
2528
+ (0, import_node_fs15.writeFileSync)(launcherPath, launcherSh(process.execPath, hubDist), "utf8");
2529
+ (0, import_node_fs15.chmodSync)(launcherPath, 493);
2530
+ const unitDir = (0, import_node_path12.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
2531
+ (0, import_node_fs15.mkdirSync)(unitDir, { recursive: true });
2532
+ (0, import_node_fs15.writeFileSync)((0, import_node_path12.join)(unitDir, SYSTEMD_SERVICE_NAME), systemdServiceUnit(launcherPath, paths.root), "utf8");
2533
+ (0, import_node_fs15.writeFileSync)((0, import_node_path12.join)(unitDir, SYSTEMD_TIMER_NAME), systemdTimerUnit(), "utf8");
2608
2534
  const reload = systemctlUser(["daemon-reload"]);
2609
2535
  if (reload.status !== 0) {
2610
2536
  return { ok: false, detail: `systemctl --user daemon-reload failed: ${(reload.stderr || reload.stdout).trim() || "unknown error \u2014 is a user systemd instance running?"}` };
@@ -2642,28 +2568,28 @@ function uninstallWindowsTask(env) {
2642
2568
  return { ok: true, detail: `automatic updates off \u2014 removed "${TASK_NAME}"; installed tooling was kept` };
2643
2569
  }
2644
2570
  function uninstallLaunchd(env) {
2645
- const plistPath = (0, import_node_path13.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
2571
+ const plistPath = (0, import_node_path12.join)((0, import_node_os6.homedir)(), "Library", "LaunchAgents", LAUNCHD_PLIST_NAME);
2646
2572
  const boot = launchctl(["bootout", `gui/${uid()}/${LAUNCHD_LABEL}`]);
2647
- if (boot.status !== 0 && (0, import_node_fs16.existsSync)(plistPath)) {
2573
+ if (boot.status !== 0 && (0, import_node_fs15.existsSync)(plistPath)) {
2648
2574
  return { ok: false, detail: `launchctl bootout failed: ${(boot.stderr || boot.stdout).trim() || "unknown error"}` };
2649
2575
  }
2650
2576
  try {
2651
- (0, import_node_fs16.rmSync)(plistPath, { force: true });
2577
+ (0, import_node_fs15.rmSync)(plistPath, { force: true });
2652
2578
  } catch {
2653
2579
  }
2654
2580
  dropLauncher(env, POSIX_LAUNCHER_FILE);
2655
2581
  return { ok: true, detail: `automatic updates off \u2014 removed "${LAUNCHD_LABEL}"; installed tooling was kept` };
2656
2582
  }
2657
2583
  function uninstallSystemdTimer(env) {
2658
- const unitDir = (0, import_node_path13.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
2659
- const timerPath = (0, import_node_path13.join)(unitDir, SYSTEMD_TIMER_NAME);
2584
+ const unitDir = (0, import_node_path12.join)((0, import_node_os6.homedir)(), ".config", "systemd", "user");
2585
+ const timerPath = (0, import_node_path12.join)(unitDir, SYSTEMD_TIMER_NAME);
2660
2586
  const disable = systemctlUser(["disable", "--now", SYSTEMD_TIMER_NAME]);
2661
- if (disable.status !== 0 && (0, import_node_fs16.existsSync)(timerPath)) {
2587
+ if (disable.status !== 0 && (0, import_node_fs15.existsSync)(timerPath)) {
2662
2588
  return { ok: false, detail: `systemctl --user disable --now ${SYSTEMD_TIMER_NAME} failed: ${(disable.stderr || disable.stdout).trim() || "unknown error"}` };
2663
2589
  }
2664
2590
  try {
2665
- (0, import_node_fs16.rmSync)(timerPath, { force: true });
2666
- (0, import_node_fs16.rmSync)((0, import_node_path13.join)(unitDir, SYSTEMD_SERVICE_NAME), { force: true });
2591
+ (0, import_node_fs15.rmSync)(timerPath, { force: true });
2592
+ (0, import_node_fs15.rmSync)((0, import_node_path12.join)(unitDir, SYSTEMD_SERVICE_NAME), { force: true });
2667
2593
  } catch {
2668
2594
  }
2669
2595
  systemctlUser(["daemon-reload"]);
@@ -2678,16 +2604,16 @@ function uninstallTask(env = process.env) {
2678
2604
  }
2679
2605
  function dropLauncher(env, file) {
2680
2606
  try {
2681
- (0, import_node_fs16.rmSync)((0, import_node_path13.join)(statePaths(env).root, file), { force: true });
2607
+ (0, import_node_fs15.rmSync)((0, import_node_path12.join)(statePaths(env).root, file), { force: true });
2682
2608
  } catch {
2683
2609
  }
2684
2610
  }
2685
2611
 
2686
2612
  // src/status.ts
2687
- var import_node_fs17 = require("node:fs");
2613
+ var import_node_fs16 = require("node:fs");
2688
2614
  function readJournal(path) {
2689
2615
  try {
2690
- const events = (0, import_node_fs17.readFileSync)(path, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
2616
+ const events = (0, import_node_fs16.readFileSync)(path, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
2691
2617
  try {
2692
2618
  return JSON.parse(line);
2693
2619
  } catch {
@@ -2718,8 +2644,14 @@ function hubStatus(hubVersion, env = process.env, invokedPath = process.argv[1])
2718
2644
  const hubDist = globalDist(env, "@mutmutco/hub", "dist/index.cjs");
2719
2645
  const globalHubVersion = hubDist ? probeVersion(hubDist) : null;
2720
2646
  actual.set("hub", globalHubVersion ? { version: globalHubVersion, staged: null, location: hubDist, detail: "absolute global Hub binary" } : { version: hubVersion, staged: null, location: invokedPath ?? null, detail: "currently executing Hub bundle (global package location unavailable)" });
2721
- const cliProbe = probeCliInstallation(env);
2722
- actual.set("cli", { version: cliProbe.version, staged: null, location: cliProbe.location, detail: cliProbe.detail });
2647
+ const cliDist = globalDist(env, "@mutmutco/cli", "dist/index.cjs");
2648
+ const cliVersion = cliDist ? probeVersion(cliDist) : null;
2649
+ actual.set("cli", {
2650
+ version: cliVersion,
2651
+ staged: null,
2652
+ location: cliDist,
2653
+ detail: cliVersion ? `absolute binary reported ${cliVersion}` : "global @mutmutco/cli binary was not readable"
2654
+ });
2723
2655
  for (const surface of probes.filter((probe) => probe.present)) {
2724
2656
  if (surface.id === "claude") {
2725
2657
  const probe = probeNativeHostInstallation("claude", env);
@@ -3087,14 +3019,14 @@ function startSpinner(enabled) {
3087
3019
  }
3088
3020
 
3089
3021
  // src/stamp.ts
3090
- var import_node_fs18 = require("node:fs");
3022
+ var import_node_fs17 = require("node:fs");
3091
3023
  var ALWAYS_ARMED = ["cli", "updater"];
3092
3024
  var PLUGIN_ARMS = /* @__PURE__ */ new Set(["claude", "codex", "jervcode", "cursor", "hermes"]);
3093
3025
  function fleetStamp(env = process.env) {
3094
3026
  const paths = statePaths(env);
3095
3027
  let events = [];
3096
3028
  try {
3097
- events = (0, import_node_fs18.readFileSync)(paths.journalPath, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
3029
+ events = (0, import_node_fs17.readFileSync)(paths.journalPath, "utf8").split("\n").filter((line) => line.trim()).map((line) => {
3098
3030
  try {
3099
3031
  return JSON.parse(line);
3100
3032
  } catch {
@@ -3144,7 +3076,7 @@ function fleetStamp(env = process.env) {
3144
3076
  // src/index.ts
3145
3077
  function ownVersion() {
3146
3078
  try {
3147
- return JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path14.join)(__dirname, "..", "package.json"), "utf8")).version;
3079
+ return JSON.parse((0, import_node_fs18.readFileSync)((0, import_node_path13.join)(__dirname, "..", "package.json"), "utf8")).version;
3148
3080
  } catch {
3149
3081
  return "0.0.0";
3150
3082
  }
@@ -3183,7 +3115,7 @@ function handOff(reexec, args, json) {
3183
3115
 
3184
3116
  `);
3185
3117
  }
3186
- const child = (0, import_node_child_process10.spawnSync)(process.execPath, [reexec.dist, ...args], {
3118
+ const child = (0, import_node_child_process9.spawnSync)(process.execPath, [reexec.dist, ...args], {
3187
3119
  stdio: "inherit",
3188
3120
  windowsHide: true,
3189
3121
  env: { ...process.env, MMI_UPDATER_REEXEC: "1" }
@@ -3346,7 +3278,6 @@ if (typeof require !== "undefined" && require.main === module) {
3346
3278
  retryHint,
3347
3279
  schedulePendingWatcher,
3348
3280
  schedulerStatus,
3349
- selfDist,
3350
3281
  sharedDocLockPath,
3351
3282
  sharedDocLockTimeoutReceipt,
3352
3283
  shouldHandOff,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/hub",
3
- "version": "4.3.6",
3
+ "version": "4.3.7",
4
4
  "description": "Install and maintain the MMI CLI and every present host surface from one release-gated Hub command.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",