@mutmutco/hub 4.0.12 → 4.0.14

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 +33 -7
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -561,6 +561,8 @@ var import_node_child_process5 = require("node:child_process");
561
561
  var import_node_fs7 = require("node:fs");
562
562
  var import_node_os3 = require("node:os");
563
563
  var import_node_path6 = require("node:path");
564
+ var REPO_URL_DEFAULT = "https://github.com/mutmutco/MMI-Hub.git";
565
+ var MMI_MARKETPLACE_REPO = "mutmutco/MMI-Hub";
564
566
  function convergedAtOrAbove(installed, target, healthy) {
565
567
  return healthy && typeof installed === "string" && compareSemver(installed, target) >= 0;
566
568
  }
@@ -628,11 +630,20 @@ function ensureClaudeSingleWriter(env, dryRun) {
628
630
  let body;
629
631
  try {
630
632
  body = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
631
- } catch {
633
+ } catch (error) {
634
+ if (error?.code === "ENOENT") return { ok: false, detail: `${path} does not exist \u2014 mutmutco marketplace is not registered`, unregistered: true };
632
635
  return { ok: false, detail: `cannot read ${path}` };
633
636
  }
634
637
  const registration = body.mutmutco;
635
- if (!registration || typeof registration !== "object") return { ok: false, detail: "mutmutco marketplace is not registered" };
638
+ if (!registration || typeof registration !== "object") return { ok: false, detail: "mutmutco marketplace is not registered", unregistered: true };
639
+ const source = registration.source;
640
+ const registeredRepo = source && typeof source === "object" && source.source === "github" ? source.repo : null;
641
+ if (registeredRepo !== MMI_MARKETPLACE_REPO) {
642
+ return {
643
+ ok: false,
644
+ 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`
645
+ };
646
+ }
636
647
  if (registration.autoUpdate !== true) return { ok: true };
637
648
  if (dryRun) return { ok: true, detail: "would disable Claude background autoUpdate (updater is the single writer)" };
638
649
  const quiescence = claudeHostRunning(env);
@@ -653,10 +664,16 @@ function ensureClaudeSingleWriter(env, dryRun) {
653
664
  function claudeArm(options) {
654
665
  const env = options.env ?? process.env;
655
666
  const runner = options.runner ?? runHostCommand;
667
+ const repoUrl = options.repoUrl ?? (env.MMI_UPDATER_REPO || REPO_URL_DEFAULT);
656
668
  const before = claudeMmi(runner, env);
657
669
  if (before.error) return { surface: "claude", from: null, to: options.target, verdict: "defer", detail: before.error };
658
670
  const from = before.row?.version ?? null;
659
- const singleWriter = ensureClaudeSingleWriter(env, options.dryRun);
671
+ let singleWriter = ensureClaudeSingleWriter(env, options.dryRun);
672
+ if (!singleWriter.ok && singleWriter.unregistered) {
673
+ const add = runner("claude", ["plugin", "marketplace", "add", repoUrl], env);
674
+ 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)}` };
675
+ singleWriter = ensureClaudeSingleWriter(env, options.dryRun);
676
+ }
660
677
  if (!singleWriter.ok) return { surface: "claude", from, to: options.target, verdict: "defer", detail: singleWriter.detail ?? "cannot establish updater as the single writer" };
661
678
  if (options.dryRun) {
662
679
  const writer = singleWriter.detail ? `; ${singleWriter.detail}` : "";
@@ -702,9 +719,11 @@ function codexMmi(runner, env) {
702
719
  if (!parsed || !Array.isArray(parsed.installed)) return { row: null, error: `codex plugin list --json failed: ${failure(result)}` };
703
720
  return { row: parsed.installed.find((row) => row.pluginId === "mmi@mutmutco") ?? null };
704
721
  }
722
+ var NOT_CONFIGURED = /not configured|is not registered|not a Git marketplace/i;
705
723
  function codexArm(options) {
706
724
  const env = options.env ?? process.env;
707
725
  const runner = options.runner ?? runHostCommand;
726
+ const repoUrl = options.repoUrl ?? (env.MMI_UPDATER_REPO || REPO_URL_DEFAULT);
708
727
  let before = codexMmi(runner, env);
709
728
  if (before.error && SNAPSHOT_MISSING.test(before.error) && !options.dryRun) {
710
729
  const restore = runner("codex", ["plugin", "marketplace", "upgrade"], env);
@@ -719,8 +738,16 @@ function codexArm(options) {
719
738
  return { surface: "codex", from, to: options.target, verdict: "ok", detail: `dry-run: would upgrade mutmutco and converge mmi@mutmutco ${from ?? "absent"} -> ${options.target}` };
720
739
  }
721
740
  const upgrade = runner("codex", ["plugin", "marketplace", "upgrade", "mutmutco", "--json"], env);
722
- const upgradeJson = parseJson(upgrade);
723
- if (upgrade.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) {
741
+ let upgradeJson = parseJson(upgrade);
742
+ if ((upgrade.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) && NOT_CONFIGURED.test(failure(upgrade))) {
743
+ const add = runner("codex", ["plugin", "marketplace", "add", repoUrl], env);
744
+ 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)}` };
745
+ const retry = runner("codex", ["plugin", "marketplace", "upgrade", "mutmutco", "--json"], env);
746
+ upgradeJson = parseJson(retry);
747
+ if (retry.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) {
748
+ return { surface: "codex", from, to: options.target, verdict: "defer", detail: `marketplace upgrade failed after registration: ${failure(retry)}` };
749
+ }
750
+ } else if (upgrade.status !== 0 || !upgradeJson || (upgradeJson.errors?.length ?? 0) > 0) {
724
751
  return { surface: "codex", from, to: options.target, verdict: "defer", detail: `marketplace upgrade failed: ${failure(upgrade)}` };
725
752
  }
726
753
  let observed = codexMmi(runner, env);
@@ -1897,7 +1924,6 @@ function reap(options) {
1897
1924
  }
1898
1925
 
1899
1926
  // src/reconcile.ts
1900
- var REPO_URL_DEFAULT = "https://github.com/mutmutco/MMI-Hub.git";
1901
1927
  var CANDIDATE_BOUND_DEFAULT = 12;
1902
1928
  function reconcile(options) {
1903
1929
  const env = options.env ?? process.env;
@@ -1985,7 +2011,7 @@ function reconcile(options) {
1985
2011
  continue;
1986
2012
  }
1987
2013
  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;
2014
+ 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
2015
  if (arm) {
1990
2016
  summary.plugins.push(arm);
1991
2017
  summary.surfaces.push({ id: probe.id, present: true, action: `arm-${arm.verdict}` });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/hub",
3
- "version": "4.0.12",
3
+ "version": "4.0.14",
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",