@mutmutco/cli 4.0.1 → 4.0.2
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 +92 -26
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -8237,6 +8237,25 @@ function awsScheduleRefs(payload) {
|
|
|
8237
8237
|
}
|
|
8238
8238
|
return refs;
|
|
8239
8239
|
}
|
|
8240
|
+
function decorateAwsModel(entries, registry2, verdicts) {
|
|
8241
|
+
if (!registry2 || registry2.length === 0) return [...entries];
|
|
8242
|
+
const rowById = new Map(registry2.map((r) => [r.id, r]));
|
|
8243
|
+
const literalById = /* @__PURE__ */ new Map();
|
|
8244
|
+
for (const v of verdicts ?? []) {
|
|
8245
|
+
if (typeof v.modelId === "string" && v.modelId.trim() && !literalById.has(v.id)) {
|
|
8246
|
+
literalById.set(v.id, v.modelId);
|
|
8247
|
+
}
|
|
8248
|
+
}
|
|
8249
|
+
return entries.map((e) => {
|
|
8250
|
+
if (!e.scheduleId) return e;
|
|
8251
|
+
const row = rowById.get(e.scheduleId);
|
|
8252
|
+
if (!row || row.executor !== "cursor-agent") return e;
|
|
8253
|
+
const literal = literalById.get(e.scheduleId);
|
|
8254
|
+
if (literal) return { ...e, model: literal };
|
|
8255
|
+
if (row.model) return { ...e, model: `role: ${row.model}` };
|
|
8256
|
+
return { ...e, model: "org-default" };
|
|
8257
|
+
});
|
|
8258
|
+
}
|
|
8240
8259
|
var DECLARED_ENTRIES = [
|
|
8241
8260
|
{ name: "mmi-backup (mm-central, mmi-fofu, zuber, 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 (verify: mmi-cli devops runtime box get <box> --ssh)" },
|
|
8242
8261
|
// #3370: the floor under runner-hygiene.yml. That workflow runs ON the runner and needs checkout +
|
|
@@ -8247,8 +8266,16 @@ var DECLARED_ENTRIES = [
|
|
|
8247
8266
|
// #4118: Listening + systemd-active ≠ GitHub online after acquirejob 503. restart.conf cannot see
|
|
8248
8267
|
// it; an Actions workflow on mmi-live cannot heal it when half the fleet is offline. Root cron.
|
|
8249
8268
|
{ 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)" },
|
|
8250
|
-
|
|
8251
|
-
|
|
8269
|
+
// #3852: the runner /tmp sweep — daily inode hygiene (03:41 UTC), deliberately the one clutter path the
|
|
8270
|
+
// out-of-band disk-relief script must never touch. Verified installed 2026-08-18: the cron.d file and
|
|
8271
|
+
// flock line match scripts/runner-tmp-sweep.cron exactly.
|
|
8272
|
+
{ name: "mmi-runner-tmp-sweep (mmi-runner)", cadence: "41 3 * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-runner-tmp-sweep \u2192 /opt/mmi-control/runner-tmp-sweep.sh; daily inode hygiene, flock -n (verify: mmi-cli devops runtime box get mmi-runner --ssh)" }
|
|
8273
|
+
// RETIRED 2026-08-18 (MMI-Hub#5234): `zuber-bake` (every 30 min) and `zuber-bake-full` (daily 00:30 UTC)
|
|
8274
|
+
// were declared as zuber systemd timers. The ZuberShade full park (#1774, 2026-08-06) stopped them: on
|
|
8275
|
+
// the box (46.225.58.31) zuber-bake.timer / zuber-bake-full.timer answer not-found and
|
|
8276
|
+
// zuber-bake-demand.timer is disabled — no bake/oven timer remains armed, and the notebook must not
|
|
8277
|
+
// claim a job the box does not run. Re-add when the hold lifts and the demand bake re-arms
|
|
8278
|
+
// (MMC-ZuberShade docs/aws-teardown-hold-2026-08-03.md).
|
|
8252
8279
|
];
|
|
8253
8280
|
function sortEntries(entries) {
|
|
8254
8281
|
return [...entries].sort(
|
|
@@ -8263,10 +8290,12 @@ function formatSchedulesTable(entries, now = /* @__PURE__ */ new Date()) {
|
|
|
8263
8290
|
const cadW = w((e) => e.cadence, "CADENCE");
|
|
8264
8291
|
const exeW = w((e) => e.executor, "EXECUTOR");
|
|
8265
8292
|
const llmW = w((e) => e.llm, "LLM");
|
|
8293
|
+
const modelOf = (e) => e.model ?? "-";
|
|
8294
|
+
const modW = w((e) => modelOf(e), "MODEL");
|
|
8266
8295
|
const resW = w((e) => resolvedOf.get(e) ?? e.resolved, "RESOLVED");
|
|
8267
|
-
const row = (n, c, x, l, r, s) => `${n.padEnd(nameW)} ${c.padEnd(cadW)} ${x.padEnd(exeW)} ${l.padEnd(llmW)} ${r.padEnd(resW)} ${s}`;
|
|
8268
|
-
const lines = [row("JOB", "CADENCE", "EXECUTOR", "LLM", "RESOLVED", "SOURCE")];
|
|
8269
|
-
for (const e of entries) lines.push(row(e.name, e.cadence, e.executor, e.llm, resolvedOf.get(e) ?? e.resolved, e.source));
|
|
8296
|
+
const row = (n, c, x, l, m, r, s) => `${n.padEnd(nameW)} ${c.padEnd(cadW)} ${x.padEnd(exeW)} ${l.padEnd(llmW)} ${m.padEnd(modW)} ${r.padEnd(resW)} ${s}`;
|
|
8297
|
+
const lines = [row("JOB", "CADENCE", "EXECUTOR", "LLM", "MODEL", "RESOLVED", "SOURCE")];
|
|
8298
|
+
for (const e of entries) lines.push(row(e.name, e.cadence, e.executor, e.llm, modelOf(e), resolvedOf.get(e) ?? e.resolved, e.source));
|
|
8270
8299
|
return lines.join("\n");
|
|
8271
8300
|
}
|
|
8272
8301
|
function withTickState(entry, now = /* @__PURE__ */ new Date()) {
|
|
@@ -8274,11 +8303,11 @@ function withTickState(entry, now = /* @__PURE__ */ new Date()) {
|
|
|
8274
8303
|
}
|
|
8275
8304
|
function renderDocSection(entries, generatedAtIso) {
|
|
8276
8305
|
const lines = [
|
|
8277
|
-
"| Job | Cadence | Executor | LLM | Resolved | Source |",
|
|
8278
|
-
"
|
|
8306
|
+
"| Job | Cadence | Executor | LLM | Model | Resolved | Source |",
|
|
8307
|
+
"|---|---|---|---|---|---|---|"
|
|
8279
8308
|
];
|
|
8280
8309
|
for (const e of entries) {
|
|
8281
|
-
lines.push(`| ${e.name} | \`${e.cadence}\` | ${e.executor} | ${e.llm} | ${e.resolved} | ${e.source} |`);
|
|
8310
|
+
lines.push(`| ${e.name} | \`${e.cadence}\` | ${e.executor} | ${e.llm} | ${e.model ?? "-"} | ${e.resolved} | ${e.source} |`);
|
|
8282
8311
|
}
|
|
8283
8312
|
return [
|
|
8284
8313
|
DOC_START_MARKER,
|
|
@@ -8694,6 +8723,22 @@ async function fetchSchedulesList(deps) {
|
|
|
8694
8723
|
return null;
|
|
8695
8724
|
}
|
|
8696
8725
|
}
|
|
8726
|
+
async function fetchRunVerdicts(deps) {
|
|
8727
|
+
if (!deps.baseUrl) return null;
|
|
8728
|
+
const token = await deps.token();
|
|
8729
|
+
if (!token) return null;
|
|
8730
|
+
try {
|
|
8731
|
+
const res = await retriedFetch(deps, `${deps.baseUrl.replace(/\/$/, "")}/schedules/verdicts`, {
|
|
8732
|
+
method: "GET",
|
|
8733
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
8734
|
+
});
|
|
8735
|
+
if (!res.ok) return null;
|
|
8736
|
+
const body = await res.json();
|
|
8737
|
+
return Array.isArray(body?.runVerdicts) ? body.runVerdicts : null;
|
|
8738
|
+
} catch {
|
|
8739
|
+
return null;
|
|
8740
|
+
}
|
|
8741
|
+
}
|
|
8697
8742
|
async function fetchOrgConfig(deps) {
|
|
8698
8743
|
if (!deps.baseUrl) return null;
|
|
8699
8744
|
const token = await deps.token();
|
|
@@ -10774,10 +10819,10 @@ var rollout_plan_default = {
|
|
|
10774
10819
|
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)."
|
|
10775
10820
|
},
|
|
10776
10821
|
baseline: {
|
|
10777
|
-
version: "4.0.
|
|
10778
|
-
tag: "v4.0.
|
|
10779
|
-
commit: "
|
|
10780
|
-
npm: "@mutmutco/cli@4.0.
|
|
10822
|
+
version: "4.0.2",
|
|
10823
|
+
tag: "v4.0.2",
|
|
10824
|
+
commit: "e703fd090be7",
|
|
10825
|
+
npm: "@mutmutco/cli@4.0.2"
|
|
10781
10826
|
},
|
|
10782
10827
|
exitCriterion: "fleet-n-of-n",
|
|
10783
10828
|
hubOnlyShortcut: "forbidden",
|
|
@@ -10794,14 +10839,14 @@ var rollout_plan_default = {
|
|
|
10794
10839
|
repo: "mutmutco/mmi-hub",
|
|
10795
10840
|
role: "canary",
|
|
10796
10841
|
schedule: "train",
|
|
10797
|
-
v3Target: "v4.0.
|
|
10842
|
+
v3Target: "v4.0.2"
|
|
10798
10843
|
}
|
|
10799
10844
|
],
|
|
10800
10845
|
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.",
|
|
10801
10846
|
rollback: {
|
|
10802
10847
|
independent: true,
|
|
10803
|
-
mechanism: "npm dist-tag latest -> 4.0.
|
|
10804
|
-
v3Target: "v4.0.
|
|
10848
|
+
mechanism: "npm dist-tag latest -> 4.0.2 and redeploy the Hub Lambda from tag v4.0.2 (e703fd090be7); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
10849
|
+
v3Target: "v4.0.2 (@mutmutco/cli@4.0.2, tag commit e703fd090be7 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
10805
10850
|
}
|
|
10806
10851
|
},
|
|
10807
10852
|
{
|
|
@@ -23516,16 +23561,23 @@ async function probeRepoIndexV4ReadinessCloud(queries, deps) {
|
|
|
23516
23561
|
if (!token) return { ok: false, error: "no Hub session token (run `gh auth login`)" };
|
|
23517
23562
|
const baseUrl = deps.baseUrl.replace(/\/$/, "");
|
|
23518
23563
|
const headers = { ...clientVersionHeaders(), Authorization: ["Bearer", token].join(" "), "content-type": "application/json" };
|
|
23519
|
-
|
|
23564
|
+
const shadowPass = async () => {
|
|
23520
23565
|
for (const query of queries) {
|
|
23521
|
-
const
|
|
23566
|
+
const res = await fetchWithRetry(deps.fetch ?? fetch, `${baseUrl}/repo-index/v4/shadow`, {
|
|
23522
23567
|
method: "POST",
|
|
23523
23568
|
headers,
|
|
23524
23569
|
body: JSON.stringify({ q: query.query, mode: query.mode, readinessProbe: true })
|
|
23525
23570
|
}, { attempts: RETRY_ATTEMPTS2, timeoutMs: 12e4, sleep: deps.retrySleep });
|
|
23526
|
-
const
|
|
23527
|
-
if (!
|
|
23571
|
+
const body = await res.json().catch(() => ({}));
|
|
23572
|
+
if (!res.ok) return { ok: false, error: `${query.id}: ${body.error ?? `v4 readiness probe HTTP ${res.status}`}${body.errorClass ? ` (${body.errorClass})` : ""}`, status: res.status };
|
|
23528
23573
|
}
|
|
23574
|
+
return { ok: true };
|
|
23575
|
+
};
|
|
23576
|
+
try {
|
|
23577
|
+
const warmup = await shadowPass();
|
|
23578
|
+
if (!warmup.ok) return warmup;
|
|
23579
|
+
const verdict = await shadowPass();
|
|
23580
|
+
if (!verdict.ok) return verdict;
|
|
23529
23581
|
const res = await fetchWithRetry(deps.fetch ?? fetch, `${baseUrl}/repo-index/status`, {
|
|
23530
23582
|
method: "GET",
|
|
23531
23583
|
headers: { ...clientVersionHeaders(), Authorization: ["Bearer", token].join(" ") }
|
|
@@ -23534,8 +23586,8 @@ async function probeRepoIndexV4ReadinessCloud(queries, deps) {
|
|
|
23534
23586
|
if (!res.ok) return { ok: false, error: body.error ?? `v4 readiness status HTTP ${res.status}`, status: res.status };
|
|
23535
23587
|
const readiness = body.v4Readiness;
|
|
23536
23588
|
const complete = !!readiness && ["ready", "not-ready"].includes(readiness.verdict) && Array.isArray(readiness.reasons) && Number.isFinite(readiness.goldenCount) && Number.isFinite(readiness.evidenceCount) && !!readiness.modes && ["lexical", "semantic", "hybrid"].every((mode) => {
|
|
23537
|
-
const
|
|
23538
|
-
return
|
|
23589
|
+
const verdict2 = readiness.modes[mode]?.verdict;
|
|
23590
|
+
return verdict2 === "ready" || verdict2 === "not-ready";
|
|
23539
23591
|
});
|
|
23540
23592
|
if (!complete) return { ok: false, error: "Hub status omitted the explicit v4 readiness verdict/reasons/modes contract", status: res.status };
|
|
23541
23593
|
return { ok: true, readiness };
|
|
@@ -26508,12 +26560,20 @@ async function readOrFail(read) {
|
|
|
26508
26560
|
async function defaultRegistryRead() {
|
|
26509
26561
|
return fetchSchedulesList(registryClientDeps(await loadConfig()));
|
|
26510
26562
|
}
|
|
26511
|
-
async function
|
|
26512
|
-
|
|
26563
|
+
async function defaultRunVerdictRead() {
|
|
26564
|
+
return fetchRunVerdicts(registryClientDeps(await loadConfig()));
|
|
26565
|
+
}
|
|
26566
|
+
function modelRoleKeyOf(row) {
|
|
26567
|
+
const model = row.model;
|
|
26568
|
+
return typeof model === "string" && model.trim() ? model : void 0;
|
|
26569
|
+
}
|
|
26570
|
+
async function fetchNotebook(client = defaultGitHubClient(), readRegistry = defaultRegistryRead, readProjects = defaultProjectsRead, readRunVerdicts = defaultRunVerdictRead) {
|
|
26571
|
+
const [gh, aws, registryRead, projectsRead, runVerdictRead] = await Promise.all([
|
|
26513
26572
|
githubEntries(client),
|
|
26514
26573
|
awsEntries(),
|
|
26515
26574
|
readOrFail(readRegistry),
|
|
26516
|
-
readOrFail(readProjects)
|
|
26575
|
+
readOrFail(readProjects),
|
|
26576
|
+
readOrFail(readRunVerdicts)
|
|
26517
26577
|
]);
|
|
26518
26578
|
const readFailures = [];
|
|
26519
26579
|
if (registryRead.state === "failed") {
|
|
@@ -26523,10 +26583,16 @@ async function fetchNotebook(client = defaultGitHubClient(), readRegistry = defa
|
|
|
26523
26583
|
readFailures.push(`registry: could not read the projects list \u2014 schedulesMode opt-outs unresolved (nothing suppressed) \u2014 ${projectsRead.error}`);
|
|
26524
26584
|
}
|
|
26525
26585
|
const registry2 = registryRead.state === "ok" ? registryRead.value : null;
|
|
26586
|
+
const runVerdicts = runVerdictRead.state === "ok" ? runVerdictRead.value : null;
|
|
26526
26587
|
const projects = projectsRead.state === "ok" ? projectsRead.value : null;
|
|
26588
|
+
const decoratedAws = decorateAwsModel(
|
|
26589
|
+
aws.entries,
|
|
26590
|
+
registry2?.map((r) => ({ id: r.id, executor: r.executor, model: modelRoleKeyOf(r) })) ?? null,
|
|
26591
|
+
runVerdicts
|
|
26592
|
+
);
|
|
26527
26593
|
const recon = assembleReconciliation(gh.entries, new Set(gh.readRepos), registry2, new Set(gh.workflowNames), {
|
|
26528
26594
|
// #3286: the harbour side joins registry rows against the live aws-scheduler clocks by scheduleId.
|
|
26529
|
-
awsEntries:
|
|
26595
|
+
awsEntries: decoratedAws,
|
|
26530
26596
|
schedulerRead: Boolean(aws.schedulerRead)
|
|
26531
26597
|
}, new Set(gh.disabledWorkflowNames));
|
|
26532
26598
|
const selfManaged = /* @__PURE__ */ new Set();
|
|
@@ -26540,7 +26606,7 @@ async function fetchNotebook(client = defaultGitHubClient(), readRegistry = defa
|
|
|
26540
26606
|
);
|
|
26541
26607
|
const driftLines = reconciliation.map(renderDrift);
|
|
26542
26608
|
return {
|
|
26543
|
-
entries: sortEntries([...gh.entries, ...
|
|
26609
|
+
entries: sortEntries([...gh.entries, ...decoratedAws, ...DECLARED_ENTRIES]),
|
|
26544
26610
|
incomplete: [...gh.incomplete, ...aws.incomplete, ...recon.incomplete, ...readFailures],
|
|
26545
26611
|
drift: driftLines,
|
|
26546
26612
|
reconciliation,
|
package/package.json
CHANGED