@mutmutco/cli 3.105.2 → 3.105.4
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 +298 -148
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -5000,7 +5000,7 @@ var program = new Command();
|
|
|
5000
5000
|
|
|
5001
5001
|
// src/index.ts
|
|
5002
5002
|
var import_promises11 = require("node:fs/promises");
|
|
5003
|
-
var
|
|
5003
|
+
var import_node_fs42 = require("node:fs");
|
|
5004
5004
|
var import_node_child_process19 = require("node:child_process");
|
|
5005
5005
|
|
|
5006
5006
|
// src/cli-shared.ts
|
|
@@ -8590,7 +8590,7 @@ function commandLadderHint() {
|
|
|
8590
8590
|
}
|
|
8591
8591
|
|
|
8592
8592
|
// src/index.ts
|
|
8593
|
-
var
|
|
8593
|
+
var import_node_path40 = require("node:path");
|
|
8594
8594
|
|
|
8595
8595
|
// src/merge-ci-policy.ts
|
|
8596
8596
|
function resolveMergeCiPolicy(input) {
|
|
@@ -15206,7 +15206,7 @@ async function executeWaveLand(plan, deps, opts = { preserveWorktree: true }) {
|
|
|
15206
15206
|
}
|
|
15207
15207
|
|
|
15208
15208
|
// src/index.ts
|
|
15209
|
-
var
|
|
15209
|
+
var import_node_os17 = require("node:os");
|
|
15210
15210
|
|
|
15211
15211
|
// src/board.ts
|
|
15212
15212
|
var import_node_child_process9 = require("node:child_process");
|
|
@@ -18832,13 +18832,25 @@ function liveEvidenceLines(evidence, repo) {
|
|
|
18832
18832
|
if (evidence.branch) live.push(`live branch ${evidence.branch} on ${repo}`);
|
|
18833
18833
|
return live;
|
|
18834
18834
|
}
|
|
18835
|
-
function
|
|
18836
|
-
|
|
18835
|
+
function sameClaimHost(a, b) {
|
|
18836
|
+
return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
|
|
18837
|
+
}
|
|
18838
|
+
function laneOwnership(marker, current) {
|
|
18839
|
+
if (!marker) return "unknown";
|
|
18840
|
+
if (marker.session && current.session) {
|
|
18841
|
+
return marker.session === current.session ? "mine" : "other";
|
|
18842
|
+
}
|
|
18843
|
+
if (marker.surface && current.surface && marker.surface !== current.surface) return "other";
|
|
18844
|
+
if (marker.host && current.host && !sameClaimHost(marker.host, current.host)) return "other";
|
|
18845
|
+
if (marker.surface && current.surface && marker.surface === current.surface && marker.host && current.host && sameClaimHost(marker.host, current.host)) {
|
|
18846
|
+
return "mine";
|
|
18847
|
+
}
|
|
18837
18848
|
return "unknown";
|
|
18838
18849
|
}
|
|
18839
18850
|
async function checkLaneContest(client, item) {
|
|
18840
18851
|
const evidence = await gatherClaimLiveness(client, item.repository, item.number, openPullsFetcher(client));
|
|
18841
|
-
const
|
|
18852
|
+
const actor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
|
|
18853
|
+
const ownership = laneOwnership(evidence.marker, actor);
|
|
18842
18854
|
const live = ownership === "mine" ? [] : liveEvidenceLines(evidence, item.repository);
|
|
18843
18855
|
const unverifiable = ownership === "mine" ? [] : evidence.failed;
|
|
18844
18856
|
return {
|
|
@@ -20413,6 +20425,14 @@ async function hotfixBaseTagForRelease(deps, tag) {
|
|
|
20413
20425
|
const current = normalizeHotfixVersion(tag).tag;
|
|
20414
20426
|
return tags.find((t) => compareHotfixVersions(t, current) < 0) ?? tags.find((t) => t !== current) ?? "origin/main^";
|
|
20415
20427
|
}
|
|
20428
|
+
async function hotfixReleaseExists(deps, ctx, tag) {
|
|
20429
|
+
try {
|
|
20430
|
+
await deps.run("gh", ["release", "view", tag, "--repo", ctx.repo, "--json", "tagName"]);
|
|
20431
|
+
return true;
|
|
20432
|
+
} catch {
|
|
20433
|
+
return false;
|
|
20434
|
+
}
|
|
20435
|
+
}
|
|
20416
20436
|
async function runHotfixStart(deps, options) {
|
|
20417
20437
|
const ctx = await buildTrainApplyContext(deps);
|
|
20418
20438
|
const deployModel = await resolveHotfixDeployModel(deps, ctx);
|
|
@@ -20425,7 +20445,11 @@ async function runHotfixStart(deps, options) {
|
|
|
20425
20445
|
const branch = hotfixBranch(tag);
|
|
20426
20446
|
const notes = [];
|
|
20427
20447
|
const existingPr = await findHotfixPr(deps, ctx, tag);
|
|
20428
|
-
|
|
20448
|
+
const existingState = (existingPr?.state ?? "").toUpperCase();
|
|
20449
|
+
const releaseExists = existingState === "MERGED" ? await hotfixReleaseExists(deps, ctx, tag) : false;
|
|
20450
|
+
const reusable = existingState === "OPEN" || existingState === "MERGED" && releaseExists;
|
|
20451
|
+
if (existingPr && reusable) {
|
|
20452
|
+
const next = existingState === "MERGED" ? `next: mmi-cli hotfix release ${tag}` : `next: merge it, then mmi-cli hotfix release ${tag}`;
|
|
20429
20453
|
return {
|
|
20430
20454
|
...ctx,
|
|
20431
20455
|
command: "hotfix-start",
|
|
@@ -20435,9 +20459,18 @@ async function runHotfixStart(deps, options) {
|
|
|
20435
20459
|
source: options.from,
|
|
20436
20460
|
prUrl: existingPr.url,
|
|
20437
20461
|
reused: true,
|
|
20438
|
-
notes: [`hotfix PR for ${tag} already exists (#${existingPr.number}, ${existingPr.state}) \u2014 reused;
|
|
20462
|
+
notes: [`hotfix PR for ${tag} already exists (#${existingPr.number}, ${existingPr.state}) \u2014 reused; ${next}`]
|
|
20439
20463
|
};
|
|
20440
20464
|
}
|
|
20465
|
+
if (existingPr) {
|
|
20466
|
+
const reason = existingState === "MERGED" && !releaseExists ? `MERGED with no GitHub Release for ${tag} \u2014 recreating ${branch} from origin/main (#4381/#4383)` : `${existingPr.state} \u2014 recreating ${branch} from origin/main (#4369)`;
|
|
20467
|
+
notes.push(`prior hotfix PR #${existingPr.number} is ${reason}`);
|
|
20468
|
+
const staleRemote = clean3(await deps.run("git", ["ls-remote", "origin", `refs/heads/${branch}`]));
|
|
20469
|
+
if (staleRemote) {
|
|
20470
|
+
await deps.run("git", ["push", "origin", "--delete", branch]);
|
|
20471
|
+
notes.push(`deleted stale origin/${branch} left by the incomplete train`);
|
|
20472
|
+
}
|
|
20473
|
+
}
|
|
20441
20474
|
const { sha, label } = await resolveHotfixSource(deps, ctx, options.from);
|
|
20442
20475
|
if (deployModel === "hub-serverless") {
|
|
20443
20476
|
await deps.run("node", ["scripts/release-distribution.mjs", "verify-deps"]);
|
|
@@ -28179,10 +28212,10 @@ function registerBoardCommands(program3) {
|
|
|
28179
28212
|
}
|
|
28180
28213
|
|
|
28181
28214
|
// src/merge-cleanup.ts
|
|
28182
|
-
var
|
|
28215
|
+
var import_node_fs35 = require("node:fs");
|
|
28183
28216
|
var import_promises8 = require("node:fs/promises");
|
|
28184
|
-
var
|
|
28185
|
-
var
|
|
28217
|
+
var import_node_path34 = require("node:path");
|
|
28218
|
+
var import_node_os13 = require("node:os");
|
|
28186
28219
|
var import_node_child_process17 = require("node:child_process");
|
|
28187
28220
|
|
|
28188
28221
|
// src/board-advance.ts
|
|
@@ -28348,6 +28381,117 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
28348
28381
|
};
|
|
28349
28382
|
}
|
|
28350
28383
|
|
|
28384
|
+
// src/jerv-cli-spawn.ts
|
|
28385
|
+
var import_node_fs34 = require("node:fs");
|
|
28386
|
+
var import_node_os12 = require("node:os");
|
|
28387
|
+
var import_node_path33 = require("node:path");
|
|
28388
|
+
var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
|
|
28389
|
+
var POSIX_NAMES = ["jerv-cli"];
|
|
28390
|
+
var JERV_CLI_ENTRY = (0, import_node_path33.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
28391
|
+
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
28392
|
+
if (platform2 !== "win32") {
|
|
28393
|
+
return pathEnv.split(import_node_path33.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
28394
|
+
}
|
|
28395
|
+
if (pathEnv.includes(";")) {
|
|
28396
|
+
return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
|
|
28397
|
+
}
|
|
28398
|
+
const looksUnix = pathEnv.startsWith("/") || /(?:^|:)\/[a-zA-Z]\//.test(pathEnv);
|
|
28399
|
+
if (looksUnix && pathEnv.includes(":")) {
|
|
28400
|
+
return pathEnv.split(":").map((e) => e.trim()).filter(Boolean);
|
|
28401
|
+
}
|
|
28402
|
+
return pathEnv.trim() ? [pathEnv.trim()] : [];
|
|
28403
|
+
}
|
|
28404
|
+
function normalizeSpawnPathEntry(entry, platform2 = process.platform) {
|
|
28405
|
+
const trimmed = entry.trim();
|
|
28406
|
+
if (!trimmed) return void 0;
|
|
28407
|
+
if (platform2 !== "win32") return trimmed;
|
|
28408
|
+
const msys = /^\/([a-zA-Z])\/(.*)$/.exec(trimmed.replace(/\\/g, "/"));
|
|
28409
|
+
if (msys) return `${msys[1].toUpperCase()}:\\${msys[2].replace(/\//g, "\\")}`;
|
|
28410
|
+
return trimmed;
|
|
28411
|
+
}
|
|
28412
|
+
function jervCliCandidateDirs(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
|
|
28413
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28414
|
+
const out = [];
|
|
28415
|
+
const push = (dir) => {
|
|
28416
|
+
if (!dir) return;
|
|
28417
|
+
const key = platform2 === "win32" ? dir.toLowerCase() : dir;
|
|
28418
|
+
if (seen.has(key)) return;
|
|
28419
|
+
seen.add(key);
|
|
28420
|
+
out.push(dir);
|
|
28421
|
+
};
|
|
28422
|
+
for (const entry of pathEnvEntries(env.PATH ?? "", platform2)) {
|
|
28423
|
+
push(normalizeSpawnPathEntry(entry, platform2));
|
|
28424
|
+
}
|
|
28425
|
+
if (platform2 === "win32") {
|
|
28426
|
+
if (env.APPDATA) push((0, import_node_path33.join)(env.APPDATA, "npm"));
|
|
28427
|
+
if (env.LOCALAPPDATA) push((0, import_node_path33.join)(env.LOCALAPPDATA, "npm"));
|
|
28428
|
+
} else {
|
|
28429
|
+
push((0, import_node_path33.join)(home, ".local", "bin"));
|
|
28430
|
+
}
|
|
28431
|
+
return out;
|
|
28432
|
+
}
|
|
28433
|
+
function jervCliCandidatePaths(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform) {
|
|
28434
|
+
const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
|
|
28435
|
+
const out = [];
|
|
28436
|
+
for (const dir of jervCliCandidateDirs(env, home, platform2)) {
|
|
28437
|
+
for (const name of names) out.push((0, import_node_path33.join)(dir, name));
|
|
28438
|
+
}
|
|
28439
|
+
return out;
|
|
28440
|
+
}
|
|
28441
|
+
function resolveJervCliPath(env = process.env, home = (0, import_node_os12.homedir)(), platform2 = process.platform, exists = import_node_fs34.existsSync) {
|
|
28442
|
+
for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
|
|
28443
|
+
if (exists(candidate)) return candidate;
|
|
28444
|
+
}
|
|
28445
|
+
return void 0;
|
|
28446
|
+
}
|
|
28447
|
+
function resolveJervCliNodeEntry(shimPath, exists = import_node_fs34.existsSync) {
|
|
28448
|
+
const entry = (0, import_node_path33.join)((0, import_node_path33.dirname)(shimPath), JERV_CLI_ENTRY);
|
|
28449
|
+
return exists(entry) ? entry : void 0;
|
|
28450
|
+
}
|
|
28451
|
+
function jervCliExecFileArgs(args, opts = {}) {
|
|
28452
|
+
const platform2 = opts.platform ?? process.platform;
|
|
28453
|
+
const exists = opts.exists ?? import_node_fs34.existsSync;
|
|
28454
|
+
const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os12.homedir)(), platform2, exists);
|
|
28455
|
+
if (resolved) {
|
|
28456
|
+
const entry = resolveJervCliNodeEntry(resolved, exists);
|
|
28457
|
+
if (entry) {
|
|
28458
|
+
return { file: opts.execPath ?? process.execPath, args: [entry, ...args], via: "node-entry" };
|
|
28459
|
+
}
|
|
28460
|
+
}
|
|
28461
|
+
const bin = resolved ?? "jerv-cli";
|
|
28462
|
+
if (platform2 === "win32") {
|
|
28463
|
+
return { file: "cmd.exe", args: ["/c", bin, ...args], via: resolved ? "cmd-shim" : "bare" };
|
|
28464
|
+
}
|
|
28465
|
+
return { file: bin, args: [...args], via: resolved ? "posix" : "bare" };
|
|
28466
|
+
}
|
|
28467
|
+
function formatJervCliSpawnFailure(err, plan, candidates) {
|
|
28468
|
+
const base = (err.stderr?.trim() || err.message.trim()).split("\n")[0] || "spawn failed";
|
|
28469
|
+
const code = err.code;
|
|
28470
|
+
if (code !== "ENOENT" && !/\bENOENT\b/i.test(base)) return base;
|
|
28471
|
+
const tried = candidates.length > 0 ? candidates.join(" | ") : "(no candidates)";
|
|
28472
|
+
return `${base} [via=${plan.via} file=${plan.file}; tried: ${tried}]`;
|
|
28473
|
+
}
|
|
28474
|
+
function isEnoent(err) {
|
|
28475
|
+
const code = err.code;
|
|
28476
|
+
if (code === "ENOENT") return true;
|
|
28477
|
+
return /\bENOENT\b/i.test(err.message ?? "");
|
|
28478
|
+
}
|
|
28479
|
+
function execJervCli(args, options = {}) {
|
|
28480
|
+
const env = options.env ?? process.env;
|
|
28481
|
+
const candidates = jervCliCandidatePaths(env);
|
|
28482
|
+
const plan = jervCliExecFileArgs(args, { env });
|
|
28483
|
+
return execFileP2(plan.file, plan.args, options).catch((err) => {
|
|
28484
|
+
if (!isEnoent(err)) throw err;
|
|
28485
|
+
const wrapped = new Error(formatJervCliSpawnFailure(err, plan, candidates));
|
|
28486
|
+
Object.assign(wrapped, {
|
|
28487
|
+
code: "ENOENT",
|
|
28488
|
+
stderr: err.stderr,
|
|
28489
|
+
cause: err
|
|
28490
|
+
});
|
|
28491
|
+
throw wrapped;
|
|
28492
|
+
});
|
|
28493
|
+
}
|
|
28494
|
+
|
|
28351
28495
|
// src/merge-cleanup.ts
|
|
28352
28496
|
var GC_GH_TIMEOUT_MS2 = 2e4;
|
|
28353
28497
|
async function advanceClosedIssuesToDone2(prNumber, repoOption) {
|
|
@@ -28466,7 +28610,8 @@ function assertPrMergeHousekeepingClean(startingPath, context, options = {}) {
|
|
|
28466
28610
|
if (verdict.blocked) throw new Error(verdict.reason);
|
|
28467
28611
|
return housekeeping;
|
|
28468
28612
|
}
|
|
28469
|
-
|
|
28613
|
+
var defaultLeaseCloseExec = (_cmd, args) => execJervCli(args, { timeout: GIT_TIMEOUT_MS });
|
|
28614
|
+
async function bestEffortLeaseClose(wtPath, exec = defaultLeaseCloseExec) {
|
|
28470
28615
|
const step = "close jerv worktree lease";
|
|
28471
28616
|
try {
|
|
28472
28617
|
await exec("jerv-cli", ["lease", "close", "--ref", wtPath]);
|
|
@@ -28489,7 +28634,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
28489
28634
|
);
|
|
28490
28635
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
28491
28636
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
28492
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
28637
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path34.dirname)((0, import_node_path34.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
28493
28638
|
const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
|
|
28494
28639
|
const owners = readWorktreeOwners(primaryRepoRoot);
|
|
28495
28640
|
const removalNow = Date.now();
|
|
@@ -28520,7 +28665,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
28520
28665
|
const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
|
|
28521
28666
|
beforeWorktrees,
|
|
28522
28667
|
startingPath: branch.worktreePath,
|
|
28523
|
-
pathExists: (p) => (0,
|
|
28668
|
+
pathExists: (p) => (0, import_node_fs35.existsSync)(p),
|
|
28524
28669
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
28525
28670
|
teardownWorktreeStage,
|
|
28526
28671
|
deferredStore,
|
|
@@ -28549,7 +28694,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
28549
28694
|
let removalAttempted = false;
|
|
28550
28695
|
try {
|
|
28551
28696
|
const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
|
|
28552
|
-
realpath: (path2) => (0,
|
|
28697
|
+
realpath: (path2) => (0, import_node_fs35.realpathSync)(path2)
|
|
28553
28698
|
});
|
|
28554
28699
|
if (!cleanupTarget.ok) {
|
|
28555
28700
|
result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
|
|
@@ -28636,13 +28781,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
|
|
|
28636
28781
|
const commits = JSON.parse(raw).commits ?? [];
|
|
28637
28782
|
const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
|
|
28638
28783
|
if (!body) return void 0;
|
|
28639
|
-
const dir = (0,
|
|
28640
|
-
const path2 = (0,
|
|
28641
|
-
(0,
|
|
28784
|
+
const dir = (0, import_node_fs35.mkdtempSync)((0, import_node_path34.join)((0, import_node_os13.tmpdir)(), "mmi-squash-body-"));
|
|
28785
|
+
const path2 = (0, import_node_path34.join)(dir, "body.txt");
|
|
28786
|
+
(0, import_node_fs35.writeFileSync)(path2, `${body}
|
|
28642
28787
|
`, "utf8");
|
|
28643
28788
|
return { path: path2, cleanup: () => {
|
|
28644
28789
|
try {
|
|
28645
|
-
(0,
|
|
28790
|
+
(0, import_node_fs35.rmSync)(dir, { recursive: true, force: true });
|
|
28646
28791
|
} catch {
|
|
28647
28792
|
}
|
|
28648
28793
|
} };
|
|
@@ -28764,13 +28909,13 @@ var realWorktreeDirRemover = {
|
|
|
28764
28909
|
probe: (p) => {
|
|
28765
28910
|
let st;
|
|
28766
28911
|
try {
|
|
28767
|
-
st = (0,
|
|
28912
|
+
st = (0, import_node_fs35.lstatSync)(p);
|
|
28768
28913
|
} catch {
|
|
28769
28914
|
return null;
|
|
28770
28915
|
}
|
|
28771
28916
|
if (st.isSymbolicLink()) return "link";
|
|
28772
28917
|
try {
|
|
28773
|
-
(0,
|
|
28918
|
+
(0, import_node_fs35.readlinkSync)(p);
|
|
28774
28919
|
return "link";
|
|
28775
28920
|
} catch {
|
|
28776
28921
|
}
|
|
@@ -28778,7 +28923,7 @@ var realWorktreeDirRemover = {
|
|
|
28778
28923
|
},
|
|
28779
28924
|
readdir: (p) => {
|
|
28780
28925
|
try {
|
|
28781
|
-
return (0,
|
|
28926
|
+
return (0, import_node_fs35.readdirSync)(p);
|
|
28782
28927
|
} catch {
|
|
28783
28928
|
return [];
|
|
28784
28929
|
}
|
|
@@ -28787,9 +28932,9 @@ var realWorktreeDirRemover = {
|
|
|
28787
28932
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
28788
28933
|
detachLink: (p) => {
|
|
28789
28934
|
try {
|
|
28790
|
-
(0,
|
|
28935
|
+
(0, import_node_fs35.rmdirSync)(p);
|
|
28791
28936
|
} catch {
|
|
28792
|
-
(0,
|
|
28937
|
+
(0, import_node_fs35.unlinkSync)(p);
|
|
28793
28938
|
}
|
|
28794
28939
|
},
|
|
28795
28940
|
removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
@@ -28822,9 +28967,9 @@ async function worktreeHasStageState(worktreePath) {
|
|
|
28822
28967
|
}
|
|
28823
28968
|
}
|
|
28824
28969
|
function stageStateFileBelongsToWorktree(statePath, worktreePath) {
|
|
28825
|
-
if (!(0,
|
|
28970
|
+
if (!(0, import_node_fs35.existsSync)(statePath)) return false;
|
|
28826
28971
|
try {
|
|
28827
|
-
const state = JSON.parse((0,
|
|
28972
|
+
const state = JSON.parse((0, import_node_fs35.readFileSync)(statePath, "utf8"));
|
|
28828
28973
|
const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
|
|
28829
28974
|
return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
|
|
28830
28975
|
} catch {
|
|
@@ -29155,9 +29300,9 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
29155
29300
|
}
|
|
29156
29301
|
|
|
29157
29302
|
// src/worktree-lifecycle-commands.ts
|
|
29158
|
-
var
|
|
29303
|
+
var import_node_fs36 = require("node:fs");
|
|
29159
29304
|
var import_promises9 = require("node:fs/promises");
|
|
29160
|
-
var
|
|
29305
|
+
var import_node_path35 = require("node:path");
|
|
29161
29306
|
var GH_TIMEOUT_MS = 2e4;
|
|
29162
29307
|
var STALE_PR_LOOKUP_LIMIT = 20;
|
|
29163
29308
|
var DEFAULT_BASE = "origin/development";
|
|
@@ -29304,7 +29449,7 @@ function classifyStaleLeaks(input) {
|
|
|
29304
29449
|
var defaultOrphanDirScanDeps = {
|
|
29305
29450
|
listDirs: (root) => {
|
|
29306
29451
|
try {
|
|
29307
|
-
return (0,
|
|
29452
|
+
return (0, import_node_fs36.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path35.join)(root, e.name));
|
|
29308
29453
|
} catch {
|
|
29309
29454
|
return [];
|
|
29310
29455
|
}
|
|
@@ -29460,13 +29605,13 @@ function registerWorktreeCommands(program3) {
|
|
|
29460
29605
|
const detached = headBorn && !symbolicBranch;
|
|
29461
29606
|
const branch = symbolicBranch || (detached ? "HEAD" : "");
|
|
29462
29607
|
if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
|
|
29463
|
-
const gitFile = (0,
|
|
29464
|
-
const isLinked = (0,
|
|
29608
|
+
const gitFile = (0, import_node_path35.join)(wtPath, ".git");
|
|
29609
|
+
const isLinked = (0, import_node_fs36.existsSync)(gitFile) && (0, import_node_fs36.statSync)(gitFile).isFile();
|
|
29465
29610
|
if (apply && !isLinked) {
|
|
29466
29611
|
return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
|
|
29467
29612
|
}
|
|
29468
29613
|
const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
29469
|
-
const primaryCheckout = commonDir ? (0,
|
|
29614
|
+
const primaryCheckout = commonDir ? (0, import_node_path35.dirname)(commonDir) : wtPath;
|
|
29470
29615
|
const localBranchNames = await execFileP2("git", ["-C", primaryCheckout, "for-each-ref", "--format=%(refname:short)", "refs/heads"], { timeout: GIT_TIMEOUT_MS }).then(({ stdout }) => new Set((stdout || "").split("\n").map((l) => l.trim()).filter(Boolean))).catch(() => void 0);
|
|
29471
29616
|
const orphan = classifyOrphanedWorktree({
|
|
29472
29617
|
branch,
|
|
@@ -29675,10 +29820,10 @@ async function gatherWorktreeContext() {
|
|
|
29675
29820
|
if (s) stages.push({ path: wt.path, port: s.port });
|
|
29676
29821
|
}
|
|
29677
29822
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
29678
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
29823
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path35.dirname)((0, import_node_path35.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
29679
29824
|
const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
|
|
29680
29825
|
let orphanDirs = [];
|
|
29681
|
-
if ((0,
|
|
29826
|
+
if ((0, import_node_fs36.existsSync)(wtRoot)) {
|
|
29682
29827
|
orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
|
|
29683
29828
|
...defaultOrphanDirScanDeps,
|
|
29684
29829
|
listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
|
|
@@ -29704,7 +29849,7 @@ ${err.stderr ?? ""}`;
|
|
|
29704
29849
|
}
|
|
29705
29850
|
|
|
29706
29851
|
// src/issue-commands.ts
|
|
29707
|
-
var
|
|
29852
|
+
var import_node_fs37 = require("node:fs");
|
|
29708
29853
|
var import_node_crypto7 = require("node:crypto");
|
|
29709
29854
|
var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
|
|
29710
29855
|
var ReparentConflictError = class extends Error {
|
|
@@ -29722,7 +29867,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
29722
29867
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
29723
29868
|
const patch = {};
|
|
29724
29869
|
let bodyChanged = false;
|
|
29725
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
29870
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs37.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
29726
29871
|
if (options.titleFile !== void 0) {
|
|
29727
29872
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
29728
29873
|
} else if (options.title !== void 0) {
|
|
@@ -30327,7 +30472,7 @@ function extendCreateCommand(issue2, batchAttach) {
|
|
|
30327
30472
|
if (opts.batch) {
|
|
30328
30473
|
let specs;
|
|
30329
30474
|
try {
|
|
30330
|
-
const raw = (0,
|
|
30475
|
+
const raw = (0, import_node_fs37.readFileSync)(opts.batch, "utf8");
|
|
30331
30476
|
specs = JSON.parse(raw);
|
|
30332
30477
|
if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
|
|
30333
30478
|
} catch (e) {
|
|
@@ -30402,8 +30547,8 @@ ${lines}`, {
|
|
|
30402
30547
|
}
|
|
30403
30548
|
|
|
30404
30549
|
// src/train-commands.ts
|
|
30405
|
-
var
|
|
30406
|
-
var
|
|
30550
|
+
var import_node_fs38 = require("node:fs");
|
|
30551
|
+
var import_node_path36 = require("node:path");
|
|
30407
30552
|
|
|
30408
30553
|
// src/train-status.ts
|
|
30409
30554
|
function buildTrainStatusReport(input) {
|
|
@@ -30443,7 +30588,7 @@ function formatTrainStatus(r) {
|
|
|
30443
30588
|
// src/train-commands.ts
|
|
30444
30589
|
function readRepoVersion() {
|
|
30445
30590
|
try {
|
|
30446
|
-
return JSON.parse((0,
|
|
30591
|
+
return JSON.parse((0, import_node_fs38.readFileSync)((0, import_node_path36.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
30447
30592
|
} catch {
|
|
30448
30593
|
return void 0;
|
|
30449
30594
|
}
|
|
@@ -30589,9 +30734,9 @@ function registerDeployCommands(program3) {
|
|
|
30589
30734
|
}
|
|
30590
30735
|
|
|
30591
30736
|
// src/discovery-commands.ts
|
|
30592
|
-
var
|
|
30593
|
-
var
|
|
30594
|
-
var
|
|
30737
|
+
var import_node_fs39 = require("node:fs");
|
|
30738
|
+
var import_node_os14 = require("node:os");
|
|
30739
|
+
var import_node_path37 = require("node:path");
|
|
30595
30740
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
30596
30741
|
async function collectStatus() {
|
|
30597
30742
|
const repo = await resolveRepo();
|
|
@@ -30779,10 +30924,10 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
30779
30924
|
else if (top) nextCommand = `mmi-cli board claim ${top.number} # ${top.title}`;
|
|
30780
30925
|
else nextCommand = "mmi-cli board read \u2014 no claimable items found";
|
|
30781
30926
|
}
|
|
30782
|
-
const home = (0,
|
|
30927
|
+
const home = (0, import_node_os14.homedir)();
|
|
30783
30928
|
const plugin = onboardPluginGate({
|
|
30784
|
-
readKnown: () => readFileSyncSafe((0,
|
|
30785
|
-
readSettings: () => readFileSyncSafe((0,
|
|
30929
|
+
readKnown: () => readFileSyncSafe((0, import_node_path37.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs39.readFileSync),
|
|
30930
|
+
readSettings: () => readFileSyncSafe((0, import_node_path37.join)(home, ".claude", "settings.json"), import_node_fs39.readFileSync)
|
|
30786
30931
|
});
|
|
30787
30932
|
return { track, board, registry: registry2, secrets, plugin, estateCli, nextCommand };
|
|
30788
30933
|
}
|
|
@@ -31686,19 +31831,19 @@ function registerSessionReport(program3) {
|
|
|
31686
31831
|
}
|
|
31687
31832
|
|
|
31688
31833
|
// src/plugin-release-catchup.ts
|
|
31689
|
-
var
|
|
31690
|
-
var
|
|
31691
|
-
var
|
|
31834
|
+
var import_node_fs40 = require("node:fs");
|
|
31835
|
+
var import_node_path38 = require("node:path");
|
|
31836
|
+
var import_node_os15 = require("node:os");
|
|
31692
31837
|
var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
31693
31838
|
var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
|
|
31694
31839
|
function releaseCatchupStatePath(env = process.env) {
|
|
31695
31840
|
if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
|
|
31696
31841
|
if (process.platform === "win32") {
|
|
31697
|
-
const base2 = env.LOCALAPPDATA || (0,
|
|
31698
|
-
return (0,
|
|
31842
|
+
const base2 = env.LOCALAPPDATA || (0, import_node_path38.join)((0, import_node_os15.homedir)(), "AppData", "Local");
|
|
31843
|
+
return (0, import_node_path38.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
|
|
31699
31844
|
}
|
|
31700
|
-
const base = env.XDG_STATE_HOME || (0,
|
|
31701
|
-
return (0,
|
|
31845
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path38.join)((0, import_node_os15.homedir)(), ".local", "state");
|
|
31846
|
+
return (0, import_node_path38.join)(base, "mmi-cli", "release-catchup.json");
|
|
31702
31847
|
}
|
|
31703
31848
|
function releaseCatchupDue(state, now, force = false) {
|
|
31704
31849
|
if (force) return true;
|
|
@@ -31708,7 +31853,7 @@ function releaseCatchupDue(state, now, force = false) {
|
|
|
31708
31853
|
function newestCachedPluginVersion(home) {
|
|
31709
31854
|
let names;
|
|
31710
31855
|
try {
|
|
31711
|
-
names = (0,
|
|
31856
|
+
names = (0, import_node_fs40.readdirSync)(pluginCacheRoot(home));
|
|
31712
31857
|
} catch {
|
|
31713
31858
|
return void 0;
|
|
31714
31859
|
}
|
|
@@ -31716,15 +31861,15 @@ function newestCachedPluginVersion(home) {
|
|
|
31716
31861
|
}
|
|
31717
31862
|
function marketplaceClonePath(home) {
|
|
31718
31863
|
try {
|
|
31719
|
-
const parsed = JSON.parse((0,
|
|
31864
|
+
const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
|
|
31720
31865
|
if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
|
|
31721
31866
|
} catch {
|
|
31722
31867
|
}
|
|
31723
|
-
return (0,
|
|
31868
|
+
return (0, import_node_path38.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
|
|
31724
31869
|
}
|
|
31725
31870
|
function readCatalogVersion(home) {
|
|
31726
31871
|
try {
|
|
31727
|
-
const parsed = JSON.parse((0,
|
|
31872
|
+
const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
|
|
31728
31873
|
return parsed.plugins?.find((p) => p.name === "mmi")?.version;
|
|
31729
31874
|
} catch {
|
|
31730
31875
|
return void 0;
|
|
@@ -31732,7 +31877,7 @@ function readCatalogVersion(home) {
|
|
|
31732
31877
|
}
|
|
31733
31878
|
function readMmiInstallRecord(home) {
|
|
31734
31879
|
try {
|
|
31735
|
-
const parsed = JSON.parse((0,
|
|
31880
|
+
const parsed = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path38.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
|
|
31736
31881
|
const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
|
|
31737
31882
|
return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
|
|
31738
31883
|
} catch {
|
|
@@ -31741,7 +31886,7 @@ function readMmiInstallRecord(home) {
|
|
|
31741
31886
|
}
|
|
31742
31887
|
async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
31743
31888
|
if (env[RELEASE_CATCHUP_DISABLE_ENV]) return { ok: true, skipped: true, detail: `disabled via ${RELEASE_CATCHUP_DISABLE_ENV}` };
|
|
31744
|
-
if (!(0,
|
|
31889
|
+
if (!(0, import_node_fs40.existsSync)(pluginCacheRoot(home))) return { ok: true, skipped: true, detail: "no mmi plugin cache on this machine \u2014 nothing to catch up" };
|
|
31745
31890
|
const statePath = releaseCatchupStatePath(env);
|
|
31746
31891
|
const state = deps.readState(statePath);
|
|
31747
31892
|
if (!releaseCatchupDue(state, deps.now(), opts.force)) {
|
|
@@ -31766,8 +31911,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
31766
31911
|
return { ok: false, detail: `released ${latest} but the install record could not be cleared \u2014 nothing changed (record still ${prior.version})` };
|
|
31767
31912
|
}
|
|
31768
31913
|
const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
|
|
31769
|
-
const payload = (0,
|
|
31770
|
-
if (!installed || !(0,
|
|
31914
|
+
const payload = (0, import_node_path38.join)(pluginCacheRoot(home), latest, ".pi-plugin");
|
|
31915
|
+
if (!installed || !(0, import_node_fs40.existsSync)(payload)) {
|
|
31771
31916
|
const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
|
|
31772
31917
|
if (!prior) return { ok: false, detail: `${why}; no prior record to restore` };
|
|
31773
31918
|
const rollback = await restorePriorRecord(home, prior, deps);
|
|
@@ -31795,7 +31940,7 @@ async function restorePriorRecord(home, prior, deps) {
|
|
|
31795
31940
|
}
|
|
31796
31941
|
function shouldSpawnReleaseCatchup(home, env, readState2, now = Date.now()) {
|
|
31797
31942
|
if (env[RELEASE_CATCHUP_DISABLE_ENV]) return false;
|
|
31798
|
-
if (!(0,
|
|
31943
|
+
if (!(0, import_node_fs40.existsSync)(pluginCacheRoot(home))) return false;
|
|
31799
31944
|
return releaseCatchupDue(readState2(releaseCatchupStatePath(env)), now);
|
|
31800
31945
|
}
|
|
31801
31946
|
function defaultRegistrationHeal(home, env) {
|
|
@@ -33841,17 +33986,17 @@ function parseOriginRepo(remoteUrl) {
|
|
|
33841
33986
|
}
|
|
33842
33987
|
function ghHostsConfigPath(env, platform2) {
|
|
33843
33988
|
const sep3 = platform2 === "win32" ? "\\" : "/";
|
|
33844
|
-
const
|
|
33989
|
+
const join36 = (...parts) => parts.join(sep3);
|
|
33845
33990
|
const explicit = env.GH_CONFIG_DIR?.trim();
|
|
33846
|
-
if (explicit) return
|
|
33991
|
+
if (explicit) return join36(explicit, "hosts.yml");
|
|
33847
33992
|
if (platform2 === "win32") {
|
|
33848
33993
|
const appData = (env.AppData ?? env.APPDATA)?.trim();
|
|
33849
|
-
return appData ?
|
|
33994
|
+
return appData ? join36(appData, "GitHub CLI", "hosts.yml") : void 0;
|
|
33850
33995
|
}
|
|
33851
33996
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
33852
|
-
if (xdg) return
|
|
33997
|
+
if (xdg) return join36(xdg, "gh", "hosts.yml");
|
|
33853
33998
|
const home = env.HOME?.trim();
|
|
33854
|
-
return home ?
|
|
33999
|
+
return home ? join36(home, ".config", "gh", "hosts.yml") : void 0;
|
|
33855
34000
|
}
|
|
33856
34001
|
function parseGhHostsAccounts(yaml, host = "github.com") {
|
|
33857
34002
|
let hostIndent = null;
|
|
@@ -33901,9 +34046,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
33901
34046
|
}
|
|
33902
34047
|
|
|
33903
34048
|
// src/doctor-io.ts
|
|
33904
|
-
var
|
|
33905
|
-
var
|
|
33906
|
-
var
|
|
34049
|
+
var import_node_fs41 = require("node:fs");
|
|
34050
|
+
var import_node_os16 = require("node:os");
|
|
34051
|
+
var import_node_path39 = require("node:path");
|
|
33907
34052
|
var import_node_child_process18 = require("node:child_process");
|
|
33908
34053
|
var import_node_util8 = require("node:util");
|
|
33909
34054
|
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process18.execFile);
|
|
@@ -33911,7 +34056,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
33911
34056
|
function installedClaudePluginVersion() {
|
|
33912
34057
|
try {
|
|
33913
34058
|
const file = JSON.parse(
|
|
33914
|
-
(0,
|
|
34059
|
+
(0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
33915
34060
|
);
|
|
33916
34061
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
33917
34062
|
if (versions.length === 0) return void 0;
|
|
@@ -33922,7 +34067,7 @@ function installedClaudePluginVersion() {
|
|
|
33922
34067
|
}
|
|
33923
34068
|
function manifestVersion(path2) {
|
|
33924
34069
|
try {
|
|
33925
|
-
const manifest = JSON.parse((0,
|
|
34070
|
+
const manifest = JSON.parse((0, import_node_fs41.readFileSync)(path2, "utf8"));
|
|
33926
34071
|
return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
|
|
33927
34072
|
} catch {
|
|
33928
34073
|
return void 0;
|
|
@@ -33932,22 +34077,22 @@ function installedSurfacePluginVersion(surface) {
|
|
|
33932
34077
|
const token = surfaceToken(surface);
|
|
33933
34078
|
if (token === "kilo") {
|
|
33934
34079
|
try {
|
|
33935
|
-
const stamp = (0,
|
|
34080
|
+
const stamp = (0, import_node_fs41.readFileSync)((0, import_node_path39.join)((0, import_node_os16.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
|
|
33936
34081
|
return stamp || void 0;
|
|
33937
34082
|
} catch {
|
|
33938
34083
|
return void 0;
|
|
33939
34084
|
}
|
|
33940
34085
|
}
|
|
33941
34086
|
if (token === "cursor") {
|
|
33942
|
-
return manifestVersion((0,
|
|
34087
|
+
return manifestVersion((0, import_node_path39.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
33943
34088
|
}
|
|
33944
34089
|
if (token === "jervcode") {
|
|
33945
34090
|
const entry = mmiPiWrapperEntry();
|
|
33946
34091
|
if (!entry) return void 0;
|
|
33947
|
-
return manifestVersion((0,
|
|
34092
|
+
return manifestVersion((0, import_node_path39.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
|
|
33948
34093
|
}
|
|
33949
34094
|
if (token === "kimi") {
|
|
33950
|
-
return manifestVersion((0,
|
|
34095
|
+
return manifestVersion((0, import_node_path39.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
|
|
33951
34096
|
}
|
|
33952
34097
|
if (token === "claude") return installedClaudePluginVersion();
|
|
33953
34098
|
if (token !== "codex") return void 0;
|
|
@@ -33985,13 +34130,13 @@ function worktreeRootSync() {
|
|
|
33985
34130
|
}
|
|
33986
34131
|
var gitignorePath = () => {
|
|
33987
34132
|
const root = worktreeRootSync();
|
|
33988
|
-
return root === null ? null : (0,
|
|
34133
|
+
return root === null ? null : (0, import_node_path39.join)(root, ".gitignore");
|
|
33989
34134
|
};
|
|
33990
34135
|
function readGitignore() {
|
|
33991
34136
|
const path2 = gitignorePath();
|
|
33992
34137
|
if (path2 === null) return null;
|
|
33993
34138
|
try {
|
|
33994
|
-
return (0,
|
|
34139
|
+
return (0, import_node_fs41.readFileSync)(path2, "utf8");
|
|
33995
34140
|
} catch {
|
|
33996
34141
|
return null;
|
|
33997
34142
|
}
|
|
@@ -34000,7 +34145,7 @@ function writeGitignore(content) {
|
|
|
34000
34145
|
const path2 = gitignorePath();
|
|
34001
34146
|
if (path2 === null) return false;
|
|
34002
34147
|
try {
|
|
34003
|
-
(0,
|
|
34148
|
+
(0, import_node_fs41.writeFileSync)(path2, content, "utf8");
|
|
34004
34149
|
return true;
|
|
34005
34150
|
} catch {
|
|
34006
34151
|
return false;
|
|
@@ -34024,7 +34169,7 @@ async function repoRoot() {
|
|
|
34024
34169
|
}
|
|
34025
34170
|
function hasRepoLocalWorktrees() {
|
|
34026
34171
|
const root = worktreeRootSync();
|
|
34027
|
-
return root !== null && (0,
|
|
34172
|
+
return root !== null && (0, import_node_fs41.existsSync)((0, import_node_path39.join)(root, ".worktrees"));
|
|
34028
34173
|
}
|
|
34029
34174
|
|
|
34030
34175
|
// src/index.ts
|
|
@@ -34043,8 +34188,8 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
34043
34188
|
function ghMultiAccountCaveat(announcedLogin) {
|
|
34044
34189
|
try {
|
|
34045
34190
|
const hostsPath = ghHostsConfigPath(process.env, process.platform);
|
|
34046
|
-
if (!hostsPath || !(0,
|
|
34047
|
-
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0,
|
|
34191
|
+
if (!hostsPath || !(0, import_node_fs42.existsSync)(hostsPath)) return void 0;
|
|
34192
|
+
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs42.readFileSync)(hostsPath, "utf8")));
|
|
34048
34193
|
} catch {
|
|
34049
34194
|
return void 0;
|
|
34050
34195
|
}
|
|
@@ -34052,12 +34197,12 @@ function ghMultiAccountCaveat(announcedLogin) {
|
|
|
34052
34197
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
34053
34198
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
34054
34199
|
function envHealLockPath(home) {
|
|
34055
|
-
return (0,
|
|
34200
|
+
return (0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
34056
34201
|
}
|
|
34057
34202
|
async function withEnvHealLock(what, run) {
|
|
34058
34203
|
try {
|
|
34059
34204
|
return await withFileLock(
|
|
34060
|
-
envHealLockPath((0,
|
|
34205
|
+
envHealLockPath((0, import_node_os17.homedir)()),
|
|
34061
34206
|
{ staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
|
|
34062
34207
|
run
|
|
34063
34208
|
);
|
|
@@ -34154,7 +34299,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
34154
34299
|
const configRoot = surfaceConfigRoot(surface);
|
|
34155
34300
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
34156
34301
|
const plan = buildPluginCachePlan(
|
|
34157
|
-
(0,
|
|
34302
|
+
(0, import_node_os17.homedir)(),
|
|
34158
34303
|
running,
|
|
34159
34304
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
34160
34305
|
{ configRoot, includeStaging: surface !== "codex" }
|
|
@@ -34178,14 +34323,14 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
34178
34323
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
34179
34324
|
const installed = installedActivePluginVersion(surface);
|
|
34180
34325
|
const plan = buildPluginCachePlan(
|
|
34181
|
-
(0,
|
|
34326
|
+
(0, import_node_os17.homedir)(),
|
|
34182
34327
|
running,
|
|
34183
34328
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
34184
34329
|
{ configRoot, includeStaging: surface !== "codex", installedVersion: installed }
|
|
34185
34330
|
);
|
|
34186
34331
|
const result = applyPluginCachePlan(
|
|
34187
34332
|
plan,
|
|
34188
|
-
(p) => (0,
|
|
34333
|
+
(p) => (0, import_node_fs42.rmSync)(p, { recursive: true }),
|
|
34189
34334
|
stagingApplyFsGuard(configRoot)
|
|
34190
34335
|
);
|
|
34191
34336
|
return {
|
|
@@ -34213,12 +34358,12 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
34213
34358
|
piPluginState: () => {
|
|
34214
34359
|
const env = { ...process.env };
|
|
34215
34360
|
delete env.CLAUDE_PLUGIN_ROOT;
|
|
34216
|
-
return readPiPluginState((0,
|
|
34361
|
+
return readPiPluginState((0, import_node_os17.homedir)(), env);
|
|
34217
34362
|
},
|
|
34218
34363
|
healPiPlugin: () => {
|
|
34219
34364
|
const env = { ...process.env };
|
|
34220
34365
|
delete env.CLAUDE_PLUGIN_ROOT;
|
|
34221
|
-
return healPiPluginRegistration((0,
|
|
34366
|
+
return healPiPluginRegistration((0, import_node_os17.homedir)(), env);
|
|
34222
34367
|
},
|
|
34223
34368
|
// #3470: what the SessionStart hook LAST emitted, measured at emission by the session-start verb below.
|
|
34224
34369
|
// A local record read ? cheap enough for every lane, including the banner.
|
|
@@ -34228,17 +34373,17 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
34228
34373
|
marketplaceRows: () => {
|
|
34229
34374
|
try {
|
|
34230
34375
|
if (detectSurface(process.env) === "codex") return [];
|
|
34231
|
-
const home = (0,
|
|
34376
|
+
const home = (0, import_node_os17.homedir)();
|
|
34232
34377
|
const rows = marketplaceRows(
|
|
34233
34378
|
MMI_MARKETPLACE_NAME,
|
|
34234
|
-
readFileSyncSafe((0,
|
|
34235
|
-
readFileSyncSafe((0,
|
|
34379
|
+
readFileSyncSafe((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs42.readFileSync),
|
|
34380
|
+
readFileSyncSafe((0, import_node_path40.join)(home, ".claude", "settings.json"), import_node_fs42.readFileSync),
|
|
34236
34381
|
// #3974: this CLI heals these rows, so report mode names the doctor run rather than the hand
|
|
34237
34382
|
// edit. Unconditional ? it is a fact about mmi-cli, not about the lane this run is on.
|
|
34238
34383
|
true
|
|
34239
34384
|
);
|
|
34240
34385
|
const pending = readMarketplacePinPending(
|
|
34241
|
-
(0,
|
|
34386
|
+
(0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
|
|
34242
34387
|
MMI_MARKETPLACE_NAME
|
|
34243
34388
|
);
|
|
34244
34389
|
if (!pending) return rows;
|
|
@@ -34262,11 +34407,11 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
34262
34407
|
healMarketplacePins: () => {
|
|
34263
34408
|
try {
|
|
34264
34409
|
if (detectSurface(process.env) === "codex") return void 0;
|
|
34265
|
-
const home = (0,
|
|
34410
|
+
const home = (0, import_node_os17.homedir)();
|
|
34266
34411
|
const names = [MMI_MARKETPLACE_NAME];
|
|
34267
|
-
const result = applyOrgMarketplacePins((0,
|
|
34412
|
+
const result = applyOrgMarketplacePins((0, import_node_path40.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
|
|
34268
34413
|
if (result?.wrote) {
|
|
34269
|
-
writeMarketplacePinPending((0,
|
|
34414
|
+
writeMarketplacePinPending((0, import_node_path40.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
|
|
34270
34415
|
}
|
|
34271
34416
|
return result;
|
|
34272
34417
|
} catch {
|
|
@@ -34282,7 +34427,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
34282
34427
|
// adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
|
|
34283
34428
|
// get a permanent ? demanding an artifact it never asked for.
|
|
34284
34429
|
docsIndexState: (root) => {
|
|
34285
|
-
if (!(0,
|
|
34430
|
+
if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
34286
34431
|
const real = createDocsIndexDeps(root);
|
|
34287
34432
|
let docs2;
|
|
34288
34433
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -34291,7 +34436,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
34291
34436
|
},
|
|
34292
34437
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
34293
34438
|
healDocsIndex: (root) => {
|
|
34294
|
-
if (!(0,
|
|
34439
|
+
if (!(0, import_node_fs42.existsSync)((0, import_node_path40.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
34295
34440
|
const real = createDocsIndexDeps(root);
|
|
34296
34441
|
let docs2;
|
|
34297
34442
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -34626,19 +34771,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
34626
34771
|
});
|
|
34627
34772
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
34628
34773
|
rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
|
|
34629
|
-
const path2 = (0,
|
|
34630
|
-
const current = (0,
|
|
34774
|
+
const path2 = (0, import_node_path40.join)(process.cwd(), ".gitignore");
|
|
34775
|
+
const current = (0, import_node_fs42.existsSync)(path2) ? (0, import_node_fs42.readFileSync)(path2, "utf8") : null;
|
|
34631
34776
|
const plan = planManagedGitignore(current);
|
|
34632
34777
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
34633
34778
|
if (opts.json) {
|
|
34634
|
-
if (opts.write && plan.changed) (0,
|
|
34779
|
+
if (opts.write && plan.changed) (0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
|
|
34635
34780
|
console.log(JSON.stringify(plan, null, 2));
|
|
34636
34781
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
34637
34782
|
return;
|
|
34638
34783
|
}
|
|
34639
34784
|
if (opts.write) {
|
|
34640
34785
|
if (plan.changed) {
|
|
34641
|
-
(0,
|
|
34786
|
+
(0, import_node_fs42.writeFileSync)(path2, plan.content, "utf8");
|
|
34642
34787
|
console.log(`mmi-cli org rules gitignore: updated .gitignore (${drift})`);
|
|
34643
34788
|
} else {
|
|
34644
34789
|
console.log("mmi-cli org rules gitignore: up to date");
|
|
@@ -34796,8 +34941,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
34796
34941
|
if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
|
|
34797
34942
|
let root;
|
|
34798
34943
|
if (o.root !== void 0) {
|
|
34799
|
-
root = (0,
|
|
34800
|
-
if (!(0,
|
|
34944
|
+
root = (0, import_node_path40.resolve)(o.root);
|
|
34945
|
+
if (!(0, import_node_fs42.existsSync)(root) || !(0, import_node_fs42.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
|
|
34801
34946
|
const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
34802
34947
|
if (isPathUnderDirectory(gcRepoRoot, root)) {
|
|
34803
34948
|
return fail(`worktree gc: --root ${root} contains this checkout ? name a worktrees root, not the repo or an ancestor of it`);
|
|
@@ -34877,7 +35022,7 @@ async function currentWorktreeRemovalContext(command, force) {
|
|
|
34877
35022
|
};
|
|
34878
35023
|
}
|
|
34879
35024
|
async function unprovenWorktreeReason(wtPath, repoRoot2) {
|
|
34880
|
-
if (!(0,
|
|
35025
|
+
if (!(0, import_node_fs42.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
|
|
34881
35026
|
const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
34882
35027
|
const registered = parseWorktreePorcelainEntries(porcelain);
|
|
34883
35028
|
if (!registered.length) {
|
|
@@ -34899,26 +35044,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
34899
35044
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
34900
35045
|
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
34901
35046
|
const take = () => {
|
|
34902
|
-
const fd = (0,
|
|
35047
|
+
const fd = (0, import_node_fs42.openSync)(lockPath, "wx");
|
|
34903
35048
|
try {
|
|
34904
|
-
(0,
|
|
35049
|
+
(0, import_node_fs42.writeSync)(fd, String(Date.now()));
|
|
34905
35050
|
} finally {
|
|
34906
|
-
(0,
|
|
35051
|
+
(0, import_node_fs42.closeSync)(fd);
|
|
34907
35052
|
}
|
|
34908
35053
|
return () => {
|
|
34909
35054
|
try {
|
|
34910
|
-
(0,
|
|
35055
|
+
(0, import_node_fs42.rmSync)(lockPath, { force: true });
|
|
34911
35056
|
} catch {
|
|
34912
35057
|
}
|
|
34913
35058
|
};
|
|
34914
35059
|
};
|
|
34915
35060
|
try {
|
|
34916
|
-
(0,
|
|
35061
|
+
(0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(lockPath), { recursive: true });
|
|
34917
35062
|
return take();
|
|
34918
35063
|
} catch {
|
|
34919
35064
|
try {
|
|
34920
|
-
if (Date.now() - (0,
|
|
34921
|
-
(0,
|
|
35065
|
+
if (Date.now() - (0, import_node_fs42.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
|
|
35066
|
+
(0, import_node_fs42.rmSync)(lockPath, { force: true });
|
|
34922
35067
|
return take();
|
|
34923
35068
|
}
|
|
34924
35069
|
} catch {
|
|
@@ -34944,6 +35089,11 @@ withExamples(mutating(
|
|
|
34944
35089
|
const resolvedRepo = await resolveRepo();
|
|
34945
35090
|
if (!resolvedRepo) return fail("worktree create: could not resolve the repo for the issue ref (run from a repo checkout)");
|
|
34946
35091
|
selector = parseIssueSelector(target, resolvedRepo);
|
|
35092
|
+
if (selector.repo.toLowerCase() !== resolvedRepo.toLowerCase()) {
|
|
35093
|
+
return fail(
|
|
35094
|
+
`worktree create: issue ${selector.repo}#${selector.number} belongs to ${selector.repo}, but this checkout is ${resolvedRepo} \u2014 re-run from ${selector.repo}'s primary checkout. Refusing to attach a foreign issue branch here (MMI-Hub#4351).`
|
|
35095
|
+
);
|
|
35096
|
+
}
|
|
34947
35097
|
const slug = o.slug ?? await fetchIssueTitle(selector.repo, selector.number).then((t) => t ? slugifyIssueTitle(t) : "");
|
|
34948
35098
|
branch = buildNewBranchName(selector.number, slug ?? "");
|
|
34949
35099
|
if (PROTECTED_BRANCHES2.has(branch)) {
|
|
@@ -35057,7 +35207,7 @@ withExamples(mutating(
|
|
|
35057
35207
|
appendWorktreeEvent(repoRoot2, { action: "created", command: "worktree create", target: wtPath, branch, actor: owner.actor });
|
|
35058
35208
|
let lease;
|
|
35059
35209
|
try {
|
|
35060
|
-
await
|
|
35210
|
+
await execJervCli([
|
|
35061
35211
|
"lease",
|
|
35062
35212
|
"open",
|
|
35063
35213
|
"--kind",
|
|
@@ -35766,7 +35916,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
35766
35916
|
if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
|
|
35767
35917
|
if (o.secretsFile) {
|
|
35768
35918
|
try {
|
|
35769
|
-
vars.push(`secrets=${(0,
|
|
35919
|
+
vars.push(`secrets=${(0, import_node_fs42.readFileSync)(o.secretsFile, "utf8")}`);
|
|
35770
35920
|
} catch (e) {
|
|
35771
35921
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
35772
35922
|
}
|
|
@@ -36520,11 +36670,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
36520
36670
|
}
|
|
36521
36671
|
});
|
|
36522
36672
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
36523
|
-
const wfDir = (0,
|
|
36524
|
-
if (!(0,
|
|
36525
|
-
return (0,
|
|
36673
|
+
const wfDir = (0, import_node_path40.join)(cwd, ".github", "workflows");
|
|
36674
|
+
if (!(0, import_node_fs42.existsSync)(wfDir)) return [];
|
|
36675
|
+
return (0, import_node_fs42.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
36526
36676
|
try {
|
|
36527
|
-
return workflowReportsPrChecks((0,
|
|
36677
|
+
return workflowReportsPrChecks((0, import_node_fs42.readFileSync)((0, import_node_path40.join)(wfDir, name), "utf8"));
|
|
36528
36678
|
} catch {
|
|
36529
36679
|
return true;
|
|
36530
36680
|
}
|
|
@@ -36556,16 +36706,16 @@ function ciAuditDeps() {
|
|
|
36556
36706
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
36557
36707
|
readSeedFile: (path2) => {
|
|
36558
36708
|
if (!root) return null;
|
|
36559
|
-
const fullPath = (0,
|
|
36560
|
-
return (0,
|
|
36709
|
+
const fullPath = (0, import_node_path40.join)(root, path2);
|
|
36710
|
+
return (0, import_node_fs42.existsSync)(fullPath) ? (0, import_node_fs42.readFileSync)(fullPath, "utf8") : null;
|
|
36561
36711
|
}
|
|
36562
36712
|
};
|
|
36563
36713
|
}
|
|
36564
36714
|
function hubRoot() {
|
|
36565
|
-
const fromPkg = (0,
|
|
36715
|
+
const fromPkg = (0, import_node_path40.join)(__dirname, "..", "..");
|
|
36566
36716
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
36567
|
-
if ((0,
|
|
36568
|
-
if ((0,
|
|
36717
|
+
if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(fromPkg, marker))) return fromPkg;
|
|
36718
|
+
if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(process.cwd(), marker))) return process.cwd();
|
|
36569
36719
|
return null;
|
|
36570
36720
|
}
|
|
36571
36721
|
pr.command("ci-policy").description("report merge CI policy: wait-for-checks vs no-ci (for grind/build agents)").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the current checkout)").action(async (o) => {
|
|
@@ -36877,7 +37027,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
36877
37027
|
localCleanup = await cleanupPrMergeLocalBranch(headRef, {
|
|
36878
37028
|
beforeWorktrees,
|
|
36879
37029
|
startingPath,
|
|
36880
|
-
pathExists: (p) => (0,
|
|
37030
|
+
pathExists: (p) => (0, import_node_fs42.existsSync)(p),
|
|
36881
37031
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
36882
37032
|
teardownWorktreeStage,
|
|
36883
37033
|
deferredStore,
|
|
@@ -37373,12 +37523,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
37373
37523
|
targets = resolution.targets;
|
|
37374
37524
|
}
|
|
37375
37525
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
37376
|
-
const fileMatrix = (0,
|
|
37526
|
+
const fileMatrix = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
37377
37527
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
37378
37528
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
37379
|
-
const fileContracts = (0,
|
|
37529
|
+
const fileContracts = (0, import_node_fs42.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs42.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
|
|
37380
37530
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
37381
|
-
const sanctioned = (0,
|
|
37531
|
+
const sanctioned = (0, import_node_fs42.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs42.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
37382
37532
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
37383
37533
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
37384
37534
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -37410,16 +37560,16 @@ function directoryBytes(path2) {
|
|
|
37410
37560
|
let total = 0;
|
|
37411
37561
|
let entries;
|
|
37412
37562
|
try {
|
|
37413
|
-
entries = (0,
|
|
37563
|
+
entries = (0, import_node_fs42.readdirSync)(path2, { withFileTypes: true });
|
|
37414
37564
|
} catch {
|
|
37415
37565
|
return 0;
|
|
37416
37566
|
}
|
|
37417
37567
|
for (const entry of entries) {
|
|
37418
|
-
const child2 = (0,
|
|
37568
|
+
const child2 = (0, import_node_path40.join)(path2, entry.name);
|
|
37419
37569
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
37420
37570
|
else {
|
|
37421
37571
|
try {
|
|
37422
|
-
total += (0,
|
|
37572
|
+
total += (0, import_node_fs42.statSync)(child2).size;
|
|
37423
37573
|
} catch {
|
|
37424
37574
|
}
|
|
37425
37575
|
}
|
|
@@ -37427,25 +37577,25 @@ function directoryBytes(path2) {
|
|
|
37427
37577
|
return total;
|
|
37428
37578
|
}
|
|
37429
37579
|
function listDirEntries(dir) {
|
|
37430
|
-
return (0,
|
|
37580
|
+
return (0, import_node_fs42.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
37431
37581
|
}
|
|
37432
37582
|
function readInstalledPluginRefs(configRoot) {
|
|
37433
37583
|
const p = installedPluginsPathForConfig(configRoot);
|
|
37434
|
-
if (!(0,
|
|
37584
|
+
if (!(0, import_node_fs42.existsSync)(p)) return [];
|
|
37435
37585
|
try {
|
|
37436
|
-
return installedPluginPaths((0,
|
|
37586
|
+
return installedPluginPaths((0, import_node_fs42.readFileSync)(p, "utf8"));
|
|
37437
37587
|
} catch {
|
|
37438
37588
|
return null;
|
|
37439
37589
|
}
|
|
37440
37590
|
}
|
|
37441
37591
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
37442
37592
|
return {
|
|
37443
|
-
exists: (p) => (0,
|
|
37444
|
-
listVersionDirs: (root) => (0,
|
|
37593
|
+
exists: (p) => (0, import_node_fs42.existsSync)(p),
|
|
37594
|
+
listVersionDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
37445
37595
|
dirBytes,
|
|
37446
|
-
listStagingDirs: (root) => (0,
|
|
37596
|
+
listStagingDirs: (root) => (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
37447
37597
|
try {
|
|
37448
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
37598
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path40.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs42.statSync)(p).mtimeMs) };
|
|
37449
37599
|
} catch {
|
|
37450
37600
|
return { name: d.name, mtimeMs: Date.now() };
|
|
37451
37601
|
}
|
|
@@ -37459,10 +37609,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
37459
37609
|
return {
|
|
37460
37610
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
37461
37611
|
mtimeMs: (name) => {
|
|
37462
|
-
const p = (0,
|
|
37463
|
-
if (!(0,
|
|
37612
|
+
const p = (0, import_node_path40.join)(stagingRoot, name);
|
|
37613
|
+
if (!(0, import_node_fs42.existsSync)(p)) return null;
|
|
37464
37614
|
try {
|
|
37465
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
37615
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs42.statSync)(q).mtimeMs);
|
|
37466
37616
|
} catch {
|
|
37467
37617
|
return null;
|
|
37468
37618
|
}
|
|
@@ -37482,13 +37632,13 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
37482
37632
|
return;
|
|
37483
37633
|
}
|
|
37484
37634
|
const plan = buildPluginCachePlan(
|
|
37485
|
-
(0,
|
|
37635
|
+
(0, import_node_os17.homedir)(),
|
|
37486
37636
|
running,
|
|
37487
37637
|
pluginCacheFsDeps(configRoot, directoryBytes),
|
|
37488
37638
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
37489
37639
|
);
|
|
37490
37640
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
37491
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
37641
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs42.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
37492
37642
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
37493
37643
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
37494
37644
|
else console.log(renderPluginCachePlan(plan, result));
|
|
@@ -37496,7 +37646,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
37496
37646
|
});
|
|
37497
37647
|
function readReleaseCatchupState(path2) {
|
|
37498
37648
|
try {
|
|
37499
|
-
const parsed = JSON.parse((0,
|
|
37649
|
+
const parsed = JSON.parse((0, import_node_fs42.readFileSync)(path2, "utf8"));
|
|
37500
37650
|
return typeof parsed?.checkedAt === "number" ? parsed : void 0;
|
|
37501
37651
|
} catch {
|
|
37502
37652
|
return void 0;
|
|
@@ -37504,8 +37654,8 @@ function readReleaseCatchupState(path2) {
|
|
|
37504
37654
|
}
|
|
37505
37655
|
function writeReleaseCatchupState(path2, state) {
|
|
37506
37656
|
try {
|
|
37507
|
-
(0,
|
|
37508
|
-
(0,
|
|
37657
|
+
(0, import_node_fs42.mkdirSync)((0, import_node_path40.dirname)(path2), { recursive: true });
|
|
37658
|
+
(0, import_node_fs42.writeFileSync)(path2, `${JSON.stringify(state)}
|
|
37509
37659
|
`);
|
|
37510
37660
|
} catch {
|
|
37511
37661
|
}
|
|
@@ -37513,7 +37663,7 @@ function writeReleaseCatchupState(path2, state) {
|
|
|
37513
37663
|
program2.command("plugin-release-catchup").description("install a newer released MMI plugin clone non-destructively and re-point the Pi registration (#4297); TTL-gated no-op when current").option("--force", "skip the 24h TTL (acceptance proof / manual run)").option("--quiet", "print only failures (the detached session-start lane)").option("--json", "machine-readable output").action(async (o) => {
|
|
37514
37664
|
const outcome = await withEnvHealLock(
|
|
37515
37665
|
"plugin release catch-up",
|
|
37516
|
-
() => runReleaseCatchup((0,
|
|
37666
|
+
() => runReleaseCatchup((0, import_node_os17.homedir)(), process.env, {
|
|
37517
37667
|
fetchReleased: fetchNpmReleasedVersion,
|
|
37518
37668
|
runClaude: (args, step) => runPluginCli("claude", args, (msg) => {
|
|
37519
37669
|
if (!o.quiet && !o.json) console.log(msg);
|
|
@@ -37529,7 +37679,7 @@ program2.command("plugin-release-catchup").description("install a newer released
|
|
|
37529
37679
|
},
|
|
37530
37680
|
readState: readReleaseCatchupState,
|
|
37531
37681
|
writeState: writeReleaseCatchupState,
|
|
37532
|
-
healRegistration: defaultRegistrationHeal((0,
|
|
37682
|
+
healRegistration: defaultRegistrationHeal((0, import_node_os17.homedir)(), process.env),
|
|
37533
37683
|
now: () => Date.now()
|
|
37534
37684
|
}, { force: o.force })
|
|
37535
37685
|
);
|
|
@@ -37597,7 +37747,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
|
|
|
37597
37747
|
spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
|
|
37598
37748
|
bannerIo.log(worktreeBanner);
|
|
37599
37749
|
}
|
|
37600
|
-
if (shouldSpawnReleaseCatchup((0,
|
|
37750
|
+
if (shouldSpawnReleaseCatchup((0, import_node_os17.homedir)(), process.env, readReleaseCatchupState)) {
|
|
37601
37751
|
spawnDetachedSelf(["plugin", "release-catchup", "--quiet"], { spawn: import_node_child_process19.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
|
|
37602
37752
|
}
|
|
37603
37753
|
if (isLinkedWorktree(process.cwd())) {
|
package/package.json
CHANGED