@mutmutco/claude-plugin 4.6.4 → 4.6.5
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
|
@@ -1355,6 +1355,7 @@ __export(cli_shared_exports, {
|
|
|
1355
1355
|
fail: () => fail,
|
|
1356
1356
|
failGraceful: () => failGraceful,
|
|
1357
1357
|
failGracefulEnvelope: () => failGracefulEnvelope,
|
|
1358
|
+
ghFilingAppEnv: () => ghFilingAppEnv,
|
|
1358
1359
|
gitOut: () => gitOut,
|
|
1359
1360
|
githubLogin: () => githubLogin,
|
|
1360
1361
|
hubHeaders: () => hubHeaders,
|
|
@@ -1385,10 +1386,10 @@ function setGhReadTokenProvider(provider) {
|
|
|
1385
1386
|
function setGhWriteTokenProvider(provider) {
|
|
1386
1387
|
ghWriteTokenProvider = provider;
|
|
1387
1388
|
}
|
|
1388
|
-
async function ghFilingAppEnv(file, args) {
|
|
1389
|
-
if (!ghWriteTokenProvider || !/(^|[\\/])gh(\.exe)?$/i.test(file) || process.env.MMI_ACTOR?.trim() === "personal") return void 0;
|
|
1389
|
+
async function ghFilingAppEnv(file, args, requireApp = false) {
|
|
1390
|
+
if (!ghWriteTokenProvider || !/(^|[\\/])gh(\.exe)?$/i.test(file) || !requireApp && process.env.MMI_ACTOR?.trim() === "personal") return void 0;
|
|
1390
1391
|
if (!isAppFilingWrite(args)) return void 0;
|
|
1391
|
-
const explicitApp = process.env.MMI_ACTOR?.trim() === "app";
|
|
1392
|
+
const explicitApp = requireApp || process.env.MMI_ACTOR?.trim() === "app";
|
|
1392
1393
|
let token;
|
|
1393
1394
|
try {
|
|
1394
1395
|
token = await ghWriteTokenProvider();
|
|
@@ -1616,7 +1617,7 @@ var init_cli_shared = __esm({
|
|
|
1616
1617
|
const pool = appEnv ? "app" : !callerEnv ? ambientPool() : !callerEnv.GH_TOKEN ? "personal" : callerEnv.MMI_GH_POOL === "app" ? "app" : callerEnv.GH_TOKEN === process.env.GH_TOKEN ? ambientPool() : "caller";
|
|
1617
1618
|
recordGhUsage("gh", pool, args.filter((a) => !a.startsWith("-")).slice(0, 2).join(" "));
|
|
1618
1619
|
}
|
|
1619
|
-
if (!appEnv) return tag(run(), "user");
|
|
1620
|
+
if (!appEnv) return tag(run(), options.env?.MMI_GH_POOL === "app" ? "app_installation" : "user");
|
|
1620
1621
|
try {
|
|
1621
1622
|
return await tag(run(appEnv), "app_installation");
|
|
1622
1623
|
} catch (e) {
|
|
@@ -23741,10 +23742,14 @@ async function claimOneBoardItem(ctx, selector, options) {
|
|
|
23741
23742
|
return;
|
|
23742
23743
|
}
|
|
23743
23744
|
if (!options.force) {
|
|
23745
|
+
if (options.bulk) {
|
|
23746
|
+
const { holder: holder2, why } = laneContestParts(contest);
|
|
23747
|
+
throw new Error(isUnknownHold(contest) ? `${item.ref} cannot be verified as free: ${holder2} (${why}); the liveness reads failed so the claim is refused fail-closed \u2014 ${CONTESTED_CLAIM_RECOVERY}` : `${item.ref} is already claimed by ${holder2} with live evidence of active work (${why}); ${CONTESTED_CLAIM_RECOVERY}`);
|
|
23748
|
+
}
|
|
23744
23749
|
const candidateRefs = [...report.primary.claimable, ...report.secondary.claimable].filter((candidate) => candidate.contentType === "Issue" && candidate.state === "OPEN" && !candidate.claim?.currentlyClaimed && !ctx.selectedRefs.has(candidate.ref.toLowerCase())).map((candidate) => candidate.ref);
|
|
23745
23750
|
const alternatives = candidateRefs.length ? `Board snapshot candidates (not guaranteed free): ${candidateRefs.join(", ")}` : "Board snapshot candidates: none in this read";
|
|
23746
23751
|
const refusal = `${laneContestMessage(item.ref, contest, "claim")}. ${alternatives}; refresh mmi-cli oracle board read before claiming.`;
|
|
23747
|
-
throw new Error(
|
|
23752
|
+
throw new Error(withGatedWriteChainHint(refusal));
|
|
23748
23753
|
}
|
|
23749
23754
|
previousHolder = displaced();
|
|
23750
23755
|
};
|
|
@@ -23799,6 +23804,13 @@ async function claimBoardIssue(options, deps = {}) {
|
|
|
23799
23804
|
const result = await claimOneBoardItem(ctx, selector, options);
|
|
23800
23805
|
return ctx.report.warnings.length ? { ...result, warnings: [...ctx.report.warnings] } : result;
|
|
23801
23806
|
}
|
|
23807
|
+
function formatBulkClaimSummary(results) {
|
|
23808
|
+
const skipped = results.filter((r) => !r.claimed);
|
|
23809
|
+
if (skipped.length === 0) return void 0;
|
|
23810
|
+
const landed = results.filter((r) => r.claimed).map((r) => r.ref);
|
|
23811
|
+
const notClaimed = skipped.map((r) => `${r.ref}${/already claimed by /i.test(r.reason) ? " (held by another lane)" : ""}`);
|
|
23812
|
+
return `claimed ${landed.length} of ${results.length}: ${landed.length ? `${landed.join(", ")} landed` : "none landed"}; not claimed: ${notClaimed.join(", ")}`;
|
|
23813
|
+
}
|
|
23802
23814
|
async function claimBoardIssues(options, deps = {}) {
|
|
23803
23815
|
const cfg = resolveBoardConfig(options.config);
|
|
23804
23816
|
const { collected, snapshot } = await collectBoardPreferringSnapshot(cfg, options, deps);
|
|
@@ -27388,10 +27400,10 @@ var rollout_plan_default = {
|
|
|
27388
27400
|
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)."
|
|
27389
27401
|
},
|
|
27390
27402
|
baseline: {
|
|
27391
|
-
version: "4.6.
|
|
27392
|
-
tag: "v4.6.
|
|
27393
|
-
commit: "
|
|
27394
|
-
npm: "@mutmutco/cli@4.6.
|
|
27403
|
+
version: "4.6.5",
|
|
27404
|
+
tag: "v4.6.5",
|
|
27405
|
+
commit: "cd6f8a959ed5",
|
|
27406
|
+
npm: "@mutmutco/cli@4.6.5"
|
|
27395
27407
|
},
|
|
27396
27408
|
exitCriterion: "fleet-n-of-n",
|
|
27397
27409
|
hubOnlyShortcut: "forbidden",
|
|
@@ -27408,14 +27420,14 @@ var rollout_plan_default = {
|
|
|
27408
27420
|
repo: "mutmutco/mmi-hub",
|
|
27409
27421
|
role: "canary",
|
|
27410
27422
|
schedule: "train",
|
|
27411
|
-
v3Target: "v4.6.
|
|
27423
|
+
v3Target: "v4.6.5"
|
|
27412
27424
|
}
|
|
27413
27425
|
],
|
|
27414
27426
|
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.",
|
|
27415
27427
|
rollback: {
|
|
27416
27428
|
independent: true,
|
|
27417
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
27418
|
-
v3Target: "v4.6.
|
|
27429
|
+
mechanism: "npm dist-tag latest -> 4.6.5 and redeploy the Hub Lambda from tag v4.6.5 (cd6f8a959ed5); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
27430
|
+
v3Target: "v4.6.5 (@mutmutco/cli@4.6.5, tag commit cd6f8a959ed5 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
27419
27431
|
}
|
|
27420
27432
|
},
|
|
27421
27433
|
{
|
|
@@ -41941,6 +41953,13 @@ var writeApi = async (args) => {
|
|
|
41941
41953
|
const { stdout, credential } = await execFileP("gh", ["api", ...args], { timeout: GH_MUTATION_TIMEOUT_MS, maxBuffer: 16 * 1024 * 1024 });
|
|
41942
41954
|
return { stdout, credential };
|
|
41943
41955
|
};
|
|
41956
|
+
var autoMergeApi = async (pr, repo, head) => {
|
|
41957
|
+
const args = ["pr", "merge", pr, "-R", repo, "--squash", "--auto", "--match-head-commit", head];
|
|
41958
|
+
const env = await ghFilingAppEnv("gh", args, true);
|
|
41959
|
+
if (!env) throw new Error("app actor: filing write token unavailable for merge-queue auto-merge fallback");
|
|
41960
|
+
await execFileP("gh", args, { timeout: GH_MUTATION_TIMEOUT_MS, maxBuffer: 16 * 1024 * 1024, env });
|
|
41961
|
+
return { credential: "app_installation" };
|
|
41962
|
+
};
|
|
41944
41963
|
var ASYNC_HEADERS = ["-H", "Accept: application/vnd.github+json", "-H", "X-GitHub-Api-Version: 2026-03-10"];
|
|
41945
41964
|
var UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
41946
41965
|
function admissionJournal(repo, pr, root) {
|
|
@@ -42017,6 +42036,21 @@ function admissionResponse(output) {
|
|
|
42017
42036
|
}
|
|
42018
42037
|
return { code: Number(response[1]), body: result };
|
|
42019
42038
|
}
|
|
42039
|
+
function admissionRejected(reason) {
|
|
42040
|
+
if (/enqueuer is not authorized to merge|not authorized to merge/i.test(reason)) {
|
|
42041
|
+
return {
|
|
42042
|
+
mergeStatus: "failed",
|
|
42043
|
+
retryable: false,
|
|
42044
|
+
admissionCause: "enqueuer-not-authorized",
|
|
42045
|
+
error: `queue admission rejected (missing merge permission): ${reason}. The landing identity reported in \`credential\` may not merge into this base through the merge queue. Granting it (the GitHub App's merge permission, or a ruleset bypass) is a repository or organization setting only an admin can change; do not rerun pr land until that grant exists, and never fall back to a personal token.`
|
|
42046
|
+
};
|
|
42047
|
+
}
|
|
42048
|
+
return {
|
|
42049
|
+
mergeStatus: "failed",
|
|
42050
|
+
retryable: false,
|
|
42051
|
+
error: `queue admission rejected: ${reason}. Resolve the reported cause, then explicitly rerun pr land; it will repeat preflight before a new request.`
|
|
42052
|
+
};
|
|
42053
|
+
}
|
|
42020
42054
|
async function submitQueueAdmission(pr, repo, head, read, write, options, resume = false) {
|
|
42021
42055
|
const unknown = (reason) => ({
|
|
42022
42056
|
mergeStatus: "failed",
|
|
@@ -42024,11 +42058,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
|
|
|
42024
42058
|
outcomeUnknown: true,
|
|
42025
42059
|
error: `queue submission outcome unknown: ${reason}. Preserve the receipt and rerun pr land to reconcile read-only; no new request was sent after this uncertainty.`
|
|
42026
42060
|
});
|
|
42027
|
-
const rejected =
|
|
42028
|
-
mergeStatus: "failed",
|
|
42029
|
-
retryable: false,
|
|
42030
|
-
error: `queue admission rejected: ${reason}. Resolve the reported cause, then explicitly rerun pr land; it will repeat preflight before a new request.`
|
|
42031
|
-
});
|
|
42061
|
+
const rejected = admissionRejected;
|
|
42032
42062
|
const reconcile = async (reason, recordEntry = false) => {
|
|
42033
42063
|
try {
|
|
42034
42064
|
const observed = await readPrMergeQueue(pr, repo, read);
|
|
@@ -42138,13 +42168,45 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
|
|
|
42138
42168
|
}
|
|
42139
42169
|
return reconcile(`GitHub reported ${body.status}, but matching-head membership or merged state is unconfirmed`, body.status === "enqueued");
|
|
42140
42170
|
}
|
|
42171
|
+
const tryAutoMergeFallback = async (reason, uuid) => {
|
|
42172
|
+
const autoMerge = options.autoMerge ?? (write === writeApi ? autoMergeApi : void 0);
|
|
42173
|
+
if (!/enqueuer is not authorized to merge/i.test(reason) || !autoMerge) return void 0;
|
|
42174
|
+
try {
|
|
42175
|
+
const fallback = await autoMerge(pr, repo, head);
|
|
42176
|
+
const fallbackCredential = fallback?.credential ?? credential ?? receipt?.credential;
|
|
42177
|
+
const observed = await readPrMergeQueue(pr, repo, read);
|
|
42178
|
+
if (observed.state === "MERGED" && observed.headRefOid === head) {
|
|
42179
|
+
try {
|
|
42180
|
+
journal.save("merged", uuid, void 0, fallbackCredential);
|
|
42181
|
+
} catch {
|
|
42182
|
+
return reconcile("the completed auto-merge fallback could not be checkpointed");
|
|
42183
|
+
}
|
|
42184
|
+
return { mergeStatus: "merged" };
|
|
42185
|
+
}
|
|
42186
|
+
if (observed.isInMergeQueue && observed.headRefOid === head) {
|
|
42187
|
+
const entry = observed.mergeQueueEntry;
|
|
42188
|
+
const queueEntry = entry?.headCommit && entry.enqueuedAt ? { headCommitOid: entry.headCommit.oid, enqueuedAt: entry.enqueuedAt } : void 0;
|
|
42189
|
+
try {
|
|
42190
|
+
journal.save("enqueued", uuid, queueEntry, fallbackCredential);
|
|
42191
|
+
} catch {
|
|
42192
|
+
return reconcile("the enqueued auto-merge fallback could not be checkpointed");
|
|
42193
|
+
}
|
|
42194
|
+
return { mergeStatus: "auto-merge-enqueued" };
|
|
42195
|
+
}
|
|
42196
|
+
} catch {
|
|
42197
|
+
}
|
|
42198
|
+
return void 0;
|
|
42199
|
+
};
|
|
42141
42200
|
if (code === 400 || code === 403 || code === 404 || code === 422) {
|
|
42201
|
+
const reason = body.details?.message ?? body.message ?? `HTTP ${code}`;
|
|
42202
|
+
const fallbackResult = await tryAutoMergeFallback(reason);
|
|
42203
|
+
if (fallbackResult) return fallbackResult;
|
|
42142
42204
|
try {
|
|
42143
42205
|
journal.save("failed", void 0, void 0, credential);
|
|
42144
42206
|
} catch {
|
|
42145
42207
|
return unknown("the explicit rejection could not be checkpointed");
|
|
42146
42208
|
}
|
|
42147
|
-
return rejected(
|
|
42209
|
+
return rejected(reason);
|
|
42148
42210
|
}
|
|
42149
42211
|
const details = body.details;
|
|
42150
42212
|
if (code !== 202 && code !== 409 || body.status !== "pending" || !UUID.test(details?.uuid ?? "")) return reconcile("the send returned no recognized admission result");
|
|
@@ -42175,6 +42237,36 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
|
|
|
42175
42237
|
continue;
|
|
42176
42238
|
}
|
|
42177
42239
|
if (!["failed", "enqueued", "merged"].includes(status ?? "")) return reconcile("the operation returned an unrecognized state");
|
|
42240
|
+
if (status === "failed") {
|
|
42241
|
+
const reason = details?.message ?? "GitHub reported a failed operation";
|
|
42242
|
+
const autoMerge = options.autoMerge ?? (write === writeApi ? autoMergeApi : void 0);
|
|
42243
|
+
if (/enqueuer is not authorized to merge/i.test(reason) && autoMerge && receipt.head === head) {
|
|
42244
|
+
try {
|
|
42245
|
+
const fallback = await autoMerge(pr, repo, head);
|
|
42246
|
+
const fallbackCredential = fallback?.credential ?? receipt?.credential;
|
|
42247
|
+
const observed = await readPrMergeQueue(pr, repo, read);
|
|
42248
|
+
if (observed.state === "MERGED" && observed.headRefOid === head) {
|
|
42249
|
+
try {
|
|
42250
|
+
journal.save("merged", receipt.uuid, void 0, fallbackCredential);
|
|
42251
|
+
} catch {
|
|
42252
|
+
return reconcile("the completed auto-merge fallback could not be checkpointed");
|
|
42253
|
+
}
|
|
42254
|
+
return { mergeStatus: "merged" };
|
|
42255
|
+
}
|
|
42256
|
+
if (observed.isInMergeQueue && observed.headRefOid === head) {
|
|
42257
|
+
const entry = observed.mergeQueueEntry;
|
|
42258
|
+
const queueEntry = entry?.headCommit && entry.enqueuedAt ? { headCommitOid: entry.headCommit.oid, enqueuedAt: entry.enqueuedAt } : void 0;
|
|
42259
|
+
try {
|
|
42260
|
+
journal.save("enqueued", receipt.uuid, queueEntry, fallbackCredential);
|
|
42261
|
+
} catch {
|
|
42262
|
+
return reconcile("the enqueued auto-merge fallback could not be checkpointed");
|
|
42263
|
+
}
|
|
42264
|
+
return { mergeStatus: "auto-merge-enqueued" };
|
|
42265
|
+
}
|
|
42266
|
+
} catch {
|
|
42267
|
+
}
|
|
42268
|
+
}
|
|
42269
|
+
}
|
|
42178
42270
|
try {
|
|
42179
42271
|
journal.save(status, receipt.uuid);
|
|
42180
42272
|
} catch {
|
|
@@ -42513,22 +42605,24 @@ function registerCancelOrphans(ci2, writeToken) {
|
|
|
42513
42605
|
});
|
|
42514
42606
|
}
|
|
42515
42607
|
var RUN_CANCEL_STATUS = "cancel-requested";
|
|
42516
|
-
|
|
42608
|
+
var RUN_FORCE_CANCEL_STATUS = "force-cancel-requested";
|
|
42609
|
+
async function cancelWorkflowRun(repo, id, deps, force = false) {
|
|
42517
42610
|
const raw = String(id).trim();
|
|
42518
42611
|
if (!/^[1-9]\d*$/.test(raw)) throw new Error(`run cancel: <id> must be a positive workflow run id (received '${String(id)}')`);
|
|
42519
42612
|
const runId = Number(raw);
|
|
42520
42613
|
if (!Number.isSafeInteger(runId)) throw new Error(`run cancel: <id> ${raw} is beyond the safe integer range; refusing to address a different run`);
|
|
42521
42614
|
if (!/^[\w.-]+\/[\w.-]+$/.test(repo)) throw new Error(`run cancel: --repo must be owner/repo (received '${repo}')`);
|
|
42522
42615
|
try {
|
|
42523
|
-
await deps.
|
|
42616
|
+
if (force && deps.forceCancel) await deps.forceCancel(repo, runId);
|
|
42617
|
+
else await deps.cancel(repo, runId);
|
|
42524
42618
|
} catch (error) {
|
|
42525
42619
|
const detail = String(error.stderr ?? error);
|
|
42526
42620
|
throw new Error(/\b403\b/.test(detail) ? "run cancel: GitHub App denied (HTTP 403); actions:write permission is required; no personal-token fallback" : `run cancel: ${detail}`);
|
|
42527
42621
|
}
|
|
42528
|
-
return { ok: true, repo, runId, status: RUN_CANCEL_STATUS };
|
|
42622
|
+
return { ok: true, repo, runId, ...force ? { force: true } : {}, status: force ? RUN_FORCE_CANCEL_STATUS : RUN_CANCEL_STATUS };
|
|
42529
42623
|
}
|
|
42530
42624
|
function registerRunCancel(run, writeToken) {
|
|
42531
|
-
run.command("cancel <id>").description("cancel one queued or in-progress workflow run on the org App (actions:write); requests the cancel and prints a receipt").requiredOption("--repo <owner/repo>", "repository that owns the run").option("--json", "machine-readable receipt").action(async (id, options) => {
|
|
42625
|
+
run.command("cancel <id>").description("cancel one queued or in-progress workflow run on the org App (actions:write); requests the cancel and prints a receipt").requiredOption("--repo <owner/repo>", "repository that owns the run").option("--force", "force-cancel the run so always() jobs stop too (#9512)").option("--json", "machine-readable receipt").action(async (id, options) => {
|
|
42532
42626
|
let receipt;
|
|
42533
42627
|
try {
|
|
42534
42628
|
receipt = await cancelWorkflowRun(options.repo, id, {
|
|
@@ -42538,13 +42632,20 @@ function registerRunCancel(run, writeToken) {
|
|
|
42538
42632
|
timeout: 2e4,
|
|
42539
42633
|
env: { ...process.env, GH_TOKEN: token }
|
|
42540
42634
|
});
|
|
42635
|
+
},
|
|
42636
|
+
forceCancel: async (repo, runId) => {
|
|
42637
|
+
const token = await writeToken();
|
|
42638
|
+
await execFileP("gh", ["api", `repos/${repo}/actions/runs/${runId}/force-cancel`, "--method", "POST"], {
|
|
42639
|
+
timeout: 2e4,
|
|
42640
|
+
env: { ...process.env, GH_TOKEN: token }
|
|
42641
|
+
});
|
|
42541
42642
|
}
|
|
42542
|
-
});
|
|
42643
|
+
}, options.force === true);
|
|
42543
42644
|
} catch (error) {
|
|
42544
42645
|
return fail(error.message);
|
|
42545
42646
|
}
|
|
42546
42647
|
if (options.json) console.log(JSON.stringify(receipt));
|
|
42547
|
-
else console.log(`run cancel: ${receipt.repo} run ${receipt.runId} \u2014 cancel requested (status: ${receipt.status})`);
|
|
42648
|
+
else console.log(`run cancel: ${receipt.repo} run ${receipt.runId} \u2014 ${receipt.force ? "force-cancel" : "cancel"} requested (status: ${receipt.status})`);
|
|
42548
42649
|
});
|
|
42549
42650
|
}
|
|
42550
42651
|
|
|
@@ -42963,6 +43064,8 @@ function registerBoardCommands(program3) {
|
|
|
42963
43064
|
console.log(result.claimed ? claimVerdict(result.ref, result) : `Skipped ${result.ref}: ${result.reason}`);
|
|
42964
43065
|
if (result.claimed) for (const line of formatDecisionLines(result.ref, ruled[i].decisions ?? [])) console.log(line);
|
|
42965
43066
|
});
|
|
43067
|
+
const summary = formatBulkClaimSummary(bulk.results);
|
|
43068
|
+
if (summary) console.log(summary);
|
|
42966
43069
|
printClaimWarnings([...bulk.warnings ?? [], ...rulingWarnings]);
|
|
42967
43070
|
}
|
|
42968
43071
|
if (bulk.failed > 0) process.exitCode = 1;
|
|
@@ -65735,11 +65838,17 @@ function tagsReadHint(path2) {
|
|
|
65735
65838
|
const slug = `${match[1]}/${match[2]}`;
|
|
65736
65839
|
return ` No App-token REST read exists for git tags or refs \u2014 read git tags directly with \`git ls-remote --tags origin 'refs/tags/*'\` (no token needed; \`git ls-remote origin refs/tags/<tag>\` for one tag), or read tag-backed GitHub Releases with \`MMI_ACTOR=app mmi-cli devops api get "repos/${slug}/releases?per_page=20"\`.`;
|
|
65737
65840
|
}
|
|
65841
|
+
function branchRulesReadHint(path2) {
|
|
65842
|
+
const match = new RegExp(`^repos/(${NAME})/(${NAME})/(?:rules/branches/[^/?#]+|branches/[^/?#]+/protection(?:/|$)|rulesets(?:/|$))`).exec(path2.split("?")[0]);
|
|
65843
|
+
if (!match) return "";
|
|
65844
|
+
const slug = `${match[1]}/${match[2]}`;
|
|
65845
|
+
return ` No raw rules, rulesets or branch-protection read is on the App allowlist, so retrying path or query variants cannot work \u2014 inspect a PR's required status contexts with \`MMI_ACTOR=app mmi-cli devops pr checks-required <pr> --repo ${slug} --json\`, or verify repository ruleset and branch-protection health with \`mmi-cli devops bootstrap verify --repo ${slug} --json\` and \`mmi-cli devops ci audit --repo ${slug} --json\`.`;
|
|
65846
|
+
}
|
|
65738
65847
|
function parseApiGetPath(rawPath) {
|
|
65739
65848
|
const path2 = rawPath.trim();
|
|
65740
65849
|
const refuse = () => {
|
|
65741
65850
|
const hint = /^[A-Za-z]:[/\\]/.test(path2) ? " Git Bash/MSYS may have rewritten a leading-slash argument; retry with MSYS_NO_PATHCONV=1 and the slash-free repos/... path. The endpoint must still be allowlisted." : "";
|
|
65742
|
-
const routeHints = `${typedReadHint(path2)}${runsReadHint(path2)}${orgScopedHint(path2)}${tagsReadHint(path2)}${hint}`;
|
|
65851
|
+
const routeHints = `${typedReadHint(path2)}${runsReadHint(path2)}${orgScopedHint(path2)}${tagsReadHint(path2)}${branchRulesReadHint(path2)}${hint}`;
|
|
65743
65852
|
return new Error(`api get: refusing '${rawPath}' \u2014${routeHints}${API_GET_RECOVERY} Only these GET reads are allowed (#7219): ${API_GET_ALLOWED_SHAPES}.`);
|
|
65744
65853
|
};
|
|
65745
65854
|
if (/[%#\\]/.test(path2) || path2.split("?")[0].split("/").some((seg) => seg === "." || seg === ".." || seg === "")) throw refuse();
|
|
@@ -69457,7 +69566,7 @@ registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand
|
|
|
69457
69566
|
appActorCommand = commandPath4;
|
|
69458
69567
|
setAuditCommand(commandPath4);
|
|
69459
69568
|
if (commandPath4 !== "whoami diagnose-hub") emitCliCallTelemetry(commandPath4);
|
|
69460
|
-
if (commandPath4 === "ci cancel-orphans") return;
|
|
69569
|
+
if (commandPath4 === "ci cancel-orphans" || commandPath4 === "run cancel") return;
|
|
69461
69570
|
try {
|
|
69462
69571
|
await activateAppActor(commandPath4, process.env, () => APP_WRITE_COMMANDS.has(commandPath4) ? mintCommandWriteToken(appActorDeps(), commandPath4) : mintInstallationToken(appActorDeps()));
|
|
69463
69572
|
} catch (e) {
|
|
@@ -70294,7 +70403,7 @@ registerCiChecksWait(ci);
|
|
|
70294
70403
|
registerCancelOrphans(ci, async () => (await mintCommandWriteToken(appActorDeps(), "ci cancel-orphans")).token);
|
|
70295
70404
|
registerRunCancel(
|
|
70296
70405
|
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"),
|
|
70297
|
-
async () => (await mintCommandWriteToken(appActorDeps(), "run cancel")).token
|
|
70406
|
+
async () => activeAppToken() ?? (await mintCommandWriteToken(appActorDeps(), "run cancel")).token
|
|
70298
70407
|
);
|
|
70299
70408
|
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) => {
|
|
70300
70409
|
if (o.apply && o.parkRuleset) {
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -165,7 +165,11 @@ that actually ships in the cut: the train refuses an issue or PR number the rele
|
|
|
165
165
|
commit, so build and verify the lines from one pass over that range —
|
|
166
166
|
`git log --stat --format='%h %s%n%b' origin/main..origin/development`, which carries each commit's
|
|
167
167
|
subject, body and changed files — never from subjects, PR titles or memory; a line whose claim is not
|
|
168
|
-
in that output does not go in the file.
|
|
168
|
+
in that output does not go in the file. Release recovery can re-cut the same `v*` tag on a new SHA, so
|
|
169
|
+
other checkouts still holding the old tag reject a plain `git fetch origin --tags` (`would clobber existing tag`);
|
|
170
|
+
refresh tags with `git fetch origin --tags --force` (or `git fetch origin '+refs/tags/*:refs/tags/*'`) and
|
|
171
|
+
never chain a plain tag fetch with `&&` ahead of a read-only `git log <tag>..origin/<branch>` range (#9517).
|
|
172
|
+
A Hub summary never mentions a Jerv-side project; the train
|
|
169
173
|
refuses such a line.
|
|
170
174
|
Every new MM-Work suite Release, solo and hotfix included, requires `--announce-summary-file` and `--announce-summary-file-tr` in the bilingual update-notes template of the [MM-Work GUIDE, "Update notes"](https://github.com/mutmutco/MM-Work/blob/development/packages/mmwork-ds/GUIDE.md#update-notes) (`Fixed`/`Düzeldi`, then `New`/`Yeni`, with `<Area>: <sentence>.` lines; a Fixed line states what works now, never the problem). A suite release requires `--member-summary-file owner/repo=path` and `--member-summary-file-tr owner/repo=path` for every member it releases. A suite cut's `--owner-go` records the owner's explicit go for that one cut, never an agent's own decision: a held train or stale MM-Work cut goes to the suite orchestrator with the exact owner-gated commands. On its own an agent runs only `suite rcand --dry-run` and `suite hotfix <member> --dry-run`; it never runs `suite release` or `suite abandon`, which have no dry-run. Details: the release skill.
|
|
171
175
|
|