@mutmutco/cli 3.124.0 → 3.125.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.
- package/dist/main.cjs +49 -42
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -9729,41 +9729,48 @@ function pluginReadGrantNote(login = "<your-github-login>") {
|
|
|
9729
9729
|
If the reinstall 404s on ${PLUGIN_READ_REPO}, you lack read on it. An org owner must grant it (idempotent):
|
|
9730
9730
|
gh api -X PUT repos/${PLUGIN_READ_REPO}/collaborators/${login} -f permission=pull`;
|
|
9731
9731
|
}
|
|
9732
|
-
async function
|
|
9733
|
-
const
|
|
9734
|
-
|
|
9735
|
-
const
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
log(" \u21BB reinstalling the MMI plugin via `kilo plugin` (install \u2192 server() provisions the skills)\u2026");
|
|
9739
|
-
for (const step of descriptor.healSteps) {
|
|
9740
|
-
const ok = await runPluginCli("kilo", [...step.args], log);
|
|
9741
|
-
if (healStepAborts(step, ok)) return false;
|
|
9742
|
-
}
|
|
9743
|
-
return true;
|
|
9744
|
-
}
|
|
9745
|
-
const tableSteps = descriptor.healSteps;
|
|
9746
|
-
if (!tableSteps) return false;
|
|
9747
|
-
const loadedCodexLauncher = token === "codex" ? captureCodexHookLauncher() : void 0;
|
|
9748
|
-
const bin = token;
|
|
9749
|
-
const refSupported = await marketplaceAddRefSupported(bin);
|
|
9732
|
+
async function runHealSteps(host, tableSteps, deps) {
|
|
9733
|
+
const log = deps.log ?? (() => {
|
|
9734
|
+
});
|
|
9735
|
+
const loadedCodexLauncher = host === "codex" ? captureCodexHookLauncher() : void 0;
|
|
9736
|
+
const needsRefProbe = tableSteps.some((step) => step.args.includes("--ref"));
|
|
9737
|
+
const refSupported = needsRefProbe ? await marketplaceAddRefSupported(host) : true;
|
|
9750
9738
|
const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
|
|
9751
|
-
log(
|
|
9739
|
+
if (deps.banner) log(deps.banner(refSupported));
|
|
9752
9740
|
const pinsPath = (0, import_node_path12.join)((0, import_node_os5.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
|
|
9753
|
-
const pins =
|
|
9741
|
+
const pins = host === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
|
|
9742
|
+
let failure;
|
|
9754
9743
|
try {
|
|
9755
9744
|
for (const step of steps) {
|
|
9756
|
-
const
|
|
9757
|
-
if (healStepAborts(step, ok))
|
|
9745
|
+
const res = await deps.run(host, [...step.args]);
|
|
9746
|
+
if (healStepAborts(step, res.ok)) {
|
|
9747
|
+
failure = res.detail ?? `\`${host} ${step.args.join(" ")}\` failed`;
|
|
9748
|
+
break;
|
|
9749
|
+
}
|
|
9758
9750
|
}
|
|
9759
9751
|
} finally {
|
|
9760
9752
|
if (restoreCodexHookLauncher(loadedCodexLauncher)) {
|
|
9761
9753
|
log(" retained the windowless Codex hook bridge for the loaded session; restart removes its need");
|
|
9762
9754
|
}
|
|
9763
9755
|
}
|
|
9764
|
-
|
|
9756
|
+
if (failure !== void 0) return { ok: false, detail: failure, refSupported };
|
|
9757
|
+
const restored = host === "claude" ? restoreMarketplacePinsOnDisk(pinsPath, pins) : void 0;
|
|
9765
9758
|
if (restored) log(` ${restored}`);
|
|
9766
|
-
return true;
|
|
9759
|
+
return { ok: true, refSupported };
|
|
9760
|
+
}
|
|
9761
|
+
async function applyPluginHeal(surface, log, opts) {
|
|
9762
|
+
const token = surfaceToken(surface);
|
|
9763
|
+
if (token !== "claude" && token !== "codex" && token !== "kilo") return false;
|
|
9764
|
+
const descriptor = PLUGIN_SURFACE_HEAL[token];
|
|
9765
|
+
if (!descriptor || !descriptor.healSteps) return false;
|
|
9766
|
+
const outcome = await runHealSteps(token, descriptor.healSteps, {
|
|
9767
|
+
run: async (bin, args) => ({ ok: await runPluginCli(bin, args, log) }),
|
|
9768
|
+
log,
|
|
9769
|
+
// kilo-p1: one non-interactive install verb, and the plugin's server() does the rest on the next
|
|
9770
|
+
// /reload — so it names an install, not a marketplace dance.
|
|
9771
|
+
banner: (refSupported) => token === "kilo" ? " \u21BB reinstalling the MMI plugin via `kilo plugin` (install \u2192 server() provisions the skills)\u2026" : healBannerLine(token, token, refSupported)
|
|
9772
|
+
});
|
|
9773
|
+
return outcome.ok;
|
|
9767
9774
|
}
|
|
9768
9775
|
async function healClaudePluginForDoctor(surface = detectSurface(process.env), onStep) {
|
|
9769
9776
|
if (surfaceToken(surface) !== "claude") {
|
|
@@ -9978,7 +9985,7 @@ function planUpdatePass(hasBinary) {
|
|
|
9978
9985
|
const skipped = [];
|
|
9979
9986
|
for (const host of DRIVEN_HOSTS) {
|
|
9980
9987
|
const descriptor = PLUGIN_SURFACE_HEAL[host];
|
|
9981
|
-
const steps = (descriptor.healSteps ?? []).map((step) => [...step.args]);
|
|
9988
|
+
const steps = (descriptor.healSteps ?? []).map((step) => ({ args: [...step.args], gated: step.gated }));
|
|
9982
9989
|
const label = `${host} plugin`;
|
|
9983
9990
|
if (steps.length === 0) {
|
|
9984
9991
|
skipped.push({ host, label, ok: true, changed: false, detail: "skipped: no non-interactive update verb declared" });
|
|
@@ -10005,14 +10012,9 @@ async function runUpdatePass(deps) {
|
|
|
10005
10012
|
let ok = true;
|
|
10006
10013
|
let detail = "updated";
|
|
10007
10014
|
try {
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
ok = false;
|
|
10012
|
-
detail = res.detail ?? `\`${arm.bin} ${args.join(" ")}\` failed`;
|
|
10013
|
-
break;
|
|
10014
|
-
}
|
|
10015
|
-
}
|
|
10015
|
+
const outcome = await runHealSteps(arm.host, arm.steps, { run: deps.run });
|
|
10016
|
+
ok = outcome.ok;
|
|
10017
|
+
if (outcome.detail) detail = outcome.detail;
|
|
10016
10018
|
} catch (e) {
|
|
10017
10019
|
ok = false;
|
|
10018
10020
|
detail = e instanceof Error ? e.message : String(e);
|
|
@@ -10037,7 +10039,7 @@ async function runUpdatePass(deps) {
|
|
|
10037
10039
|
}
|
|
10038
10040
|
function describeUpdatePlan(hasBinary) {
|
|
10039
10041
|
const { arms, skipped } = planUpdatePass(hasBinary);
|
|
10040
|
-
const lines = arms.map((arm) => `${arm.label}: ${arm.steps.map((
|
|
10042
|
+
const lines = arms.map((arm) => `${arm.label}: ${arm.steps.map((step) => `${arm.bin} ${step.args.join(" ")}`).join(" && ")}`);
|
|
10041
10043
|
for (const note of [...skipped, ...operatorOwnedHosts()]) lines.push(`${note.label}: ${note.detail}`);
|
|
10042
10044
|
lines.push("marketplace background updates: set auto-update off (this pass is the update channel)");
|
|
10043
10045
|
lines.push("mmi-cli: npm install -g @mutmutco/cli@<released> \u2014 the cli-version row, immediately after this pass");
|
|
@@ -15838,10 +15840,10 @@ var rollout_plan_default = {
|
|
|
15838
15840
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
15839
15841
|
},
|
|
15840
15842
|
baseline: {
|
|
15841
|
-
version: "3.
|
|
15842
|
-
tag: "v3.
|
|
15843
|
-
commit: "
|
|
15844
|
-
npm: "@mutmutco/cli@3.
|
|
15843
|
+
version: "3.125.0",
|
|
15844
|
+
tag: "v3.125.0",
|
|
15845
|
+
commit: "2ffc8e9b6dc8",
|
|
15846
|
+
npm: "@mutmutco/cli@3.125.0"
|
|
15845
15847
|
},
|
|
15846
15848
|
exitCriterion: "fleet-n-of-n",
|
|
15847
15849
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15858,14 +15860,14 @@ var rollout_plan_default = {
|
|
|
15858
15860
|
repo: "mutmutco/mmi-hub",
|
|
15859
15861
|
role: "canary",
|
|
15860
15862
|
schedule: "train",
|
|
15861
|
-
v3Target: "v3.
|
|
15863
|
+
v3Target: "v3.125.0"
|
|
15862
15864
|
}
|
|
15863
15865
|
],
|
|
15864
15866
|
rollbackTrigger: "Any red inside the post-cut soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a v3 client refused while the compat window must still admit it (SUPPORTED_MINOR_WINDOW=2, MIN_CLIENT_VERSION 0.0.0 \u2014 D6a), or npm consumer install/doctor failure on the v4 dist.",
|
|
15865
15867
|
rollback: {
|
|
15866
15868
|
independent: true,
|
|
15867
|
-
mechanism: "npm dist-tag latest -> 3.
|
|
15868
|
-
v3Target: "v3.
|
|
15869
|
+
mechanism: "npm dist-tag latest -> 3.125.0 and redeploy the Hub Lambda from tag v3.125.0 (2ffc8e9b6dc8); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15870
|
+
v3Target: "v3.125.0 (@mutmutco/cli@3.125.0, tag commit 2ffc8e9b6dc8 \u2014 the preserved latest-v3 distribution, D6b)"
|
|
15869
15871
|
}
|
|
15870
15872
|
},
|
|
15871
15873
|
{
|
|
@@ -39612,9 +39614,14 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39612
39614
|
// background channel left to protect.
|
|
39613
39615
|
runUpdatePass: () => runUpdatePass({
|
|
39614
39616
|
hasBinary: binaryOnPath,
|
|
39617
|
+
// #4873: `runHostBinLogged`, never a bare `execFileP`. Every host verb here is an npm global shim,
|
|
39618
|
+
// which on Windows is `<bin>.cmd` — Node does no PATHEXT resolution, so a bare-name spawn is
|
|
39619
|
+
// ENOENT for all three arms and the pass can never converge on that platform. That helper is the
|
|
39620
|
+
// CLI's one Windows spawn path (`cmd.exe /c`), and it also carries the ignored-stdin and 16 MB
|
|
39621
|
+
// maxBuffer that #4078 established for exactly these plugin verbs.
|
|
39615
39622
|
run: async (bin, args) => {
|
|
39616
39623
|
try {
|
|
39617
|
-
await
|
|
39624
|
+
await runHostBinLogged(bin, args, { timeout: GH_MUTATION_TIMEOUT_MS, step: `${bin} ${args.join(" ")}` });
|
|
39618
39625
|
return { ok: true };
|
|
39619
39626
|
} catch (e) {
|
|
39620
39627
|
const err = e;
|
package/package.json
CHANGED