@mutmutco/codex-plugin 4.5.95 → 4.5.96

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mmi",
3
- "version": "4.5.95",
3
+ "version": "4.5.96",
4
4
  "mmiCompat": "4.x",
5
5
  "description": "MMI workflow skills and org gates delivery.",
6
6
  "author": {
package/cli/dist/main.cjs CHANGED
@@ -7460,11 +7460,11 @@ function workflowEntry(repo, workflowPath, yamlText) {
7460
7460
  };
7461
7461
  }
7462
7462
  var DECLARED_ENTRIES = [
7463
- { name: "mmi-backup (mm-central, mm-work, mmi-oguz)", cadence: "17 2 * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-backup \u2192 /opt/mmi-control/nightly-backup.sh; every Docker volume is tarred and every running Postgres container is pg_dumpall'd beside it (#7147; source scripts/nightly-backup.sh); zuber (46.225.58.31) is gone: deleted 2026-09-18 by the owner-approved ZuberShade decommission (MMC-ZuberShade#1838, snapshot kept); Hetzner has since reassigned that IP to another machine (#7351)" },
7463
+ { name: "mmi-backup (mm-central, mm-work)", cadence: "17 2 * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-backup \u2192 /opt/mmi-control/nightly-backup.sh; every Docker volume is tarred and every running Postgres container is pg_dumpall'd beside it (#7147; source scripts/nightly-backup.sh); owner-approved mmi-oguz rebuild as CI-only mmi-runner2 with full erasure and no backups (#7859); zuber (46.225.58.31) is gone: deleted 2026-09-18 by the owner-approved ZuberShade decommission (MMC-ZuberShade#1838, snapshot kept); Hetzner has since reassigned that IP to another machine (#7351)" },
7464
7464
  // #7148: a backup nobody restored is a hope. Monthly, restore the latest artifact of every
7465
7465
  // archived stage (including a stage whose containers are down) into scratch Postgres and compare
7466
7466
  // row counts, and read-verify every storage archive against its listing; per-stage PASS/FAIL.
7467
- { name: "mmi-backup-restore-check (mm-central, mm-work, mmi-oguz)", cadence: "0 3 1 * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-backup-restore-check \u2192 /opt/mmi-control/nightly-backup-restore-check.sh; monthly restore proof for every archived stage (#7148; source scripts/nightly-backup-restore-check.sh); zuber (46.225.58.31) is gone: deleted 2026-09-18 by the owner-approved ZuberShade decommission (MMC-ZuberShade#1838, snapshot kept); Hetzner has since reassigned that IP to another machine (#7351)" },
7467
+ { name: "mmi-backup-restore-check (mm-central, mm-work)", cadence: "0 3 1 * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-backup-restore-check \u2192 /opt/mmi-control/nightly-backup-restore-check.sh; monthly restore proof for every archived stage (#7148; source scripts/nightly-backup-restore-check.sh); owner-approved mmi-oguz rebuild as CI-only mmi-runner2 with full erasure and no backups (#7859); zuber (46.225.58.31) is gone: deleted 2026-09-18 by the owner-approved ZuberShade decommission (MMC-ZuberShade#1838, snapshot kept); Hetzner has since reassigned that IP to another machine (#7351)" },
7468
7468
  // #7662 (MM-Work#1520): Vercel Cron's 15-minute central mail call, moved to the box with MM-Work. The app
7469
7469
  // calls its own endpoint with its own CRON_SECRET via docker exec, so the secret stays in the container.
7470
7470
  { name: "mm-work-mail-tick (mm-work)", cadence: "*/15 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mm-work-mail-tick \u2192 /opt/mmi-control/mm-work-mail-tick.sh; GET /api/internal/mail per stage listed in MM_WORK_MAIL_STAGES (source scripts/mm-work-mail-tick.sh; log /var/log/mm-work-mail-tick.log)" },
@@ -7472,10 +7472,11 @@ var DECLARED_ENTRIES = [
7472
7472
  // setup-node before it can prune, so at 100% it dies at checkout and never prunes — the cleanup is
7473
7473
  // unavailable exactly when it is needed. This one is root cron on the box: no checkout, no node, and
7474
7474
  // a no-op below 90% disk, which is why 15 minutes is affordable.
7475
- { name: "mmi-runner-hygiene-oob (mmi-runner)", cadence: "*/15 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-runner-hygiene \u2192 /opt/mmi-control/runner-hygiene-oob.sh; routine docker/cache prunes every tick, _work relief only at >=90% disk (verify: mmi-cli devops runtime box get mmi-runner --ssh)" },
7475
+ { name: "mmi-runner-hygiene-oob (mmi-runner, mmi-runner2)", cadence: "*/15 * * * * + 5-59/15,10-59/15 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-runner-hygiene \u2192 /opt/mmi-control/runner-hygiene-oob.sh; routine docker/cache prunes every 15 min, relief-only pressure checks between, _work relief at >=90% disk or <8 GiB free; second-host rollout #7859 (verify each box via mmi-cli devops runtime box get <box> --ssh)" },
7476
7476
  // #4118: Listening + systemd-active ≠ GitHub online after acquirejob 503. restart.conf cannot see
7477
7477
  // it; an Actions workflow on mmi-live cannot heal it when half the fleet is offline. Root cron.
7478
7478
  { name: "mmi-runner-online-reconcile (mmi-runner)", cadence: "*/5 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-runner-online \u2192 /opt/mmi-control/runner-online-reconcile.sh; API-offline + _diag acquirejob, max 2 restarts/tick (verify: mmi-cli devops runtime box get mmi-runner --ssh)" },
7479
+ { name: "mmi-runner-online-reconcile (mmi-runner2)", cadence: "*/5 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-runner-online \u2192 /opt/mmi-control/runner-online-reconcile.sh; scripts/runner2-online-reconcile.cron selects lanes 13-16, disables credential files, _diag acquirejob only, max 2 restarts/tick; rollout #7859 (verify: mmi-cli devops runtime box get mmi-runner2 --ssh)" },
7479
7480
  // #5292: a lane that holds a dispatched JOB but produces zero output past the budget honestly
7480
7481
  // reports "busy", so the online reconcile never fires and GitHub will not re-dispatch while the
7481
7482
  // run holds the assignment. This tick cancels + re-triggers those runs (max 1/tick, debounced).
@@ -7483,7 +7484,7 @@ var DECLARED_ENTRIES = [
7483
7484
  // #3852: the runner /tmp sweep — daily inode hygiene (03:41 UTC), deliberately the one clutter path the
7484
7485
  // out-of-band disk-relief script must never touch. Verified installed 2026-08-18: the cron.d file and
7485
7486
  // flock line match scripts/runner-tmp-sweep.cron exactly.
7486
- { name: "mmi-runner-tmp-sweep (mmi-runner)", cadence: "41 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-runner-tmp-sweep \u2192 /opt/mmi-control/runner-tmp-sweep.sh; hourly inode hygiene, 6h age (#6274), flock -n (verify: mmi-cli devops runtime box get mmi-runner --ssh)" }
7487
+ { name: "mmi-runner-tmp-sweep (mmi-runner, mmi-runner2)", cadence: "41 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-runner-tmp-sweep \u2192 /opt/mmi-control/runner-tmp-sweep.sh; hourly inode hygiene, 6h age (#6274), flock -n; second-host rollout #7859 (verify each box via mmi-cli devops runtime box get <box> --ssh)" }
7487
7488
  // RETIRED 2026-08-18 (MMI-Hub#5234): `zuber-bake` (every 30 min) and `zuber-bake-full` (daily 00:30 UTC)
7488
7489
  // were declared as zuber systemd timers. The ZuberShade full park (#1774, 2026-08-06) stopped them: on
7489
7490
  // the box (46.225.58.31) zuber-bake.timer / zuber-bake-full.timer answer not-found and
@@ -17255,10 +17256,10 @@ var rollout_plan_default = {
17255
17256
  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)."
17256
17257
  },
17257
17258
  baseline: {
17258
- version: "4.5.95",
17259
- tag: "v4.5.95",
17260
- commit: "d6d4a135bce9",
17261
- npm: "@mutmutco/cli@4.5.95"
17259
+ version: "4.5.96",
17260
+ tag: "v4.5.96",
17261
+ commit: "191fc3cf3396",
17262
+ npm: "@mutmutco/cli@4.5.96"
17262
17263
  },
17263
17264
  exitCriterion: "fleet-n-of-n",
17264
17265
  hubOnlyShortcut: "forbidden",
@@ -17275,14 +17276,14 @@ var rollout_plan_default = {
17275
17276
  repo: "mutmutco/mmi-hub",
17276
17277
  role: "canary",
17277
17278
  schedule: "train",
17278
- v3Target: "v4.5.95"
17279
+ v3Target: "v4.5.96"
17279
17280
  }
17280
17281
  ],
17281
17282
  rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
17282
17283
  rollback: {
17283
17284
  independent: true,
17284
- mechanism: "npm dist-tag latest -> 4.5.95 and redeploy the Hub Lambda from tag v4.5.95 (d6d4a135bce9); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
17285
- v3Target: "v4.5.95 (@mutmutco/cli@4.5.95, tag commit d6d4a135bce9 \u2014 last known-good release carrying the repo-index v4-only contract)"
17285
+ mechanism: "npm dist-tag latest -> 4.5.96 and redeploy the Hub Lambda from tag v4.5.96 (191fc3cf3396); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
17286
+ v3Target: "v4.5.96 (@mutmutco/cli@4.5.96, tag commit 191fc3cf3396 \u2014 last known-good release carrying the repo-index v4-only contract)"
17286
17287
  }
17287
17288
  },
