@mutmutco/cli 4.5.152 → 4.5.153

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 CHANGED
@@ -7081,6 +7081,12 @@ var APP_ELIGIBLE_COMMANDS = /* @__PURE__ */ new Set([
7081
7081
  "read run watch",
7082
7082
  "read run log",
7083
7083
  // #8136: bounded jobs/logs REST read, same polling credential.
7084
+ "read pr list",
7085
+ // #8347: stored-field PR list; author/viewer-dependent filters refused.
7086
+ "read pr diff",
7087
+ // #8347: fixed PR diff read; no viewer fields.
7088
+ "read pr queue",
7089
+ // #8347: fixed mergeQueueEntry query; no generic GraphQL or viewer resolution.
7084
7090
  "read pr view",
7085
7091
  "read pr checks",
7086
7092
  "read issue view",
@@ -16415,6 +16421,33 @@ function defaultTrackedFirstSegments(root, firstSegments, exec3 = import_node_ch
16415
16421
  throw error;
16416
16422
  }
16417
16423
  }
16424
+ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
16425
+ const env = deps.env ?? process.env;
16426
+ if (env.GITHUB_EVENT_NAME !== "merge_group") return "";
16427
+ let source = "merge_group event payload";
16428
+ try {
16429
+ const event = JSON.parse(readFile10(env.GITHUB_EVENT_PATH ?? "") ?? "");
16430
+ const match = /^refs\/heads\/gh-readonly-queue\/.+\/pr-([1-9]\d*)-[a-f0-9]+$/.exec(event.merge_group?.head_ref ?? "");
16431
+ const repo = env.GITHUB_REPOSITORY;
16432
+ if (!match || !repo || !/^[\w.-]+\/[\w.-]+$/.test(repo)) throw new Error("invalid queue source");
16433
+ source = `repos/${repo}/pulls/${match[1]}/commits`;
16434
+ const gh2 = deps.gh ?? ((args) => (0, import_node_child_process6.execFileSync)("gh", args, {
16435
+ cwd: root,
16436
+ encoding: "utf8",
16437
+ windowsHide: true,
16438
+ timeout: 3e4,
16439
+ maxBuffer: CHECK_IGNORE_MAX_BUFFER,
16440
+ env: { ...env, GH_TOKEN: env.GH_TOKEN || env.GITHUB_TOKEN },
16441
+ stdio: ["ignore", "pipe", "pipe"]
16442
+ }));
16443
+ const pages = JSON.parse(gh2(["api", source, "--paginate", "--slurp"]));
16444
+ if (!Array.isArray(pages) || !pages.every((page) => Array.isArray(page) && page.every((commit) => typeof commit?.commit?.message === "string"))) throw new Error("invalid commit response");
16445
+ return pages.flat().map((commit) => commit.commit.message).join("\n");
16446
+ } catch {
16447
+ warnings.push({ kind: "runbook-source-unverified", doc: source, line: 0, detail: `failed to read ${source}; using git-log Runbook-Unaffected declarations only` });
16448
+ return "";
16449
+ }
16450
+ }
16418
16451
  function runDocRefs(root, deps = {}) {
16419
16452
  const readFile10 = deps.readFile ?? readFileOrNull;
16420
16453
  const exists = deps.exists ?? import_node_fs17.existsSync;
@@ -16451,7 +16484,10 @@ function runDocRefs(root, deps = {}) {
16451
16484
  if (deps.base) {
16452
16485
  const git3 = deps.git ?? ((args) => (0, import_node_child_process6.execFileSync)("git", args, { cwd: root, encoding: "utf8", maxBuffer: CHECK_IGNORE_MAX_BUFFER, windowsHide: true }));
16453
16486
  const stale = checkRunbookCoverage(runbooks, deps.base, git3);
16454
- const override = /^Runbook-Unaffected:[ \t]*\S.*$/m.test(git3(["log", "--format=%B", `${deps.base}..HEAD`]));
16487
+ const messages = git3(["log", "--format=%B", `${deps.base}..HEAD`]);
16488
+ const sourceMessages = stale.length ? mergeGroupRunbookMessages(root, deps, readFile10, warnings) : "";
16489
+ const override = /^Runbook-Unaffected:[ \t]*\S.*$/m.test(`${messages}
16490
+ ${sourceMessages}`);
16455
16491
  (override ? warnings : findings).push(...stale);
16456
16492
  }
16457
16493
  return {
@@ -18684,10 +18720,10 @@ var rollout_plan_default = {
18684
18720
  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)."
18685
18721
  },
18686
18722
  baseline: {
18687
- version: "4.5.152",
18688
- tag: "v4.5.152",
18689
- commit: "8437cd11d3f1",
18690
- npm: "@mutmutco/cli@4.5.152"
18723
+ version: "4.5.153",
18724
+ tag: "v4.5.153",
18725
+ commit: "57b23d8d7d5f",
18726
+ npm: "@mutmutco/cli@4.5.153"
18691
18727
  },
18692
18728
  exitCriterion: "fleet-n-of-n",
18693
18729
  hubOnlyShortcut: "forbidden",
@@ -18704,14 +18740,14 @@ var rollout_plan_default = {
18704
18740
  repo: "mutmutco/mmi-hub",
18705
18741
  role: "canary",
18706
18742
  schedule: "train",
18707
- v3Target: "v4.5.152"
18743
+ v3Target: "v4.5.153"
18708
18744
  }
18709
18745
  ],
18710
18746
  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.",
18711
18747
  rollback: {
18712
18748
  independent: true,
18713
- mechanism: "npm dist-tag latest -> 4.5.152 and redeploy the Hub Lambda from tag v4.5.152 (8437cd11d3f1); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18714
- v3Target: "v4.5.152 (@mutmutco/cli@4.5.152, tag commit 8437cd11d3f1 \u2014 last known-good release carrying the repo-index v4-only contract)"
18749
+ mechanism: "npm dist-tag latest -> 4.5.153 and redeploy the Hub Lambda from tag v4.5.153 (57b23d8d7d5f); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
18750
+ v3Target: "v4.5.153 (@mutmutco/cli@4.5.153, tag commit 57b23d8d7d5f \u2014 last known-good release carrying the repo-index v4-only contract)"
18715
18751
  }
18716
18752
  },
