@mutmutco/cli 3.132.1 → 3.133.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 +94 -74
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -3528,19 +3528,19 @@ function hardExit(code) {
3528
3528
  }
3529
3529
  var STDIO_FLUSH_TIMEOUT_MS = 2e3;
3530
3530
  function flushStream(stream) {
3531
- return new Promise((resolve6) => {
3531
+ return new Promise((resolve7) => {
3532
3532
  try {
3533
- stream.write("", () => resolve6());
3533
+ stream.write("", () => resolve7());
3534
3534
  } catch {
3535
- resolve6();
3535
+ resolve7();
3536
3536
  }
3537
3537
  });
3538
3538
  }
3539
3539
  async function flushStdio(timeoutMs = STDIO_FLUSH_TIMEOUT_MS) {
3540
3540
  await Promise.race([
3541
3541
  Promise.all([flushStream(process.stdout), flushStream(process.stderr)]),
3542
- new Promise((resolve6) => {
3543
- setTimeout(resolve6, timeoutMs).unref?.();
3542
+ new Promise((resolve7) => {
3543
+ setTimeout(resolve7, timeoutMs).unref?.();
3544
3544
  })
3545
3545
  ]);
3546
3546
  }
@@ -3548,7 +3548,7 @@ async function cleanExit(code) {
3548
3548
  process.exitCode = code;
3549
3549
  await closeHttpPool();
3550
3550
  await flushStdio();
3551
- await new Promise((resolve6) => setImmediate(resolve6));
3551
+ await new Promise((resolve7) => setImmediate(resolve7));
3552
3552
  return void 0;
3553
3553
  }
3554
3554
  var CLI_EXIT_WATCHDOG_MS = (() => {
@@ -3935,7 +3935,7 @@ async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
3935
3935
  const attempts = opts.attempts ?? 3;
3936
3936
  const baseDelayMs = opts.baseDelayMs ?? 250;
3937
3937
  const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
3938
- const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
3938
+ const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
3939
3939
  let lastErr;
3940
3940
  for (let i = 0; i < attempts; i++) {
3941
3941
  const isLast = i === attempts - 1;
@@ -4096,8 +4096,8 @@ async function readStdin(opts = {}) {
4096
4096
  })().catch(() => {
4097
4097
  });
4098
4098
  let timer;
4099
- const timeout = new Promise((resolve6) => {
4100
- timer = setTimeout(resolve6, timeoutMs);
4099
+ const timeout = new Promise((resolve7) => {
4100
+ timer = setTimeout(resolve7, timeoutMs);
4101
4101
  });
4102
4102
  try {
4103
4103
  await Promise.race([drain, timeout]);
@@ -4151,12 +4151,12 @@ function killProcessTree(pid) {
4151
4151
  function execFileHard(file, args, options) {
4152
4152
  const { timeout, step, ...rest } = options;
4153
4153
  const started = Date.now();
4154
- return new Promise((resolve6, reject) => {
4154
+ return new Promise((resolve7, reject) => {
4155
4155
  const child2 = (0, import_node_child_process3.execFile)(file, args, { encoding: "utf8", windowsHide: true, ...rest, timeout: 0 }, (error, stdout, stderr) => {
4156
4156
  clearTimeout(timer);
4157
4157
  if (expired) return;
4158
4158
  if (error) reject(error);
4159
- else resolve6({ stdout: String(stdout), stderr: String(stderr) });
4159
+ else resolve7({ stdout: String(stdout), stderr: String(stderr) });
4160
4160
  });
4161
4161
  let expired = false;
4162
4162
  const timer = setTimeout(() => {
@@ -5961,7 +5961,7 @@ async function runWithSweepWatchdog(run, timeoutMs, onTimeout) {
5961
5961
  clearTimeout(timer);
5962
5962
  }
5963
5963
  }
5964
- var defaultSleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
5964
+ var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
5965
5965
  async function removeWorktreeWithRecovery(wtPath, deps) {
5966
5966
  const maxAttempts = deps.maxAttempts ?? 3;
5967
5967
  const backoff = deps.backoffMs ?? [250, 1e3];
@@ -7455,7 +7455,7 @@ var import_node_path16 = require("node:path");
7455
7455
  // src/file-lock.ts
7456
7456
  var import_promises2 = require("node:fs/promises");
7457
7457
  var import_node_path15 = require("node:path");
7458
- var sleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
7458
+ var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
7459
7459
  var IMMEDIATE_RETRY_BUDGET = 3;
7460
7460
  var FileLockBusyError = class extends Error {
7461
7461
  lockPath;
@@ -7720,7 +7720,7 @@ function capWorktreeDirName(name, max = 40) {
7720
7720
  }
7721
7721
  function defaultWorktreePath(repoRoot2, branch) {
7722
7722
  const safe = capWorktreeDirName(branch.replace(/[/\\]+/g, "-"));
7723
- return (0, import_node_path16.join)((0, import_node_path16.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path16.basename)(repoRoot2), safe);
7723
+ return (0, import_node_path16.resolve)((0, import_node_path16.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path16.basename)(repoRoot2), safe);
7724
7724
  }
7725
7725
  async function primaryCheckoutRootOf(git2) {
7726
7726
  try {
@@ -10070,8 +10070,8 @@ function hasUserInstallRecord(file, pluginId) {
10070
10070
  var CLAUDE_PLUGIN_TIMEOUT_MS = 12e4;
10071
10071
  var NPM_VIEW_TIMEOUT_MS = 15e3;
10072
10072
  function runHostBin(bin, args, opts) {
10073
- const { step, timeout } = opts;
10074
- const shared = { timeout, stdio: ["ignore", "pipe", "pipe"], maxBuffer: 16 * 1024 * 1024 };
10073
+ const { step, timeout, env } = opts;
10074
+ const shared = { timeout, stdio: ["ignore", "pipe", "pipe"], maxBuffer: 16 * 1024 * 1024, ...env ? { env } : {} };
10075
10075
  const file = isWin ? "cmd.exe" : bin;
10076
10076
  const argv = isWin ? ["/c", bin, ...args] : args;
10077
10077
  return step ? execFileHard(file, argv, { ...shared, step }) : execFileP2(file, argv, shared);
@@ -10290,15 +10290,8 @@ function mmiPiPackageHealthy(env = process.env, home = (0, import_node_os6.homed
10290
10290
  const root = mmiPiPackageRoot(env, home);
10291
10291
  return Boolean(root && (0, import_node_fs19.existsSync)((0, import_node_path19.join)(root, "skills", "mmi", "SKILL.md")));
10292
10292
  }
10293
- function jervcodeHostBin() {
10294
- for (const bin of ["jervcode", "pi"]) {
10295
- try {
10296
- runHostBinSync(bin, ["--version"]);
10297
- return bin;
10298
- } catch {
10299
- }
10300
- }
10301
- return null;
10293
+ function piDoctorEnv(agentDir) {
10294
+ return { ...process.env, PI_CODING_AGENT_DIR: agentDir };
10302
10295
  }
10303
10296
  function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRepo = false) {
10304
10297
  const root = surfaceConfigRoot(surface);
@@ -10522,21 +10515,27 @@ async function healClaudePluginForDoctor(surface = detectSurface(process.env), o
10522
10515
  };
10523
10516
  }
10524
10517
  async function healJervCodeForDoctor() {
10525
- if (jervcodeAgentDirs().length === 0) {
10518
+ const agentDir = jervcodeAgentDirs()[0];
10519
+ if (!agentDir) {
10526
10520
  return { ok: true, detail: "skipped \u2014 no Pi/JervCode install (no agent config dir)" };
10527
10521
  }
10528
- const bin = jervcodeHostBin();
10529
- if (!bin) return { ok: false, detail: "neither `jervcode` nor `pi` is on PATH \u2014 install JervCode, then rerun `mmi-cli plugin heal`" };
10522
+ const env = piDoctorEnv(agentDir);
10523
+ const bin = "pi";
10524
+ try {
10525
+ runHostBinSync(bin, ["--version"]);
10526
+ } catch {
10527
+ return { ok: false, detail: "`pi` is not on PATH \u2014 install JervCode, then rerun `mmi-cli plugin heal`" };
10528
+ }
10530
10529
  const args = ["install", `npm:${JERVCODE_NPM_PACKAGE}`];
10531
10530
  try {
10532
- await runHostBinLogged(bin, args, { timeout: CLAUDE_PLUGIN_TIMEOUT_MS, step: `${bin} ${args.join(" ")}` });
10531
+ await runHostBinLogged(bin, args, { timeout: CLAUDE_PLUGIN_TIMEOUT_MS, step: `${bin} ${args.join(" ")}`, env });
10533
10532
  } catch (error) {
10534
10533
  return { ok: false, detail: `\`${bin} ${args.join(" ")}\` failed: ${error.message}` };
10535
10534
  }
10536
10535
  const legacy = legacyMmiPiPathEntries();
10537
10536
  for (const stale of legacy) {
10538
10537
  try {
10539
- await runHostBinLogged(bin, ["remove", stale], { timeout: CLAUDE_PLUGIN_TIMEOUT_MS, step: `${bin} remove ${stale}` });
10538
+ await runHostBinLogged(bin, ["remove", stale], { timeout: CLAUDE_PLUGIN_TIMEOUT_MS, step: `${bin} remove ${stale}`, env });
10540
10539
  } catch {
10541
10540
  }
10542
10541
  }
@@ -10693,7 +10692,7 @@ async function runPluginHeal(surface = detectSurface(process.env)) {
10693
10692
  } else {
10694
10693
  process.exitCode = 1;
10695
10694
  console.log(` \u2717 Auto-heal failed or was skipped. Run manually:
10696
- jervcode install npm:${JERVCODE_NPM_PACKAGE}`);
10695
+ pi install npm:${JERVCODE_NPM_PACKAGE}`);
10697
10696
  }
10698
10697
  return;
10699
10698
  }
@@ -12280,7 +12279,7 @@ function upstreamFaultMessage(verb, stderr) {
12280
12279
  }
12281
12280
  async function ghCreate(args, deps = {}) {
12282
12281
  const exec = deps.exec ?? execFileP2;
12283
- const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
12282
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
12284
12283
  const swapped = await bodyArgsViaFile(args);
12285
12284
  try {
12286
12285
  for (let attempt = 1; attempt <= GH_CREATE_UPSTREAM_RETRIES; attempt++) {
@@ -13486,8 +13485,8 @@ var PRE_SPAWN_DRAIN_TIMEOUT_MS = 2e3;
13486
13485
  async function drainHttpPoolBeforeSpawn() {
13487
13486
  const drained = await Promise.race([
13488
13487
  closeHttpPool().then(() => true),
13489
- new Promise((resolve6) => {
13490
- setTimeout(() => resolve6(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
13488
+ new Promise((resolve7) => {
13489
+ setTimeout(() => resolve7(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
13491
13490
  })
13492
13491
  ]);
13493
13492
  if (!drained) destroyHttpPool();
@@ -14200,10 +14199,10 @@ var rollout_plan_default = {
14200
14199
  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)."
14201
14200
  },
14202
14201
  baseline: {
14203
- version: "3.132.1",
14204
- tag: "v3.132.1",
14205
- commit: "264af6faca3a",
14206
- npm: "@mutmutco/cli@3.132.1"
14202
+ version: "3.133.0",
14203
+ tag: "v3.133.0",
14204
+ commit: "e84ca12a12b4",
14205
+ npm: "@mutmutco/cli@3.133.0"
14207
14206
  },
14208
14207
  exitCriterion: "fleet-n-of-n",
14209
14208
  hubOnlyShortcut: "forbidden",
@@ -14220,14 +14219,14 @@ var rollout_plan_default = {
14220
14219
  repo: "mutmutco/mmi-hub",
14221
14220
  role: "canary",
14222
14221
  schedule: "train",
14223
- v3Target: "v3.132.1"
14222
+ v3Target: "v3.133.0"
14224
14223
  }
14225
14224
  ],
14226
14225
  rollbackTrigger: "Any red inside the post-cut soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a v3 client refused while the compat window must still admit it (SUPPORTED_MINOR_WINDOW=2, MIN_CLIENT_VERSION 0.0.0 \u2014 D6a), or npm consumer install/doctor failure on the v4 dist.",
14227
14226
  rollback: {
14228
14227
  independent: true,
14229
- mechanism: "npm dist-tag latest -> 3.132.1 and redeploy the Hub Lambda from tag v3.132.1 (264af6faca3a); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
14230
- v3Target: "v3.132.1 (@mutmutco/cli@3.132.1, tag commit 264af6faca3a \u2014 the preserved latest-v3 distribution, D6b)"
14228
+ mechanism: "npm dist-tag latest -> 3.133.0 and redeploy the Hub Lambda from tag v3.133.0 (e84ca12a12b4); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
14229
+ v3Target: "v3.133.0 (@mutmutco/cli@3.133.0, tag commit e84ca12a12b4 \u2014 the preserved latest-v3 distribution, D6b)"
14231
14230
  }
14232
14231
  },
14233
14232
  {
@@ -16634,7 +16633,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
16634
16633
  async function predictMergeConflicts(deps, ours, theirs) {
16635
16634
  return runMergeTreePreflight(deps, ours, theirs);
16636
16635
  }
16637
- async function mergeWithToleratedResolution(deps, sourceRef, label, resolve6, extraTolerated = []) {
16636
+ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, extraTolerated = []) {
16638
16637
  try {
16639
16638
  await deps.run("git", ["merge", sourceRef, "--no-edit"]);
16640
16639
  return;
@@ -16648,7 +16647,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve6, ex
16648
16647
  unmerged.length === 0 ? `${label} merge failed without conflicted paths \u2014 merge aborted; inspect the repo state and rerun` : `${label} merge conflicts on untolerated path(s): ${blocking.join(", ")} \u2014 merge aborted (the train is misaligned; reconcile the branches via an approved alignment PR, then rerun)`
16649
16648
  );
16650
16649
  }
16651
- await deps.run("git", ["checkout", `--${resolve6}`, "--", ...unmerged]);
16650
+ await deps.run("git", ["checkout", `--${resolve7}`, "--", ...unmerged]);
16652
16651
  await deps.run("git", ["add", "--", ...unmerged]);
16653
16652
  await deps.run("git", ["commit", "--no-edit"]);
16654
16653
  }
@@ -16859,7 +16858,7 @@ var CORRELATE_SKEW_SLACK_MS = 1e4;
16859
16858
  var CORRELATE_PAGE_LIMIT = 50;
16860
16859
  var RUN_CONFIRM_ATTEMPTS = 3;
16861
16860
  var RUN_CONFIRM_DELAY_MS = 1e3;
16862
- var defaultSleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
16861
+ var defaultSleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
16863
16862
  function resolveSleep(deps) {
16864
16863
  return deps.sleep ?? defaultSleep2;
16865
16864
  }
@@ -19774,7 +19773,7 @@ async function mergeAutoWithTransientRetry(prNumber, repo, deps) {
19774
19773
  if (first.mergeStatus !== "failed") return first;
19775
19774
  const ready = await deps.probeMergeReady(prNumber, repo).catch(() => ({ open: false, mergeable: false, checksPassing: false }));
19776
19775
  if (!ready.open || !ready.mergeable || !ready.checksPassing) return first;
19777
- const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
19776
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
19778
19777
  await sleep3(PR_LAND_MERGE_RETRY_DELAY_MS);
19779
19778
  const retried = await deps.mergeAuto(prNumber, repo);
19780
19779
  if (retried.mergeStatus !== "failed") return retried;
@@ -19785,7 +19784,7 @@ var AUTO_MERGE_CONFIRM_DELAY_MS = 3e3;
19785
19784
  async function confirmAutoMergeEnqueued(deps, options) {
19786
19785
  const retries = options?.retries ?? AUTO_MERGE_CONFIRM_RETRIES;
19787
19786
  const delayMs = options?.delayMs ?? AUTO_MERGE_CONFIRM_DELAY_MS;
19788
- const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
19787
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
19789
19788
  for (let attempt = 0; attempt < retries; attempt++) {
19790
19789
  if (await deps.readMerged().catch(() => false)) return "merged";
19791
19790
  const stuck = await deps.readAutoMergeRequest().then((s) => s.trim()).catch(() => "");
@@ -19802,7 +19801,7 @@ async function confirmAutoMergeEnqueued(deps, options) {
19802
19801
  async function readGhPrStateWithRetry(fetchState, options) {
19803
19802
  const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
19804
19803
  const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
19805
- const sleep3 = options?.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
19804
+ const sleep3 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
19806
19805
  let lastError = "empty state";
19807
19806
  for (let attempt = 0; attempt < retries; attempt++) {
19808
19807
  try {
@@ -19909,7 +19908,7 @@ function healthPollIntervalMs() {
19909
19908
  return HEALTH_POLL_INTERVAL_MS;
19910
19909
  }
19911
19910
  function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
19912
- return new Promise((resolve6, reject) => {
19911
+ return new Promise((resolve7, reject) => {
19913
19912
  let settled = false;
19914
19913
  const finish = (fn) => {
19915
19914
  if (settled) return;
@@ -19919,7 +19918,7 @@ function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
19919
19918
  child2.removeAllListeners("exit");
19920
19919
  fn();
19921
19920
  };
19922
- const timer = setTimeout(() => finish(resolve6), graceMs);
19921
+ const timer = setTimeout(() => finish(resolve7), graceMs);
19923
19922
  child2.on("error", (err) => finish(() => reject(new Error(`stage process failed to start: ${err.message}`))));
19924
19923
  child2.on("exit", (code, signal) => {
19925
19924
  const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
@@ -20129,10 +20128,10 @@ function pickStagePort(range, isFree) {
20129
20128
  throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
20130
20129
  }
20131
20130
  function isPortFree(port) {
20132
- return new Promise((resolve6) => {
20131
+ return new Promise((resolve7) => {
20133
20132
  const srv = (0, import_node_net.createServer)();
20134
- srv.once("error", () => resolve6(false));
20135
- srv.once("listening", () => srv.close(() => resolve6(true)));
20133
+ srv.once("error", () => resolve7(false));
20134
+ srv.once("listening", () => srv.close(() => resolve7(true)));
20136
20135
  srv.listen(port, "127.0.0.1");
20137
20136
  });
20138
20137
  }
@@ -20343,7 +20342,7 @@ async function killTree(pid) {
20343
20342
  } catch {
20344
20343
  }
20345
20344
  }
20346
- await new Promise((resolve6) => setTimeout(resolve6, 500));
20345
+ await new Promise((resolve7) => setTimeout(resolve7, 500));
20347
20346
  try {
20348
20347
  process.kill(-pid, "SIGKILL");
20349
20348
  } catch {
@@ -20364,7 +20363,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
20364
20363
  } catch (e) {
20365
20364
  last = e.message;
20366
20365
  }
20367
- await new Promise((resolve6) => setTimeout(resolve6, healthPollIntervalMs()));
20366
+ await new Promise((resolve7) => setTimeout(resolve7, healthPollIntervalMs()));
20368
20367
  }
20369
20368
  throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
20370
20369
  }
@@ -21775,7 +21774,7 @@ async function setBoardItemPriority(client, cfg, itemId, priority) {
21775
21774
  await updateItemSingleSelect(client, cfg.projectId, itemId, cfg.priorityFieldId, optionId);
21776
21775
  return cliPriorityToFieldName(priority);
21777
21776
  }
21778
- var defaultRetrySleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
21777
+ var defaultRetrySleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
21779
21778
  async function resolveProjectItemIdWithRetry(client, cfg, selector, opts = {}) {
21780
21779
  const attempts = Math.max(1, opts.attempts ?? 5);
21781
21780
  const delayMs = opts.delayMs ?? 300;
@@ -24184,7 +24183,7 @@ function clean3(out) {
24184
24183
  return out.trim();
24185
24184
  }
24186
24185
  function sleeper(deps) {
24187
- return deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
24186
+ return deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
24188
24187
  }
24189
24188
  function normalizeHotfixVersion(input) {
24190
24189
  const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
@@ -28013,7 +28012,7 @@ async function awsJson(args) {
28013
28012
  try {
28014
28013
  return await run();
28015
28014
  } catch {
28016
- await new Promise((resolve6) => setTimeout(resolve6, AWS_RETRY_DELAY_MS));
28015
+ await new Promise((resolve7) => setTimeout(resolve7, AWS_RETRY_DELAY_MS));
28017
28016
  return run();
28018
28017
  }
28019
28018
  }
@@ -30867,7 +30866,7 @@ function boardAdvanceFailureMessage(result) {
30867
30866
  // src/deferred-registry-store.ts
30868
30867
  var import_promises8 = require("node:fs/promises");
30869
30868
  var import_node_path38 = require("node:path");
30870
- var sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
30869
+ var sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
30871
30870
  async function atomicWrite(target, contents) {
30872
30871
  const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
30873
30872
  await (0, import_promises8.writeFile)(tmp, contents, "utf8");
@@ -31482,7 +31481,7 @@ async function resolvePrimaryCheckout(execGit) {
31482
31481
  function worktreeRemoveDeps(execGit) {
31483
31482
  return {
31484
31483
  git: execGit,
31485
- sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
31484
+ sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
31486
31485
  // #3064: unlink any reparse point (esp. a `node_modules` junction to base) before the git-native
31487
31486
  // `worktree remove --force`, which would otherwise recurse through it and empty the base checkout.
31488
31487
  detachReparsePoints: (worktreePath) => detachReparsePoints(worktreePath, realWorktreeDirRemover),
@@ -31661,7 +31660,7 @@ var PR_SNAPSHOT_READ_DELAY_MS = 2e3;
31661
31660
  async function readRestPrSnapshotWithRetry(prNumber, repo, gh = defaultGhApi, options) {
31662
31661
  const retries = options?.retries ?? PR_SNAPSHOT_READ_RETRIES;
31663
31662
  const delayMs = options?.delayMs ?? PR_SNAPSHOT_READ_DELAY_MS;
31664
- const sleep3 = options?.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
31663
+ const sleep3 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
31665
31664
  let lastError = "no attempt completed";
31666
31665
  for (let attempt = 0; attempt < retries; attempt++) {
31667
31666
  try {
@@ -32485,7 +32484,27 @@ function registerWorktreeCommands(program3) {
32485
32484
  const worktree2 = program3.commands.find((c) => c.name() === "worktree");
32486
32485
  if (!worktree2) return;
32487
32486
  const has = (name) => worktree2.commands.some((c) => c.name() === name);
32488
- if (has("land") && has("list")) return;
32487
+ if (has("land") && has("list") && has("path")) return;
32488
+ if (!has("path")) worktree2.command("path <branch-or-issue>").description("print the absolute canonical worktree path for a branch or issue ref").action(async (target) => {
32489
+ try {
32490
+ let branch = target;
32491
+ if (isIssueRef(target)) {
32492
+ const repo = await resolveRepo();
32493
+ if (!repo) return fail("worktree path: could not resolve the repo for the issue ref (run from a repo checkout)");
32494
+ const qualifiedRepo = /^([\w.-]+\/[\w.-]+)#\d+$/.exec(target)?.[1];
32495
+ if (qualifiedRepo && qualifiedRepo.toLowerCase() !== repo.toLowerCase()) {
32496
+ return fail(`worktree path: issue ${target} belongs to ${qualifiedRepo}; re-run from that repository's primary checkout`);
32497
+ }
32498
+ const number = Number(target.match(/\d+$/)?.[0]);
32499
+ const title = await fetchIssueTitle(repo, number);
32500
+ branch = buildNewBranchName(number, title ? slugifyIssueTitle(title) : "");
32501
+ }
32502
+ const primaryRoot = await primaryCheckoutRootOf(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
32503
+ console.log(defaultWorktreePath(primaryRoot ?? process.cwd(), branch));
32504
+ } catch (e) {
32505
+ return failGraceful(`worktree path: ${e.message}`);
32506
+ }
32507
+ });
32489
32508
  if (!has("land")) worktree2.command("land").description("post-merge clean: remove the current worktree, delete its local + origin branch, and stop its dev stage (dry-run by default)").option("--apply", "execute the cleanup (default: dry-run preview)").option("--dry-run", "show what would be removed without doing it (default)").option("--remote <name>", "remote whose branch is deleted", DEFAULT_REMOTE).option("--keep-remote", "do not delete the remote (origin) branch").option("--json", "machine-readable output").action(async (o) => {
32490
32509
  if (o.apply && o.dryRun) return fail("worktree land: choose either --dry-run or --apply");
32491
32510
  const apply = Boolean(o.apply);
@@ -32762,7 +32781,8 @@ function registerWorktreeCommands(program3) {
32762
32781
  const lines = ["worktree list:"];
32763
32782
  for (const wt of ctx.worktrees) {
32764
32783
  const tag = wt.primary ? "primary" : "worktree";
32765
- lines.push(` ${wt.branch} @ ${wt.path} (${tag})`);
32784
+ lines.push(` ${tag} path: ${wt.path}`);
32785
+ lines.push(` branch: ${wt.branch}`);
32766
32786
  }
32767
32787
  console.log(lines.join("\n"));
32768
32788
  } catch (e) {
@@ -32775,7 +32795,7 @@ async function gatherWorktreeContext() {
32775
32795
  const porcelain = (await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
32776
32796
  const parsed = parseWorktreePorcelain(porcelain);
32777
32797
  const primaryPath = parsed[0]?.path ?? repoRoot2;
32778
- const worktrees = parsed.map((w) => ({ path: toNativePath(w.path), branch: w.branch, primary: w.path === primaryPath }));
32798
+ const worktrees = parsed.map((w) => ({ path: (0, import_node_path41.resolve)(toNativePath(w.path)), branch: w.branch, primary: w.path === primaryPath }));
32779
32799
  const branchOut = (await execFileP2("git", ["branch", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
32780
32800
  const localBranches = branchOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
32781
32801
  const currentBranch2 = (await execFileP2("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || void 0;
@@ -38321,8 +38341,8 @@ function mmiDoctorDeps(opts = {}) {
38321
38341
  });
38322
38342
  const raced = await Promise.race([
38323
38343
  work.then((r) => ({ ...r, timedOut: false })),
38324
- new Promise((resolve6) => {
38325
- ceiling = setTimeout(() => resolve6({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
38344
+ new Promise((resolve7) => {
38345
+ ceiling = setTimeout(() => resolve7({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
38326
38346
  })
38327
38347
  ]);
38328
38348
  if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
@@ -38355,8 +38375,8 @@ function mmiDoctorDeps(opts = {}) {
38355
38375
  incomplete: nb.incomplete,
38356
38376
  timedOut: false
38357
38377
  })),
38358
- new Promise((resolve6) => {
38359
- ceiling = setTimeout(() => resolve6({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
38378
+ new Promise((resolve7) => {
38379
+ ceiling = setTimeout(() => resolve7({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
38360
38380
  })
38361
38381
  ]);
38362
38382
  if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
@@ -38870,7 +38890,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
38870
38890
  quiet ? "ignore" : "inherit",
38871
38891
  "pipe"
38872
38892
  ];
38873
- return new Promise((resolve6, reject) => {
38893
+ return new Promise((resolve7, reject) => {
38874
38894
  const child2 = opts?.shell ? (0, import_node_child_process19.spawn)(command, { cwd, stdio, windowsHide: true, shell: true }) : (() => {
38875
38895
  const [bin, ...args] = command.split(" ");
38876
38896
  const file = isWin2 ? "cmd.exe" : bin;
@@ -38897,7 +38917,7 @@ function runWorktreeInstall(command, cwd, quiet, opts) {
38897
38917
  });
38898
38918
  child2.on("exit", (code) => {
38899
38919
  clearTimeout(timer);
38900
- if (code === 0) return resolve6();
38920
+ if (code === 0) return resolve7();
38901
38921
  const tail = stderrTail.trim();
38902
38922
  reject(new Error(`${command} exited ${code} in ${cwd}${tail ? `
38903
38923
  ${tail}` : ""}`));
@@ -39107,7 +39127,7 @@ withExamples(mutating(
39107
39127
  await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS }).catch(() => {
39108
39128
  });
39109
39129
  },
39110
- sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
39130
+ sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
39111
39131
  log: (m) => {
39112
39132
  if (!o.json) console.error(` ${m}`);
39113
39133
  }
@@ -40764,7 +40784,7 @@ pr.command("checks-wait <number>").description(`bounded wait for PR checks; skip
40764
40784
  // reading as "your tests failed". One call per failing run, only at the verdict.
40765
40785
  diagnoseFailure: () => waitLoopDiagnosis("pr checks-wait", number, repo),
40766
40786
  baseBranch,
40767
- sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
40787
+ sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
40768
40788
  log: (message) => console.warn(message),
40769
40789
  timeoutMs,
40770
40790
  // Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
@@ -40844,7 +40864,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
40844
40864
  // then read its own wall-clock kill as a broken diff.
40845
40865
  diagnoseFailure: () => waitLoopDiagnosis("pr land", prNumber, repo),
40846
40866
  baseBranch: "development",
40847
- sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
40867
+ sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
40848
40868
  log: (message) => console.warn(message),
40849
40869
  // `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
40850
40870
  // 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
@@ -40887,7 +40907,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
40887
40907
  } else {
40888
40908
  lastFailure = void 0;
40889
40909
  }
40890
- await new Promise((resolve6) => setTimeout(resolve6, PR_LAND_POLL_MS));
40910
+ await new Promise((resolve7) => setTimeout(resolve7, PR_LAND_POLL_MS));
40891
40911
  }
40892
40912
  if (lastFailure) {
40893
40913
  throw new Error(
@@ -40987,7 +41007,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
40987
41007
  pollRateLimit: () => waitLoopCorePool("pr merge --wait"),
40988
41008
  diagnoseFailure: () => waitLoopDiagnosis("pr merge --wait", number, repo),
40989
41009
  baseBranch,
40990
- sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
41010
+ sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
40991
41011
  log: (message) => console.warn(message),
40992
41012
  progress: ({ state, elapsedMs, remainingMs }) => console.warn(`pr merge: --wait checks \u2014 ${state}, ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
40993
41013
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "3.132.1",
3
+ "version": "3.133.0",
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",