@mutmutco/cli 2.38.1 → 2.38.2
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 +41 -3
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -8656,6 +8656,10 @@ function gateConfigToVars(gate) {
|
|
|
8656
8656
|
if (typeof gate.pyVersion === "string" && gate.pyVersion.trim()) out.GATE_PY_VERSION = gate.pyVersion;
|
|
8657
8657
|
return out;
|
|
8658
8658
|
}
|
|
8659
|
+
function seedMatchesDeployModel(seed, deployModel) {
|
|
8660
|
+
if (!seed.deployModels?.length) return true;
|
|
8661
|
+
return deployModel != null && seed.deployModels.includes(deployModel);
|
|
8662
|
+
}
|
|
8659
8663
|
function planSeedAction(seed, exists) {
|
|
8660
8664
|
if (seed.source === "fanout") {
|
|
8661
8665
|
return { target: seed.target, action: "skip", ownership: "fanout", reason: "delivered by the fanout pipeline" };
|
|
@@ -11877,6 +11881,20 @@ async function reconcileDirtyOrgSpineBeforePull(deps, branch, options = {}) {
|
|
|
11877
11881
|
return reconciled;
|
|
11878
11882
|
}
|
|
11879
11883
|
|
|
11884
|
+
// src/git-clean-tree.ts
|
|
11885
|
+
function isAgentScratchPath(path2) {
|
|
11886
|
+
const normalized = path2.replace(/\\/g, "/").trim();
|
|
11887
|
+
return normalized === ".mmi" || normalized.startsWith(".mmi/");
|
|
11888
|
+
}
|
|
11889
|
+
function porcelainHasBlockingChanges(porcelain) {
|
|
11890
|
+
return porcelain.split("\n").some((line) => {
|
|
11891
|
+
const trimmed = line.trim();
|
|
11892
|
+
if (!trimmed) return false;
|
|
11893
|
+
const path2 = trimmed.slice(3).split(" -> ")[0]?.trim() ?? "";
|
|
11894
|
+
return path2 !== "" && !isAgentScratchPath(path2);
|
|
11895
|
+
});
|
|
11896
|
+
}
|
|
11897
|
+
|
|
11880
11898
|
// src/train-apply.ts
|
|
11881
11899
|
function resolveDeployModel2(meta, repo) {
|
|
11882
11900
|
const m = meta?.deployModel;
|
|
@@ -12032,7 +12050,7 @@ function commandAuthorityLabel(owner) {
|
|
|
12032
12050
|
}
|
|
12033
12051
|
async function requireCleanTree(deps) {
|
|
12034
12052
|
const status = await deps.run("git", ["status", "--porcelain"]);
|
|
12035
|
-
if (status
|
|
12053
|
+
if (porcelainHasBlockingChanges(status)) throw new Error("working tree must be clean before train apply");
|
|
12036
12054
|
}
|
|
12037
12055
|
async function requireBranch(deps, branch) {
|
|
12038
12056
|
const current = clean2(await deps.run("git", ["rev-parse", "--abbrev-ref", "HEAD"]));
|
|
@@ -13041,7 +13059,7 @@ async function runHotfixStart(deps, options) {
|
|
|
13041
13059
|
const ctx = await buildTrainApplyContext(deps);
|
|
13042
13060
|
const deployModel = await resolveHotfixDeployModel(deps, ctx);
|
|
13043
13061
|
const status = await deps.run("git", ["status", "--porcelain"]);
|
|
13044
|
-
if (status
|
|
13062
|
+
if (porcelainHasBlockingChanges(status)) throw new Error("working tree must be clean before hotfix start");
|
|
13045
13063
|
await deps.run("git", ["fetch", "origin", "--tags"]);
|
|
13046
13064
|
const { tag, version } = await deriveHotfixVersion(deps);
|
|
13047
13065
|
const branch = hotfixBranch(tag);
|
|
@@ -13154,7 +13172,7 @@ async function runHotfixRelease(deps, versionInput, options = {}) {
|
|
|
13154
13172
|
const deployModel = await resolveHotfixDeployModel(deps, ctx);
|
|
13155
13173
|
const { tag, version } = normalizeHotfixVersion(versionInput);
|
|
13156
13174
|
const status = await deps.run("git", ["status", "--porcelain"]);
|
|
13157
|
-
if (status
|
|
13175
|
+
if (porcelainHasBlockingChanges(status)) throw new Error("working tree must be clean before hotfix release");
|
|
13158
13176
|
await deps.run("git", ["fetch", "origin", "--tags"]);
|
|
13159
13177
|
const pr2 = await findHotfixPr(deps, ctx, tag);
|
|
13160
13178
|
if (!pr2) throw new Error(`no hotfix PR found for ${tag} (head ${hotfixBranch(tag)}, base main) \u2014 run mmi-cli hotfix start first`);
|
|
@@ -14029,6 +14047,15 @@ async function verifyBootstrap(repo, repoClass, deps, releaseTrack) {
|
|
|
14029
14047
|
const trainScript = "scripts/next-version.mjs";
|
|
14030
14048
|
checks.push({ ok: await contentExists2(deps, repo, baseBranch, trainScript), label: `train tooling script exists: ${trainScript}` });
|
|
14031
14049
|
}
|
|
14050
|
+
if (repoClass === "deployable" && deps.deployModel === "tenant-container") {
|
|
14051
|
+
for (const path2 of ["docker-compose.yml", "Dockerfile"]) {
|
|
14052
|
+
checks.push({
|
|
14053
|
+
ok: await contentExists2(deps, repo, baseBranch, path2),
|
|
14054
|
+
label: `tenant-container runtime file exists: ${path2}`,
|
|
14055
|
+
detail: `bootstrap seeds ${path2} for deployModel tenant-container \u2014 see docs/Guides/tenant-runtime.md`
|
|
14056
|
+
});
|
|
14057
|
+
}
|
|
14058
|
+
}
|
|
14032
14059
|
checks.push({ ok: await contentExists2(deps, repo, baseBranch, ".cursor/environment.json"), label: "Cursor environment committed" });
|
|
14033
14060
|
const readme = await contentText(deps, repo, baseBranch, "README.md");
|
|
14034
14061
|
checks.push({
|
|
@@ -18264,6 +18291,7 @@ bootstrap.command("verify <repo>").description("audit whether an existing repo i
|
|
|
18264
18291
|
const report = await verifyBootstrap(repo, o.class, {
|
|
18265
18292
|
client: defaultGitHubClient(),
|
|
18266
18293
|
projectMeta: meta,
|
|
18294
|
+
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
18267
18295
|
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs19.existsSync)(path2) ? (0, import_node_fs19.readFileSync)(path2, "utf8") : null,
|
|
18268
18296
|
// requiredGcpApis is stored as an array by a JSON write, but `project set --var KEY=VALUE` stores a raw
|
|
18269
18297
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
@@ -18335,8 +18363,18 @@ bootstrap.command("apply <repo>").description("idempotent seed apply from skills
|
|
|
18335
18363
|
}
|
|
18336
18364
|
const actions = [];
|
|
18337
18365
|
const applied = [];
|
|
18366
|
+
let applyDeployModel;
|
|
18367
|
+
try {
|
|
18368
|
+
applyDeployModel = buildRegisterPayload(repo, o.class, vars, {
|
|
18369
|
+
projectType: o.projectType || void 0,
|
|
18370
|
+
deployModel: o.deployModel || void 0,
|
|
18371
|
+
releaseTrack: o.releaseTrack || void 0
|
|
18372
|
+
}).deployModel;
|
|
18373
|
+
} catch {
|
|
18374
|
+
}
|
|
18338
18375
|
for (const seed of manifest.seeds) {
|
|
18339
18376
|
if (!seed.classes.includes(o.class)) continue;
|
|
18377
|
+
if (!seedMatchesDeployModel(seed, applyDeployModel)) continue;
|
|
18340
18378
|
const resolved = { ...seed, target: seed.target.replace("{{REPO_SLUG}}", slug) };
|
|
18341
18379
|
let exists = false;
|
|
18342
18380
|
let sha;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "2.38.
|
|
3
|
+
"version": "2.38.2",
|
|
4
4
|
"description": "MMI Future CLI — delivers the org rules (whole-file), plus saga and KB access. The cross-IDE engine the plugin's SessionStart hook drives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|