@mutmutco/codex-plugin 4.5.145 → 4.5.147

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.145",
3
+ "version": "4.5.147",
4
4
  "mmiCompat": "4.x",
5
5
  "description": "MMI workflow skills and org gates delivery.",
6
6
  "author": {
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.145",
18281
- tag: "v4.5.145",
18282
- commit: "765f3b953988",
18283
- npm: "@mutmutco/cli@4.5.145"
18280
+ version: "4.5.147",
18281
+ tag: "v4.5.147",
18282
+ commit: "c21970738b82",
18283
+ npm: "@mutmutco/cli@4.5.147"
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.145"
18300
+ v3Target: "v4.5.147"
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.145 and redeploy the Hub Lambda from tag v4.5.145 (765f3b953988); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18307
- v3Target: "v4.5.145 (@mutmutco/cli@4.5.145, tag commit 765f3b953988 \u2014 last known-good release carrying the repo-index v4-only contract)"
18306
+ mechanism: "npm dist-tag latest -> 4.5.147 and redeploy the Hub Lambda from tag v4.5.147 (c21970738b82); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18307
+ v3Target: "v4.5.147 (@mutmutco/cli@4.5.147, tag commit c21970738b82 \u2014 last known-good release carrying the repo-index v4-only contract)"
18308
18308
  }
18309
18309
  },
