@mutmutco/cli 4.4.4 → 4.4.6

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.
Files changed (2) hide show
  1. package/dist/main.cjs +194 -48
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -7288,37 +7288,71 @@ function pathWords(text) {
7288
7288
  function proseWords(text) {
7289
7289
  return text.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
7290
7290
  }
7291
+ function countWords(words) {
7292
+ const counts = /* @__PURE__ */ new Map();
7293
+ for (const w of words) counts.set(w, (counts.get(w) ?? 0) + 1);
7294
+ return counts;
7295
+ }
7296
+ var TITLE_WEIGHT = 3;
7297
+ var PATH_WEIGHT = 4;
7298
+ var BODY_WEIGHT = 1;
7291
7299
  function inferSurface(candidates, context = {}) {
7292
7300
  const sorted = [...candidates].sort();
7293
7301
  if (sorted.length === 0) throw new Error("inferSurface: no surface:* candidates to choose from");
7294
- const pWords = new Set(pathWords(context.body ?? ""));
7295
- const tWords = /* @__PURE__ */ new Set([...proseWords(context.title ?? ""), ...proseWords(context.body ?? "")]);
7302
+ const titleCounts = countWords(proseWords([context.title ?? "", context.type ?? ""].join(" ")));
7303
+ const pathCounts = countWords(pathWords(context.body ?? ""));
7304
+ const bodyCounts = countWords(proseWords(context.body ?? ""));
7305
+ const scoreOf = (label) => {
7306
+ let score = 0;
7307
+ let fromPath = false;
7308
+ let fromTitle = false;
7309
+ for (const word of surfaceWords(label)) {
7310
+ const title = titleCounts.get(word) ?? 0;
7311
+ const path2 = pathCounts.get(word) ?? 0;
7312
+ const body = bodyCounts.get(word) ?? 0;
7313
+ if (title > 0) fromTitle = true;
7314
+ if (path2 > 0) fromPath = true;
7315
+ score += title * TITLE_WEIGHT + path2 * PATH_WEIGHT + body * BODY_WEIGHT;
7316
+ }
7317
+ return { score, fromPath, fromTitle };
7318
+ };
7296
7319
  let best = sorted[0];
7297
7320
  let bestScore = 0;
7298
7321
  let bestFromPath = false;
7322
+ let bestFromTitle = false;
7323
+ const scores = /* @__PURE__ */ new Map();
7299
7324
  for (const label of sorted) {
7300
- const words = surfaceWords(label);
7301
- if (!words.length) continue;
7302
- const pathHits = words.filter((w) => pWords.has(w)).length;
7303
- const proseHits = words.filter((w) => tWords.has(w)).length;
7304
- const score = pathHits * 2 + proseHits;
7325
+ const { score, fromPath, fromTitle } = scoreOf(label);
7326
+ scores.set(label, score);
7305
7327
  if (score > bestScore) {
7306
7328
  bestScore = score;
7307
7329
  best = label;
7308
- bestFromPath = pathHits > 0;
7330
+ bestFromPath = fromPath;
7331
+ bestFromTitle = fromTitle;
7309
7332
  }
7310
7333
  }
7311
- if (bestScore === 0) {
7312
- return {
7313
- label: sorted[0],
7314
- reason: `no path or title/body word matched any of ${sorted.length} surface label(s) \u2014 defaulted to the alphabetically-first`
7315
- };
7316
- }
7334
+ const tied = sorted.filter((label) => (scores.get(label) ?? 0) === bestScore);
7335
+ const uncertain = bestScore === 0 || bestScore < TITLE_WEIGHT || tied.length > 1;
7336
+ const alternatives = uncertain ? sorted.filter((label) => label !== best && (scores.get(label) ?? 0) > 0).sort((a, b) => (scores.get(b) ?? 0) - (scores.get(a) ?? 0) || (a < b ? -1 : a > b ? 1 : 0)).slice(0, 3) : [];
7337
+ const reason = bestScore === 0 ? `no path or title/body word matched any of ${sorted.length} surface label(s) \u2014 defaulted to the alphabetically-first` : bestFromPath ? "matched a path mentioned in the issue body" : bestFromTitle ? "matched a word in the issue title/body" : "matched a word in the issue body";
7317
7338
  return {
7318
7339
  label: best,
7319
- reason: bestFromPath ? "matched a path mentioned in the issue body" : "matched a word in the issue title/body"
7340
+ reason,
7341
+ ...uncertain ? { uncertain: true } : {},
7342
+ ...alternatives.length ? { alternatives } : {}
7320
7343
  };
7321
7344
  }
7345
+ function surfaceInferenceSuffix(inferred) {
7346
+ if (!inferred.uncertain) return "";
7347
+ const alts = inferred.alternatives?.length ? ` Other candidates: ${inferred.alternatives.join(", ")}.` : "";
7348
+ return ` This pick is low-confidence \u2014 pass --surface <value> to choose explicitly.${alts}`;
7349
+ }
7350
+ function surfaceInferenceNote(inferred) {
7351
+ const base = `mmi-cli: no --surface given \u2014 filed under ${inferred.label} (${inferred.reason}).`;
7352
+ return inferred.uncertain ? `${base}${surfaceInferenceSuffix(inferred)}
7353
+ ` : `${base} Pass --surface to choose.
7354
+ `;
7355
+ }
7322
7356
  async function checkSurfaceRequirement(input, deps = {}) {
7323
7357
  if (input.waiver) {
7324
7358
  const reason = input.waiver.reason.trim();
@@ -7350,7 +7384,7 @@ async function checkSurfaceRequirement(input, deps = {}) {
7350
7384
  }
7351
7385
  if (known.length === 0) return { enforcing: false, taxonomyAbsent: true };
7352
7386
  if (labelsCarrySurface(input.labels)) return { enforcing: true };
7353
- return { enforcing: true, inferred: inferSurface(known, { title: input.title, body: input.body }) };
7387
+ return { enforcing: true, inferred: inferSurface(known, { title: input.title, type: input.type, body: input.body }) };
7354
7388
  }
7355
7389
  function conflictingSurfaceInputs(surfaceFlag, labels) {
7356
7390
  if (!surfaceFlag) return void 0;
@@ -15870,10 +15904,10 @@ var rollout_plan_default = {
15870
15904
  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)."
15871
15905
  },
15872
15906
  baseline: {
15873
- version: "4.4.4",
15874
- tag: "v4.4.4",
15875
- commit: "d35da22e2e0b",
15876
- npm: "@mutmutco/cli@4.4.4"
15907
+ version: "4.4.6",
15908
+ tag: "v4.4.6",
15909
+ commit: "640e312fac88",
15910
+ npm: "@mutmutco/cli@4.4.6"
15877
15911
  },
15878
15912
  exitCriterion: "fleet-n-of-n",
15879
15913
  hubOnlyShortcut: "forbidden",
@@ -15890,14 +15924,14 @@ var rollout_plan_default = {
15890
15924
  repo: "mutmutco/mmi-hub",
15891
15925
  role: "canary",
15892
15926
  schedule: "train",
15893
- v3Target: "v4.4.4"
15927
+ v3Target: "v4.4.6"
15894
15928
  }
15895
15929
  ],
15896
15930
  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.",
15897
15931
  rollback: {
15898
15932
  independent: true,
15899
- mechanism: "npm dist-tag latest -> 4.4.4 and redeploy the Hub Lambda from tag v4.4.4 (d35da22e2e0b); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15900
- v3Target: "v4.4.4 (@mutmutco/cli@4.4.4, tag commit d35da22e2e0b \u2014 last known-good release carrying the repo-index v4-only contract)"
15933
+ mechanism: "npm dist-tag latest -> 4.4.6 and redeploy the Hub Lambda from tag v4.4.6 (640e312fac88); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15934
+ v3Target: "v4.4.6 (@mutmutco/cli@4.4.6, tag commit 640e312fac88 \u2014 last known-good release carrying the repo-index v4-only contract)"
15901
15935
  }
15902
15936
  },