17288
17289
  {
@@ -37015,8 +37016,8 @@ function bothSidesText(portFailures, portLaneShas) {
37015
37016
  if (rows.length === 0) return "";
37016
37017
  return `BEFORE that --ack: ${rows.map((r) => `${r.label} also conflicts on ${r.paths.join(", ")}`).join("; ")}, which exist on both branches \u2014 the port resolves them by hand for main, so land the SAME resolution on development first (the --ack covers the whole commit, and the next release would otherwise overwrite or clash with the main-only content). `;
37017
37018
  }
37018
- function formatHotfixBatchPreflightRefusal(failures, fromSpecs, portLaneShas = /* @__PURE__ */ new Map()) {
37019
- const lines2 = failures.map((f) => ` - ${f.label}: ${f.blocking.join(", ")}`);
37019
+ function formatHotfixBatchPreflightRefusal(failures, fromSpecs, portLaneShas = /* @__PURE__ */ new Map(), context = { sources: failures, ackedShas: [] }) {
37020
+ const lines2 = failures.map((f) => ` - ${f.label}: ${f.blocking.join(", ")}` + (f.afterAbortedPicks?.length ? ` (observed after aborted pick(s): ${f.afterAbortedPicks.join(", ")}; may depend on those missing changes)` : ""));
37020
37021
  const portFailures = failures.filter((f) => portLaneShas.has(f.sha));
37021
37022
  const synthFailures = failures.filter((f) => !portLaneShas.has(f.sha));
37022
37023
  const head = `hotfix start batch preflight refused: ${failures.length} pick(s) would hard-stop on origin/main:
@@ -37024,15 +37025,15 @@ ${lines2.join("\n")}
37024
37025
  `;
37025
37026
  const batchFrom = fromSpecs.join(",");
37026
37027
  const guide = "https://github.com/mutmutco/MMI-Hub/blob/development/docs/Guides/train-troubleshooting.md#hotfix-pick-refused";
37027
- if (portFailures.length > 0) {
37028
- const originals = portFailures.map((f) => f.sha.slice(0, 7)).join(",");
37029
- const portText = `${portFailures.length === failures.length ? "Every failing pick" : `Pick(s) ${portFailures.map((f) => f.label).join(", ")}`} fail on path(s) ABSENT on origin/main but present on origin/development, so a development-based cite-only synthesis PR cannot carry them (a new development commit cannot add files development already has \u2014 its cherry-pick onto main carries nothing, #7669). Use the main-based PORT-COMMIT lane: cut a branch FROM origin/main, add ONE port commit that brings the listed path(s) and the fix onto main-lineage (e.g. \`git checkout origin/development -- <paths>\` then the fix), push it and keep it pushed until the release \u2014 never merge it into development \u2014 then run \`mmi-cli devops hotfix start --from <portSHA> --ack ${originals}\` (a bare SHA is accepted; the originals are the acked development fixes the port replaces), and record the port SHA in the hotfix PR body. The port commit never reaches development and will not patch-id match, so the NEXT rc\u2192main release must pass \`--ack <the hotfix's main commit>\` (hotfix-coverage). ` + bothSidesText(portFailures, portLaneShas);
37030
- if (synthFailures.length === 0) return `${head}${portText}Never hand-resolve onto main; see ${guide}`;
37031
- return `${head}Mixed batch \u2014 two lanes. ${portText}Pick(s) ${synthFailures.map((f) => f.label).join(", ")} fit the development-based cite-only synthesis lane instead: cut the branch FROM origin/development, regenerate the conflict content so it cherry-picks cleanly onto current origin/main, and land that development-parented PR with the cite-only marker (the #5096 flow). Then rerun \`mmi-cli devops hotfix start --from <synthesis merge SHA(s)>,<portSHA> --ack ${originals}\` (the original --from was ${batchFrom}) \u2014 never hand-resolve onto main; never a main-parented branch into development; see ${guide}`;
37032
- }
37033
- return `hotfix start batch preflight refused: ${failures.length} pick(s) would hard-stop on origin/main:
37034
- ${lines2.join("\n")}
37035
- Land ONE development-based cite-only synthesis PR for the whole batch (#4643 supersedes the old cut-from-origin/main wording, which produced main-lineage PRs into development \u2014 the shape portFoldToDevelopment forbids, #4365/#4371): cut the branch FROM origin/development, regenerate the listed conflict content so it cherry-picks cleanly onto current origin/main, and land that development-parented PR with the cite-only marker (the proven #5096 flow), then rerun \`mmi-cli devops hotfix start --from ${batchFrom}\` with the port merge SHA(s) \u2014 never hand-resolve onto main; never a main-parented branch into development; never N serial ports (#3167) \u2014 see https://github.com/mutmutco/MMI-Hub/blob/development/docs/Guides/train-troubleshooting.md#hotfix-pick-refused`;
37028
+ const replaceNow = failures.filter((f) => !f.afterAbortedPicks?.length);
37029
+ const replacements = new Map(replaceNow.map((f, i) => [f.sha, `<replacementSHA${i + 1}>`]));
37030
+ const picks = context.sources.map((s) => replacements.get(s.sha) ?? s.sha).join(",");
37031
+ const exclusions = [.../* @__PURE__ */ new Set([...context.ackedShas, ...replaceNow.map((f) => f.sha)])].join(",");
37032
+ const mapping = replaceNow.map((f) => `${replacements.get(f.sha)} replaces ${f.label} (${f.sha})`).join("; ");
37033
+ const dependencyNote = failures.some((f) => f.afterAbortedPicks?.length) ? "Later failures were observed after earlier picks were aborted. Keep those original SHAs in the retry. Re-preflight the complete repaired batch before treating a later path absent on static origin/main as an independent port requirement. If a later pick still fails, replacing it requires separate approval for its exact original SHA. " : "";
37034
+ const portText = portFailures.length > 0 ? `Pick(s) ${portFailures.map((f) => f.label).join(", ")} have path(s) ABSENT on origin/main but present on origin/development. If they still fail after prerequisite repairs, use the main-based PORT-COMMIT lane: cut a branch FROM origin/main, add the missing paths and fix, push it and keep it pushed until the release \u2014 never merge it into development. Record the port SHA in the hotfix PR body. The NEXT rc\u2192main release must pass \`--ack <the hotfix's main commit>\` (hotfix-coverage). ` + bothSidesText(portFailures, portLaneShas) : "";
37035
+ const repairText = synthFailures.length > 0 ? `Pick(s) ${synthFailures.map((f) => f.label).join(", ")} need a development repair PR: cut FROM origin/development and land the conflict correction through normal CI. Its picked commit must carry the required main-clean delta; merely citing the original fixes carries no content and grants no coverage exemption. If that delta cannot be produced on development, stop and ask the owner for a scoped port plan. ` : "";
37036
+ return `${head}${portFailures.length > 0 && synthFailures.length > 0 ? "Mixed batch. " : ""}${dependencyNote}${portText}${repairText}Original ordered --from: ${batchFrom}. Replacement mapping: ${mapping}. Keep every passing pick in its original position and retain existing approved exclusions. Additional owner approval required for replacing/excluding original development commit(s): ${replaceNow.map((f) => f.sha).join(",")}. No cite-only marker is implemented; mmi-hotfix-carries is release verification only. Only after that explicit approval, replace the placeholders and rerun \`mmi-cli devops hotfix start --from ${picks} --ack ${exclusions}\`. Re-preflight the whole batch. Never hand-resolve onto main or merge a main-parented branch into development; see ${guide}`;
37036
37037
  }
37037
37038
  var CHERRY_PICKED_FROM = /\(cherry picked from commit ([0-9a-f]{7,40})\)/g;
37038
37039
  async function scanHotfixPickGaps(deps, sources, tolerated, rcRef) {
@@ -37122,7 +37123,8 @@ async function preflightHotfixBatchPicks(deps, sources, pickTolerated) {
37122
37123
  failures.push({
37123
37124
  label: source.label,
37124
37125
  sha: source.sha,
37125
- blocking: blocking.length > 0 ? blocking : [message2.split("\n")[0] ?? message2]
37126
+ blocking: blocking.length > 0 ? blocking : [message2.split("\n")[0] ?? message2],
37127
+ ...failures.length > 0 ? { afterAbortedPicks: failures.map((f) => f.label) } : {}
37126
37128
  });
37127
37129
  }
37128
37130
  }
@@ -37337,7 +37339,7 @@ async function runHotfixStartLocked(deps, options, doctor) {
37337
37339
  const preflight2 = await preflightHotfixBatchPicks(deps, sources, pickTolerated);
37338
37340
  if (preflight2.failures.length > 0) {
37339
37341
  const portLaneShas = await classifyHotfixPortLanePicks(deps, preflight2.failures);
37340
- throw new Error(formatHotfixBatchPreflightRefusal(preflight2.failures, specs, portLaneShas));
37342
+ throw new Error(formatHotfixBatchPreflightRefusal(preflight2.failures, specs, portLaneShas, { sources, ackedShas }));
37341
37343
  }
37342
37344
  if (preflight2.skipped.length > 0) {
37343
37345
  const skippedShas = new Set(preflight2.skipped.map((s) => s.sha));
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.95",
3
+ "version": "4.5.96",
4
4
  "description": "MMI Future CLI — the org dev toolbox and shared cross-IDE engine for every registry-declared MMI coding surface.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/codex-plugin",
3
- "version": "4.5.95",
3
+ "version": "4.5.96",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",