@mutmutco/codex-plugin 4.5.170 → 4.5.171
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli/dist/main.cjs
CHANGED
|
@@ -19087,10 +19087,10 @@ var rollout_plan_default = {
|
|
|
19087
19087
|
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)."
|
|
19088
19088
|
},
|
|
19089
19089
|
baseline: {
|
|
19090
|
-
version: "4.5.
|
|
19091
|
-
tag: "v4.5.
|
|
19092
|
-
commit: "
|
|
19093
|
-
npm: "@mutmutco/cli@4.5.
|
|
19090
|
+
version: "4.5.171",
|
|
19091
|
+
tag: "v4.5.171",
|
|
19092
|
+
commit: "79faa07090b1",
|
|
19093
|
+
npm: "@mutmutco/cli@4.5.171"
|
|
19094
19094
|
},
|
|
19095
19095
|
exitCriterion: "fleet-n-of-n",
|
|
19096
19096
|
hubOnlyShortcut: "forbidden",
|
|
@@ -19107,14 +19107,14 @@ var rollout_plan_default = {
|
|
|
19107
19107
|
repo: "mutmutco/mmi-hub",
|
|
19108
19108
|
role: "canary",
|
|
19109
19109
|
schedule: "train",
|
|
19110
|
-
v3Target: "v4.5.
|
|
19110
|
+
v3Target: "v4.5.171"
|
|
19111
19111
|
}
|
|
19112
19112
|
],
|
|
19113
19113
|
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.",
|
|
19114
19114
|
rollback: {
|
|
19115
19115
|
independent: true,
|
|
19116
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
19117
|
-
v3Target: "v4.5.
|
|
19116
|
+
mechanism: "npm dist-tag latest -> 4.5.171 and redeploy the Hub Lambda from tag v4.5.171 (79faa07090b1); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
19117
|
+
v3Target: "v4.5.171 (@mutmutco/cli@4.5.171, tag commit 79faa07090b1 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
19118
19118
|
}
|
|
19119
19119
|
},
|
|
19120
19120
|
{
|
|
@@ -19304,7 +19304,7 @@ function formatTrainStatus(r) {
|
|
|
19304
19304
|
"",
|
|
19305
19305
|
`release track: ${r.releaseTrack} \u2014 stages: ${r.branches.join(" -> ")}`,
|
|
19306
19306
|
`cli version: ${r.cliVersion}${r.repoVersion ? ` (repo: ${r.repoVersion})` : ""}${r.releasedVersion ? ` (released: ${r.releasedVersion})` : ""}`,
|
|
19307
|
-
`release bump intent: ${r.bumpIntent ?? "not declared \u2014 an ordinary train defaults to patch (#4929);
|
|
19307
|
+
`release bump intent: ${r.bumpIntent ?? "not declared \u2014 an ordinary train defaults to patch (#4929)"} (proposed: patch; minor needs MMI_BUMP_REASON, major also MMI_MAJOR_APPROVED=<version> \u2014 docs/versioning.md)`
|
|
19308
19308
|
];
|
|
19309
19309
|
if (r.versionLag.ok) {
|
|
19310
19310
|
lines2.push("version lag: none \u2014 CLI is current");
|
|
@@ -26562,6 +26562,53 @@ async function selfConvergeTrainCli(input) {
|
|
|
26562
26562
|
}
|
|
26563
26563
|
}
|
|
26564
26564
|
|
|
26565
|
+
// src/bump-proposal.ts
|
|
26566
|
+
var BREAKING_BANG = /^[a-z]+(\([^)]*\))?!:/i;
|
|
26567
|
+
var BREAKING_TRAILER = /^BREAKING[ -]CHANGE:/m;
|
|
26568
|
+
var MAX_BUMP_REASON = 200;
|
|
26569
|
+
function proposeBump(commits, _opts = {}) {
|
|
26570
|
+
const breaking = [];
|
|
26571
|
+
for (const c of commits) {
|
|
26572
|
+
if (BREAKING_BANG.test(c.subject) || BREAKING_TRAILER.test(c.body)) breaking.push(`${c.sha.slice(0, 8)} ${c.subject}`);
|
|
26573
|
+
}
|
|
26574
|
+
return { proposed: "patch", breaking };
|
|
26575
|
+
}
|
|
26576
|
+
function parseRangeLog(raw) {
|
|
26577
|
+
return raw.split("").map((r) => r.replace(/^\n+/, "")).filter((r) => r.trim()).map((r) => {
|
|
26578
|
+
const [sha = "", subject = "", body = ""] = r.split("");
|
|
26579
|
+
return { sha: sha.trim(), subject: subject.trim(), body };
|
|
26580
|
+
});
|
|
26581
|
+
}
|
|
26582
|
+
var RANGE_LOG_FORMAT = "--format=%H%x1f%s%x1f%b%x1e";
|
|
26583
|
+
function enforceBumpRules(input) {
|
|
26584
|
+
const { env, proposal } = input;
|
|
26585
|
+
const effective = input.preOneZero && input.intent === "major" ? "minor" : input.intent;
|
|
26586
|
+
const reason = (env.MMI_BUMP_REASON ?? "").trim();
|
|
26587
|
+
const evidence = proposal.breaking.join("; ");
|
|
26588
|
+
const decision = () => ({ intent: effective, reason: reason || null, proposed: proposal.proposed, breaking: proposal.breaking });
|
|
26589
|
+
if (effective !== "patch") {
|
|
26590
|
+
if (!reason) throw new Error(`MMI_BUMP_INTENT=${input.intent} needs MMI_BUMP_REASON \u2014 a one-line reason (\u2264${MAX_BUMP_REASON} chars) for a real feature or significant change; patch is the default (#8499)`);
|
|
26591
|
+
if (/[\r\n]/.test(reason) || reason.length > MAX_BUMP_REASON) throw new Error(`MMI_BUMP_REASON must be one line of at most ${MAX_BUMP_REASON} chars (#8499)`);
|
|
26592
|
+
}
|
|
26593
|
+
if (effective === "major") {
|
|
26594
|
+
const approved = (env.MMI_MAJOR_APPROVED ?? "").trim().replace(/^v/, "");
|
|
26595
|
+
const target = (input.majorTarget ?? "").replace(/^v/, "");
|
|
26596
|
+
if (!approved) throw new Error(`a major release is owner-gated: set MMI_MAJOR_APPROVED=${target || "<target version>"} only after Jervaise's fresh approval in this turn (#8499)`);
|
|
26597
|
+
if (approved !== target) throw new Error(`MMI_MAJOR_APPROVED=${approved} does not match the major target ${target}; a stale approval cannot tag a different major (#8499)`);
|
|
26598
|
+
return decision();
|
|
26599
|
+
}
|
|
26600
|
+
if (proposal.breaking.length && effective === "patch") {
|
|
26601
|
+
throw new Error(input.preOneZero ? `range carries breaking changes (${evidence}): this repo is held on 0.x.y, so declare MMI_BUMP_INTENT=minor with MMI_BUMP_REASON, or ship a shim (patch) (#8499)` : `range carries breaking changes (${evidence}): ship a shim (patch) or declare an owner-gated major (MMI_BUMP_INTENT=major, MMI_BUMP_REASON, MMI_MAJOR_APPROVED=<version>) (#8499)`);
|
|
26602
|
+
}
|
|
26603
|
+
if (proposal.breaking.length && !input.preOneZero) {
|
|
26604
|
+
throw new Error(`range carries breaking changes (${evidence}): ship a shim (patch) or declare an owner-gated major (#8499)`);
|
|
26605
|
+
}
|
|
26606
|
+
return decision();
|
|
26607
|
+
}
|
|
26608
|
+
function bumpNotesLine(d) {
|
|
26609
|
+
return `Version bump: ${d.intent} \u2014 ${d.reason ?? "default patch"}`;
|
|
26610
|
+
}
|
|
26611
|
+
|
|
26565
26612
|
// src/train-doctor.ts
|
|
26566
26613
|
var TRAIN_LANES = ["release", "rcand", "hotfix"];
|
|
26567
26614
|
var TROUBLESHOOTING_GUIDE = "docs/Guides/train-troubleshooting.md";
|
|
@@ -26857,6 +26904,17 @@ async function runTrainDoctor(input) {
|
|
|
26857
26904
|
if (workflows === null && !startBranchMissing) {
|
|
26858
26905
|
add({ code: "workflows-unreadable", severity: "blocker", source: "local", title: `.github/workflows at ${workflowsRef} could not be read from ${cwd} \u2014 the tag-addressability (#5428) and npm-major (#5666) preflights did not run`, remedy: `run from a checkout whose git can read ${workflowsRef} (fetch origin first), then rerun; an unread workflow set is unverified, not green` });
|
|
26859
26906
|
}
|
|
26907
|
+
if (lane === "release" && !startBranchMissing && startBranch) {
|
|
26908
|
+
try {
|
|
26909
|
+
const proposal = proposeBump(parseRangeLog(await git3(["log", `origin/main..origin/${startBranch}`, RANGE_LOG_FORMAT])));
|
|
26910
|
+
add({ code: "bump-proposal", severity: "info", source: "origin", title: `bump proposal: ${proposal.proposed}`, remedy: "nothing \u2014 patch is the default; minor needs MMI_BUMP_REASON, major also MMI_MAJOR_APPROVED=<version> (docs/versioning.md)" });
|
|
26911
|
+
for (const evidence of proposal.breaking) {
|
|
26912
|
+
add({ code: "bump-breaking", severity: "warning", source: "origin", title: `breaking signal in the release range: ${evidence}`, remedy: "ship a shim (patch) or declare an owner-gated major; the train refuses otherwise" });
|
|
26913
|
+
}
|
|
26914
|
+
} catch (e) {
|
|
26915
|
+
void e;
|
|
26916
|
+
}
|
|
26917
|
+
}
|
|
26860
26918
|
if (lane === "release" && !startBranchMissing) {
|
|
26861
26919
|
const required = meta?.requiredChecks?.length ? meta.requiredChecks : ["gate"];
|
|
26862
26920
|
const emitters = (workflows ?? []).filter((f) => parseWorkflowJobIds(f.body).some((id) => required.some((context) => contextMatchesJobId(id, context))));
|
|
@@ -29623,6 +29681,17 @@ async function resolveTrainBumpIntent(deps, env = process.env, latestRelease, pr
|
|
|
29623
29681
|
}
|
|
29624
29682
|
return "patch";
|
|
29625
29683
|
}
|
|
29684
|
+
async function enforceTrainBump(deps, env, intent, preOneZero, source) {
|
|
29685
|
+
const raw = await deps.run("git", ["log", `origin/main..${source}`, RANGE_LOG_FORMAT]);
|
|
29686
|
+
const proposal = proposeBump(parseRangeLog(raw), { preOneZero });
|
|
29687
|
+
let majorTarget;
|
|
29688
|
+
if (intent === "major") {
|
|
29689
|
+
const explicit = (env.MMI_RELEASE_VERSION ?? "").trim().replace(/^v/, "");
|
|
29690
|
+
const latest = await latestLocalReleaseTag(deps, void 0, preOneZero);
|
|
29691
|
+
majorTarget = explicit || `${latest.major + 1}.0.0`;
|
|
29692
|
+
}
|
|
29693
|
+
return enforceBumpRules({ intent, env, proposal, preOneZero, majorTarget });
|
|
29694
|
+
}
|
|
29626
29695
|
async function resolveHotfixVersion(deps, env = process.env, preOneZero = false) {
|
|
29627
29696
|
const latest = await latestLocalReleaseTag(deps, "origin/main", preOneZero);
|
|
29628
29697
|
if (latest.major === 0 && latest.minor === 0 && latest.patch === 0) {
|
|
@@ -29668,9 +29737,19 @@ async function runTrainApplyLocked(command, deps, options = {}) {
|
|
|
29668
29737
|
await requireCleanTree(deps);
|
|
29669
29738
|
await runGitRemoteRead(deps, ["fetch", "origin"]);
|
|
29670
29739
|
const meta = requireProjectMetaForTrain(await loadProjectMeta(deps, ctx), ctx.repo);
|
|
29671
|
-
const
|
|
29740
|
+
const declaredIntent = await resolveTrainBumpIntent(deps, process.env, void 0, preOneZeroInForce(meta));
|
|
29672
29741
|
const branchHints = await loadReleaseTrackBranchHints(deps);
|
|
29673
29742
|
const directTrack = isHubControlRepo(ctx.repo) || resolveReleaseTrack(meta, branchHints) === "direct";
|
|
29743
|
+
const bump = await enforceTrainBump(
|
|
29744
|
+
deps,
|
|
29745
|
+
process.env,
|
|
29746
|
+
declaredIntent,
|
|
29747
|
+
preOneZeroInForce(meta),
|
|
29748
|
+
command === "release" && !directTrack && options.dev !== true ? "origin/rc" : "origin/development"
|
|
29749
|
+
);
|
|
29750
|
+
const bumpIntent = bump.intent;
|
|
29751
|
+
const bumpReceipt = { intent: bump.intent, reason: bump.reason, proposed: bump.proposed, breaking: bump.breaking };
|
|
29752
|
+
options = { ...options, bumpLine: bumpNotesLine(bump) };
|
|
29674
29753
|
assertSuiteAutoVersion(ctx.repo, meta, process.env, command === "release" && !directTrack);
|
|
29675
29754
|
if (command === "release" && meta.suite === "mm-work") await requireSuiteReleaseSummary(deps, options.announceSummaryFile, options.announceSummaryFileTr);
|
|
29676
29755
|
const pipelineInput = { deps, ctx, command, meta, branchHints, watch, options, bumpIntent };
|
|
@@ -29678,28 +29757,31 @@ async function runTrainApplyLocked(command, deps, options = {}) {
|
|
|
29678
29757
|
if (directTrack) {
|
|
29679
29758
|
throw new Error("direct-track repos release straight to main (no rc); run `mmi-cli devops release --apply` from development instead of rcand");
|
|
29680
29759
|
}
|
|
29681
|
-
return withCheckoutRestoredAfterRelease(deps, await
|
|
29760
|
+
return withCheckoutRestoredAfterRelease(deps, await runPipelineWithBump(bumpReceipt, "rcand", pipelineInput), "development");
|
|
29682
29761
|
}
|
|
29683
29762
|
if (directTrack) {
|
|
29684
29763
|
return withCheckoutRestoredAfterRelease(
|
|
29685
29764
|
deps,
|
|
29686
|
-
await
|
|
29765
|
+
await runPipelineWithBump(bumpReceipt, "release-dev", { ...pipelineInput, directTrack: true }),
|
|
29687
29766
|
"development"
|
|
29688
29767
|
);
|
|
29689
29768
|
}
|
|
29690
29769
|
if (command === "release" && options.dev) {
|
|
29691
29770
|
return withCheckoutRestoredAfterRelease(
|
|
29692
29771
|
deps,
|
|
29693
|
-
await
|
|
29772
|
+
await runPipelineWithBump(bumpReceipt, "release-dev", pipelineInput),
|
|
29694
29773
|
"development"
|
|
29695
29774
|
);
|
|
29696
29775
|
}
|
|
29697
29776
|
return withCheckoutRestoredAfterRelease(
|
|
29698
29777
|
deps,
|
|
29699
|
-
await
|
|
29778
|
+
await runPipelineWithBump(bumpReceipt, "release-full", pipelineInput),
|
|
29700
29779
|
"rc"
|
|
29701
29780
|
);
|
|
29702
29781
|
}
|
|
29782
|
+
async function runPipelineWithBump(bump, mode, input) {
|
|
29783
|
+
return { ...await runTrainApplyPipeline(mode, input), bump };
|
|
29784
|
+
}
|
|
29703
29785
|
|
|
29704
29786
|
// src/ci-audit.ts
|
|
29705
29787
|
var HUB_REPO4 = "mutmutco/MMI-Hub";
|
|
@@ -32490,7 +32572,7 @@ function parseTrainTag(tag) {
|
|
|
32490
32572
|
function cmpTrainRelease(a, b) {
|
|
32491
32573
|
return a.major - b.major || a.minor - b.minor || a.patch - b.patch;
|
|
32492
32574
|
}
|
|
32493
|
-
function trainPlanTargetsFromTags(tags, explicitRaw) {
|
|
32575
|
+
function trainPlanTargetsFromTags(tags, explicitRaw, intent = process.env.MMI_BUMP_INTENT) {
|
|
32494
32576
|
const all = tags.map(parseTrainTag).filter((v) => Boolean(v));
|
|
32495
32577
|
const release = all.find((v) => v.rc === null) ?? { major: 0, minor: 0, patch: 0, rc: null };
|
|
32496
32578
|
const targets = {};
|
|
@@ -32507,7 +32589,8 @@ function trainPlanTargetsFromTags(tags, explicitRaw) {
|
|
|
32507
32589
|
}
|
|
32508
32590
|
}
|
|
32509
32591
|
if (!targets.plannedReleaseError) {
|
|
32510
|
-
const
|
|
32592
|
+
const bumped = intent === "major" ? { major: release.major + 1, minor: 0, patch: 0 } : intent === "minor" ? { major: release.major, minor: release.minor + 1, patch: 0 } : { major: release.major, minor: release.minor, patch: release.patch + 1 };
|
|
32593
|
+
const planned = explicit ?? { ...bumped, rc: null };
|
|
32511
32594
|
targets.plannedRelease = `v${planned.major}.${planned.minor}.${planned.patch}`;
|
|
32512
32595
|
}
|
|
32513
32596
|
let rcs = all.filter((v) => v.rc !== null);
|
|
@@ -32997,6 +33080,9 @@ function parseSecretsCatalogVar(raw) {
|
|
|
32997
33080
|
if (e.aliases !== void 0 && (!Array.isArray(e.aliases) || e.aliases.some((a) => typeof a !== "string"))) {
|
|
32998
33081
|
throw new Error(`org project set: secrets["${mapKey}"].aliases must be a string array`);
|
|
32999
33082
|
}
|
|
33083
|
+
if (e.branchReadable !== void 0 && typeof e.branchReadable !== "boolean") {
|
|
33084
|
+
throw new Error(`org project set: secrets["${mapKey}"].branchReadable must be a boolean`);
|
|
33085
|
+
}
|
|
33000
33086
|
}
|
|
33001
33087
|
return parsed;
|
|
33002
33088
|
}
|
|
@@ -33495,7 +33581,7 @@ var SETTABLE_VAR_HINTS = {
|
|
|
33495
33581
|
requiredBuildSecrets: 'JSON flat array, e.g. ["NODE_AUTH_TOKEN=@github-packages-token"]',
|
|
33496
33582
|
tenantTasks: 'JSON map {name:{service,command[],stages[],timeoutSeconds?,artifact?:"required",output?:"file",secretOutput?:{path,vault:{repo,key},overwrite?}}} \u2014 merged per entry, at most 20 stored in total; retire ONE task with --unset-task NAME; use {artifact} in argv when required; a secretOutput is master-only',
|
|
33497
33583
|
internalPeers: "JSON {owner/repo:[dev|rc|main]} \u2014 same-box suite peers via the box Caddy; clear with --unset internalPeers (#7886)",
|
|
33498
|
-
secrets: "JSON catalog map keyed by KEY {key,purpose,group,owner,stages[],consumers[]} \u2014 merged per entry; drop ONE entry with --unset-secret KEY; clear ALL with --unset secrets --confirm-clear-secrets; prefer --secrets-file",
|
|
33584
|
+
secrets: "JSON catalog map keyed by KEY {key,purpose,group,owner,stages[],consumers[],branchReadable?} \u2014 merged per entry; drop ONE entry with --unset-secret KEY; clear ALL with --unset secrets --confirm-clear-secrets; prefer --secrets-file",
|
|
33499
33585
|
edgeDomains: "JSON {dev,rc,main} domain map",
|
|
33500
33586
|
statusOptions: "JSON name\u2192id map",
|
|
33501
33587
|
priorityOptions: "JSON {Urgent,High,Medium,Low}\u2192id map",
|
|
@@ -43022,6 +43108,15 @@ async function openSuitePinPr(deps, input) {
|
|
|
43022
43108
|
}
|
|
43023
43109
|
}
|
|
43024
43110
|
|
|
43111
|
+
// src/pr-title-check.ts
|
|
43112
|
+
var CONVENTIONAL_PR_TITLE = /^(feat|fix|docs|chore|refactor|perf|test|build|ci|revert|style)(\([^)]+\))?!?: .+/;
|
|
43113
|
+
var EXEMPT_PR_TITLE = /^Merge pull request /;
|
|
43114
|
+
function prTitleRefusal(title) {
|
|
43115
|
+
const t = title.trim();
|
|
43116
|
+
if (CONVENTIONAL_PR_TITLE.test(t) || EXEMPT_PR_TITLE.test(t)) return null;
|
|
43117
|
+
return `pr land: PR title "${t}" is not a Conventional type. Expected \`<type>(<scope>)?(!)?: <summary>\` with type one of feat|fix|docs|chore|refactor|perf|test|build|ci|revert|style (e.g. \`fix(cli): refuse a stale tag\`); retitle with \`gh pr edit <n> --title \u2026\` and land again (#8499)`;
|
|
43118
|
+
}
|
|
43119
|
+
|
|
43025
43120
|
// src/command-register-collaboration.ts
|
|
43026
43121
|
var import_node_child_process17 = require("node:child_process");
|
|
43027
43122
|
var import_node_fs47 = require("node:fs");
|
|
@@ -47962,6 +48057,9 @@ ${list}`);
|
|
|
47962
48057
|
return typeof viewed.state === "string" ? viewed.state : void 0;
|
|
47963
48058
|
}
|
|
47964
48059
|
);
|
|
48060
|
+
const landTitle = await execFileP("gh", ["pr", "view", number, ...repoArgs, "--json", "title", "--jq", ".title"], { timeout: GC_GH_TIMEOUT_MS }).then((r) => r.stdout.trim(), () => "");
|
|
48061
|
+
const landTitleRefusal = landTitle ? prTitleRefusal(landTitle) : null;
|
|
48062
|
+
if (landTitleRefusal) return refused(landTitleRefusal);
|
|
47965
48063
|
const landSquashBody = squashBodyTextForMerge(landClosingGuardInput, true);
|
|
47966
48064
|
warnSquashBodyClosingStrip("pr land", landClosingGuardInput, landSquashBody);
|
|
47967
48065
|
const landClosingGuardVerdict = evaluateClosingGuard(landClosingGuardInput, {
|
|
@@ -57683,7 +57781,7 @@ projectDeploy.command("retire [owner/repo]").description("retire (tombstone) one
|
|
|
57683
57781
|
}
|
|
57684
57782
|
if (!result.ok) return failGraceful(`org project deploy retire: ${result.error ?? "read failed"}`);
|
|
57685
57783
|
});
|
|
57686
|
-
project.command("set [owner/repo]").description("upsert project META (idempotent merge; master-gated)").addOption(new Option("--class <class>", "deployable | content").choices(["deployable", "content"])).addOption(new Option("--project-type <type>", `${PROJECT_TYPES.join(" | ")} (capability shape)`).choices([...PROJECT_TYPES])).addOption(new Option("--deploy-model <model>", `${DEPLOY_MODELS.join(" | ")} (release/deploy path; none means no Hub deploy registration)`).choices([...DEPLOY_MODELS])).addOption(new Option("--release-track <track>", `${RELEASE_TRACKS.join(" | ")} (branch topology; direct skips rc)`).choices([...RELEASE_TRACKS])).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 (drop ONE entry with --unset-secret KEY; clear ALL with --unset secrets --confirm-clear-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"|?], "provider":"<optional>"}').option("--unset-secret <KEY...>", "remove exactly these #2244 catalog entries (repeatable; KEY or KEY@dev|rc|main). Refuses while a stage still requires the key \u2014 drop it from requiredRuntimeSecrets/requiredBuildSecrets first").option("--unset-task <NAME...>", "retire exactly these tenant tasks (repeatable; lowercase kebab-case names). Refuses a name that is not declared. tenantTasks merges per entry and is capped at 20 stored in total").option("--confirm-clear-secrets", "required to let --unset secrets wipe the WHOLE catalog (the refusal names how many entries that removes)").option("--unset <KEY...>", "META field to remove (repeatable): oauth, requiredRuntimeSecrets, requiredBuildSecrets, secrets (the WHOLE catalog \u2014 needs --confirm-clear-secrets), edgeDomains, requiredGcpApis, publishRequired, releaseChannel, releaseLanguage").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) => {
|
|
57784
|
+
project.command("set [owner/repo]").description("upsert project META (idempotent merge; master-gated)").addOption(new Option("--class <class>", "deployable | content").choices(["deployable", "content"])).addOption(new Option("--project-type <type>", `${PROJECT_TYPES.join(" | ")} (capability shape)`).choices([...PROJECT_TYPES])).addOption(new Option("--deploy-model <model>", `${DEPLOY_MODELS.join(" | ")} (release/deploy path; none means no Hub deploy registration)`).choices([...DEPLOY_MODELS])).addOption(new Option("--release-track <track>", `${RELEASE_TRACKS.join(" | ")} (branch topology; direct skips rc)`).choices([...RELEASE_TRACKS])).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 (drop ONE entry with --unset-secret KEY; clear ALL with --unset secrets --confirm-clear-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"|?], "provider":"<optional>", "branchReadable":<optional boolean, master-only #8497>}').option("--unset-secret <KEY...>", "remove exactly these #2244 catalog entries (repeatable; KEY or KEY@dev|rc|main). Refuses while a stage still requires the key \u2014 drop it from requiredRuntimeSecrets/requiredBuildSecrets first").option("--unset-task <NAME...>", "retire exactly these tenant tasks (repeatable; lowercase kebab-case names). Refuses a name that is not declared. tenantTasks merges per entry and is capped at 20 stored in total").option("--confirm-clear-secrets", "required to let --unset secrets wipe the WHOLE catalog (the refusal names how many entries that removes)").option("--unset <KEY...>", "META field to remove (repeatable): oauth, requiredRuntimeSecrets, requiredBuildSecrets, secrets (the WHOLE catalog \u2014 needs --confirm-clear-secrets), edgeDomains, requiredGcpApis, publishRequired, releaseChannel, releaseLanguage").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) => {
|
|
57687
57785
|
const cfg = await loadConfig();
|
|
57688
57786
|
let target;
|
|
57689
57787
|
try {
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -118,6 +118,10 @@ Production changes require explicit authorization from the authorized human.
|
|
|
118
118
|
Read the selected release skill before operating the train. Let it choose versions, run gates,
|
|
119
119
|
publish, deploy, and verify the resulting release. A refusal requires fixing its cause; do not
|
|
120
120
|
finish by hand, bypass checks, or start a duplicate release.
|
|
121
|
+
Versions: patch is the default for fixes and small compatible additions. Minor is a deliberate call
|
|
122
|
+
for a real feature, with a one-line reason. Major is a new start or direction and needs the owner's
|
|
123
|
+
fresh approval before tagging. A breaking change refuses until it is shimmed or made an approved
|
|
124
|
+
major. The [release](../../release/SKILL.md) skill names the exact switches.
|
|
121
125
|
A release announces itself in Slack once its deploy and publish are green: the Hub to the org alerts channel, a product to its own
|
|
122
126
|
project channel when the project's registry META sets `releaseChannel`; never post release notes
|
|
123
127
|
by hand. The Hub always needs a curated `--announce-summary-file`, and so does any product whose
|
package/skills/release/SKILL.md
CHANGED
|
@@ -7,6 +7,8 @@ description: Ship rc or direct-track development to main and production.
|
|
|
7
7
|
|
|
8
8
|
**Argument:** `/release minor`, `/release major`, or `/release patch` — a bare bump word, never a `--flag` or env var. No argument → `patch`; a `/release patch` from development is a legitimate ordinary release, `/hotfix` stays the cherry-pick promotion lane.
|
|
9
9
|
|
|
10
|
+
**Bump rules** ([docs/versioning.md](../../docs/versioning.md)): patch is the default and needs nothing. `minor` only for a real feature or significant change, with a one-line reason exported as `MMI_BUMP_REASON`. `major` only with Jervaise's fresh approval in this turn: export `MMI_BUMP_REASON` and `MMI_MAJOR_APPROVED=<exact target version>` (e.g. `5.0.0`) only after that approval, never earlier or from a prior turn. A breaking signal in the range (`feat!:`, `BREAKING CHANGE:`) makes the train refuse until it is shimmed (patch) or declared an owner-gated major.
|
|
11
|
+
|
|
10
12
|
# /release — ship to main + prod
|
|
11
13
|
|
|
12
14
|
Full-track repos ship exactly what is on `rc` (never `development`): merge `rc → main`, tag `vX.Y.0`, publish the GitHub Release, deploy prod, roll `development` forward. Direct-track repos ship `development → main`, and the release event fires the repo's own deploy/publish workflow (MMI-Hub: `deploy.yml` + `publish.yml`). `rc` is ephemeral: `/rcand` creates its runtime, `/release` retires it after a confirmed prod deploy (`rcRetirement`). A prod release needs the authorized human's explicit go in the current turn — an agent never self-initiates it. The board needs no touch: items reached `Done` when their PRs merged to `development`.
|