@mutmutco/cli 4.5.27 → 4.5.29

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.
Files changed (2) hide show
  1. package/dist/main.cjs +121 -32
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -5491,7 +5491,8 @@ async function fetchHubBoardSnapshot(request, deps) {
5491
5491
  ...request.statusFieldId ? { statusFieldId: request.statusFieldId } : {},
5492
5492
  activeOnly: request.activeOnly !== false,
5493
5493
  allowPartial: request.allowPartial === true,
5494
- includePullRequests: request.includePullRequests !== false
5494
+ includePullRequests: request.includePullRequests !== false,
5495
+ ...request.minCursor !== void 0 ? { minCursor: request.minCursor } : {}
5495
5496
  })
5496
5497
  },
5497
5498
  { attempts: 3, timeoutMs: deps.timeoutMs ?? BOARD_SNAPSHOT_TIMEOUT_MS, sleep: deps.retrySleep }
@@ -12472,7 +12473,8 @@ async function collectBoardPreferringSnapshot(cfg, options, deps) {
12472
12473
  number: cfg.projectNumber,
12473
12474
  statusFieldId: cfg.statusFieldId,
12474
12475
  activeOnly: true,
12475
- allowPartial: options.allowPartial === true
12476
+ allowPartial: options.allowPartial === true,
12477
+ ...options.minCursor !== void 0 ? { minCursor: options.minCursor } : {}
12476
12478
  },
12477
12479
  deps.snapshot
12478
12480
  ) : void 0;
@@ -16816,10 +16818,10 @@ var rollout_plan_default = {
16816
16818
  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)."
16817
16819
  },
16818
16820
  baseline: {
16819
- version: "4.5.27",
16820
- tag: "v4.5.27",
16821
- commit: "30f02884a0f7",
16822
- npm: "@mutmutco/cli@4.5.27"
16821
+ version: "4.5.29",
16822
+ tag: "v4.5.29",
16823
+ commit: "0d0f26e607d4",
16824
+ npm: "@mutmutco/cli@4.5.29"
16823
16825
  },
16824
16826
  exitCriterion: "fleet-n-of-n",
16825
16827
  hubOnlyShortcut: "forbidden",
@@ -16836,14 +16838,14 @@ var rollout_plan_default = {
16836
16838
  repo: "mutmutco/mmi-hub",
16837
16839
  role: "canary",
16838
16840
  schedule: "train",
16839
- v3Target: "v4.5.27"
16841
+ v3Target: "v4.5.29"
16840
16842
  }
16841
16843
  ],
16842
16844
  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.",
16843
16845
  rollback: {
16844
16846
  independent: true,
16845
- mechanism: "npm dist-tag latest -> 4.5.27 and redeploy the Hub Lambda from tag v4.5.27 (30f02884a0f7); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
16846
- v3Target: "v4.5.27 (@mutmutco/cli@4.5.27, tag commit 30f02884a0f7 \u2014 last known-good release carrying the repo-index v4-only contract)"
16847
+ mechanism: "npm dist-tag latest -> 4.5.29 and redeploy the Hub Lambda from tag v4.5.29 (0d0f26e607d4); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
16848
+ v3Target: "v4.5.29 (@mutmutco/cli@4.5.29, tag commit 0d0f26e607d4 \u2014 last known-good release carrying the repo-index v4-only contract)"
16847
16849
  }
16848
16850
  },
16849
16851
  {
@@ -19156,7 +19158,7 @@ async function correlateRun(deps, args) {
19156
19158
  });
19157
19159
  const tokens2 = args.mode === "dispatch" ? args.titleIncludes : void 0;
19158
19160
  const titleMatch = tokens2 && tokens2.length ? candidates.find((c) => tokens2.every((t) => (c.row.displayTitle ?? "").includes(t))) : void 0;
19159
- const match = titleMatch ?? (args.mode === "workflow" || windowProvenWhole ? candidates[0] : void 0);
19161
+ const match = titleMatch ?? (!("requireTitleMatch" in args && args.requireTitleMatch) && (args.mode === "workflow" || windowProvenWhole) ? candidates[0] : void 0);
19160
19162
  if (match) return { runId: match.row.databaseId, runUrl: match.row.url, read: "found" };
