@mutmutco/cli 3.48.1 → 3.49.0
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 +100 -28
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -6754,11 +6754,17 @@ async function secretsVerify(deps, key, opts) {
|
|
|
6754
6754
|
deps.err(`invalid secret key ${JSON.stringify(key)}`);
|
|
6755
6755
|
return false;
|
|
6756
6756
|
}
|
|
6757
|
-
|
|
6758
|
-
deps.err(`no provider verifier configured for ${secretLeafName(key)}`);
|
|
6759
|
-
return false;
|
|
6760
|
-
}
|
|
6757
|
+
const hasProviderVerifier = Boolean(providerForSecretKey(key));
|
|
6761
6758
|
const value = await fetchSecretValue(deps, key, opts);
|
|
6759
|
+
if (!hasProviderVerifier) {
|
|
6760
|
+
if (!value) {
|
|
6761
|
+
deps.err(`${key}: ABSENT or unreachable at this coordinate \u2014 no value could be read`);
|
|
6762
|
+
deps.err(`Locate a key across every vault you can reach: mmi-cli org access capabilities${opts.repo ? ` --repo ${opts.repo}` : ""}`);
|
|
6763
|
+
return false;
|
|
6764
|
+
}
|
|
6765
|
+
deps.log(`${key}: PRESENT (${value.length} chars) \u2014 reachability only; no provider verifier is configured for ${secretLeafName(key)}, so the credential itself was not validated`);
|
|
6766
|
+
return true;
|
|
6767
|
+
}
|
|
6762
6768
|
if (!value) {
|
|
6763
6769
|
deps.err(`secrets verify: could not read ${key}; no value was printed`);
|
|
6764
6770
|
return false;
|
|
@@ -6903,6 +6909,11 @@ async function secretsDeclare(deps, key, opts) {
|
|
|
6903
6909
|
const body = await readJsonBody(res);
|
|
6904
6910
|
if (!res.ok) {
|
|
6905
6911
|
deps.err(await upgradeMessage(res, body) ?? `secrets declare failed: HTTP ${res.status}${errorDetail(body)}`);
|
|
6912
|
+
if (res.status === 404 && !errorDetail(body)) {
|
|
6913
|
+
deps.err(
|
|
6914
|
+
`The Hub did not recognize the declare route (no error body \u2014 an API-gateway 404, not an authority refusal). Fall back to the master-side catalog write: mmi-cli org project set ${repo} --secrets-file <catalog.json> (shape: keyed by env name; each entry {key,purpose,group,owner,stages[],consumers[]} \u2014 see docs/Guides/oauth-provision.md \xA7 Cred catalog shape).`
|
|
6915
|
+
);
|
|
6916
|
+
}
|
|
6906
6917
|
return false;
|
|
6907
6918
|
}
|
|
6908
6919
|
if (opts.json) {
|
|
@@ -7115,7 +7126,12 @@ async function secretsUse(deps, key, opts) {
|
|
|
7115
7126
|
" \u2022 Runtime: the central deploy injects the declared stage env; broker consumers use the workload's scoped runtime token. Never bake a value into an image or commit it.",
|
|
7116
7127
|
` \u2022 CI (GitHub Actions): the workflow assumes its OIDC role and runs \`aws ssm get-parameter --with-decryption --name ${path2}\` \u2014 no GitHub secret.`,
|
|
7117
7128
|
" \u2022 Own project: the stageless canonical and any declared dev/rc/main overrides are project-admin self-service.",
|
|
7118
|
-
" \u2022 Org-infra/cross-slug keys remain master-gated unless exactly granted."
|
|
7129
|
+
" \u2022 Org-infra/cross-slug keys remain master-gated unless exactly granted.",
|
|
7130
|
+
"",
|
|
7131
|
+
"Answer it without consuming it (#3436):",
|
|
7132
|
+
" \u2022 WHERE does a key live, across every vault you can reach: `mmi-cli org access capabilities` (names + tier + scope, never values). `secrets list` is this repo only and cannot see _org.",
|
|
7133
|
+
` \u2022 DOES it exist here: \`mmi-cli secrets verify ${key}${opts.slug ? ` --slug ${opts.slug}` : ""}\` \u2014 PRESENT/ABSENT even with no provider verifier configured.`,
|
|
7134
|
+
" \u2022 PowerShell note: `mmi-cli` resolves to npm's mmi-cli.ps1, whose binder eats the `--` separator. The wrapped command works either way; if a flag still misbinds, call `mmi-cli.cmd` explicitly."
|
|
7119
7135
|
].join("\n")
|
|
7120
7136
|
);
|
|
7121
7137
|
return;
|
|
@@ -9179,8 +9195,11 @@ async function waitForPrChecks(deps) {
|
|
|
9179
9195
|
failureStreak += 1;
|
|
9180
9196
|
if (failureStreak >= PR_CHECKS_FAILURE_CONFIRMATIONS) {
|
|
9181
9197
|
const diagnosis = deps.diagnoseFailure ? await deps.diagnoseFailure().catch(() => null) : null;
|
|
9182
|
-
if (diagnosis?.cause === "
|
|
9183
|
-
return { policy, status: "failure", reason: diagnosis.reason, detail: "
|
|
9198
|
+
if (diagnosis?.cause === "stale-head") {
|
|
9199
|
+
return { policy, status: "failure", reason: diagnosis.reason, detail: "stale-head" };
|
|
9200
|
+
}
|
|
9201
|
+
if (diagnosis?.cause === "runner-infra") {
|
|
9202
|
+
return { policy, status: "failure", reason: diagnosis.reason, detail: "runner-infra" };
|
|
9184
9203
|
}
|
|
9185
9204
|
return { policy, status: "failure", reason, detail: "checks-failure" };
|
|
9186
9205
|
}
|
|
@@ -11808,27 +11827,36 @@ function setCommandMetadata(command, metadata) {
|
|
|
11808
11827
|
function commandMetadata(command) {
|
|
11809
11828
|
return command[COMMAND_METADATA];
|
|
11810
11829
|
}
|
|
11811
|
-
|
|
11812
|
-
|
|
11830
|
+
var REQUIRED_OPTION_HELP = {
|
|
11831
|
+
optionDescription(option) {
|
|
11832
|
+
const described = Help.prototype.optionDescription.call(this, option);
|
|
11833
|
+
return option.mandatory ? `(required) ${described}` : described;
|
|
11834
|
+
}
|
|
11835
|
+
};
|
|
11836
|
+
function classifyTree(command, path2, inherited, hideFromParent) {
|
|
11837
|
+
const override = PATH_OVERRIDES[path2];
|
|
11838
|
+
const metadata = override ?? inherited;
|
|
11813
11839
|
setCommandMetadata(command, metadata);
|
|
11814
|
-
if (metadata.discovery !== "primary") {
|
|
11840
|
+
if ((override !== void 0 || hideFromParent) && metadata.discovery !== "primary") {
|
|
11815
11841
|
command._hidden = true;
|
|
11816
11842
|
}
|
|
11817
11843
|
for (const option of command.options) {
|
|
11818
11844
|
if ((HIDDEN_OPTIONS[path2] ?? []).includes(option.long ?? option.short ?? "")) option.hideHelp();
|
|
11819
11845
|
}
|
|
11846
|
+
command.configureHelp(REQUIRED_OPTION_HELP);
|
|
11820
11847
|
for (const child2 of command.commands) {
|
|
11821
11848
|
const childPath = path2 ? `${path2} ${child2.name()}` : child2.name();
|
|
11822
|
-
classifyTree(child2, childPath,
|
|
11849
|
+
classifyTree(child2, childPath, metadata, false);
|
|
11823
11850
|
}
|
|
11824
11851
|
}
|
|
11825
11852
|
function applyCommandTaxonomy(program3) {
|
|
11826
11853
|
for (const command of program3.commands) {
|
|
11827
11854
|
const metadata = topLevelMetadata(command.name());
|
|
11828
11855
|
command.helpGroup(metadata.help_group);
|
|
11829
|
-
classifyTree(command, command.name(), metadata);
|
|
11856
|
+
classifyTree(command, command.name(), metadata, true);
|
|
11830
11857
|
}
|
|
11831
11858
|
program3.configureHelp({
|
|
11859
|
+
...REQUIRED_OPTION_HELP,
|
|
11832
11860
|
visibleCommands(command) {
|
|
11833
11861
|
const visible = command.commands.filter((child2) => !child2._hidden);
|
|
11834
11862
|
const helpCommand = command._getHelpCommand();
|
|
@@ -16872,7 +16900,7 @@ async function withSecrets(run) {
|
|
|
16872
16900
|
function registerSecretsCommands(program3) {
|
|
16873
16901
|
const secrets = program3.command("secrets").description("project vault \u2014 project-admins self-serve their own repo's full tree (stageless + dev/rc/main); org-infra namespaces are master-gated");
|
|
16874
16902
|
secrets.command("where").description("print where this repo's secrets live \u2014 the two-tier vault layout + well-known keys (no values)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json", "machine-readable output").action((o) => withSecrets((d) => secretsWhere(d, o)));
|
|
16875
|
-
secrets.command("list").description("list secret NAMES + tier for
|
|
16903
|
+
secrets.command("list").description("list secret NAMES + tier for THIS repo (never values). To locate a key you cannot place \u2014 including org-infra (_org) \u2014 use the cross-slug view: `mmi-cli org access capabilities` (#3436)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json", "machine-readable output").action((o) => withSecrets((d) => secretsList(d, o)));
|
|
16876
16904
|
secrets.command("find <intent>").description("resolve a plain-language intent to canonical secret names + the exact keyless-use command (master-only, #2244)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json", "machine-readable output").action((intent, o) => withSecrets(async (d) => {
|
|
16877
16905
|
if (!await secretsFind(d, intent, o)) process.exitCode = 1;
|
|
16878
16906
|
}));
|
|
@@ -16995,7 +17023,7 @@ function registerSecretsCommands(program3) {
|
|
|
16995
17023
|
});
|
|
16996
17024
|
if (!ok) process.exitCode = 1;
|
|
16997
17025
|
}));
|
|
16998
|
-
secrets.command("verify <key>").description("validate a known provider secret without printing its value").option("--repo <owner/repo>", "target repo (defaults to the current repo)").action((key, o) => withSecrets(async (d) => {
|
|
17026
|
+
secrets.command("verify <key>").description("validate a known provider secret without printing its value; a key with no configured provider verifier falls back to a value-free PRESENT/ABSENT reachability check (#3436)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--slug <slug>", "org-infra namespace (e.g. _org) for a granted org secret").action((key, o) => withSecrets(async (d) => {
|
|
16999
17027
|
const ok = await secretsVerify(d, key, o);
|
|
17000
17028
|
if (!ok) process.exitCode = 1;
|
|
17001
17029
|
}));
|
|
@@ -17045,7 +17073,7 @@ function registerSecretsCommands(program3) {
|
|
|
17045
17073
|
if (!ok) process.exitCode = 1;
|
|
17046
17074
|
}));
|
|
17047
17075
|
secrets.command("rm <key>").description("remove a secret from your own full project vault; org-infra requires master or an exact grant. --slug _org removes an org-infra <provider>/<KEY> value (#3315)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--slug <slug>", "org-infra namespace (e.g. _org) for the value removal \u2014 master or an exact grant (#3315)").action((key, o) => withSecrets((d) => secretsRemove(d, key, o)));
|
|
17048
|
-
secrets.command("use <key> [command...]").description("consume a secret KEYLESS: own-project full tree or an exactly granted org-infra key; injects into command env and never prints it").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--slug <slug>", "org-infra namespace (e.g. _org) for a granted org secret").option("--name <ENVVAR>", "env var name to inject under (default: the key leaf, UPPER_SNAKE)").action((key, command, o) => withSecrets(async (d) => {
|
|
17076
|
+
secrets.command("use <key> [command...]").description("consume a secret KEYLESS: own-project full tree or an exactly granted org-infra key; injects into command env and never prints it. The wrapped command keeps its OWN flags (`-- node -e \u2026`, `-- curl -H \u2026`) with or without the `--`, because npm's PowerShell shim swallows `--` before the CLI sees it (#3436)").allowUnknownOption().option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--slug <slug>", "org-infra namespace (e.g. _org) for a granted org secret").option("--name <ENVVAR>", "env var name to inject under (default: the key leaf, UPPER_SNAKE)").action((key, command, o) => withSecrets(async (d) => {
|
|
17049
17077
|
const ok = await secretsUse(d, key, { ...o, command });
|
|
17050
17078
|
if (ok === false) process.exitCode = 1;
|
|
17051
17079
|
}));
|
|
@@ -20748,14 +20776,30 @@ function parseRestPrSnapshot(json) {
|
|
|
20748
20776
|
const pr2 = json ?? {};
|
|
20749
20777
|
const headSha = pr2.head?.sha ?? "";
|
|
20750
20778
|
if (!headSha) throw new Error("pulls endpoint returned no head SHA");
|
|
20779
|
+
const headRepo = pr2.head?.repo?.full_name;
|
|
20780
|
+
const baseRepo = pr2.base?.repo?.full_name;
|
|
20751
20781
|
return {
|
|
20752
20782
|
headSha,
|
|
20783
|
+
headRef: pr2.head?.ref ?? "",
|
|
20784
|
+
// Only call it a fork when BOTH names are known and differ — an absent name (private/deleted fork)
|
|
20785
|
+
// must not read as same-repo and send a git-ref probe at a branch the base repo does not have.
|
|
20786
|
+
headIsFork: Boolean(headRepo && baseRepo && headRepo !== baseRepo),
|
|
20753
20787
|
mergeable: pr2.mergeable === true ? "MERGEABLE" : pr2.mergeable === false ? "CONFLICTING" : "UNKNOWN",
|
|
20754
20788
|
baseRef: pr2.base?.ref ?? "development",
|
|
20755
20789
|
merged: pr2.merged === true,
|
|
20756
20790
|
state: pr2.state ?? ""
|
|
20757
20791
|
};
|
|
20758
20792
|
}
|
|
20793
|
+
async function fetchBranchTipSha(repo, ref, gh = defaultGhApi) {
|
|
20794
|
+
if (!ref) return null;
|
|
20795
|
+
try {
|
|
20796
|
+
const parsed = JSON.parse(await gh([`repos/${repo}/git/ref/heads/${ref}`]));
|
|
20797
|
+
const sha = parsed.object?.sha;
|
|
20798
|
+
return typeof sha === "string" && sha ? sha : null;
|
|
20799
|
+
} catch {
|
|
20800
|
+
return null;
|
|
20801
|
+
}
|
|
20802
|
+
}
|
|
20759
20803
|
async function fetchRestPrSnapshot(prNumber, repo, gh = defaultGhApi) {
|
|
20760
20804
|
return parseRestPrSnapshot(JSON.parse(await gh([`repos/${repo}/pulls/${prNumber}`])));
|
|
20761
20805
|
}
|
|
@@ -20790,36 +20834,54 @@ async function pollRestPrMerged(prNumber, repo, gh = defaultGhApi) {
|
|
|
20790
20834
|
}
|
|
20791
20835
|
}
|
|
20792
20836
|
var CI_BUDGET_ANNOTATION_TITLE = "CI budget exceeded";
|
|
20837
|
+
var CI_DISK_ANNOTATION_TITLE = "CI runner disk";
|
|
20838
|
+
var CI_TOOLCHAIN_ANNOTATION_TITLE = "CI runner toolchain";
|
|
20839
|
+
var RUNNER_INFRA_ANNOTATION_TITLES = /* @__PURE__ */ new Set([
|
|
20840
|
+
CI_BUDGET_ANNOTATION_TITLE,
|
|
20841
|
+
CI_DISK_ANNOTATION_TITLE,
|
|
20842
|
+
CI_TOOLCHAIN_ANNOTATION_TITLE
|
|
20843
|
+
]);
|
|
20793
20844
|
function isErrorAnnotation(a) {
|
|
20794
20845
|
const level = a.annotation_level?.toLowerCase();
|
|
20795
20846
|
return level === "failure" || level === "error";
|
|
20796
20847
|
}
|
|
20797
20848
|
function classifyFailedChecks(failing) {
|
|
20798
|
-
const
|
|
20849
|
+
const infraFailures = [];
|
|
20799
20850
|
const otherFailures = [];
|
|
20800
20851
|
for (const check of failing) {
|
|
20801
20852
|
const errors = check.annotations.filter(isErrorAnnotation);
|
|
20802
|
-
const
|
|
20803
|
-
(
|
|
20853
|
+
const allInfra = errors.length > 0 && errors.every((a) => RUNNER_INFRA_ANNOTATION_TITLES.has(a.title?.trim() ?? ""));
|
|
20854
|
+
(allInfra ? infraFailures : otherFailures).push(check.name);
|
|
20804
20855
|
}
|
|
20805
|
-
if (
|
|
20856
|
+
if (infraFailures.length && !otherFailures.length) {
|
|
20806
20857
|
return {
|
|
20807
|
-
cause: "
|
|
20808
|
-
|
|
20858
|
+
cause: "runner-infra",
|
|
20859
|
+
infraFailures,
|
|
20809
20860
|
otherFailures,
|
|
20810
|
-
reason: `${
|
|
20861
|
+
reason: `${infraFailures.length} check(s) failed on RUNNER INFRASTRUCTURE, not your diff: ${infraFailures.join(", ")}. No test failed \u2014 the shared runner hit a wall-clock budget kill, ran out of disk, or was missing a toolchain (the check annotation names which). Re-run once the runner drains/heals (gh run rerun --failed); do not debug the diff.`
|
|
20811
20862
|
};
|
|
20812
20863
|
}
|
|
20813
20864
|
return {
|
|
20814
20865
|
cause: "checks-failure",
|
|
20815
|
-
|
|
20866
|
+
infraFailures,
|
|
20816
20867
|
otherFailures,
|
|
20817
|
-
reason:
|
|
20868
|
+
reason: infraFailures.length ? `checks failed: ${otherFailures.join(", ")}; separately, ${infraFailures.join(", ")} failed on runner infrastructure, not a test.` : `checks failed: ${otherFailures.join(", ") || "unknown"}.`
|
|
20818
20869
|
};
|
|
20819
20870
|
}
|
|
20820
20871
|
async function diagnoseFailedRestChecks(prNumber, repo, gh = defaultGhApi) {
|
|
20821
20872
|
try {
|
|
20822
20873
|
const snapshot = await fetchRestPrSnapshot(prNumber, repo, gh);
|
|
20874
|
+
if (!snapshot.headIsFork) {
|
|
20875
|
+
const branchTip = await fetchBranchTipSha(repo, snapshot.headRef, gh);
|
|
20876
|
+
if (branchTip && branchTip !== snapshot.headSha) {
|
|
20877
|
+
return {
|
|
20878
|
+
cause: "stale-head",
|
|
20879
|
+
infraFailures: [],
|
|
20880
|
+
otherFailures: [],
|
|
20881
|
+
reason: `the PR head (${snapshot.headSha.slice(0, 7)}) is BEHIND the branch tip (${branchTip.slice(0, 7)}) \u2014 GitHub likely dropped a \`synchronize\` event, so the reported red is a superseded commit and NO run exists for your current push. This is not your diff failing. Re-push (an empty commit is enough) or close and reopen the PR to re-sync the head and trigger a fresh run.`
|
|
20882
|
+
};
|
|
20883
|
+
}
|
|
20884
|
+
}
|
|
20823
20885
|
const failing = (await fetchHeadCheckRuns(snapshot.headSha, repo, gh)).filter((run) => classifyCheckRun(run) === "fail" && typeof run.id === "number");
|
|
20824
20886
|
if (!failing.length) return null;
|
|
20825
20887
|
const annotated = await Promise.all(failing.map(async (run) => ({
|
|
@@ -24548,7 +24610,7 @@ projectDeploy.command("get [owner/repo]").description("read nonsecret DEPLOY# fa
|
|
|
24548
24610
|
const payload = stage ? { slug: out.slug, stage, deploy: out.stages[stage] ?? null } : out;
|
|
24549
24611
|
console.log(JSON.stringify(payload));
|
|
24550
24612
|
});
|
|
24551
|
-
project.command("set [owner/repo]").description("upsert project META (idempotent merge; master-gated)").option("--class <class>", "deployable | content").option("--project-type <type>", `${PROJECT_TYPES.join(" | ")} (capability shape)`).option("--deploy-model <model>", `${DEPLOY_MODELS.join(" | ")} (release/deploy path; none means no Hub deploy registration)`).option("--release-track <track>", `${RELEASE_TRACKS.join(" | ")} (branch topology; direct skips rc)`).option("--var <KEY=VALUE...>", settableVarHelp()).option("--set <KEY=VALUE...>", "alias of --var (one KEY=VALUE per flag; repeat the flag to set several)").option("--secrets-file <path>",
|
|
24613
|
+
project.command("set [owner/repo]").description("upsert project META (idempotent merge; master-gated)").option("--class <class>", "deployable | content").option("--project-type <type>", `${PROJECT_TYPES.join(" | ")} (capability shape)`).option("--deploy-model <model>", `${DEPLOY_MODELS.join(" | ")} (release/deploy path; none means no Hub deploy registration)`).option("--release-track <track>", `${RELEASE_TRACKS.join(" | ")} (branch topology; direct skips rc)`).option("--var <KEY=VALUE...>", settableVarHelp()).option("--set <KEY=VALUE...>", "alias of --var (one KEY=VALUE per flag; repeat the flag to set several)").option("--secrets-file <path>", 'read the #2244 secrets catalog map (JSON) from a file and merge it per entry into the existing catalog (clear all with --unset secrets). SHAPE: a JSON object keyed by env name, each entry {"key":"UPPER_SNAKE" (repeat the env name), "purpose":"<non-empty>", "group":"<e.g. auth|database>", "owner":"<github login>", "stages":[] (empty = the one stageless shared value; else any of dev/rc/main), "consumers":["runtime"|"box"|\u2026], "provider":"<optional>"}').option("--unset <KEY...>", "META field to remove (repeatable): oauth, requiredRuntimeSecrets, requiredBuildSecrets, secrets, edgeDomains, requiredGcpApis, publishRequired").option("--clear-web-profile", "remove web-only registry fields (oauth, edgeDomains) for non-web/content projects").option("--json", "machine-readable output").action(async (repoOrSlug, o) => {
|
|
24552
24614
|
const cfg = await loadConfig();
|
|
24553
24615
|
let target;
|
|
24554
24616
|
try {
|
|
@@ -24735,7 +24797,15 @@ oauth.command("plan", { isDefault: true }).description("print the canonical JS o
|
|
|
24735
24797
|
try {
|
|
24736
24798
|
oc = parseOauthConfig(meta ?? {}, slug);
|
|
24737
24799
|
} catch (e) {
|
|
24738
|
-
|
|
24800
|
+
const message = e.message;
|
|
24801
|
+
if (/^oauth is not configured for /.test(message)) {
|
|
24802
|
+
return failGraceful(
|
|
24803
|
+
`org oauth plan: ${message}. Declare it in the registry META first:
|
|
24804
|
+
mmi-cli org project set ${o.repo ?? `mutmutco/${slug}`} --var 'oauth={"subdomains":["${defaultSubdomain(slug)}"],"callbackPath":"${DEFAULT_CALLBACK_PATH}"}'
|
|
24805
|
+
New repo? The GCP project and its Google Auth Platform consent screen must exist too \u2014 docs/Guides/oauth-provision.md \xA7 New repo.`
|
|
24806
|
+
);
|
|
24807
|
+
}
|
|
24808
|
+
return failGraceful(`org oauth plan: ${message}`);
|
|
24739
24809
|
}
|
|
24740
24810
|
const origins = expectedJsOrigins(oc);
|
|
24741
24811
|
const redirects = expectedRedirectUris(oc);
|
|
@@ -25292,8 +25362,10 @@ pr.command("checks-wait <number>").description(`bounded wait for PR checks; skip
|
|
|
25292
25362
|
printLine(`pr checks-wait: timeout \u2014 waited ${Math.round((result.waitedMs ?? 0) / 6e4)}m, last state: ${result.detail ?? "pending"}. No check failed; re-run to keep waiting, or pass --timeout <minutes>.`);
|
|
25293
25363
|
} else if (result.status === "rate-limited") {
|
|
25294
25364
|
printLine(`pr checks-wait: rate-limited \u2014 ${result.reason ?? "REST pool below floor"}. No check failed; re-run after the pool resets.`);
|
|
25295
|
-
} else if (result.detail === "
|
|
25296
|
-
printLine(`pr checks-wait: failure (
|
|
25365
|
+
} else if (result.detail === "runner-infra") {
|
|
25366
|
+
printLine(`pr checks-wait: failure (runner infrastructure, NOT a test failure) \u2014 ${result.reason}`);
|
|
25367
|
+
} else if (result.detail === "stale-head") {
|
|
25368
|
+
printLine(`pr checks-wait: failure (stale PR head, NOT a test failure) \u2014 ${result.reason}`);
|
|
25297
25369
|
} else printLine(`pr checks-wait: ${result.status}${result.reason ? ` \u2014 ${result.reason}` : ""}${result.detail ? ` (${result.detail})` : ""}`);
|
|
25298
25370
|
if (result.status === "failure" || result.status === "conflicting") process.exitCode = 1;
|
|
25299
25371
|
if (result.status === "timeout" || result.status === "rate-limited") process.exitCode = PR_CHECKS_TIMEOUT_EXIT_CODE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.49.0",
|
|
4
4
|
"description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|