@mutmutco/cli 4.5.130 → 4.5.131
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 +47 -21
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -8162,6 +8162,11 @@ var DECLARED_ENTRIES = [
|
|
|
8162
8162
|
// archived stage (including a stage whose containers are down) into scratch Postgres and compare
|
|
8163
8163
|
// row counts, and read-verify every storage archive against its listing; per-stage PASS/FAIL.
|
|
8164
8164
|
{ 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)" },
|
|
8165
|
+
// #8176: continuous WAL archiving of the mm-work dev Postgres (owner targets RPO <= 5 min, RTO <= 1 h). Postgres copies each
|
|
8166
|
+
// finished WAL file into a host spool (MM-Work#4170); this timer ships it encrypted to the Storage Box with WAL-G.
|
|
8167
|
+
{ name: "mmi-walg-ship@mm-work-dev (mm-work)", cadence: "every 30s (systemd OnUnitInactiveSec=30s)", executor: "box systemd", llm: "no", resolved: "declared", source: "/etc/systemd/system/mmi-walg-ship@.timer \u2192 /opt/mmi-control/walg-ship.sh mm-work-dev; spool /srv/mm-work/walspool/mm-work-dev \u2192 Storage Box backups/walg/mmi-tools/mm-work-dev, libsodium-encrypted (#8176; source scripts/walg/; status /var/lib/mmi-backup-status/mm-work-dev.ship.json)" },
|
|
8168
|
+
{ name: "mmi-walg-base (mm-work)", cadence: "30 3 * * 0", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-walg-base \u2192 /opt/mmi-control/walg-base.sh mm-work-dev; weekly WAL-G base backup + age-based retention (keep the base at or before now-7d and everything after, #8193) (#8176; source scripts/walg/; log /var/log/mmi-walg.log; status /var/lib/mmi-backup-status/mm-work-dev.base.json)" },
|
|
8169
|
+
{ name: "mmi-walg-drill (mm-work)", cadence: "0 4 2 * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-walg-drill \u2192 /opt/mmi-control/walg-drill.sh mm-work-dev; monthly restore drill measuring RPO/RTO against the owner targets (300s/3600s) into a throwaway --network none container (#8177; source scripts/walg/; status /var/lib/mmi-backup-status/mm-work-dev.drill.json; alarm: backup-health.yml)" },
|
|
8165
8170
|
// #7662 (MM-Work#1520): Vercel Cron's 15-minute central mail call, moved to the box with MM-Work. The app
|
|
8166
8171
|
// calls its own endpoint with its own CRON_SECRET via docker exec, so the secret stays in the container.
|
|
8167
8172
|
{ 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)" },
|
|
@@ -16681,6 +16686,7 @@ function gateExtraStepsYaml(steps) {
|
|
|
16681
16686
|
return steps.map((step) => [
|
|
16682
16687
|
`
|
|
16683
16688
|
- name: ${yamlScalar(step.name)}`,
|
|
16689
|
+
"\n if: ${{ steps.development-gate.outputs.reuse != 'true' }}",
|
|
16684
16690
|
step.env && Object.keys(step.env).length ? `
|
|
16685
16691
|
env:${envYaml(step.env, " ")}` : "",
|
|
16686
16692
|
"\n uses: mutmutco/MMI-Hub/.github/actions/run-with-budget@{{GATE_BUDGET_SHA}}",
|
|
@@ -17240,23 +17246,33 @@ async function installAppFoldDeps(deps) {
|
|
|
17240
17246
|
}
|
|
17241
17247
|
var SHARED_INSTALLER_PACKAGES = ["@mutmutco/installer-face", "@mutmutco/installer-launcher", "@mutmutco/installer-gate"];
|
|
17242
17248
|
async function refreshSharedInstallerDeps(deps) {
|
|
17243
|
-
let
|
|
17249
|
+
let lockPaths;
|
|
17244
17250
|
try {
|
|
17245
|
-
|
|
17246
|
-
const present = Object.keys(lock.packages ?? {});
|
|
17247
|
-
declared = SHARED_INSTALLER_PACKAGES.filter((name) => present.some((key) => key === `node_modules/${name}` || key.endsWith(`/node_modules/${name}`)));
|
|
17248
|
-
} catch {
|
|
17249
|
-
return null;
|
|
17250
|
-
}
|
|
17251
|
-
if (declared.length === 0) return null;
|
|
17252
|
-
try {
|
|
17253
|
-
await deps.run("npm", ["update", ...declared, "--package-lock-only", "--no-audit", "--no-fund"]);
|
|
17251
|
+
lockPaths = (await deps.run("git", ["ls-tree", "-r", "--name-only", "HEAD"])).split("\n").filter((path2) => path2 === "package-lock.json" || path2.endsWith("/package-lock.json"));
|
|
17254
17252
|
} catch (e) {
|
|
17255
|
-
|
|
17256
|
-
|
|
17257
|
-
|
|
17253
|
+
throw trainReadFailure(
|
|
17254
|
+
"shared installer refresh: `git ls-tree -r --name-only HEAD`",
|
|
17255
|
+
e,
|
|
17256
|
+
"rerun in a readable checkout \u2014 lockfile roots must be discovered, never guessed"
|
|
17257
|
+
);
|
|
17258
|
+
}
|
|
17259
|
+
const notes = [];
|
|
17260
|
+
for (const lockPath of lockPaths) {
|
|
17261
|
+
const lock = JSON.parse(await deps.run("git", ["show", `HEAD:${lockPath}`]));
|
|
17262
|
+
const present = Object.keys(lock.packages ?? {});
|
|
17263
|
+
const declared = SHARED_INSTALLER_PACKAGES.filter((name) => present.some((key) => key === `node_modules/${name}` || key.endsWith(`/node_modules/${name}`)));
|
|
17264
|
+
if (declared.length === 0) continue;
|
|
17265
|
+
const prefix = lockPath.includes("/") ? lockPath.slice(0, lockPath.lastIndexOf("/")) : null;
|
|
17266
|
+
try {
|
|
17267
|
+
await deps.run("npm", [...prefix ? ["--prefix", prefix] : [], "update", ...declared, "--package-lock-only", "--no-audit", "--no-fund"]);
|
|
17268
|
+
notes.push(`shared installer deps refreshed in ${prefix ?? "."} (${declared.join(", ")})`);
|
|
17269
|
+
} catch (e) {
|
|
17270
|
+
const why = e instanceof Error ? e.message.split("\n")[0] : String(e);
|
|
17271
|
+
deps.warn?.(`shared installer refresh skipped for ${prefix ?? "."} (${why}) \u2014 shipping the locked versions`);
|
|
17272
|
+
notes.push(`shared installer refresh skipped for ${prefix ?? "."} (${why}); the locked ${declared.join(", ")} still satisfy their ranges`);
|
|
17273
|
+
}
|
|
17258
17274
|
}
|
|
17259
|
-
return
|
|
17275
|
+
return notes.length > 0 ? notes.join("; ") : null;
|
|
17260
17276
|
}
|
|
17261
17277
|
async function restoreMainNpmPackIdentities(deps, version) {
|
|
17262
17278
|
const bomPath = "distribution-bom.json";
|
|
@@ -18258,10 +18274,10 @@ var rollout_plan_default = {
|
|
|
18258
18274
|
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)."
|
|
18259
18275
|
},
|
|
18260
18276
|
baseline: {
|
|
18261
|
-
version: "4.5.
|
|
18262
|
-
tag: "v4.5.
|
|
18263
|
-
commit: "
|
|
18264
|
-
npm: "@mutmutco/cli@4.5.
|
|
18277
|
+
version: "4.5.131",
|
|
18278
|
+
tag: "v4.5.131",
|
|
18279
|
+
commit: "1070f097f90f",
|
|
18280
|
+
npm: "@mutmutco/cli@4.5.131"
|
|
18265
18281
|
},
|
|
18266
18282
|
exitCriterion: "fleet-n-of-n",
|
|
18267
18283
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18278,14 +18294,14 @@ var rollout_plan_default = {
|
|
|
18278
18294
|
repo: "mutmutco/mmi-hub",
|
|
18279
18295
|
role: "canary",
|
|
18280
18296
|
schedule: "train",
|
|
18281
|
-
v3Target: "v4.5.
|
|
18297
|
+
v3Target: "v4.5.131"
|
|
18282
18298
|
}
|
|
18283
18299
|
],
|
|
18284
18300
|
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.",
|
|
18285
18301
|
rollback: {
|
|
18286
18302
|
independent: true,
|
|
18287
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18288
|
-
v3Target: "v4.5.
|
|
18303
|
+
mechanism: "npm dist-tag latest -> 4.5.131 and redeploy the Hub Lambda from tag v4.5.131 (1070f097f90f); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18304
|
+
v3Target: "v4.5.131 (@mutmutco/cli@4.5.131, tag commit 1070f097f90f \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
18289
18305
|
}
|
|
18290
18306
|
},
|
|
18291
18307
|
{
|
|
@@ -29517,10 +29533,17 @@ ${r.repo} (${r.class}, policy=${r.mergePolicy}) ${verdict}`);
|
|
|
29517
29533
|
}
|
|
29518
29534
|
return lines2.join("\n");
|
|
29519
29535
|
}
|
|
29536
|
+
function unauditedReconcileError(reason) {
|
|
29537
|
+
return `cannot audit \u2014 ${reason}; no reconcile change made (unaudited, not canonical)`;
|
|
29538
|
+
}
|
|
29520
29539
|
async function applyCiReconcileMergeSettingsFromReport(repo, deps, report) {
|
|
29521
29540
|
const applied = [];
|
|
29522
29541
|
const skipped = [];
|
|
29523
29542
|
const errors = [];
|
|
29543
|
+
if (report.unauditedReason) {
|
|
29544
|
+
errors.push(unauditedReconcileError(report.unauditedReason));
|
|
29545
|
+
return { repo, applied, skipped, errors };
|
|
29546
|
+
}
|
|
29524
29547
|
const mergeChecks = report.checks.filter((c) => c.label.startsWith("allow_") || c.label.startsWith("delete_branch") || c.label.startsWith("has_wiki"));
|
|
29525
29548
|
const needsPatch = mergeChecks.some((c) => !c.ok);
|
|
29526
29549
|
if (!needsPatch) {
|
|
@@ -29824,6 +29847,9 @@ async function applyCiReconcileRepo(repo, deps, options = {}) {
|
|
|
29824
29847
|
return { repo, applied: [], skipped: [], errors: ["product-ruleset requires registry META requiredChecks"] };
|
|
29825
29848
|
}
|
|
29826
29849
|
const report = await auditRepoCi(repo, deps);
|
|
29850
|
+
if (report.unauditedReason) {
|
|
29851
|
+
return { repo, applied: [], skipped: [], errors: [unauditedReconcileError(report.unauditedReason)] };
|
|
29852
|
+
}
|
|
29827
29853
|
const finish = (result2, pendingReason) => options.productRulesetOnly ? Promise.resolve(result2) : finalizeCiReconcile(repo, deps, result2, report, pendingReason);
|
|
29828
29854
|
const baseBranch = "development";
|
|
29829
29855
|
let raw = report.class === "deployable" && !report.explicitNoCi ? await fetchRulesetSeedBody(deps, repo) : null;
|
package/package.json
CHANGED