@mutmutco/hub 4.0.13 → 4.0.15
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 +38 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -382,7 +382,11 @@ function enumerateSurfaces(env = process.env) {
|
|
|
382
382
|
return [
|
|
383
383
|
{ id: "claude", marker: (0, import_node_path3.join)(home, ".claude", "plugins", "installed_plugins.json") },
|
|
384
384
|
{ id: "codex", marker: (0, import_node_path3.join)(codexHome, "plugins", "installed_plugins.json") },
|
|
385
|
-
|
|
385
|
+
// The host, not the payload (#4951, #5356): this marker used to be plugins/local/mmi — the MMI
|
|
386
|
+
// plugin tree itself — so a machine running Cursor WITHOUT the plugin enumerated as "no Cursor"
|
|
387
|
+
// and the arm could never make the first install. The plugin's absence is a converge action, not
|
|
388
|
+
// a skip. The host root mirrors surfaceConfigRoot('cursor') in cli/src/plugin-guard-io.ts.
|
|
389
|
+
{ id: "cursor", marker: (0, import_node_path3.join)(home, ".cursor") },
|
|
386
390
|
{ id: "kilo", marker: (0, import_node_path3.join)(home, ".config", "kilo") },
|
|
387
391
|
// The host, not the payload (#4951): this marker used to be plugins/managed/mmi — the MMI plugin
|
|
388
392
|
// itself — so a machine running Kimi WITHOUT the plugin enumerated as "no Kimi" and the arm
|
|
@@ -561,6 +565,8 @@ var import_node_child_process5 = require("node:child_process");
|
|
|
561
565
|
var import_node_fs7 = require("node:fs");
|
|
562
566
|
var import_node_os3 = require("node:os");
|
|
563
567
|
var import_node_path6 = require("node:path");
|
|
568
|
+
var REPO_URL_DEFAULT = "https://github.com/mutmutco/MMI-Hub.git";
|
|
569
|
+
var MMI_MARKETPLACE_REPO = "mutmutco/MMI-Hub";
|
|
564
570
|
function convergedAtOrAbove(installed, target, healthy) {
|
|
565
571
|
return healthy && typeof installed === "string" && compareSemver(installed, target) >= 0;
|
|
566
572
|
}
|
|
@@ -628,11 +634,20 @@ function ensureClaudeSingleWriter(env, dryRun) {
|
|
|
628
634
|
let body;
|
|
629
635
|
try {
|
|
630
636
|
body = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
|
|
631
|
-
} catch {
|
|
637
|
+
} catch (error) {
|
|
638
|
+
if (error?.code === "ENOENT") return { ok: false, detail: `${path} does not exist \u2014 mutmutco marketplace is not registered`, unregistered: true };
|
|
632
639
|
return { ok: false, detail: `cannot read ${path}` };
|
|
633
640
|
}
|
|
634
641
|
const registration = body.mutmutco;
|
|
635
|
-
if (!registration || typeof registration !== "object") return { ok: false, detail: "mutmutco marketplace is not registered" };
|
|
642
|
+
if (!registration || typeof registration !== "object") return { ok: false, detail: "mutmutco marketplace is not registered", unregistered: true };
|
|
643
|
+
const source = registration.source;
|
|
644
|
+
const registeredRepo = source && typeof source === "object" && source.source === "github" ? source.repo : null;
|
|
645
|
+
if (registeredRepo !== MMI_MARKETPLACE_REPO) {
|
|
646
|
+
return {
|
|
647
|
+
ok: false,
|
|
648
|
+
detail: `mutmutco marketplace is registered to ${registeredRepo ?? "a non-github source"}, not ${MMI_MARKETPLACE_REPO} \u2014 a retired or foreign repo is squatting the name; re-register it (claude plugin marketplace remove mutmutco && claude plugin marketplace add ${REPO_URL_DEFAULT}) before the updater can trust it`
|
|
649
|
+
};
|
|
650
|
+
}
|
|
636
651
|
if (registration.autoUpdate !== true) return { ok: true };
|
|
637
652
|
if (dryRun) return { ok: true, detail: "would disable Claude background autoUpdate (updater is the single writer)" };
|
|
638
653
|
const quiescence = claudeHostRunning(env);
|
|
@@ -653,10 +668,16 @@ function ensureClaudeSingleWriter(env, dryRun) {
|
|
|
653
668
|
function claudeArm(options) {
|
|
654
669
|
const env = options.env ?? process.env;
|
|
655
670
|
const runner = options.runner ?? runHostCommand;
|
|
671
|
+
const repoUrl = options.repoUrl ?? (env.MMI_UPDATER_REPO || REPO_URL_DEFAULT);
|
|
656
672
|
const before = claudeMmi(runner, env);
|
|
657
673
|
if (before.error) return { surface: "claude", from: null, to: options.target, verdict: "defer", detail: before.error };
|
|
658
674
|
const from = before.row?.version ?? null;
|
|
659
|
-
|
|
675
|
+
let singleWriter = ensureClaudeSingleWriter(env, options.dryRun);
|
|
676
|
+
if (!singleWriter.ok && singleWriter.unregistered) {
|
|
677
|
+
const add = runner("claude", ["plugin", "marketplace", "add", repoUrl], env);
|
|
678
|
+
if (add.status !== 0) return { surface: "claude", from, to: options.target, verdict: "defer", detail: `mutmutco marketplace was not registered and marketplace add failed: ${failure(add)}` };
|
|
679
|
+
singleWriter = ensureClaudeSingleWriter(env, options.dryRun);
|
|
680
|
+
}
|
|
660
681
|
if (!singleWriter.ok) return { surface: "claude", from, to: options.target, verdict: "defer", detail: singleWriter.detail ?? "cannot establish updater as the single writer" };
|
|
661
682
|
if (options.dryRun) {
|
|
662
683
|
const writer = singleWriter.detail ? `; ${singleWriter.detail}` : "";
|
|
@@ -702,9 +723,11 @@ function codexMmi(runner, env) {
|
|
|
702
723
|
if (!parsed || !Array.isArray(parsed.installed)) return { row: null, error: `codex plugin list --json failed: ${failure(result)}` };
|
|
703
724
|
return { row: parsed.installed.find((row) => row.pluginId === "mmi@mutmutco") ?? null };
|
|
704
725
|
}
|
|
726
|
+
var NOT_CONFIGURED = /not configured|is not registered|not a Git marketplace/i;
|
|
705
727
|
function codexArm(options) {
|
|
706
728
|
const env = options.env ?? process.env;
|
|
707
729
|
const runner = options.runner ?? runHostCommand;
|
|
730
|
+
const repoUrl = options.repoUrl ?? (env.MMI_UPDATER_REPO || REPO_URL_DEFAULT);
|
|
708
731
|
let before = codexMmi(runner, env);
|
|
709
732
|
if (before.error && SNAPSHOT_MISSING.test(before.error) && !options.dryRun) {
|
|
710
733
|
const restore = runner("codex", ["plugin", "marketplace", "upgrade"], env);
|
|
@@ -719,8 +742,16 @@ function codexArm(options) {
|
|
|
719
742
|
return { surface: "codex", from, to: options.target, verdict: "ok", detail: `dry-run: would upgrade mutmutco and converge mmi@mutmutco ${from ?? "absent"} -> ${options.target}` };
|
|
720
743
|
}
|
|
721
744
|
const upgrade = runner("codex", ["plugin", "marketplace", "upgrade", "mutmutco", "--json"], env);
|
|
722
|
-
|
|
723
|
-
if (upgrade.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) {
|
|
745
|
+
let upgradeJson = parseJson(upgrade);
|
|
746
|
+
if ((upgrade.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) && NOT_CONFIGURED.test(failure(upgrade))) {
|
|
747
|
+
const add = runner("codex", ["plugin", "marketplace", "add", repoUrl], env);
|
|
748
|
+
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)}` };
|
|
749
|
+
const retry = runner("codex", ["plugin", "marketplace", "upgrade", "mutmutco", "--json"], env);
|
|
750
|
+
upgradeJson = parseJson(retry);
|
|
751
|
+
if (retry.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) {
|
|
752
|
+
return { surface: "codex", from, to: options.target, verdict: "defer", detail: `marketplace upgrade failed after registration: ${failure(retry)}` };
|
|
753
|
+
}
|
|
754
|
+
} else if (upgrade.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) {
|
|
724
755
|
return { surface: "codex", from, to: options.target, verdict: "defer", detail: `marketplace upgrade failed: ${failure(upgrade)}` };
|
|
725
756
|
}
|
|
726
757
|
let observed = codexMmi(runner, env);
|
|
@@ -1897,7 +1928,6 @@ function reap(options) {
|
|
|
1897
1928
|
}
|
|
1898
1929
|
|
|
1899
1930
|
// src/reconcile.ts
|
|
1900
|
-
var REPO_URL_DEFAULT = "https://github.com/mutmutco/MMI-Hub.git";
|
|
1901
1931
|
var CANDIDATE_BOUND_DEFAULT = 12;
|
|
1902
1932
|
function reconcile(options) {
|
|
1903
1933
|
const env = options.env ?? process.env;
|
|
@@ -1985,7 +2015,7 @@ function reconcile(options) {
|
|
|
1985
2015
|
continue;
|
|
1986
2016
|
}
|
|
1987
2017
|
say(`${probe.id}: converging to v${summary.target}`);
|
|
1988
|
-
const arm = probe.id === "claude" ? claudeArm({ target: summary.target, dryRun: options.dryRun, env }) : probe.id === "codex" ? codexArm({ target: summary.target, dryRun: options.dryRun, env }) : probe.id === "kilo" ? kiloArm({ target: summary.target, dryRun: options.dryRun, env }) : probe.id === "kimi" ? kimiArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : probe.id === "cursor" ? cursorArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : probe.id === "jervcode" ? jervcodeArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : probe.id === "hermes" ? hermesArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : null;
|
|
2018
|
+
const arm = probe.id === "claude" ? claudeArm({ target: summary.target, dryRun: options.dryRun, env, repoUrl }) : probe.id === "codex" ? codexArm({ target: summary.target, dryRun: options.dryRun, env, repoUrl }) : probe.id === "kilo" ? kiloArm({ target: summary.target, dryRun: options.dryRun, env }) : probe.id === "kimi" ? kimiArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : probe.id === "cursor" ? cursorArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : probe.id === "jervcode" ? jervcodeArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : probe.id === "hermes" ? hermesArm({ target: summary.target, dryRun: options.dryRun, paths, env }) : null;
|
|
1989
2019
|
if (arm) {
|
|
1990
2020
|
summary.plugins.push(arm);
|
|
1991
2021
|
summary.surfaces.push({ id: probe.id, present: true, action: `arm-${arm.verdict}` });
|
package/package.json
CHANGED