18310
18310
  {
@@ -39981,6 +39981,7 @@ async function updatePrHeadFromBase(input) {
39981
39981
  throw new Error(`GitHub accepted the update of ${input.head} from ${input.base} but the head did not move \u2014 check the PR, then rerun`);
39982
39982
  }
39983
39983
  var PR_LAND_POLL_MS = 6e4;
39984
+ var PR_LAND_EJECT_CONFIRM_MS = 2e4;
39984
39985
  var PR_LAND_ENQUEUE_TIMEOUT_MS = 10 * 6e4;
39985
39986
  var PR_LAND_STATE_READ_RETRIES = 3;
39986
39987
  var PR_LAND_STATE_READ_DELAY_MS = 15e3;
@@ -40155,6 +40156,13 @@ async function pollPrMergeQueue(pr, options, deps, base, snapshot, deadlineMs) {
40155
40156
  deps.queueProgress?.(base);
40156
40157
  if (options.enqueueOnly) return { ...base, status: "queued" };
40157
40158
  } else if (read.state === "OPEN" && !read.autoMergeRequest) {
40159
+ await sleep2(PR_LAND_EJECT_CONFIRM_MS);
40160
+ const again = await deps.readMergeQueue(pr, base.repo);
40161
+ if (again.state === "MERGED") return queueMerged(base, deps);
40162
+ if (again.isInMergeQueue || again.autoMergeRequest) {
40163
+ snapshot = again;
40164
+ continue;
40165
+ }
40158
40166
  const run = await deps.findMergeGroupRun(pr, base.repo, base.base);
40159
40167
  const result2 = {
40160
40168
  ...base,
@@ -41226,6 +41234,32 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh2, opts) {
41226
41234
  return void 0;
41227
41235
  }
41228
41236
  }
41237
+ async function ghAdminTrueMergeWhenClean(prNumber, repo, opts = {}) {
41238
+ const io = opts.io ?? defaultGhMergeAutoIo;
41239
+ const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
41240
+ const pollMs = opts.pollMs ?? 15e3;
41241
+ const deadline = Date.now() + (opts.timeoutMs ?? 20 * 6e4);
41242
+ for (; ; ) {
41243
+ const raw = await io.gh(["pr", "view", prNumber, "--repo", repo, "--json", "state,mergeStateStatus"], GC_GH_TIMEOUT_MS).catch(() => "");
41244
+ let view = {};
41245
+ try {
41246
+ view = JSON.parse(raw);
41247
+ } catch {
41248
+ }
41249
+ if (view.state === "MERGED") return { mergeStatus: "merged" };
41250
+ if (view.state === "CLOSED") return { mergeStatus: "failed", error: `PR #${prNumber} was closed without a merge` };
41251
+ if (view.mergeStateStatus === "CLEAN") break;
41252
+ if (Date.now() >= deadline) return { mergeStatus: "failed", error: `PR #${prNumber} not CLEAN before the deadline (${view.mergeStateStatus ?? "unread"})` };
41253
+ await sleep2(pollMs);
41254
+ }
41255
+ try {
41256
+ await io.gh(["pr", "merge", prNumber, "--repo", repo, "--merge", "--admin"], GH_MUTATION_TIMEOUT_MS);
41257
+ } catch (e) {
41258
+ const message2 = String(e.message || "");
41259
+ if (!/already been merged/i.test(message2)) return { mergeStatus: "failed", error: ghFailureReason(e) };
41260
+ }
41261
+ return { mergeStatus: "merged" };
41262
+ }
41229
41263
  async function ghMergeAutoEnqueue(prNumber, repo, method, extra) {
41230
41264
  const io = extra?.io ?? defaultGhMergeAutoIo;
41231
41265
  const args = repo ? ["--repo", repo] : [];
@@ -41414,6 +41448,69 @@ async function deleteMergedRemoteBranch(options) {
41414
41448
  };
41415
41449
  }
41416
41450
 
41451
+ // src/pr-merge-queue.ts
41452
+ init_cli_shared();
41453
+ var readApi = async (args) => {
41454
+ const env = await ghReadEnv();
41455
+ return (await execFileP("gh", ["api", ...args], {
41456
+ timeout: 2e4,
41457
+ ...env ? { env } : {}
41458
+ })).stdout;
41459
+ };
41460
+ async function queueGraphql(repo, fields, gh2) {
41461
+ const [owner, name] = repo.split("/");
41462
+ const response = JSON.parse(await gh2(["graphql", "-f", `query=query { repository(owner:${JSON.stringify(owner)},name:${JSON.stringify(name)}) { ${fields} } }`]));
41463
+ if (response.errors?.length) throw new Error(response.errors.map((e) => e.message).join("; "));
41464
+ if (!response.data?.repository) throw new Error("merge queue repository read failed");
41465
+ return response.data.repository;
41466
+ }
41467
+ async function hasPrMergeQueue(repo, base, gh2 = readApi) {
41468
+ const result = await queueGraphql(repo, `mergeQueue(branch:${JSON.stringify(base)}) { id }`, gh2);
41469
+ return result.mergeQueue !== null;
41470
+ }
41471
+ async function readPrMergeQueueMethod(repo, base, gh2 = readApi) {
41472
+ const result = await queueGraphql(
41473
+ repo,
41474
+ `mergeQueue(branch:${JSON.stringify(base)}) { configuration { mergeMethod } }`,
41475
+ gh2
41476
+ );
41477
+ return result.mergeQueue ? result.mergeQueue.configuration?.mergeMethod ?? "UNKNOWN" : void 0;
41478
+ }
41479
+ function decideQueueMergeRoute(queueMethod, method, headRef) {
41480
+ if (!queueMethod || `--${queueMethod.toLowerCase()}` === method) return "normal";
41481
+ return method === "--merge" && /^(release-align|hotfix-fold)\//.test(headRef) ? "admin-true-merge" : "refuse";
41482
+ }
41483
+ async function readPrMergeQueue(pr, repo, gh2 = readApi) {
41484
+ if (!/^\d+$/.test(pr)) throw new Error("merge queue read requires a PR number");
41485
+ const result = await queueGraphql(
41486
+ repo,
41487
+ `pullRequest(number:${pr}) { state isInMergeQueue mergeQueueEntry { state position } autoMergeRequest { enabledAt } }`,
41488
+ gh2
41489
+ );
41490
+ if (!result.pullRequest) throw new Error(`merge queue PR #${pr} not found`);
41491
+ return result.pullRequest;
41492
+ }
41493
+ async function findPrMergeGroupRun(pr, repo, base, gh2 = readApi) {
41494
+ const pages = JSON.parse(await gh2([`repos/${repo}/actions/runs?event=merge_group&per_page=100`, "--paginate", "--slurp"]));
41495
+ const prefix = `gh-readonly-queue/${base}/pr-${pr}-`;
41496
+ const run = pages.flatMap((page) => page.workflow_runs).filter((run2) => run2.head_branch?.startsWith(prefix)).sort((a, b) => b.created_at.localeCompare(a.created_at) || b.id - a.id)[0];
41497
+ return run ? { id: run.id, url: run.html_url, conclusion: run.conclusion } : void 0;
41498
+ }
41499
+ function prMergeQueueLine(result) {
41500
+ const queue = result.mergeQueue;
41501
+ if (!queue) return void 0;
41502
+ switch (queue.state) {
41503
+ case "queued":
41504
+ return `pr land: PR #${result.pr} queued on ${queue.base}${queue.position === void 0 ? "" : ` (position ${queue.position})`}`;
41505
+ case "merged":
41506
+ return `pr land: PR #${result.pr} merged via merge queue`;
41507
+ case "ejected":
41508
+ return `pr land: PR #${result.pr} ejected from merge queue \u2014 ${queue.ejectedRun ? `merge_group run ${queue.ejectedRun.id} ${queue.ejectedRun.conclusion} ${queue.ejectedRun.url}` : "merge_group run not found"}`;
41509
+ case "timeout":
41510
+ return `pr land: PR #${result.pr} merge queue timeout on ${queue.base}`;
41511
+ }
41512
+ }
41513
+
41417
41514
  // src/project-info-sync.ts
41418
41515
  var import_node_fs34 = require("node:fs");
41419
41516
  var import_node_path33 = require("node:path");
@@ -42022,57 +42119,6 @@ function applyChecklistCheck(body, query, checked) {
42022
42119
  return { ok: true, edit: setChecklistMarker(body, sel.item, checked), item: sel.item };
42023
42120
  }
42024
42121
 
42025
- // src/pr-merge-queue.ts
42026
- init_cli_shared();
42027
- var readApi = async (args) => {
42028
- const env = await ghReadEnv();
42029
- return (await execFileP("gh", ["api", ...args], {
42030
- timeout: 2e4,
42031
- ...env ? { env } : {}
42032
- })).stdout;
42033
- };
42034
- async function queueGraphql(repo, fields, gh2) {
42035
- const [owner, name] = repo.split("/");
42036
- const response = JSON.parse(await gh2(["graphql", "-f", `query=query { repository(owner:${JSON.stringify(owner)},name:${JSON.stringify(name)}) { ${fields} } }`]));
42037
- if (response.errors?.length) throw new Error(response.errors.map((e) => e.message).join("; "));
42038
- if (!response.data?.repository) throw new Error("merge queue repository read failed");
42039
- return response.data.repository;
42040
- }
42041
- async function hasPrMergeQueue(repo, base, gh2 = readApi) {
42042
- const result = await queueGraphql(repo, `mergeQueue(branch:${JSON.stringify(base)}) { id }`, gh2);
42043
- return result.mergeQueue !== null;
42044
- }
42045
- async function readPrMergeQueue(pr, repo, gh2 = readApi) {
42046
- if (!/^\d+$/.test(pr)) throw new Error("merge queue read requires a PR number");
42047
- const result = await queueGraphql(
42048
- repo,
42049
- `pullRequest(number:${pr}) { state isInMergeQueue mergeQueueEntry { state position } autoMergeRequest { enabledAt } }`,
42050
- gh2
42051
- );
42052
- if (!result.pullRequest) throw new Error(`merge queue PR #${pr} not found`);
42053
- return result.pullRequest;
42054
- }
42055
- async function findPrMergeGroupRun(pr, repo, base, gh2 = readApi) {
42056
- const pages = JSON.parse(await gh2([`repos/${repo}/actions/runs?event=merge_group&per_page=100`, "--paginate", "--slurp"]));
42057
- const prefix = `gh-readonly-queue/${base}/pr-${pr}-`;
42058
- const run = pages.flatMap((page) => page.workflow_runs).filter((run2) => run2.head_branch?.startsWith(prefix)).sort((a, b) => b.created_at.localeCompare(a.created_at) || b.id - a.id)[0];
42059
- return run ? { id: run.id, url: run.html_url, conclusion: run.conclusion } : void 0;
42060
- }
42061
- function prMergeQueueLine(result) {
42062
- const queue = result.mergeQueue;
42063
- if (!queue) return void 0;
42064
- switch (queue.state) {
42065
- case "queued":
42066
- return `pr land: PR #${result.pr} queued on ${queue.base}${queue.position === void 0 ? "" : ` (position ${queue.position})`}`;
42067
- case "merged":
42068
- return `pr land: PR #${result.pr} merged via merge queue`;
42069
- case "ejected":
42070
- return `pr land: PR #${result.pr} ejected from merge queue \u2014 ${queue.ejectedRun ? `merge_group run ${queue.ejectedRun.id} ${queue.ejectedRun.conclusion} ${queue.ejectedRun.url}` : "merge_group run not found"}`;
42071
- case "timeout":
42072
- return `pr land: PR #${result.pr} merge queue timeout on ${queue.base}`;
42073
- }
42074
- }
42075
-
42076
42122
  // src/command-register-collaboration.ts
42077
42123
  init_github_client();
42078
42124
  init_github_quota();
@@ -47351,6 +47397,25 @@ ${list}`);
47351
47397
  return true;
47352
47398
  };
47353
47399
  if (o.wait && !await runWaitGate()) return;
47400
+ if (prMeta.state === "OPEN") {
47401
+ const queueMethod = await readPrMergeQueueMethod(repoForPostCleanup, baseRef);
47402
+ const route = decideQueueMergeRoute(queueMethod, method, headRef);
47403
+ if (route === "refuse") {
47404
+ throw new Error(`pr merge: ${baseRef} in ${repoForPostCleanup} merges through a ${queueMethod} merge queue, which would land ${method} as ${queueMethod}. Use --squash (or pr land); only release-align/ and hotfix-fold/ train PRs true-merge outside the queue (#8304).`);
47405
+ }
47406
+ if (route === "admin-true-merge") {
47407
+ console.warn(`pr merge: ${baseRef} has a ${queueMethod} merge queue \u2014 landing train PR #${number} as a true merge through the ruleset bypass once it is CLEAN (#8296).`);
47408
+ const res = await ghAdminTrueMergeWhenClean(number, repoForPostCleanup);
47409
+ if (res.mergeStatus !== "merged") {
47410
+ console.log(JSON.stringify({ mergeStatus: "not-merged", reason: "admin-true-merge-failed", pr: number, branch: headRef, error: res.error }));
47411
+ console.error(`pr merge: train PR #${number} not merged \u2014 ${res.error}`);
47412
+ process.exitCode = 1;
47413
+ return;
47414
+ }
47415
+ console.log(JSON.stringify({ mergeStatus: "merged", method: "merge", via: "ruleset-bypass", pr: number, branch: headRef }));
47416
+ return;
47417
+ }
47418
+ }
47354
47419
  if (ciPolicy.policy === "no-ci") {
47355
47420
  const guard = decidePrMergeNoCiGuard(await pollGhPrChecks(number, repoArgs), ciPolicy.reason);
47356
47421
  if (guard.action === "refuse") throw new Error(`gh pr merge ${number}: ${guard.message}`);
@@ -47825,7 +47890,11 @@ function trainApplyDeps() {
47825
47890
  // #2737: enqueue GitHub auto-merge on the `main -> development` alignment PR the release opens, so the
47826
47891
  // train lands the back-merge itself instead of leaving a manual step. Same enqueue path `pr land` uses,
47827
47892
  // but method `--merge` (NOT squash): the misalignment guard needs the merge parentage to survive.
47828
- mergeAuto: (prNumber, repo) => ghMergeAutoEnqueue(prNumber, repo, "--merge"),
47893
+ // #8296: a merge-queue base squashes, so there the train waits for green and true-merges via admin bypass.
47894
+ mergeAuto: async (prNumber, repo) => {
47895
+ const base = (await execFileP("gh", ["pr", "view", prNumber, "--repo", repo, "--json", "baseRefName", "--jq", ".baseRefName"], { timeout: GH_TRAIN_TIMEOUT_MS })).stdout.trim();
47896
+ return base && await hasPrMergeQueue(repo, base) ? ghAdminTrueMergeWhenClean(prNumber, repo) : ghMergeAutoEnqueue(prNumber, repo, "--merge");
47897
+ },
47829
47898
  // Slack release announcement (#883/#6521/#6523): the org alerts channel for the Hub, the project's own
47830
47899
  // registry releaseChannel META for a product repo — best-effort inside announceRelease itself.
47831
47900
  announce: (args) => announceRelease({
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.145",
3
+ "version": "4.5.147",
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.145",
3
+ "version": "4.5.147",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",
@@ -48,7 +48,7 @@ env:
48
48
  # innocent queued runs — MMC-ZuberShade#880). Pushes group by ref: each tag and the train
49
49
  # branch supersede only themselves.
50
50
  concurrency:
51
- group: gate-${{ github.event.pull_request.number || github.ref }}
51
+ group: gate-${{ github.event.pull_request.number || (github.event_name == 'push' && github.sha) || github.ref }}
52
52
  cancel-in-progress: true
53
53
 
54
54
  permissions:
@@ -7,7 +7,7 @@ on:
7
7
  branches: {{GATE_PUSH_BRANCHES_YAML}}
8
8
  tags: ['v*']
9
9
  concurrency:
10
- group: gate-${{ github.event.pull_request.number || github.ref }}
10
+ group: gate-${{ github.event.pull_request.number || (github.event_name == 'push' && github.sha) || github.ref }}
11
11
  cancel-in-progress: true
12
12
  permissions:
13
13
  actions: read # #8206: exact-SHA development workflow verdict
@@ -10,7 +10,7 @@ on:
10
10
  tags: ['v*']
11
11
  # Cancel superseded runs per PR, or per branch for pushes (MMI-Hub#7515, #3001; as MM-Strategy#415).
12
12
  concurrency:
13
- group: screens-${{ github.event.pull_request.number || github.ref }}
13
+ group: screens-${{ github.event.pull_request.number || (github.event_name == 'push' && github.sha) || github.ref }}
14
14
  cancel-in-progress: true
15
15
  permissions:
16
16
  contents: read