19161
19163
  if (!windowProvenWhole) truncatedWindow = true;
19162
19164
  }
@@ -19177,8 +19179,8 @@ async function correlateRun(deps, args) {
19177
19179
  function correlateTenantRun(deps, since, titleIncludes) {
19178
19180
  return correlateRun(deps, { workflow: "tenant-deploy.yml", since, mode: "dispatch", titleIncludes });
19179
19181
  }
19180
- function correlateGetPublishRun(deps, since, product) {
19181
- return correlateRun(deps, { workflow: "get-publish.yml", since, mode: "dispatch", titleIncludes: [product] });
19182
+ function correlateGetPublishRun(deps, since, product, mode) {
19183
+ return correlateRun(deps, { workflow: "get-publish.yml", since, mode: "dispatch", titleIncludes: [product, ...mode ? [mode] : []], ...mode ? { requireTitleMatch: true } : {} });
19182
19184
  }
19183
19185
  function correlateControlRun(deps, since, titleIncludes) {
19184
19186
  return correlateRun(deps, { workflow: "tenant-control.yml", since, mode: "dispatch", titleIncludes });
@@ -20061,10 +20063,50 @@ async function appendMmiGetRedeploy(deps, input, dispatch) {
20061
20063
  workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "success" }]
20062
20064
  };
20063
20065
  }
20064
- async function appendServedChannelPublish(deps, input, dispatch) {
20066
+ async function appendServedChannelStage(deps, input, dispatch) {
20067
+ if (!isHubControlRepo(input.repo)) return dispatch;
20068
+ const remedy = `${getPublishDispatchCommand(input.repo)} -f mode=stage`;
20069
+ const prior = await findPriorGreenDispatch(deps, input.repo, "get-publish.yml", input.releaseSha, [HUB_SERVED_PRODUCT, "stage"]);
20070
+ let row;
20071
+ if (prior) {
20072
+ row = { workflow: "get-publish.yml", runId: prior.runId, ...prior.runUrl ? { runUrl: prior.runUrl } : {}, conclusion: "success" };
20073
+ } else {
20074
+ const since = (deps.now ?? Date.now)();
20075
+ try {
20076
+ await deps.run("gh", ["workflow", "run", "get-publish.yml", "--repo", input.repo, "--ref", "main", "-f", `product=${HUB_SERVED_PRODUCT}`, "-f", "mode=stage"]);
20077
+ } catch (e) {
20078
+ const why = e instanceof Error ? e.message : String(e);
20079
+ return {
20080
+ ...dispatch,
20081
+ note: `${dispatch.note}; get-publish stage dispatch FAILED: ${why} \u2014 recover with \`${remedy}\``,
20082
+ deployStatus: "failure",
20083
+ workflowRuns: [...dispatch.workflowRuns ?? [], planeFailureRow("get-publish.yml", `stage dispatch refused: ${why}`)]
20084
+ };
20085
+ }
20086
+ const correlated = await correlateGetPublishRun(deps, since, HUB_SERVED_PRODUCT, "stage");
20087
+ if (correlated.read !== "found") {
20088
+ return {
20089
+ ...dispatch,
20090
+ note: `${dispatch.note}; get-publish stage dispatched but its run could not be READ \u2014 check Actions; recover with \`${remedy}\``,
20091
+ deployStatus: "failure",
20092
+ workflowRuns: [...dispatch.workflowRuns ?? [], planeFailureRow("get-publish.yml", "stage dispatched, but its run could not be read")]
20093
+ };
20094
+ }
20095
+ row = { workflow: "get-publish.yml", runId: correlated.runId, ...correlated.runUrl ? { runUrl: correlated.runUrl } : {}, conclusion: "pending" };
20096
+ if (input.watch) row.conclusion = await watchTenantRun(deps, correlated.runId, input.repo);
20097
+ }
20098
+ return {
20099
+ ...dispatch,
20100
+ note: `${dispatch.note}; get-publish stage ${row.conclusion}${row.conclusion === "failure" ? ` \u2014 recover with \`${remedy}\`` : ""}`,
20101
+ workflowRuns: [...dispatch.workflowRuns ?? [], row],
20102
+ ...row.conclusion === "failure" ? { deployStatus: "failure" } : {}
20103
+ };
20104
+ }
20105
+ async function appendServedChannelPublish(deps, input, dispatch, redeployed) {
20065
20106
  if (!isHubControlRepo(input.repo)) return dispatch;
20066
20107
  const channelUrl = input.channelUrl ?? readServedChannelUrl();
20067
20108
  const remedy = getPublishDispatchCommand(input.repo);
20109
+ const pointerRemedy = input.tag ? `${remedy} -f mode=pointer -f version=${input.tag.replace(/^v/, "")}` : remedy;
20068
20110
  const withNote = (note, deployStatus, row) => ({
20069
20111
  ...dispatch,
20070
20112
  note: `${dispatch.note}; ${note}`,
@@ -20074,23 +20116,25 @@ async function appendServedChannelPublish(deps, input, dispatch) {
20074
20116
  if (input.publishStatus !== "success") {
20075
20117
  return withNote(`served channel NOT moved (publish did not succeed) \u2014 after the publish is green, run \`${remedy}\``);
20076
20118
  }
