@mutmutco/cli 2.32.4 → 2.33.0
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 +139 -148
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -7229,7 +7229,7 @@ ${buildReportBody(body, sourceRepo)}`;
|
|
|
7229
7229
|
|
|
7230
7230
|
// src/skill-lesson.ts
|
|
7231
7231
|
var SKILL_LESSON_LABEL = "skill-lesson";
|
|
7232
|
-
var SKILL_NAMES = ["bootstrap", "browser-automation", "grind", "hotfix", "mmi", "rcand", "release", "secrets", "stage"];
|
|
7232
|
+
var SKILL_NAMES = ["bootstrap", "browser-automation", "build", "grind", "hotfix", "mmi", "rcand", "release", "secrets", "stage"];
|
|
7233
7233
|
function assertSkillName(name) {
|
|
7234
7234
|
const match = SKILL_NAMES.find((skill) => skill === name);
|
|
7235
7235
|
if (!match) throw new Error(`unknown skill "${name}" \u2014 expected one of: ${SKILL_NAMES.join(", ")}`);
|
|
@@ -7355,127 +7355,92 @@ function buildPanelPlan(input) {
|
|
|
7355
7355
|
};
|
|
7356
7356
|
}
|
|
7357
7357
|
|
|
7358
|
-
// src/
|
|
7359
|
-
var
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7358
|
+
// src/build-policy.ts
|
|
7359
|
+
var TIER_BUDGETS = {
|
|
7360
|
+
light: {
|
|
7361
|
+
tier: "light",
|
|
7362
|
+
agents: 2,
|
|
7363
|
+
planners: 0,
|
|
7364
|
+
parallelSitesCap: 1,
|
|
7365
|
+
verificationDepth: "panel-once",
|
|
7366
|
+
reasoningEffort: "standard"
|
|
7367
|
+
},
|
|
7368
|
+
standard: {
|
|
7369
|
+
tier: "standard",
|
|
7370
|
+
agents: 3,
|
|
7371
|
+
planners: 0,
|
|
7372
|
+
parallelSitesCap: 2,
|
|
7373
|
+
verificationDepth: "full-panel",
|
|
7374
|
+
reasoningEffort: "standard-high"
|
|
7375
|
+
},
|
|
7376
|
+
deep: {
|
|
7377
|
+
tier: "deep",
|
|
7378
|
+
agents: 4,
|
|
7379
|
+
planners: 2,
|
|
7380
|
+
parallelSitesCap: 3,
|
|
7381
|
+
verificationDepth: "full-double-pass",
|
|
7382
|
+
reasoningEffort: "high"
|
|
7383
|
+
},
|
|
7384
|
+
max: {
|
|
7385
|
+
tier: "max",
|
|
7386
|
+
agents: 5,
|
|
7387
|
+
planners: 3,
|
|
7388
|
+
parallelSitesCap: 4,
|
|
7389
|
+
verificationDepth: "integration-checkpoints",
|
|
7390
|
+
reasoningEffort: "max"
|
|
7391
|
+
}
|
|
7372
7392
|
};
|
|
7373
|
-
function
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7393
|
+
function getTierBudgets(tier) {
|
|
7394
|
+
return TIER_BUDGETS[tier];
|
|
7395
|
+
}
|
|
7396
|
+
function isWideOrArchitectural(scope) {
|
|
7397
|
+
return scope === "wide" || scope === "architectural";
|
|
7398
|
+
}
|
|
7399
|
+
function isCrossModuleOrProduct(blast) {
|
|
7400
|
+
return blast === "cross-module" || blast === "product";
|
|
7401
|
+
}
|
|
7402
|
+
function pickEffortTier(signals) {
|
|
7403
|
+
if (signals.explicitTier) {
|
|
7404
|
+
return {
|
|
7405
|
+
tier: signals.explicitTier,
|
|
7406
|
+
reason: `explicit user override \u2192 ${signals.explicitTier}`,
|
|
7407
|
+
budgets: getTierBudgets(signals.explicitTier)
|
|
7408
|
+
};
|
|
7389
7409
|
}
|
|
7390
|
-
if (
|
|
7391
|
-
|
|
7410
|
+
if (signals.risk === "critical") {
|
|
7411
|
+
return { tier: "max", reason: "critical risk", budgets: getTierBudgets("max") };
|
|
7392
7412
|
}
|
|
7393
|
-
|
|
7394
|
-
webSearch: Boolean(input.toolPolicy?.webSearch),
|
|
7395
|
-
maxQueriesPerLens: input.toolPolicy?.maxQueriesPerLens ?? 3,
|
|
7396
|
-
denyDomains: input.toolPolicy?.denyDomains ?? []
|
|
7397
|
-
};
|
|
7398
|
-
return {
|
|
7399
|
-
provider,
|
|
7400
|
-
routing,
|
|
7401
|
-
lenses,
|
|
7402
|
-
models,
|
|
7403
|
-
toolPolicy,
|
|
7404
|
-
criteria: input.criteria,
|
|
7405
|
-
diff: input.diff,
|
|
7406
|
-
fallback: "host-panel",
|
|
7407
|
-
instructions: "Hosted fusion when provider is configured; else spawn host lenses and pipe JSON to `mmi-cli verify synthesize`. Synthesizer slot must differ from builder."
|
|
7408
|
-
};
|
|
7409
|
-
}
|
|
7410
|
-
function adaptFusionResponse(raw) {
|
|
7411
|
-
if (raw.lenses) {
|
|
7412
|
-
const lenses = parseLensResults(raw.lenses);
|
|
7413
|
-
const base2 = synthesizePanelReport(lenses);
|
|
7413
|
+
if (signals.foundational && (isWideOrArchitectural(signals.scope) || signals.blastRadius === "product")) {
|
|
7414
7414
|
return {
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
partial_coverage: raw.partial_coverage ?? base2.partial_coverage,
|
|
7419
|
-
unique_insights: raw.unique_insights ?? base2.unique_insights,
|
|
7420
|
-
blind_spots: raw.blind_spots ?? base2.blind_spots,
|
|
7421
|
-
nits: raw.nits ?? base2.nits
|
|
7415
|
+
tier: "max",
|
|
7416
|
+
reason: "foundational seam with wide/architectural scope or product blast radius",
|
|
7417
|
+
budgets: getTierBudgets("max")
|
|
7422
7418
|
};
|
|
7423
7419
|
}
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
title: b.title,
|
|
7427
|
-
file: b.file,
|
|
7428
|
-
line: b.line,
|
|
7429
|
-
why: b.why,
|
|
7430
|
-
sources: b.sources ?? ["hosted-fusion"]
|
|
7431
|
-
}));
|
|
7432
|
-
return {
|
|
7433
|
-
consensus: raw.consensus ?? [],
|
|
7434
|
-
contradictions: raw.contradictions ?? [],
|
|
7435
|
-
partial_coverage: raw.partial_coverage ?? [],
|
|
7436
|
-
unique_insights: raw.unique_insights ?? [],
|
|
7437
|
-
blind_spots: raw.blind_spots ?? [],
|
|
7438
|
-
blockers,
|
|
7439
|
-
nits: raw.nits ?? []
|
|
7440
|
-
};
|
|
7441
|
-
}
|
|
7442
|
-
async function runFusionProvider(plan2, deps = {}) {
|
|
7443
|
-
const url = resolveFusionProviderUrl(deps.providerUrl ?? plan2.provider ?? void 0);
|
|
7444
|
-
if (!url) {
|
|
7445
|
-
return { ok: false, source: "fallback", error: "no fusion provider configured" };
|
|
7420
|
+
if (signals.risk === "high") {
|
|
7421
|
+
return { tier: "deep", reason: "high risk", budgets: getTierBudgets("deep") };
|
|
7446
7422
|
}
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
const headers = { "content-type": "application/json" };
|
|
7450
|
-
if (apiKey) headers.authorization = `Bearer ${apiKey}`;
|
|
7451
|
-
try {
|
|
7452
|
-
const res = await fetchImpl(url, {
|
|
7453
|
-
method: "POST",
|
|
7454
|
-
headers,
|
|
7455
|
-
body: JSON.stringify({
|
|
7456
|
-
routing: plan2.routing,
|
|
7457
|
-
lenses: plan2.lenses,
|
|
7458
|
-
models: plan2.models,
|
|
7459
|
-
toolPolicy: plan2.toolPolicy,
|
|
7460
|
-
criteria: plan2.criteria,
|
|
7461
|
-
diff: plan2.diff
|
|
7462
|
-
}),
|
|
7463
|
-
signal: AbortSignal.timeout(3e4)
|
|
7464
|
-
});
|
|
7465
|
-
if (!res.ok) {
|
|
7466
|
-
return { ok: false, source: "fallback", error: `provider HTTP ${res.status}` };
|
|
7467
|
-
}
|
|
7468
|
-
const body = await res.json();
|
|
7469
|
-
return { ok: true, source: "hosted-fusion", report: adaptFusionResponse(body) };
|
|
7470
|
-
} catch (e) {
|
|
7471
|
-
return { ok: false, source: "fallback", error: e.message };
|
|
7423
|
+
if (signals.ambiguity === "high") {
|
|
7424
|
+
return { tier: "deep", reason: "high ambiguity", budgets: getTierBudgets("deep") };
|
|
7472
7425
|
}
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7426
|
+
if (signals.scope === "architectural") {
|
|
7427
|
+
return { tier: "deep", reason: "architectural scope", budgets: getTierBudgets("deep") };
|
|
7428
|
+
}
|
|
7429
|
+
if (isCrossModuleOrProduct(signals.blastRadius)) {
|
|
7430
|
+
return {
|
|
7431
|
+
tier: "deep",
|
|
7432
|
+
reason: `${signals.blastRadius} blast radius`,
|
|
7433
|
+
budgets: getTierBudgets("deep")
|
|
7434
|
+
};
|
|
7435
|
+
}
|
|
7436
|
+
if (signals.scope === "trivial" && signals.ambiguity === "low" && signals.risk === "low") {
|
|
7437
|
+
return {
|
|
7438
|
+
tier: "light",
|
|
7439
|
+
reason: "trivial scope with low risk and low ambiguity",
|
|
7440
|
+
budgets: getTierBudgets("light")
|
|
7441
|
+
};
|
|
7442
|
+
}
|
|
7443
|
+
return { tier: "standard", reason: "default \u2014 normal slice", budgets: getTierBudgets("standard") };
|
|
7479
7444
|
}
|
|
7480
7445
|
|
|
7481
7446
|
// src/gc.ts
|
|
@@ -10704,9 +10669,8 @@ async function runHotfixRelease(deps, versionInput, options = {}) {
|
|
|
10704
10669
|
if (releaseExists) {
|
|
10705
10670
|
releaseNote = `Release ${tag} already exists \u2014 resumed without recreating`;
|
|
10706
10671
|
} else {
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
releaseNote = `Release ${tag} created (target ${tagCommit.slice(0, 7)})`;
|
|
10672
|
+
await deps.run("gh", ["release", "create", tag, "--repo", ctx.repo, "--target", "main", "--generate-notes", "--latest"]);
|
|
10673
|
+
releaseNote = `Release ${tag} created (target main)`;
|
|
10710
10674
|
if (deps.announce) {
|
|
10711
10675
|
announceNote = (await deps.announce({ repo: ctx.repo, tag, summaryFile: options.announceSummaryFile })).note;
|
|
10712
10676
|
}
|
|
@@ -11561,6 +11525,13 @@ async function verifyBootstrap(repo, repoClass, deps, releaseTrack) {
|
|
|
11561
11525
|
ok: Boolean(config?.projectOwner && config?.projectNumber && config?.projectId && config?.statusFieldId && config?.statusOptions),
|
|
11562
11526
|
label: "registry project board META exists"
|
|
11563
11527
|
});
|
|
11528
|
+
if (config?.projectId && config.projectNumber == null) {
|
|
11529
|
+
checks.push({
|
|
11530
|
+
ok: false,
|
|
11531
|
+
label: "registry projectNumber present when projectId set",
|
|
11532
|
+
detail: "projectNumber is missing \u2014 bootstrap apply must pass PROJECT_NUMBER or derive it from the live board GraphQL query"
|
|
11533
|
+
});
|
|
11534
|
+
}
|
|
11564
11535
|
if (config?.projectOwner && config.projectNumber != null) {
|
|
11565
11536
|
const fieldsQuery = `query($login: String!, $number: Int!) { organization(login: $login) { projectV2(number: $number) { fields(first: 50) { nodes { ... on ProjectV2FieldCommon { id name } ... on ProjectV2SingleSelectField { id name options { id name } } } } } } }`;
|
|
11566
11537
|
const fields = await (async () => {
|
|
@@ -12187,6 +12158,25 @@ function boardRegistryGaps(meta) {
|
|
|
12187
12158
|
if (meta.projectNumber != null) return [];
|
|
12188
12159
|
return ["projectNumber"];
|
|
12189
12160
|
}
|
|
12161
|
+
function previewRegistryMetaMerge(existing, patch) {
|
|
12162
|
+
const out = { ...existing ?? {} };
|
|
12163
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
12164
|
+
if (value === null) delete out[key];
|
|
12165
|
+
else out[key] = value;
|
|
12166
|
+
}
|
|
12167
|
+
return out;
|
|
12168
|
+
}
|
|
12169
|
+
function boardLinkWriteError(patch, existing) {
|
|
12170
|
+
const patchHasProjectId = typeof patch.projectId === "string" && patch.projectId.length > 0;
|
|
12171
|
+
const patchHasProjectNumber = typeof patch.projectNumber === "number" && Number.isFinite(patch.projectNumber);
|
|
12172
|
+
if (patchHasProjectId && !patchHasProjectNumber && existing?.projectNumber == null) {
|
|
12173
|
+
return "projectId requires projectNumber in registry META \u2014 pass projectNumber with board coords";
|
|
12174
|
+
}
|
|
12175
|
+
if (patch.projectNumber === null && boardRegistryGaps(previewRegistryMetaMerge(existing, patch)).length) {
|
|
12176
|
+
return "projectId requires projectNumber in registry META \u2014 pass projectNumber with board coords";
|
|
12177
|
+
}
|
|
12178
|
+
return null;
|
|
12179
|
+
}
|
|
12190
12180
|
function boardRegistryGapMessage(repo) {
|
|
12191
12181
|
return `Board META incomplete for ${repo}: registry has projectId but no projectNumber \u2014 board claim and auto-add will fail until projectNumber is backfilled (re-run \`node infra/migrate/seed-registry.mjs\` or \`mmi-cli bootstrap apply --execute\` with board vars)`;
|
|
12192
12182
|
}
|
|
@@ -14404,6 +14394,9 @@ project.command("set [owner/repo]").description("MASTER-ONLY: upsert a project M
|
|
|
14404
14394
|
} catch (e) {
|
|
14405
14395
|
return fail(e.message.replace(/^project set: /, "project set: "));
|
|
14406
14396
|
}
|
|
14397
|
+
const existing = await fetchProjectBySlug(slug, registryClientDeps(cfg));
|
|
14398
|
+
const boardError = boardLinkWriteError(patch, existing);
|
|
14399
|
+
if (boardError) return fail(`project set: ${boardError}`);
|
|
14407
14400
|
const res = await upsertProject(slug, patch, registryClientDeps(cfg));
|
|
14408
14401
|
return reportWrite("project set", res);
|
|
14409
14402
|
});
|
|
@@ -14680,39 +14673,37 @@ verify.command("synthesize").description("merge lens JSON array into a PanelRepo
|
|
|
14680
14673
|
return fail(`verify synthesize: ${e.message}`);
|
|
14681
14674
|
}
|
|
14682
14675
|
});
|
|
14683
|
-
var
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
});
|
|
14702
|
-
console.log(
|
|
14703
|
-
} catch (e) {
|
|
14704
|
-
return fail(`verify fusion plan: ${e.message}`);
|
|
14676
|
+
var build = program2.command("build").description("Build skill helpers \u2014 effort-tier selection and milestone partitioning");
|
|
14677
|
+
build.command("tier").description("Recommend an effort tier (light|standard|deep|max) from scope/risk/ambiguity signals").option("--scope <s>", "trivial|narrow|normal|wide|architectural").option("--risk <r>", "low|medium|high|critical").option("--ambiguity <a>", "low|medium|high").option("--blast-radius <b>", "isolated|module|cross-module|product").option("--foundational", "touches shared seams").option("--explicit <t>", "force a tier: light|standard|deep|max").option("--json", "output JSON").action((opts) => {
|
|
14678
|
+
const signals = {
|
|
14679
|
+
scope: opts.scope,
|
|
14680
|
+
risk: opts.risk,
|
|
14681
|
+
ambiguity: opts.ambiguity,
|
|
14682
|
+
blastRadius: opts.blastRadius,
|
|
14683
|
+
foundational: opts.foundational ?? void 0,
|
|
14684
|
+
explicitTier: opts.explicit
|
|
14685
|
+
};
|
|
14686
|
+
const decision = pickEffortTier(signals);
|
|
14687
|
+
if (opts.json) console.log(JSON.stringify(decision, null, 2));
|
|
14688
|
+
else {
|
|
14689
|
+
console.log(`tier: ${decision.tier}`);
|
|
14690
|
+
console.log(`reason: ${decision.reason}`);
|
|
14691
|
+
console.log(`agents: ${decision.budgets.agents}`);
|
|
14692
|
+
console.log(`planners: ${decision.budgets.planners}`);
|
|
14693
|
+
console.log(`parallel: ${decision.budgets.parallelSitesCap} sites`);
|
|
14694
|
+
console.log(`verify: ${decision.budgets.verificationDepth}`);
|
|
14695
|
+
console.log(`reasoning: ${decision.budgets.reasoningEffort}`);
|
|
14705
14696
|
}
|
|
14706
14697
|
});
|
|
14707
|
-
|
|
14708
|
-
|
|
14709
|
-
|
|
14710
|
-
|
|
14711
|
-
|
|
14712
|
-
|
|
14713
|
-
|
|
14714
|
-
|
|
14715
|
-
|
|
14698
|
+
build.command("plan").description("Partition a set of issue refs into sites + waves (parallel/serialize/batch) for milestone construction").argument("[issues...]", "issue refs like owner/repo#N or #N").option("--json", "output JSON").action((issues, opts) => {
|
|
14699
|
+
const plan2 = {
|
|
14700
|
+
waves: issues.length > 0 ? [{ wave: 0, mode: "parallel", issues }] : [],
|
|
14701
|
+
note: issues.length === 0 ? "No issues provided." : "v1 partitioning: single parallel wave. Use grind --auto Phase 00 patterns for deeper analysis."
|
|
14702
|
+
};
|
|
14703
|
+
if (opts.json) console.log(JSON.stringify(plan2, null, 2));
|
|
14704
|
+
else {
|
|
14705
|
+
console.log(plan2.note);
|
|
14706
|
+
for (const w of plan2.waves) console.log(`wave ${w.wave} (${w.mode}): ${w.issues.join(" ")}`);
|
|
14716
14707
|
}
|
|
14717
14708
|
});
|
|
14718
14709
|
program2.command("skill-lesson").description("file a skill-lesson on the Hub board (GitHub auth, dedups open lessons) and print {number,url} JSON").requiredOption("--skill <name>", `which skill misfired (${SKILL_NAMES.join(" | ")})`).option("--title <title>", "one-line summary of what misfired").option("--title-file <path|->", "read the one-line summary from a UTF-8 file, or from stdin with -").option("--body <body>", "lesson body: what misfired, the evidence, and the proposed amendment (markdown)").option("--body-file <path|->", "read the lesson body from a UTF-8 file, or from stdin with -").option("--priority <priority>", "urgent | high | medium | low (board Priority field when configured)", "medium").option("--repo <owner/repo>", `target repo (defaults to the org Hub: ${HUB_REPO})`).option("--force", "file a new issue even when an open lesson looks like a duplicate").option("--json", "machine-readable output (already the default \u2014 skill-lesson always prints JSON)").action(async (o) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.33.0",
|
|
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",
|