@mutmutco/codex-plugin 4.5.137 → 4.5.139
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/cli/dist/main.cjs
CHANGED
|
@@ -18277,10 +18277,10 @@ var rollout_plan_default = {
|
|
|
18277
18277
|
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)."
|
|
18278
18278
|
},
|
|
18279
18279
|
baseline: {
|
|
18280
|
-
version: "4.5.
|
|
18281
|
-
tag: "v4.5.
|
|
18282
|
-
commit: "
|
|
18283
|
-
npm: "@mutmutco/cli@4.5.
|
|
18280
|
+
version: "4.5.139",
|
|
18281
|
+
tag: "v4.5.139",
|
|
18282
|
+
commit: "59be27fc975d",
|
|
18283
|
+
npm: "@mutmutco/cli@4.5.139"
|
|
18284
18284
|
},
|
|
18285
18285
|
exitCriterion: "fleet-n-of-n",
|
|
18286
18286
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18297,14 +18297,14 @@ var rollout_plan_default = {
|
|
|
18297
18297
|
repo: "mutmutco/mmi-hub",
|
|
18298
18298
|
role: "canary",
|
|
18299
18299
|
schedule: "train",
|
|
18300
|
-
v3Target: "v4.5.
|
|
18300
|
+
v3Target: "v4.5.139"
|
|
18301
18301
|
}
|
|
18302
18302
|
],
|
|
18303
18303
|
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.",
|
|
18304
18304
|
rollback: {
|
|
18305
18305
|
independent: true,
|
|
18306
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18307
|
-
v3Target: "v4.5.
|
|
18306
|
+
mechanism: "npm dist-tag latest -> 4.5.139 and redeploy the Hub Lambda from tag v4.5.139 (59be27fc975d); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18307
|
+
v3Target: "v4.5.139 (@mutmutco/cli@4.5.139, tag commit 59be27fc975d \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
18308
18308
|
}
|
|
18309
18309
|
},
|
|
18310
18310
|
{
|
|
@@ -20427,7 +20427,10 @@ async function readTrainLogin(deps, waitMs = 18e4, attempts = 5) {
|
|
|
20427
20427
|
try {
|
|
20428
20428
|
return requireValue(clean2(await deps.run("gh", ["api", "user", "--jq", ".login"])), "GitHub login");
|
|
20429
20429
|
} catch (e) {
|
|
20430
|
-
if (
|
|
20430
|
+
if (!isRateLimitText(e instanceof Error ? e.message : String(e))) throw e;
|
|
20431
|
+
const stored = clean2(await deps.run("gh", ["config", "get", "user", "-h", "github.com"]).catch(() => ""));
|
|
20432
|
+
if (stored) return stored;
|
|
20433
|
+
if (i >= attempts) throw e;
|
|
20431
20434
|
deps.warn?.(`GitHub login read rate-limited; retrying in ${waitMs / 6e4} min (${i}/${attempts - 1})`);
|
|
20432
20435
|
await resolveSleep(deps)(waitMs);
|
|
20433
20436
|
}
|
|
@@ -22181,6 +22184,10 @@ async function announceShippedRelease(deps, args, model, legs, deferred) {
|
|
|
22181
22184
|
return (await deps.announce(args)).note;
|
|
22182
22185
|
}
|
|
22183
22186
|
async function listTargetRun(deps, repo, target, headSha) {
|
|
22187
|
+
const { read: _read, ...run } = await readTargetRun(deps, repo, target, headSha);
|
|
22188
|
+
return run;
|
|
22189
|
+
}
|
|
22190
|
+
async function readTargetRun(deps, repo, target, headSha) {
|
|
22184
22191
|
let rows;
|
|
22185
22192
|
try {
|
|
22186
22193
|
rows = JSON.parse(await deps.run("gh", [
|
|
@@ -22201,11 +22208,12 @@ async function listTargetRun(deps, repo, target, headSha) {
|
|
|
22201
22208
|
]));
|
|
22202
22209
|
if (!Array.isArray(rows)) throw new Error("run list did not return an array");
|
|
22203
22210
|
} catch {
|
|
22204
|
-
return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending" };
|
|
22211
|
+
return { workflow: `${target.workflow} (${target.event}) not listable`, event: target.event, conclusion: "pending", read: "failed" };
|
|
22205
22212
|
}
|
|
22206
22213
|
const row = rows.find((r) => typeof r.databaseId === "number" && r.event === target.event);
|
|
22207
|
-
if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending" };
|
|
22214
|
+
if (!row) return { workflow: `${target.workflow} (${target.event}) has not started`, event: target.event, conclusion: "pending", read: "absent" };
|
|
22208
22215
|
return {
|
|
22216
|
+
read: "found",
|
|
22209
22217
|
workflow: target.workflow,
|
|
22210
22218
|
runId: row.databaseId,
|
|
22211
22219
|
runUrl: row.url,
|
|
@@ -25740,6 +25748,8 @@ var COMPOSE_GUARD_HARD_FAIL = /^secrets preflight: .*noEnvFile is (not )?true.*$
|
|
|
25740
25748
|
var PREFLIGHT_TIMEOUT = /aborted due to timeout|TimeoutError|ETIMEDOUT|ESOCKETTIMEDOUT|UND_ERR_(?:HEADERS|CONNECT)_TIMEOUT/i;
|
|
25741
25749
|
var PREFLIGHT_TIMEOUT_RETRIES = 2;
|
|
25742
25750
|
var PREFLIGHT_RETRY_BASE_MS = 1e3;
|
|
25751
|
+
var CANDIDATE_PUSH_GATE_WAIT_MS = 20 * 6e4;
|
|
25752
|
+
var CANDIDATE_PUSH_GATE_POLL_MS = 3e4;
|
|
25743
25753
|
function readOriginWorkflowsDefault(root, ref) {
|
|
25744
25754
|
const git3 = (args) => (0, import_node_child_process9.execFileSync)("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
25745
25755
|
let paths;
|
|
@@ -26021,6 +26031,51 @@ async function runTrainDoctor(input) {
|
|
|
26021
26031
|
if (workflows === null && !startBranchMissing) {
|
|
26022
26032
|
add({ code: "workflows-unreadable", severity: "blocker", source: "local", title: `.github/workflows at ${workflowsRef} could not be read from ${cwd} \u2014 the tag-addressability (#5428) and npm-major (#5666) preflights did not run`, remedy: `run from a checkout whose git can read ${workflowsRef} (fetch origin first), then rerun; an unread workflow set is unverified, not green` });
|
|
26023
26033
|
}
|
|
26034
|
+
if (lane === "release" && !startBranchMissing) {
|
|
26035
|
+
const required = meta?.requiredChecks?.length ? meta.requiredChecks : ["gate"];
|
|
26036
|
+
const emitters = (workflows ?? []).filter((f) => parseWorkflowJobIds(f.body).some((id) => required.some((context) => contextMatchesJobId(id, context))));
|
|
26037
|
+
const gateFiles = emitters.length ? emitters : (workflows ?? []).filter((f) => isGateWorkflowPath(f.path));
|
|
26038
|
+
const gates = gateFiles.length ? gateFiles.map((f) => f.path.split("/").pop()) : ["gate"];
|
|
26039
|
+
try {
|
|
26040
|
+
const tip = await git3(["rev-parse", "--verify", "--quiet", `refs/remotes/origin/${startBranch}`]);
|
|
26041
|
+
for (const workflow of gates) {
|
|
26042
|
+
let run = await readTargetRun(train, repo, { workflow, event: "push" }, tip);
|
|
26043
|
+
let lastUrl = run.runUrl;
|
|
26044
|
+
let elapsed = 0;
|
|
26045
|
+
const startedAt = Date.now();
|
|
26046
|
+
while (input.refuse && run.read === "found" && run.conclusion === "pending" && elapsed < CANDIDATE_PUSH_GATE_WAIT_MS) {
|
|
26047
|
+
train.warn?.(`candidate push gate ${run.runUrl} still running \u2014 ${elapsed / 1e3}s elapsed (20m bound)`);
|
|
26048
|
+
await deps.sleep(CANDIDATE_PUSH_GATE_POLL_MS);
|
|
26049
|
+
run = await readTargetRun(train, repo, { workflow, event: "push" }, tip);
|
|
26050
|
+
elapsed = Math.max(elapsed + CANDIDATE_PUSH_GATE_POLL_MS, Date.now() - startedAt);
|
|
26051
|
+
lastUrl = run.runUrl ?? lastUrl;
|
|
26052
|
+
}
|
|
26053
|
+
const url = run.runUrl ?? lastUrl ?? (run.runId ? `https://github.com/${repo}/actions/runs/${run.runId}` : "(no run URL)");
|
|
26054
|
+
if (run.read === "failed") {
|
|
26055
|
+
originUnverified = true;
|
|
26056
|
+
add({ code: "candidate-push-gate-unread", severity: "warning", source: "origin", title: `${workflow} push runs on ${startBranch}@${tip.slice(0, 12)} could not be read`, remedy: `repair the GitHub run-list read and rerun; unread is not a pass${elapsed ? ` \u2014 last observed run: ${url}` : ""}` });
|
|
26057
|
+
if (input.refuse && elapsed) throw new Error(`candidate push gate became unreadable while waiting \u2014 ${url}; nothing was tagged`);
|
|
26058
|
+
} else if (run.read === "absent") {
|
|
26059
|
+
add({ code: "candidate-push-gate-missing", severity: "warning", source: "origin", title: `no ${workflow} push run on ${startBranch}@${tip.slice(0, 12)}`, remedy: "no pre-tag push verdict is available; some repos intentionally run gate only on PRs and tags" });
|
|
26060
|
+
} else if (run.conclusion === "failure") {
|
|
26061
|
+
let jobs = "failed jobs unreadable";
|
|
26062
|
+
try {
|
|
26063
|
+
const rows = JSON.parse(await train.run("gh", ["run", "view", String(run.runId), "--repo", repo, "--json", "jobs"]));
|
|
26064
|
+
jobs = rows.jobs.filter((j) => !["success", "skipped", "neutral", ""].includes(j.conclusion)).map((j) => j.name).join(", ") || "no failed job names reported";
|
|
26065
|
+
} catch {
|
|
26066
|
+
}
|
|
26067
|
+
add({ code: "candidate-push-gate-red", severity: "blocker", source: "origin", title: `${workflow} push gate failed on ${startBranch}@${tip.slice(0, 12)} \u2014 ${url}`, remedy: `${url} \u2014 failed job(s): ${jobs}. Fix on development through a normal CI-gated PR and rerun; --heal never clears a red gate` });
|
|
26068
|
+
} else if (run.conclusion === "pending") {
|
|
26069
|
+
add({ code: "candidate-push-gate-running", severity: "warning", source: "origin", title: `${workflow} push gate still running \u2014 ${url}`, remedy: "wait for the run to conclude and rerun; apply waits up to 20 minutes before refusing" });
|
|
26070
|
+
if (input.refuse) throw new Error(`candidate push gate still running after 20 minutes \u2014 ${url}; nothing was tagged`);
|
|
26071
|
+
}
|
|
26072
|
+
}
|
|
26073
|
+
} catch (e) {
|
|
26074
|
+
if (input.refuse) throw e;
|
|
26075
|
+
originUnverified = true;
|
|
26076
|
+
add({ code: "candidate-push-gate-unread", severity: "warning", source: "origin", title: `candidate push gate could not be read: ${message(e)}`, remedy: "repair the candidate SHA / GitHub read and rerun; unread is not a pass" });
|
|
26077
|
+
}
|
|
26078
|
+
}
|
|
26024
26079
|
if (!startBranchMissing) {
|
|
26025
26080
|
try {
|
|
26026
26081
|
const required = await discoverRequiredCheckContexts(train, ctx, stage);
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -109,7 +109,7 @@ commit, so build and verify the lines from one pass over that range —
|
|
|
109
109
|
subject, body and changed files — never from subjects, PR titles or memory; a line whose claim is not
|
|
110
110
|
in that output does not go in the file. A Hub summary never mentions a Jerv-side project; the train
|
|
111
111
|
refuses such a line.
|
|
112
|
-
Every new MM-Work suite Release, solo and hotfix included, requires `--announce-summary-file` and `--announce-summary-file-tr` in the bilingual update-notes template of the [MM-Work GUIDE, "Update notes"](https://github.com/mutmutco/MM-Work/blob/development/packages/mmwork-ds/GUIDE.md) (`Fixed`/`Düzeldi`, then `New`/`Yeni`, with `<Area>: <sentence>.` lines). A suite release requires `--member-summary-file owner/repo=path` and `--member-summary-file-tr owner/repo=path` for every member it releases. Details: the release skill.
|
|
112
|
+
Every new MM-Work suite Release, solo and hotfix included, requires `--announce-summary-file` and `--announce-summary-file-tr` in the bilingual update-notes template of the [MM-Work GUIDE, "Update notes"](https://github.com/mutmutco/MM-Work/blob/development/packages/mmwork-ds/GUIDE.md#update-notes) (`Fixed`/`Düzeldi`, then `New`/`Yeni`, with `<Area>: <sentence>.` lines). A suite release requires `--member-summary-file owner/repo=path` and `--member-summary-file-tr owner/repo=path` for every member it releases. Details: the release skill.
|
|
113
113
|
|
|
114
114
|
Announcement delivery uses the developer's GitHub-authenticated Hub session. The Hub checks project
|
|
115
115
|
authority, resolves the registered channel, and reads the MMI Future Slack key inside its vault boundary.
|
package/skills/release/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ Full-track repos ship exactly what is on `rc` (never `development`): merge `rc
|
|
|
15
15
|
|
|
16
16
|
In the suite lead (MM-Work) a plain rcand, release or hotfix refuses: run `mmi-cli devops suite rcand --owner-go` or `mmi-cli devops suite release --owner-go` instead (a lead-only cut needs `--suite-solo --owner-go`). A suite member cannot run standalone rcand, release or hotfix: cut from the suite lead; only a backward-compatible solo backend release/hotfix with explicit owner approval may pass `--suite-solo --owner-go`, and its MM-Work development pin PR must land before the suite is in sync.
|
|
17
17
|
|
|
18
|
-
Every new mm-work suite Release (including solo and hotfix releases) requires both `--announce-summary-file <path>` (English) and `--announce-summary-file-tr <path>` (Turkish, "sen" form) in the update-notes template. The canonical wording lives in the [MM-Work GUIDE, "Update notes"](https://github.com/mutmutco/MM-Work/blob/development/packages/mmwork-ds/GUIDE.md); this repo links it and never copies it. Each file has the section word `Fixed` / `Düzeldi` (the problem the person saw, present tense) and/or `New` / `Yeni` (what you can now do) on its own line, Fixed first, each only when it has lines. Under them go 1–8 lines of `<Area>: <sentence>.`, each at most 120 characters, with no issue numbers, versions or commit prefixes. Off-template or missing files refuse before tagging. Do not write the head (app · date · time) or the thanks line: MM-Work renders both from the Release date and credits. Suite release also requires a valid `--member-summary-file <owner/repo=path>` and `--member-summary-file-tr <owner/repo=path>` for every member being released, before promoting any member. Carried, held and already-released members need none, and existing Releases can resume without new files.
|
|
18
|
+
Every new mm-work suite Release (including solo and hotfix releases) requires both `--announce-summary-file <path>` (English) and `--announce-summary-file-tr <path>` (Turkish, "sen" form) in the update-notes template. The canonical wording lives in the [MM-Work GUIDE, "Update notes"](https://github.com/mutmutco/MM-Work/blob/development/packages/mmwork-ds/GUIDE.md#update-notes); this repo links it and never copies it. Each file has the section word `Fixed` / `Düzeldi` (the problem the person saw, present tense) and/or `New` / `Yeni` (what you can now do) on its own line, Fixed first, each only when it has lines. Under them go 1–8 lines of `<Area>: <sentence>.`, each at most 120 characters, with no issue numbers, versions or commit prefixes. Off-template or missing files refuse before tagging. Do not write the head (app · date · time) or the thanks line: MM-Work renders both from the Release date and credits. Suite release also requires a valid `--member-summary-file <owner/repo=path>` and `--member-summary-file-tr <owner/repo=path>` for every member being released, before promoting any member. Carried, held and already-released members need none, and existing Releases can resume without new files.
|
|
19
19
|
The `/user-releases` feed serves template notes as `updateNotes: {en?, tr?: {fixed[], new[]}}`. Older title-and-notes bodies keep `plainWords` and get `updateNotes: null`.
|
|
20
20
|
|
|
21
21
|
Read META and name the lane before describing or executing anything:
|