20077
- const prior = input.releaseSha ? await findPriorGreenDispatch(deps, input.repo, "get-publish.yml", input.releaseSha, [HUB_SERVED_PRODUCT]) : void 0;
20119
+ const prior = input.releaseSha ? await findPriorGreenDispatch(deps, input.repo, "get-publish.yml", input.releaseSha, [HUB_SERVED_PRODUCT, "pointer"]) : void 0;
20078
20120
  let runRow;
20079
20121
  let runStatus;
20080
20122
  if (prior) {
20081
20123
  runRow = { workflow: "get-publish.yml", runId: prior.runId, ...prior.runUrl ? { runUrl: prior.runUrl } : {} };
20082
20124
  runStatus = "success";
20083
20125
  } else {
20126
+ const version = input.tag?.replace(/^v/, "") ?? (deps.readLauncherVersion ?? readLocalLauncherVersion)();
20127
+ if (!version) return withNote("the local launcher version could not be read \u2014 nothing was compared, so the move is unverified");
20084
20128
  const since = (deps.now ?? Date.now)();
20085
20129
  try {
20086
- await deps.run("gh", ["workflow", "run", "get-publish.yml", "--repo", input.repo, "--ref", "main", "-f", `product=${HUB_SERVED_PRODUCT}`]);
20130
+ await deps.run("gh", ["workflow", "run", "get-publish.yml", "--repo", input.repo, "--ref", "main", "-f", `product=${HUB_SERVED_PRODUCT}`, "-f", "mode=pointer", "-f", `version=${version}`]);
20087
20131
  } catch (e) {
20088
20132
  const msg = e instanceof Error ? e.message : String(e);
20089
- return withNote(`get-publish dispatch FAILED: ${msg}. The release itself landed, but the SERVED CHANNEL IS UNCHANGED \u2014 recover with \`${remedy}\``, "failure", planeFailureRow("get-publish.yml", `dispatch refused: ${msg}`));
20133
+ return withNote(`get-publish dispatch FAILED: ${msg}. The release itself landed, but the SERVED CHANNEL IS UNCHANGED \u2014 recover with \`${pointerRemedy}\``, "failure", planeFailureRow("get-publish.yml", `dispatch refused: ${msg}`));
20090
20134
  }
20091
- const correlated = await correlateGetPublishRun(deps, since, HUB_SERVED_PRODUCT);
20092
- if (correlated.read === "failed") {
20093
- return withNote(`get-publish dispatched but its run could not be READ: ${correlated.error}. Check the Actions tab; if it never ran, recover with \`${remedy}\``, "failure", planeFailureRow("get-publish.yml", `dispatched, but its run could not be read`));
20135
+ const correlated = await correlateGetPublishRun(deps, since, HUB_SERVED_PRODUCT, "pointer");
20136
+ if (correlated.read !== "found") {
20137
+ return withNote(`get-publish dispatched but its run could not be READ: ${correlated.error ?? "no matching run appeared"}. Check the Actions tab; if it never ran, recover with \`${pointerRemedy}\``, "failure", planeFailureRow("get-publish.yml", `dispatched, but its run could not be read`));
20094
20138
  }
20095
20139
  const { runId, runUrl } = correlated;
20096
20140
  runRow = { workflow: "get-publish.yml", ...runId ? { runId } : {}, ...runUrl ? { runUrl } : {} };
@@ -20106,12 +20150,12 @@ async function appendServedChannelPublish(deps, input, dispatch) {
20106
20150
  if (runStatus !== "success") {
20107
20151
  return {
20108
20152
  ...dispatch,
20109
- note: `${dispatch.note}; get-publish.yml ${runStatus} \u2014 the SERVED CHANNEL IS UNCHANGED; recover with \`${remedy}\``,
20153
+ note: `${dispatch.note}; get-publish.yml ${runStatus} \u2014 the SERVED CHANNEL IS UNCHANGED; recover with \`${pointerRemedy}\``,
20110
20154
  workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: runStatus }],
20111
20155
  deployStatus: "failure"
20112
20156
  };
20113
20157
  }
20114
- const expected = (deps.readLauncherVersion ?? readLocalLauncherVersion)();
20158
+ const expected = input.tag ? input.tag.replace(/^v/, "") : (deps.readLauncherVersion ?? readLocalLauncherVersion)();
20115
20159
  const runs = [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "success" }];