15903
15937
  {
@@ -22814,6 +22848,62 @@ async function waitForFoldIndexLock(deps, startBranch, resumeCommand) {
22814
22848
  await sleep2(Math.min(GIT_INDEX_LOCK_POLL_MS, Math.max(1, deadline - now())));
22815
22849
  }
22816
22850
  }
22851
+ function isIndexLockFailure(message2) {
22852
+ return /index\.lock/i.test(message2) && /File exists/i.test(message2);
22853
+ }
22854
+ async function clearFoldChildIndexLock(deps) {
22855
+ const lockPath = requireValue(
22856
+ clean2(await deps.run("git", ["rev-parse", "--git-path", "index.lock"])),
22857
+ "git index lock path"
22858
+ );
22859
+ try {
22860
+ await (0, import_promises3.unlink)(lockPath);
22861
+ } catch (e) {
22862
+ if (e.code === "ENOENT") return void 0;
22863
+ throw e;
22864
+ }
22865
+ return lockPath;
22866
+ }
22867
+ async function resetFoldMainWithStaleLockRetry(deps, preFoldMainSha, killedCause) {
22868
+ try {
22869
+ await deps.run("git", ["reset", "--hard", preFoldMainSha]);
22870
+ return { ok: true, lockNote: "" };
22871
+ } catch (firstError) {
22872
+ const firstMessage = firstError instanceof Error ? firstError.message : String(firstError);
22873
+ if (!isIndexLockFailure(firstMessage)) return { ok: false, error: firstError, lockNote: "" };
22874
+ if (!foldChildWasKilled(killedCause)) {
22875
+ return {
22876
+ ok: false,
22877
+ error: firstError,
22878
+ lockNote: "the git index lock was NOT removed \u2014 no killed fold child is attributable, so its holder may still be alive (resolve or wait it out, then retry)"
22879
+ };
22880
+ }
22881
+ let clearedLockPath;
22882
+ try {
22883
+ clearedLockPath = await clearFoldChildIndexLock(deps);
22884
+ } catch (e) {
22885
+ return {
22886
+ ok: false,
22887
+ error: firstError,
22888
+ lockNote: `the fold child's stale git index lock could not be removed: ${e instanceof Error ? e.message : String(e)}`
22889
+ };
22890
+ }
22891
+ if (!clearedLockPath) return { ok: false, error: firstError, lockNote: "" };
22892
+ try {
22893
+ await deps.run("git", ["reset", "--hard", preFoldMainSha]);
22894
+ return {
22895
+ ok: true,
22896
+ lockNote: `removed the stale git index lock ${clearedLockPath} left by the fold child the train killed (signal), then retried the reset`
22897
+ };
22898
+ } catch (retryError) {
22899
+ return {
22900
+ ok: false,
22901
+ error: retryError,
22902
+ lockNote: `removed the stale git index lock ${clearedLockPath} left by the fold child the train killed (signal) and retried the reset once, which failed again`
22903
+ };
22904
+ }
22905
+ }
22906
+ }
22817
22907
  async function recoverFailedRcand(deps, cause, preRcSha) {
22818
22908
  const causeMessage = cause instanceof Error ? cause.message : String(cause);
22819
22909
  const branch = await currentBranch(deps).catch(() => "");
@@ -22857,10 +22947,13 @@ Recovery sequence:
22857
22947
  3. mmi-cli devops rcand --apply`
22858
22948
  );
22859
22949
  }
22950
+ function foldChildWasKilled(causeMessage) {
22951
+ return /\bSIGTERM\b|was killed \(signal/.test(causeMessage);
22952
+ }
22860
22953
  function foldFailureAnchor(causeMessage) {
22861
- if (/\bSIGTERM\b|was killed \(signal/.test(causeMessage)) return "docs/Guides/train-troubleshooting.md#fold-npm-ci-sigterm";
22862
- if (/\bEPERM\b|\bEBUSY\b/.test(causeMessage)) return "docs/Guides/train-troubleshooting.md#fold-eperm-ebusy";
22863
- if (/^(?:npm|node) .* failed\b/.test(causeMessage)) return "docs/Guides/train-troubleshooting.md#fold-lifecycle-script";
22954
+ if (foldChildWasKilled(causeMessage)) return troubleshootingAnchor("fold-npm-ci-sigterm");
22955
+ if (/\bEPERM\b|\bEBUSY\b/.test(causeMessage)) return troubleshootingAnchor("fold-eperm-ebusy");
22956
+ if (/^(?:npm|node) .* failed\b/.test(causeMessage)) return troubleshootingAnchor("fold-lifecycle-script");
22864
22957
  return void 0;
22865
22958
  }
22866
22959
  async function recoverFailedFold(deps, cause, startBranch, preFoldMainSha, resumeCommand) {
@@ -22889,13 +22982,12 @@ fold failed with an in-progress merge; automatic \`git merge --abort\` failed: $
22889
22982
  if (probe.branch === "main" && preFoldMainSha) {
22890
22983
  const mainDescendsFromPreFold = await deps.run("git", ["merge-base", "--is-ancestor", preFoldMainSha, "main"]).then(() => true).catch(() => false);
22891
22984
  if (mainDescendsFromPreFold) {
22892
- try {
22893
- await deps.run("git", ["reset", "--hard", preFoldMainSha]);
22894
- } catch (e) {
22985
+ const attempt = await resetFoldMainWithStaleLockRetry(deps, preFoldMainSha, rawCause);
22986
+ if (!attempt.ok) {
22895
22987
  return foldFailureGuidance(
22896
22988
  `${causeMessage}
22897
22989
 
22898
- fold failed after this run's merge/fold committed locally on main; automatic \`git reset --hard ${shaLabel(preFoldMainSha)}\` failed: ${e instanceof Error ? e.message : String(e)}.`,
22990
+ fold failed after this run's merge/fold committed locally on main; automatic \`git reset --hard ${shaLabel(preFoldMainSha)}\` failed: ${attempt.error instanceof Error ? attempt.error.message : String(attempt.error)}${attempt.lockNote ? `; ${attempt.lockNote}` : ""}.`,
22899
22991
  await probeFoldFailureState(deps),
22900
22992
  startBranch,
22901
22993
  preFoldMainSha,
@@ -22910,7 +23002,7 @@ fold failed after this run's merge/fold committed locally on main; automatic \`g
22910
23002
  startBranch,
22911
23003
  preFoldMainSha,
22912
23004
  resumeCommand,
22913
- `local main was reset to its pre-fold state ${shaLabel(preFoldMainSha)} (discarding only this run's merge/fold commit(s) at ${shaLabel(probe.mainSha)})${aheadNote}`
23005
+ `local main was reset to its pre-fold state ${shaLabel(preFoldMainSha)} (discarding only this run's merge/fold commit(s) at ${shaLabel(probe.mainSha)})${attempt.lockNote ? `; ${attempt.lockNote}` : ""}${aheadNote}`
22914
23006
  );
