@mutmutco/codex-plugin 4.6.8 → 4.6.9

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.6.8",
3
+ "version": "4.6.9",
4
4
  "mmiCompat": "4.x",
5
5
  "description": "MMI workflow skills and org gates delivery.",
6
6
  "author": {
package/cli/dist/main.cjs CHANGED
@@ -1236,7 +1236,7 @@ var init_house_map = __esm({
1236
1236
  api: "devops",
1237
1237
  // allowlisted GitHub REST GET reads for automation (pull files, compare, contents)
1238
1238
  run: "devops",
1239
- // #9479: one named workflow run — currently the bounded `run cancel <id>` write
1239
+ // #9479: one named workflow run — the bounded `run cancel <id>` and `run rerun <id>` writes
1240
1240
  ci: "devops",
1241
1241
  // the CI/gate audit
1242
1242
  jev: "devops",
@@ -15347,6 +15347,8 @@ var APP_WRITE_COMMANDS = /* @__PURE__ */ new Map([
15347
15347
  ["ci cancel-orphans", { metadata: "read", actions: "write" }],
15348
15348
  // #9479: one named run cancelled under the same actions:write profile as the orphan sweep.
15349
15349
  ["run cancel", { metadata: "read", actions: "write" }],
15350
+ // #9587: one named run rerun (all or failed jobs) — same actions:write profile, nothing broader.
15351
+ ["run rerun", { metadata: "read", actions: "write" }],
15350
15352
  ["issue comment", { metadata: "read", issues: "write", pull_requests: "write" }],
15351
15353
  // #8401: the detached related-issue lookup (issue list/view reads + one marker comment) — no identity contract.
15352
15354
  ["issue discover-related", { metadata: "read", issues: "write" }]
@@ -25039,10 +25041,15 @@ function checkRunbookCoverage(docs, base, git3) {
25039
25041
  const heading = headings[i];
25040
25042
  const end = headings.slice(i + 1).find((h) => h.level <= heading.level)?.start ?? lines2.length + 1;
25041
25043
  const markerEnd = headings[i + 1]?.start ?? end;
25042
- const globs = lines2.slice(heading.start, markerEnd - 1).flatMap((text) => /<!--\s*runbook-covers:\s*(.*?)\s*-->/.exec(text)?.[1].split(",").map((s) => s.trim()) ?? []);
25044
+ const markers = lines2.slice(heading.start, markerEnd - 1).flatMap((text, j) => {
25045
+ const found = /<!--\s*runbook-covers:\s*(.*?)\s*-->/.exec(text)?.[1].split(",").map((s) => s.trim());
25046
+ return found ? [{ line: heading.start + 1 + j, globs: found }] : [];
25047
+ });
25048
+ const globs = markers.flatMap((m) => m.globs);
25043
25049
  const affected = changed.filter((path2) => globs.some((glob) => matches(glob, path2)) && !changesOnlyUses(path2));
25044
25050
  if (affected.length && !ranges.some((r) => r.count > 0 && r.start < end && r.start + r.count > heading.start)) {
25045
- findings.push({ kind: "runbook-section-stale", doc, line: heading.start, detail: `${heading.title} (lines ${heading.start}\u2013${end - 1}): changed ${affected.join(", ")}; update this section's text (lines ${heading.start}\u2013${end - 1}) or runbook-covers list, or add a \`Runbook-Unaffected: <reason>\` trailer to a commit message in this PR`, section: { heading: heading.title, level: heading.level, startLine: heading.start, endLine: end - 1, covers: globs }, sources: affected });
25051
+ const markerLine = markers.find((m) => m.globs.some((glob) => affected.some((path2) => matches(glob, path2)))).line;
25052
+ findings.push({ kind: "runbook-section-stale", doc, line: markerLine, detail: `${heading.title} (lines ${heading.start}\u2013${end - 1}, covers marker at line ${markerLine}): changed ${affected.join(", ")}; update this section's text (lines ${heading.start}\u2013${end - 1}) or runbook-covers list, or add a \`Runbook-Unaffected: <reason>\` trailer to a commit message in this PR`, section: { heading: heading.title, level: heading.level, startLine: heading.start, endLine: end - 1, covers: globs }, sources: affected });
25046
25053
  }
25047
25054
  }
25048
25055
  }
@@ -27506,10 +27513,10 @@ var rollout_plan_default = {
27506
27513
  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)."
27507
27514
  },
27508
27515
  baseline: {
27509
- version: "4.6.8",
27510
- tag: "v4.6.8",
27511
- commit: "0dd075a0d2c1",
27512
- npm: "@mutmutco/cli@4.6.8"
27516
+ version: "4.6.9",
27517
+ tag: "v4.6.9",
27518
+ commit: "7cbf84926132",
27519
+ npm: "@mutmutco/cli@4.6.9"
27513
27520
  },
27514
27521
  exitCriterion: "fleet-n-of-n",
27515
27522
  hubOnlyShortcut: "forbidden",
@@ -27526,14 +27533,14 @@ var rollout_plan_default = {
27526
27533
  repo: "mutmutco/mmi-hub",
27527
27534
  role: "canary",
27528
27535
  schedule: "train",
27529
- v3Target: "v4.6.8"
27536
+ v3Target: "v4.6.9"
27530
27537
  }
27531
27538
  ],
27532
27539
  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.",
27533
27540
  rollback: {
27534
27541
  independent: true,
27535
- mechanism: "npm dist-tag latest -> 4.6.8 and redeploy the Hub Lambda from tag v4.6.8 (0dd075a0d2c1); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27536
- v3Target: "v4.6.8 (@mutmutco/cli@4.6.8, tag commit 0dd075a0d2c1 \u2014 last known-good release carrying the repo-index v4-only contract)"
27542
+ mechanism: "npm dist-tag latest -> 4.6.9 and redeploy the Hub Lambda from tag v4.6.9 (7cbf84926132); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27543
+ v3Target: "v4.6.9 (@mutmutco/cli@4.6.9, tag commit 7cbf84926132 \u2014 last known-good release carrying the repo-index v4-only contract)"
27537
27544
  }
27538
27545
  },
27539
27546
  {
@@ -32106,8 +32113,11 @@ function classifyRunnerCost(selector) {
32106
32113
  }
32107
32114
  var STANDARD_HOSTED_ALLOWLIST = [
32108
32115
  ["mutmutco/MMI-Hub", ".github/workflows/launcher-build.yml", "build", "windows-latest"],
32109
- ["mutmutco/Jerv-JervCode", ".github/workflows/release-archives.yml", "release-platform-arm64", "windows-11-arm"]
32116
+ ["mutmutco/Jerv-JervCode", ".github/workflows/release-archives.yml", "release-platform-arm64", "windows-11-arm"],
32117
+ // #9571 (MM-Work#8894 chooser): owned mmi-heavy first, included ubuntu-latest only on a deep backlog.
32118
+ ["mutmutco/MMI-Hub", ".github/workflows/gate.yml", "cli-part", "hosted-spill"]
32110
32119
  ];
32120
+ var HOSTED_SPILL_RE = /^\$\{\{\s*(?:matrix\.[\w-]+\s*==\s*'[\w-]+'\s*&&\s*'([^']+)'\s*\|\|\s*)?fromJSON\(needs\.[\w-]+\.outputs\.heavy_runs_on\s*\|\|\s*('[^']+')\)\s*\}\}$/;
32111
32121
  function standardHostedLabelFor(repo, path2, jobId) {
32112
32122
  if (repo === "mutmutco/Jerv-Hub") return ["ubuntu-latest", "windows-latest", "macos-14"];
32113
32123
  return STANDARD_HOSTED_ALLOWLIST.find(([r, p, j]) => r === repo && p === path2 && j === jobId)?.[3];
@@ -32122,6 +32132,8 @@ function classifyJobRunnerCost(job, allowance2) {
32122
32132
  if (approved(raw) || allowance2 === "windows-11-arm" && raw === allowance2) return "standard-hosted";
32123
32133
  const fallback = /^\$\{\{\s*vars\.MMI_RUNNER_FALLBACK\s*==\s*'hosted'\s*&&\s*'([^']+)'\s*\|\|\s*(fromJSON\('[^']+'\))\s*\}\}$/.exec(raw);