20116
20160
  if (!channelUrl) {
20117
20161
  return {
@@ -20120,6 +20164,7 @@ async function appendServedChannelPublish(deps, input, dispatch) {
20120
20164
  workflowRuns: runs
20121
20165
  };
20122
20166
  }
20167
+ if (redeployed) await redeployed;
20123
20168
  const probe = await (deps.readServedChannelVersion ?? fetchServedChannelVersion)(channelUrl);
20124
20169
  const evidence = (conclusion, text) => [...runs, servedChannelRow(HUB_SERVED_PRODUCT, conclusion, text)];
20125
20170
  if (!probe.ok && staleServedProcess(probe)) {
@@ -20142,7 +20187,7 @@ async function appendServedChannelPublish(deps, input, dispatch) {
20142
20187
  if (expected && probe.version !== expected) {
20143
20188
  return {
20144
20189
  ...dispatch,
20145
- note: `${dispatch.note}; get-publish.yml succeeded but the served channel still reports ${probe.version} (expected launcher ${expected}) \u2014 THE CHANNEL DID NOT MOVE; recover with \`${remedy}\``,
20190
+ note: `${dispatch.note}; get-publish.yml succeeded but the served channel still reports ${probe.version} (expected launcher ${expected}) \u2014 THE CHANNEL DID NOT MOVE; recover with \`${pointerRemedy}\``,
20146
20191
  workflowRuns: evidence("failure", `${channelUrl} reports ${probe.version}, expected ${expected}`),
20147
20192
  deployStatus: "failure"
20148
20193
  };
@@ -20271,12 +20316,50 @@ async function appendInstallHomePublish(deps, input, dispatch) {
20271
20316
  workflowRuns: [...dispatch.workflowRuns ?? [], { ...row, conclusion: "success" }]
20272
20317
  };
20273
20318
  }
20319
+ function mergeServedLegs(base, first, second) {
20320
+ if (first === base) return second;
20321
+ if (second === base) return first;
20322
+ const priorRows = base.workflowRuns?.length ?? 0;
20323
+ const rows = [...(first.workflowRuns ?? []).slice(priorRows), ...(second.workflowRuns ?? []).slice(priorRows)];
20324
+ return {
20325
+ ...base,
20326
+ note: base.note + first.note.slice(base.note.length) + second.note.slice(base.note.length),
20327
+ ...rows.length ? { workflowRuns: [...base.workflowRuns ?? [], ...rows] } : {},
20328
+ ...first.deployStatus === "failure" || second.deployStatus === "failure" ? { deployStatus: "failure" } : {}
20329
+ };
20330
+ }
20331
+ function prepareServedChannel(deps, input) {
20332
+ const base = { note: "", deployStatus: "success", workflowRuns: [] };
20333
+ const prepared = Promise.all([
20334
+ appendMmiGetRedeploy(deps, { ...input, publishStatus: "success" }, base),
20335
+ appendServedChannelStage(deps, input, base)
20336
+ ]).then(([box, stage]) => mergeServedLegs(base, box, stage));
20337
+ prepared.catch(() => void 0);
20338
+ return prepared;
20339
+ }
20274
20340
  async function appendServedChannelLegs(deps, input, dispatch) {
20275
20341
  const publishStatus = input.publish?.state === "complete" ? "success" : "failure";
20276
- let out = await appendMmiGetRedeploy(deps, { repo: input.repo, publishStatus, watch: input.watch, releaseSha: input.releaseSha }, dispatch);
20277
- out = await appendServedChannelPublish(deps, { repo: input.repo, publishStatus, watch: input.watch, releaseSha: input.releaseSha }, out);
20278
- out = await appendInstallHomePublish(deps, { repo: input.repo, installer: input.installer, publishStatus, watch: input.watch }, out);
20279
- return appendServedChannelProof(deps, { repo: input.repo, tag: input.tag, shipped: shipLegsGreen(input.deploy, input.publish), installer: input.installer }, out);
20342
+ const prepared = await (input.prepared ?? prepareServedChannel(deps, input));
20343
+ if (!isHubControlRepo(input.repo)) {
20344
+ const [home2, proof2] = await Promise.all([
20345
+ appendInstallHomePublish(deps, { repo: input.repo, installer: input.installer, publishStatus, watch: input.watch }, dispatch),
20346
+ appendServedChannelProof(deps, { repo: input.repo, tag: input.tag, shipped: shipLegsGreen(input.deploy, input.publish), installer: input.installer }, dispatch)
20347
+ ]);
20348
+ return mergeServedLegs(dispatch, home2, proof2);
20349
+ }
20350
+ const stageGreen = (prepared.workflowRuns ?? []).filter((r) => r.workflow === "get-publish.yml").every((r) => r.conclusion === "success");
20351
+ const channel = stageGreen || !isHubControlRepo(input.repo) || publishStatus !== "success" ? await appendServedChannelPublish(deps, { repo: input.repo, publishStatus, watch: input.watch, releaseSha: input.releaseSha, tag: input.tag }, dispatch, Promise.resolve(prepared)) : { ...dispatch, note: `${dispatch.note}; served channel NOT moved (stage not green) \u2014 recover with \`${getPublishDispatchCommand(input.repo)} -f mode=stage\`, then \`${getPublishDispatchCommand(input.repo)} -f mode=pointer -f version=${input.tag.replace(/^v/, "")}\`` };
20352
+ const out = mergeServedLegs(dispatch, {
20353
+ ...dispatch,
20354
+ note: dispatch.note + prepared.note,
20355
+ workflowRuns: [...dispatch.workflowRuns ?? [], ...prepared.workflowRuns ?? []],
20356
+ ...prepared.deployStatus === "failure" ? { deployStatus: "failure" } : {}
20357
+ }, channel);
20358
+ const [home, proof] = await Promise.all([
20359
+ appendInstallHomePublish(deps, { repo: input.repo, installer: input.installer, publishStatus, watch: input.watch }, out),
20360
+ appendServedChannelProof(deps, { repo: input.repo, tag: input.tag, shipped: shipLegsGreen(input.deploy, input.publish), installer: input.installer }, out)
20361
+ ]);
20362
+ return mergeServedLegs(out, home, proof);
20280
20363
  }
20281
20364
  function servedChannelRowsAfter(before, after) {
20282
20365
  return (after.workflowRuns ?? []).slice((before.workflowRuns ?? []).length);
@@ -25295,6 +25378,7 @@ ${recovery.note}`), recoveryInput);
25295
25378
  await verifyPublishedRelease(deps, ctx.repo, tag, "main", releaseSha);
25296
25379
  await recordPhase(ledger, deps, ledgerAnchors, "githubRelease", phaseEntry({ state: "complete", sha: releaseSha, runUrl: releaseUrl, note: `verified GitHub Release ${tag} against ${releaseSha.slice(0, 12)}` }), { landed: "the immutable tag, the green required-check wall, and the origin/main fast-forward" });
25297
25380
  let alignment = alignEarly ? await alignEarly() : void 0;
25381
+ const prepared = prepareServedChannel(deps, { repo: ctx.repo, releaseSha, watch });
25298
25382
  const [deployDispatch0, publishDispatch0] = await joinDeployAndPublish(
25299
25383
  dispatchDeploy(deps, ctx, "main", "main", deployModel, watch, autoRunSince, releaseSha, "report", meta.publishDir),
25300
25384
  observePublishIfRequired(deps, ctx, meta, deployModel, "main", releaseSha, watch)
@@ -25345,7 +25429,7 @@ ${recovery.note}`), recoveryInput);
25345
25429
  const aligning = watch && alignment ? awaitAlignmentsLanded(deps, ctx, alignment) : Promise.resolve(alignment);
25346
25430
  const dispatch = await appendServedChannelLegs(
25347
25431
  deps,
25348
- { repo: ctx.repo, tag, releaseSha, watch, deploy: deployLeg, publish: publishLeg, installer: meta.installer },
25432
+ { repo: ctx.repo, tag, releaseSha, watch, deploy: deployLeg, publish: publishLeg, installer: meta.installer, prepared },
25349
25433
  appendPublishDispatch(deployDispatch, publishDispatch)
25350
25434
  );
25351
25435
  alignment = await aligning;
@@ -25837,6 +25921,7 @@ ${recovery.note}`), recoveryInput);
25837
25921
  await recordPhase(ledger, deps, anchors, "githubRelease", phaseEntry({ state: "complete", sha: tagSha, runUrl: releaseUrl, note: "verified the Release published against the tagged commit" }), { strict: ledgerMode === "strict", landed: "the immutable tag, the re-proven wall, and the origin/main push" });
25838
25922
  let devRollForward = await rollDevelopmentForward(deps, ctx, tag);
25839
25923
  let rcAlignment = !directTrack && branchHints.hasRcBranch ? await alignRcForward(deps, ctx, tag) : void 0;
25924
+ const channelPreparation = prepareServedChannel(deps, { repo: ctx.repo, releaseSha: tagSha, watch });
25840
25925
  const [deployDispatch0, publishDispatch0] = await joinDeployAndPublish(
25841
25926
  dispatchDeploy(deps, ctx, "main", "main", deployModel, watch, autoRunSince, tagSha, "report", meta.publishDir),
25842
25927
  observePublishIfRequired(deps, ctx, meta, deployModel, "main", tagSha, watch)
@@ -25880,7 +25965,7 @@ ${recovery.note}`), recoveryInput);
25880
25965
  }
