@mutmutco/claude-plugin 4.6.38 → 4.6.39
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
|
@@ -28405,10 +28405,10 @@ var rollout_plan_default = {
|
|
|
28405
28405
|
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)."
|
|
28406
28406
|
},
|
|
28407
28407
|
baseline: {
|
|
28408
|
-
version: "4.6.
|
|
28409
|
-
tag: "v4.6.
|
|
28410
|
-
commit: "
|
|
28411
|
-
npm: "@mutmutco/cli@4.6.
|
|
28408
|
+
version: "4.6.39",
|
|
28409
|
+
tag: "v4.6.39",
|
|
28410
|
+
commit: "2669c496b69e",
|
|
28411
|
+
npm: "@mutmutco/cli@4.6.39"
|
|
28412
28412
|
},
|
|
28413
28413
|
exitCriterion: "fleet-n-of-n",
|
|
28414
28414
|
hubOnlyShortcut: "forbidden",
|
|
@@ -28425,14 +28425,14 @@ var rollout_plan_default = {
|
|
|
28425
28425
|
repo: "mutmutco/mmi-hub",
|
|
28426
28426
|
role: "canary",
|
|
28427
28427
|
schedule: "train",
|
|
28428
|
-
v3Target: "v4.6.
|
|
28428
|
+
v3Target: "v4.6.39"
|
|
28429
28429
|
}
|
|
28430
28430
|
],
|
|
28431
28431
|
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.",
|
|
28432
28432
|
rollback: {
|
|
28433
28433
|
independent: true,
|
|
28434
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
28435
|
-
v3Target: "v4.6.
|
|
28434
|
+
mechanism: "npm dist-tag latest -> 4.6.39 and redeploy the Hub Lambda from tag v4.6.39 (2669c496b69e); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
28435
|
+
v3Target: "v4.6.39 (@mutmutco/cli@4.6.39, tag commit 2669c496b69e \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
28436
28436
|
}
|
|
28437
28437
|
},
|
|
28438
28438
|
{
|
|
@@ -44015,7 +44015,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
|
|
|
44015
44015
|
for (let readAttempt = 0; readAttempt < maxReads; readAttempt++) {
|
|
44016
44016
|
if (readAttempt) await sleep3(readAttempt * 1e3);
|
|
44017
44017
|
try {
|
|
44018
|
-
const observed = await readPrMergeQueue(pr, repo, read);
|
|
44018
|
+
const observed = await readPrMergeQueue(pr, repo, read, options.sleep);
|
|
44019
44019
|
if (observed.state === "MERGED" && observed.headRefOid === head) return markReenqueued({ mergeStatus: "merged" });
|
|
44020
44020
|
if (observed.isInMergeQueue && observed.headRefOid === head) {
|
|
44021
44021
|
const entry = observed.mergeQueueEntry;
|
|
@@ -44057,13 +44057,13 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
|
|
|
44057
44057
|
if (receipt && (receipt.state === "enqueued" || receipt.state === "merged")) {
|
|
44058
44058
|
if (receipt.head.toLowerCase() !== head.toLowerCase()) {
|
|
44059
44059
|
try {
|
|
44060
|
-
const observed = await readPrMergeQueue(pr, repo, read);
|
|
44060
|
+
const observed = await readPrMergeQueue(pr, repo, read, options.sleep);
|
|
44061
44061
|
superseded = observed.state === "OPEN" && !observed.isInMergeQueue;
|
|
44062
44062
|
} catch {
|
|
44063
44063
|
}
|
|
44064
44064
|
} else {
|
|
44065
44065
|
try {
|
|
44066
|
-
const observed = await readPrMergeQueue(pr, repo, read);
|
|
44066
|
+
const observed = await readPrMergeQueue(pr, repo, read, options.sleep);
|
|
44067
44067
|
if (observed.state === "OPEN" && !observed.isInMergeQueue && observed.headRefOid?.toLowerCase() === receipt.head.toLowerCase()) {
|
|
44068
44068
|
const boundMs = receipt.queueEntry ? Date.parse(receipt.queueEntry.enqueuedAt) : receipt.observedAt + UNWITNESSED_EJECTION_GRACE_MS;
|
|
44069
44069
|
const events = await readArrayPages(
|
|
@@ -44266,6 +44266,15 @@ ${list}
|
|
|
44266
44266
|
Co-authored-by: GitHub <noreply@github.com>
|
|
44267
44267
|
`;
|
|
44268
44268
|
}
|
|
44269
|
+
var WAIVER_KEYS = /^(?:Test-Policy-Override|Runbook-Unaffected)\s*:/i;
|
|
44270
|
+
function clipTrailer(trailer) {
|
|
44271
|
+
return trailer.length > 120 ? `${trailer.slice(0, 117)}...` : trailer;
|
|
44272
|
+
}
|
|
44273
|
+
function describeWaiverText(label, message2, cwd) {
|
|
44274
|
+
const block = parseTrailers(message2, cwd).filter((trailer) => WAIVER_KEYS.test(trailer));
|
|
44275
|
+
const found = block.length ? `final trailer block holds ${block.map((trailer) => `\`${clipTrailer(trailer)}\``).join(" and ")}` : "git parses no Test-Policy-Override or Runbook-Unaffected trailer there";
|
|
44276
|
+
return `${label}: ${found}`;
|
|
44277
|
+
}
|
|
44269
44278
|
function checkQueueSquashOverride(title, pr, messages, root) {
|
|
44270
44279
|
if (messages.length <= 1 || !messages.some((message2) => /^\s*Test-Policy-Override\s*:/im.test(`${message2.headline}
|
|
44271
44280
|
${message2.body}`)) || readMessageOverride2(githubQueueSquashMessage(title, pr, messages), root)) return void 0;
|
|
@@ -44399,7 +44408,8 @@ ${pull.body}`;
|
|
|
44399
44408
|
}
|
|
44400
44409
|
const requiredBody = options.bodyText ?? composedBody;
|
|
44401
44410
|
const prBodyPreservesOverrides = requiredBody != null && method === "SQUASH" && policy.body === "PR_BODY" && options.bodyText == null && prBodyPreservesCommitOverrides(messages, headline, pull.body, process.cwd());
|
|
44402
|
-
|
|
44411
|
+
const queueKeepsWaiver = options.bodyText == null && method !== "SQUASH" && Boolean(readMessageOverride2(actualMessage, process.cwd()));
|
|
44412
|
+
if (requiredBody && !prBodyPreservesOverrides && !queueKeepsWaiver && (method !== "SQUASH" || requiredBody.trim() !== body.trim())) {
|
|
44403
44413
|
if (method === "SQUASH" && policy.body === "PR_BODY" && options.bodyText == null) {
|
|
44404
44414
|
return {
|
|
44405
44415
|
kind: "refused",
|
|
@@ -44411,7 +44421,9 @@ ${pull.body}`;
|
|
|
44411
44421
|
issueTargets: [],
|
|
44412
44422
|
nextAction: `PR author: this repository squashes with PR_BODY, so place the required Test-Policy-Override trailer(s) in the PR body final trailer block (e.g. \`mmi-cli devops pr edit ${pr} --repo ${repo} --body-file .jerv/tmp/pr-${pr}-body.md\`) without a body override, then rerun \`pr land\`. Keep repository settings unchanged.`
|
|
44413
44423
|
},
|
|
44414
|
-
error:
|
|
44424
|
+
error: `queue preparation needed: repository squash policy is PR_BODY, and the PR body does not carry the required Test-Policy-Override trailer(s) in its final Git-recognized trailer block \u2014 ${describeWaiverText("the PR body", pull.body, process.cwd())}; ${describeWaiverText("the source commit messages", messages.map((message2) => `${message2.headline}
|
|
44425
|
+
|
|
44426
|
+
${message2.body}`).join("\n\n"), process.cwd())}`
|
|
44415
44427
|
}
|
|
44416
44428
|
};
|
|
44417
44429
|
}
|
|
@@ -44420,9 +44432,12 @@ ${pull.body}`;
|
|
|
44420
44432
|
return keys.length ? keys.join(", ") : "none";
|
|
44421
44433
|
};
|
|
44422
44434
|
const source = options.bodyText != null ? "the explicit body override" : "the body composed from the source commit messages";
|
|
44435
|
+
const sentLabel = method === "SQUASH" ? `squash ${policy.body ?? "unknown"}, ${messages.length} commit message${messages.length === 1 ? "" : "s"}` : `${method}${repository.merge_commit_message === "PR_BODY" ? " + PR body" : ""}`;
|
|
44423
44436
|
const detail = `the requested sanitized body or trailer arrangement cannot be sent to queue admission: queue merge method ${method}, squash body policy ${policy.body ?? "unknown"}; required body is ${source} (trailer keys: ${trailerKeys(`${headline}
|
|
44424
44437
|
|
|
44425
|
-
${requiredBody}`)}), but the message the queue would send carries trailer keys: ${trailerKeys(actualMessage)}
|
|
44438
|
+
${requiredBody}`)}), but the message the queue would send carries trailer keys: ${trailerKeys(actualMessage)}. ${describeWaiverText(`the message the queue sends (${sentLabel})`, actualMessage, process.cwd())}; ${describeWaiverText("the source commit messages", messages.map((message2) => `${message2.headline}
|
|
44439
|
+
|
|
44440
|
+
${message2.body}`).join("\n\n"), process.cwd())}.`;
|
|
44426
44441
|
const next = options.bodyText != null ? `PR author: a merge queue accepts no body override; drop --body/--squash-body-file and place the required trailer(s) where the queue's ${method}${method === "SQUASH" ? ` (${policy.body})` : ""} message reads them, then rerun \`mmi-cli devops pr land ${pr} --repo ${repo}\`. Keep repository settings unchanged.` : method !== "SQUASH" ? `PR author: the queue's ${method} method keeps the original commit messages, so the required trailer(s) must sit in a source commit message's final trailer block; amend the commit, push, re-run checks and \`mmi-cli devops pr land ${pr} --repo ${repo}\`. Keep repository settings unchanged.` : policy.body === "BLANK" ? `PR author: squash body policy BLANK sends an empty body, so no trailer from the commits or PR body reaches the queue commit; the waiver cannot survive queue admission with unchanged repository settings \u2014 remove the need for the override or ask a maintainer. Keep repository settings unchanged.` : `PR author: squash body policy ${policy.body} does not reproduce the composed body; consolidate the required trailer(s) into one source commit message's final trailer block, push, re-run checks and \`mmi-cli devops pr land ${pr} --repo ${repo}\`. Keep repository settings unchanged.`;
|
|
44427
44442
|
const caveat = " GitHub may append coauthors even to one source commit, so source consolidation alone does not prove the generated message passes test policy; the combined queue candidate must pass with the shared trailer reader.";
|
|
44428
44443
|
return { kind: "refused", result: preparation("queue-message-override", [], detail, next + caveat) };
|
|
@@ -44472,7 +44487,7 @@ async function abandonQueueAdmission(pr, repo, options = {}) {
|
|
|
44472
44487
|
}
|
|
44473
44488
|
let snapshot;
|
|
44474
44489
|
try {
|
|
44475
|
-
snapshot = await readPrMergeQueue(pr, repo, options.read ?? actorReadApi);
|
|
44490
|
+
snapshot = await readPrMergeQueue(pr, repo, options.read ?? actorReadApi, options.sleep);
|
|
44476
44491
|
} catch (error) {
|
|
44477
44492
|
return refuse(`the PR and queue state could not be read (${error.message}); the admission is unchanged`);
|
|
44478
44493
|
}
|
|
@@ -44497,13 +44512,19 @@ function decideQueueMergeRoute(hasQueue, method, headRef) {
|
|
|
44497
44512
|
if (!hasQueue) return "normal";
|
|
44498
44513
|
return method === "--merge" && /^(release-align|hotfix-fold)\//.test(headRef) ? "admin-true-merge" : "pr-land";
|
|
44499
44514
|
}
|
|
44500
|
-
async function readPrMergeQueue(pr, repo, gh2 = actorReadApi) {
|
|
44515
|
+
async function readPrMergeQueue(pr, repo, gh2 = actorReadApi, sleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms))) {
|
|
44501
44516
|
if (!/^\d+$/.test(pr)) throw new Error("merge queue read requires a PR number");
|
|
44502
|
-
const
|
|
44503
|
-
|
|
44504
|
-
|
|
44505
|
-
|
|
44506
|
-
|
|
44517
|
+
const fields = `pullRequest(number:${pr}) { state isInMergeQueue mergeQueueEntry { state position enqueuedAt headCommit { oid } } autoMergeRequest { enabledAt } headRefOid }`;
|
|
44518
|
+
let result;
|
|
44519
|
+
for (let attempt = 0; ; attempt++) {
|
|
44520
|
+
try {
|
|
44521
|
+
result = await queueGraphql(repo, fields, gh2);
|
|
44522
|
+
break;
|
|
44523
|
+
} catch (error) {
|
|
44524
|
+
if (attempt >= 2 || !isUpstreamGitHubFault(execErrorText(error))) throw error;
|
|
44525
|
+
await sleep2(2e3 * (attempt + 1));
|
|
44526
|
+
}
|
|
44527
|
+
}
|
|
44507
44528
|
if (!result.pullRequest) throw new Error(`merge queue PR #${pr} not found`);
|
|
44508
44529
|
const entry = result.pullRequest.mergeQueueEntry;
|
|
44509
44530
|
if (entry && (entry.enqueuedAt !== void 0 && !Number.isFinite(Date.parse(entry.enqueuedAt)) || entry.headCommit && !/^[a-f0-9]{40}$/i.test(entry.headCommit.oid))) throw new Error("queue entry identity is unreadable");
|
|
@@ -44932,7 +44953,7 @@ async function dispatchWorkflow(repo, workflow, ref, inputs, deps) {
|
|
|
44932
44953
|
const fields = ["-f", `ref=${ref}`];
|
|
44933
44954
|
const names = /* @__PURE__ */ new Set();
|
|
44934
44955
|
for (const input of inputs) {
|
|
44935
|
-
const match = /^([A-Za-z_][A-Za-z0-9_]{0,63})=([^\r\n]{0,2048})$/.exec(input);
|
|
44956
|
+
const match = /^([A-Za-z_][A-Za-z0-9_-]{0,63})=([^\r\n]{0,2048})$/.exec(input);
|
|
44936
44957
|
if (!match || names.has(match[1])) throw new Error("run dispatch: invalid or duplicate input");
|
|
44937
44958
|
names.add(match[1]);
|
|
44938
44959
|
fields.push("-f", `inputs[${match[1]}]=${match[2]}`);
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -83,7 +83,9 @@ jobs:
|
|
|
83
83
|
# that runs the full job; main must never become skippable via bootstrap vars alone while the
|
|
84
84
|
# org ruleset still requires `gate` on main.
|
|
85
85
|
if: ${{ github.event_name != 'push' || github.ref_name == '{{GATE_FULL_RUN_BRANCH}}' || github.ref_name == 'main' || github.ref_type == 'tag' }}
|
|
86
|
-
|
|
86
|
+
# #9248: included GitHub-hosted capacity, first choice for CI.
|
|
87
|
+
# #9668: GATE_HOSTED_SPILL_QUEUE=off routes it to the owned mmi-live lanes at Actions run-out.
|
|
88
|
+
runs-on: ${{ vars.GATE_HOSTED_SPILL_QUEUE == 'off' && fromJSON('["self-hosted","linux","x64","mmi-live"]') || 'ubuntu-latest' }}
|
|
87
89
|
defaults:
|
|
88
90
|
run: { working-directory: {{GATE_WORKDIR}} }{{GATE_SERVICES_YAML}}
|
|
89
91
|
steps:{{GATE_VERDICT_STEP_YAML}}
|
|
@@ -21,7 +21,8 @@ jobs:
|
|
|
21
21
|
# the earlier "included Ubuntu for light pre-gates" permission; it creates no new runner class — standard
|
|
22
22
|
# included hosted labels are allowed (`ubuntu-*`, `windows-*`, `macos-*`, ARM variants; #8977); only
|
|
23
23
|
# larger/paid images, GPU and custom runner groups stay refused.
|
|
24
|
-
|
|
24
|
+
# #9668: GATE_HOSTED_SPILL_QUEUE=off routes it to the owned mmi-live lanes at Actions run-out.
|
|
25
|
+
runs-on: ${{ vars.GATE_HOSTED_SPILL_QUEUE == 'off' && fromJSON('["self-hosted","linux","x64","mmi-live"]') || 'ubuntu-latest' }}
|
|
25
26
|
timeout-minutes: 10
|
|
26
27
|
steps:{{GATE_VERDICT_STEP_YAML}}
|
|
27
28
|
- if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|