22915
23007
  }
22916
23008
  }
@@ -33529,10 +33621,10 @@ function formatOwnDetail(cmd) {
33529
33621
  }
33530
33622
  lines2.push("");
33531
33623
  }
33532
- const ownOptions = cmd.options.filter((opt) => opt.flags !== "--help" && opt.flags !== "-V, --version");
33533
- if (ownOptions.length) {
33624
+ const ownOptions2 = cmd.options.filter((opt) => opt.flags !== "--help" && opt.flags !== "-V, --version");
33625
+ if (ownOptions2.length) {
33534
33626
  lines2.push("Options:");
33535
- for (const opt of ownOptions) {
33627
+ for (const opt of ownOptions2) {
33536
33628
  const tags = [];
33537
33629
  if (opt.mandatory) tags.push("required");
33538
33630
  if (opt.default !== void 0) tags.push(`default: ${JSON.stringify(opt.default)}`);
@@ -33594,6 +33686,56 @@ function formatExplainLoop(playbook) {
33594
33686
  }
33595
33687
  return lines2.join("\n");
33596
33688
  }
33689
+ function ownOptions(cmd) {
33690
+ return cmd.options.filter((opt) => opt.flags !== "--help" && opt.flags !== "-V, --version");
33691
+ }
33692
+ function briefCommand(cmd) {
33693
+ return {
33694
+ path: cmd.path,
33695
+ ...cmd.description ? { description: cmd.description } : {},
33696
+ arguments: cmd.arguments.map((arg) => ({
33697
+ name: arg.name,
33698
+ required: arg.required,
33699
+ ...arg.variadic ? { variadic: true } : {},
33700
+ ...arg.description ? { description: arg.description } : {}
33701
+ })),
33702
+ options: ownOptions(cmd).map((opt) => ({
33703
+ flags: opt.flags,
33704
+ takesValue: opt.takesValue,
33705
+ ...opt.mandatory ? { required: true } : {},
33706
+ ...opt.description ? { description: opt.description } : {}
33707
+ }))
33708
+ };
33709
+ }
33710
+ function explainBriefManifest(manifest, command) {
33711
+ return {
33712
+ schema_version: 1,
33713
+ scope: "command",
33714
+ brief: true,
33715
+ name: manifest.name,
33716
+ ...manifest.version ? { version: manifest.version } : {},
33717
+ command: briefCommand(command),
33718
+ ...command.subcommands.length ? { children: command.subcommands.map(briefCommand) } : {}
33719
+ };
33720
+ }
33721
+ function formatExplainBrief(cmd, rootName) {
33722
+ const lines2 = [`${rootName} ${cmd.path}${cmd.description ? ` \u2014 ${cmd.description}` : ""}`];
33723
+ for (const arg of cmd.arguments) {
33724
+ const flag = arg.required ? `<${arg.name}>` : `[${arg.name}]`;
33725
+ lines2.push(` ${flag} ${arg.required ? "required" : "optional"}${arg.description ? ` ${arg.description}` : ""}`);
33726
+ }
33727
+ for (const opt of ownOptions(cmd)) {
33728
+ lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
33729
+ }
33730
+ for (const child2 of cmd.subcommands) {
33731
+ const args = child2.arguments.map((arg) => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(" ");
33732
+ lines2.push(`${child2.path}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
33733
+ for (const opt of ownOptions(child2)) {
33734
+ lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
33735
+ }
33736
+ }
33737
+ return lines2.join("\n");
33738
+ }
33597
33739
  function catalogCommandPaths(manifest) {
33598
33740
  const acc = [];
33599
33741
  const walk2 = (command) => {
@@ -33728,7 +33870,7 @@ function findCommandInManifest(manifest, commandPath3) {
33728
33870
  return visit(manifest.tree);
33729
33871
  }
33730
33872
  function registerExplainCommand(program3) {
33731
- program3.command("explain").description("print a command's purpose, flags, and examples from the live schema \u2014 one grounding call replaces trial-and-error").argument("[command...]", 'the command path to explain (e.g. "issue create")').addOption(new Option("--loop <name>", "print the canonical command sequence: agent | start-work | ship-pr | hotfix").choices(Object.keys(LOOP_PLAYBOOKS))).option("--json", "machine-readable focused command, route, or loop detail").option("--out <path>", "write the output to a UTF-8 file instead of stdout (#5802 byte contract)").option("--recursive", "include full schemas for immediate children (default: compact child index)").option("--full", "alias for --recursive").action((commandArgs, opts) => {
33873
+ program3.command("explain").description("print a command's purpose, flags, and examples from the live schema \u2014 one grounding call replaces trial-and-error").argument("[command...]", 'the command path to explain (e.g. "issue create")').addOption(new Option("--loop <name>", "print the canonical command sequence: agent | start-work | ship-pr | hotfix").choices(Object.keys(LOOP_PLAYBOOKS))).option("--json", "machine-readable focused command, route, or loop detail").option("--brief", "compact per-verb flags, value requirements, and one-line descriptions (no schemas or prose)").option("--out <path>", "write the output to a UTF-8 file instead of stdout (#5802 byte contract)").option("--recursive", "include full schemas for immediate children (default: compact child index)").option("--full", "alias for --recursive").action((commandArgs, opts) => {
33732
33874
  const emit = (output) => {
33733
33875
  if (!opts.out) console.log(output);
33734
33876
  else console.log(`Wrote explain output to ${opts.out} (UTF-8, ${writeUtf8Receipt(opts.out, output)} bytes)`);
@@ -33767,6 +33909,10 @@ function registerExplainCommand(program3) {
33767
33909
  return;
33768
33910
  }
33769
33911
  const recursive = Boolean(opts.recursive || opts.full);
33912
+ if (opts.brief) {
33913
+ emit(opts.json ? JSON.stringify(explainBriefManifest(manifest, command), null, 2) : formatExplainBrief(command, manifest.name));
33914
+ return;
33915
+ }
33770
33916
  emit(opts.json ? JSON.stringify(explainCommandManifest(manifest, command, { recursive }), null, 2) : command.subcommands.length ? formatExplainGroup(command, manifest.name) : formatExplainCommand(command, manifest.name));
33771
33917
  });
33772
33918
  }
@@ -34438,10 +34584,10 @@ async function preflightBatchSurfaces(validated, rowRepo, options) {
34438
34584
  continue;
34439
34585
  }
34440
34586
  if (known.length === 0) continue;
34441
- const inferred = inferSurface(known, { title: spec.title, body: spec.body });
34587
+ const inferred = inferSurface(known, { title: spec.title, type: spec.type, body: spec.body });
34442
34588
  spec.labels = [...spec.labels ?? [], inferred.label];
34443
34589
  process.stderr.write(
34444
- `mmi-cli: no --surface given \u2014 row ${row} filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.
34590
+ `mmi-cli: no --surface given \u2014 row ${row} filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.${surfaceInferenceSuffix(inferred)}
34445
34591
  `
34446
34592
  );
34447
34593
  }
@@ -40750,6 +40896,7 @@ function registerCollaborationCommands(program3) {
40750
40896
  repo: planRepo,
40751
40897
  labels: [...planLabels, ...surface ? [surface] : []],
40752
40898
  title,
40899
+ type,
40753
40900
  body: opts.body
40754
40901
  });
40755
40902
  if (warn) process.stderr.write(`${warn}
@@ -40757,10 +40904,7 @@ function registerCollaborationCommands(program3) {
40757
40904
  if (refusal) fail(refusal.message, refusal.payload);
40758
40905
  if (inferred && !surface) {
40759
40906
  planInferred = inferred;
40760
- process.stderr.write(
40761
- `mmi-cli: no --surface given \u2014 filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.
40762
- `
40763
- );
40907
+ process.stderr.write(surfaceInferenceNote(inferred));
40764
40908
  }
40765
40909
  }
40766
40910
  return {
@@ -40770,7 +40914,9 @@ function registerCollaborationCommands(program3) {
40770
40914
  priority,
40771
40915
  repo: opts.repo,
40772
40916
  ...surface ? { surface } : {},
40773
- ...planInferred ? { surface_inferred: true, surface: planInferred.label, surface_reason: planInferred.reason } : {}
40917
+ ...planInferred ? { surface_inferred: true, surface: planInferred.label, surface_reason: planInferred.reason } : {},
40918
+ ...planInferred?.uncertain ? { surface_uncertain: true } : {},
40919
+ ...planInferred?.alternatives?.length ? { surface_alternatives: planInferred.alternatives } : {}
40774
40920
  };
40775
40921
  }
40776
40922
  ).action(async (o) => {
@@ -40814,7 +40960,7 @@ function registerCollaborationCommands(program3) {
40814
40960
  return fail(`issue create: ${e.message}`, e instanceof TextArgError ? { code: e.code, offending_flag: e.offendingFlag } : void 0);
40815
40961
  }
40816
40962
  {
40817
- const surfaceCheck = await checkSurfaceRequirement({ repo: targetRepo2, labels: extraLabels, title, body });
40963
+ const surfaceCheck = await checkSurfaceRequirement({ repo: targetRepo2, labels: extraLabels, title, type: issueType, body });
40818
40964
  const { refusal, warn, inferred } = surfaceCheck;
40819
40965
  if (warn) process.stderr.write(`${warn}
40820
40966
  `);
@@ -40844,10 +40990,7 @@ function registerCollaborationCommands(program3) {
40844
40990
  labels: extraLabels.length ? extraLabels : void 0
40845
40991
  });
40846
40992
  surfaceInferred = inferred;
40847
- process.stderr.write(
40848
- `mmi-cli: no --surface given \u2014 filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.
40849
- `
40850
- );
40993
+ process.stderr.write(surfaceInferenceNote(inferred));
40851
40994
  }
40852
40995
  if (refusal && !surfaceWaived()) return fail(refusal.message, refusal.payload);
40853
40996
  }
@@ -40887,7 +41030,10 @@ function registerCollaborationCommands(program3) {
40887
41030
  } : {},
40888
41031
  ...parentLinkFields(parent, parentLinkError),
40889
41032
  // #1164: surfaced so a caller can see (and override with --surface) a pick it never asked for.
40890
- ...surfaceInferred ? { surface_inferred: true, surface: surfaceInferred.label, surface_reason: surfaceInferred.reason } : {}
41033
+ ...surfaceInferred ? { surface_inferred: true, surface: surfaceInferred.label, surface_reason: surfaceInferred.reason } : {},
41034
+ // #6818: a weak/ambiguous pick says so, with its runner-ups, so the caller can pass --surface.
41035
+ ...surfaceInferred?.uncertain ? { surface_uncertain: true } : {},
41036
+ ...surfaceInferred?.alternatives?.length ? { surface_alternatives: surfaceInferred.alternatives } : {}
40891
41037
  }));
40892
41038
  }), [
40893
41039
  'mmi-cli oracle issue create --type task --title "Wire the schema"',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.4.4",
3
+ "version": "4.4.6",
4
4
  "description": "MMI Future CLI — the org dev toolbox and shared cross-IDE engine for every registry-declared MMI coding surface.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",