25881
25966
  const dispatch = await appendServedChannelLegs(
25882
25967
  deps,
25883
- { repo: ctx.repo, tag, releaseSha: tagSha, watch, deploy: deployLeg, publish: publishLeg, installer: meta.installer },
25968
+ { repo: ctx.repo, tag, releaseSha: tagSha, watch, deploy: deployLeg, publish: publishLeg, installer: meta.installer, prepared: channelPreparation },
25884
25969
  appendPublishDispatch(deployDispatch, publishDispatch)
25885
25970
  );
25886
25971
  const announcing = announceShippedRelease(
@@ -28845,6 +28930,8 @@ function registerBoardCommands(program3) {
28845
28930
  }
28846
28931
  async function runBoardRead(o) {
28847
28932
  try {
28933
+ if (o.minCursor !== void 0 && !/^\d{1,15}$/.test(o.minCursor)) throw new Error("--min-cursor must be a non-negative integer board-event cursor");
28934
+ if (o.minCursor !== void 0 && o.direct) throw new Error("--min-cursor applies to the Hub snapshot and cannot be combined with --direct");
28848
28935
  const config = await loadConfigForRepo(o.repo);
28849
28936
  const report = await readBoard({
28850
28937
  config,
@@ -28852,7 +28939,8 @@ function registerBoardCommands(program3) {
28852
28939
  includeBundleDetails: o.bundleDetails,
28853
28940
  includeAllBodies: o.bodies,
28854
28941
  allowPartial: o.allowPartial,
28855
- snapshotOnly: o.snapshotOnly
28942
+ snapshotOnly: o.snapshotOnly,
28943
+ ...o.minCursor !== void 0 ? { minCursor: Number(o.minCursor) } : {}
28856
28944
  }, o.direct ? {} : { snapshot: registryClientDeps(config) });
28857
28945
  const output = o.json ? JSON.stringify(report) : renderBoardReport(report);
28858
28946
  if (!o.out) console.log(output);
@@ -28895,7 +28983,7 @@ function registerBoardCommands(program3) {
28895
28983
  return `Claimed ${ref} for ${holder} - In Progress${reclaimed}`;
28896
28984
  }
28897
28985
  const board = program3.command("board").description("read, claim, show, and move Project v2 work items for the current repo");
28898
- board.command("read", { isDefault: true }).alias("list").description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--direct", "bypass the Hub snapshot and read the live board through direct GitHub GraphQL").option("--snapshot-only", "fail instead of falling back to your personal GraphQL pool when the Hub snapshot is unavailable \u2014 for ambient readers such as sidebars (#7203)").option("--bundle-details", "fetch body/comments only for user-owned and claimable issues").option("--bodies", "fetch body/comments for EVERY scoped row, including taken and unowned in-flight ones \u2014 for consumers that scope by Status rather than ownership (#4861); implies --bundle-details and costs one extra read per row").option("--allow-partial", "return partial board results when later page/detail reads fail").option("--out <path>", "write the output to this file as UTF-8 (no BOM) instead of stdout \u2014 the shell-free receipt path (#5802)").addHelpText("after", "\nread is always the authoritative live GitHub Project v2 board (#4926).\n--direct skips the Hub snapshot and uses the existing direct GitHub GraphQL read immediately.\n--allow-partial applies to the paginated path and detail reads.\n\nWhen using Windows PowerShell 5.1, avoid shell redirects: PowerShell 5.1's `> file.json` is Out-File,\nwhich writes UTF-16LE with a BOM, and Node reading it as 'utf8' then fails JSON.parse at position 1\n(#5802). Use --out instead \u2014 the CLI writes the file itself as UTF-8:\n mmi-cli oracle board read --json --out .jerv/tmp/board.json\n").action((o) => runBoardRead(o));
28986
+ board.command("read", { isDefault: true }).alias("list").description("read the board and print user-owned, claimable, and taken items").option("--json", "machine-readable output").option("--repo <owner/repo>", "current repo (defaults to git origin)").option("--direct", "bypass the Hub snapshot and read the live board through direct GitHub GraphQL").option("--snapshot-only", "fail instead of falling back to your personal GraphQL pool when the Hub snapshot is unavailable \u2014 for ambient readers such as sidebars (#7203)").option("--min-cursor <n>", "board-event cursor (from `oracle board events`) the Hub snapshot must postdate; a cached snapshot older than that event is rebuilt (#7240)").option("--bundle-details", "fetch body/comments only for user-owned and claimable issues").option("--bodies", "fetch body/comments for EVERY scoped row, including taken and unowned in-flight ones \u2014 for consumers that scope by Status rather than ownership (#4861); implies --bundle-details and costs one extra read per row").option("--allow-partial", "return partial board results when later page/detail reads fail").option("--out <path>", "write the output to this file as UTF-8 (no BOM) instead of stdout \u2014 the shell-free receipt path (#5802)").addHelpText("after", "\nread is always the authoritative live GitHub Project v2 board (#4926).\n--direct skips the Hub snapshot and uses the existing direct GitHub GraphQL read immediately.\n--allow-partial applies to the paginated path and detail reads.\n\nWhen using Windows PowerShell 5.1, avoid shell redirects: PowerShell 5.1's `> file.json` is Out-File,\nwhich writes UTF-16LE with a BOM, and Node reading it as 'utf8' then fails JSON.parse at position 1\n(#5802). Use --out instead \u2014 the CLI writes the file itself as UTF-8:\n mmi-cli oracle board read --json --out .jerv/tmp/board.json\n").action((o) => runBoardRead(o));
28899
28987
  board.command("events").description("content-free board/CI change records after a cursor, from the Hub event feed (no GitHub call) \u2014 for real-time sidebars (#7235)").option("--since <cursor>", "cursor from the previous answer; omit on first read (answers the head cursor with resync:true)").option("--wait <seconds>", "hold up to this long (max 120), polling every 2s, and return on the first event or resync", "0").option("--repo <owner/repo>", "repo whose Hub config to use (defaults to git origin)").option("--json", "machine-readable output (already the default)").addHelpText("after", "\nPrints {cursor, events, resync, more[, hidden]}. Pass the returned cursor as the next --since.\nresync:true means records were missed (retention ~1h, or a gap): re-read the board with\n`mmi-cli oracle board read --snapshot-only --json`.\n").action(async (o) => {
28900
28988
  try {
28901
28989
  if (o.since !== void 0 && !/^\d{1,15}$/.test(o.since)) throw new Error("--since must be a non-negative integer cursor");
@@ -46615,7 +46703,7 @@ async function appendHotfixServedChannel(deps, input, runs, note) {
46615
46703
  const before = hotfixDispatchFromRuns(runs, note);
46616
46704
  const after = await appendServedChannelLegs(
46617
46705
  deps,
46618
- { repo: input.repo, tag: input.tag, releaseSha: input.sha, watch: true, deploy: input.deploy, publish: input.publish, installer: input.installer },
46706
+ { repo: input.repo, tag: input.tag, releaseSha: input.sha, watch: true, deploy: input.deploy, publish: input.publish, installer: input.installer, prepared: input.prepared },
46619
46707
  before
46620
46708
  );
46621
46709
  for (const row of servedChannelRowsAfter(before, after)) {
@@ -46848,6 +46936,7 @@ ${decision.note}`);
46848
46936
  releaseNote = `Release ${tag} created (target main)`;
46849
46937
  }
46850
46938
  await recordHotfixPhase(ledger, anchors, "githubRelease", { state: "complete", sha: mergedSha, note: releaseNote }, "the immutable tag, the green wall, and origin/main");
46939
+ const prepared = prepareServedChannel(deps, { repo: ctx.repo, releaseSha: mergedSha, watch: true });
46851
46940
  const runs = [];
46852
46941
  let deployNote;
46853
46942
  let tenantPublishDispatch = null;
@@ -46906,7 +46995,7 @@ ${decision.note}`);
46906
46995
  );
46907
46996
  await recordHotfixPhase(ledger, anchors, "deploy", ledgerInputs.deploy, "the immutable tag, the green wall, origin/main, and the GitHub Release");
46908
46997
  await recordHotfixPhase(ledger, anchors, "publish", ledgerInputs.publish, "the immutable tag, the green wall, origin/main, the GitHub Release, and the deploy path");
46909
- deployNote = await appendHotfixServedChannel(deps, { repo: ctx.repo, tag, sha: mergedSha, deploy: ledgerInputs.deploy, publish: ledgerInputs.publish, installer: meta.installer }, runs, deployNote);
46998
+ deployNote = await appendHotfixServedChannel(deps, { repo: ctx.repo, tag, sha: mergedSha, deploy: ledgerInputs.deploy, publish: ledgerInputs.publish, installer: meta.installer, prepared }, runs, deployNote);
46910
46999
  const announceNote = releaseExists ? void 0 : await announceShippedRelease(
46911
47000
  deps,
46912
47001
  { repo: ctx.repo, tag, summaryFile: options.announceSummaryFile },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.27",
3
+ "version": "4.5.29",
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",