18717
18753
  {
@@ -53140,6 +53176,46 @@ function parseBrokerAssignee(raw) {
53140
53176
  return v;
53141
53177
  }
53142
53178
  var SINGLE_SHOT_TIMEOUT_MS = 6e4;
53179
+ var BROKER_MAX_BUFFER = 64 * 1024 * 1024;
53180
+ var PR_QUEUE_QUERY = "query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){pullRequest(number:$number){mergeQueueEntry{state position enqueuedAt estimatedTimeToMerge headCommit{oid}}}}}";
53181
+ function buildPrQueueSpec(number, o) {
53182
+ const repo = parseBrokerRepo(o.repo, "--repo");
53183
+ if (!repo) throw new Error("read pr queue: --repo is required");
53184
+ const [owner, name] = repo.split("/");
53185
+ return { program: "gh", args: ["api", "graphql", "-f", `query=${PR_QUEUE_QUERY}`, "-f", `owner=${owner}`, "-f", `name=${name}`, "-F", `number=${parseBrokerId(number, "PR number")}`], timeoutMs: SINGLE_SHOT_TIMEOUT_MS };
53186
+ }
53187
+ function buildPrDiffSpec(number, o) {
53188
+ const args = withRepo(["pr", "diff", parseBrokerId(number, "PR number")], parseBrokerRepo(o.repo, "--repo"));
53189
+ if (o.nameOnly) args.push("--name-only");
53190
+ return { program: "gh", args, timeoutMs: SINGLE_SHOT_TIMEOUT_MS };
53191
+ }
53192
+ function parseBrokerPrSearch(raw) {
53193
+ const search = parseBrokerSearch(raw);
53194
+ if (search && /@me/i.test(search)) throw new Error("read: --search resolves the viewer \u2014 viewer-scoped reads stay personal");
53195
+ return search;
53196
+ }
53197
+ function parseBrokerPrState(raw) {
53198
+ if (raw === void 0) return void 0;
53199
+ if (!["open", "closed", "merged", "all"].includes(raw)) throw new Error("read: --state must be one of: open, closed, merged, all");
53200
+ return raw;
53201
+ }
53202
+ function buildPrListSpec(o) {
53203
+ const args = withJson(withRepo(["pr", "list"], parseBrokerRepo(o.repo, "--repo")), parseBrokerJsonFields(o.json), o.json);
53204
+ const state = parseBrokerPrState(o.state);
53205
+ if (state) args.push("--state", state);
53206
+ for (const flag of ["base", "head"]) {
53207
+ const branch = parseBrokerBranch(o[flag]);
53208
+ if (branch) args.push(`--${flag}`, branch);
53209
+ }
53210
+ const label = parseBrokerLabel(o.label);
53211
+ if (label !== void 0) args.push("--label", label);
53212
+ const search = parseBrokerPrSearch(o.search);
53213
+ if (search !== void 0) args.push("--search", search);
53214
+ const assignee = parseBrokerAssignee(o.assignee);
53215
+ if (assignee) args.push("--assignee", assignee);
53216
+ if (o.limit !== void 0) args.push("--limit", String(parseBrokerInt(o.limit, "--limit", 1, 100)));
53217
+ return { program: "gh", args, timeoutMs: SINGLE_SHOT_TIMEOUT_MS };
53218
+ }
53143
53219
  function withRepo(args, repo) {
53144
53220
  return repo ? [...args, "--repo", repo] : args;
53145
53221
  }
@@ -53332,7 +53408,7 @@ async function dispatchRestChecksRead(deps, resolveRepo2, label, spec, json) {
53332
53408
  process.exitCode = result.exitCode;
53333
53409
  }
53334
53410
  function registerAppReadBrokerCommands(program3, resolveRepo2, overrides) {
53335
- const ghRun = overrides?.ghRunner ?? (async (args, opts) => (await execFileP("gh", args, { timeout: opts.timeoutMs, env: opts.env })).stdout);
53411
+ const ghRun = overrides?.ghRunner ?? (async (args, opts) => (await execFileP("gh", args, { timeout: opts.timeoutMs, env: opts.env, maxBuffer: BROKER_MAX_BUFFER })).stdout);
53336
53412
  const restGhApi = overrides?.restGhApi ?? ((env) => ghApiWithEnv(env));
53337
53413
  const deps = { readRequired: readRequiredCheckRows, fetchSnapshot: fetchRestPrSnapshot, fetchRows: fetchHeadCheckRows, restGhApi };
53338
53414
  const dispatchGh = (spec, label) => (async () => {
@@ -53385,7 +53461,28 @@ function registerAppReadBrokerCommands(program3, resolveRepo2, overrides) {
53385
53461
  }
53386
53462
  await dispatchGh(spec, "read run watch");
53387
53463
  });
53388
- const pr = read.command("pr").description("pull-request reads \u2014 view rides gh; checks is REST-backed (deterministic closed-custody adapter; native was EMPTY only on the historical #3035 fixture)");
53464
+ const pr = read.command("pr").description("pull-request reads \u2014 view/list/diff ride gh; queue uses fixed GraphQL; checks is REST-backed (deterministic closed-custody adapter; native was EMPTY only on the historical #3035 fixture)");
53465
+ pr.command("list").description("list viewer-free PRs (author/viewer filters stay personal)").requiredOption("--repo <owner/repo>", "target repo", repoOpt).option("--json [fields]", "native gh JSON fields", jsonOpt).addOption(new Option("--state <state>", "open|closed|merged|all").choices(["open", "closed", "merged", "all"])).option("--base <branch>", "base branch", branchOpt).option("--head <branch>", "head branch", branchOpt).option("--label <label>", "filter by label", labelOpt).option("--search <query>", "viewer-free search", (v) => parseBrokerPrSearch(v)).option("--assignee <login>", "explicit assignee (viewer refused)", assigneeOpt).option("--limit <n>", "maximum PRs (1-100)", intOpt("--limit", 1, 100)).action(async (o) => {
53466
+ await dispatchGh(buildPrListSpec(o), "read pr list");
53467
+ });
53468
+ pr.command("diff").description("read a bounded PR diff on the App pool").requiredOption("--repo <owner/repo>", "target repo", repoOpt).option("--name-only", "only changed file names").argument("<number>", "PR number", idOpt("PR number")).action(async (number, o) => {
53469
+ await dispatchGh(buildPrDiffSpec(number, o), "read pr diff");
53470
+ });
53471
+ pr.command("queue").description("read one PR mergeQueueEntry (fixed GraphQL query, no permission widening)").requiredOption("--repo <owner/repo>", "target repo", repoOpt).option("--json", "machine-readable mergeQueueEntry (null when not queued)").argument("<number>", "PR number", idOpt("PR number")).action(async (number, o) => {
53472
+ const spec = buildPrQueueSpec(number, o);
53473
+ requireBrokerApp("read pr queue");
53474
+ try {
53475
+ process.exitCode = await runBrokerGh(async (args, opts) => {
53476
+ const result = JSON.parse(await ghRun(args, opts));
53477
+ if (result.errors?.length) throw new Error(JSON.stringify(result.errors));
53478
+ const pr2 = result.data?.repository?.pullRequest;
53479
+ if (!pr2) throw new Error("PR not found or not accessible on the App pool");
53480
+ return JSON.stringify(pr2.mergeQueueEntry) + "\n";
53481
+ }, spec);
53482
+ } catch (e) {
53483
+ return fail(`read pr queue: ${e.message}`);
53484
+ }
53485
+ });
53389
53486
  pr.command("view").description("read a PR as gh JSON (comments/json; --json supports statusCheckRollup selection; formatters refused)").option("--repo <owner/repo>", "target repo (defaults to the current repo)", repoOpt).option("--json [fields]", "machine-readable output (comma-separated gh fields)", jsonOpt).option("--comments", "include PR comments").argument("<number>", "PR number", idOpt("PR number")).action(async (number, o) => {
53390
53487
  let spec;
53391
53488
  try {
@@ -53456,14 +53553,14 @@ var RUNS_QUERY_VALUE = {
53456
53553
  created: /^[0-9:TZ.<>=-]+$/,
53457
53554
  actor: /^[A-Za-z0-9_.\[\]-]+$/
53458
53555
  };
53459
- function validRunsQuery(query) {
53556
+ function validRunsQuery(query, allowed = RUNS_QUERY_VALUE) {
53460
53557
  const seen = /* @__PURE__ */ new Set();
53461
53558
  for (const pair of query.split("&")) {
53462
53559
  const eq = pair.indexOf("=");
53463
53560
  if (eq < 1) return false;
53464
53561
  const key = pair.slice(0, eq);
53465
53562
  const value = pair.slice(eq + 1);
53466
- const re = Object.prototype.hasOwnProperty.call(RUNS_QUERY_VALUE, key) ? RUNS_QUERY_VALUE[key] : void 0;
53563
+ const re = Object.prototype.hasOwnProperty.call(allowed, key) ? allowed[key] : void 0;
53467
53564
  if (!re || seen.has(key) || !re.test(value)) return false;
53468
53565
  seen.add(key);
53469
53566
  }
@@ -53475,10 +53572,12 @@ var ACTIONS_JOBS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+(?:/at
53475
53572
  var ACTIONS_ARTIFACTS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/runs/\\d+/artifacts$`);
53476
53573
  var ACTIONS_ARTIFACT_ZIP_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/artifacts/\\d+/zip$`);
53477
53574
  var ACTIONS_JOB_LOGS_RE = new RegExp(`^repos/${NAME}/${NAME}/actions/jobs/\\d+/logs$`);
53575
+ var RELEASE_LIST_RE = new RegExp(`^repos/${NAME}/${NAME}/releases$`);
53576
+ var RELEASE_LIST_QUERY_VALUE = { per_page: RUNS_QUERY_VALUE.per_page, page: RUNS_QUERY_VALUE.page };
53478
53577
  var RELEASE_LATEST_RE = new RegExp(`^repos/${NAME}/${NAME}/releases/latest$`);
53479
53578
  var RELEASE_TAG_RE = new RegExp(`^repos/${NAME}/${NAME}/releases/tags/(${NAME})$`);
53480
53579
  var RELEASE_ASSET_RE = new RegExp(`^repos/${NAME}/${NAME}/releases/assets/\\d+$`);
53481
- var API_GET_ALLOWED_SHAPES = "repos/{owner}/{repo}/pulls/{n}/files, repos/{owner}/{repo}/compare/{a}...{b}, repos/{owner}/{repo}/contents/{path}[?ref=<branch>], repos/{owner}/{repo}/actions/runs[?per_page=1-100&page=<n>&status=&branch=&event=&head_sha=<40-hex>&created=<date-range>&actor=, each key at most once], repos/{owner}/{repo}/actions/runs/{id}, repos/{owner}/{repo}/actions/runs/{id}/jobs, repos/{owner}/{repo}/actions/runs/{id}/attempts/{n}/jobs, repos/{owner}/{repo}/actions/runs/{id}/artifacts, repos/{owner}/{repo}/actions/artifacts/{id}/zip (needs --out <file>), repos/{owner}/{repo}/actions/jobs/{id}/logs (needs --out <file>), repos/{owner}/{repo}/releases/latest, repos/{owner}/{repo}/releases/tags/{tag}, repos/{owner}/{repo}/releases/assets/{id} (needs --out <file>)";
53580
+ var API_GET_ALLOWED_SHAPES = "repos/{owner}/{repo}/pulls/{n}/files, repos/{owner}/{repo}/compare/{a}...{b}, repos/{owner}/{repo}/contents/{path}[?ref=<branch>], repos/{owner}/{repo}/actions/runs[?per_page=1-100&page=<n>&status=&branch=&event=&head_sha=<40-hex>&created=<date-range>&actor=, each key at most once], repos/{owner}/{repo}/actions/runs/{id}, repos/{owner}/{repo}/actions/runs/{id}/jobs, repos/{owner}/{repo}/actions/runs/{id}/attempts/{n}/jobs, repos/{owner}/{repo}/actions/runs/{id}/artifacts, repos/{owner}/{repo}/actions/artifacts/{id}/zip (needs --out <file>), repos/{owner}/{repo}/actions/jobs/{id}/logs (needs --out <file>), repos/{owner}/{repo}/releases[?per_page=1-100&page=<n>, each key at most once], repos/{owner}/{repo}/releases/latest, repos/{owner}/{repo}/releases/tags/{tag}, repos/{owner}/{repo}/releases/assets/{id} (needs --out <file>)";
53482
53581
  function parseApiGetPath(rawPath) {
53483
53582
  const path2 = rawPath.trim();
53484
53583
  const refuse = () => new Error(`api get: refusing '${rawPath}' \u2014 only these GET reads are allowed (#7219): ${API_GET_ALLOWED_SHAPES}`);
@@ -53494,6 +53593,7 @@ function parseApiGetPath(rawPath) {
53494
53593
  if (ACTIONS_ARTIFACTS_RE.test(path2)) return { kind: "actions-artifacts", path: path2, paginate: true };
53495
53594
  if (ACTIONS_ARTIFACT_ZIP_RE.test(path2)) return { kind: "actions-artifact-zip", path: path2, paginate: false };
53496
53595
  if (ACTIONS_JOB_LOGS_RE.test(path2)) return { kind: "actions-job-logs", path: path2, paginate: false };
53596
+ if (RELEASE_LIST_RE.test(base) && (q === -1 || validRunsQuery(query, RELEASE_LIST_QUERY_VALUE))) return { kind: "release-list", path: path2, paginate: false };
53497
53597
  if (RELEASE_LATEST_RE.test(path2)) return { kind: "release-latest", path: path2, paginate: false };
53498
53598
  const tag = RELEASE_TAG_RE.exec(path2)?.[1];
53499
53599
  if (tag && !tag.includes("..")) return { kind: "release-tag", path: path2, paginate: false };
@@ -739,6 +739,33 @@ function defaultTrackedFirstSegments(root, firstSegments, exec2 = import_node_ch
739
739
  throw error;
740
740
  }
741
741
  }
742
+ function mergeGroupRunbookMessages(root, deps, readFile2, warnings) {
743
+ const env = deps.env ?? process.env;
744
+ if (env.GITHUB_EVENT_NAME !== "merge_group") return "";
745
+ let source = "merge_group event payload";
746
+ try {
747
+ const event = JSON.parse(readFile2(env.GITHUB_EVENT_PATH ?? "") ?? "");
748
+ const match = /^refs\/heads\/gh-readonly-queue\/.+\/pr-([1-9]\d*)-[a-f0-9]+$/.exec(event.merge_group?.head_ref ?? "");
749
+ const repo = env.GITHUB_REPOSITORY;
750
+ if (!match || !repo || !/^[\w.-]+\/[\w.-]+$/.test(repo)) throw new Error("invalid queue source");
751
+ source = `repos/${repo}/pulls/${match[1]}/commits`;
752
+ const gh = deps.gh ?? ((args) => (0, import_node_child_process.execFileSync)("gh", args, {
753
+ cwd: root,
754
+ encoding: "utf8",
755
+ windowsHide: true,
756
+ timeout: 3e4,
757
+ maxBuffer: CHECK_IGNORE_MAX_BUFFER,
758
+ env: { ...env, GH_TOKEN: env.GH_TOKEN || env.GITHUB_TOKEN },
759
+ stdio: ["ignore", "pipe", "pipe"]
760
+ }));
761
+ const pages = JSON.parse(gh(["api", source, "--paginate", "--slurp"]));
762
+ if (!Array.isArray(pages) || !pages.every((page) => Array.isArray(page) && page.every((commit) => typeof commit?.commit?.message === "string"))) throw new Error("invalid commit response");
763
+ return pages.flat().map((commit) => commit.commit.message).join("\n");
764
+ } catch {
765
+ warnings.push({ kind: "runbook-source-unverified", doc: source, line: 0, detail: `failed to read ${source}; using git-log Runbook-Unaffected declarations only` });
766
+ return "";
767
+ }
768
+ }
742
769
  function runDocRefs(root, deps = {}) {
743
770
  const readFile2 = deps.readFile ?? readFileOrNull;
744
771
  const exists = deps.exists ?? import_node_fs.existsSync;
@@ -775,7 +802,10 @@ function runDocRefs(root, deps = {}) {
775
802
  if (deps.base) {
776
803
  const git = deps.git ?? ((args) => (0, import_node_child_process.execFileSync)("git", args, { cwd: root, encoding: "utf8", maxBuffer: CHECK_IGNORE_MAX_BUFFER, windowsHide: true }));
777
804
  const stale = checkRunbookCoverage(runbooks, deps.base, git);
778
- const override = /^Runbook-Unaffected:[ \t]*\S.*$/m.test(git(["log", "--format=%B", `${deps.base}..HEAD`]));
805
+ const messages = git(["log", "--format=%B", `${deps.base}..HEAD`]);
806
+ const sourceMessages = stale.length ? mergeGroupRunbookMessages(root, deps, readFile2, warnings) : "";
807
+ const override = /^Runbook-Unaffected:[ \t]*\S.*$/m.test(`${messages}
808
+ ${sourceMessages}`);
779
809
  (override ? warnings : findings).push(...stale);
780
810
  }
781
811
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.152",
3
+ "version": "4.5.153",
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",