@mutmutco/cli 3.33.0 → 3.34.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.
Files changed (2) hide show
  1. package/dist/main.cjs +28 -105
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -8919,6 +8919,14 @@ function defaultWorktreePath(repoRoot2, branch) {
8919
8919
  const safe = branch.replace(/[/\\]+/g, "-");
8920
8920
  return (0, import_node_path11.join)((0, import_node_path11.dirname)(repoRoot2), "mmi-worktrees", safe);
8921
8921
  }
8922
+ async function primaryCheckoutRootOf(git) {
8923
+ try {
8924
+ const out = (await git(["rev-parse", "--path-format=absolute", "--git-common-dir"])).trim();
8925
+ return out ? (0, import_node_path11.dirname)(out) : void 0;
8926
+ } catch {
8927
+ return void 0;
8928
+ }
8929
+ }
8922
8930
  function resolveWorktreeBase(from, remote) {
8923
8931
  const remotePrefix = `${remote}/`;
8924
8932
  const fetchBranch = from.startsWith(remotePrefix) ? from.slice(remotePrefix.length) : void 0;
@@ -10378,6 +10386,14 @@ function earlyExitGraceMs() {
10378
10386
  }
10379
10387
  return EARLY_EXIT_GRACE_MS;
10380
10388
  }
10389
+ var HEALTH_POLL_INTERVAL_MS = 1e3;
10390
+ function healthPollIntervalMs() {
10391
+ if (process.env.NODE_ENV === "test") {
10392
+ const testOverride = Number(process.env.MMI_CLI_TEST_HEALTH_POLL_MS);
10393
+ if (Number.isFinite(testOverride) && testOverride >= 10) return testOverride;
10394
+ }
10395
+ return HEALTH_POLL_INTERVAL_MS;
10396
+ }
10381
10397
  function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
10382
10398
  return new Promise((resolve5, reject) => {
10383
10399
  let settled = false;
@@ -10793,7 +10809,7 @@ function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
10793
10809
  async function cleanupStageState(state, paths, timeoutMs, fallbackCwd) {
10794
10810
  await killTree(state.pid);
10795
10811
  if (state.teardown?.command.trim()) {
10796
- await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, timeoutMs);
10812
+ await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, Math.max(timeoutMs, 1e4));
10797
10813
  }
10798
10814
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
10799
10815
  (0, import_node_fs14.rmSync)(path2, { force: true });
@@ -10834,7 +10850,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
10834
10850
  } catch (e) {
10835
10851
  last = e.message;
10836
10852
  }
10837
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
10853
+ await new Promise((resolve5) => setTimeout(resolve5, healthPollIntervalMs()));
10838
10854
  }
10839
10855
  throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
10840
10856
  }
@@ -11275,29 +11291,6 @@ function resolveIssueTitle(input, deps) {
11275
11291
  noun: "title"
11276
11292
  });
11277
11293
  }
11278
- var NORTH_STAR_BODY_PREFIX = "North Star:";
11279
- var NORTH_STAR_SLUG_RE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
11280
- function normalizeNorthStarSlug(raw) {
11281
- const slug = raw.trim();
11282
- if (!slug || !NORTH_STAR_SLUG_RE.test(slug)) {
11283
- throw new Error(`invalid North Star slug "${raw}" \u2014 expected kebab-case like agent-session-workflow`);
11284
- }
11285
- return slug;
11286
- }
11287
- function northStarLabel(slug) {
11288
- return `northstar:${slug}`;
11289
- }
11290
- function appendNorthStarLine(body, slug) {
11291
- const line = `${NORTH_STAR_BODY_PREFIX} ${slug}`;
11292
- const existing = new RegExp(`^${NORTH_STAR_BODY_PREFIX}\\s+\\S+\\s*$`, "m");
11293
- if (existing.test(body)) return body;
11294
- const trimmed = body.replace(/\s+$/, "");
11295
- return trimmed ? `${trimmed}
11296
-
11297
- ${line}
11298
- ` : `${line}
11299
- `;
11300
- }
11301
11294
 
