@mutmutco/cli 4.6.32 → 4.6.33
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 +134 -11
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -27062,6 +27062,71 @@ function contentPutInputArgs(repo, path2, inputFile) {
|
|
|
27062
27062
|
inputFile
|
|
27063
27063
|
];
|
|
27064
27064
|
}
|
|
27065
|
+
var BANK_REQUEST_REPO = "mutmutco/Jerv-Hub";
|
|
27066
|
+
var BANK_REQUEST_LABEL = "bank-request";
|
|
27067
|
+
var BANK_REQUEST_SOURCE = "MMI-Hub#9958";
|
|
27068
|
+
function bankRequestTitle(repoName2) {
|
|
27069
|
+
return `bank-request: coding-agent::${repoName2}`;
|
|
27070
|
+
}
|
|
27071
|
+
function bankRequestBody(fullName) {
|
|
27072
|
+
return `Create the coding-agent memory bank for \`${fullName}\` (asked by \`mmi-cli devops bootstrap apply\`; see ${BANK_REQUEST_SOURCE}).`;
|
|
27073
|
+
}
|
|
27074
|
+
function planBankRequest(fullName, existing) {
|
|
27075
|
+
const parsed = parseOwnerRepo(fullName);
|
|
27076
|
+
const base = { title: bankRequestTitle(parsed.name), label: BANK_REQUEST_LABEL, body: bankRequestBody(parsed.fullName) };
|
|
27077
|
+
if (existing == null) return { ...base, action: "skip", reason: `could not read ${BANK_REQUEST_REPO} issues` };
|
|
27078
|
+
const found = existing.find((issue) => issue?.title === base.title);
|
|
27079
|
+
if (found) {
|
|
27080
|
+
return {
|
|
27081
|
+
...base,
|
|
27082
|
+
action: "exists",
|
|
27083
|
+
number: found.number,
|
|
27084
|
+
state: found.state ?? "open",
|
|
27085
|
+
url: found.url ?? `https://github.com/${BANK_REQUEST_REPO}/issues/${found.number}`
|
|
27086
|
+
};
|
|
27087
|
+
}
|
|
27088
|
+
return { ...base, action: "create" };
|
|
27089
|
+
}
|
|
27090
|
+
var oneLine = (e) => String(e?.message ?? e).split("\n")[0].trim();
|
|
27091
|
+
function bankRequestManualStep(request, reason) {
|
|
27092
|
+
return `file it by hand at https://github.com/${BANK_REQUEST_REPO}/issues/new \u2014 title "${request.title}", label ${request.label}, body: ${request.body} (${reason})`;
|
|
27093
|
+
}
|
|
27094
|
+
function renderBankRequestPlan(result) {
|
|
27095
|
+
return [
|
|
27096
|
+
"bootstrap apply \u2014 coding-agent memory bank request (dry-run; no issue filed):",
|
|
27097
|
+
` PLAN file issue "${result.title}" (label ${result.label}) in ${BANK_REQUEST_REPO}`,
|
|
27098
|
+
` body: ${result.body}`
|
|
27099
|
+
].join("\n");
|
|
27100
|
+
}
|
|
27101
|
+
function renderBankRequestLine(result) {
|
|
27102
|
+
if (result.status === "opened") {
|
|
27103
|
+
return `memory bank request: ${BANK_REQUEST_REPO}#${result.number} opened \u2014 "${result.title}" (label ${result.label})${result.url ? ` ${result.url}` : ""}`;
|
|
27104
|
+
}
|
|
27105
|
+
if (result.status === "exists") {
|
|
27106
|
+
return `memory bank request: already requested \u2014 ${BANK_REQUEST_REPO}#${result.number} (${result.state})${result.url ? ` ${result.url}` : ""}`;
|
|
27107
|
+
}
|
|
27108
|
+
return `memory bank request: SKIPPED (${result.reason ?? "not attempted"}) \u2014 ${bankRequestManualStep(result, result.reason ?? "not attempted")}`;
|
|
27109
|
+
}
|
|
27110
|
+
async function runBankRequest(fullName, options, deps) {
|
|
27111
|
+
const parsed = parseOwnerRepo(fullName);
|
|
27112
|
+
const request = { title: bankRequestTitle(parsed.name), label: BANK_REQUEST_LABEL, body: bankRequestBody(parsed.fullName) };
|
|
27113
|
+
if (options.dryRun) return { ...request, status: "planned" };
|
|
27114
|
+
let existing;
|
|
27115
|
+
try {
|
|
27116
|
+
existing = await deps.listIssues();
|
|
27117
|
+
} catch (e) {
|
|
27118
|
+
return { ...request, status: "skipped", reason: `could not read ${BANK_REQUEST_REPO} issues: ${oneLine(e)}` };
|
|
27119
|
+
}
|
|
27120
|
+
const plan = planBankRequest(fullName, existing);
|
|
27121
|
+
if (plan.action === "exists") return { ...request, status: "exists", number: plan.number, state: plan.state, url: plan.url };
|
|
27122
|
+
if (plan.action === "skip") return { ...request, status: "skipped", reason: plan.reason };
|
|
27123
|
+
try {
|
|
27124
|
+
const created = await deps.createIssue(request);
|
|
27125
|
+
return { ...request, status: "opened", number: created.number, url: created.url };
|
|
27126
|
+
} catch (e) {
|
|
27127
|
+
return { ...request, status: "skipped", reason: `App issue write failed: ${oneLine(e)}` };
|
|
27128
|
+
}
|
|
27129
|
+
}
|
|
27065
27130
|
|
|
27066
27131
|
// src/train-apply-contracts.ts
|
|
27067
27132
|
var import_node_fs21 = require("node:fs");
|
|
@@ -28301,10 +28366,10 @@ var rollout_plan_default = {
|
|
|
28301
28366
|
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)."
|
|
28302
28367
|
},
|
|
28303
28368
|
baseline: {
|
|
28304
|
-
version: "4.6.
|
|
28305
|
-
tag: "v4.6.
|
|
28306
|
-
commit: "
|
|
28307
|
-
npm: "@mutmutco/cli@4.6.
|
|
28369
|
+
version: "4.6.33",
|
|
28370
|
+
tag: "v4.6.33",
|
|
28371
|
+
commit: "80768b0b2052",
|
|
28372
|
+
npm: "@mutmutco/cli@4.6.33"
|
|
28308
28373
|
},
|
|
28309
28374
|
exitCriterion: "fleet-n-of-n",
|
|
28310
28375
|
hubOnlyShortcut: "forbidden",
|
|
@@ -28321,14 +28386,14 @@ var rollout_plan_default = {
|
|
|
28321
28386
|
repo: "mutmutco/mmi-hub",
|
|
28322
28387
|
role: "canary",
|
|
28323
28388
|
schedule: "train",
|
|
28324
|
-
v3Target: "v4.6.
|
|
28389
|
+
v3Target: "v4.6.33"
|
|
28325
28390
|
}
|
|
28326
28391
|
],
|
|
28327
28392
|
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.",
|
|
28328
28393
|
rollback: {
|
|
28329
28394
|
independent: true,
|
|
28330
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
28331
|
-
v3Target: "v4.6.
|
|
28395
|
+
mechanism: "npm dist-tag latest -> 4.6.33 and redeploy the Hub Lambda from tag v4.6.33 (80768b0b2052); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
28396
|
+
v3Target: "v4.6.33 (@mutmutco/cli@4.6.33, tag commit 80768b0b2052 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
28332
28397
|
}
|
|
28333
28398
|
},
|
|
28334
28399
|
{
|
|
@@ -51508,6 +51573,7 @@ function registerBootstrapCommands(program3) {
|
|
|
51508
51573
|
}
|
|
51509
51574
|
const actions = [];
|
|
51510
51575
|
const applied = [];
|
|
51576
|
+
let bankRequest = null;
|
|
51511
51577
|
let applyDeployModel;
|
|
51512
51578
|
let applyProjectType;
|
|
51513
51579
|
try {
|
|
@@ -51986,6 +52052,48 @@ ${onlyManagedBlock ? `Only the marker-bounded Hub-managed block inside repo-owne
|
|
|
51986
52052
|
applied.push(`ddb register ${registerPayload.slug} (failed: ${why})`);
|
|
51987
52053
|
}
|
|
51988
52054
|
}
|
|
52055
|
+
if (!onlyTarget) {
|
|
52056
|
+
bankRequest = await runBankRequest(repo, { dryRun: !o.execute }, {
|
|
52057
|
+
listIssues: async () => {
|
|
52058
|
+
const listed = await gh2([
|
|
52059
|
+
"issue",
|
|
52060
|
+
"list",
|
|
52061
|
+
"--repo",
|
|
52062
|
+
BANK_REQUEST_REPO,
|
|
52063
|
+
"--state",
|
|
52064
|
+
"all",
|
|
52065
|
+
"--search",
|
|
52066
|
+
`in:title "${bankRequestTitle(parsedRepo.name)}"`,
|
|
52067
|
+
"--json",
|
|
52068
|
+
"number,title,state,url",
|
|
52069
|
+
"--limit",
|
|
52070
|
+
"50"
|
|
52071
|
+
]);
|
|
52072
|
+
const rows = JSON.parse(listed.stdout || "[]");
|
|
52073
|
+
if (!Array.isArray(rows)) throw new Error("issue list is not an array");
|
|
52074
|
+
return rows;
|
|
52075
|
+
},
|
|
52076
|
+
createIssue: async (request) => {
|
|
52077
|
+
const out = await gh2([
|
|
52078
|
+
"issue",
|
|
52079
|
+
"create",
|
|
52080
|
+
"--repo",
|
|
52081
|
+
BANK_REQUEST_REPO,
|
|
52082
|
+
"--title",
|
|
52083
|
+
request.title,
|
|
52084
|
+
"--body",
|
|
52085
|
+
request.body,
|
|
52086
|
+
"--label",
|
|
52087
|
+
request.label
|
|
52088
|
+
]);
|
|
52089
|
+
const url = out.stdout.trim().split("\n").pop()?.trim() ?? "";
|
|
52090
|
+
const number = Number(/(\d+)$/.exec(url)?.[1]);
|
|
52091
|
+
if (!url || !Number.isFinite(number)) throw new Error(`issue create returned no issue URL: ${out.stdout.trim().slice(0, 200)}`);
|
|
52092
|
+
return { number, url };
|
|
52093
|
+
}
|
|
52094
|
+
});
|
|
52095
|
+
if (o.execute) applied.push(renderBankRequestLine(bankRequest));
|
|
52096
|
+
}
|
|
51989
52097
|
if (o.execute && !onlyTarget) {
|
|
51990
52098
|
const github = await readBootstrapGitHubFacts(repo, effectiveTrack, controlClient);
|
|
51991
52099
|
controlDeployFacts = await fetchDeployFactsBySlug(slug, registryClientDeps(await loadConfig()));
|
|
@@ -52081,13 +52189,15 @@ ${onlyManagedBlock ? `Only the marker-bounded Hub-managed block inside repo-owne
|
|
|
52081
52189
|
return failGraceful(`bootstrap apply: cannot plan labels/environments; no writes made: ${e.message}`);
|
|
52082
52190
|
}
|
|
52083
52191
|
}
|
|
52084
|
-
if (o.json) console.log(JSON.stringify({ repo, class: o.class, sourceSha: seedSource.sha, only: onlyTarget || null, execute: o.execute, seedDelivery: seedPlan.mode, seedBranch: seedPlan.branch, seedBaseSha: scopedPlan?.baseSha, seedPrUrl, actions, controlPlane: controlRows, labels: ancillaryPlan, environments: environmentPlan, applied, ddbWrites }, null, 2));
|
|
52192
|
+
if (o.json) console.log(JSON.stringify({ repo, class: o.class, sourceSha: seedSource.sha, only: onlyTarget || null, execute: o.execute, seedDelivery: seedPlan.mode, seedBranch: seedPlan.branch, seedBaseSha: scopedPlan?.baseSha, seedPrUrl, actions, controlPlane: controlRows, labels: ancillaryPlan, environments: environmentPlan, bankRequest, applied, ddbWrites }, null, 2));
|
|
52085
52193
|
else {
|
|
52086
52194
|
console.log(renderSeedPlan(actions));
|
|
52087
52195
|
if (controlRows.length) console.log(`
|
|
52088
52196
|
${renderBootstrapControlPlan(controlRows)}`);
|
|
52089
52197
|
if (ancillaryPlan && environmentPlan) console.log(`
|
|
52090
52198
|
${renderBootstrapAncillaryPlan(ancillaryPlan, environmentPlan, repoEnvironmentSpecs(repo, effectiveTrack, suiteSlug).filter((spec) => spec.exception).map((spec) => ({ name: spec.name, detail: spec.exception })))}`);
|
|
52199
|
+
if (bankRequest?.status === "planned") console.log(`
|
|
52200
|
+
${renderBankRequestPlan(bankRequest)}`);
|
|
52091
52201
|
if (o.execute) console.log(`
|
|
52092
52202
|
LIVE apply to ${repo}:
|
|
52093
52203
|
${applied.join("\n ")}`);
|
|
@@ -56455,6 +56565,7 @@ async function verifyCustodyBootstrap(value, api, controller, requiredContexts,
|
|
|
56455
56565
|
// src/release-custody.ts
|
|
56456
56566
|
var RELEASE_CUSTODY_BRANCH = "mmi-release-state";
|
|
56457
56567
|
var RELEASE_CUSTODY_PATH = "release-custody.json";
|
|
56568
|
+
var HUB_RELEASE_CUSTODY_JOB = "release";
|
|
56458
56569
|
var ReleaseCustodyError = class extends Error {
|
|
56459
56570
|
constructor(message2) {
|
|
56460
56571
|
super("Release custody: " + message2);
|
|
@@ -56528,6 +56639,14 @@ function githubCustodyStore(repo, baseSha, api = defaultGitHubClient()) {
|
|
|
56528
56639
|
`repos/${repo}/actions/runs/${controller.runId}/attempts/${controller.runAttempt}`
|
|
56529
56640
|
);
|
|
56530
56641
|
return run.id === controller.runId && run.run_attempt === controller.runAttempt && run.path === HUB_RELEASE_WORKFLOW && run.status === "completed";
|
|
56642
|
+
},
|
|
56643
|
+
async jobCompleted(controller) {
|
|
56644
|
+
const jobs = await api.rest(
|
|
56645
|
+
"GET",
|
|
56646
|
+
`repos/${repo}/actions/runs/${controller.runId}/attempts/${controller.runAttempt}/jobs?per_page=100`
|
|
56647
|
+
);
|
|
56648
|
+
const job = (jobs?.jobs ?? []).find((row) => row.name === (controller.job ?? HUB_RELEASE_CUSTODY_JOB));
|
|
56649
|
+
return job?.status === "completed" && job.conclusion === "success";
|
|
56531
56650
|
}
|
|
56532
56651
|
};
|
|
56533
56652
|
}
|
|
@@ -56546,8 +56665,12 @@ var ReleaseCustodySession = class _ReleaseCustodySession {
|
|
|
56546
56665
|
poison;
|
|
56547
56666
|
static async acquire(store, controller, repo, initialize, prepare) {
|
|
56548
56667
|
const found = await store.read();
|
|
56549
|
-
|
|
56550
|
-
|
|
56668
|
+
const prior = found.state?.controller;
|
|
56669
|
+
if (prior) {
|
|
56670
|
+
const handoff = prior.runId === controller.runId && prior.runAttempt === controller.runAttempt;
|
|
56671
|
+
if (!(handoff ? await store.jobCompleted(prior) : await store.terminal(prior))) {
|
|
56672
|
+
throw new ReleaseCustodyError(handoff ? `previous controller ${prior.job ?? HUB_RELEASE_CUSTODY_JOB} job of run ${prior.runId} attempt ${prior.runAttempt} is not proven completed` : `previous controller run ${prior.runId} attempt ${prior.runAttempt} is not proven terminal`);
|
|
56673
|
+
}
|
|
56551
56674
|
}
|
|
56552
56675
|
let state = {
|
|
56553
56676
|
...found.state ?? { schema: "mmi-release-custody/v1", repo, precutId: (0, import_node_crypto21.randomUUID)(), effects: {}, ...await initialize() },
|
|
@@ -56845,7 +56968,7 @@ function withHubReleaseCustody(deps) {
|
|
|
56845
56968
|
if (!authority.ok || !authority.train || authority.authenticatedDelegation !== true) {
|
|
56846
56969
|
throw new ReleaseCustodyError("repository custody requires the server-verified owner-triggered train session");
|
|
56847
56970
|
}
|
|
56848
|
-
const controller = { ...runIdentity, token: (0, import_node_crypto21.randomUUID)() };
|
|
56971
|
+
const controller = { ...runIdentity, token: (0, import_node_crypto21.randomUUID)(), ...process.env.GITHUB_JOB ? { job: process.env.GITHUB_JOB } : {} };
|
|
56849
56972
|
const raw = localRaw(path2);
|
|
56850
56973
|
const requiredContexts = () => discoverRequiredCheckContexts(
|
|
56851
56974
|
deps,
|
package/package.json
CHANGED