@mutmutco/cli 3.53.0 → 3.55.0

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/main.cjs +74 -1
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -9108,6 +9108,7 @@ function cachedReadNote(cachedAt, now = Date.now()) {
9108
9108
  // src/marketplace-autoupdate.ts
9109
9109
  var KNOWN_MARKETPLACES_RELATIVE = [".claude", "plugins", "known_marketplaces.json"];
9110
9110
  var MMI_MARKETPLACE_NAME = "mutmutco";
9111
+ var JERV_MARKETPLACE_NAME = "jervaise";
9111
9112
  function readFileSyncSafe(path2, read) {
9112
9113
  try {
9113
9114
  return read(path2, "utf8");
@@ -9144,6 +9145,49 @@ function resolveAutoUpdate(probe) {
9144
9145
  reason: "undeclared \u2014 third-party marketplaces are OFF by default, so nothing auto-updates and no update notice ever prints"
9145
9146
  };
9146
9147
  }
9148
+ function captureMarketplacePins(raw, names) {
9149
+ const out = /* @__PURE__ */ new Map();
9150
+ for (const name of names) {
9151
+ const { registered, declared, ref } = readKnownMarketplace(raw, name);
9152
+ if (!registered) continue;
9153
+ const pins = {
9154
+ ...typeof declared === "boolean" ? { autoUpdate: declared } : {},
9155
+ ...ref ? { ref } : {}
9156
+ };
9157
+ if (Object.keys(pins).length) out.set(name, pins);
9158
+ }
9159
+ return out;
9160
+ }
9161
+ function restoreMarketplacePins(raw, pins) {
9162
+ if (!raw || pins.size === 0) return null;
9163
+ let parsed;
9164
+ try {
9165
+ parsed = JSON.parse(raw);
9166
+ } catch {
9167
+ return null;
9168
+ }
9169
+ if (!parsed || typeof parsed !== "object") return null;
9170
+ const root = parsed;
9171
+ let changed = false;
9172
+ for (const [name, want] of pins) {
9173
+ const entry = root[name];
9174
+ if (!entry || typeof entry !== "object") continue;
9175
+ const e = entry;
9176
+ if (typeof want.autoUpdate === "boolean" && e.autoUpdate !== want.autoUpdate) {
9177
+ e.autoUpdate = want.autoUpdate;
9178
+ changed = true;
9179
+ }
9180
+ if (want.ref && e.source && typeof e.source === "object") {
9181
+ const source = e.source;
9182
+ if (source.ref !== want.ref) {
9183
+ source.ref = want.ref;
9184
+ changed = true;
9185
+ }
9186
+ }
9187
+ }
9188
+ return changed ? `${JSON.stringify(root, null, 2)}
9189
+ ` : null;
9190
+ }
9147
9191
  function readKnownMarketplace(raw, name) {
9148
9192
  if (!raw) return { registered: false };
9149
9193
  let parsed;
@@ -22732,9 +22776,13 @@ async function applyPluginHeal(surface, log, opts) {
22732
22776
  const refSupported = await marketplaceAddRefSupported("claude");
22733
22777
  const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
22734
22778
  log(healBannerLine("claude", "claude", refSupported));
22779
+ const pinsPath = (0, import_node_path26.join)((0, import_node_os6.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
22780
+ const pins = captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]);
22735
22781
  for (const step of steps) {
22736
22782
  if (healStepAborts(step, await runClaudePlugin([...step.args]))) return false;
22737
22783
  }
22784
+ const restored = restoreMarketplacePinsOnDisk(pinsPath, pins);
22785
+ if (restored) log(` ${restored}`);
22738
22786
  return true;
22739
22787
  }
22740
22788
  async function healClaudePluginForDoctor(surface = detectSurface(process.env)) {
@@ -22743,11 +22791,36 @@ async function healClaudePluginForDoctor(surface = detectSurface(process.env)) {
22743
22791
  }
22744
22792
  const steps = [];
22745
22793
  const ok = await applyPluginHeal(surface, (msg) => steps.push(msg.trim()));
22794
+ const pinNote = steps.find((s) => s.startsWith("re-pinned ") || s.includes("re-pin by hand"));
22746
22795
  return {
22747
22796
  ok,
22748
- detail: ok ? "marketplace remove \u2192 add \u2192 install succeeded" : `\`claude plugin\` reinstall failed or was skipped${steps.length ? ` (${steps[steps.length - 1]})` : ""}`
22797
+ detail: ok ? `marketplace remove \u2192 add \u2192 install succeeded${pinNote ? `; ${pinNote}` : ""}` : `\`claude plugin\` reinstall failed or was skipped${steps.length ? ` (${steps[steps.length - 1]})` : ""}`
22749
22798
  };
22750
22799
  }
22800
+ function readKnownMarketplacesFile(path2) {
22801
+ try {
22802
+ return (0, import_node_fs28.existsSync)(path2) ? (0, import_node_fs28.readFileSync)(path2, "utf8") : void 0;
22803
+ } catch {
22804
+ return void 0;
22805
+ }
22806
+ }
22807
+ function restoreMarketplacePinsOnDisk(path2, pins) {
22808
+ if (pins.size === 0) return void 0;
22809
+ const after = readKnownMarketplacesFile(path2);
22810
+ const next = restoreMarketplacePins(after, pins);
22811
+ if (next === null) return void 0;
22812
+ try {
22813
+ (0, import_node_fs28.writeFileSync)(path2, next, "utf8");
22814
+ } catch {
22815
+ return `could NOT restore ${[...pins.keys()].join(", ")} \u2014 re-pin by hand`;
22816
+ }
22817
+ const verify = readKnownMarketplacesFile(path2);
22818
+ const failed = [...pins].filter(([name, want]) => {
22819
+ const got = readKnownMarketplace(verify, name);
22820
+ return typeof want.autoUpdate === "boolean" && got.declared !== want.autoUpdate || want.ref !== void 0 && got.ref !== want.ref;
22821
+ });
22822
+ return failed.length ? `restore did NOT take for ${failed.map(([n]) => n).join(", ")} \u2014 re-pin by hand` : `re-pinned ${[...pins.keys()].join(", ")} (auto-update + catalog ref survive the reinstall)`;
22823
+ }
22751
22824
  async function runGuard(readOrigin) {
22752
22825
  try {
22753
22826
  const surface = detectSurface(process.env);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.53.0",
3
+ "version": "3.55.0",
4
4
  "description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",