@mutmutco/hub 4.6.3 → 4.6.5
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 +100 -22
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
buildWatcherCommand: () => buildWatcherCommand,
|
|
27
27
|
checkAtomicity: () => checkAtomicity,
|
|
28
28
|
claudeArm: () => claudeArm,
|
|
29
|
+
claudeCatalogMmiVersion: () => claudeCatalogMmiVersion,
|
|
29
30
|
clearLaunchTarget: () => clearLaunchTarget,
|
|
30
31
|
clearPending: () => clearPending,
|
|
31
32
|
codexArm: () => codexArm,
|
|
@@ -79,6 +80,7 @@ __export(index_exports, {
|
|
|
79
80
|
sharedDocLockTimeoutReceipt: () => sharedDocLockTimeoutReceipt,
|
|
80
81
|
shippedTargetFrom: () => shippedTargetFrom,
|
|
81
82
|
shouldHandOff: () => shouldHandOff,
|
|
83
|
+
stagingPrunePreview: () => stagingPrunePreview,
|
|
82
84
|
statusScreen: () => statusScreen,
|
|
83
85
|
surfaceArmPlan: () => surfaceArmPlan,
|
|
84
86
|
systemdServiceUnit: () => systemdServiceUnit,
|
|
@@ -2510,6 +2512,9 @@ function claudeHomeDir(env) {
|
|
|
2510
2512
|
function claudeMarketplacesPath(env) {
|
|
2511
2513
|
return env.MMI_UPDATER_CLAUDE_MARKETPLACES || (0, import_node_path10.join)(claudeHomeDir(env), "plugins", "known_marketplaces.json");
|
|
2512
2514
|
}
|
|
2515
|
+
function claudeLaunchTargetPath(env) {
|
|
2516
|
+
return (0, import_node_path10.join)(claudeHomeDir(env), "plugins", "staging", "launch-target.json");
|
|
2517
|
+
}
|
|
2513
2518
|
function ensureClaudeMarketplace(env) {
|
|
2514
2519
|
const path = claudeMarketplacesPath(env);
|
|
2515
2520
|
let body;
|
|
@@ -2555,7 +2560,30 @@ function claudeNpmEnv(env) {
|
|
|
2555
2560
|
return { ...env, npm_config_allow_remote: "all" };
|
|
2556
2561
|
}
|
|
2557
2562
|
function probeClaudeLaunchStaging(env = process.env) {
|
|
2558
|
-
return probeLaunchTargetVersion((
|
|
2563
|
+
return probeLaunchTargetVersion(claudeLaunchTargetPath(env), claudeMarkerVersion);
|
|
2564
|
+
}
|
|
2565
|
+
function catalogVersionAt(path, pick) {
|
|
2566
|
+
try {
|
|
2567
|
+
const version = pick(JSON.parse((0, import_node_fs14.readFileSync)(path, "utf8")));
|
|
2568
|
+
return typeof version === "string" && parseSemver(version) ? version : null;
|
|
2569
|
+
} catch {
|
|
2570
|
+
return null;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
function claudeCatalogMmiVersion(env) {
|
|
2574
|
+
let clone = null;
|
|
2575
|
+
try {
|
|
2576
|
+
const location = JSON.parse((0, import_node_fs14.readFileSync)(claudeMarketplacesPath(env), "utf8"))?.mutmutco?.installLocation;
|
|
2577
|
+
clone = typeof location === "string" && location.trim() ? location : null;
|
|
2578
|
+
} catch {
|
|
2579
|
+
clone = null;
|
|
2580
|
+
}
|
|
2581
|
+
const root = clone ?? (0, import_node_path10.join)(claudeHomeDir(env), "plugins", "marketplaces", "mutmutco");
|
|
2582
|
+
const fromCatalog = catalogVersionAt(
|
|
2583
|
+
(0, import_node_path10.join)(root, ".claude-plugin", "marketplace.json"),
|
|
2584
|
+
(body) => Array.isArray(body?.plugins) ? body.plugins.find((row) => row?.name === "mmi")?.version : null
|
|
2585
|
+
);
|
|
2586
|
+
return fromCatalog ?? catalogVersionAt((0, import_node_path10.join)(root, ".claude-plugin", "plugin.json"), (body) => body?.version);
|
|
2559
2587
|
}
|
|
2560
2588
|
function claudeArm(options) {
|
|
2561
2589
|
const env = options.env ?? process.env;
|
|
@@ -2588,7 +2616,7 @@ function claudeArm(options) {
|
|
|
2588
2616
|
}
|
|
2589
2617
|
if (!marketplaceTrust.ok) return result(from, target, "defer", marketplaceTrust.detail ?? "cannot trust the mutmutco marketplace registration");
|
|
2590
2618
|
const pluginsRoot = claudePluginsRoot(env);
|
|
2591
|
-
const launchTargetPath = (
|
|
2619
|
+
const launchTargetPath = claudeLaunchTargetPath(env);
|
|
2592
2620
|
if (options.dryRun) {
|
|
2593
2621
|
return result(from, target, "ok", `dry-run: would refresh mutmutco, stage ${target} on the Claude volume, and converge mmi@mutmutco ${from ?? "absent"} -> ${target}`);
|
|
2594
2622
|
}
|
|
@@ -2602,6 +2630,10 @@ function claudeArm(options) {
|
|
|
2602
2630
|
clearLaunchTarget(launchTargetPath);
|
|
2603
2631
|
return result(from, target, "ok", `catalog refreshed; installed+enabled at target ${target}`);
|
|
2604
2632
|
}
|
|
2633
|
+
const catalogVersion = claudeCatalogMmiVersion(env);
|
|
2634
|
+
if (catalogVersion && compareSemver(catalogVersion, target) < 0) {
|
|
2635
|
+
return result(from, target, "defer", `catalog not yet at target (catalog ${catalogVersion} < target ${target}; release-align pending)`);
|
|
2636
|
+
}
|
|
2605
2637
|
const incomingRoot = (0, import_node_path10.join)(pluginsRoot, "staging", "incoming");
|
|
2606
2638
|
const incoming = (0, import_node_path10.join)(incomingRoot, target);
|
|
2607
2639
|
const priorLaunch = readLaunchTarget(launchTargetPath);
|
|
@@ -2687,12 +2719,13 @@ function codexArm(options) {
|
|
|
2687
2719
|
if (options.dryRun) {
|
|
2688
2720
|
return { surface: "codex", from, to: options.target, verdict: "ok", detail: `dry-run: would upgrade mutmutco and converge mmi@mutmutco ${from ?? "absent"} -> ${options.target}` };
|
|
2689
2721
|
}
|
|
2690
|
-
const
|
|
2722
|
+
const npmEnv = claudeNpmEnv(env);
|
|
2723
|
+
const upgrade = runner("codex", ["plugin", "marketplace", "upgrade", "mutmutco", "--json"], npmEnv);
|
|
2691
2724
|
let upgradeJson = parseJson(upgrade);
|
|
2692
2725
|
if ((upgrade.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) && NOT_CONFIGURED.test(failure(upgrade))) {
|
|
2693
|
-
const add = runner("codex", ["plugin", "marketplace", "add", repoUrl],
|
|
2726
|
+
const add = runner("codex", ["plugin", "marketplace", "add", repoUrl], npmEnv);
|
|
2694
2727
|
if (add.status !== 0) return { surface: "codex", from, to: options.target, verdict: "defer", detail: `mutmutco marketplace was not configured and marketplace add failed: ${failure(add)}` };
|
|
2695
|
-
const retry = runner("codex", ["plugin", "marketplace", "upgrade", "mutmutco", "--json"],
|
|
2728
|
+
const retry = runner("codex", ["plugin", "marketplace", "upgrade", "mutmutco", "--json"], npmEnv);
|
|
2696
2729
|
upgradeJson = parseJson(retry);
|
|
2697
2730
|
if (retry.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) {
|
|
2698
2731
|
return { surface: "codex", from, to: options.target, verdict: "defer", detail: `marketplace upgrade failed after registration: ${failure(retry)}` };
|
|
@@ -2702,8 +2735,8 @@ function codexArm(options) {
|
|
|
2702
2735
|
}
|
|
2703
2736
|
let observed = codexMmi(runner, env);
|
|
2704
2737
|
if (observed.error) return { surface: "codex", from, to: options.target, verdict: "defer", detail: observed.error };
|
|
2705
|
-
if (!observed.row || observed.row.installed
|
|
2706
|
-
const install = runner("codex", ["plugin", "add", "mmi@mutmutco", "--json"],
|
|
2738
|
+
if (!observed.row || !convergedAtOrAbove(observed.row.version, options.target, observed.row.installed === true && observed.row.enabled === true)) {
|
|
2739
|
+
const install = runner("codex", ["plugin", "add", "mmi@mutmutco", "--json"], npmEnv);
|
|
2707
2740
|
if (install.status !== 0) {
|
|
2708
2741
|
return { surface: "codex", from, to: options.target, verdict: "defer", detail: `plugin add failed: ${failure(install)}` };
|
|
2709
2742
|
}
|
|
@@ -3323,28 +3356,65 @@ function generationSets(root) {
|
|
|
3323
3356
|
if (children.some((name) => parseSemver(name))) return [root];
|
|
3324
3357
|
return children.map((name) => (0, import_node_path14.join)(root, name)).filter((path) => listDirs(path).some((name) => parseSemver(name)));
|
|
3325
3358
|
}
|
|
3326
|
-
function pruneGenerations(root, category, dryRun) {
|
|
3327
|
-
|
|
3359
|
+
function pruneGenerations(root, category, dryRun, options = {}) {
|
|
3360
|
+
const protectedPaths = options.protectedPaths ?? /* @__PURE__ */ new Set();
|
|
3361
|
+
const isProtected = (path) => {
|
|
3362
|
+
const dir = path.replaceAll("\\", "/");
|
|
3363
|
+
for (const ref of protectedPaths) {
|
|
3364
|
+
if (ref === dir || ref.startsWith(`${dir}/`)) return true;
|
|
3365
|
+
}
|
|
3366
|
+
return false;
|
|
3367
|
+
};
|
|
3368
|
+
const prunablePaths = (set, versions, incoming) => {
|
|
3369
|
+
const tree = incoming && parseSemver(incoming) && !versions.includes(incoming) ? [...versions, incoming] : versions;
|
|
3370
|
+
return [...tree].sort((a, b) => compareSemver(b, a)).slice(KEEP_GENERATIONS).map((version) => (0, import_node_path14.join)(set, version)).filter((path) => !isProtected(path));
|
|
3371
|
+
};
|
|
3372
|
+
const relName = (path) => (0, import_node_path14.relative)(root, path).replaceAll("\\", "/");
|
|
3373
|
+
const collect = (incoming) => {
|
|
3374
|
+
const candidates = [];
|
|
3375
|
+
for (const set of generationSets(root)) {
|
|
3376
|
+
candidates.push(...prunablePaths(set, listDirs(set).filter((name) => parseSemver(name)), incoming));
|
|
3377
|
+
}
|
|
3378
|
+
return candidates;
|
|
3379
|
+
};
|
|
3328
3380
|
const failures = [];
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
for (const
|
|
3332
|
-
if (dryRun) {
|
|
3333
|
-
reaped += 1;
|
|
3334
|
-
continue;
|
|
3335
|
-
}
|
|
3381
|
+
const removed = [];
|
|
3382
|
+
if (!dryRun) {
|
|
3383
|
+
for (const path of collect()) {
|
|
3336
3384
|
try {
|
|
3337
|
-
(0, import_node_fs20.rmSync)(
|
|
3338
|
-
|
|
3385
|
+
(0, import_node_fs20.rmSync)(path, { recursive: true, force: true });
|
|
3386
|
+
removed.push(path);
|
|
3339
3387
|
} catch (error) {
|
|
3340
|
-
failures.push(`${
|
|
3388
|
+
failures.push(`${(0, import_node_path14.basename)(path)}: ${error?.code ?? error?.message ?? error}`);
|
|
3341
3389
|
}
|
|
3342
3390
|
}
|
|
3343
3391
|
}
|
|
3344
|
-
|
|
3392
|
+
const pruned = dryRun ? collect() : removed;
|
|
3393
|
+
const preview = dryRun && options.incomingTarget ? collect(options.incomingTarget) : [];
|
|
3394
|
+
if (!pruned.length && !failures.length && !preview.length) return { category, reaped: 0, verdict: "skip", detail: `${root}: within keep-${KEEP_GENERATIONS}` };
|
|
3345
3395
|
const verb = dryRun ? "dry-run: would prune" : "pruned";
|
|
3346
3396
|
const stuck = failures.length ? `; ${failures.length} locked (${failures.join(", ")})` : "";
|
|
3347
|
-
|
|
3397
|
+
const segments = [`${verb} ${pruned.length} generation(s) below keep-${KEEP_GENERATIONS} under ${root}${pruned.length ? `: ${pruned.map(relName).join(", ")}` : ""}`];
|
|
3398
|
+
if (preview.length) segments.push(`after staging ${options.incomingTarget}: would prune ${preview.length} generation(s) below keep-${KEEP_GENERATIONS} under ${root}: ${preview.map(relName).join(", ")}`);
|
|
3399
|
+
return { category, reaped: pruned.length, verdict: failures.length ? "defer" : "ok", detail: `${segments.join("; ")}${stuck}` };
|
|
3400
|
+
}
|
|
3401
|
+
function liveGenerationRefs(env, paths) {
|
|
3402
|
+
const refs = /* @__PURE__ */ new Set();
|
|
3403
|
+
const launch = readLaunchTarget(claudeLaunchTargetPath(env));
|
|
3404
|
+
if (launch?.incoming) refs.add(launch.incoming.replaceAll("\\", "/"));
|
|
3405
|
+
for (const pending of readPending(paths)) {
|
|
3406
|
+
for (const dir of pending.dirs) refs.add(dir.replaceAll("\\", "/"));
|
|
3407
|
+
}
|
|
3408
|
+
return refs;
|
|
3409
|
+
}
|
|
3410
|
+
function stagingPrunePreview(options) {
|
|
3411
|
+
const env = options.env ?? process.env;
|
|
3412
|
+
const startedAt = import_node_perf_hooks.performance.now();
|
|
3413
|
+
try {
|
|
3414
|
+
return { ...pruneGenerations(options.paths.staging, "staging-prune-preview", true, { incomingTarget: options.incomingTarget, protectedPaths: liveGenerationRefs(env, options.paths) }), durationMs: elapsedMs(startedAt) };
|
|
3415
|
+
} catch (error) {
|
|
3416
|
+
return { category: "staging-prune-preview", reaped: 0, verdict: "fail", detail: `reap failed: ${error?.message ?? error}`, durationMs: elapsedMs(startedAt) };
|
|
3417
|
+
}
|
|
3348
3418
|
}
|
|
3349
3419
|
var LEASE_STEAL_SCRATCH = /^lease\.lock\.stale-\d+$/;
|
|
3350
3420
|
function atomicWriteScratch(path) {
|
|
@@ -3413,8 +3483,9 @@ function reap(options) {
|
|
|
3413
3483
|
}
|
|
3414
3484
|
};
|
|
3415
3485
|
const atomicWritePaths = [claudeMarketplacesPath(env)];
|
|
3486
|
+
const protectedPaths = liveGenerationRefs(env, paths);
|
|
3416
3487
|
return [
|
|
3417
|
-
guarded("staging-prune", () => pruneGenerations(paths.staging, "staging-prune", dryRun)),
|
|
3488
|
+
guarded("staging-prune", () => pruneGenerations(paths.staging, "staging-prune", dryRun, { protectedPaths })),
|
|
3418
3489
|
guarded("scratch", () => reapScratch({ root: paths.root, atomicWritePaths }, dryRun)),
|
|
3419
3490
|
guarded("cursor-retire", () => retireCursor({ paths, dryRun, env }))
|
|
3420
3491
|
];
|
|
@@ -3533,6 +3604,11 @@ async function reconcile(options) {
|
|
|
3533
3604
|
say(`target v${summary.target} (${summary.gate})`);
|
|
3534
3605
|
phase("resolve", "ok");
|
|
3535
3606
|
options.onTargetResolved?.(summary.target, summary.gate);
|
|
3607
|
+
if (options.dryRun && summary.target) {
|
|
3608
|
+
const preview = stagingPrunePreview({ paths, env, incomingTarget: summary.target });
|
|
3609
|
+
summary.reap.push(preview);
|
|
3610
|
+
journal({ kind: "reap", surface: preview.category, verdict: preview.verdict, count: preview.reaped, detail: preview.detail, durationMs: preview.durationMs });
|
|
3611
|
+
}
|
|
3536
3612
|
phase("check", "running");
|
|
3537
3613
|
say("updater: self-bootstrap");
|
|
3538
3614
|
const selfStartedAt = import_node_perf_hooks2.performance.now();
|
|
@@ -4457,6 +4533,7 @@ if (typeof require !== "undefined" && require.main === module) {
|
|
|
4457
4533
|
buildWatcherCommand,
|
|
4458
4534
|
checkAtomicity,
|
|
4459
4535
|
claudeArm,
|
|
4536
|
+
claudeCatalogMmiVersion,
|
|
4460
4537
|
clearLaunchTarget,
|
|
4461
4538
|
clearPending,
|
|
4462
4539
|
codexArm,
|
|
@@ -4510,6 +4587,7 @@ if (typeof require !== "undefined" && require.main === module) {
|
|
|
4510
4587
|
sharedDocLockTimeoutReceipt,
|
|
4511
4588
|
shippedTargetFrom,
|
|
4512
4589
|
shouldHandOff,
|
|
4590
|
+
stagingPrunePreview,
|
|
4513
4591
|
statusScreen,
|
|
4514
4592
|
surfaceArmPlan,
|
|
4515
4593
|
systemdServiceUnit,
|
package/package.json
CHANGED