@mutmutco/claude-plugin 4.6.12 → 4.6.13
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
|
@@ -1674,6 +1674,7 @@ __export(board_write_exports, {
|
|
|
1674
1674
|
BoardAttachError: () => BoardAttachError,
|
|
1675
1675
|
addIssueToProjectViaHub: () => addIssueToProjectViaHub,
|
|
1676
1676
|
boardAttachHttpError: () => boardAttachHttpError,
|
|
1677
|
+
createBoardIssueViaHub: () => createBoardIssueViaHub,
|
|
1677
1678
|
writeHubBoardField: () => writeHubBoardField
|
|
1678
1679
|
});
|
|
1679
1680
|
async function writeHubBoardField(request) {
|
|
@@ -1715,6 +1716,18 @@ function boardAttachHttpError(status, detail) {
|
|
|
1715
1716
|
const code = status === 401 ? "hub_session_missing" : status === 403 ? "forbidden" : status === 429 ? "rate_limited" : status >= 500 ? "hub_unavailable" : "refused";
|
|
1716
1717
|
return new BoardAttachError(code, status, detail);
|
|
1717
1718
|
}
|
|
1719
|
+
async function createBoardIssueViaHub(request) {
|
|
1720
|
+
const config = await loadConfig();
|
|
1721
|
+
const res = await fetch(`${config.sagaApiUrl?.replace(/\/$/, "")}/board/issues`, {
|
|
1722
|
+
method: "POST",
|
|
1723
|
+
headers: await hubHeaders({ "content-type": "application/json" }),
|
|
1724
|
+
body: JSON.stringify(request),
|
|
1725
|
+
signal: AbortSignal.timeout(25e3)
|
|
1726
|
+
});
|
|
1727
|
+
const body = await res.json().catch(() => null);
|
|
1728
|
+
if (!res.ok || !body?.number || !body.url) throw new Error(`board issue create HTTP ${res.status}: ${body?.error ?? "unconfirmed result"}`);
|
|
1729
|
+
return { number: body.number, url: body.url, projectItemId: body.projectItemId, onBoard: Boolean(body.onBoard) };
|
|
1730
|
+
}
|
|
1718
1731
|
var BOARD_ATTACH_HINTS, BoardAttachError;
|
|
1719
1732
|
var init_board_write = __esm({
|
|
1720
1733
|
"src/board-write.ts"() {
|
|
@@ -1723,7 +1736,7 @@ var init_board_write = __esm({
|
|
|
1723
1736
|
BOARD_ATTACH_HINTS = {
|
|
1724
1737
|
// #8965: honest, not a promise — attach did NOT run. App automation never has a Hub session by design.
|
|
1725
1738
|
hub_session_missing: "No Hub session (an App installation token cannot open one). Hub adds new issues in registered repos to their board automatically when they are opened; check membership with `mmi-cli oracle board show <n> --repo <owner/repo>`. A human login or MMI_HUB_TOKEN (Actions /auth/session-ci) is needed only to attach older or transferred issues.",
|
|
1726
|
-
forbidden: "the Hub denied this login: attach needs org-owner
|
|
1739
|
+
forbidden: "the Hub denied this login: attach needs org-owner, repo-admin or verified repository write authority on <owner/repo>",
|
|
1727
1740
|
hub_unavailable: "the Hub or GitHub failed transiently; the add is idempotent, so rerun `mmi-cli oracle board attach <issue>`",
|
|
1728
1741
|
rate_limited: "GitHub quota is exhausted; rerun `mmi-cli oracle board attach <issue>` after the reset",
|
|
1729
1742
|
refused: "the Hub refused this attach; check the board registration for <owner/repo>"
|
|
@@ -27010,6 +27023,24 @@ async function reconcileOrgNoAgentFilesRuleset(plan, client, org = ORG_LOGIN) {
|
|
|
27010
27023
|
};
|
|
27011
27024
|
}
|
|
27012
27025
|
|
|
27026
|
+
// src/registry-repositories.ts
|
|
27027
|
+
function qualifyRegistryRepo(raw) {
|
|
27028
|
+
return raw.includes("/") ? raw : `mutmutco/${raw}`;
|
|
27029
|
+
}
|
|
27030
|
+
function registryRepoKey(repo) {
|
|
27031
|
+
return repo.toLowerCase();
|
|
27032
|
+
}
|
|
27033
|
+
function repoProjectClaim(project2, repoKey) {
|
|
27034
|
+
if (!project2) return 0;
|
|
27035
|
+
const slug = typeof project2.slug === "string" ? project2.slug.toLowerCase() : void 0;
|
|
27036
|
+
if (slug !== void 0 && slug === repoKey.split("/")[1]) return 3;
|
|
27037
|
+
if (project2.projectType !== "hub-service") return 2;
|
|
27038
|
+
return 1;
|
|
27039
|
+
}
|
|
27040
|
+
function preferPrimaryRepoProject(current, candidate, repoKey) {
|
|
27041
|
+
return repoProjectClaim(candidate, repoKey) > repoProjectClaim(current, repoKey) ? candidate : current;
|
|
27042
|
+
}
|
|
27043
|
+
|
|
27013
27044
|
// src/safe-json.ts
|
|
27014
27045
|
function safeJson(text, fallback) {
|
|
27015
27046
|
try {
|
|
@@ -27291,17 +27322,23 @@ async function auditOrgAccess(targets, deps, matrix = {}, dataAccess, sanctioned
|
|
|
27291
27322
|
}
|
|
27292
27323
|
function loadAccessTargets(projectsJson) {
|
|
27293
27324
|
const projects = safeJson(projectsJson, {}).projects ?? [];
|
|
27294
|
-
const
|
|
27295
|
-
const targets = [];
|
|
27325
|
+
const byRepo = /* @__PURE__ */ new Map();
|
|
27296
27326
|
for (const project2 of projects) {
|
|
27297
27327
|
for (const repo of project2.repos ?? []) {
|
|
27298
|
-
|
|
27299
|
-
|
|
27300
|
-
|
|
27301
|
-
|
|
27302
|
-
|
|
27328
|
+
const key = repo.toLowerCase();
|
|
27329
|
+
const existing = byRepo.get(key);
|
|
27330
|
+
byRepo.set(key, {
|
|
27331
|
+
repo: existing?.repo ?? repo,
|
|
27332
|
+
project: preferPrimaryRepoProject(existing?.project, project2, key)
|
|
27333
|
+
});
|
|
27303
27334
|
}
|
|
27304
27335
|
}
|
|
27336
|
+
const targets = [];
|
|
27337
|
+
for (const { repo, project: project2 } of byRepo.values()) {
|
|
27338
|
+
const cls = project2.class === "content" || project2.deployModel === "content" ? "content" : "deployable";
|
|
27339
|
+
const releaseTrack = cls === "content" ? "trunk" : resolveReleaseTrack(project2, void 0, repo);
|
|
27340
|
+
targets.push({ repo, class: cls, releaseTrack });
|
|
27341
|
+
}
|
|
27305
27342
|
return targets;
|
|
27306
27343
|
}
|
|
27307
27344
|
function resolveOrgAuditTargets(registryProjects) {
|
|
@@ -27665,10 +27702,10 @@ var rollout_plan_default = {
|
|
|
27665
27702
|
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)."
|
|
27666
27703
|
},
|
|
27667
27704
|
baseline: {
|
|
27668
|
-
version: "4.6.
|
|
27669
|
-
tag: "v4.6.
|
|
27670
|
-
commit: "
|
|
27671
|
-
npm: "@mutmutco/cli@4.6.
|
|
27705
|
+
version: "4.6.13",
|
|
27706
|
+
tag: "v4.6.13",
|
|
27707
|
+
commit: "70ee5f41b61b",
|
|
27708
|
+
npm: "@mutmutco/cli@4.6.13"
|
|
27672
27709
|
},
|
|
27673
27710
|
exitCriterion: "fleet-n-of-n",
|
|
27674
27711
|
hubOnlyShortcut: "forbidden",
|
|
@@ -27685,14 +27722,14 @@ var rollout_plan_default = {
|
|
|
27685
27722
|
repo: "mutmutco/mmi-hub",
|
|
27686
27723
|
role: "canary",
|
|
27687
27724
|
schedule: "train",
|
|
27688
|
-
v3Target: "v4.6.
|
|
27725
|
+
v3Target: "v4.6.13"
|
|
27689
27726
|
}
|
|
27690
27727
|
],
|
|
27691
27728
|
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.",
|
|
27692
27729
|
rollback: {
|
|
27693
27730
|
independent: true,
|
|
27694
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
27695
|
-
v3Target: "v4.6.
|
|
27731
|
+
mechanism: "npm dist-tag latest -> 4.6.13 and redeploy the Hub Lambda from tag v4.6.13 (70ee5f41b61b); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
27732
|
+
v3Target: "v4.6.13 (@mutmutco/cli@4.6.13, tag commit 70ee5f41b61b \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
27696
27733
|
}
|
|
27697
27734
|
},
|
|
27698
27735
|
{
|
|
@@ -27923,7 +27960,10 @@ function buildOrgVersionsReport(projects, probes, generatedAt) {
|
|
|
27923
27960
|
name: String(project2.name ?? project2.slug ?? "?")
|
|
27924
27961
|
});
|
|
27925
27962
|
}
|
|
27926
|
-
for (const repo of repos2)
|
|
27963
|
+
for (const repo of repos2) {
|
|
27964
|
+
const key = repo.trim().toLowerCase();
|
|
27965
|
+
projectByRepo.set(key, preferPrimaryRepoProject(projectByRepo.get(key), project2, key));
|
|
27966
|
+
}
|
|
27927
27967
|
}
|
|
27928
27968
|
const repos = orgVersionRepos(projects).map((repo) => {
|
|
27929
27969
|
const project2 = projectByRepo.get(repo.toLowerCase());
|
|
@@ -28942,7 +28982,7 @@ function buildFleetTrackInventory(projects, releaseProbes, pluginProbes, generat
|
|
|
28942
28982
|
}
|
|
28943
28983
|
for (const repo of repos2) {
|
|
28944
28984
|
const key = repo.trim().toLowerCase();
|
|
28945
|
-
projectByRepo.set(key, projectByRepo.get(key)
|
|
28985
|
+
projectByRepo.set(key, preferPrimaryRepoProject(projectByRepo.get(key), project2, key));
|
|
28946
28986
|
}
|
|
28947
28987
|
}
|
|
28948
28988
|
const repos = orgVersionRepos(projects).map((repo) => {
|
|
@@ -29030,15 +29070,16 @@ function defaultFleetTrackInventoryDeps(consistent = false) {
|
|
|
29030
29070
|
async function readFleetTrackInventory(deps = defaultFleetTrackInventoryDeps()) {
|
|
29031
29071
|
const projects = await deps.projects();
|
|
29032
29072
|
const repos = orgVersionRepos(projects);
|
|
29033
|
-
const
|
|
29073
|
+
const projectByRepo = /* @__PURE__ */ new Map();
|
|
29034
29074
|
for (const project2 of projects) {
|
|
29035
29075
|
for (const repo of (project2.repos ?? []).filter(validRepo2)) {
|
|
29036
29076
|
const key = repo.trim().toLowerCase();
|
|
29037
|
-
|
|
29038
|
-
branchByRepo.set(key, typeof project2.branch === "string" ? project2.branch : void 0);
|
|
29039
|
-
}
|
|
29077
|
+
projectByRepo.set(key, preferPrimaryRepoProject(projectByRepo.get(key), project2, key));
|
|
29040
29078
|
}
|
|
29041
29079
|
}
|
|
29080
|
+
const branchByRepo = new Map(
|
|
29081
|
+
[...projectByRepo].map(([key, project2]) => [key, typeof project2.branch === "string" ? project2.branch : void 0])
|
|
29082
|
+
);
|
|
29042
29083
|
const [releaseProbes, pluginProbes, onboardingProbes] = await Promise.all([
|
|
29043
29084
|
mapBounded2(repos, 6, (repo) => readOrgVersionProbe(deps.query, repo)),
|
|
29044
29085
|
mapBounded2(repos, 6, (repo) => readFleetPluginProbe(deps.query, repo, branchByRepo.get(repo.toLowerCase()))),
|
|
@@ -39110,14 +39151,6 @@ function renderPinDiffs(tick) {
|
|
|
39110
39151
|
return tick.diffs.map((d) => [`${d.repo}:`, ...d.files.flatMap((f) => f.changes.map((c) => ` ${f.path}:${c.line} ${c.action} ${c.from === "development" ? "@development" : c.from.slice(0, 12)} -> ${c.to.slice(0, 12)}`))].join("\n")).join("\n");
|
|
39111
39152
|
}
|
|
39112
39153
|
|
|
39113
|
-
// src/registry-repositories.ts
|
|
39114
|
-
function qualifyRegistryRepo(raw) {
|
|
39115
|
-
return raw.includes("/") ? raw : `mutmutco/${raw}`;
|
|
39116
|
-
}
|
|
39117
|
-
function registryRepoKey(repo) {
|
|
39118
|
-
return repo.toLowerCase();
|
|
39119
|
-
}
|
|
39120
|
-
|
|
39121
39154
|
// src/ci-audit.ts
|
|
39122
39155
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
39123
39156
|
var HUB_REPO5 = "mutmutco/MMI-Hub";
|
|
@@ -39426,6 +39459,11 @@ function rulesetStatusChecks(rulesets) {
|
|
|
39426
39459
|
function sortedUnique(values) {
|
|
39427
39460
|
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
39428
39461
|
}
|
|
39462
|
+
function isGitHub404(e) {
|
|
39463
|
+
const err = e;
|
|
39464
|
+
if (err?.status === 404) return true;
|
|
39465
|
+
return /\b404\b|\bnot found\b/i.test(String(err?.message ?? ""));
|
|
39466
|
+
}
|
|
39429
39467
|
async function restJson2(deps, path2, fallback) {
|
|
39430
39468
|
try {
|
|
39431
39469
|
return await deps.client.rest("GET", path2) ?? fallback;
|
|
@@ -39795,7 +39833,23 @@ async function auditRepoCi(repo, callerDeps) {
|
|
|
39795
39833
|
const registryRequiredChecks = meta?.requiredChecks;
|
|
39796
39834
|
const explicitNoCi = registryCi === "none" || registryRequiredChecks === null || Array.isArray(registryRequiredChecks) && registryRequiredChecks.length === 0;
|
|
39797
39835
|
const deployableGated = repoClass === "deployable" && !explicitNoCi;
|
|
39798
|
-
|
|
39836
|
+
let info;
|
|
39837
|
+
try {
|
|
39838
|
+
info = await deps.client.rest("GET", `repos/${repo}`) ?? {};
|
|
39839
|
+
} catch (e) {
|
|
39840
|
+
if (isGitHub404(e)) {
|
|
39841
|
+
return {
|
|
39842
|
+
repo,
|
|
39843
|
+
class: repoClass,
|
|
39844
|
+
mergePolicy: "wait-for-checks",
|
|
39845
|
+
ok: false,
|
|
39846
|
+
checks: [],
|
|
39847
|
+
explicitNoCi,
|
|
39848
|
+
excludedReason: "GitHub repository returned 404 (not found)"
|
|
39849
|
+
};
|
|
39850
|
+
}
|
|
39851
|
+
info = {};
|
|
39852
|
+
}
|
|
39799
39853
|
if (info.archived === true) {
|
|
39800
39854
|
return {
|
|
39801
39855
|
repo,
|
|
@@ -41876,8 +41930,9 @@ async function runPrLandOnce(prNumber, options, deps) {
|
|
|
41876
41930
|
if (!verdict.ok) {
|
|
41877
41931
|
return { ...base, error: `train authority unavailable: ${verdict.error}` };
|
|
41878
41932
|
}
|
|
41879
|
-
base.train = { role: verdict.authority.role, train: verdict.authority.train };
|
|
41880
|
-
|
|
41933
|
+
base.train = { role: verdict.authority.role, train: verdict.authority.train, ...verdict.authority.developmentMerge !== void 0 ? { developmentMerge: verdict.authority.developmentMerge } : {} };
|
|
41934
|
+
const canMerge = verdict.authority.train || resolved.base === "development" && verdict.authority.developmentMerge === true;
|
|
41935
|
+
if (!canMerge) {
|
|
41881
41936
|
return {
|
|
41882
41937
|
...base,
|
|
41883
41938
|
error: `@${verdict.authority.login ?? "caller"} is ${verdict.authority.role} \u2014 train not authorized on ${repo}; cannot land PR`
|
|
@@ -48676,7 +48731,11 @@ async function propagationScope(classes, what) {
|
|
|
48676
48731
|
} catch (e) {
|
|
48677
48732
|
return fail(e.message);
|
|
48678
48733
|
}
|
|
48679
|
-
const bySlugMeta =
|
|
48734
|
+
const bySlugMeta = /* @__PURE__ */ new Map();
|
|
48735
|
+
for (const p of projects) for (const r of p.repos ?? []) {
|
|
48736
|
+
const key = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
48737
|
+
bySlugMeta.set(key, preferPrimaryRepoProject(bySlugMeta.get(key), p, key));
|
|
48738
|
+
}
|
|
48680
48739
|
const classOf = (repo) => bySlugMeta.get(repo.toLowerCase())?.class ?? "deployable";
|
|
48681
48740
|
const seedClasses = classes ?? [...new Set(rosterRepos.map(classOf))];
|
|
48682
48741
|
const inClassRepos = rosterRepos.filter((repo) => seedClasses.includes(classOf(repo)));
|
|
@@ -48889,13 +48948,12 @@ function registerBootstrapCommands(program3) {
|
|
|
48889
48948
|
return failGraceful("bootstrap drift: the registry roster is unreadable or empty \u2014 refusing to report a fleet verdict from a scope this command could not establish (#3808)");
|
|
48890
48949
|
}
|
|
48891
48950
|
targets = collectRegistryRepos(projects);
|
|
48892
|
-
const byRepo = /* @__PURE__ */ new Map();
|
|
48893
48951
|
const metaByRepo = /* @__PURE__ */ new Map();
|
|
48894
48952
|
for (const p of projects) for (const r of p.repos ?? []) {
|
|
48895
48953
|
const key = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
48896
|
-
|
|
48897
|
-
metaByRepo.set(key, p);
|
|
48954
|
+
metaByRepo.set(key, preferPrimaryRepoProject(metaByRepo.get(key), p, key));
|
|
48898
48955
|
}
|
|
48956
|
+
const byRepo = new Map([...metaByRepo].map(([key, p]) => [key, p.class ?? "deployable"]));
|
|
48899
48957
|
classOf = (repo) => byRepo.get(repo.toLowerCase()) ?? "deployable";
|
|
48900
48958
|
metaOf = (repo) => metaByRepo.get(repo.toLowerCase()) ?? null;
|
|
48901
48959
|
}
|
|
@@ -55094,6 +55152,9 @@ async function openSuitePinPr(deps, input) {
|
|
|
55094
55152
|
}
|
|
55095
55153
|
}
|
|
55096
55154
|
|
|
55155
|
+
// src/command-register-collaboration.ts
|
|
55156
|
+
init_board_write();
|
|
55157
|
+
|
|
55097
55158
|
// src/pr-title-check.ts
|
|
55098
55159
|
var CONVENTIONAL_PR_TITLE = /^(feat|fix|docs|chore|refactor|perf|test|build|ci|revert|style)(\([^)]+\))?!?: .+/;
|
|
55099
55160
|
var EXEMPT_PR_TITLE = /^Merge pull request /;
|
|
@@ -59500,8 +59561,25 @@ function registerCollaborationCommands(program3) {
|
|
|
59500
59561
|
}
|
|
59501
59562
|
if (refusal && !surfaceWaived()) return fail(refusal.message, refusal.payload);
|
|
59502
59563
|
}
|
|
59503
|
-
|
|
59504
|
-
|
|
59564
|
+
let created;
|
|
59565
|
+
try {
|
|
59566
|
+
await ensureLabelsExist(extraLabels, targetRepo2);
|
|
59567
|
+
created = await ghCreate(args);
|
|
59568
|
+
} catch (error) {
|
|
59569
|
+
if (o.parent !== void 0 || !/Could not resolve to a Repository|HTTP 404|Not Found/i.test(error.message)) throw error;
|
|
59570
|
+
const filed = await createBoardIssueViaHub({ repo: targetRepo2, title, body, type: issueType, priority, labels: extraLabels });
|
|
59571
|
+
const nextStep = filed.onBoard ? void 0 : `mmi-cli oracle board attach ${targetRepo2}#${filed.number}`;
|
|
59572
|
+
console.log(JSON.stringify({
|
|
59573
|
+
status: filed.onBoard ? "created" : "partial",
|
|
59574
|
+
...filed,
|
|
59575
|
+
label: issueType,
|
|
59576
|
+
priority,
|
|
59577
|
+
credential: "app",
|
|
59578
|
+
...nextStep ? { boardAttach: "failed", nextStep, nextSteps: [nextStep] } : {},
|
|
59579
|
+
...surfaceInferred ? { surface_inferred: true, surface: surfaceInferred.label, surface_reason: surfaceInferred.reason } : {}
|
|
59580
|
+
}));
|
|
59581
|
+
return;
|
|
59582
|
+
}
|
|
59505
59583
|
if (isGhCreateRateLimited(created)) {
|
|
59506
59584
|
console.log(JSON.stringify(created));
|
|
59507
59585
|
process.exitCode = 1;
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -4,6 +4,10 @@ GitHub repository admins hold project-admin authority on their own projects with
|
|
|
4
4
|
registry enrollment. Registry-listed admins with repository write access remain supported.
|
|
5
5
|
Use `mmi-cli oracle org access role <owner/repo> --json` to verify authority for release,
|
|
6
6
|
candidate, hotfix, and runtime operations. Organization membership role alone is not this check.
|
|
7
|
+
Verified repository writers (GitHub write, maintain or admin) may land PRs targeting `development`
|
|
8
|
+
on non-Hub repositories. `/train-authority` reports this separately as `developmentMerge`;
|
|
9
|
+
it does not grant release, candidate, hotfix or runtime train authority. MMI-Hub development
|
|
10
|
+
merges remain master-only.
|
|
7
11
|
The Hub distribution train remains organization-master-only. It runs in the `hub-release` workflow on
|
|
8
12
|
our self-hosted runners, dispatched by an org owner, never on a workstation (#9137).
|
|
9
13
|
A 503 `github-rate-limited` answer means the org App's hourly GitHub allowance is used up. It is
|