32124
32134
  if (fallback && approved(fallback[1]) && classifyRunnerCost("${{ " + fallback[2] + " }}") === "self-hosted") return "standard-hosted";
32135
+ const spill = allowance2 === "hosted-spill" ? HOSTED_SPILL_RE.exec(raw) : null;
32136
+ if (spill) return (!spill[1] || spill[1] === "ubuntu-latest") && classifyRunnerCost(`\${{ fromJSON(${spill[2]}) }}`) === "self-hosted" ? "standard-hosted" : "unknown";
32125
32137
  const direct = classifyRunnerCost(raw);
32126
32138
  const matrix = /^\$\{\{\s*matrix\.([\w-]+)(?:\.([\w-]+))?\s*\}\}$/.exec(raw);
32127
32139
  if (!matrix || direct === "hosted") return direct;
@@ -38643,7 +38655,7 @@ function runsOnLabelSets(job) {
38643
38655
  if (plainRecord(selector)) selector = selector.labels;
38644
38656
  if (typeof selector !== "string" || !selector.includes("${{")) return [toSet(selector)].filter((s) => Boolean(s));
38645
38657
  const sets = [];
38646
- for (const m of selector.matchAll(/fromJSON\('([^']+)'\)/g)) {
38658
+ for (const m of selector.matchAll(/fromJSON\((?:needs\.[\w-]+\.outputs\.[\w-]+\s*\|\|\s*)?'([^']+)'\)/g)) {
38647
38659
  try {
38648
38660
  const parsed = toSet(JSON.parse(m[1]));
38649
38661
  if (parsed) sets.push(parsed);
@@ -43366,6 +43378,57 @@ function registerRunCancel(run, writeToken) {
43366
43378
  else console.log(`run cancel: ${receipt.repo} run ${receipt.runId} \u2014 ${receipt.force ? "force-cancel" : "cancel"} requested (status: ${receipt.status}${receipt.runStatus ? `, runStatus: ${receipt.runStatus}` : ""})`);
43367
43379
  });
43368
43380
  }
43381
+ var RUN_RERUN_STATUS = "rerun-requested";
43382
+ async function rerunWorkflowRun(repo, id, deps, failed2 = false) {
43383
+ const raw = String(id).trim();
43384
+ if (!/^[1-9]\d*$/.test(raw)) throw new Error(`run rerun: <id> must be a positive workflow run id (received '${String(id)}')`);
43385
+ const runId = Number(raw);
43386
+ if (!Number.isSafeInteger(runId)) throw new Error(`run rerun: <id> ${raw} is beyond the safe integer range; refusing to address a different run`);
43387
+ if (!/^[\w.-]+\/[\w.-]+$/.test(repo)) throw new Error(`run rerun: --repo must be owner/repo (received '${repo}')`);
43388
+ const projects = await deps.projects();
43389
+ if (!projects) throw new Error("run rerun: the Hub project registry is unreadable; refusing to rerun on a repo this command cannot prove registered");
43390
+ const key = registryRepoKey(repo);
43391
+ if (!projects.some((p) => (p.repos ?? []).some((r) => typeof r === "string" && registryRepoKey(qualifyRegistryRepo(r)) === key))) {
43392
+ throw new Error(`run rerun: ${repo} is not a registered org repo; App writes are limited to repos in the Hub registry`);
43393
+ }
43394
+ const mode = failed2 ? "failed" : "all";
43395
+ let httpStatus;
43396
+ try {
43397
+ httpStatus = await deps.post(`repos/${repo}/actions/runs/${runId}/${failed2 ? "rerun-failed-jobs" : "rerun"}`);
43398
+ } catch (error) {
43399
+ const e = error;
43400
+ const detail = String(e.stderr ?? error);
43401
+ const code = /\bHTTP(?:\/[\d.]+)? (\d{3})\b/.exec(`${detail} ${e.stdout ?? ""}`)?.[1];
43402
+ if (code === "403") throw new Error(`run rerun: GitHub App denied (HTTP 403) on ${repo}; actions:write permission is required; no personal-token fallback`);
43403
+ if (code === "404") throw new Error(`run rerun: run ${runId} not found on ${repo} (HTTP 404), or the App cannot see that repo`);
43404
+ if (code === "409" || code === "422") throw new Error(`run rerun: run ${runId} is not rerunnable (HTTP ${code}); it may still be in progress, or be past GitHub's rerun window`);
43405
+ throw new Error(`run rerun: ${detail}`);
43406
+ }
43407
+ return { ok: true, repo, runId, mode, httpStatus, credential: "app_installation", status: RUN_RERUN_STATUS };
43408
+ }
43409
+ function appRunPost(writeToken, exec3 = execFileP) {
43410
+ let token;
43411
+ return async (path2) => {
43412
+ token ??= await writeToken();
43413
+ const { stdout } = await exec3("gh", ["api", "--include", "--method", "POST", path2], {
43414
+ timeout: 2e4,
43415
+ env: { ...process.env, GH_TOKEN: token, MMI_GH_POOL: "app" }
43416
+ });
43417
+ return Number(/^HTTP\/[\d.]+ (\d{3})/.exec(stdout)?.[1] ?? 0);
43418
+ };
43419
+ }
43420
+ function registerRunRerun(run, writeToken, projects) {
43421
+ run.command("rerun <id>").description("rerun one workflow run on the org App (actions:write), registered repos only; --failed reruns only the failed jobs; prints a receipt").requiredOption("--repo <owner/repo>", "registered repository that owns the run").option("--failed", "rerun only the failed jobs (POST .../rerun-failed-jobs)").option("--json", "machine-readable receipt").action(async (id, options) => {
43422
+ let receipt;
43423
+ try {
43424
+ receipt = await rerunWorkflowRun(options.repo, id, { projects, post: appRunPost(writeToken) }, options.failed === true);
43425
+ } catch (error) {
43426
+ return fail(error.message);
43427
+ }
43428
+ if (options.json) console.log(JSON.stringify(receipt));
43429
+ else console.log(`run rerun: ${receipt.repo} run ${receipt.runId} \u2014 ${receipt.mode === "failed" ? "failed jobs" : "all jobs"} rerun requested (HTTP ${receipt.httpStatus}, credential: ${receipt.credential})`);
43430
+ });
43431
+ }
43369
43432
 
43370
43433
  // src/board-commands.ts
43371
43434
  init_cli_shared();
@@ -69965,7 +70028,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
69965
70028
  appActorCommand = commandPath4;
69966
70029
  setAuditCommand(commandPath4);
69967
70030
  if (commandPath4 !== "whoami diagnose-hub") emitCliCallTelemetry(commandPath4);
69968
- if (commandPath4 === "ci cancel-orphans" || commandPath4 === "run cancel") return;
70031
+ if (commandPath4 === "ci cancel-orphans" || commandPath4 === "run cancel" || commandPath4 === "run rerun") return;
69969
70032
  try {
69970
70033
  await activateAppActor(commandPath4, process.env, () => APP_WRITE_COMMANDS.has(commandPath4) ? mintCommandWriteToken(appActorDeps(), commandPath4) : mintInstallationToken(appActorDeps()));
69971
70034
  } catch (e) {
@@ -70800,9 +70863,12 @@ ci.command("audit").description("read-only fleet scan: gate workflow, ruleset co
70800
70863
  });
70801
70864
  registerCiChecksWait(ci);
70802
70865
  registerCancelOrphans(ci, async () => (await mintCommandWriteToken(appActorDeps(), "ci cancel-orphans")).token);
70803
- registerRunCancel(
70804
- program2.command("run").description("bounded workflow-run writes \u2014 `run cancel <id>` is the only one, and it rides the org App actions:write profile"),
70805
- async () => activeAppToken() ?? (await mintCommandWriteToken(appActorDeps(), "run cancel")).token
70866
+ var runRoot = program2.command("run").description("bounded workflow-run writes \u2014 `run cancel <id>` and `run rerun <id> [--failed]`, both on the org App actions:write profile");
70867
+ registerRunCancel(runRoot, async () => activeAppToken() ?? (await mintCommandWriteToken(appActorDeps(), "run cancel")).token);
70868
+ registerRunRerun(
70869
+ runRoot,
70870
+ async () => activeAppToken() ?? (await mintCommandWriteToken(appActorDeps(), "run rerun")).token,
70871
+ async () => fetchProjectsList(registryClientDeps(await loadConfig()))
70806
70872
  );
70807
70873
  ci.command("reconcile").description("audit + optionally apply merge settings and product ruleset activation (master-admin)").option("--json", "machine-readable output").option("--repo <owner/repo>", "reconcile one repo instead of the full registry").option("--apply", "PATCH merge settings + activate product ruleset when missing (master role required); activation is skipped while the repo's gate has never passed (#3694)").option("--park-ruleset", "stop the product ruleset enforcing without deleting it \u2014 keeps its required contexts (master role required)").action(async (o) => {
70808
70874
  if (o.apply && o.parkRuleset) {
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.6.8",
3
+ "version": "4.6.9",
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.6.8",
3
+ "version": "4.6.9",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",