@mutmutco/cli 2.65.0 → 2.66.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/README.md +1 -2
- package/dist/main.cjs +343 -351
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -3408,7 +3408,7 @@ var program = new Command();
|
|
|
3408
3408
|
|
|
3409
3409
|
// src/index.ts
|
|
3410
3410
|
var import_promises4 = require("node:fs/promises");
|
|
3411
|
-
var
|
|
3411
|
+
var import_node_fs18 = require("node:fs");
|
|
3412
3412
|
|
|
3413
3413
|
// src/rules-sync.ts
|
|
3414
3414
|
function normalizeEol(s) {
|
|
@@ -3543,7 +3543,7 @@ function hardExit(code) {
|
|
|
3543
3543
|
async function cleanExit(code) {
|
|
3544
3544
|
process.exitCode = code;
|
|
3545
3545
|
await closeHttpPool();
|
|
3546
|
-
await new Promise((
|
|
3546
|
+
await new Promise((resolve6) => setImmediate(resolve6));
|
|
3547
3547
|
process.exit(code);
|
|
3548
3548
|
}
|
|
3549
3549
|
async function failGraceful(msg) {
|
|
@@ -3708,7 +3708,7 @@ async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
|
|
|
3708
3708
|
const attempts = opts.attempts ?? 3;
|
|
3709
3709
|
const baseDelayMs = opts.baseDelayMs ?? 250;
|
|
3710
3710
|
const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
|
|
3711
|
-
const sleep = opts.sleep ?? ((ms) => new Promise((
|
|
3711
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
3712
3712
|
let lastErr;
|
|
3713
3713
|
for (let i = 0; i < attempts; i++) {
|
|
3714
3714
|
const isLast = i === attempts - 1;
|
|
@@ -3745,7 +3745,7 @@ function defaultHubSessionCachePath(env = process.env) {
|
|
|
3745
3745
|
const base2 = env.LOCALAPPDATA || (0, import_node_path3.join)((0, import_node_os.homedir)(), "AppData", "Local");
|
|
3746
3746
|
return (0, import_node_path3.join)(base2, "MMI Future", "mmi-cli", "hub-session.json");
|
|
3747
3747
|
}
|
|
3748
|
-
const base = env.XDG_STATE_HOME || (0, import_node_path3.join)((0, import_node_os.homedir)(), ".
|
|
3748
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path3.join)((0, import_node_os.homedir)(), ".local", "state");
|
|
3749
3749
|
return (0, import_node_path3.join)(base, "mmi-cli", "hub-session.json");
|
|
3750
3750
|
}
|
|
3751
3751
|
function readCache(path2, apiUrl, now, githubTokenFingerprint) {
|
|
@@ -3852,8 +3852,8 @@ async function readStdin(opts = {}) {
|
|
|
3852
3852
|
})().catch(() => {
|
|
3853
3853
|
});
|
|
3854
3854
|
let timer;
|
|
3855
|
-
const timeout = new Promise((
|
|
3856
|
-
timer = setTimeout(
|
|
3855
|
+
const timeout = new Promise((resolve6) => {
|
|
3856
|
+
timer = setTimeout(resolve6, timeoutMs);
|
|
3857
3857
|
});
|
|
3858
3858
|
try {
|
|
3859
3859
|
await Promise.race([drain, timeout]);
|
|
@@ -3948,8 +3948,8 @@ async function syncDocs(deps, docs2 = SYNCED_DOCS) {
|
|
|
3948
3948
|
}
|
|
3949
3949
|
|
|
3950
3950
|
// src/session-start.ts
|
|
3951
|
-
var
|
|
3952
|
-
var
|
|
3951
|
+
var import_node_fs7 = require("node:fs");
|
|
3952
|
+
var import_node_path7 = require("node:path");
|
|
3953
3953
|
|
|
3954
3954
|
// src/scratch-gc.ts
|
|
3955
3955
|
var import_node_child_process4 = require("node:child_process");
|
|
@@ -3980,15 +3980,12 @@ function hashContent(s) {
|
|
|
3980
3980
|
}
|
|
3981
3981
|
|
|
3982
3982
|
// src/scratch-gc.ts
|
|
3983
|
-
var TMP_STALE_MS = 6e4;
|
|
3984
|
-
var FLUSH_LOCK_GC_MS = 6e5;
|
|
3985
3983
|
var HEAD_TS_STALE_MS = 48 * 36e5;
|
|
3986
|
-
var CONFLICT_COPY_STALE_MS = 24 * 36e5;
|
|
3987
3984
|
var PLAN_ADVISORY_AGE_MS = 30 * 24 * 36e5;
|
|
3988
3985
|
var ROOT_SCRATCH_STALE_MS = 24 * 36e5;
|
|
3989
3986
|
var SCRATCH_GC_THROTTLE_MS = 24 * 36e5;
|
|
3990
|
-
function scratchGcThrottlePath(
|
|
3991
|
-
return (0, import_node_path5.join)(
|
|
3987
|
+
function scratchGcThrottlePath(runtimeRoot) {
|
|
3988
|
+
return (0, import_node_path5.join)(runtimeRoot, "head-ts", ".scratch-gc-last");
|
|
3992
3989
|
}
|
|
3993
3990
|
function scratchGcDue(stampPath, now = Date.now(), read = import_node_fs5.readFileSync) {
|
|
3994
3991
|
try {
|
|
@@ -4046,21 +4043,11 @@ function buildPrMergeScratchHousekeeping(repoRoot, deps = {}) {
|
|
|
4046
4043
|
}
|
|
4047
4044
|
var ROOT_SCRATCH_DIRS = /* @__PURE__ */ new Set(["tmp", ".playwright-mcp", "test-results", "playwright-report"]);
|
|
4048
4045
|
var ROOT_SCRATCH_FILE_PREFIXES = ["tmp_"];
|
|
4049
|
-
var NEVER_BASENAMES = /* @__PURE__ */ new Set([".session", "config.json"
|
|
4050
|
-
var TMP_SIDECAR_BASES = ["saga-pending.jsonl"];
|
|
4051
|
-
var CONFLICT_COPY_ALLOWLIST = /* @__PURE__ */ new Set(["saga-pending.jsonl"]);
|
|
4052
|
-
function conflictCopyOriginal(name) {
|
|
4053
|
-
const m = /^(.+) \d+(\.[^.]+)$/.exec(name);
|
|
4054
|
-
return m ? `${m[1]}${m[2]}` : null;
|
|
4055
|
-
}
|
|
4056
|
-
function isTmpSidecar(name) {
|
|
4057
|
-
return name.endsWith(".tmp") && TMP_SIDECAR_BASES.some((b) => name.startsWith(`${b}.`));
|
|
4058
|
-
}
|
|
4046
|
+
var NEVER_BASENAMES = /* @__PURE__ */ new Set([".session", "config.json"]);
|
|
4059
4047
|
function planScratchGc(snap, now = Date.now()) {
|
|
4060
4048
|
const candidates = [];
|
|
4061
4049
|
const normalizePath = (p) => p.replace(/\\/g, "/");
|
|
4062
4050
|
const repoRoot = normalizePath((snap.repoRoot ?? (0, import_node_path5.dirname)(snap.mmiRoot)).replace(/[\\/]+$/, ""));
|
|
4063
|
-
const mmiPaths = new Set(snap.mmiFiles.map((f) => normalizePath(f.path)));
|
|
4064
4051
|
const headTsPrefix = `${snap.mmiRoot.replace(/[\\/]+$/, "")}/head-ts/`.replace(/\\/g, "/");
|
|
4065
4052
|
const days = (ms) => `${Math.floor(ms / 864e5)}d`;
|
|
4066
4053
|
for (const f of snap.rootScratchFiles ?? []) {
|
|
@@ -4094,23 +4081,11 @@ function planScratchGc(snap, now = Date.now()) {
|
|
|
4094
4081
|
for (const f of snap.mmiFiles) {
|
|
4095
4082
|
const age = now - f.mtimeMs;
|
|
4096
4083
|
const add = (family, reason) => candidates.push({ path: f.path, family, kind: "file", tier: "safe-auto", reason, bytes: f.bytes });
|
|
4097
|
-
if (isTmpSidecar(f.name)) {
|
|
4098
|
-
if (age > TMP_STALE_MS) add("tmp-sidecar", `crashed atomic-write sidecar (${days(age)} old)`);
|
|
4099
|
-
continue;
|
|
4100
|
-
}
|
|
4101
|
-
if (f.name === "saga-flush.lock") {
|
|
4102
|
-
if (age > FLUSH_LOCK_GC_MS) add("flush-lock", `abandoned flush lock (${days(age)} old)`);
|
|
4103
|
-
continue;
|
|
4104
|
-
}
|
|
4105
4084
|
if (NEVER_BASENAMES.has(f.name)) continue;
|
|
4106
4085
|
if (f.path.replace(/\\/g, "/").startsWith(headTsPrefix) && !f.name.startsWith(".")) {
|
|
4107
4086
|
if (age > HEAD_TS_STALE_MS) add("head-ts", `stale throttle stamp (${days(age)} old)`);
|
|
4108
4087
|
continue;
|
|
4109
4088
|
}
|
|
4110
|
-
const orig = conflictCopyOriginal(f.name);
|
|
4111
|
-
if (orig && CONFLICT_COPY_ALLOWLIST.has(orig) && mmiPaths.has(normalizePath((0, import_node_path5.join)(f.dir, orig))) && age > CONFLICT_COPY_STALE_MS) {
|
|
4112
|
-
add("conflict-copy", `cloud-sync conflict copy of ${orig} (${days(age)} old)`);
|
|
4113
|
-
}
|
|
4114
4089
|
}
|
|
4115
4090
|
if (snap.syncQueueSlugs === null) {
|
|
4116
4091
|
for (const f of snap.planMdFiles) {
|
|
@@ -4330,7 +4305,7 @@ function applyScratchGc(plan, mmiRoot, now = Date.now()) {
|
|
|
4330
4305
|
continue;
|
|
4331
4306
|
}
|
|
4332
4307
|
}
|
|
4333
|
-
const floor = c.family === "
|
|
4308
|
+
const floor = c.family === "head-ts" ? HEAD_TS_STALE_MS : c.family === "plan" ? PLAN_ADVISORY_AGE_MS : c.family === "scratch-dir" || c.family === "scratch-file" ? ROOT_SCRATCH_STALE_MS : 0;
|
|
4334
4309
|
if (floor > 0 && now - st.mtimeMs <= floor) {
|
|
4335
4310
|
result.skipped += 1;
|
|
4336
4311
|
continue;
|
|
@@ -4498,6 +4473,40 @@ function collectScratchSnapshot(repoRoot, deps = {}) {
|
|
|
4498
4473
|
return { repoRoot, mmiRoot, mmiFiles, rootScratchFiles, planMdFiles, planMeta, project: project2, syncQueueSlugs };
|
|
4499
4474
|
}
|
|
4500
4475
|
|
|
4476
|
+
// src/repo-runtime-state.ts
|
|
4477
|
+
var import_node_crypto2 = require("node:crypto");
|
|
4478
|
+
var import_node_fs6 = require("node:fs");
|
|
4479
|
+
var import_node_os2 = require("node:os");
|
|
4480
|
+
var import_node_path6 = require("node:path");
|
|
4481
|
+
var RUNTIME_DIR = "mmi-runtime";
|
|
4482
|
+
function hashPath(path2) {
|
|
4483
|
+
return (0, import_node_crypto2.createHash)("sha256").update((0, import_node_path6.resolve)(path2)).digest("hex").slice(0, 16);
|
|
4484
|
+
}
|
|
4485
|
+
function resolveGitDir(cwd) {
|
|
4486
|
+
const dotGit = (0, import_node_path6.join)(cwd, ".git");
|
|
4487
|
+
try {
|
|
4488
|
+
const st = (0, import_node_fs6.statSync)(dotGit);
|
|
4489
|
+
if (st.isDirectory()) return dotGit;
|
|
4490
|
+
if (!st.isFile()) return void 0;
|
|
4491
|
+
} catch {
|
|
4492
|
+
return void 0;
|
|
4493
|
+
}
|
|
4494
|
+
try {
|
|
4495
|
+
const raw = (0, import_node_fs6.readFileSync)(dotGit, "utf8").trim();
|
|
4496
|
+
const match = /^gitdir:\s*(.+)$/i.exec(raw);
|
|
4497
|
+
if (!match) return void 0;
|
|
4498
|
+
const gitdir = match[1].trim();
|
|
4499
|
+
return (0, import_node_path6.isAbsolute)(gitdir) ? gitdir : (0, import_node_path6.resolve)(cwd, gitdir);
|
|
4500
|
+
} catch {
|
|
4501
|
+
return void 0;
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
function repoRuntimeStatePath(cwd, ...parts) {
|
|
4505
|
+
const gitDir = resolveGitDir(cwd);
|
|
4506
|
+
if (gitDir && (0, import_node_fs6.existsSync)(gitDir)) return (0, import_node_path6.join)(gitDir, RUNTIME_DIR, ...parts);
|
|
4507
|
+
return (0, import_node_path6.join)((0, import_node_os2.tmpdir)(), "mmi-cli", hashPath(cwd), ...parts);
|
|
4508
|
+
}
|
|
4509
|
+
|
|
4501
4510
|
// src/session-start.ts
|
|
4502
4511
|
async function runBufferedStep(step) {
|
|
4503
4512
|
const lines = [];
|
|
@@ -4542,20 +4551,20 @@ function spawnDetachedSelf(args, deps) {
|
|
|
4542
4551
|
} catch {
|
|
4543
4552
|
}
|
|
4544
4553
|
}
|
|
4545
|
-
function isInsideRepoSubdir(cwd, exists =
|
|
4546
|
-
if (exists((0,
|
|
4554
|
+
function isInsideRepoSubdir(cwd, exists = import_node_fs7.existsSync) {
|
|
4555
|
+
if (exists((0, import_node_path7.join)(cwd, ".git"))) return false;
|
|
4547
4556
|
let dir = cwd;
|
|
4548
4557
|
for (; ; ) {
|
|
4549
|
-
const parent = (0,
|
|
4558
|
+
const parent = (0, import_node_path7.dirname)(dir);
|
|
4550
4559
|
if (parent === dir) return false;
|
|
4551
|
-
if (exists((0,
|
|
4560
|
+
if (exists((0, import_node_path7.join)(parent, ".git"))) return true;
|
|
4552
4561
|
dir = parent;
|
|
4553
4562
|
}
|
|
4554
4563
|
}
|
|
4555
4564
|
function scratchGcLines(cwd, env = process.env, now = Date.now()) {
|
|
4556
4565
|
if (env.MMI_NO_AUTO_GC) return [];
|
|
4557
4566
|
try {
|
|
4558
|
-
const stamp = scratchGcThrottlePath((
|
|
4567
|
+
const stamp = scratchGcThrottlePath(repoRuntimeStatePath(cwd));
|
|
4559
4568
|
if (!scratchGcDue(stamp, now)) return [];
|
|
4560
4569
|
const run = executeScratchGc(cwd, { apply: true }, now);
|
|
4561
4570
|
markScratchGcRun(stamp, now);
|
|
@@ -5533,16 +5542,16 @@ function ghError(e) {
|
|
|
5533
5542
|
}
|
|
5534
5543
|
|
|
5535
5544
|
// src/board-slice-cache.ts
|
|
5536
|
-
var
|
|
5537
|
-
var
|
|
5538
|
-
var BOARD_SLICE_CACHE_FILE = (0,
|
|
5545
|
+
var import_node_fs8 = require("node:fs");
|
|
5546
|
+
var import_node_path8 = require("node:path");
|
|
5547
|
+
var BOARD_SLICE_CACHE_FILE = (0, import_node_path8.join)("board-slice.json");
|
|
5539
5548
|
var BOARD_SLICE_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
5540
5549
|
function boardSliceCachePath(cwd) {
|
|
5541
|
-
return (
|
|
5550
|
+
return repoRuntimeStatePath(cwd, BOARD_SLICE_CACHE_FILE);
|
|
5542
5551
|
}
|
|
5543
5552
|
function readCachedBoardSlice(cwd) {
|
|
5544
5553
|
try {
|
|
5545
|
-
const parsed = JSON.parse((0,
|
|
5554
|
+
const parsed = JSON.parse((0, import_node_fs8.readFileSync)(boardSliceCachePath(cwd), "utf8"));
|
|
5546
5555
|
if (typeof parsed.ts !== "number") return null;
|
|
5547
5556
|
return { block: typeof parsed.block === "string" ? parsed.block : null, ts: parsed.ts };
|
|
5548
5557
|
} catch {
|
|
@@ -5553,12 +5562,12 @@ function writeCachedBoardSlice(cwd, slice) {
|
|
|
5553
5562
|
const path2 = boardSliceCachePath(cwd);
|
|
5554
5563
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
5555
5564
|
try {
|
|
5556
|
-
(0,
|
|
5557
|
-
(0,
|
|
5558
|
-
(0,
|
|
5565
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
|
|
5566
|
+
(0, import_node_fs8.writeFileSync)(tmp, JSON.stringify(slice));
|
|
5567
|
+
(0, import_node_fs8.renameSync)(tmp, path2);
|
|
5559
5568
|
} catch {
|
|
5560
5569
|
try {
|
|
5561
|
-
(0,
|
|
5570
|
+
(0, import_node_fs8.rmSync)(tmp, { force: true });
|
|
5562
5571
|
} catch {
|
|
5563
5572
|
}
|
|
5564
5573
|
}
|
|
@@ -5570,7 +5579,7 @@ function boardSliceCacheStale(cached, now, ttlMs = BOARD_SLICE_CACHE_TTL_MS) {
|
|
|
5570
5579
|
// src/board-slice.ts
|
|
5571
5580
|
var SESSION_START_BOARD_TIMEOUT_MS = 3e3;
|
|
5572
5581
|
var BOARD_SLICE_REFRESH_TIMEOUT_MS = 3e4;
|
|
5573
|
-
var BOARD_SLICE_FRAMING = "BOARD SLICE \u2014
|
|
5582
|
+
var BOARD_SLICE_FRAMING = "BOARD SLICE \u2014 board Status is authoritative for work lifecycle.";
|
|
5574
5583
|
var BOARD_SLICE_EMPTY = "Board: nothing assigned or claimable right now \u2014 `mmi-cli board read` (or `/mmi`) for the full board.";
|
|
5575
5584
|
var BOARD_SLICE_PENDING = "Board: loading your slice in the background \u2014 run `/mmi` now; it renders here next session.";
|
|
5576
5585
|
var BOARD_SLICE_MAX_LINES = 5;
|
|
@@ -5686,8 +5695,8 @@ async function refreshBoardSliceCache(deps) {
|
|
|
5686
5695
|
}
|
|
5687
5696
|
|
|
5688
5697
|
// src/worktree.ts
|
|
5689
|
-
var
|
|
5690
|
-
var
|
|
5698
|
+
var import_node_fs9 = require("node:fs");
|
|
5699
|
+
var import_node_path9 = require("node:path");
|
|
5691
5700
|
var LOCAL_ONLY_FILES = [".claude/settings.local.json"];
|
|
5692
5701
|
var PKG = "package.json";
|
|
5693
5702
|
var LOCKFILE = "package-lock.json";
|
|
@@ -5695,21 +5704,21 @@ var NODE_MODULES = "node_modules";
|
|
|
5695
5704
|
var realFsProbe = {
|
|
5696
5705
|
isDir: (p) => {
|
|
5697
5706
|
try {
|
|
5698
|
-
return (0,
|
|
5707
|
+
return (0, import_node_fs9.statSync)(p).isDirectory();
|
|
5699
5708
|
} catch {
|
|
5700
5709
|
return false;
|
|
5701
5710
|
}
|
|
5702
5711
|
},
|
|
5703
5712
|
isFile: (p) => {
|
|
5704
5713
|
try {
|
|
5705
|
-
return (0,
|
|
5714
|
+
return (0, import_node_fs9.statSync)(p).isFile();
|
|
5706
5715
|
} catch {
|
|
5707
5716
|
return false;
|
|
5708
5717
|
}
|
|
5709
5718
|
},
|
|
5710
5719
|
listDirs: (p) => {
|
|
5711
5720
|
try {
|
|
5712
|
-
return (0,
|
|
5721
|
+
return (0, import_node_fs9.readdirSync)(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
5713
5722
|
} catch {
|
|
5714
5723
|
return [];
|
|
5715
5724
|
}
|
|
@@ -5717,12 +5726,12 @@ var realFsProbe = {
|
|
|
5717
5726
|
};
|
|
5718
5727
|
function scanInstallDirs(root, fs2 = realFsProbe) {
|
|
5719
5728
|
const factsFor = (dir) => {
|
|
5720
|
-
const abs = dir ? (0,
|
|
5729
|
+
const abs = dir ? (0, import_node_path9.join)(root, dir) : root;
|
|
5721
5730
|
return {
|
|
5722
5731
|
dir,
|
|
5723
|
-
hasPackageJson: fs2.isFile((0,
|
|
5724
|
-
hasLockfile: fs2.isFile((0,
|
|
5725
|
-
hasNodeModules: fs2.isDir((0,
|
|
5732
|
+
hasPackageJson: fs2.isFile((0, import_node_path9.join)(abs, PKG)),
|
|
5733
|
+
hasLockfile: fs2.isFile((0, import_node_path9.join)(abs, LOCKFILE)),
|
|
5734
|
+
hasNodeModules: fs2.isDir((0, import_node_path9.join)(abs, NODE_MODULES))
|
|
5726
5735
|
};
|
|
5727
5736
|
};
|
|
5728
5737
|
const children = fs2.listDirs(root).filter((name) => name !== NODE_MODULES && name !== ".git");
|
|
@@ -5732,7 +5741,7 @@ function npmInstallTargets(dirs) {
|
|
|
5732
5741
|
return dirs.filter((d) => d.hasPackageJson && !d.hasNodeModules).map((d) => ({ dir: d.dir, command: d.hasLockfile ? "npm ci" : "npm install" }));
|
|
5733
5742
|
}
|
|
5734
5743
|
function isLinkedWorktree(root, fs2 = realFsProbe) {
|
|
5735
|
-
return fs2.isFile((0,
|
|
5744
|
+
return fs2.isFile((0, import_node_path9.join)(root, ".git"));
|
|
5736
5745
|
}
|
|
5737
5746
|
function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
5738
5747
|
if (!isLinkedWorktree(root, fs2)) return null;
|
|
@@ -5742,8 +5751,8 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
|
5742
5751
|
return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
|
|
5743
5752
|
}
|
|
5744
5753
|
function defaultCopyFile(from, to) {
|
|
5745
|
-
(0,
|
|
5746
|
-
(0,
|
|
5754
|
+
(0, import_node_fs9.mkdirSync)((0, import_node_path9.dirname)(to), { recursive: true });
|
|
5755
|
+
(0, import_node_fs9.copyFileSync)(from, to);
|
|
5747
5756
|
}
|
|
5748
5757
|
async function provisionWorktree(worktreeRoot, deps) {
|
|
5749
5758
|
const fs2 = deps.fs ?? realFsProbe;
|
|
@@ -5755,7 +5764,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
5755
5764
|
const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules).map((d) => d.dir);
|
|
5756
5765
|
const installed = [];
|
|
5757
5766
|
for (const target of targets) {
|
|
5758
|
-
const cwd = target.dir ? (0,
|
|
5767
|
+
const cwd = target.dir ? (0, import_node_path9.join)(worktreeRoot, target.dir) : worktreeRoot;
|
|
5759
5768
|
log(`installing deps: ${target.command} in ${target.dir || "."}`);
|
|
5760
5769
|
await deps.runInstall(target.command, cwd);
|
|
5761
5770
|
installed.push(target);
|
|
@@ -5764,7 +5773,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
5764
5773
|
const copySkipped = [];
|
|
5765
5774
|
const primary = await deps.primaryCheckout();
|
|
5766
5775
|
for (const rel of LOCAL_ONLY_FILES) {
|
|
5767
|
-
const dest = (0,
|
|
5776
|
+
const dest = (0, import_node_path9.join)(worktreeRoot, rel);
|
|
5768
5777
|
if (fs2.isFile(dest)) {
|
|
5769
5778
|
copySkipped.push({ file: rel, reason: "already-present" });
|
|
5770
5779
|
continue;
|
|
@@ -5773,11 +5782,11 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
5773
5782
|
copySkipped.push({ file: rel, reason: "no-primary" });
|
|
5774
5783
|
continue;
|
|
5775
5784
|
}
|
|
5776
|
-
if (!fs2.isFile((0,
|
|
5785
|
+
if (!fs2.isFile((0, import_node_path9.join)(primary, rel))) {
|
|
5777
5786
|
copySkipped.push({ file: rel, reason: "absent-in-primary" });
|
|
5778
5787
|
continue;
|
|
5779
5788
|
}
|
|
5780
|
-
copyFile((0,
|
|
5789
|
+
copyFile((0, import_node_path9.join)(primary, rel), dest);
|
|
5781
5790
|
copied.push(rel);
|
|
5782
5791
|
log(`copied local config: ${rel}`);
|
|
5783
5792
|
}
|
|
@@ -5785,7 +5794,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
5785
5794
|
}
|
|
5786
5795
|
function defaultWorktreePath(repoRoot, branch) {
|
|
5787
5796
|
const safe = branch.replace(/[/\\]+/g, "-");
|
|
5788
|
-
return (0,
|
|
5797
|
+
return (0, import_node_path9.join)((0, import_node_path9.dirname)(repoRoot), "mmi-worktrees", safe);
|
|
5789
5798
|
}
|
|
5790
5799
|
function resolveWorktreeBase(from, remote) {
|
|
5791
5800
|
const remotePrefix = `${remote}/`;
|
|
@@ -5817,7 +5826,7 @@ function whoamiLine(report) {
|
|
|
5817
5826
|
}
|
|
5818
5827
|
|
|
5819
5828
|
// src/index.ts
|
|
5820
|
-
var
|
|
5829
|
+
var import_node_path18 = require("node:path");
|
|
5821
5830
|
|
|
5822
5831
|
// src/merge-ci-policy.ts
|
|
5823
5832
|
function resolveMergeCiPolicy(input) {
|
|
@@ -6056,12 +6065,6 @@ var MANAGED_GITIGNORE_LINES = [
|
|
|
6056
6065
|
"docs/superpowers/",
|
|
6057
6066
|
".playwright-mcp/",
|
|
6058
6067
|
".claude/worktrees/",
|
|
6059
|
-
// .mmi is agent/CI scratch — ignore the WHOLE tree at any depth (root + cli/.mmi, .github/workflows/.mmi,
|
|
6060
|
-
// and any future feature's subdir) so new scratch NEVER needs a new ignore line. `**/.mmi/*` ignores the
|
|
6061
|
-
// dir's contents (not the dir itself). hub-v3 step-back: there is no longer a tracked `.mmi/config.json`
|
|
6062
|
-
// marker (the org-repo gate is the git `origin` remote check now), so nothing under .mmi is re-included.
|
|
6063
|
-
// MMI-Hub's own already-tracked config.json keeps tracking — git never untracks a tracked file.
|
|
6064
|
-
"**/.mmi/*",
|
|
6065
6068
|
".aws-sam/",
|
|
6066
6069
|
"/*.png",
|
|
6067
6070
|
// Runtime secrets/config are vault-only (AGENTS.md "Privileged ops") — never commit a local .env. The
|
|
@@ -6948,7 +6951,7 @@ var PR_LAND_STATE_READ_DELAY_MS = 2e3;
|
|
|
6948
6951
|
async function readGhPrStateWithRetry(fetchState, options) {
|
|
6949
6952
|
const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
|
|
6950
6953
|
const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
|
|
6951
|
-
const sleep = options?.sleep ?? ((ms) => new Promise((
|
|
6954
|
+
const sleep = options?.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
6952
6955
|
let lastError = "empty state";
|
|
6953
6956
|
for (let attempt = 0; attempt < retries; attempt++) {
|
|
6954
6957
|
try {
|
|
@@ -7008,10 +7011,10 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
7008
7011
|
}
|
|
7009
7012
|
|
|
7010
7013
|
// src/wave-status.ts
|
|
7011
|
-
var
|
|
7014
|
+
var import_node_fs11 = require("node:fs");
|
|
7012
7015
|
|
|
7013
7016
|
// src/gc.ts
|
|
7014
|
-
var
|
|
7017
|
+
var import_node_path10 = require("node:path");
|
|
7015
7018
|
var DEFERRED_SWEEP_COMMAND = "mmi-cli gc sweep-deferred";
|
|
7016
7019
|
var DEFERRED_NOTE = "Worktree cleanup queued (IDE lock). Detached sweep will retry automatically \u2014 no human action required.";
|
|
7017
7020
|
var PRESERVED_WORKTREE_CONFIG = "mmi.preservedWorktreeBranch";
|
|
@@ -7081,7 +7084,7 @@ async function sweepDeferredWorktreesWithRetry(store, deps, opts = {}) {
|
|
|
7081
7084
|
}
|
|
7082
7085
|
return last;
|
|
7083
7086
|
}
|
|
7084
|
-
var defaultSleep = (ms) => new Promise((
|
|
7087
|
+
var defaultSleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
7085
7088
|
async function removeWorktreeWithRecovery(wtPath, deps) {
|
|
7086
7089
|
const maxAttempts = deps.maxAttempts ?? 3;
|
|
7087
7090
|
const backoff = deps.backoffMs ?? [250, 1e3];
|
|
@@ -7282,8 +7285,8 @@ function resolveSafeSiblingWorktreeCleanupTarget(worktreePath, siblingRoot, deps
|
|
|
7282
7285
|
return { ok: true, path: worktreePath };
|
|
7283
7286
|
}
|
|
7284
7287
|
function siblingMmiWorktreesRoot(repoRoot) {
|
|
7285
|
-
const parent = (0,
|
|
7286
|
-
return (0,
|
|
7288
|
+
const parent = (0, import_node_path10.dirname)(repoRoot);
|
|
7289
|
+
return (0, import_node_path10.basename)(parent).toLowerCase() === "mmi-worktrees" ? parent : (0, import_node_path10.join)(parent, "mmi-worktrees");
|
|
7287
7290
|
}
|
|
7288
7291
|
function classifySiblingWorktreeDir(entry) {
|
|
7289
7292
|
if (!entry.ownedByCurrentRepo) {
|
|
@@ -7944,15 +7947,15 @@ function formatGcPlan(plan, apply) {
|
|
|
7944
7947
|
|
|
7945
7948
|
// src/stage-runner.ts
|
|
7946
7949
|
var import_node_child_process6 = require("node:child_process");
|
|
7947
|
-
var
|
|
7948
|
-
var
|
|
7950
|
+
var import_node_fs10 = require("node:fs");
|
|
7951
|
+
var import_node_path11 = require("node:path");
|
|
7949
7952
|
var import_node_net = require("node:net");
|
|
7950
7953
|
var import_node_util6 = require("node:util");
|
|
7951
7954
|
var execFileP4 = (0, import_node_util6.promisify)(import_node_child_process6.execFile);
|
|
7952
7955
|
var DOCKER_TIMEOUT_MS = 15e3;
|
|
7953
7956
|
var EARLY_EXIT_GRACE_MS = 2e3;
|
|
7954
7957
|
function waitForProcessStability(child, graceMs = EARLY_EXIT_GRACE_MS) {
|
|
7955
|
-
return new Promise((
|
|
7958
|
+
return new Promise((resolve6, reject) => {
|
|
7956
7959
|
let settled = false;
|
|
7957
7960
|
const finish = (fn) => {
|
|
7958
7961
|
if (settled) return;
|
|
@@ -7962,7 +7965,7 @@ function waitForProcessStability(child, graceMs = EARLY_EXIT_GRACE_MS) {
|
|
|
7962
7965
|
child.removeAllListeners("exit");
|
|
7963
7966
|
fn();
|
|
7964
7967
|
};
|
|
7965
|
-
const timer = setTimeout(() => finish(
|
|
7968
|
+
const timer = setTimeout(() => finish(resolve6), graceMs);
|
|
7966
7969
|
child.on("error", (err) => finish(() => reject(new Error(`stage process failed to start: ${err.message}`))));
|
|
7967
7970
|
child.on("exit", (code, signal) => {
|
|
7968
7971
|
const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
|
|
@@ -8062,11 +8065,11 @@ function appendForceRecreate(up) {
|
|
|
8062
8065
|
return `${up.trimEnd()} --force-recreate`;
|
|
8063
8066
|
}
|
|
8064
8067
|
function stageStatePath(cwd = process.cwd()) {
|
|
8065
|
-
return (0,
|
|
8068
|
+
return (0, import_node_path11.join)(cwd, "tmp", "stage", "state.json");
|
|
8066
8069
|
}
|
|
8067
8070
|
function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
|
|
8068
|
-
const dir = (0,
|
|
8069
|
-
return (0,
|
|
8071
|
+
const dir = (0, import_node_path11.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path11.resolve)(cwd, gitCommonDir);
|
|
8072
|
+
return (0, import_node_path11.join)(dir, "mmi", "stage", "state.json");
|
|
8070
8073
|
}
|
|
8071
8074
|
function normPath2(path2) {
|
|
8072
8075
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -8172,10 +8175,10 @@ function pickStagePort(range, isFree) {
|
|
|
8172
8175
|
throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
|
|
8173
8176
|
}
|
|
8174
8177
|
function isPortFree(port) {
|
|
8175
|
-
return new Promise((
|
|
8178
|
+
return new Promise((resolve6) => {
|
|
8176
8179
|
const srv = (0, import_node_net.createServer)();
|
|
8177
|
-
srv.once("error", () =>
|
|
8178
|
-
srv.once("listening", () => srv.close(() =>
|
|
8180
|
+
srv.once("error", () => resolve6(false));
|
|
8181
|
+
srv.once("listening", () => srv.close(() => resolve6(true)));
|
|
8179
8182
|
srv.listen(port, "127.0.0.1");
|
|
8180
8183
|
});
|
|
8181
8184
|
}
|
|
@@ -8290,14 +8293,14 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
8290
8293
|
}
|
|
8291
8294
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
8292
8295
|
if (!config.ensureEnv) return;
|
|
8293
|
-
const target = (0,
|
|
8294
|
-
const example = (0,
|
|
8295
|
-
if (!(0,
|
|
8296
|
-
(0,
|
|
8297
|
-
} else if ((0,
|
|
8298
|
-
const stale = detectStaleEnvFile((0,
|
|
8299
|
-
exampleMtimeMs: (0,
|
|
8300
|
-
targetMtimeMs: (0,
|
|
8296
|
+
const target = (0, import_node_path11.join)(cwd, config.ensureEnv.target);
|
|
8297
|
+
const example = (0, import_node_path11.join)(cwd, config.ensureEnv.example);
|
|
8298
|
+
if (!(0, import_node_fs10.existsSync)(target) && (0, import_node_fs10.existsSync)(example)) {
|
|
8299
|
+
(0, import_node_fs10.copyFileSync)(example, target);
|
|
8300
|
+
} else if ((0, import_node_fs10.existsSync)(target) && (0, import_node_fs10.existsSync)(example)) {
|
|
8301
|
+
const stale = detectStaleEnvFile((0, import_node_fs10.readFileSync)(example, "utf8"), (0, import_node_fs10.readFileSync)(target, "utf8"), {
|
|
8302
|
+
exampleMtimeMs: (0, import_node_fs10.statSync)(example).mtimeMs,
|
|
8303
|
+
targetMtimeMs: (0, import_node_fs10.statSync)(target).mtimeMs
|
|
8301
8304
|
});
|
|
8302
8305
|
if (stale) {
|
|
8303
8306
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -8305,8 +8308,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
8305
8308
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
8306
8309
|
}
|
|
8307
8310
|
}
|
|
8308
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
8309
|
-
(0,
|
|
8311
|
+
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs10.existsSync)(target)) {
|
|
8312
|
+
(0, import_node_fs10.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs10.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
|
|
8310
8313
|
}
|
|
8311
8314
|
}
|
|
8312
8315
|
async function gitText(cwd, args) {
|
|
@@ -8336,20 +8339,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
8336
8339
|
return void 0;
|
|
8337
8340
|
}
|
|
8338
8341
|
function readState(path2) {
|
|
8339
|
-
if (!(0,
|
|
8342
|
+
if (!(0, import_node_fs10.existsSync)(path2)) return null;
|
|
8340
8343
|
try {
|
|
8341
|
-
return JSON.parse((0,
|
|
8344
|
+
return JSON.parse((0, import_node_fs10.readFileSync)(path2, "utf8"));
|
|
8342
8345
|
} catch {
|
|
8343
8346
|
return null;
|
|
8344
8347
|
}
|
|
8345
8348
|
}
|
|
8346
8349
|
function mkdirFor(path2) {
|
|
8347
8350
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
8348
|
-
(0,
|
|
8351
|
+
(0, import_node_fs10.mkdirSync)(dir, { recursive: true });
|
|
8349
8352
|
}
|
|
8350
8353
|
function writeState(path2, state) {
|
|
8351
8354
|
mkdirFor(path2);
|
|
8352
|
-
(0,
|
|
8355
|
+
(0, import_node_fs10.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
8353
8356
|
}
|
|
8354
8357
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
8355
8358
|
const reservation = {
|
|
@@ -8369,7 +8372,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd) {
|
|
|
8369
8372
|
await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, timeoutMs);
|
|
8370
8373
|
}
|
|
8371
8374
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
8372
|
-
(0,
|
|
8375
|
+
(0, import_node_fs10.rmSync)(path2, { force: true });
|
|
8373
8376
|
}
|
|
8374
8377
|
}
|
|
8375
8378
|
async function killTree(pid) {
|
|
@@ -8386,7 +8389,7 @@ async function killTree(pid) {
|
|
|
8386
8389
|
} catch {
|
|
8387
8390
|
}
|
|
8388
8391
|
}
|
|
8389
|
-
await new Promise((
|
|
8392
|
+
await new Promise((resolve6) => setTimeout(resolve6, 500));
|
|
8390
8393
|
try {
|
|
8391
8394
|
process.kill(-pid, "SIGKILL");
|
|
8392
8395
|
} catch {
|
|
@@ -8407,7 +8410,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
|
|
|
8407
8410
|
} catch (e) {
|
|
8408
8411
|
last = e.message;
|
|
8409
8412
|
}
|
|
8410
|
-
await new Promise((
|
|
8413
|
+
await new Promise((resolve6) => setTimeout(resolve6, 1e3));
|
|
8411
8414
|
}
|
|
8412
8415
|
throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
|
|
8413
8416
|
}
|
|
@@ -8525,8 +8528,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
8525
8528
|
await ensureStageRuntimeEnv(config, opts, cwd);
|
|
8526
8529
|
if (build) await shell(sub(build), cwd, timeoutMs, stageProcessEnv(stagePort, extraEnv));
|
|
8527
8530
|
} catch (e) {
|
|
8528
|
-
(0,
|
|
8529
|
-
if (globalStatePath && globalStatePath !== statePath) (0,
|
|
8531
|
+
(0, import_node_fs10.rmSync)(statePath, { force: true });
|
|
8532
|
+
if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs10.rmSync)(globalStatePath, { force: true });
|
|
8530
8533
|
throw e;
|
|
8531
8534
|
}
|
|
8532
8535
|
const started = await startStage(config, {
|
|
@@ -8551,9 +8554,9 @@ function parseNextFromHead(headText) {
|
|
|
8551
8554
|
}
|
|
8552
8555
|
function readStageSummary(worktreePath) {
|
|
8553
8556
|
const statePath = stageStatePath(worktreePath);
|
|
8554
|
-
if (!(0,
|
|
8557
|
+
if (!(0, import_node_fs11.existsSync)(statePath)) return void 0;
|
|
8555
8558
|
try {
|
|
8556
|
-
const state = JSON.parse((0,
|
|
8559
|
+
const state = JSON.parse((0, import_node_fs11.readFileSync)(statePath, "utf8"));
|
|
8557
8560
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
8558
8561
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
8559
8562
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -8596,7 +8599,7 @@ async function collectWaveStatus(deps) {
|
|
|
8596
8599
|
} catch {
|
|
8597
8600
|
dirty = true;
|
|
8598
8601
|
}
|
|
8599
|
-
const headText = await deps.fetchSagaHeadText(wt.branch).catch(() => void 0);
|
|
8602
|
+
const headText = await deps.fetchSagaHeadText?.(wt.branch).catch(() => void 0);
|
|
8600
8603
|
rows.push({
|
|
8601
8604
|
path: wt.path,
|
|
8602
8605
|
branch: wt.branch,
|
|
@@ -8669,9 +8672,9 @@ async function resolveAutoAddBoardAttach(client, cfg, selector, priority, warn =
|
|
|
8669
8672
|
|
|
8670
8673
|
// src/gh-create.ts
|
|
8671
8674
|
var import_promises2 = require("node:fs/promises");
|
|
8672
|
-
var
|
|
8673
|
-
var
|
|
8674
|
-
var
|
|
8675
|
+
var import_node_os3 = require("node:os");
|
|
8676
|
+
var import_node_path12 = require("node:path");
|
|
8677
|
+
var import_node_crypto3 = require("node:crypto");
|
|
8675
8678
|
var ISSUE_TYPES = ["bug", "feature", "task"];
|
|
8676
8679
|
var GH_MUTATION_TIMEOUT_MS = 12e4;
|
|
8677
8680
|
function timeoutKillNote(err, timeoutMs) {
|
|
@@ -8711,7 +8714,7 @@ async function bodyArgsViaFile(args, deps = {}) {
|
|
|
8711
8714
|
} };
|
|
8712
8715
|
const write = deps.write ?? import_promises2.writeFile;
|
|
8713
8716
|
const remove = deps.remove ?? import_promises2.unlink;
|
|
8714
|
-
const file = (0,
|
|
8717
|
+
const file = (0, import_node_path12.join)(deps.dir ?? (0, import_node_os3.tmpdir)(), `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
|
|
8715
8718
|
await write(file, args[i + 1], "utf8");
|
|
8716
8719
|
return {
|
|
8717
8720
|
args: [...args.slice(0, i), "--body-file", file, ...args.slice(i + 2)],
|
|
@@ -8757,9 +8760,9 @@ function buildPrArgs({ title, body, base, head, repo }) {
|
|
|
8757
8760
|
}
|
|
8758
8761
|
|
|
8759
8762
|
// src/issue-body.ts
|
|
8760
|
-
var
|
|
8763
|
+
var import_node_os4 = require("node:os");
|
|
8761
8764
|
function emptyStdinMessage(fileFlag) {
|
|
8762
|
-
if ((0,
|
|
8765
|
+
if ((0, import_node_os4.platform)() === "win32") {
|
|
8763
8766
|
return `${fileFlag} - read empty stdin (on Windows, ${fileFlag} - is unreliable through the npm .cmd shim \u2014 use ${fileFlag} <path>, or pipe to \`node cli/dist/index.cjs\` directly)`;
|
|
8764
8767
|
}
|
|
8765
8768
|
return `${fileFlag} - read empty stdin (nothing piped \u2014 pass a heredoc/pipe, or ${fileFlag} <path>)`;
|
|
@@ -9410,7 +9413,7 @@ function bootstrapPlan(repo, repoClass) {
|
|
|
9410
9413
|
{ label: `create or inspect ${repo}` },
|
|
9411
9414
|
{ label: `provision branch model: ${branchModel}`, gated: true },
|
|
9412
9415
|
{ label: `apply branch protection / allowlist: ${protectedBranches}`, gated: true },
|
|
9413
|
-
{ label: "attach GitHub Project v2 and register
|
|
9416
|
+
{ label: "attach GitHub Project v2 and register Hub registry META", gated: true },
|
|
9414
9417
|
{ label: "seed README.md and architecture.md", gated: true },
|
|
9415
9418
|
{ label: "commit .cursor/rules/<repo>.mdc and .cursor/environment.json", gated: true },
|
|
9416
9419
|
{ label: `register fanout target on ${repoClass === "content" ? "main" : "development"}`, gated: true }
|
|
@@ -9600,9 +9603,6 @@ async function runStageLiveDown(deps, t) {
|
|
|
9600
9603
|
// src/git-clean-tree.ts
|
|
9601
9604
|
function isAgentScratchPath(path2) {
|
|
9602
9605
|
const normalized = path2.replace(/\\/g, "/").trim();
|
|
9603
|
-
if (normalized === ".mmi" || normalized.startsWith(".mmi/")) {
|
|
9604
|
-
return true;
|
|
9605
|
-
}
|
|
9606
9606
|
return /^tmp_[^/]+$/.test(normalized);
|
|
9607
9607
|
}
|
|
9608
9608
|
function porcelainHasBlockingChanges(porcelain) {
|
|
@@ -9746,7 +9746,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
|
|
|
9746
9746
|
async function predictMergeConflicts(deps, ours, theirs) {
|
|
9747
9747
|
return runMergeTreePreflight(deps, ours, theirs);
|
|
9748
9748
|
}
|
|
9749
|
-
async function mergeWithToleratedResolution(deps, sourceRef, label,
|
|
9749
|
+
async function mergeWithToleratedResolution(deps, sourceRef, label, resolve6, extraTolerated = []) {
|
|
9750
9750
|
try {
|
|
9751
9751
|
await deps.run("git", ["merge", sourceRef, "--no-edit"]);
|
|
9752
9752
|
return;
|
|
@@ -9760,7 +9760,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve5, ex
|
|
|
9760
9760
|
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)`
|
|
9761
9761
|
);
|
|
9762
9762
|
}
|
|
9763
|
-
await deps.run("git", ["checkout", `--${
|
|
9763
|
+
await deps.run("git", ["checkout", `--${resolve6}`, "--", ...unmerged]);
|
|
9764
9764
|
await deps.run("git", ["add", "--", ...unmerged]);
|
|
9765
9765
|
await deps.run("git", ["commit", "--no-edit"]);
|
|
9766
9766
|
}
|
|
@@ -9877,7 +9877,7 @@ function requireProjectMetaForTrain(load, repo) {
|
|
|
9877
9877
|
var CORRELATE_ATTEMPTS = 5;
|
|
9878
9878
|
var CORRELATE_DELAY_MS = 1500;
|
|
9879
9879
|
var CORRELATE_SKEW_SLACK_MS = 1e4;
|
|
9880
|
-
var defaultSleep2 = (ms) => new Promise((
|
|
9880
|
+
var defaultSleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
9881
9881
|
function resolveSleep(deps) {
|
|
9882
9882
|
return deps.sleep ?? defaultSleep2;
|
|
9883
9883
|
}
|
|
@@ -10887,7 +10887,7 @@ function clean2(out) {
|
|
|
10887
10887
|
return out.trim();
|
|
10888
10888
|
}
|
|
10889
10889
|
function sleeper(deps) {
|
|
10890
|
-
return deps.sleep ?? ((ms) => new Promise((
|
|
10890
|
+
return deps.sleep ?? ((ms) => new Promise((resolve6) => setTimeout(resolve6, ms)));
|
|
10891
10891
|
}
|
|
10892
10892
|
function normalizeHotfixVersion(input) {
|
|
10893
10893
|
const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
|
|
@@ -11464,8 +11464,8 @@ async function announceRelease(deps, args) {
|
|
|
11464
11464
|
}
|
|
11465
11465
|
|
|
11466
11466
|
// src/port-registry.ts
|
|
11467
|
-
var
|
|
11468
|
-
var
|
|
11467
|
+
var import_node_fs12 = require("node:fs");
|
|
11468
|
+
var import_node_path13 = require("node:path");
|
|
11469
11469
|
|
|
11470
11470
|
// ../infra/port-geometry.mjs
|
|
11471
11471
|
var PORT_BLOCK = 100;
|
|
@@ -11479,8 +11479,8 @@ function nextPortBlock(registry2) {
|
|
|
11479
11479
|
return [base, base + PORT_SPAN];
|
|
11480
11480
|
}
|
|
11481
11481
|
function loadPortRegistry(path2) {
|
|
11482
|
-
if (!(0,
|
|
11483
|
-
const raw = JSON.parse((0,
|
|
11482
|
+
if (!(0, import_node_fs12.existsSync)(path2)) return {};
|
|
11483
|
+
const raw = JSON.parse((0, import_node_fs12.readFileSync)(path2, "utf8"));
|
|
11484
11484
|
const out = {};
|
|
11485
11485
|
for (const [key, value] of Object.entries(raw)) {
|
|
11486
11486
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -11494,9 +11494,9 @@ function ensurePortRange(repo, path2) {
|
|
|
11494
11494
|
const existing = registry2[repo];
|
|
11495
11495
|
if (existing) return existing;
|
|
11496
11496
|
const range = nextPortBlock(registry2);
|
|
11497
|
-
const raw = (0,
|
|
11497
|
+
const raw = (0, import_node_fs12.existsSync)(path2) ? JSON.parse((0, import_node_fs12.readFileSync)(path2, "utf8")) : {};
|
|
11498
11498
|
raw[repo] = range;
|
|
11499
|
-
(0,
|
|
11499
|
+
(0, import_node_fs12.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
|
|
11500
11500
|
return range;
|
|
11501
11501
|
}
|
|
11502
11502
|
function portCursorSeed(registry2) {
|
|
@@ -11518,18 +11518,18 @@ function existingPortRange(repo, registry2) {
|
|
|
11518
11518
|
return registry2[repo] ?? null;
|
|
11519
11519
|
}
|
|
11520
11520
|
function portRangeInfraAt(root, source) {
|
|
11521
|
-
const registryPath = (0,
|
|
11522
|
-
const ddbScriptPath = (0,
|
|
11523
|
-
if (!(0,
|
|
11521
|
+
const registryPath = (0, import_node_path13.join)(root, "infra", "port-ranges.json");
|
|
11522
|
+
const ddbScriptPath = (0, import_node_path13.join)(root, "infra", "port-ddb.mjs");
|
|
11523
|
+
if (!(0, import_node_fs12.existsSync)(registryPath) || !(0, import_node_fs12.existsSync)(ddbScriptPath)) return null;
|
|
11524
11524
|
return { root, source, registryPath, ddbScriptPath };
|
|
11525
11525
|
}
|
|
11526
11526
|
function resolvePortRangeInfra(cwd) {
|
|
11527
11527
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
11528
11528
|
if (direct) return direct;
|
|
11529
|
-
for (let dir = cwd; ; dir = (0,
|
|
11530
|
-
const sibling = portRangeInfraAt((0,
|
|
11529
|
+
for (let dir = cwd; ; dir = (0, import_node_path13.dirname)(dir)) {
|
|
11530
|
+
const sibling = portRangeInfraAt((0, import_node_path13.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
11531
11531
|
if (sibling) return sibling;
|
|
11532
|
-
const parent = (0,
|
|
11532
|
+
const parent = (0, import_node_path13.dirname)(dir);
|
|
11533
11533
|
if (parent === dir) return null;
|
|
11534
11534
|
}
|
|
11535
11535
|
}
|
|
@@ -14307,8 +14307,8 @@ async function secretsUse(deps, key, opts) {
|
|
|
14307
14307
|
}
|
|
14308
14308
|
|
|
14309
14309
|
// src/secrets-commands.ts
|
|
14310
|
-
var
|
|
14311
|
-
var
|
|
14310
|
+
var import_node_fs13 = require("node:fs");
|
|
14311
|
+
var import_node_path14 = require("node:path");
|
|
14312
14312
|
var RAILS_CREDENTIALS_DECRYPT_TIMEOUT_MS = 3e4;
|
|
14313
14313
|
var DEFAULT_RAILS_CREDENTIALS_FILE = "config/credentials.yml.enc";
|
|
14314
14314
|
var DEFAULT_RAILS_MASTER_KEY_FILE = "config/master.key";
|
|
@@ -14316,18 +14316,18 @@ function collectMap(value, previous = []) {
|
|
|
14316
14316
|
return [...previous, value];
|
|
14317
14317
|
}
|
|
14318
14318
|
async function decryptRailsCredentials(input) {
|
|
14319
|
-
const appDir = (0,
|
|
14319
|
+
const appDir = (0, import_node_path14.resolve)(input.appDir ?? process.cwd());
|
|
14320
14320
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
14321
14321
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
14322
|
-
const credentialsPath = (0,
|
|
14323
|
-
const masterKeyPath = (0,
|
|
14322
|
+
const credentialsPath = (0, import_node_path14.resolve)(appDir, credentialsFile);
|
|
14323
|
+
const masterKeyPath = (0, import_node_path14.resolve)(appDir, masterKeyFile);
|
|
14324
14324
|
const env = {
|
|
14325
14325
|
...process.env,
|
|
14326
14326
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
14327
14327
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
14328
14328
|
};
|
|
14329
|
-
if ((0,
|
|
14330
|
-
env.RAILS_MASTER_KEY = (0,
|
|
14329
|
+
if ((0, import_node_fs13.existsSync)(masterKeyPath)) {
|
|
14330
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs13.readFileSync)(masterKeyPath, "utf8").trim();
|
|
14331
14331
|
}
|
|
14332
14332
|
const script = [
|
|
14333
14333
|
'require "json"',
|
|
@@ -14393,7 +14393,7 @@ function registerSecretsCommands(program3) {
|
|
|
14393
14393
|
secrets.command("org-catalog").description("MASTER-ONLY: set the _org/<provider>/* catalog declarations from a JSON file (#2244)").requiredOption("--file <path>", 'JSON file: { "entries": { "<provider>/<KEY>": {key,purpose,group,owner,provider,stages[],consumers[]} } }').action((o) => withSecrets(async (d) => {
|
|
14394
14394
|
let body;
|
|
14395
14395
|
try {
|
|
14396
|
-
body = (0,
|
|
14396
|
+
body = (0, import_node_fs13.readFileSync)((0, import_node_path14.resolve)(o.file), "utf8");
|
|
14397
14397
|
} catch (e) {
|
|
14398
14398
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
14399
14399
|
}
|
|
@@ -14468,7 +14468,7 @@ function registerSecretsCommands(program3) {
|
|
|
14468
14468
|
{
|
|
14469
14469
|
...d,
|
|
14470
14470
|
decryptRailsCredentials,
|
|
14471
|
-
removeFile: (path2) => (0,
|
|
14471
|
+
removeFile: (path2) => (0, import_node_fs13.unlinkSync)((0, import_node_path14.resolve)(o.appDir ?? process.cwd(), path2))
|
|
14472
14472
|
},
|
|
14473
14473
|
{
|
|
14474
14474
|
repo: o.repo,
|
|
@@ -14557,11 +14557,11 @@ function registerEdgeCommands(program3) {
|
|
|
14557
14557
|
}
|
|
14558
14558
|
|
|
14559
14559
|
// src/doctor-run.ts
|
|
14560
|
-
var
|
|
14560
|
+
var import_node_fs17 = require("node:fs");
|
|
14561
14561
|
var import_node_child_process10 = require("node:child_process");
|
|
14562
14562
|
var import_promises3 = require("node:fs/promises");
|
|
14563
|
-
var
|
|
14564
|
-
var
|
|
14563
|
+
var import_node_path17 = require("node:path");
|
|
14564
|
+
var import_node_os6 = require("node:os");
|
|
14565
14565
|
|
|
14566
14566
|
// src/plugin-guard.ts
|
|
14567
14567
|
function buildPluginGuardDecision(i) {
|
|
@@ -14582,9 +14582,9 @@ function buildGuardSessionStartLine(state, opts = {}) {
|
|
|
14582
14582
|
|
|
14583
14583
|
// src/cursor-plugin-seed.ts
|
|
14584
14584
|
var import_node_child_process9 = require("node:child_process");
|
|
14585
|
-
var
|
|
14586
|
-
var
|
|
14587
|
-
var
|
|
14585
|
+
var import_node_fs14 = require("node:fs");
|
|
14586
|
+
var import_node_os5 = require("node:os");
|
|
14587
|
+
var import_node_path15 = require("node:path");
|
|
14588
14588
|
var import_node_util7 = require("node:util");
|
|
14589
14589
|
function isSemverVersion(v) {
|
|
14590
14590
|
return typeof v === "string" && /^v?\d+\.\d+\.\d+/.test(v.trim());
|
|
@@ -14601,17 +14601,17 @@ function ghReleaseTarballApiArgs(tag) {
|
|
|
14601
14601
|
}
|
|
14602
14602
|
function cursorUserGlobalStatePath() {
|
|
14603
14603
|
if (process.platform === "win32") {
|
|
14604
|
-
const base = process.env.APPDATA || (0,
|
|
14605
|
-
return (0,
|
|
14604
|
+
const base = process.env.APPDATA || (0, import_node_path15.join)((0, import_node_os5.homedir)(), "AppData", "Roaming");
|
|
14605
|
+
return (0, import_node_path15.join)(base, "Cursor", "User", "globalStorage", "state.vscdb");
|
|
14606
14606
|
}
|
|
14607
14607
|
if (process.platform === "darwin") {
|
|
14608
|
-
return (0,
|
|
14608
|
+
return (0, import_node_path15.join)((0, import_node_os5.homedir)(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
14609
14609
|
}
|
|
14610
|
-
return (0,
|
|
14610
|
+
return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
14611
14611
|
}
|
|
14612
14612
|
async function readCursorThirdPartyExtensibilityEnabled(execFileP5) {
|
|
14613
14613
|
const dbPath = cursorUserGlobalStatePath();
|
|
14614
|
-
if (!(0,
|
|
14614
|
+
if (!(0, import_node_fs14.existsSync)(dbPath)) return void 0;
|
|
14615
14615
|
try {
|
|
14616
14616
|
const { stdout } = await execFileP5("sqlite3", [dbPath, `SELECT value FROM ItemTable WHERE key = '${CURSOR_THIRD_PARTY_STATE_KEY}';`], {
|
|
14617
14617
|
timeout: 5e3
|
|
@@ -14625,57 +14625,57 @@ async function readCursorThirdPartyExtensibilityEnabled(execFileP5) {
|
|
|
14625
14625
|
}
|
|
14626
14626
|
}
|
|
14627
14627
|
function syncDirContents(src, dest) {
|
|
14628
|
-
(0,
|
|
14629
|
-
for (const name of (0,
|
|
14630
|
-
(0,
|
|
14628
|
+
(0, import_node_fs14.mkdirSync)(dest, { recursive: true });
|
|
14629
|
+
for (const name of (0, import_node_fs14.readdirSync)(dest)) {
|
|
14630
|
+
(0, import_node_fs14.rmSync)((0, import_node_path15.join)(dest, name), { recursive: true, force: true });
|
|
14631
14631
|
}
|
|
14632
|
-
(0,
|
|
14632
|
+
(0, import_node_fs14.cpSync)(src, dest, { recursive: true });
|
|
14633
14633
|
}
|
|
14634
14634
|
function releaseTag(releasedVersion) {
|
|
14635
14635
|
return releasedVersion.startsWith("v") ? releasedVersion : `v${releasedVersion}`;
|
|
14636
14636
|
}
|
|
14637
14637
|
async function extractPluginMmiFromHubCheckout(hubCheckout, tag, tmpRoot, execFileP5) {
|
|
14638
|
-
const tarFile = (0,
|
|
14638
|
+
const tarFile = (0, import_node_path15.join)(tmpRoot, "archive.tar");
|
|
14639
14639
|
try {
|
|
14640
14640
|
await execFileP5("git", gitFetchReleaseTagArgs(hubCheckout, tag), { timeout: 6e4 });
|
|
14641
14641
|
await execFileP5("git", ["-C", hubCheckout, "archive", "--format=tar", `--output=${tarFile}`, tag, "plugins/mmi"], {
|
|
14642
14642
|
timeout: 6e4
|
|
14643
14643
|
});
|
|
14644
14644
|
await execFileP5("tar", ["-xf", tarFile, "-C", tmpRoot], { timeout: 6e4 });
|
|
14645
|
-
const pluginMmi = (0,
|
|
14646
|
-
return (0,
|
|
14645
|
+
const pluginMmi = (0, import_node_path15.join)(tmpRoot, "plugins", "mmi");
|
|
14646
|
+
return (0, import_node_fs14.existsSync)((0, import_node_path15.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
|
|
14647
14647
|
} catch {
|
|
14648
14648
|
return void 0;
|
|
14649
14649
|
}
|
|
14650
14650
|
}
|
|
14651
14651
|
async function downloadPluginMmiViaGh(tag, tmpRoot) {
|
|
14652
|
-
const tarPath = (0,
|
|
14652
|
+
const tarPath = (0, import_node_path15.join)(tmpRoot, "repo.tgz");
|
|
14653
14653
|
try {
|
|
14654
|
-
(0,
|
|
14654
|
+
(0, import_node_fs14.mkdirSync)(tmpRoot, { recursive: true });
|
|
14655
14655
|
const { stdout } = await execFileBuffer("gh", ghReleaseTarballApiArgs(tag), {
|
|
14656
14656
|
timeout: 12e4,
|
|
14657
14657
|
maxBuffer: 100 * 1024 * 1024,
|
|
14658
14658
|
encoding: "buffer",
|
|
14659
14659
|
windowsHide: true
|
|
14660
14660
|
});
|
|
14661
|
-
(0,
|
|
14661
|
+
(0, import_node_fs14.writeFileSync)(tarPath, stdout);
|
|
14662
14662
|
await execFileBuffer("tar", ["-xzf", tarPath, "-C", tmpRoot], { timeout: 12e4, windowsHide: true });
|
|
14663
|
-
const top = (0,
|
|
14663
|
+
const top = (0, import_node_fs14.readdirSync)(tmpRoot).find((entry) => entry !== "repo.tgz");
|
|
14664
14664
|
if (!top) return void 0;
|
|
14665
|
-
const pluginMmi = (0,
|
|
14666
|
-
return (0,
|
|
14665
|
+
const pluginMmi = (0, import_node_path15.join)(tmpRoot, top, "plugins", "mmi");
|
|
14666
|
+
return (0, import_node_fs14.existsSync)((0, import_node_path15.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
|
|
14667
14667
|
} catch {
|
|
14668
14668
|
return void 0;
|
|
14669
14669
|
}
|
|
14670
14670
|
}
|
|
14671
14671
|
async function resolvePluginMmiSource(releasedVersion, hubCheckout, tmpRoot, execFileP5) {
|
|
14672
|
-
(0,
|
|
14672
|
+
(0, import_node_fs14.mkdirSync)(tmpRoot, { recursive: true });
|
|
14673
14673
|
const tag = releaseTag(releasedVersion);
|
|
14674
14674
|
if (hubCheckout) {
|
|
14675
14675
|
const fromHub = await extractPluginMmiFromHubCheckout(hubCheckout, tag, tmpRoot, execFileP5);
|
|
14676
14676
|
if (fromHub) return fromHub;
|
|
14677
14677
|
}
|
|
14678
|
-
return downloadPluginMmiViaGh(tag, (0,
|
|
14678
|
+
return downloadPluginMmiViaGh(tag, (0, import_node_path15.join)(tmpRoot, "gh"));
|
|
14679
14679
|
}
|
|
14680
14680
|
function cursorPluginPinsNeedingSeed(pins, releasedVersion) {
|
|
14681
14681
|
if (!isSemverVersion(releasedVersion)) return pins.filter((pin) => !pin.hasPluginJson || !pin.hasHooksJson || pin.isEmpty);
|
|
@@ -14696,7 +14696,7 @@ async function applyCursorPluginCacheSeed(input) {
|
|
|
14696
14696
|
for (const pin of pinsToSeed) {
|
|
14697
14697
|
syncDirContents(source, pin.path);
|
|
14698
14698
|
}
|
|
14699
|
-
(0,
|
|
14699
|
+
(0, import_node_fs14.rmSync)(tmpRoot, { recursive: true, force: true });
|
|
14700
14700
|
return true;
|
|
14701
14701
|
}
|
|
14702
14702
|
|
|
@@ -14715,7 +14715,7 @@ function buildGithubAuthCheck(input) {
|
|
|
14715
14715
|
const ok = Boolean(input.login?.trim());
|
|
14716
14716
|
return {
|
|
14717
14717
|
ok,
|
|
14718
|
-
label: "GitHub auth identity (
|
|
14718
|
+
label: "GitHub auth identity (gh ops)",
|
|
14719
14719
|
fix: input.ghInstalled ? GH_PROJECT_LOGIN_FIX : `install GitHub CLI (https://cli.github.com), then: ${GH_PROJECT_LOGIN_FIX.replace(/^run: /, "")}`
|
|
14720
14720
|
};
|
|
14721
14721
|
}
|
|
@@ -15802,9 +15802,9 @@ function buildPluginResolvabilityCheck(input) {
|
|
|
15802
15802
|
}
|
|
15803
15803
|
|
|
15804
15804
|
// src/cli-doctor-shared.ts
|
|
15805
|
-
var import_node_fs14 = require("node:fs");
|
|
15806
|
-
var import_node_path15 = require("node:path");
|
|
15807
15805
|
var import_node_fs15 = require("node:fs");
|
|
15806
|
+
var import_node_path16 = require("node:path");
|
|
15807
|
+
var import_node_fs16 = require("node:fs");
|
|
15808
15808
|
var GC_GH_TIMEOUT_MS = 2e4;
|
|
15809
15809
|
async function awsCallerArn() {
|
|
15810
15810
|
try {
|
|
@@ -15850,7 +15850,7 @@ async function localBranchHeads() {
|
|
|
15850
15850
|
}
|
|
15851
15851
|
async function currentRepoWorktreeGitRoot(repoRoot) {
|
|
15852
15852
|
const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
15853
|
-
return gitCommonDir ? (0,
|
|
15853
|
+
return gitCommonDir ? (0, import_node_path16.resolve)(repoRoot, gitCommonDir, "worktrees") : "";
|
|
15854
15854
|
}
|
|
15855
15855
|
async function worktreeBranches() {
|
|
15856
15856
|
const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
|
|
@@ -15870,18 +15870,18 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
|
|
|
15870
15870
|
const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
|
|
15871
15871
|
if (!match?.[1]) return void 0;
|
|
15872
15872
|
const raw = match[1].trim();
|
|
15873
|
-
return (0,
|
|
15873
|
+
return (0, import_node_path16.isAbsolute)(raw) ? raw : (0, import_node_path16.resolve)(worktreePath, raw);
|
|
15874
15874
|
}
|
|
15875
15875
|
function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
15876
15876
|
if (!worktreeGitRoot) return false;
|
|
15877
15877
|
try {
|
|
15878
|
-
const entries = (0,
|
|
15878
|
+
const entries = (0, import_node_fs16.readdirSync)(worktreeGitRoot, { withFileTypes: true });
|
|
15879
15879
|
for (const ent of entries) {
|
|
15880
15880
|
if (!ent.isDirectory()) continue;
|
|
15881
15881
|
try {
|
|
15882
|
-
const gitdirPath = (0,
|
|
15883
|
-
const resolvedGitdir = (0,
|
|
15884
|
-
if (sameWorktreeMetadataPath((0,
|
|
15882
|
+
const gitdirPath = (0, import_node_fs15.readFileSync)((0, import_node_path16.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
|
|
15883
|
+
const resolvedGitdir = (0, import_node_path16.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path16.resolve)(worktreeGitRoot, ent.name, gitdirPath);
|
|
15884
|
+
if (sameWorktreeMetadataPath((0, import_node_path16.dirname)(resolvedGitdir), worktreePath)) return true;
|
|
15885
15885
|
} catch {
|
|
15886
15886
|
}
|
|
15887
15887
|
}
|
|
@@ -15891,7 +15891,7 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
|
15891
15891
|
}
|
|
15892
15892
|
function pathExistsKnown(path2) {
|
|
15893
15893
|
try {
|
|
15894
|
-
(0,
|
|
15894
|
+
(0, import_node_fs16.statSync)(path2);
|
|
15895
15895
|
return true;
|
|
15896
15896
|
} catch (e) {
|
|
15897
15897
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
@@ -15900,10 +15900,10 @@ function pathExistsKnown(path2) {
|
|
|
15900
15900
|
}
|
|
15901
15901
|
}
|
|
15902
15902
|
function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
15903
|
-
const gitPath = (0,
|
|
15903
|
+
const gitPath = (0, import_node_path16.join)(path2, ".git");
|
|
15904
15904
|
let st;
|
|
15905
15905
|
try {
|
|
15906
|
-
st = (0,
|
|
15906
|
+
st = (0, import_node_fs16.lstatSync)(gitPath);
|
|
15907
15907
|
} catch (e) {
|
|
15908
15908
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
15909
15909
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -15920,7 +15920,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
|
15920
15920
|
if (st.isDirectory()) return { path: path2, gitType: "dir" };
|
|
15921
15921
|
if (!st.isFile()) return { path: path2, gitType: "other" };
|
|
15922
15922
|
try {
|
|
15923
|
-
const gitFileContent = (0,
|
|
15923
|
+
const gitFileContent = (0, import_node_fs15.readFileSync)(gitPath, "utf8");
|
|
15924
15924
|
const gitdir = resolveGitdirForWorktreeFile(path2, gitFileContent);
|
|
15925
15925
|
const gitDirExists = gitdir ? pathExistsKnown(gitdir) : false;
|
|
15926
15926
|
return {
|
|
@@ -15937,7 +15937,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
|
15937
15937
|
}
|
|
15938
15938
|
function inspectDeadWorktreeDirContent(path2) {
|
|
15939
15939
|
try {
|
|
15940
|
-
return { entries: (0,
|
|
15940
|
+
return { entries: (0, import_node_fs16.readdirSync)(path2) };
|
|
15941
15941
|
} catch (e) {
|
|
15942
15942
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
15943
15943
|
return { error: code ? `unable to inspect directory contents (${code})` : "unable to inspect directory contents" };
|
|
@@ -15956,8 +15956,8 @@ async function siblingWorktreeDirs() {
|
|
|
15956
15956
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot);
|
|
15957
15957
|
const siblingRoot = siblingMmiWorktreesRoot(repoRoot);
|
|
15958
15958
|
try {
|
|
15959
|
-
const entries = (0,
|
|
15960
|
-
return entries.filter((ent) => ent.isDirectory()).map((ent) => inspectSiblingWorktreeDir((0,
|
|
15959
|
+
const entries = (0, import_node_fs16.readdirSync)(siblingRoot, { withFileTypes: true });
|
|
15960
|
+
return entries.filter((ent) => ent.isDirectory()).map((ent) => inspectSiblingWorktreeDir((0, import_node_path16.join)(siblingRoot, ent.name), worktreeGitRoot)).filter((entry) => Boolean(entry));
|
|
15961
15961
|
} catch {
|
|
15962
15962
|
return [];
|
|
15963
15963
|
}
|
|
@@ -16007,7 +16007,7 @@ async function fetchHubVersionInfo(baseUrl) {
|
|
|
16007
16007
|
}
|
|
16008
16008
|
function readRepoVersion() {
|
|
16009
16009
|
try {
|
|
16010
|
-
return JSON.parse((0,
|
|
16010
|
+
return JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path17.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
16011
16011
|
} catch {
|
|
16012
16012
|
return void 0;
|
|
16013
16013
|
}
|
|
@@ -16058,12 +16058,12 @@ function runHostBin(bin, args, opts) {
|
|
|
16058
16058
|
return isWin ? execFileP2("cmd.exe", ["/c", bin, ...args], opts) : execFileP2(bin, args, opts);
|
|
16059
16059
|
}
|
|
16060
16060
|
function reexecMmiCli(args) {
|
|
16061
|
-
return new Promise((
|
|
16061
|
+
return new Promise((resolve6) => {
|
|
16062
16062
|
let settled = false;
|
|
16063
16063
|
const done = (code) => {
|
|
16064
16064
|
if (!settled) {
|
|
16065
16065
|
settled = true;
|
|
16066
|
-
|
|
16066
|
+
resolve6(code);
|
|
16067
16067
|
}
|
|
16068
16068
|
};
|
|
16069
16069
|
const env = { ...process.env, [DOCTOR_POST_SELF_UPDATE_ENV]: "1" };
|
|
@@ -16124,11 +16124,11 @@ async function applyPluginHeal(token, surface, log, opts) {
|
|
|
16124
16124
|
}
|
|
16125
16125
|
var installedPluginsPath = (surface = detectSurface(process.env)) => {
|
|
16126
16126
|
const homeDir = surface === "codex" ? ".codex" : ".claude";
|
|
16127
|
-
return (0,
|
|
16127
|
+
return (0, import_node_path17.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "installed_plugins.json");
|
|
16128
16128
|
};
|
|
16129
16129
|
function readInstalledPlugins(surface = detectSurface(process.env)) {
|
|
16130
16130
|
try {
|
|
16131
|
-
return JSON.parse((0,
|
|
16131
|
+
return JSON.parse((0, import_node_fs17.readFileSync)(installedPluginsPath(surface), "utf8"));
|
|
16132
16132
|
} catch {
|
|
16133
16133
|
return null;
|
|
16134
16134
|
}
|
|
@@ -16139,15 +16139,15 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
|
|
|
16139
16139
|
return {
|
|
16140
16140
|
isOrgRepo,
|
|
16141
16141
|
installRecordPresent: hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()),
|
|
16142
|
-
marketplaceClonePresent: (0,
|
|
16143
|
-
pluginCachePresent: (0,
|
|
16142
|
+
marketplaceClonePresent: (0, import_node_fs17.existsSync)((0, import_node_path17.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "marketplaces", "mutmutco")),
|
|
16143
|
+
pluginCachePresent: (0, import_node_fs17.existsSync)((0, import_node_path17.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "cache", "mutmutco", "mmi"))
|
|
16144
16144
|
};
|
|
16145
16145
|
}
|
|
16146
16146
|
function installedPluginSources() {
|
|
16147
16147
|
return ["claude", "codex"].map((surface) => {
|
|
16148
|
-
const recordPath = (0,
|
|
16148
|
+
const recordPath = (0, import_node_path17.join)((0, import_node_os6.homedir)(), `.${surface}`, "plugins", "installed_plugins.json");
|
|
16149
16149
|
try {
|
|
16150
|
-
return { surface, installed: JSON.parse((0,
|
|
16150
|
+
return { surface, installed: JSON.parse((0, import_node_fs17.readFileSync)(recordPath, "utf8")), recordPath };
|
|
16151
16151
|
} catch {
|
|
16152
16152
|
return { surface, installed: null, recordPath };
|
|
16153
16153
|
}
|
|
@@ -16155,7 +16155,7 @@ function installedPluginSources() {
|
|
|
16155
16155
|
}
|
|
16156
16156
|
function readClaudeSettings() {
|
|
16157
16157
|
try {
|
|
16158
|
-
return JSON.parse((0,
|
|
16158
|
+
return JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path17.join)(process.cwd(), ".claude", "settings.json"), "utf8"));
|
|
16159
16159
|
} catch {
|
|
16160
16160
|
return null;
|
|
16161
16161
|
}
|
|
@@ -16177,7 +16177,7 @@ function writeProjectInstallRecord(record) {
|
|
|
16177
16177
|
const list = file.plugins[MMI_PLUGIN_ID] ?? [];
|
|
16178
16178
|
list.push(record);
|
|
16179
16179
|
file.plugins[MMI_PLUGIN_ID] = list;
|
|
16180
|
-
(0,
|
|
16180
|
+
(0, import_node_fs17.writeFileSync)(installedPluginsPath(), `${JSON.stringify(file, null, 2)}
|
|
16181
16181
|
`, "utf8");
|
|
16182
16182
|
return true;
|
|
16183
16183
|
} catch {
|
|
@@ -16190,9 +16190,9 @@ function backupAndWriteInstalledPlugins(records, pluginId) {
|
|
|
16190
16190
|
if (!file) return false;
|
|
16191
16191
|
if (!file.plugins) file.plugins = {};
|
|
16192
16192
|
const path2 = installedPluginsPath();
|
|
16193
|
-
(0,
|
|
16193
|
+
(0, import_node_fs17.copyFileSync)(path2, `${path2}.bak`);
|
|
16194
16194
|
file.plugins[pluginId] = records;
|
|
16195
|
-
(0,
|
|
16195
|
+
(0, import_node_fs17.writeFileSync)(path2, `${JSON.stringify(file, null, 2)}
|
|
16196
16196
|
`, "utf8");
|
|
16197
16197
|
return true;
|
|
16198
16198
|
} catch {
|
|
@@ -16200,22 +16200,22 @@ function backupAndWriteInstalledPlugins(records, pluginId) {
|
|
|
16200
16200
|
}
|
|
16201
16201
|
}
|
|
16202
16202
|
function opencodeConfigDir() {
|
|
16203
|
-
return (0,
|
|
16203
|
+
return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".config", "opencode");
|
|
16204
16204
|
}
|
|
16205
16205
|
function opencodeConfigPath() {
|
|
16206
|
-
return (0,
|
|
16206
|
+
return (0, import_node_path17.join)(opencodeConfigDir(), "opencode.jsonc");
|
|
16207
16207
|
}
|
|
16208
16208
|
function opencodeCommandsDir() {
|
|
16209
|
-
return (0,
|
|
16209
|
+
return (0, import_node_path17.join)(opencodeConfigDir(), "commands");
|
|
16210
16210
|
}
|
|
16211
16211
|
function opencodeSkillsPath() {
|
|
16212
|
-
return (0,
|
|
16212
|
+
return (0, import_node_path17.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "skills");
|
|
16213
16213
|
}
|
|
16214
16214
|
function opencodeConfigSnapshot() {
|
|
16215
16215
|
const path2 = opencodeConfigPath();
|
|
16216
|
-
if (!(0,
|
|
16216
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return { path: path2, hasConfig: false, hasPluginField: false, parseOk: true };
|
|
16217
16217
|
try {
|
|
16218
|
-
const raw = (0,
|
|
16218
|
+
const raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
|
|
16219
16219
|
const parsed = JSON.parse(stripJsonc(raw));
|
|
16220
16220
|
const hasPluginField = Object.prototype.hasOwnProperty.call(parsed, "plugin");
|
|
16221
16221
|
const skillsPaths = Array.isArray(parsed.skills?.paths) ? parsed.skills.paths.filter((p) => typeof p === "string") : void 0;
|
|
@@ -16238,9 +16238,9 @@ function writeOpencodeConfigPlugin(snapshot) {
|
|
|
16238
16238
|
const plan = planOpencodeConfigWrite(snapshot.hasConfig ? snapshot.raw : void 0);
|
|
16239
16239
|
if (plan.action === "already") return true;
|
|
16240
16240
|
if (!plan.text || plan.action === "unsafe") return false;
|
|
16241
|
-
(0,
|
|
16242
|
-
if (snapshot.hasConfig) (0,
|
|
16243
|
-
(0,
|
|
16241
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(path2), { recursive: true });
|
|
16242
|
+
if (snapshot.hasConfig) (0, import_node_fs17.copyFileSync)(path2, `${path2}.bak`);
|
|
16243
|
+
(0, import_node_fs17.writeFileSync)(path2, plan.text, "utf8");
|
|
16244
16244
|
return true;
|
|
16245
16245
|
} catch {
|
|
16246
16246
|
return false;
|
|
@@ -16255,9 +16255,9 @@ function writeOpencodeSkillsPath(snapshot, skillsPath) {
|
|
|
16255
16255
|
const normalized = skillsPath.replace(/\\/g, "/");
|
|
16256
16256
|
if (!paths.some((p) => p.replace(/\\/g, "/") === normalized)) paths.push(skillsPath.replace(/\\/g, "/"));
|
|
16257
16257
|
parsed.skills = { ...skills, paths };
|
|
16258
|
-
(0,
|
|
16259
|
-
if (snapshot.hasConfig && (0,
|
|
16260
|
-
(0,
|
|
16258
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(snapshot.path), { recursive: true });
|
|
16259
|
+
if (snapshot.hasConfig && (0, import_node_fs17.existsSync)(snapshot.path)) (0, import_node_fs17.copyFileSync)(snapshot.path, `${snapshot.path}.bak`);
|
|
16260
|
+
(0, import_node_fs17.writeFileSync)(snapshot.path, `${JSON.stringify(parsed, null, 2)}
|
|
16261
16261
|
`, "utf8");
|
|
16262
16262
|
return true;
|
|
16263
16263
|
} catch {
|
|
@@ -16266,7 +16266,7 @@ function writeOpencodeSkillsPath(snapshot, skillsPath) {
|
|
|
16266
16266
|
}
|
|
16267
16267
|
function opencodeExistingCommands() {
|
|
16268
16268
|
try {
|
|
16269
|
-
return (0,
|
|
16269
|
+
return (0, import_node_fs17.readdirSync)(opencodeCommandsDir(), { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name.slice(0, -3).toLowerCase());
|
|
16270
16270
|
} catch {
|
|
16271
16271
|
return [];
|
|
16272
16272
|
}
|
|
@@ -16274,9 +16274,9 @@ function opencodeExistingCommands() {
|
|
|
16274
16274
|
function writeOpencodeCommandFiles() {
|
|
16275
16275
|
try {
|
|
16276
16276
|
const dir = opencodeCommandsDir();
|
|
16277
|
-
(0,
|
|
16277
|
+
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
16278
16278
|
for (const command of OPENCODE_WORKFLOW_COMMANDS) {
|
|
16279
|
-
(0,
|
|
16279
|
+
(0, import_node_fs17.writeFileSync)((0, import_node_path17.join)(dir, `${command}.md`), opencodeCommandMarkdown(command), "utf8");
|
|
16280
16280
|
}
|
|
16281
16281
|
return true;
|
|
16282
16282
|
} catch {
|
|
@@ -16285,12 +16285,12 @@ function writeOpencodeCommandFiles() {
|
|
|
16285
16285
|
}
|
|
16286
16286
|
function readOpencodeAdapterDiskVersion() {
|
|
16287
16287
|
const candidates = [
|
|
16288
|
-
(0,
|
|
16289
|
-
(0,
|
|
16288
|
+
(0, import_node_path17.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "package.json"),
|
|
16289
|
+
(0, import_node_path17.join)((0, import_node_os6.homedir)(), ".cache", "opencode", "node_modules", "@mutmutco", "opencode-mmi", "package.json")
|
|
16290
16290
|
];
|
|
16291
16291
|
for (const path2 of candidates) {
|
|
16292
16292
|
try {
|
|
16293
|
-
const parsed = JSON.parse((0,
|
|
16293
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
|
|
16294
16294
|
if (typeof parsed.version === "string" && parsed.version.trim()) return parsed.version.trim();
|
|
16295
16295
|
} catch {
|
|
16296
16296
|
continue;
|
|
@@ -16306,7 +16306,7 @@ async function forceInstallOpencodeMmiPlugins(snapshot, log) {
|
|
|
16306
16306
|
try {
|
|
16307
16307
|
const specs = opencodeMmiPluginSpecs(snapshot);
|
|
16308
16308
|
log(` \u21BB force-refreshing OpenCode MMI npm plugin(s): ${specs.join(", ")}\u2026`);
|
|
16309
|
-
(0,
|
|
16309
|
+
(0, import_node_fs17.mkdirSync)(opencodeConfigDir(), { recursive: true });
|
|
16310
16310
|
await runHostBin("npm", ["install", "--prefix", opencodeConfigDir(), "--force", ...specs], { timeout: NPM_UPDATE_TIMEOUT_MS });
|
|
16311
16311
|
return true;
|
|
16312
16312
|
} catch {
|
|
@@ -16321,30 +16321,30 @@ function opencodePluginVersionsForReport() {
|
|
|
16321
16321
|
}
|
|
16322
16322
|
function opencodeDesktopLogsRoot() {
|
|
16323
16323
|
if (process.platform === "win32") {
|
|
16324
|
-
const base = process.env.APPDATA || (0,
|
|
16325
|
-
return (0,
|
|
16324
|
+
const base = process.env.APPDATA || (0, import_node_path17.join)((0, import_node_os6.homedir)(), "AppData", "Roaming");
|
|
16325
|
+
return (0, import_node_path17.join)(base, "ai.opencode.desktop", "logs");
|
|
16326
16326
|
}
|
|
16327
16327
|
if (process.platform === "darwin") {
|
|
16328
|
-
return (0,
|
|
16328
|
+
return (0, import_node_path17.join)((0, import_node_os6.homedir)(), "Library", "Application Support", "ai.opencode.desktop", "logs");
|
|
16329
16329
|
}
|
|
16330
|
-
return (0,
|
|
16330
|
+
return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".config", "ai.opencode.desktop", "logs");
|
|
16331
16331
|
}
|
|
16332
16332
|
function opencodeDesktopBootstrapSnapshot() {
|
|
16333
16333
|
const root = opencodeDesktopLogsRoot();
|
|
16334
16334
|
try {
|
|
16335
|
-
const sessionDirs = (0,
|
|
16335
|
+
const sessionDirs = (0, import_node_fs17.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => (0, import_node_path17.join)(root, entry.name)).sort((a, b) => (0, import_node_fs17.statSync)(b).mtimeMs - (0, import_node_fs17.statSync)(a).mtimeMs);
|
|
16336
16336
|
const newest = sessionDirs[0];
|
|
16337
16337
|
if (!newest) return [];
|
|
16338
|
-
const logPath = (0,
|
|
16339
|
-
const text = (0,
|
|
16340
|
-
return opencodeAgentDirectoriesFromLog(text).filter((directory) => !(0,
|
|
16338
|
+
const logPath = (0, import_node_path17.join)(newest, "renderer.log");
|
|
16339
|
+
const text = (0, import_node_fs17.readFileSync)(logPath, "utf8");
|
|
16340
|
+
return opencodeAgentDirectoriesFromLog(text).filter((directory) => !(0, import_node_fs17.existsSync)(directory)).map((directory) => ({ directory, logPath }));
|
|
16341
16341
|
} catch {
|
|
16342
16342
|
return [];
|
|
16343
16343
|
}
|
|
16344
16344
|
}
|
|
16345
16345
|
function opencodeLegacyConfigSnapshot() {
|
|
16346
|
-
const legacyPath = (0,
|
|
16347
|
-
if (!(0,
|
|
16346
|
+
const legacyPath = (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".opencode", "opencode.json");
|
|
16347
|
+
if (!(0, import_node_fs17.existsSync)(legacyPath)) return {};
|
|
16348
16348
|
const content = readTextFile(legacyPath);
|
|
16349
16349
|
if (content == null) return {};
|
|
16350
16350
|
const plugins = parseOpencodeLegacyConfigPlugins(content);
|
|
@@ -16356,45 +16356,45 @@ function opencodeLegacyConfigSnapshot() {
|
|
|
16356
16356
|
function quarantineOpencodeLegacyConfig(legacyPath) {
|
|
16357
16357
|
try {
|
|
16358
16358
|
const backupPath = `${legacyPath}.bak`;
|
|
16359
|
-
if ((0,
|
|
16360
|
-
(0,
|
|
16359
|
+
if ((0, import_node_fs17.existsSync)(backupPath)) return false;
|
|
16360
|
+
(0, import_node_fs17.renameSync)(legacyPath, backupPath);
|
|
16361
16361
|
return true;
|
|
16362
16362
|
} catch {
|
|
16363
16363
|
return false;
|
|
16364
16364
|
}
|
|
16365
16365
|
}
|
|
16366
16366
|
function cursorPluginCacheRoot() {
|
|
16367
|
-
return (0,
|
|
16367
|
+
return (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".cursor", "plugins", "cache", "mutmutco", "mmi");
|
|
16368
16368
|
}
|
|
16369
16369
|
function cursorPluginCachePinSnapshots() {
|
|
16370
16370
|
const root = cursorPluginCacheRoot();
|
|
16371
16371
|
try {
|
|
16372
|
-
return (0,
|
|
16373
|
-
const path2 = (0,
|
|
16374
|
-
const pluginJson = (0,
|
|
16375
|
-
const hooksJson = (0,
|
|
16376
|
-
const cliBundle = (0,
|
|
16377
|
-
const cursorHook = (0,
|
|
16372
|
+
return (0, import_node_fs17.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => {
|
|
16373
|
+
const path2 = (0, import_node_path17.join)(root, entry.name);
|
|
16374
|
+
const pluginJson = (0, import_node_path17.join)(path2, ".cursor-plugin", "plugin.json");
|
|
16375
|
+
const hooksJson = (0, import_node_path17.join)(path2, "hooks", "hooks.json");
|
|
16376
|
+
const cliBundle = (0, import_node_path17.join)(path2, "cli", "dist", "index.cjs");
|
|
16377
|
+
const cursorHook = (0, import_node_path17.join)(path2, "scripts", "cursor-hook.mjs");
|
|
16378
16378
|
let version;
|
|
16379
16379
|
try {
|
|
16380
|
-
const raw = JSON.parse((0,
|
|
16380
|
+
const raw = JSON.parse((0, import_node_fs17.readFileSync)(pluginJson, "utf8"));
|
|
16381
16381
|
version = typeof raw.version === "string" ? raw.version : void 0;
|
|
16382
16382
|
} catch {
|
|
16383
16383
|
version = void 0;
|
|
16384
16384
|
}
|
|
16385
16385
|
let isEmpty = true;
|
|
16386
16386
|
try {
|
|
16387
|
-
isEmpty = (0,
|
|
16387
|
+
isEmpty = (0, import_node_fs17.readdirSync)(path2).length === 0;
|
|
16388
16388
|
} catch {
|
|
16389
16389
|
isEmpty = true;
|
|
16390
16390
|
}
|
|
16391
16391
|
return {
|
|
16392
16392
|
name: entry.name,
|
|
16393
16393
|
path: path2,
|
|
16394
|
-
hasPluginJson: (0,
|
|
16395
|
-
hasHooksJson: (0,
|
|
16396
|
-
hasCliBundle: (0,
|
|
16397
|
-
hasCursorHookScript: (0,
|
|
16394
|
+
hasPluginJson: (0, import_node_fs17.existsSync)(pluginJson),
|
|
16395
|
+
hasHooksJson: (0, import_node_fs17.existsSync)(hooksJson),
|
|
16396
|
+
hasCliBundle: (0, import_node_fs17.existsSync)(cliBundle),
|
|
16397
|
+
hasCursorHookScript: (0, import_node_fs17.existsSync)(cursorHook),
|
|
16398
16398
|
isEmpty,
|
|
16399
16399
|
version
|
|
16400
16400
|
};
|
|
@@ -16404,19 +16404,19 @@ function cursorPluginCachePinSnapshots() {
|
|
|
16404
16404
|
}
|
|
16405
16405
|
}
|
|
16406
16406
|
function hubCheckoutForCursorSeed() {
|
|
16407
|
-
const manifest = (0,
|
|
16408
|
-
return (0,
|
|
16407
|
+
const manifest = (0, import_node_path17.join)(process.cwd(), "plugins", "mmi", ".cursor-plugin", "plugin.json");
|
|
16408
|
+
return (0, import_node_fs17.existsSync)(manifest) ? process.cwd() : void 0;
|
|
16409
16409
|
}
|
|
16410
16410
|
function mmiPluginCacheRootSnapshots() {
|
|
16411
16411
|
const roots = [
|
|
16412
|
-
{ surface: "claude", root: (0,
|
|
16413
|
-
{ surface: "codex", root: (0,
|
|
16412
|
+
{ surface: "claude", root: (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".claude", "plugins", "cache", "mutmutco", "mmi") },
|
|
16413
|
+
{ surface: "codex", root: (0, import_node_path17.join)((0, import_node_os6.homedir)(), ".codex", "plugins", "cache", "mutmutco", "mmi") }
|
|
16414
16414
|
];
|
|
16415
16415
|
return roots.flatMap(({ surface, root }) => {
|
|
16416
16416
|
try {
|
|
16417
|
-
const entries = (0,
|
|
16417
|
+
const entries = (0, import_node_fs17.readdirSync)(root, { withFileTypes: true }).map((entry) => ({
|
|
16418
16418
|
name: entry.name,
|
|
16419
|
-
path: (0,
|
|
16419
|
+
path: (0, import_node_path17.join)(root, entry.name),
|
|
16420
16420
|
isDirectory: entry.isDirectory()
|
|
16421
16421
|
}));
|
|
16422
16422
|
return [{ surface, root, entries }];
|
|
@@ -16427,7 +16427,7 @@ function mmiPluginCacheRootSnapshots() {
|
|
|
16427
16427
|
}
|
|
16428
16428
|
function hasNestedMmiChild(versionDir) {
|
|
16429
16429
|
try {
|
|
16430
|
-
return (0,
|
|
16430
|
+
return (0, import_node_fs17.statSync)((0, import_node_path17.join)(versionDir, "mmi")).isDirectory();
|
|
16431
16431
|
} catch {
|
|
16432
16432
|
return false;
|
|
16433
16433
|
}
|
|
@@ -16438,10 +16438,10 @@ function nestedPluginTreeSnapshot() {
|
|
|
16438
16438
|
);
|
|
16439
16439
|
}
|
|
16440
16440
|
function uniqueQuarantineTarget(path2) {
|
|
16441
|
-
if (!(0,
|
|
16441
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return path2;
|
|
16442
16442
|
for (let i = 1; i < 100; i += 1) {
|
|
16443
16443
|
const candidate = `${path2}-${i}`;
|
|
16444
|
-
if (!(0,
|
|
16444
|
+
if (!(0, import_node_fs17.existsSync)(candidate)) return candidate;
|
|
16445
16445
|
}
|
|
16446
16446
|
return `${path2}-${Date.now()}`;
|
|
16447
16447
|
}
|
|
@@ -16450,10 +16450,10 @@ function quarantinePluginCacheDirs(plan) {
|
|
|
16450
16450
|
const failed = [];
|
|
16451
16451
|
for (const move of plan) {
|
|
16452
16452
|
try {
|
|
16453
|
-
if (!(0,
|
|
16453
|
+
if (!(0, import_node_fs17.existsSync)(move.from)) continue;
|
|
16454
16454
|
const target = uniqueQuarantineTarget(move.to);
|
|
16455
|
-
(0,
|
|
16456
|
-
(0,
|
|
16455
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(target), { recursive: true });
|
|
16456
|
+
(0, import_node_fs17.renameSync)(move.from, target);
|
|
16457
16457
|
moved += 1;
|
|
16458
16458
|
} catch {
|
|
16459
16459
|
failed.push(move);
|
|
@@ -16472,23 +16472,23 @@ async function robocopyMirrorEmpty(emptyDir, target) {
|
|
|
16472
16472
|
}
|
|
16473
16473
|
async function clearNestedPluginTreeDir(targetPath) {
|
|
16474
16474
|
try {
|
|
16475
|
-
if (!(0,
|
|
16475
|
+
if (!(0, import_node_fs17.existsSync)(targetPath)) return true;
|
|
16476
16476
|
if (isWin) {
|
|
16477
|
-
const emptyDir = (0,
|
|
16478
|
-
(0,
|
|
16477
|
+
const emptyDir = (0, import_node_path17.join)((0, import_node_os6.tmpdir)(), `mmi-empty-${Date.now()}`);
|
|
16478
|
+
(0, import_node_fs17.mkdirSync)(emptyDir, { recursive: true });
|
|
16479
16479
|
try {
|
|
16480
16480
|
await robocopyMirrorEmpty(emptyDir, targetPath);
|
|
16481
|
-
(0,
|
|
16481
|
+
(0, import_node_fs17.rmSync)(targetPath, { recursive: true, force: true });
|
|
16482
16482
|
} finally {
|
|
16483
16483
|
try {
|
|
16484
|
-
(0,
|
|
16484
|
+
(0, import_node_fs17.rmSync)(emptyDir, { recursive: true, force: true });
|
|
16485
16485
|
} catch {
|
|
16486
16486
|
}
|
|
16487
16487
|
}
|
|
16488
|
-
return !(0,
|
|
16488
|
+
return !(0, import_node_fs17.existsSync)(targetPath);
|
|
16489
16489
|
}
|
|
16490
|
-
(0,
|
|
16491
|
-
return !(0,
|
|
16490
|
+
(0, import_node_fs17.rmSync)(targetPath, { recursive: true, force: true });
|
|
16491
|
+
return !(0, import_node_fs17.existsSync)(targetPath);
|
|
16492
16492
|
} catch {
|
|
16493
16493
|
return false;
|
|
16494
16494
|
}
|
|
@@ -16501,23 +16501,23 @@ async function applyNestedPluginTreeCleanup(paths, log) {
|
|
|
16501
16501
|
}
|
|
16502
16502
|
return true;
|
|
16503
16503
|
}
|
|
16504
|
-
var gitignorePath = () => (0,
|
|
16504
|
+
var gitignorePath = () => (0, import_node_path17.join)(process.cwd(), ".gitignore");
|
|
16505
16505
|
function readTextFile(path2) {
|
|
16506
16506
|
try {
|
|
16507
|
-
if (!(0,
|
|
16508
|
-
return (0,
|
|
16507
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
16508
|
+
return (0, import_node_fs17.readFileSync)(path2, "utf8");
|
|
16509
16509
|
} catch {
|
|
16510
16510
|
return null;
|
|
16511
16511
|
}
|
|
16512
16512
|
}
|
|
16513
16513
|
function playwrightMcpConfigSnapshots() {
|
|
16514
16514
|
const cwd = process.cwd();
|
|
16515
|
-
const home = (0,
|
|
16515
|
+
const home = (0, import_node_os6.homedir)();
|
|
16516
16516
|
const candidates = [
|
|
16517
|
-
(0,
|
|
16518
|
-
(0,
|
|
16519
|
-
(0,
|
|
16520
|
-
(0,
|
|
16517
|
+
(0, import_node_path17.join)(cwd, ".mcp.json"),
|
|
16518
|
+
(0, import_node_path17.join)(cwd, ".cursor", "mcp.json"),
|
|
16519
|
+
(0, import_node_path17.join)(home, ".cursor", "mcp.json"),
|
|
16520
|
+
(0, import_node_path17.join)(home, ".codex", "config.toml")
|
|
16521
16521
|
];
|
|
16522
16522
|
const out = [];
|
|
16523
16523
|
for (const path2 of candidates) {
|
|
@@ -16530,7 +16530,7 @@ function strayBrowserArtifactPaths() {
|
|
|
16530
16530
|
const cwd = process.cwd();
|
|
16531
16531
|
return STRAY_BROWSER_ARTIFACT_DIRS.filter((rel) => {
|
|
16532
16532
|
try {
|
|
16533
|
-
return (0,
|
|
16533
|
+
return (0, import_node_fs17.existsSync)((0, import_node_path17.join)(cwd, rel));
|
|
16534
16534
|
} catch {
|
|
16535
16535
|
return false;
|
|
16536
16536
|
}
|
|
@@ -16538,14 +16538,14 @@ function strayBrowserArtifactPaths() {
|
|
|
16538
16538
|
}
|
|
16539
16539
|
function readGitignore() {
|
|
16540
16540
|
try {
|
|
16541
|
-
return (0,
|
|
16541
|
+
return (0, import_node_fs17.readFileSync)(gitignorePath(), "utf8");
|
|
16542
16542
|
} catch {
|
|
16543
16543
|
return null;
|
|
16544
16544
|
}
|
|
16545
16545
|
}
|
|
16546
16546
|
function writeGitignore(content) {
|
|
16547
16547
|
try {
|
|
16548
|
-
(0,
|
|
16548
|
+
(0, import_node_fs17.writeFileSync)(gitignorePath(), content, "utf8");
|
|
16549
16549
|
return true;
|
|
16550
16550
|
} catch {
|
|
16551
16551
|
return false;
|
|
@@ -16587,7 +16587,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
|
|
|
16587
16587
|
const semverPrefix = /^\d+\.\d+\.\d+/;
|
|
16588
16588
|
const isBehind = (installed2, released) => Boolean(installed2 && released && semverPrefix.test(installed2) && semverPrefix.test(released) && compareVersions(installed2, released) < 0);
|
|
16589
16589
|
const opencodeAdapterStale = isBehind(opencodeInstalledVersionForDoctor(), releasedVersion);
|
|
16590
|
-
const cursorCacheStale = (0,
|
|
16590
|
+
const cursorCacheStale = (0, import_node_fs17.existsSync)(cursorPluginCacheRoot()) && (cursorPluginCachePinSnapshots() ?? []).some((p) => isBehind(p.version, releasedVersion));
|
|
16591
16591
|
const healPlan = doctorHealPlan({
|
|
16592
16592
|
isOrgRepo,
|
|
16593
16593
|
surface,
|
|
@@ -16622,7 +16622,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
|
|
|
16622
16622
|
let onPath = pathProbe;
|
|
16623
16623
|
if (!onPath) {
|
|
16624
16624
|
const root = process.env.CLAUDE_PLUGIN_ROOT;
|
|
16625
|
-
if (root && (0,
|
|
16625
|
+
if (root && (0, import_node_fs17.existsSync)(`${root}/bin/mmi-cli${isWin ? ".cmd" : ""}`)) onPath = true;
|
|
16626
16626
|
}
|
|
16627
16627
|
checks.push({ ok: onPath, label: "mmi-cli on PATH", fix: "auto-provisioned at session start \u2014 reopen the session, or install the MMI plugin" });
|
|
16628
16628
|
const reloadHint = reloadAction(surface);
|
|
@@ -16991,7 +16991,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
|
|
|
16991
16991
|
isOrgRepo,
|
|
16992
16992
|
surface,
|
|
16993
16993
|
cacheRoot: cursorCacheRoot,
|
|
16994
|
-
cacheRootExists: (0,
|
|
16994
|
+
cacheRootExists: (0, import_node_fs17.existsSync)(cursorCacheRoot),
|
|
16995
16995
|
pins: cursorPins,
|
|
16996
16996
|
hubCheckout: hubCheckoutForCursorSeed(),
|
|
16997
16997
|
releasedVersion
|
|
@@ -17002,7 +17002,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
|
|
|
17002
17002
|
releasedVersion,
|
|
17003
17003
|
hubCheckout: hubCheckoutForCursorSeed(),
|
|
17004
17004
|
execFileP: execFileP2,
|
|
17005
|
-
mkdtemp: (prefix) => (0, import_promises3.mkdtemp)((0,
|
|
17005
|
+
mkdtemp: (prefix) => (0, import_promises3.mkdtemp)((0, import_node_path17.join)((0, import_node_os6.tmpdir)(), prefix)),
|
|
17006
17006
|
log: (m) => io.err(m)
|
|
17007
17007
|
});
|
|
17008
17008
|
if (seeded) {
|
|
@@ -17011,7 +17011,7 @@ async function runDoctor(opts, io = consoleIo, readOrigin) {
|
|
|
17011
17011
|
isOrgRepo,
|
|
17012
17012
|
surface,
|
|
17013
17013
|
cacheRoot: cursorCacheRoot,
|
|
17014
|
-
cacheRootExists: (0,
|
|
17014
|
+
cacheRootExists: (0, import_node_fs17.existsSync)(cursorCacheRoot),
|
|
17015
17015
|
pins: cursorPins,
|
|
17016
17016
|
hubCheckout: hubCheckoutForCursorSeed(),
|
|
17017
17017
|
releasedVersion
|
|
@@ -17150,23 +17150,23 @@ function mergeGuardHook(settings) {
|
|
|
17150
17150
|
next.hooks = hooks;
|
|
17151
17151
|
return next;
|
|
17152
17152
|
}
|
|
17153
|
-
var userScopeSettingsPath = (surface = detectSurface(process.env)) => (0,
|
|
17153
|
+
var userScopeSettingsPath = (surface = detectSurface(process.env)) => (0, import_node_path17.join)((0, import_node_os6.homedir)(), surface === "codex" ? ".codex" : ".claude", "settings.json");
|
|
17154
17154
|
function ensureUserScopeGuardHook(opts = {}) {
|
|
17155
17155
|
const path2 = opts.settingsPath ?? userScopeSettingsPath();
|
|
17156
17156
|
try {
|
|
17157
17157
|
let current = null;
|
|
17158
|
-
if ((0,
|
|
17158
|
+
if ((0, import_node_fs17.existsSync)(path2)) {
|
|
17159
17159
|
try {
|
|
17160
|
-
current = JSON.parse((0,
|
|
17160
|
+
current = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
|
|
17161
17161
|
} catch {
|
|
17162
17162
|
return "failed";
|
|
17163
17163
|
}
|
|
17164
17164
|
}
|
|
17165
17165
|
if (settingsHasGuardHook(current)) return "already";
|
|
17166
17166
|
const merged = mergeGuardHook(current);
|
|
17167
|
-
(0,
|
|
17168
|
-
if ((0,
|
|
17169
|
-
(0,
|
|
17167
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(path2), { recursive: true });
|
|
17168
|
+
if ((0, import_node_fs17.existsSync)(path2)) (0, import_node_fs17.copyFileSync)(path2, `${path2}.bak`);
|
|
17169
|
+
(0, import_node_fs17.writeFileSync)(path2, `${JSON.stringify(merged, null, 2)}
|
|
17170
17170
|
`, "utf8");
|
|
17171
17171
|
return "written";
|
|
17172
17172
|
} catch {
|
|
@@ -17301,7 +17301,7 @@ async function applyGcPlan(plan, remote) {
|
|
|
17301
17301
|
cleanupBranch: (branch, expectedHeadOid) => cleanupPrMergeLocalBranch(branch.branch, {
|
|
17302
17302
|
beforeWorktrees,
|
|
17303
17303
|
startingPath: branch.worktreePath,
|
|
17304
|
-
pathExists: (p) => (0,
|
|
17304
|
+
pathExists: (p) => (0, import_node_fs18.existsSync)(p),
|
|
17305
17305
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
17306
17306
|
teardownWorktreeStage,
|
|
17307
17307
|
deferredStore,
|
|
@@ -17324,7 +17324,7 @@ async function applyGcPlan(plan, remote) {
|
|
|
17324
17324
|
for (const wt of plan.worktreeDirs) {
|
|
17325
17325
|
try {
|
|
17326
17326
|
const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
|
|
17327
|
-
realpath: (path2) => (0,
|
|
17327
|
+
realpath: (path2) => (0, import_node_fs18.realpathSync)(path2)
|
|
17328
17328
|
});
|
|
17329
17329
|
if (!cleanupTarget.ok) {
|
|
17330
17330
|
result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
|
|
@@ -17404,10 +17404,10 @@ async function runRulesSync(opts, io = consoleIo) {
|
|
|
17404
17404
|
for (const entry of fetched) {
|
|
17405
17405
|
if ("error" in entry) continue;
|
|
17406
17406
|
const { file, source } = entry;
|
|
17407
|
-
const current = (0,
|
|
17407
|
+
const current = (0, import_node_fs18.existsSync)(file) ? await (0, import_promises4.readFile)(file, "utf8") : null;
|
|
17408
17408
|
if (needsUpdate(source, current)) {
|
|
17409
17409
|
const slash = file.lastIndexOf("/");
|
|
17410
|
-
if (slash > 0) (0,
|
|
17410
|
+
if (slash > 0) (0, import_node_fs18.mkdirSync)(file.slice(0, slash), { recursive: true });
|
|
17411
17411
|
await (0, import_promises4.writeFile)(file, normalizeEol(source), "utf8");
|
|
17412
17412
|
changed++;
|
|
17413
17413
|
if (!opts.quiet) io.log(`mmi-cli rules: updated ${file}`);
|
|
@@ -17421,13 +17421,13 @@ rules.command("sync").option("--quiet", "stay silent unless something changed or
|
|
|
17421
17421
|
if (!await runRulesSync(opts)) process.exitCode = 1;
|
|
17422
17422
|
});
|
|
17423
17423
|
rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
|
|
17424
|
-
const path2 = (0,
|
|
17425
|
-
const current = (0,
|
|
17424
|
+
const path2 = (0, import_node_path18.join)(process.cwd(), ".gitignore");
|
|
17425
|
+
const current = (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
|
|
17426
17426
|
const plan = planManagedGitignore(current);
|
|
17427
17427
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
17428
17428
|
if (opts.write) {
|
|
17429
17429
|
if (plan.changed) {
|
|
17430
|
-
(0,
|
|
17430
|
+
(0, import_node_fs18.writeFileSync)(path2, plan.content, "utf8");
|
|
17431
17431
|
console.log(`mmi-cli rules gitignore: updated .gitignore (${drift})`);
|
|
17432
17432
|
} else {
|
|
17433
17433
|
console.log("mmi-cli rules gitignore: up to date");
|
|
@@ -17454,7 +17454,7 @@ async function runDocsSync(opts, io = consoleIo) {
|
|
|
17454
17454
|
return null;
|
|
17455
17455
|
}
|
|
17456
17456
|
},
|
|
17457
|
-
localContent: async (f) => (0,
|
|
17457
|
+
localContent: async (f) => (0, import_node_fs18.existsSync)(f) ? await (0, import_promises4.readFile)(f, "utf8") : null,
|
|
17458
17458
|
writeDoc: async (f, c) => {
|
|
17459
17459
|
await (0, import_promises4.writeFile)(f, c, "utf8");
|
|
17460
17460
|
}
|
|
@@ -17464,7 +17464,7 @@ async function runDocsSync(opts, io = consoleIo) {
|
|
|
17464
17464
|
if (!opts.quiet && result.updated.length === 0 && result.skippedDirty.length === 0) io.log("mmi-cli docs: up to date");
|
|
17465
17465
|
}
|
|
17466
17466
|
var docs = program2.command("docs").description("repo-owned authoritative docs");
|
|
17467
|
-
docs.command("sync").option("--quiet", "stay silent unless something changed or errored").description("refresh README.md / architecture.md from the repo default branch
|
|
17467
|
+
docs.command("sync").option("--quiet", "stay silent unless something changed or errored").description("refresh README.md / architecture.md from the repo default branch; never clobbers uncommitted edits").action((opts) => runDocsSync(opts));
|
|
17468
17468
|
program2.command("commands").description("print the command manifest \u2014 every subcommand + its flags (ground against this instead of guessing)").option("--json", "machine-readable JSON: { name, version, tree, index } \u2014 index is a flat list of every leaf command path").action((o) => {
|
|
17469
17469
|
const manifest = buildCommandManifest(program2);
|
|
17470
17470
|
consoleIo.log(o.json ? JSON.stringify(manifest, null, 2) : formatManifestHuman(manifest));
|
|
@@ -17482,21 +17482,13 @@ program2.command("whoami").description('resolve the logged-in human: {login, sou
|
|
|
17482
17482
|
await runWhoami();
|
|
17483
17483
|
});
|
|
17484
17484
|
var wave = program2.command("wave").description("multi-worktree visibility and serial merge train");
|
|
17485
|
-
wave.command("status").description("worktrees, open PRs, local stages
|
|
17485
|
+
wave.command("status").description("worktrees, open PRs, and local stages at a glance (#1927)").option("--json", "machine-readable output").action(async (o) => {
|
|
17486
17486
|
try {
|
|
17487
|
-
const cfg = await loadConfig();
|
|
17488
|
-
const project2 = cfg.project || (await gitOut(["remote", "get-url", "origin"])).replace(/\.git$/, "").split("/").pop() || "-";
|
|
17489
17487
|
const rows = await collectWaveStatus({
|
|
17490
17488
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
17491
17489
|
listOpenPrs: async () => {
|
|
17492
17490
|
const { stdout } = await execFileP2("gh", ["pr", "list", "--state", "open", "--limit", "100", "--json", "number,headRefName,state,url"], { timeout: GC_GH_TIMEOUT_MS2 });
|
|
17493
17491
|
return JSON.parse(stdout || "[]");
|
|
17494
|
-
},
|
|
17495
|
-
fetchSagaHeadText: async (branch) => {
|
|
17496
|
-
if (!cfg.sagaApiUrl) return void 0;
|
|
17497
|
-
const qs = new URLSearchParams({ project: project2, branch }).toString();
|
|
17498
|
-
const res = await fetchWithRetry(fetch, `${cfg.sagaApiUrl}/saga/head?${qs}`, { headers: await hubHeaders() }, { attempts: 1, timeoutMs: 3e3 });
|
|
17499
|
-
return res.ok ? await res.text() : void 0;
|
|
17500
17492
|
}
|
|
17501
17493
|
});
|
|
17502
17494
|
if (o.json) return console.log(JSON.stringify({ worktrees: rows }, null, 2));
|
|
@@ -17601,7 +17593,7 @@ function runWorktreeInstall(command, cwd, quiet) {
|
|
|
17601
17593
|
const [bin, ...args] = command.split(" ");
|
|
17602
17594
|
const file = isWin2 ? "cmd.exe" : bin;
|
|
17603
17595
|
const spawnArgs = isWin2 ? ["/c", bin, ...args] : args;
|
|
17604
|
-
return new Promise((
|
|
17596
|
+
return new Promise((resolve6, reject) => {
|
|
17605
17597
|
const child = (0, import_node_child_process11.spawn)(file, spawnArgs, { cwd, stdio: quiet ? "ignore" : "inherit", windowsHide: true });
|
|
17606
17598
|
const timer = setTimeout(() => {
|
|
17607
17599
|
try {
|
|
@@ -17616,7 +17608,7 @@ function runWorktreeInstall(command, cwd, quiet) {
|
|
|
17616
17608
|
});
|
|
17617
17609
|
child.on("exit", (code) => {
|
|
17618
17610
|
clearTimeout(timer);
|
|
17619
|
-
if (code === 0)
|
|
17611
|
+
if (code === 0) resolve6();
|
|
17620
17612
|
else reject(new Error(`${command} exited ${code} in ${cwd}`));
|
|
17621
17613
|
});
|
|
17622
17614
|
});
|
|
@@ -17624,7 +17616,7 @@ function runWorktreeInstall(command, cwd, quiet) {
|
|
|
17624
17616
|
async function primaryCheckoutRoot(worktreeRoot) {
|
|
17625
17617
|
try {
|
|
17626
17618
|
const out = (await execFileP2("git", ["-C", worktreeRoot, "rev-parse", "--path-format=absolute", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
|
|
17627
|
-
return out ? (0,
|
|
17619
|
+
return out ? (0, import_node_path18.dirname)(out) : void 0;
|
|
17628
17620
|
} catch {
|
|
17629
17621
|
return void 0;
|
|
17630
17622
|
}
|
|
@@ -17637,28 +17629,28 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
17637
17629
|
};
|
|
17638
17630
|
}
|
|
17639
17631
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
17640
|
-
const lockPath = (
|
|
17632
|
+
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
17641
17633
|
const take = () => {
|
|
17642
|
-
const fd = (0,
|
|
17634
|
+
const fd = (0, import_node_fs18.openSync)(lockPath, "wx");
|
|
17643
17635
|
try {
|
|
17644
|
-
(0,
|
|
17636
|
+
(0, import_node_fs18.writeSync)(fd, String(Date.now()));
|
|
17645
17637
|
} finally {
|
|
17646
|
-
(0,
|
|
17638
|
+
(0, import_node_fs18.closeSync)(fd);
|
|
17647
17639
|
}
|
|
17648
17640
|
return () => {
|
|
17649
17641
|
try {
|
|
17650
|
-
(0,
|
|
17642
|
+
(0, import_node_fs18.rmSync)(lockPath, { force: true });
|
|
17651
17643
|
} catch {
|
|
17652
17644
|
}
|
|
17653
17645
|
};
|
|
17654
17646
|
};
|
|
17655
17647
|
try {
|
|
17656
|
-
(0,
|
|
17648
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path18.dirname)(lockPath), { recursive: true });
|
|
17657
17649
|
return take();
|
|
17658
17650
|
} catch {
|
|
17659
17651
|
try {
|
|
17660
|
-
if (Date.now() - (0,
|
|
17661
|
-
(0,
|
|
17652
|
+
if (Date.now() - (0, import_node_fs18.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
|
|
17653
|
+
(0, import_node_fs18.rmSync)(lockPath, { force: true });
|
|
17662
17654
|
return take();
|
|
17663
17655
|
}
|
|
17664
17656
|
} catch {
|
|
@@ -17890,8 +17882,8 @@ tenant.command("sweep-rc").description("discover (and optionally retire) running
|
|
|
17890
17882
|
async function resolveDnsBounded(host, timeoutMs = 3e3) {
|
|
17891
17883
|
const { lookup } = await import("node:dns/promises");
|
|
17892
17884
|
const probe = lookup(host).then(() => true).catch((e) => dnsErrorToResolution(e?.code));
|
|
17893
|
-
const timeout = new Promise((
|
|
17894
|
-
setTimeout(() =>
|
|
17885
|
+
const timeout = new Promise((resolve6) => {
|
|
17886
|
+
setTimeout(() => resolve6(void 0), timeoutMs).unref?.();
|
|
17895
17887
|
});
|
|
17896
17888
|
return Promise.race([probe, timeout]);
|
|
17897
17889
|
}
|
|
@@ -18153,7 +18145,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
18153
18145
|
const vars = rawValues("--var");
|
|
18154
18146
|
if (o.secretsFile) {
|
|
18155
18147
|
try {
|
|
18156
|
-
vars.push(`secrets=${(0,
|
|
18148
|
+
vars.push(`secrets=${(0, import_node_fs18.readFileSync)(o.secretsFile, "utf8")}`);
|
|
18157
18149
|
} catch (e) {
|
|
18158
18150
|
return fail(`project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
18159
18151
|
}
|
|
@@ -18693,9 +18685,9 @@ pr.command("create").description("create a PR and print {number,url} JSON").opti
|
|
|
18693
18685
|
console.log(JSON.stringify(created));
|
|
18694
18686
|
});
|
|
18695
18687
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
18696
|
-
const wfDir = (0,
|
|
18697
|
-
if (!(0,
|
|
18698
|
-
return (0,
|
|
18688
|
+
const wfDir = (0, import_node_path18.join)(cwd, ".github", "workflows");
|
|
18689
|
+
if (!(0, import_node_fs18.existsSync)(wfDir)) return [];
|
|
18690
|
+
return (0, import_node_fs18.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).map((name) => `.github/workflows/${name}`);
|
|
18699
18691
|
}
|
|
18700
18692
|
async function resolveMergeCiPolicyForCheckout(repoOpt) {
|
|
18701
18693
|
const repo = repoOpt ?? await resolveRepo();
|
|
@@ -18714,7 +18706,7 @@ function ciAuditDeps() {
|
|
|
18714
18706
|
// Continuous CI delivery (#1550): the gate re-seed renders from the Hub's on-disk seed templates. The
|
|
18715
18707
|
// reconcile runs IN the Hub checkout, so this is local-file I/O (no network fetch). Path is relative to
|
|
18716
18708
|
// the repo root (e.g. skills/bootstrap/seeds/gate.template.yml).
|
|
18717
|
-
readSeedFile: (path2) => (0,
|
|
18709
|
+
readSeedFile: (path2) => (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null
|
|
18718
18710
|
};
|
|
18719
18711
|
}
|
|
18720
18712
|
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) => {
|
|
@@ -18744,7 +18736,7 @@ pr.command("checks-wait <number>").description("bounded wait for PR checks; skip
|
|
|
18744
18736
|
const result = await waitForPrChecks({
|
|
18745
18737
|
resolvePolicy: () => resolveMergeCiPolicyForCheckout(o.repo),
|
|
18746
18738
|
pollChecks: () => pollGhPrChecks(number, repoArgs),
|
|
18747
|
-
sleep: (ms) => new Promise((
|
|
18739
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms))
|
|
18748
18740
|
});
|
|
18749
18741
|
if (o.json) printLine(JSON.stringify(result));
|
|
18750
18742
|
else printLine(`pr checks-wait: ${result.status}${result.reason ? ` \u2014 ${result.reason}` : ""}${result.detail ? ` (${result.detail})` : ""}`);
|
|
@@ -18771,7 +18763,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
|
|
|
18771
18763
|
waitForChecks: (prNumber, repo) => waitForPrChecks({
|
|
18772
18764
|
resolvePolicy: () => resolveRepoMergeCiPolicy(repo, ciAuditDeps()),
|
|
18773
18765
|
pollChecks: () => pollGhPrChecks(prNumber, repo ? ["--repo", repo] : []),
|
|
18774
|
-
sleep: (ms) => new Promise((
|
|
18766
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms))
|
|
18775
18767
|
}),
|
|
18776
18768
|
mergeAuto: async (prNumber, repo) => {
|
|
18777
18769
|
const args = repo ? ["--repo", repo] : [];
|
|
@@ -18807,7 +18799,7 @@ pr.command("land <number>").description("agent merge path (#1440): train probe \
|
|
|
18807
18799
|
while (Date.now() < deadlineMs) {
|
|
18808
18800
|
const stateRead = await readGhPrStateWithRetry(async () => (await execFileP2("gh", ["pr", "view", prNumber, ...args, "--json", "state", "--jq", ".state"], { timeout: GC_GH_TIMEOUT_MS2 })).stdout, { retries: 2, delayMs: 1e3 });
|
|
18809
18801
|
if (stateRead.ok && stateRead.state === "MERGED") return true;
|
|
18810
|
-
await new Promise((
|
|
18802
|
+
await new Promise((resolve6) => setTimeout(resolve6, PR_LAND_POLL_MS));
|
|
18811
18803
|
}
|
|
18812
18804
|
return false;
|
|
18813
18805
|
}
|
|
@@ -18867,7 +18859,7 @@ async function createDeferredWorktreeStore() {
|
|
|
18867
18859
|
},
|
|
18868
18860
|
write: async (entries) => {
|
|
18869
18861
|
try {
|
|
18870
|
-
await (0, import_promises4.mkdir)((0,
|
|
18862
|
+
await (0, import_promises4.mkdir)((0, import_node_path18.dirname)(registryPath), { recursive: true });
|
|
18871
18863
|
await (0, import_promises4.writeFile)(registryPath, serializeDeferredWorktrees(entries), "utf8");
|
|
18872
18864
|
} catch {
|
|
18873
18865
|
}
|
|
@@ -18881,13 +18873,13 @@ var realWorktreeDirRemover = {
|
|
|
18881
18873
|
probe: (p) => {
|
|
18882
18874
|
let st;
|
|
18883
18875
|
try {
|
|
18884
|
-
st = (0,
|
|
18876
|
+
st = (0, import_node_fs18.lstatSync)(p);
|
|
18885
18877
|
} catch {
|
|
18886
18878
|
return null;
|
|
18887
18879
|
}
|
|
18888
18880
|
if (st.isSymbolicLink()) return "link";
|
|
18889
18881
|
try {
|
|
18890
|
-
(0,
|
|
18882
|
+
(0, import_node_fs18.readlinkSync)(p);
|
|
18891
18883
|
return "link";
|
|
18892
18884
|
} catch {
|
|
18893
18885
|
}
|
|
@@ -18895,7 +18887,7 @@ var realWorktreeDirRemover = {
|
|
|
18895
18887
|
},
|
|
18896
18888
|
readdir: (p) => {
|
|
18897
18889
|
try {
|
|
18898
|
-
return (0,
|
|
18890
|
+
return (0, import_node_fs18.readdirSync)(p);
|
|
18899
18891
|
} catch {
|
|
18900
18892
|
return [];
|
|
18901
18893
|
}
|
|
@@ -18904,9 +18896,9 @@ var realWorktreeDirRemover = {
|
|
|
18904
18896
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
18905
18897
|
detachLink: (p) => {
|
|
18906
18898
|
try {
|
|
18907
|
-
(0,
|
|
18899
|
+
(0, import_node_fs18.rmdirSync)(p);
|
|
18908
18900
|
} catch {
|
|
18909
|
-
(0,
|
|
18901
|
+
(0, import_node_fs18.unlinkSync)(p);
|
|
18910
18902
|
}
|
|
18911
18903
|
},
|
|
18912
18904
|
removeTree: (p) => (0, import_promises4.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
@@ -18921,7 +18913,7 @@ async function resolvePrimaryCheckout(execGit) {
|
|
|
18921
18913
|
function worktreeRemoveDeps(execGit) {
|
|
18922
18914
|
return {
|
|
18923
18915
|
git: execGit,
|
|
18924
|
-
sleep: (ms) => new Promise((
|
|
18916
|
+
sleep: (ms) => new Promise((resolve6) => setTimeout(resolve6, ms)),
|
|
18925
18917
|
removeWorktreeDir: async (worktreePath) => removeWorktreeTree(worktreePath, await resolvePrimaryCheckout(execGit), realWorktreeDirRemover)
|
|
18926
18918
|
};
|
|
18927
18919
|
}
|
|
@@ -18936,9 +18928,9 @@ async function worktreeHasStageState(worktreePath) {
|
|
|
18936
18928
|
}
|
|
18937
18929
|
}
|
|
18938
18930
|
function stageStateFileBelongsToWorktree(statePath, worktreePath) {
|
|
18939
|
-
if (!(0,
|
|
18931
|
+
if (!(0, import_node_fs18.existsSync)(statePath)) return false;
|
|
18940
18932
|
try {
|
|
18941
|
-
const state = JSON.parse((0,
|
|
18933
|
+
const state = JSON.parse((0, import_node_fs18.readFileSync)(statePath, "utf8"));
|
|
18942
18934
|
const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
|
|
18943
18935
|
return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
|
|
18944
18936
|
} catch {
|
|
@@ -19011,7 +19003,7 @@ pr.command("merge <number>").description("merge a PR (squash by default) and cle
|
|
|
19011
19003
|
} : await cleanupPrMergeLocalBranch(headRef, {
|
|
19012
19004
|
beforeWorktrees,
|
|
19013
19005
|
startingPath,
|
|
19014
|
-
pathExists: (p) => (0,
|
|
19006
|
+
pathExists: (p) => (0, import_node_fs18.existsSync)(p),
|
|
19015
19007
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
19016
19008
|
teardownWorktreeStage,
|
|
19017
19009
|
deferredStore,
|
|
@@ -19208,7 +19200,7 @@ function stageScopedRunOpts(o) {
|
|
|
19208
19200
|
};
|
|
19209
19201
|
}
|
|
19210
19202
|
function printLine(value) {
|
|
19211
|
-
(0,
|
|
19203
|
+
(0, import_node_fs18.writeSync)(1, `${value}
|
|
19212
19204
|
`);
|
|
19213
19205
|
}
|
|
19214
19206
|
function stageKeepAlive() {
|
|
@@ -19225,8 +19217,8 @@ async function resolveStage() {
|
|
|
19225
19217
|
local,
|
|
19226
19218
|
shell: shellFor(),
|
|
19227
19219
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
19228
|
-
hasCompose: (0,
|
|
19229
|
-
hasEnvExample: (0,
|
|
19220
|
+
hasCompose: (0, import_node_fs18.existsSync)((0, import_node_path18.join)(process.cwd(), "docker-compose.yml")),
|
|
19221
|
+
hasEnvExample: (0, import_node_fs18.existsSync)((0, import_node_path18.join)(process.cwd(), ".env.example"))
|
|
19230
19222
|
});
|
|
19231
19223
|
}
|
|
19232
19224
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -19690,7 +19682,7 @@ bootstrap.command("verify <repo>").description("audit whether an existing repo i
|
|
|
19690
19682
|
client: defaultGitHubClient(),
|
|
19691
19683
|
projectMeta: meta,
|
|
19692
19684
|
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
19693
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
19685
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null,
|
|
19694
19686
|
// requiredGcpApis is stored as an array by a JSON write, but `project set --var KEY=VALUE` stores a raw
|
|
19695
19687
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
19696
19688
|
requiredGcpApis: (() => {
|
|
@@ -19733,12 +19725,12 @@ bootstrap.command("apply <repo>").description("idempotent seed apply from skills
|
|
|
19733
19725
|
return fail(`bootstrap apply: ${e.message}`);
|
|
19734
19726
|
}
|
|
19735
19727
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
19736
|
-
if (!(0,
|
|
19737
|
-
const manifest = loadBootstrapSeeds((0,
|
|
19728
|
+
if (!(0, import_node_fs18.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; run from the MMI-Hub repo root`);
|
|
19729
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs18.readFileSync)(manifestPath, "utf8"));
|
|
19738
19730
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
19739
19731
|
const slug = parsedRepo.slug;
|
|
19740
19732
|
const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
|
|
19741
|
-
const readFile3 = (p) => (0,
|
|
19733
|
+
const readFile3 = (p) => (0, import_node_fs18.existsSync)(p) ? (0, import_node_fs18.readFileSync)(p, "utf8") : null;
|
|
19742
19734
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
19743
19735
|
const rawVars = {};
|
|
19744
19736
|
for (const value of rawValues("--var")) {
|
|
@@ -19985,16 +19977,16 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
19985
19977
|
const repoClass = o.class;
|
|
19986
19978
|
targets = [{ repo: o.repo, class: repoClass, releaseTrack: repoClass === "content" ? "trunk" : resolveReleaseTrack(meta, void 0, o.repo) }];
|
|
19987
19979
|
} else {
|
|
19988
|
-
const projectsJson = registryProjects ? JSON.stringify({ projects: registryProjects }) : (0,
|
|
19980
|
+
const projectsJson = registryProjects ? JSON.stringify({ projects: registryProjects }) : (0, import_node_fs18.existsSync)("projects.json") ? (0, import_node_fs18.readFileSync)("projects.json", "utf8") : null;
|
|
19989
19981
|
if (!projectsJson) return failGraceful("access audit: no project registry \u2014 Hub API unreachable and projects.json not found; run from the MMI-Hub repo root or pass --repo <owner/repo>");
|
|
19990
|
-
const fanoutJson = (0,
|
|
19982
|
+
const fanoutJson = (0, import_node_fs18.existsSync)(".github/fanout-targets.json") ? (0, import_node_fs18.readFileSync)(".github/fanout-targets.json", "utf8") : null;
|
|
19991
19983
|
targets = loadAccessTargets(projectsJson, fanoutJson);
|
|
19992
19984
|
}
|
|
19993
19985
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
19994
|
-
const fileMatrix = (0,
|
|
19986
|
+
const fileMatrix = (0, import_node_fs18.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs18.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
19995
19987
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
19996
19988
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
19997
|
-
const fileContracts = (0,
|
|
19989
|
+
const fileContracts = (0, import_node_fs18.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs18.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
|
|
19998
19990
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
19999
19991
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess);
|
|
20000
19992
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|