@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.
- package/dist/main.cjs +28 -105
- 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,
|
|
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
|
|
16808
|
+
const basename3 = workflowPath.split("/").pop() ?? workflowPath;
|
|
16816
16809
|
return {
|
|
16817
|
-
name: `${repo}/${
|
|
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", "
|
|
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
|
|
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(
|
|
22775
|
-
|
|
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 =
|
|
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("--
|
|
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.
|
|
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",
|