@mutmutco/cli 4.5.230 → 4.5.232
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 +105 -245
- package/dist/runbook-sweep.cjs +0 -24
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -1469,8 +1469,8 @@ function commandFromFailMessage(msg) {
|
|
|
1469
1469
|
const head = msg.split(":", 1)[0].trim();
|
|
1470
1470
|
if (!head || head.startsWith("-")) return "mmi-cli";
|
|
1471
1471
|
if (!/^[a-z][a-z0-9-]*(?: [a-z][a-z0-9-]*){0,5}$/.test(head)) return "mmi-cli";
|
|
1472
|
-
const
|
|
1473
|
-
if (
|
|
1472
|
+
const canonical = canonicalPathFor(head);
|
|
1473
|
+
if (canonical) return canonical;
|
|
1474
1474
|
return HOUSE_ROOTS.includes(head.split(" ")[0]) ? head : "mmi-cli";
|
|
1475
1475
|
}
|
|
1476
1476
|
function canonicalFailMessage(msg) {
|
|
@@ -24015,20 +24015,20 @@ function reseedProductRulesetStrictness(current, seed, declared = {}) {
|
|
|
24015
24015
|
}
|
|
24016
24016
|
return { policy: policy2, parameters: parameters2 };
|
|
24017
24017
|
};
|
|
24018
|
-
const
|
|
24019
|
-
const strict =
|
|
24018
|
+
const canonical = parse2(seed);
|
|
24019
|
+
const strict = canonical.parameters.strict_required_status_checks_policy;
|
|
24020
24020
|
if (typeof strict !== "boolean") throw new Error("canonical product ruleset must declare boolean strictness");
|
|
24021
24021
|
if (current === null) return seed;
|
|
24022
24022
|
const { policy, parameters } = parse2(current);
|
|
24023
24023
|
let changed = parameters.strict_required_status_checks_policy !== strict;
|
|
24024
24024
|
parameters.strict_required_status_checks_policy = strict;
|
|
24025
24025
|
if (declared.requiredChecks) {
|
|
24026
|
-
const checks =
|
|
24026
|
+
const checks = canonical.parameters.required_status_checks.map((check) => parameters.required_status_checks.find((old) => old.context === check.context) ?? check);
|
|
24027
24027
|
if (JSON.stringify(parameters.required_status_checks) !== JSON.stringify(checks)) changed = true;
|
|
24028
24028
|
parameters.required_status_checks = checks;
|
|
24029
24029
|
}
|
|
24030
24030
|
if (declared.requiredCheckBranches) {
|
|
24031
|
-
const refs =
|
|
24031
|
+
const refs = canonical.policy.conditions?.ref_name?.include;
|
|
24032
24032
|
if (!Array.isArray(refs) || !refs.length) throw new Error("canonical product ruleset must declare branch includes");
|
|
24033
24033
|
const conditions = policy.conditions;
|
|
24034
24034
|
const refName = conditions?.ref_name;
|
|
@@ -24297,13 +24297,13 @@ function upsertManagedSeedBlock(current, desired, begin, end) {
|
|
|
24297
24297
|
if (desired.slice(0, desiredBegin.start).trim() || desired.slice(desiredEnd.end).trim()) {
|
|
24298
24298
|
return { ok: false, reason: "managed block source must contain only the bounded block" };
|
|
24299
24299
|
}
|
|
24300
|
-
const
|
|
24300
|
+
const canonical = desired.slice(desiredBegin.start, desiredEnd.textEnd);
|
|
24301
24301
|
const currentLines = sourceLines(current);
|
|
24302
24302
|
const begins = currentLines.filter((line) => line.text === begin);
|
|
24303
24303
|
const ends = currentLines.filter((line) => line.text === end);
|
|
24304
24304
|
if (begins.length === 0 && ends.length === 0) {
|
|
24305
24305
|
const eol2 = current.match(/\r\n|\n|\r/)?.[0] ?? "\n";
|
|
24306
|
-
const block2 = normalizeEol(
|
|
24306
|
+
const block2 = normalizeEol(canonical).replace(/\n/g, eol2);
|
|
24307
24307
|
if (current.length === 0) return { ok: true, content: `${block2}${eol2}`, changed: true, action: "insert" };
|
|
24308
24308
|
const separator = /(?:\r\n|\n|\r)$/.test(current) ? eol2 : `${eol2}${eol2}`;
|
|
24309
24309
|
return { ok: true, content: `${current}${separator}${block2}${eol2}`, changed: true, action: "insert" };
|
|
@@ -24317,11 +24317,11 @@ function upsertManagedSeedBlock(current, desired, begin, end) {
|
|
|
24317
24317
|
return { ok: false, reason: "malformed managed block markers (end precedes begin)" };
|
|
24318
24318
|
}
|
|
24319
24319
|
const existing = current.slice(currentBegin.start, currentEnd.textEnd);
|
|
24320
|
-
if (normalizeEol(existing) === normalizeEol(
|
|
24320
|
+
if (normalizeEol(existing) === normalizeEol(canonical)) {
|
|
24321
24321
|
return { ok: true, content: current, changed: false, action: "current" };
|
|
24322
24322
|
}
|
|
24323
24323
|
const eol = current.match(/\r\n|\n|\r/)?.[0] ?? "\n";
|
|
24324
|
-
const block = normalizeEol(
|
|
24324
|
+
const block = normalizeEol(canonical).replace(/\n/g, eol);
|
|
24325
24325
|
return {
|
|
24326
24326
|
ok: true,
|
|
24327
24327
|
content: `${current.slice(0, currentBegin.start)}${block}${current.slice(currentEnd.textEnd)}`,
|
|
@@ -27242,10 +27242,10 @@ var rollout_plan_default = {
|
|
|
27242
27242
|
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)."
|
|
27243
27243
|
},
|
|
27244
27244
|
baseline: {
|
|
27245
|
-
version: "4.5.
|
|
27246
|
-
tag: "v4.5.
|
|
27247
|
-
commit: "
|
|
27248
|
-
npm: "@mutmutco/cli@4.5.
|
|
27245
|
+
version: "4.5.232",
|
|
27246
|
+
tag: "v4.5.232",
|
|
27247
|
+
commit: "cd546199eccb",
|
|
27248
|
+
npm: "@mutmutco/cli@4.5.232"
|
|
27249
27249
|
},
|
|
27250
27250
|
exitCriterion: "fleet-n-of-n",
|
|
27251
27251
|
hubOnlyShortcut: "forbidden",
|
|
@@ -27262,14 +27262,14 @@ var rollout_plan_default = {
|
|
|
27262
27262
|
repo: "mutmutco/mmi-hub",
|
|
27263
27263
|
role: "canary",
|
|
27264
27264
|
schedule: "train",
|
|
27265
|
-
v3Target: "v4.5.
|
|
27265
|
+
v3Target: "v4.5.232"
|
|
27266
27266
|
}
|
|
27267
27267
|
],
|
|
27268
27268
|
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.",
|
|
27269
27269
|
rollback: {
|
|
27270
27270
|
independent: true,
|
|
27271
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
27272
|
-
v3Target: "v4.5.
|
|
27271
|
+
mechanism: "npm dist-tag latest -> 4.5.232 and redeploy the Hub Lambda from tag v4.5.232 (cd546199eccb); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
27272
|
+
v3Target: "v4.5.232 (@mutmutco/cli@4.5.232, tag commit cd546199eccb \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
27273
27273
|
}
|
|
27274
27274
|
},
|
|
27275
27275
|
{
|
|
@@ -28931,15 +28931,15 @@ function planFleetLockstepEnforcement(read, enrollment, stagePlan, statusFinding
|
|
|
28931
28931
|
};
|
|
28932
28932
|
}
|
|
28933
28933
|
async function resolveCanonicalRepoNames(client, repos) {
|
|
28934
|
-
const
|
|
28934
|
+
const canonical = /* @__PURE__ */ new Map();
|
|
28935
28935
|
for (const repo of repos) {
|
|
28936
28936
|
const detail = await client.rest("GET", `repos/${repo}`, { timeoutMs: 2e4 });
|
|
28937
28937
|
if (typeof detail?.name !== "string" || !detail.name) {
|
|
28938
28938
|
throw new Error(`could not resolve the canonical repository name for ${repo} \u2014 refusing to write a ruleset include entry from guessed casing`);
|
|
28939
28939
|
}
|
|
28940
|
-
|
|
28940
|
+
canonical.set(repo.toLowerCase(), detail.name);
|
|
28941
28941
|
}
|
|
28942
|
-
return
|
|
28942
|
+
return canonical;
|
|
28943
28943
|
}
|
|
28944
28944
|
async function writeFleetLockstepRuleset(client, body, liveId, target, org) {
|
|
28945
28945
|
if (liveId == null) {
|
|
@@ -28963,7 +28963,7 @@ async function writeFleetLockstepRuleset(client, body, liveId, target, org) {
|
|
|
28963
28963
|
verified: true
|
|
28964
28964
|
};
|
|
28965
28965
|
}
|
|
28966
|
-
async function applyFleetLockstepStage(client, plan, target,
|
|
28966
|
+
async function applyFleetLockstepStage(client, plan, target, canonical, org = ORG_LOGIN) {
|
|
28967
28967
|
const stage = plan.stages.find((s) => s.stage === target);
|
|
28968
28968
|
if (!stage) throw new Error(`unknown arming stage ${target} \u2014 stages run 1..${plan.totalStages}`);
|
|
28969
28969
|
if (target > plan.armedThroughStage + 1 && plan.state !== "disarmed") {
|
|
@@ -28972,7 +28972,7 @@ async function applyFleetLockstepStage(client, plan, target, canonical2, org = O
|
|
|
28972
28972
|
);
|
|
28973
28973
|
}
|
|
28974
28974
|
const include = stage.cumulativeRepos.map((repo) => {
|
|
28975
|
-
const name =
|
|
28975
|
+
const name = canonical.get(repo.toLowerCase());
|
|
28976
28976
|
if (!name) throw new Error(`no canonical name resolved for ${repo}`);
|
|
28977
28977
|
return name;
|
|
28978
28978
|
});
|
|
@@ -29276,8 +29276,8 @@ function registerFleetLockstepEnforce(program3) {
|
|
|
29276
29276
|
rollback stays available: mmi-cli devops train enforce --apply --disarm`
|
|
29277
29277
|
);
|
|
29278
29278
|
}
|
|
29279
|
-
const
|
|
29280
|
-
const result = await applyFleetLockstepStage(client, plan, target,
|
|
29279
|
+
const canonical = await resolveCanonicalRepoNames(client, plan.stages.find((s) => s.stage === target).cumulativeRepos);
|
|
29280
|
+
const result = await applyFleetLockstepStage(client, plan, target, canonical);
|
|
29281
29281
|
const { plan: after } = await readEnforcementPlan(client);
|
|
29282
29282
|
if (o.json) console.log(JSON.stringify({ result, plan: after }, null, 2));
|
|
29283
29283
|
else {
|
|
@@ -30433,15 +30433,15 @@ function parseRuntimeIdentity(log, expected) {
|
|
|
30433
30433
|
if (proofs.length !== 1) return unavailable("invalid-proof");
|
|
30434
30434
|
const encoded = proofs[0].slice(prefix.length).trim();
|
|
30435
30435
|
if (encoded.length > 16384) return unavailable("invalid-proof");
|
|
30436
|
-
const
|
|
30436
|
+
const object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
30437
30437
|
const keys = (v, allowed) => Object.keys(v).length === allowed.length && Object.keys(v).every((k) => allowed.includes(k));
|
|
30438
30438
|
const text = (v, re) => typeof v === "string" && re.test(v);
|
|
30439
30439
|
try {
|
|
30440
30440
|
const p = JSON.parse(encoded);
|
|
30441
|
-
if (JSON.stringify(p) !== encoded || !
|
|
30441
|
+
if (JSON.stringify(p) !== encoded || !object(p)) return unavailable("invalid-proof");
|
|
30442
30442
|
if (p.version !== 1) return unavailable("unsupported-version");
|
|
30443
30443
|
const parts = expected.repo.split("/");
|
|
30444
|
-
if (parts.length !== 2 || !parts.every(Boolean) || !
|
|
30444
|
+
if (parts.length !== 2 || !parts.every(Boolean) || !object(p.target) || !keys(p.target, ["slug", "stage"]) || p.target.slug !== parts[1].toLowerCase() || p.target.stage !== expected.stage) return unavailable("target-mismatch");
|
|
30445
30445
|
if (p.status === "unavailable") {
|
|
30446
30446
|
if (!keys(p, ["version", "target", "status", "reason"]) || typeof p.reason !== "string" || !["selection-unavailable", "inspection-failed", "snapshot-changed", "output-too-large"].includes(p.reason)) return unavailable("invalid-proof");
|
|
30447
30447
|
return unavailable(p.reason);
|
|
@@ -30449,7 +30449,7 @@ function parseRuntimeIdentity(log, expected) {
|
|
|
30449
30449
|
if (!keys(p, ["version", "target", "status", "slot", "replicas"]) || p.status !== "available" || p.slot !== "blue" && p.slot !== "green" || !Array.isArray(p.replicas) || !p.replicas.length) return unavailable("invalid-proof");
|
|
30450
30450
|
const seen = /* @__PURE__ */ new Set();
|
|
30451
30451
|
for (const r of p.replicas) {
|
|
30452
|
-
if (!
|
|
30452
|
+
if (!object(r) || !keys(r, ["service", "container", "configuredRef", "actualImageID", "repoDigests", "health", "state"]) || !text(r.service, /^[A-Za-z0-9][A-Za-z0-9_-]*$/) || !text(r.container, /^[a-f0-9]{64}$/) || !text(r.configuredRef, /^[A-Za-z0-9][A-Za-z0-9._/@:-]*$/) || !text(r.actualImageID, /^sha256:[a-f0-9]{64}$/) || !Array.isArray(r.repoDigests) || !r.repoDigests.every((d) => text(d, /^[A-Za-z0-9][A-Za-z0-9._/:-]*@sha256:[a-f0-9]{64}$/)) || (typeof r.health !== "string" || !["healthy", "unhealthy", "starting", "not-configured", "unknown"].includes(r.health)) || r.state !== "running" || seen.has(r.container)) return unavailable("invalid-proof");
|
|
30453
30453
|
seen.add(r.container);
|
|
30454
30454
|
}
|
|
30455
30455
|
return p;
|
|
@@ -31932,114 +31932,6 @@ function parseRunnerJobs(source) {
|
|
|
31932
31932
|
return void 0;
|
|
31933
31933
|
}
|
|
31934
31934
|
}
|
|
31935
|
-
function parseRunnerWorkflowContract(source) {
|
|
31936
|
-
if (!source || source.length > 15e5) return void 0;
|
|
31937
|
-
try {
|
|
31938
|
-
const doc = (0, import_yaml.parseDocument)(source, { uniqueKeys: true, stringKeys: true, merge: false, prettyErrors: false });
|
|
31939
|
-
if (doc.errors.length || doc.warnings.length || !literalMap(doc.contents)) return void 0;
|
|
31940
|
-
let invalid = false, nodes = 0;
|
|
31941
|
-
(0, import_yaml.visit)(doc, (_key, node, path2) => {
|
|
31942
|
-
if (++nodes > 1e5 || path2.length > 64 || !literal(node) || (0, import_yaml.isPair)(node) && (0, import_yaml.isScalar)(node.key) && node.key.value === "<<") {
|
|
31943
|
-
invalid = true;
|
|
31944
|
-
return import_yaml.visit.BREAK;
|
|
31945
|
-
}
|
|
31946
|
-
});
|
|
31947
|
-
return invalid ? void 0 : doc.toJS({ maxAliasCount: 0 });
|
|
31948
|
-
} catch {
|
|
31949
|
-
return void 0;
|
|
31950
|
-
}
|
|
31951
|
-
}
|
|
31952
|
-
|
|
31953
|
-
// ../shared/ci-allowance-contract.ts
|
|
31954
|
-
var import_node_crypto9 = require("node:crypto");
|
|
31955
|
-
var CLI_ALLOWANCE_MANIFEST = Object.freeze({
|
|
31956
|
-
id: "hub-cli-v1",
|
|
31957
|
-
parts: ["tests-1", "tests-2", "checks"],
|
|
31958
|
-
// Includes checkout, toolchain, installation and teardown, not just the test subprocess.
|
|
31959
|
-
jobMinutes: 10,
|
|
31960
|
-
aggregateMinutes: 1,
|
|
31961
|
-
maxAttempts: 3,
|
|
31962
|
-
storageBytes: 0
|
|
31963
|
-
});
|
|
31964
|
-
var CLI_ATTEMPT_MINUTES = CLI_ALLOWANCE_MANIFEST.parts.length * CLI_ALLOWANCE_MANIFEST.jobMinutes + CLI_ALLOWANCE_MANIFEST.aggregateMinutes;
|
|
31965
|
-
var CI_PROFILES = Object.freeze({
|
|
31966
|
-
"included-linux": "ubuntu-latest",
|
|
31967
|
-
"owned-linux": ["self-hosted", "linux", "x64", "mmi-live"]
|
|
31968
|
-
});
|
|
31969
|
-
var CLI_ADMISSION_IF = "${{ always() && !cancelled() && needs.cli-admission.result == 'success' && needs.cli-admission.outputs.admitted == 'true' && needs.cli-admission.outputs.attempt == format('{0}', github.run_attempt) && needs.cli-admission.outputs.candidate == github.sha && (needs.cli-admission.outputs.profile == 'included-linux' || needs.cli-admission.outputs.profile == 'owned-linux') }}";
|
|
31970
|
-
var CLI_ADMISSION_RUNNER = `\${{ needs.cli-admission.outputs.profile == 'included-linux' && 'ubuntu-latest' || fromJSON('["self-hosted","linux","x64","mmi-live"]') }}`;
|
|
31971
|
-
var CLI_AGGREGATE_SCRIPT = `test "$ADMISSION_RESULT" = success
|
|
31972
|
-
test "$ADMITTED" = true
|
|
31973
|
-
test "$ADMITTED_ATTEMPT" = "$CURRENT_ATTEMPT"
|
|
31974
|
-
test "$ADMITTED_CANDIDATE" = "$CURRENT_CANDIDATE"
|
|
31975
|
-
test "$PART_RESULT" = success`;
|
|
31976
|
-
var aggregateEnv = {
|
|
31977
|
-
ADMISSION_RESULT: "${{ needs.cli-admission.result }}",
|
|
31978
|
-
ADMITTED: "${{ needs.cli-admission.outputs.admitted }}",
|
|
31979
|
-
ADMITTED_ATTEMPT: "${{ needs.cli-admission.outputs.attempt }}",
|
|
31980
|
-
CURRENT_ATTEMPT: "${{ github.run_attempt }}",
|
|
31981
|
-
ADMITTED_CANDIDATE: "${{ needs.cli-admission.outputs.candidate }}",
|
|
31982
|
-
CURRENT_CANDIDATE: "${{ github.sha }}",
|
|
31983
|
-
PART_RESULT: "${{ needs.cli-part.result }}"
|
|
31984
|
-
};
|
|
31985
|
-
function object(value) {
|
|
31986
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
31987
|
-
}
|
|
31988
|
-
function equal(a, b) {
|
|
31989
|
-
return canonical(a) === canonical(b);
|
|
31990
|
-
}
|
|
31991
|
-
function canonical(value) {
|
|
31992
|
-
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
31993
|
-
if (object(value)) return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${canonical(value[k])}`).join(",")}}`;
|
|
31994
|
-
return JSON.stringify(value);
|
|
31995
|
-
}
|
|
31996
|
-
function cliAdmissionJobs(coordinatorSha) {
|
|
31997
|
-
if (!/^[a-f0-9]{40}$/.test(coordinatorSha)) throw new Error("immutable coordinator SHA required");
|
|
31998
|
-
return {
|
|
31999
|
-
"cli-admission": { uses: `mutmutco/MMI-Hub/.github/workflows/ci-allowance.yml@${coordinatorSha}`, permissions: { "id-token": "write" } },
|
|
32000
|
-
// Merge these keys into the EXISTING cli-part; retain every test/build step.
|
|
32001
|
-
"cli-part": { needs: ["cli-admission"], if: CLI_ADMISSION_IF, "runs-on": CLI_ADMISSION_RUNNER, "timeout-minutes": CLI_ALLOWANCE_MANIFEST.jobMinutes },
|
|
32002
|
-
cli: {
|
|
32003
|
-
needs: ["cli-admission", "cli-part"],
|
|
32004
|
-
if: "${{ always() && !cancelled() }}",
|
|
32005
|
-
"runs-on": CI_PROFILES["owned-linux"],
|
|
32006
|
-
"timeout-minutes": 1,
|
|
32007
|
-
permissions: {},
|
|
32008
|
-
steps: [{ name: "Require fresh admission and every CLI part", shell: "bash", env: aggregateEnv, run: CLI_AGGREGATE_SCRIPT }]
|
|
32009
|
-
}
|
|
32010
|
-
};
|
|
32011
|
-
}
|
|
32012
|
-
function verifyCliAdmissionContract(workflow, coordinatorSha) {
|
|
32013
|
-
if (!object(workflow) || !object(workflow.jobs)) return null;
|
|
32014
|
-
if (!equal(workflow.permissions, { contents: "read", "pull-requests": "read" })) return null;
|
|
32015
|
-
const expected = cliAdmissionJobs(coordinatorSha);
|
|
32016
|
-
const admission = workflow.jobs["cli-admission"], part = workflow.jobs["cli-part"], aggregate = workflow.jobs.cli;
|
|
32017
|
-
if (!equal(admission, expected["cli-admission"]) || !equal(aggregate, expected.cli) || !object(part)) return null;
|
|
32018
|
-
if (!Object.entries(expected["cli-part"]).every(([key, value]) => equal(part[key], value))) return null;
|
|
32019
|
-
if (!object(part.strategy) || part.strategy["fail-fast"] !== false || !object(part.strategy.matrix) || !equal(part.strategy.matrix, { part: [...CLI_ALLOWANCE_MANIFEST.parts] }) || part["continue-on-error"]) return null;
|
|
32020
|
-
if (!Array.isArray(part.steps) || !part.steps.every(object)) return null;
|
|
32021
|
-
const toolchains = part.steps.filter((step) => step.uses === "./.github/actions/runner-node-toolchain");
|
|
32022
|
-
if (toolchains.length !== 1 || !object(toolchains[0].with) || toolchains[0].with["package-manager-cache"] !== "false" || toolchains[0].with.cache !== "") return null;
|
|
32023
|
-
if (part.steps.some((step) => typeof step.uses === "string" && /(?:upload-artifact|actions\/cache)/.test(step.uses))) return null;
|
|
32024
|
-
return (0, import_node_crypto9.createHash)("sha256").update(canonical(workflow)).digest("hex");
|
|
32025
|
-
}
|
|
32026
|
-
var CLI_ALLOWANCE_SOURCE = Object.freeze({
|
|
32027
|
-
repository: "mutmutco/MMI-Hub",
|
|
32028
|
-
callerPath: ".github/workflows/gate.yml",
|
|
32029
|
-
coordinatorPath: ".github/workflows/ci-allowance.yml",
|
|
32030
|
-
coordinatorSha: "50f0bd4d8e35f3f09119bd3fa1bb7705fcc6f09b",
|
|
32031
|
-
coordinatorSha256: "7b23f22131c5e08292f142eeed3899c8ecf49b1bdcc96bfdfe114cf1dca47b48",
|
|
32032
|
-
executionSha256: "6198e0896a5533f9546e084642ceb214336c930561fe9f8292eb7e6a0972933b"
|
|
32033
|
-
});
|
|
32034
|
-
function verifyCliAdmissionSourceContract(workflow, coordinator) {
|
|
32035
|
-
const source = CLI_ALLOWANCE_SOURCE;
|
|
32036
|
-
if (coordinator.repo !== source.repository || coordinator.path !== source.coordinatorPath || coordinator.ref !== source.coordinatorSha || (0, import_node_crypto9.createHash)("sha256").update(coordinator.body).digest("hex") !== source.coordinatorSha256) return null;
|
|
32037
|
-
const digest = verifyCliAdmissionContract(workflow, source.coordinatorSha);
|
|
32038
|
-
if (!digest) return null;
|
|
32039
|
-
const { jobs, ...context } = workflow;
|
|
32040
|
-
const execution = { ...context, jobs: { "cli-admission": jobs["cli-admission"], "cli-part": jobs["cli-part"], cli: jobs.cli } };
|
|
32041
|
-
return (0, import_node_crypto9.createHash)("sha256").update(canonical(execution)).digest("hex") === source.executionSha256 ? digest : null;
|
|
32042
|
-
}
|
|
32043
31935
|
|
|
32044
31936
|
// src/workflow-runner-source.ts
|
|
32045
31937
|
var WORKFLOW_PATH = /^\.github\/workflows\/[\w.-]+\.ya?ml$/;
|
|
@@ -32161,15 +32053,12 @@ function classifyRunnerWorkflows(files) {
|
|
|
32161
32053
|
return files.flatMap((file) => {
|
|
32162
32054
|
const jobs = parsed.get(locationOf(file));
|
|
32163
32055
|
if (!jobs) return [{ repo: file.repo, path: file.path, job: "(invalid YAML)", cost: "unknown", callee: false }];
|
|
32164
|
-
const source = CLI_ALLOWANCE_SOURCE;
|
|
32165
|
-
const coordinator = known.get(locationOf({ repo: source.repository, path: source.coordinatorPath, ref: source.coordinatorSha }));
|
|
32166
|
-
const allowance2 = file.repo === source.repository && file.path === source.callerPath && coordinator && resolved(file, /* @__PURE__ */ new Set()) && verifyCliAdmissionSourceContract(parseRunnerWorkflowContract(file.body), coordinator) !== null;
|
|
32167
32056
|
return [...jobs].flatMap(([id, job]) => {
|
|
32168
32057
|
const hasCallee = Object.hasOwn(job, "uses");
|
|
32169
32058
|
const uses = hasCallee && typeof job.uses === "string" && !Object.hasOwn(job, "runs-on") ? job.uses : void 0;
|
|
32170
32059
|
const target = uses && resolveCallee(file, uses);
|
|
32171
32060
|
if (target && known.has(locationOf(target)) && resolved(file, /* @__PURE__ */ new Set())) return [];
|
|
32172
|
-
const cost = hasCallee ? "unknown" :
|
|
32061
|
+
const cost = hasCallee ? "unknown" : classifyJobRunnerCost(job, standardHostedLabelFor(file.repo, file.path, id));
|
|
32173
32062
|
return [{ repo: file.repo, path: file.path, job: id, cost, callee: hasCallee }];
|
|
32174
32063
|
});
|
|
32175
32064
|
});
|
|
@@ -33129,7 +33018,7 @@ function checkLineEndings(probe) {
|
|
|
33129
33018
|
// src/release-ledger.ts
|
|
33130
33019
|
var import_node_fs28 = require("node:fs");
|
|
33131
33020
|
var import_node_path26 = require("node:path");
|
|
33132
|
-
var
|
|
33021
|
+
var import_node_crypto9 = require("node:crypto");
|
|
33133
33022
|
|
|
33134
33023
|
// src/file-lock.ts
|
|
33135
33024
|
var import_promises2 = require("node:fs/promises");
|
|
@@ -33491,7 +33380,7 @@ function releaseLedgerPath(cwd) {
|
|
|
33491
33380
|
}
|
|
33492
33381
|
function atomicWriteJson(path2, ledger) {
|
|
33493
33382
|
(0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(path2), { recursive: true });
|
|
33494
|
-
const tmp = `${path2}.tmp-${process.pid}-${(0,
|
|
33383
|
+
const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto9.randomBytes)(4).toString("hex")}`;
|
|
33495
33384
|
(0, import_node_fs28.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
|
|
33496
33385
|
`, "utf8");
|
|
33497
33386
|
(0, import_node_fs28.renameSync)(tmp, path2);
|
|
@@ -40257,14 +40146,14 @@ function buildCommand(cmd, flatPath) {
|
|
|
40257
40146
|
);
|
|
40258
40147
|
}
|
|
40259
40148
|
const aliases = cmd.aliases();
|
|
40260
|
-
const
|
|
40149
|
+
const canonical = canonicalPathFor(flatPath) ?? flatPath;
|
|
40261
40150
|
const out = {
|
|
40262
40151
|
name: cmd.name(),
|
|
40263
|
-
path:
|
|
40152
|
+
path: canonical,
|
|
40264
40153
|
flat_path: flatPath,
|
|
40265
40154
|
...aliases.length ? { aliases: [...aliases] } : {},
|
|
40266
40155
|
house,
|
|
40267
|
-
canonical
|
|
40156
|
+
canonical,
|
|
40268
40157
|
arguments: cmd.registeredArguments.map(buildArgument),
|
|
40269
40158
|
// A hand-parsed command registers no Commander options, so its declared set is merged in (#3682).
|
|
40270
40159
|
options: [...cmd.options.map(buildOption), ...readDeclaredOptions(cmd)],
|
|
@@ -40436,8 +40325,8 @@ function findCommandByPath(root, path2) {
|
|
|
40436
40325
|
function buildDoorsCatalog(tree) {
|
|
40437
40326
|
return DOOR_DECLARATIONS.map((decl) => {
|
|
40438
40327
|
const house = houseForPath(decl.path);
|
|
40439
|
-
const
|
|
40440
|
-
if (!house || !
|
|
40328
|
+
const canonical = canonicalPathFor(decl.path);
|
|
40329
|
+
if (!house || !canonical) {
|
|
40441
40330
|
throw new Error(
|
|
40442
40331
|
`command-manifest: doors catalog entry '${decl.door}' names path '${decl.path}' with no house assignment \u2014 fix DOOR_DECLARATIONS or cli/src/house-map.ts.`
|
|
40443
40332
|
);
|
|
@@ -40447,7 +40336,7 @@ function buildDoorsCatalog(tree) {
|
|
|
40447
40336
|
question: decl.question,
|
|
40448
40337
|
house,
|
|
40449
40338
|
command: decl.path,
|
|
40450
|
-
canonical
|
|
40339
|
+
canonical,
|
|
40451
40340
|
source: decl.source,
|
|
40452
40341
|
live: Boolean(findCommandByPath(tree, decl.path))
|
|
40453
40342
|
};
|
|
@@ -41270,8 +41159,8 @@ function registerBoardCommands(program3) {
|
|
|
41270
41159
|
}
|
|
41271
41160
|
});
|
|
41272
41161
|
function resolveBoardStatus(status) {
|
|
41273
|
-
const
|
|
41274
|
-
if (
|
|
41162
|
+
const canonical = canonicalizeBoardStatus(status);
|
|
41163
|
+
if (canonical) return canonical;
|
|
41275
41164
|
fail(`board move failed: unknown status '${status}'; expected one of ${BOARD_STATUSES.join(", ")}`, {
|
|
41276
41165
|
code: ERROR_CODES.ERR_BAD_ENUM,
|
|
41277
41166
|
expected: [...BOARD_STATUSES]
|
|
@@ -41731,7 +41620,7 @@ var import_node_os18 = require("node:os");
|
|
|
41731
41620
|
var import_node_path31 = require("node:path");
|
|
41732
41621
|
|
|
41733
41622
|
// src/box-control.ts
|
|
41734
|
-
var
|
|
41623
|
+
var import_node_crypto10 = require("node:crypto");
|
|
41735
41624
|
var MANIFEST_PATH = "infra/box-control/manifest.json";
|
|
41736
41625
|
var ALLOWED_POST = /* @__PURE__ */ new Set(["systemctl daemon-reload"]);
|
|
41737
41626
|
var sshdPost = (dest) => `if sshd -t; then systemctl reload ssh; else rm -f ${dest}; echo 'sshd -t rejected ${dest}: removed, not reloaded' >&2; exit 1; fi`;
|
|
@@ -41835,7 +41724,7 @@ function laneCoverageAction(files, box, op) {
|
|
|
41835
41724
|
return { notice: `LANE_COVERAGE: ${mismatch}` };
|
|
41836
41725
|
}
|
|
41837
41726
|
function md5(content) {
|
|
41838
|
-
return (0,
|
|
41727
|
+
return (0, import_node_crypto10.createHash)("md5").update(content).digest("hex");
|
|
41839
41728
|
}
|
|
41840
41729
|
function planRemoteScript(dests) {
|
|
41841
41730
|
const lines2 = ["set -u"];
|
|
@@ -42614,18 +42503,18 @@ function secretRemovalRefusal(existing, patch) {
|
|
|
42614
42503
|
return `org project set: --unset-secret ${mapKey} is not declared in ${existing?.slug ?? "this project"}'s secrets catalog \u2014 nothing to remove`;
|
|
42615
42504
|
}
|
|
42616
42505
|
const at = mapKey.indexOf("@");
|
|
42617
|
-
const
|
|
42506
|
+
const canonical = at === -1 ? mapKey : mapKey.slice(0, at);
|
|
42618
42507
|
for (const [stage, names] of Object.entries(runtime)) {
|
|
42619
|
-
if (Array.isArray(names) && names.includes(
|
|
42620
|
-
return `org project set: ${
|
|
42508
|
+
if (Array.isArray(names) && names.includes(canonical)) {
|
|
42509
|
+
return `org project set: ${canonical} is still required by stage ${stage} \u2014 drop it there first (--var requiredRuntimeSecrets=...)`;
|
|
42621
42510
|
}
|
|
42622
42511
|
}
|
|
42623
42512
|
for (const raw of build) {
|
|
42624
42513
|
if (typeof raw !== "string") continue;
|
|
42625
42514
|
const eq = raw.indexOf("=");
|
|
42626
42515
|
const ref = eq === -1 ? raw : raw.slice(eq + 1);
|
|
42627
|
-
if (ref ===
|
|
42628
|
-
return `org project set: ${
|
|
42516
|
+
if (ref === canonical) {
|
|
42517
|
+
return `org project set: ${canonical} is still required by the build secret contract \u2014 drop it there first (--var requiredBuildSecrets=...)`;
|
|
42629
42518
|
}
|
|
42630
42519
|
}
|
|
42631
42520
|
}
|
|
@@ -43933,7 +43822,7 @@ function renderDeployPortDoctor(report) {
|
|
|
43933
43822
|
}
|
|
43934
43823
|
|
|
43935
43824
|
// src/bootstrap-drift.ts
|
|
43936
|
-
var
|
|
43825
|
+
var import_node_crypto11 = require("node:crypto");
|
|
43937
43826
|
function byteComparableSeeds(manifest, cls) {
|
|
43938
43827
|
return manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self" && s.classes.includes(cls));
|
|
43939
43828
|
}
|
|
@@ -43953,7 +43842,7 @@ function compareSeedBytes(hubContent, repoContent) {
|
|
|
43953
43842
|
return normalize(hubContent) === normalize(repoContent) ? "match" : "drift";
|
|
43954
43843
|
}
|
|
43955
43844
|
function seedContentHash(content) {
|
|
43956
|
-
return (0,
|
|
43845
|
+
return (0, import_node_crypto11.createHash)("sha256").update(content.replace(/\r\n/g, "\n"), "utf8").digest("hex");
|
|
43957
43846
|
}
|
|
43958
43847
|
function auditRepoSeedDrift(repo, seeds, hubContents, repoReads) {
|
|
43959
43848
|
const byTarget = new Map(repoReads.map((r) => [r.target, r.content]));
|
|
@@ -44130,7 +44019,7 @@ function renderPropagationReport(plan) {
|
|
|
44130
44019
|
}
|
|
44131
44020
|
|
|
44132
44021
|
// src/bootstrap-propagation-identity.ts
|
|
44133
|
-
var
|
|
44022
|
+
var import_node_crypto12 = require("node:crypto");
|
|
44134
44023
|
var PROPAGATION_BRANCH_PREFIX = "seed-propagate-";
|
|
44135
44024
|
var TARGET_MARKER_NAME = "mmi-bootstrap-propagation-target";
|
|
44136
44025
|
function safeBranchPart(value, maxLength, fallback) {
|
|
@@ -44143,7 +44032,7 @@ function repoSlug2(repo) {
|
|
|
44143
44032
|
function propagationBranch(repo, target) {
|
|
44144
44033
|
const repoPart = safeBranchPart(repoSlug2(repo), 32, "repo");
|
|
44145
44034
|
const targetPart = safeBranchPart(target, 48, "target");
|
|
44146
|
-
const hash = (0,
|
|
44035
|
+
const hash = (0, import_node_crypto12.createHash)("sha256").update(repo.trim().toLowerCase()).update("\0").update(target).digest("hex").slice(0, 12);
|
|
44147
44036
|
return `${PROPAGATION_BRANCH_PREFIX}${repoPart}-${targetPart}-${hash}`;
|
|
44148
44037
|
}
|
|
44149
44038
|
function legacyPropagationBranch(repo) {
|
|
@@ -44663,11 +44552,11 @@ function boardGroupingDrift(board, wantColumn, wantSwimlane) {
|
|
|
44663
44552
|
}
|
|
44664
44553
|
return problems;
|
|
44665
44554
|
}
|
|
44666
|
-
function boardCardFieldDrift(visibleFields,
|
|
44555
|
+
function boardCardFieldDrift(visibleFields, canonical) {
|
|
44667
44556
|
const have = new Set(visibleFields);
|
|
44668
|
-
const want = new Set(
|
|
44557
|
+
const want = new Set(canonical);
|
|
44669
44558
|
return {
|
|
44670
|
-
missing:
|
|
44559
|
+
missing: canonical.filter((f) => !have.has(f)),
|
|
44671
44560
|
extra: visibleFields.filter((f) => !want.has(f))
|
|
44672
44561
|
};
|
|
44673
44562
|
}
|
|
@@ -45385,7 +45274,7 @@ function renderBootstrapVerifyReport(report) {
|
|
|
45385
45274
|
}
|
|
45386
45275
|
|
|
45387
45276
|
// src/bootstrap-seed-delivery.ts
|
|
45388
|
-
var
|
|
45277
|
+
var import_node_crypto13 = require("node:crypto");
|
|
45389
45278
|
init_github_client();
|
|
45390
45279
|
var SHA = /^[a-f0-9]{40}$/;
|
|
45391
45280
|
async function readSeedFile(repo, target, ref, client) {
|
|
@@ -45418,7 +45307,7 @@ async function targetedSeedPlan(repo, slug, target, baseBranch, sourceSha, clien
|
|
|
45418
45307
|
}
|
|
45419
45308
|
const baseSha = base?.object?.sha;
|
|
45420
45309
|
if (!baseSha || !SHA.test(baseSha) || !SHA.test(sourceSha)) throw new Error("bootstrap apply: seed identity is unreadable");
|
|
45421
|
-
const identity = (0,
|
|
45310
|
+
const identity = (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify([repo.toLowerCase(), target, baseSha, sourceSha])).digest("hex").slice(0, 24);
|
|
45422
45311
|
const delivery = planSeedDelivery(rules, slug, baseBranch, `bootstrap-seed-${identity}`);
|
|
45423
45312
|
const scoped = forcePr && delivery.mode === "direct" ? { mode: "pr", ref: `bootstrap-seed-${identity}-${slug}`, branch: `bootstrap-seed-${identity}-${slug}`, reason: "registry gate render requires review" } : delivery;
|
|
45424
45313
|
return { ...scoped, baseSha, baseBranch };
|
|
@@ -47263,7 +47152,7 @@ init_github_client();
|
|
|
47263
47152
|
init_cli_shared();
|
|
47264
47153
|
|
|
47265
47154
|
// src/suite-status.ts
|
|
47266
|
-
var
|
|
47155
|
+
var import_node_crypto14 = require("node:crypto");
|
|
47267
47156
|
var SUITE_REPO = "mutmutco/MM-Work";
|
|
47268
47157
|
var REPOS = {
|
|
47269
47158
|
"mmi-scout": "mutmutco/MMI-Scout",
|
|
@@ -47291,7 +47180,7 @@ function parseSuiteMapping(body) {
|
|
|
47291
47180
|
return void 0;
|
|
47292
47181
|
}
|
|
47293
47182
|
}
|
|
47294
|
-
var sha256 = (b) => (0,
|
|
47183
|
+
var sha256 = (b) => (0, import_node_crypto14.createHash)("sha256").update(b).digest("hex");
|
|
47295
47184
|
async function proveBundle(url, tag, fetchUrl) {
|
|
47296
47185
|
const get = async (u) => {
|
|
47297
47186
|
try {
|
|
@@ -47548,7 +47437,7 @@ async function waitSuiteDev(deps, opts) {
|
|
|
47548
47437
|
// src/suite-train.ts
|
|
47549
47438
|
var import_node_fs36 = require("node:fs");
|
|
47550
47439
|
var import_node_path33 = require("node:path");
|
|
47551
|
-
var
|
|
47440
|
+
var import_node_crypto15 = require("node:crypto");
|
|
47552
47441
|
|
|
47553
47442
|
// src/kit-version.ts
|
|
47554
47443
|
var parse = (v) => /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(typeof v === "string" ? v.trim() : "");
|
|
@@ -47650,7 +47539,7 @@ function readSuiteCut(path2) {
|
|
|
47650
47539
|
}
|
|
47651
47540
|
function writeSuiteCut(path2, record2) {
|
|
47652
47541
|
(0, import_node_fs36.mkdirSync)((0, import_node_path33.dirname)(path2), { recursive: true });
|
|
47653
|
-
const temp = `${path2}.${(0,
|
|
47542
|
+
const temp = `${path2}.${(0, import_node_crypto15.randomBytes)(8).toString("hex")}.tmp`;
|
|
47654
47543
|
try {
|
|
47655
47544
|
(0, import_node_fs36.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
|
|
47656
47545
|
(0, import_node_fs36.renameSync)(temp, path2);
|
|
@@ -51895,7 +51784,7 @@ async function deleteMergedRemoteBranch(options) {
|
|
|
51895
51784
|
}
|
|
51896
51785
|
|
|
51897
51786
|
// src/pr-merge-queue.ts
|
|
51898
|
-
var
|
|
51787
|
+
var import_node_crypto16 = require("node:crypto");
|
|
51899
51788
|
var import_node_fs39 = require("node:fs");
|
|
51900
51789
|
var import_node_os21 = require("node:os");
|
|
51901
51790
|
var import_node_path36 = require("node:path");
|
|
@@ -51920,12 +51809,17 @@ async function queueGraphql(repo, fields, gh2) {
|
|
|
51920
51809
|
if (!response.data?.repository) throw new Error("merge queue repository read failed");
|
|
51921
51810
|
return response.data.repository;
|
|
51922
51811
|
}
|
|
51812
|
+
async function readArrayPages(endpoint, gh2, error) {
|
|
51813
|
+
const pages = parseNdjsonLines(await gh2([endpoint, "--paginate", "--jq", "{items: .}"]));
|
|
51814
|
+
if (!pages.length || !pages.every((page) => Array.isArray(page?.items))) throw new Error(error);
|
|
51815
|
+
return pages.flatMap((page) => page.items);
|
|
51816
|
+
}
|
|
51923
51817
|
async function hasPrMergeQueue(repo, base, gh2 = readApi) {
|
|
51924
|
-
const
|
|
51925
|
-
if (!
|
|
51818
|
+
const rules = await readArrayPages(`repos/${repo}/rules/branches/${encodeURIComponent(base)}?per_page=100`, gh2, `merge queue policy unreadable for ${repo}:${base}`);
|
|
51819
|
+
if (!rules.every((rule) => typeof rule?.type === "string")) {
|
|
51926
51820
|
throw new Error(`merge queue policy unreadable for ${repo}:${base}`);
|
|
51927
51821
|
}
|
|
51928
|
-
if (
|
|
51822
|
+
if (rules.some((rule) => rule.type === "merge_queue")) return true;
|
|
51929
51823
|
const result = await queueGraphql(repo, `mergeQueue(branch:${JSON.stringify(base)}) { id }`, gh2 === readApi ? actorReadApi : gh2);
|
|
51930
51824
|
if (result.mergeQueue === void 0) throw new Error(`merge queue policy unreadable for ${repo}:${base}`);
|
|
51931
51825
|
return result.mergeQueue !== null;
|
|
@@ -51935,7 +51829,7 @@ var ASYNC_HEADERS = ["-H", "Accept: application/vnd.github+json", "-H", "X-GitHu
|
|
|
51935
51829
|
var UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
51936
51830
|
function admissionJournal(repo, pr, root) {
|
|
51937
51831
|
const stateRoot = root ?? (process.platform === "win32" ? (0, import_node_path36.join)(process.env.LOCALAPPDATA || (0, import_node_path36.join)((0, import_node_os21.homedir)(), "AppData", "Local"), "MMI Future", "mmi-cli", "queue-admissions") : (0, import_node_path36.join)(process.env.XDG_STATE_HOME || (0, import_node_path36.join)((0, import_node_os21.homedir)(), ".local", "state"), "mmi-cli", "queue-admissions"));
|
|
51938
|
-
const directory = (0, import_node_path36.join)(stateRoot, (0,
|
|
51832
|
+
const directory = (0, import_node_path36.join)(stateRoot, (0, import_node_crypto16.createHash)("sha256").update(`${repo.toLowerCase()}#${pr}`).digest("hex"));
|
|
51939
51833
|
(0, import_node_fs39.mkdirSync)(directory, { recursive: true, mode: 448 });
|
|
51940
51834
|
const attempts = (0, import_node_fs39.readdirSync)(directory).map((name) => {
|
|
51941
51835
|
if (!/^[1-9][0-9]*\.jsonl$/.test(name)) throw new Error("queue admission receipt directory contains an unrecognized record");
|
|
@@ -51965,7 +51859,7 @@ function admissionJournal(repo, pr, root) {
|
|
|
51965
51859
|
receipt: attempt ? load() : void 0,
|
|
51966
51860
|
create(head) {
|
|
51967
51861
|
const createdAt = Date.now();
|
|
51968
|
-
const initial = { version: 1, repo: repo.toLowerCase(), pr, head, intentId: (0,
|
|
51862
|
+
const initial = { version: 1, repo: repo.toLowerCase(), pr, head, intentId: (0, import_node_crypto16.randomUUID)(), createdAt, observedAt: createdAt, state: "dispatching" };
|
|
51969
51863
|
try {
|
|
51970
51864
|
(0, import_node_fs39.writeFileSync)(path2(attempt + 1), JSON.stringify(initial) + "\n", { flag: "wx", mode: 384, flush: true });
|
|
51971
51865
|
} catch (error) {
|
|
@@ -52168,11 +52062,10 @@ async function enqueuePrMergeQueue(pr, repo, options = {}) {
|
|
|
52168
52062
|
merge_commit_title: metadata.mergeCommitTitle,
|
|
52169
52063
|
merge_commit_message: metadata.mergeCommitMessage
|
|
52170
52064
|
};
|
|
52171
|
-
const
|
|
52172
|
-
if (!
|
|
52065
|
+
const commits = await readArrayPages(`repos/${repo}/pulls/${pr}/commits?per_page=100`, read, `queue commit messages unreadable for PR #${pr}`);
|
|
52066
|
+
if (!commits.every((row) => typeof row?.commit?.message === "string")) {
|
|
52173
52067
|
throw new Error(`queue commit messages unreadable for PR #${pr}`);
|
|
52174
52068
|
}
|
|
52175
|
-
const commits = commitsPages.flat();
|
|
52176
52069
|
if (!commits.length || commits.length !== pull.commits?.totalCount) throw new Error(`queue commit messages incomplete for PR #${pr}; no submission occurred`);
|
|
52177
52070
|
const parsed = parseRestClosingGuardInput({ state: pull.state, title: pull.title, body: pull.body }, commits, repo);
|
|
52178
52071
|
parsed.closing = closing;
|
|
@@ -52187,11 +52080,11 @@ async function enqueuePrMergeQueue(pr, repo, options = {}) {
|
|
|
52187
52080
|
},
|
|
52188
52081
|
error: `queue preparation needed: ${detail}`
|
|
52189
52082
|
});
|
|
52190
|
-
const
|
|
52191
|
-
if (!
|
|
52083
|
+
const rules = await readArrayPages(`repos/${repo}/rules/branches/${encodeURIComponent(pull.baseRefName)}?per_page=100`, read, "queue merge method unreadable");
|
|
52084
|
+
if (!rules.every((rule) => typeof rule?.type === "string")) {
|
|
52192
52085
|
throw new Error("queue merge method unreadable");
|
|
52193
52086
|
}
|
|
52194
|
-
const methods = [...new Set(
|
|
52087
|
+
const methods = [...new Set(rules.filter((rule) => rule.type === "merge_queue").map((rule) => rule.parameters?.merge_method))];
|
|
52195
52088
|
let method = methods.length === 1 ? methods[0] : void 0;
|
|
52196
52089
|
if (!methods.length) {
|
|
52197
52090
|
const legacy = await queueGraphql(
|
|
@@ -52315,7 +52208,7 @@ function hubReleaseCiRun(env) {
|
|
|
52315
52208
|
}
|
|
52316
52209
|
|
|
52317
52210
|
// src/release-custody.ts
|
|
52318
|
-
var
|
|
52211
|
+
var import_node_crypto17 = require("node:crypto");
|
|
52319
52212
|
var import_node_fs40 = require("node:fs");
|
|
52320
52213
|
var import_node_path37 = require("node:path");
|
|
52321
52214
|
init_github_client();
|
|
@@ -52538,7 +52431,7 @@ var ReleaseCustodyError = class extends Error {
|
|
|
52538
52431
|
this.name = "ReleaseCustodyError";
|
|
52539
52432
|
}
|
|
52540
52433
|
};
|
|
52541
|
-
var custodyDigest = (value) => (0,
|
|
52434
|
+
var custodyDigest = (value) => (0, import_node_crypto17.createHash)("sha256").update(value).digest("hex");
|
|
52542
52435
|
function parseCustody(raw, repo) {
|
|
52543
52436
|
const s = JSON.parse(raw);
|
|
52544
52437
|
if (s.schema !== "mmi-release-custody/v1" || s.repo !== repo || !s.precutId || !Number.isSafeInteger(s.revision) || s.revision < 1 || !s.controller || !Number.isSafeInteger(s.controller.runId) || s.controller.runId <= 0 || !Number.isSafeInteger(s.controller.runAttempt) || s.controller.runAttempt <= 0 || !s.controller.token || !(s.ledger === null || typeof s.ledger === "string") || !s.archives || !s.effects) {
|
|
@@ -52626,7 +52519,7 @@ var ReleaseCustodySession = class _ReleaseCustodySession {
|
|
|
52626
52519
|
throw new ReleaseCustodyError(`previous controller run ${found.state.controller.runId} attempt ${found.state.controller.runAttempt} is not proven terminal`);
|
|
52627
52520
|
}
|
|
52628
52521
|
let state = {
|
|
52629
|
-
...found.state ?? { schema: "mmi-release-custody/v1", repo, precutId: (0,
|
|
52522
|
+
...found.state ?? { schema: "mmi-release-custody/v1", repo, precutId: (0, import_node_crypto17.randomUUID)(), effects: {}, ...await initialize() },
|
|
52630
52523
|
revision: (found.state?.revision ?? 0) + 1,
|
|
52631
52524
|
controller
|
|
52632
52525
|
};
|
|
@@ -52634,44 +52527,6 @@ var ReleaseCustodySession = class _ReleaseCustodySession {
|
|
|
52634
52527
|
const sha = await store.compareAndSet(found.sha, state);
|
|
52635
52528
|
return new _ReleaseCustodySession(store, sha, state);
|
|
52636
52529
|
}
|
|
52637
|
-
/** Incident recovery must already have custody: it cannot create, migrate or replace a release. */
|
|
52638
|
-
static async acquireExisting(store, controller, repo) {
|
|
52639
|
-
return this.acquire(store, controller, repo, async () => {
|
|
52640
|
-
throw new ReleaseCustodyError("incident recovery requires existing authoritative custody; no initialization or migration");
|
|
52641
|
-
}, async (state) => {
|
|
52642
|
-
if (Object.values(state.archives).some((a) => a.disposition === "unresolved") || Object.values(state.effects).some((e) => e.state === "intent")) {
|
|
52643
|
-
throw new ReleaseCustodyError("unresolved custody requires read-only reconciliation before incident recovery");
|
|
52644
|
-
}
|
|
52645
|
-
return state;
|
|
52646
|
-
});
|
|
52647
|
-
}
|
|
52648
|
-
/** A fixed incident scope survives ledger replacement and a new precut ID. Even an acknowledged
|
|
52649
|
-
* result is spent: a new controller can observe it but never re-execute the same operation kind. */
|
|
52650
|
-
incidentEffect(incident, kind, identity, execute) {
|
|
52651
|
-
const operation = this.effectTail.then(async () => {
|
|
52652
|
-
this.assertWritable();
|
|
52653
|
-
this.assertEvidenceResolved();
|
|
52654
|
-
if (!/^[a-z0-9-]{1,80}$/.test(incident) || !/^[a-z0-9-]{1,80}$/.test(kind)) throw new ReleaseCustodyError("invalid incident identity");
|
|
52655
|
-
const scope = `incident:${incident}`;
|
|
52656
|
-
const id = custodyDigest(JSON.stringify({ scope, kind }));
|
|
52657
|
-
if (this.state.effects[id] || Object.values(this.state.effects).some((e) => e.scope === scope && e.kind === kind)) {
|
|
52658
|
-
throw new ReleaseCustodyError("incident operation is spent; observe it without another provider write");
|
|
52659
|
-
}
|
|
52660
|
-
if (Object.values(this.state.effects).some((e) => e.state === "intent")) throw new ReleaseCustodyError("unresolved effect blocks another provider write");
|
|
52661
|
-
const effect = { id, scope, kind, identity, state: "intent", startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
52662
|
-
await this.change((state) => ({ ...state, effects: { ...state.effects, [id]: effect } }));
|
|
52663
|
-
let result;
|
|
52664
|
-
try {
|
|
52665
|
-
result = await execute();
|
|
52666
|
-
} catch {
|
|
52667
|
-
throw new ReleaseCustodyError("incident request outcome is unacknowledged; intent remains spent, observation only");
|
|
52668
|
-
}
|
|
52669
|
-
await this.change((state) => ({ ...state, effects: { ...state.effects, [id]: { ...effect, state: "observed", result } } }));
|
|
52670
|
-
return result;
|
|
52671
|
-
});
|
|
52672
|
-
this.effectTail = operation.catch(() => void 0);
|
|
52673
|
-
return operation;
|
|
52674
|
-
}
|
|
52675
52530
|
assertWritable() {
|
|
52676
52531
|
if (this.poison) throw this.poison;
|
|
52677
52532
|
}
|
|
@@ -52725,7 +52580,7 @@ var ReleaseCustodySession = class _ReleaseCustodySession {
|
|
|
52725
52580
|
proof: { kind: "ledger-lifecycle", controller: state.controller }
|
|
52726
52581
|
};
|
|
52727
52582
|
}
|
|
52728
|
-
return { ...state, ledger: raw, archives, precutId: state.ledger && !raw ? (0,
|
|
52583
|
+
return { ...state, ledger: raw, archives, precutId: state.ledger && !raw ? (0, import_node_crypto17.randomUUID)() : state.precutId };
|
|
52729
52584
|
});
|
|
52730
52585
|
}
|
|
52731
52586
|
async preserveLocal(raw) {
|
|
@@ -52832,7 +52687,12 @@ async function commandIdentity(file, args, run, repo) {
|
|
|
52832
52687
|
const fields = Object.fromEntries(args.flatMap((arg, i) => ["-f", "--field", "-F", "--raw-field"].includes(arg) ? [args[i + 1].split(/=(.*)/s).slice(0, 2)] : []));
|
|
52833
52688
|
const ref = args.includes("--ref") ? args[args.indexOf("--ref") + 1] : "main";
|
|
52834
52689
|
const sha = (await run("git", ["rev-parse", `origin/${ref}`])).trim();
|
|
52835
|
-
const before = JSON.parse(await run("gh", [
|
|
52690
|
+
const before = JSON.parse(await run("gh", [
|
|
52691
|
+
"api",
|
|
52692
|
+
`repos/${repo}/actions/workflows/${args[2]}/runs?event=workflow_dispatch&per_page=100`,
|
|
52693
|
+
"--jq",
|
|
52694
|
+
"{workflow_runs: [.workflow_runs[] | {id}]}"
|
|
52695
|
+
]));
|
|
52836
52696
|
return { kind: "workflow-dispatch", identity: { repo, workflow: args[2], fields, sha, beforeRunIds: before.workflow_runs.map((row) => row.id) } };
|
|
52837
52697
|
}
|
|
52838
52698
|
if (file === "gh" && args[0] === "run" && args[1] === "rerun") {
|
|
@@ -52914,7 +52774,7 @@ function withHubReleaseCustody(deps) {
|
|
|
52914
52774
|
if (!authority.ok || !authority.train || authority.authenticatedDelegation !== true) {
|
|
52915
52775
|
throw new ReleaseCustodyError("repository custody requires the server-verified owner-triggered train session");
|
|
52916
52776
|
}
|
|
52917
|
-
const controller = { ...runIdentity, token: (0,
|
|
52777
|
+
const controller = { ...runIdentity, token: (0, import_node_crypto17.randomUUID)() };
|
|
52918
52778
|
const raw = localRaw(path2);
|
|
52919
52779
|
const requiredContexts = () => discoverRequiredCheckContexts(
|
|
52920
52780
|
deps,
|
|
@@ -53619,7 +53479,7 @@ init_github_quota();
|
|
|
53619
53479
|
|
|
53620
53480
|
// src/issue-commands.ts
|
|
53621
53481
|
var import_node_fs43 = require("node:fs");
|
|
53622
|
-
var
|
|
53482
|
+
var import_node_crypto18 = require("node:crypto");
|
|
53623
53483
|
init_cli_shared();
|
|
53624
53484
|
init_clean_exit();
|
|
53625
53485
|
init_error_codes();
|
|
@@ -54092,7 +53952,7 @@ function rowIdempotencyKey(batchKey, spec) {
|
|
|
54092
53952
|
const identity = `${spec.type}
|
|
54093
53953
|
${spec.title.trim()}
|
|
54094
53954
|
${spec.body ?? ""}`;
|
|
54095
|
-
const hash = (0,
|
|
53955
|
+
const hash = (0, import_node_crypto18.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
|
|
54096
53956
|
return `${batchKey}:${hash}`;
|
|
54097
53957
|
}
|
|
54098
53958
|
var BATCH_SPEC_KEYS = /* @__PURE__ */ new Set(["type", "title", "body", "priority", "labels", "label", "parent", "repo", "surface"]);
|
|
@@ -59656,7 +59516,7 @@ function releaseFollowUpLegs(result, projectInfoSync) {
|
|
|
59656
59516
|
legs.push(...runs2.map((run) => ({
|
|
59657
59517
|
leg: run.workflow,
|
|
59658
59518
|
status: followUpLegStatus(run.conclusion),
|
|
59659
|
-
...run.conclusion === "failure" ? { error: run.workflow === "jerv-gateway" ? result.dispatch : `${run.workflow} reported failure` } : {}
|
|
59519
|
+
...run.conclusion === "failure" ? { error: run.workflow === "jerv-gateway" ? result.dispatch : run.runUrlNote ?? `${run.workflow} reported failure` } : {}
|
|
59660
59520
|
})));
|
|
59661
59521
|
} else if (result.deployStatus && result.deployStatus !== "success") {
|
|
59662
59522
|
legs.push({
|
|
@@ -63793,9 +63653,9 @@ function formatExplainCommand(cmd, rootName) {
|
|
|
63793
63653
|
return lines2.join("\n").trimEnd();
|
|
63794
63654
|
}
|
|
63795
63655
|
function formatExplainGroup(cmd, rootName) {
|
|
63796
|
-
const
|
|
63656
|
+
const canonical = (node) => node.path;
|
|
63797
63657
|
const lines2 = [
|
|
63798
|
-
`${rootName} ${
|
|
63658
|
+
`${rootName} ${canonical(cmd)}${cmd.description ? ` \u2014 ${cmd.description}` : ""}`,
|
|
63799
63659
|
`Category: ${cmd.category} \xB7 Discovery: ${cmd.discovery}`,
|
|
63800
63660
|
""
|
|
63801
63661
|
];
|
|
@@ -63806,7 +63666,7 @@ function formatExplainGroup(cmd, rootName) {
|
|
|
63806
63666
|
const name = arg.variadic ? `${arg.name}...` : arg.name;
|
|
63807
63667
|
return arg.required ? `<${name}>` : `[${name}]`;
|
|
63808
63668
|
}).join(" ");
|
|
63809
|
-
lines2.push(` ${
|
|
63669
|
+
lines2.push(` ${canonical(child2)}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
|
|
63810
63670
|
}
|
|
63811
63671
|
return lines2.join("\n");
|
|
63812
63672
|
}
|
|
@@ -66565,14 +66425,14 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
|
|
|
66565
66425
|
}
|
|
66566
66426
|
|
|
66567
66427
|
// src/tenant-artifact.ts
|
|
66568
|
-
var
|
|
66428
|
+
var import_node_crypto19 = require("node:crypto");
|
|
66569
66429
|
var import_node_fs58 = require("node:fs");
|
|
66570
66430
|
var import_promises11 = require("node:fs/promises");
|
|
66571
66431
|
var import_node_path53 = require("node:path");
|
|
66572
66432
|
var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
66573
66433
|
var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
|
|
66574
66434
|
async function sha256File(path2) {
|
|
66575
|
-
const hash = (0,
|
|
66435
|
+
const hash = (0, import_node_crypto19.createHash)("sha256");
|
|
66576
66436
|
for await (const chunk of (0, import_node_fs58.createReadStream)(path2)) hash.update(chunk);
|
|
66577
66437
|
return hash.digest("hex");
|
|
66578
66438
|
}
|
|
@@ -67164,13 +67024,13 @@ async function executeWaveLand(plan, deps) {
|
|
|
67164
67024
|
|
|
67165
67025
|
// src/dist-drift.ts
|
|
67166
67026
|
var import_node_child_process22 = require("node:child_process");
|
|
67167
|
-
var
|
|
67027
|
+
var import_node_crypto21 = require("node:crypto");
|
|
67168
67028
|
var import_node_fs61 = require("node:fs");
|
|
67169
67029
|
var import_node_os26 = require("node:os");
|
|
67170
67030
|
var import_node_path56 = require("node:path");
|
|
67171
67031
|
|
|
67172
67032
|
// ../scripts/distribution-digest.mjs
|
|
67173
|
-
var
|
|
67033
|
+
var import_node_crypto20 = require("node:crypto");
|
|
67174
67034
|
var import_node_fs60 = require("node:fs");
|
|
67175
67035
|
var import_node_path55 = require("node:path");
|
|
67176
67036
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
@@ -67183,7 +67043,7 @@ function repoPath(root, declaredPath, label) {
|
|
|
67183
67043
|
return target;
|
|
67184
67044
|
}
|
|
67185
67045
|
function digestFiles(files) {
|
|
67186
|
-
const hash = (0,
|
|
67046
|
+
const hash = (0, import_node_crypto20.createHash)("sha256");
|
|
67187
67047
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
67188
67048
|
const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs60.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs60.readFileSync)(file.absolute);
|
|
67189
67049
|
hash.update(file.relative, "utf8");
|
|
@@ -67214,7 +67074,7 @@ var DIST_ARTIFACTS = [
|
|
|
67214
67074
|
];
|
|
67215
67075
|
var BOM_DIST_TREE_ID = "mmi-cli-dist";
|
|
67216
67076
|
var ABSENT = "absent";
|
|
67217
|
-
var sha2562 = (bytes) => `sha256:${(0,
|
|
67077
|
+
var sha2562 = (bytes) => `sha256:${(0, import_node_crypto21.createHash)("sha256").update(bytes).digest("hex")}`;
|
|
67218
67078
|
function artifactDrift(path2, committedBytes, rebuiltBytes) {
|
|
67219
67079
|
const committed = committedBytes ? sha2562(committedBytes) : ABSENT;
|
|
67220
67080
|
const rebuiltExpected = rebuiltBytes ? sha2562(rebuiltBytes) : ABSENT;
|
|
@@ -68549,8 +68409,8 @@ function resolveParseHint() {
|
|
|
68549
68409
|
const candidates = unknownCommandCandidates(parent, allCommandPaths());
|
|
68550
68410
|
const tail = unknownCommandTail(process.argv.slice(2), lastUnknownCommand);
|
|
68551
68411
|
const path3 = lastUnknownCommand ? suggestCommandPath(lastUnknownCommand, candidates, tail) : void 0;
|
|
68552
|
-
const
|
|
68553
|
-
if (
|
|
68412
|
+
const canonical = path3 ? canonicalPathFor(path3) ?? path3 : void 0;
|
|
68413
|
+
if (canonical) return `(did you mean \`mmi-cli ${canonical}\`? ${DISCOVERY_HINT})`;
|
|
68554
68414
|
return parent ? `(${DISCOVERY_HINT})` : STALE_HINT;
|
|
68555
68415
|
}
|
|
68556
68416
|
if (lastParseErrorKind !== "bad-arguments") return STALE_HINT;
|
|
@@ -68569,10 +68429,10 @@ function positionalCommandEntries(house) {
|
|
|
68569
68429
|
if (commandMetadata(node)?.category !== "internal") {
|
|
68570
68430
|
const args = node.registeredArguments ?? [];
|
|
68571
68431
|
const path2 = commandPath3(node);
|
|
68572
|
-
const
|
|
68573
|
-
if (args[0] &&
|
|
68432
|
+
const canonical = path2 ? canonicalPathFor(path2) ?? path2 : "";
|
|
68433
|
+
if (args[0] && canonical && (house === void 0 || houseForPath(canonical) === house)) {
|
|
68574
68434
|
acc.push({
|
|
68575
|
-
path:
|
|
68435
|
+
path: canonical,
|
|
68576
68436
|
names: [node.name(), ...node.aliases()],
|
|
68577
68437
|
argName: args[0].name(),
|
|
68578
68438
|
ownFlags: commandOwnLongFlags(node)
|
|
@@ -68587,8 +68447,8 @@ function positionalCommandEntries(house) {
|
|
|
68587
68447
|
function excessArgumentCorrection(extra, argv) {
|
|
68588
68448
|
const invoked = resolveCommandFromArgv(program2, [...argv]);
|
|
68589
68449
|
if (!invoked || extra.length !== 1) return void 0;
|
|
68590
|
-
const
|
|
68591
|
-
const entries = positionalCommandEntries(houseForPath(
|
|
68450
|
+
const canonical = canonicalPathFor(commandPath3(invoked)) ?? commandPath3(invoked);
|
|
68451
|
+
const entries = positionalCommandEntries(houseForPath(canonical)).filter((e) => e.path !== canonical);
|
|
68592
68452
|
const sibling = siblingTakingPositional(invoked.name(), entries);
|
|
68593
68453
|
return sibling ? correctedPositionalCommand(sibling, extra[0], argv) : void 0;
|
|
68594
68454
|
}
|
package/dist/runbook-sweep.cjs
CHANGED
|
@@ -12316,30 +12316,6 @@ async function discoverShaWorkflowRuns(deps, repo, headSha, seenRunIds) {
|
|
|
12316
12316
|
// src/workflow-runner-yaml.ts
|
|
12317
12317
|
var import_yaml = __toESM(require_dist(), 1);
|
|
12318
12318
|
|
|
12319
|
-
// ../shared/ci-allowance-contract.ts
|
|
12320
|
-
var CLI_ALLOWANCE_MANIFEST = Object.freeze({
|
|
12321
|
-
id: "hub-cli-v1",
|
|
12322
|
-
parts: ["tests-1", "tests-2", "checks"],
|
|
12323
|
-
// Includes checkout, toolchain, installation and teardown, not just the test subprocess.
|
|
12324
|
-
jobMinutes: 10,
|
|
12325
|
-
aggregateMinutes: 1,
|
|
12326
|
-
maxAttempts: 3,
|
|
12327
|
-
storageBytes: 0
|
|
12328
|
-
});
|
|
12329
|
-
var CLI_ATTEMPT_MINUTES = CLI_ALLOWANCE_MANIFEST.parts.length * CLI_ALLOWANCE_MANIFEST.jobMinutes + CLI_ALLOWANCE_MANIFEST.aggregateMinutes;
|
|
12330
|
-
var CI_PROFILES = Object.freeze({
|
|
12331
|
-
"included-linux": "ubuntu-latest",
|
|
12332
|
-
"owned-linux": ["self-hosted", "linux", "x64", "mmi-live"]
|
|
12333
|
-
});
|
|
12334
|
-
var CLI_ALLOWANCE_SOURCE = Object.freeze({
|
|
12335
|
-
repository: "mutmutco/MMI-Hub",
|
|
12336
|
-
callerPath: ".github/workflows/gate.yml",
|
|
12337
|
-
coordinatorPath: ".github/workflows/ci-allowance.yml",
|
|
12338
|
-
coordinatorSha: "50f0bd4d8e35f3f09119bd3fa1bb7705fcc6f09b",
|
|
12339
|
-
coordinatorSha256: "7b23f22131c5e08292f142eeed3899c8ecf49b1bdcc96bfdfe114cf1dca47b48",
|
|
12340
|
-
executionSha256: "6198e0896a5533f9546e084642ceb214336c930561fe9f8292eb7e6a0972933b"
|
|
12341
|
-
});
|
|
12342
|
-
|
|
12343
12319
|
// src/train-doctor.ts
|
|
12344
12320
|
var import_node_child_process7 = require("node:child_process");
|
|
12345
12321
|
var import_node_fs8 = require("node:fs");
|
package/package.json
CHANGED