11302
11295
  // src/issue-view-json.ts
11303
11296
  var DEFAULT_ISSUE_VIEW_FIELDS = "number,title,state,url,labels,author,assignees,milestone,body";
@@ -16812,9 +16805,9 @@ function extractWorkflowCrons(yamlText) {
16812
16805
  function workflowEntry(repo, workflowPath, yamlText) {
16813
16806
  const crons = extractWorkflowCrons(yamlText);
16814
16807
  if (!crons.length) return null;
16815
- const basename4 = workflowPath.split("/").pop() ?? workflowPath;
16808
+ const basename3 = workflowPath.split("/").pop() ?? workflowPath;
16816
16809
  return {
16817
- name: `${repo}/${basename4.replace(/\.ya?ml$/, "")}`,
16810
+ name: `${repo}/${basename3.replace(/\.ya?ml$/, "")}`,
16818
16811
  cadence: crons.join(" + "),
16819
16812
  executor: "github-actions",
16820
16813
  llm: llmFromHeader(yamlText),
@@ -19815,7 +19808,6 @@ function classifyStaleLeaks(input) {
19815
19808
  const protectedBranches = input.protectedBranches ?? PROTECTED_BRANCHES2;
19816
19809
  const leaks = [];
19817
19810
  const worktreeBranches2 = new Set(input.worktrees.filter((w) => !w.primary).map((w) => w.branch));
19818
- const worktreeByBranch = new Map(input.worktrees.map((w) => [w.branch, w.path]));
19819
19811
  const stageByPath = new Map(input.stages.map((s) => [s.path, s.port]));
19820
19812
  for (const wt of input.worktrees) {
19821
19813
  if (wt.primary) continue;
@@ -20066,7 +20058,6 @@ async function editIssue(client, options, deps = {}) {
20066
20058
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
20067
20059
  const patch = {};
20068
20060
  let bodyChanged = false;
20069
- let northStarSlug;
20070
20061
  if (options.title !== void 0) patch.title = options.title;
20071
20062
  if (options.body !== void 0 || options.bodyFile !== void 0) {
20072
20063
  let body;
@@ -20076,29 +20067,14 @@ async function editIssue(client, options, deps = {}) {
20076
20067
  } else {
20077
20068
  body = options.body ?? "";
20078
20069
  }
20079
- if (options.northStar) {
20080
- northStarSlug = normalizeNorthStarSlug(options.northStar);
20081
- body = appendNorthStarLine(body, northStarSlug);
20082
- }
20083
20070
  patch.body = body;
20084
20071
  bodyChanged = true;
20085
- } else if (options.northStar) {
20086
- northStarSlug = normalizeNorthStarSlug(options.northStar);
20087
- const current = await client.rest("GET", `repos/${repo}/issues/${parsed.number}`);
20088
- patch.body = appendNorthStarLine(current?.body ?? "", northStarSlug);
20089
- bodyChanged = true;
20090
20072
  }
20091
20073
  if (patch.title !== void 0 || patch.body !== void 0) {
20092
20074
  await client.rest("PATCH", `repos/${repo}/issues/${parsed.number}`, { body: patch });
20093
20075
  }
20094
20076
  const labelsAdded = [];
20095
20077
  const labelsRemoved = [];
20096
- if (options.northStar && northStarSlug) {
20097
- const nsLabel = northStarLabel(northStarSlug);
20098
- if (!options.addLabel?.includes(nsLabel)) {
20099
- (options.addLabel ??= []).push(nsLabel);
20100
- }
20101
- }
20102
20078
  if (options.addLabel?.length) {
20103
20079
  await client.rest("POST", `repos/${repo}/issues/${parsed.number}/labels`, { body: { labels: options.addLabel } });
20104
20080
  labelsAdded.push(...options.addLabel);
@@ -20128,8 +20104,7 @@ async function editIssue(client, options, deps = {}) {
20128
20104
  bodyChanged,
20129
20105
  labelsAdded,
20130
20106
  labelsRemoved,
20131
- ...parentResult ? { parent: parentResult } : {},
20132
- ...northStarSlug ? { northStarSlug } : {}
20107
+ ...parentResult ? { parent: parentResult } : {}
20133
20108
  };
20134
20109
  }
20135
20110
  async function closeIssue(client, options, deps = {}) {
@@ -20309,7 +20284,7 @@ ${spec.body ?? ""}`;
20309
20284
  const hash = (0, import_node_crypto5.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
20310
20285
  return `${batchKey}:${hash}`;
20311
20286
  }
20312
- var BATCH_SPEC_KEYS = /* @__PURE__ */ new Set(["type", "title", "body", "priority", "labels", "northStar", "parent", "repo"]);
20287
+ var BATCH_SPEC_KEYS = /* @__PURE__ */ new Set(["type", "title", "body", "priority", "labels", "parent", "repo"]);
20313
20288
  function validateBatchSpecs(specs) {
20314
20289
  const errors = [];
20315
20290
  const validated = [];
@@ -20349,28 +20324,6 @@ function validateBatchSpecs(specs) {
20349
20324
  }
20350
20325
  return { ok: errors.length === 0, errors, validated };
20351
20326
  }
20352
- var NORTH_STAR_LABEL_COLOR = "5319e7";
20353
- function northStarLabelsForBatch(specs) {
20354
- const labels = /* @__PURE__ */ new Set();
20355
- for (const spec of specs) {
20356
- if (spec.northStar) labels.add(northStarLabel(normalizeNorthStarSlug(spec.northStar)));
20357
- for (const l of spec.labels ?? []) if (l.startsWith("northstar:")) labels.add(l);
20358
- }
20359
- return [...labels].sort((a, b) => a.localeCompare(b));
20360
- }
20361
- async function ensureNorthStarLabels(client, repo, specs) {
20362
- const minted = [];
20363
- for (const name of northStarLabelsForBatch(specs)) {
20364
- try {
20365
- await client.rest("POST", `repos/${repo}/labels`, {
20366
- body: { name, color: NORTH_STAR_LABEL_COLOR, description: `North Star: ${name.slice("northstar:".length)}` }
20367
- });
20368
- minted.push(name);
20369
- } catch {
20370
- }
20371
- }
20372
- return minted;
20373
- }
20374
20327
  async function createIssuesBatch(specs, options, deps = {}) {
20375
20328
  const client = deps.client ?? defaultGitHubClient();
20376
20329
  const validation = validateBatchSpecs(specs);
@@ -20384,14 +20337,6 @@ ${lines}`);
20384
20337
  throw new Error("could not resolve repo \u2014 pass --repo owner/repo or set repo per row");
20385
20338
  }
20386
20339
  const rowRepo = (spec) => spec.repo ?? defaultRepo;
20387
- const byRepo = /* @__PURE__ */ new Map();
20388
- for (const v of validation.validated) {
20389
- const r = rowRepo(v.spec);
20390
- byRepo.set(r, [...byRepo.get(r) ?? [], v.spec]);
20391
- }
20392
- for (const [r, specsForRepo] of byRepo) {
20393
- await ensureNorthStarLabels(client, r, specsForRepo);
20394
- }
20395
20340
  const created = [];
20396
20341
  const failures = [];
20397
20342
  for (const entry of validation.validated) {
@@ -20406,12 +20351,6 @@ ${lines}`);
20406
20351
  }
20407
20352
  }
20408
20353
  let body = spec.body ?? "";
20409
- if (spec.northStar) {
20410
- const slug = normalizeNorthStarSlug(spec.northStar);
20411
- body = appendNorthStarLine(body, slug);
20412
- const nsLabel = northStarLabel(slug);
20413
- if (!spec.labels?.includes(nsLabel)) (spec.labels ??= []).push(nsLabel);
20414
- }
20415
20354
  if (rowKey) {
20416
20355
  body = appendIdempotencyMarker(body, rowKey);
20417
20356
  }
@@ -20465,7 +20404,7 @@ function registerIssueLifecycleCommands(program3) {
20465
20404
  const issue2 = program3.commands.find((c) => c.name() === "issue");
20466
20405
  if (!issue2) return;
20467
20406
  mutating(
20468
- issue2.command("edit <ref>").description("edit an issue title/body/labels, reparent it (--parent), or link a North Star \u2014 reparenting is impossible via raw gh").option("--title <title>", "new title").option("--body <body>", "new body (markdown)").option("--body-file <path|->", "read new body from a UTF-8 file, or stdin with -").option("--add-label <label...>", "label(s) to add (repeatable)").option("--remove-label <label...>", "label(s) to remove (repeatable)").option("--parent <ref>", "reparent: link under this parent (#123, owner/repo#123, or URL)").option("--north-star <slug>", "append a North Star body line + northstar:<slug> label").option("--repo <owner/repo>", "repo for a bare ref (defaults to the current repo)"),
20407
+ issue2.command("edit <ref>").description("edit an issue title/body/labels or reparent it (--parent) \u2014 reparenting is impossible via raw gh").option("--title <title>", "new title").option("--body <body>", "new body (markdown)").option("--body-file <path|->", "read new body from a UTF-8 file, or stdin with -").option("--add-label <label...>", "label(s) to add (repeatable)").option("--remove-label <label...>", "label(s) to remove (repeatable)").option("--parent <ref>", "reparent: link under this parent (#123, owner/repo#123, or URL)").option("--repo <owner/repo>", "repo for a bare ref (defaults to the current repo)"),
20469
20408
  (opts, args) => ({ command: "issue edit", ref: args[0], fields: Object.keys(opts).filter((k) => k !== "repo" && opts[k] !== void 0) })
20470
20409
  ).action(async (ref, o) => {
20471
20410
  try {
@@ -20478,8 +20417,7 @@ function registerIssueLifecycleCommands(program3) {
20478
20417
  bodyFile: o.bodyFile,
20479
20418
  addLabel: o.addLabel,
20480
20419
  removeLabel: o.removeLabel,
20481
- parent: o.parent,
20482
- northStar: o.northStar
20420
+ parent: o.parent
20483
20421
  });
20484
20422
  console.log(JSON.stringify(result));
20485
20423
  } catch (e) {
@@ -22771,13 +22709,8 @@ function runWorktreeInstall(command, cwd, quiet) {
22771
22709
  });
22772
22710
  });
22773
22711
  }
22774
- async function primaryCheckoutRoot(worktreeRoot) {
22775
- try {
22776
- const out = (await execFileP2("git", ["-C", worktreeRoot, "rev-parse", "--path-format=absolute", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
22777
- return out ? (0, import_node_path23.dirname)(out) : void 0;
22778
- } catch {
22779
- return void 0;
22780
- }
22712
+ async function primaryCheckoutRoot(from) {
22713
+ return primaryCheckoutRootOf(async (args) => (await execFileP2("git", ["-C", from, ...args], { timeout: GIT_TIMEOUT_MS })).stdout);
22781
22714
  }
22782
22715
  function makeProvisionDeps(worktreeRoot, quiet, log) {
22783
22716
  return {
@@ -22841,7 +22774,7 @@ withExamples(mutating(
22841
22774
  } else if (o.claim || o.for) {
22842
22775
  return fail("worktree create: --claim/--for need an issue-ref argument (e.g. worktree create 2687 --claim)");
22843
22776
  }
22844
- const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
22777
+ const repoRoot2 = await primaryCheckoutRoot(process.cwd()) ?? process.cwd();
22845
22778
  const wtPath = o.path ?? defaultWorktreePath(repoRoot2, branch);
22846
22779
  const { base, fetchBranch } = resolveWorktreeBase(fromRef, o.remote);
22847
22780
  if (fetchBranch) {
@@ -23512,7 +23445,7 @@ function resolveCreateType(raw, command) {
23512
23445
  }
23513
23446
  var issue = program2.command("issue").description("issues \u2014 reliable create with structured output");
23514
23447
  withExamples(mutating(
23515
- issue.command("create").description("create an issue (type \u2192 label) and print {number,url,label} JSON").option("--type <type>", "bug | feature | task (sets the matching label; required unless --batch)").option("--title <title>", "issue title").option("--title-file <path|->", "read the issue title from a UTF-8 file, or from stdin with -").option("--body <body>", "issue body (markdown)").option("--body-file <path|->", "read issue body from a UTF-8 file, or from stdin with -").option("--priority <priority>", "urgent | high | medium | low (defaults to medium; sets the board Priority field only \u2014 never a priority:* label, #416)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--label <label...>", "extra label(s) to attach (repeatable; auto-created if missing)").option("--north-star <slug>", "link to a North Star plan \u2014 appends a body line + northstar:<slug> label (#1922)").option("--parent <ref>", "file as a native sub-issue of this parent (#123, owner/repo#123, or URL)").option("--no-related", "skip the auto related-issues comment"),
23448
+ issue.command("create").description("create an issue (type \u2192 label) and print {number,url,label} JSON").option("--type <type>", "bug | feature | task (sets the matching label; required unless --batch)").option("--title <title>", "issue title").option("--title-file <path|->", "read the issue title from a UTF-8 file, or from stdin with -").option("--body <body>", "issue body (markdown)").option("--body-file <path|->", "read issue body from a UTF-8 file, or from stdin with -").option("--priority <priority>", "urgent | high | medium | low (defaults to medium; sets the board Priority field only \u2014 never a priority:* label, #416)").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--label <label...>", "extra label(s) to attach (repeatable; auto-created if missing)").option("--parent <ref>", "file as a native sub-issue of this parent (#123, owner/repo#123, or URL)").option("--no-related", "skip the auto related-issues comment"),
23516
23449
  // --dry-run/--validate-only plan: validate --type + --priority (mirrors the action — a bad enum fails
23517
23450
  // ERR_BAD_ENUM, a missing priority defaults to medium) then echo the resolved create intent. Refs
23518
23451
  // (`--parent`) and title-source are validated by the action on a real run.
@@ -23527,23 +23460,14 @@ withExamples(mutating(
23527
23460
  let body;
23528
23461
  let title;
23529
23462
  let issueType;
23530
- let northStarSlug;
23531
23463
  let extraLabels = [];
23532
23464
  try {
23533
23465
  issueType = resolveCreateType(o.type, "issue create");
23534
23466
  title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises6.readFile, readStdin });
23535
23467
  body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises6.readFile, readStdin });
23536
- if (o.northStar !== void 0) {
23537
- northStarSlug = normalizeNorthStarSlug(o.northStar);
23538
- body = appendNorthStarLine(body, northStarSlug);
23539
- }
23540
23468
  if (o.idempotencyKey) body = appendIdempotencyMarker(body, o.idempotencyKey);
23541
23469
  priority = resolveCreatePriority(o.priority, "issue create");
23542
23470
  extraLabels = [...o.label ?? []];
23543
- if (northStarSlug) {
23544
- const nsLabel = northStarLabel(northStarSlug);
23545
- if (!extraLabels.includes(nsLabel)) extraLabels.push(nsLabel);
23546
- }
23547
23471
  args = buildIssueArgs({
23548
23472
  type: issueType,
23549
23473
  title,
@@ -23585,7 +23509,6 @@ withExamples(mutating(
23585
23509
  priority,
23586
23510
  projectItemId,
23587
23511
  onBoard,
23588
- ...northStarSlug ? { northStarSlug } : {},
23589
23512
  ...parentLinkFields(parent, parentLinkError)
23590
23513
  }));
23591
23514
  }), [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.33.0",
3
+ "version": "3.34.0",
4
4
  "description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",