@mutmutco/cli 3.127.0 → 3.128.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +742 -336
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -6744,7 +6744,7 @@ function localTrainSyncBannerLine(result) {
|
|
|
6744
6744
|
// src/gc.ts
|
|
6745
6745
|
var import_node_fs11 = require("node:fs");
|
|
6746
6746
|
var import_promises = require("node:fs/promises");
|
|
6747
|
-
var
|
|
6747
|
+
var import_node_path10 = require("node:path");
|
|
6748
6748
|
|
|
6749
6749
|
// src/active-workspace-root.ts
|
|
6750
6750
|
var import_node_fs9 = require("node:fs");
|
|
@@ -6762,6 +6762,12 @@ function isPathUnderDirectory(childPath, parentPath, platform2 = process.platfor
|
|
|
6762
6762
|
if (child2 === parent) return true;
|
|
6763
6763
|
return child2.startsWith(`${parent}/`);
|
|
6764
6764
|
}
|
|
6765
|
+
function isCursorAgentHost(env = process.env) {
|
|
6766
|
+
return env.CURSOR_AGENT === "1" || Boolean(env.CURSOR_EXTENSION_HOST_ROLE?.trim()) || Boolean(env.AGENT_TRANSCRIPTS?.trim());
|
|
6767
|
+
}
|
|
6768
|
+
function unresolvedWorkspaceRefusalMessage() {
|
|
6769
|
+
return "refusing to remove a worktree: Cursor agent host cannot resolve the active workspace root. Open the primary checkout in Cursor first (keep the workspace root on the primary; edit the worktree without move_agent_to_root), or set MMI_ACTIVE_WORKSPACE_ROOT to the primary path, then retry `mmi-cli worktree gc sweep-deferred` / `worktree gc --apply` / `worktree land --apply`.";
|
|
6770
|
+
}
|
|
6765
6771
|
function normalizeActiveWorkspaceRoot(value, opts = {}) {
|
|
6766
6772
|
const raw = value?.trim();
|
|
6767
6773
|
if (!raw) return void 0;
|
|
@@ -6779,8 +6785,13 @@ function removalTouchesActiveWorkspace(targetPath, activeWorkspaceRoot, platform
|
|
|
6779
6785
|
function activeWorkspaceRefusalMessage(targetPath, activeWorkspaceRoot) {
|
|
6780
6786
|
return `refusing to remove active Cursor workspace ${activeWorkspaceRoot} (target ${targetPath}). Open the primary checkout in Cursor first, then retry \`mmi-cli worktree gc sweep-deferred\` / \`worktree gc --apply\`.`;
|
|
6781
6787
|
}
|
|
6782
|
-
function decideActiveWorkspaceGuard(targetPath, activeWorkspaceRoot, platform2 = process.platform) {
|
|
6783
|
-
if (!activeWorkspaceRoot)
|
|
6788
|
+
function decideActiveWorkspaceGuard(targetPath, activeWorkspaceRoot, platform2 = process.platform, opts = {}) {
|
|
6789
|
+
if (!activeWorkspaceRoot) {
|
|
6790
|
+
if (opts.cursorAgentHost) {
|
|
6791
|
+
return { action: "refuse", reason: "unresolved-workspace", message: unresolvedWorkspaceRefusalMessage() };
|
|
6792
|
+
}
|
|
6793
|
+
return { action: "proceed" };
|
|
6794
|
+
}
|
|
6784
6795
|
if (!removalTouchesActiveWorkspace(targetPath, activeWorkspaceRoot, platform2)) {
|
|
6785
6796
|
return { action: "proceed" };
|
|
6786
6797
|
}
|
|
@@ -6882,10 +6893,137 @@ function resolveActiveWorkspaceRoot(deps = {}) {
|
|
|
6882
6893
|
return resolveCursorAgentWorkspaceRoot(deps);
|
|
6883
6894
|
}
|
|
6884
6895
|
|
|
6896
|
+
// src/estate-hygiene.ts
|
|
6897
|
+
var import_node_path8 = require("node:path");
|
|
6898
|
+
function win32LongPath(p, platform2 = process.platform) {
|
|
6899
|
+
if (platform2 !== "win32") return p;
|
|
6900
|
+
if (p.startsWith("\\\\?\\")) return p;
|
|
6901
|
+
if (p.startsWith("\\\\")) return `\\\\?\\UNC\\${p.slice(2)}`;
|
|
6902
|
+
return `\\\\?\\${p}`;
|
|
6903
|
+
}
|
|
6904
|
+
function normalizeGithubRemote(url) {
|
|
6905
|
+
const raw = url.trim();
|
|
6906
|
+
if (!raw) return void 0;
|
|
6907
|
+
const ssh = raw.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/i);
|
|
6908
|
+
if (ssh) return `${ssh[1]}/${ssh[2]}`.toLowerCase();
|
|
6909
|
+
const https = raw.match(/^https?:\/\/github\.com\/([^/]+)\/(.+?)(?:\.git)?$/i);
|
|
6910
|
+
if (https) return `${https[1]}/${https[2]}`.toLowerCase();
|
|
6911
|
+
return void 0;
|
|
6912
|
+
}
|
|
6913
|
+
function remotesOverlap(a, b) {
|
|
6914
|
+
const left = new Set(a.map(normalizeGithubRemote).filter((x) => Boolean(x)));
|
|
6915
|
+
if (!left.size) return false;
|
|
6916
|
+
return b.some((url) => {
|
|
6917
|
+
const key = normalizeGithubRemote(url);
|
|
6918
|
+
return Boolean(key && left.has(key));
|
|
6919
|
+
});
|
|
6920
|
+
}
|
|
6921
|
+
function worktreesRootOf(primaryCheckout) {
|
|
6922
|
+
return (0, import_node_path8.join)((0, import_node_path8.dirname)(primaryCheckout), "mmi-worktrees", (0, import_node_path8.basename)(primaryCheckout));
|
|
6923
|
+
}
|
|
6924
|
+
function helperWorktreeRoots(primaryCheckout) {
|
|
6925
|
+
return [
|
|
6926
|
+
(0, import_node_path8.join)(primaryCheckout, ".claude", "worktrees"),
|
|
6927
|
+
(0, import_node_path8.join)(primaryCheckout, ".worktrees")
|
|
6928
|
+
];
|
|
6929
|
+
}
|
|
6930
|
+
function pathProvesRepoContainerOwnership(dir, repoContainer, platform2 = process.platform) {
|
|
6931
|
+
const norm = (p) => {
|
|
6932
|
+
const unified = p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
6933
|
+
return platform2 === "win32" || platform2 === "darwin" ? unified.toLowerCase() : unified;
|
|
6934
|
+
};
|
|
6935
|
+
return norm((0, import_node_path8.dirname)(dir)) === norm(repoContainer);
|
|
6936
|
+
}
|
|
6937
|
+
function worktreesRootFromLeaseRef(ref) {
|
|
6938
|
+
const unified = ref.replace(/\\/g, "/");
|
|
6939
|
+
const marker = "/mmi-worktrees/";
|
|
6940
|
+
const idx = unified.toLowerCase().lastIndexOf(marker);
|
|
6941
|
+
if (idx < 0) return void 0;
|
|
6942
|
+
const after = unified.slice(idx + marker.length);
|
|
6943
|
+
const repo = after.split("/").filter(Boolean)[0];
|
|
6944
|
+
if (!repo) return void 0;
|
|
6945
|
+
return unified.slice(0, idx + marker.length + repo.length);
|
|
6946
|
+
}
|
|
6947
|
+
function classifyEstateAudit(input) {
|
|
6948
|
+
const otherPrimaries = input.otherCheckouts.filter((c) => remotesOverlap(input.remoteUrls, c.remoteUrls)).map((c) => c.path);
|
|
6949
|
+
const thisRoot = input.thisWorktreesRoot.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
6950
|
+
const foreignLeaseRoots = [...new Set(
|
|
6951
|
+
(input.leaseRefs ?? []).map(worktreesRootFromLeaseRef).filter((root) => Boolean(root)).filter((root) => root.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase() !== thisRoot)
|
|
6952
|
+
)];
|
|
6953
|
+
const reasons = [];
|
|
6954
|
+
if (otherPrimaries.length) {
|
|
6955
|
+
reasons.push(
|
|
6956
|
+
`another primary checkout of the same remotes exists: ${otherPrimaries.join(", ")}`
|
|
6957
|
+
);
|
|
6958
|
+
}
|
|
6959
|
+
if (foreignLeaseRoots.length) {
|
|
6960
|
+
reasons.push(
|
|
6961
|
+
`jerv lease ledger points at another worktrees root: ${foreignLeaseRoots.join(", ")}`
|
|
6962
|
+
);
|
|
6963
|
+
}
|
|
6964
|
+
return {
|
|
6965
|
+
auditedClone: input.auditedClone,
|
|
6966
|
+
otherPrimaries,
|
|
6967
|
+
foreignLeaseRoots,
|
|
6968
|
+
blocksGreen: reasons.length > 0,
|
|
6969
|
+
reasons
|
|
6970
|
+
};
|
|
6971
|
+
}
|
|
6972
|
+
function formatEstateAuditLines(audit) {
|
|
6973
|
+
const lines = [`audited clone: ${audit.auditedClone}`];
|
|
6974
|
+
if (!audit.blocksGreen) return lines;
|
|
6975
|
+
lines.push('refusing a clean "no leaks" report \u2014 this clone is not the whole estate:');
|
|
6976
|
+
for (const reason of audit.reasons) lines.push(` ${reason}`);
|
|
6977
|
+
lines.push(" fix: run doctor / worktree list --stale / worktree gc from the canonical primary (E:\\AI Projects\\Mutatis Mutandis\\\u2026), not a second clone");
|
|
6978
|
+
return lines;
|
|
6979
|
+
}
|
|
6980
|
+
function classifyOriginLeftovers(input) {
|
|
6981
|
+
const local = new Set(input.localBranches ?? []);
|
|
6982
|
+
const leftovers = [];
|
|
6983
|
+
for (const branch of input.remoteBranches) {
|
|
6984
|
+
const name = branch.replace(/^origin\//, "").trim();
|
|
6985
|
+
if (!name || name === "HEAD" || input.protectedBranches.has(name)) continue;
|
|
6986
|
+
if (input.openPrBranches.has(name)) {
|
|
6987
|
+
leftovers.push({
|
|
6988
|
+
branch: name,
|
|
6989
|
+
kind: "open-pr",
|
|
6990
|
+
autoReap: false,
|
|
6991
|
+
detail: `origin/${name} has an open PR \u2014 gc will not delete it`
|
|
6992
|
+
});
|
|
6993
|
+
continue;
|
|
6994
|
+
}
|
|
6995
|
+
if (input.mergedPrBranches.has(name)) {
|
|
6996
|
+
leftovers.push({
|
|
6997
|
+
branch: name,
|
|
6998
|
+
kind: "merged-missed",
|
|
6999
|
+
autoReap: true,
|
|
7000
|
+
detail: local.has(name) ? `origin/${name} is merged; this clone still has the head` : `origin/${name} is merged; this clone has no local branch (missed reap)`
|
|
7001
|
+
});
|
|
7002
|
+
continue;
|
|
7003
|
+
}
|
|
7004
|
+
if (input.closedUnmergedBranches.has(name)) {
|
|
7005
|
+
leftovers.push({
|
|
7006
|
+
branch: name,
|
|
7007
|
+
kind: "closed-not-merged",
|
|
7008
|
+
autoReap: Boolean(input.trainOnly),
|
|
7009
|
+
detail: `origin/${name} is closed-not-merged \u2014 gc will not auto-delete it${input.trainOnly ? " unless --train-only --apply" : ""}`
|
|
7010
|
+
});
|
|
7011
|
+
continue;
|
|
7012
|
+
}
|
|
7013
|
+
leftovers.push({
|
|
7014
|
+
branch: name,
|
|
7015
|
+
kind: local.has(name) ? "no-pr" : "other-clone",
|
|
7016
|
+
autoReap: Boolean(input.trainOnly),
|
|
7017
|
+
detail: local.has(name) ? `origin/${name} has no PR \u2014 gc will not auto-delete it` : `origin/${name} is an other-clone leftover with no PR this clone can see`
|
|
7018
|
+
});
|
|
7019
|
+
}
|
|
7020
|
+
return leftovers;
|
|
7021
|
+
}
|
|
7022
|
+
|
|
6885
7023
|
// src/worktree-ownership.ts
|
|
6886
7024
|
var import_node_fs10 = require("node:fs");
|
|
6887
7025
|
var import_node_os4 = require("node:os");
|
|
6888
|
-
var
|
|
7026
|
+
var import_node_path9 = require("node:path");
|
|
6889
7027
|
var OWNERS_FILE = "worktree-owners.json";
|
|
6890
7028
|
var EVENTS_FILE = "worktree-events.jsonl";
|
|
6891
7029
|
var WORKTREE_ACTIVITY_WINDOW_MS = 30 * 6e4;
|
|
@@ -6990,7 +7128,7 @@ function decideWorktreeRemoval(input) {
|
|
|
6990
7128
|
}
|
|
6991
7129
|
function readFreshWorktreeLease(path2, now) {
|
|
6992
7130
|
try {
|
|
6993
|
-
const candidate = JSON.parse((0, import_node_fs10.readFileSync)((0,
|
|
7131
|
+
const candidate = JSON.parse((0, import_node_fs10.readFileSync)((0, import_node_path9.join)(path2, WORKTREE_LEASE_MARKER), "utf8"));
|
|
6994
7132
|
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return void 0;
|
|
6995
7133
|
const lease = candidate;
|
|
6996
7134
|
if (lease.kind !== "worktree" || lease.state !== "active" || typeof lease.agent !== "string" || !lease.agent.trim() || typeof lease.ref !== "string" || !sameWorktreePath(lease.ref, path2) || typeof lease.createdAt !== "string" || typeof lease.ttlHours !== "number" || !Number.isFinite(lease.ttlHours) || lease.ttlHours <= 0) return void 0;
|
|
@@ -7017,7 +7155,7 @@ function readOwners(primaryRoot) {
|
|
|
7017
7155
|
function writeOwners(primaryRoot, entries) {
|
|
7018
7156
|
try {
|
|
7019
7157
|
const path2 = worktreeOwnersPath(primaryRoot);
|
|
7020
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
7158
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path9.dirname)(path2), { recursive: true });
|
|
7021
7159
|
(0, import_node_fs10.writeFileSync)(path2, serializeWorktreeOwners(entries), "utf8");
|
|
7022
7160
|
} catch {
|
|
7023
7161
|
}
|
|
@@ -7053,7 +7191,7 @@ function dropWorktreeOwner(primaryRoot, path2, expectedCreatedAt) {
|
|
|
7053
7191
|
function appendWorktreeEvent(primaryRoot, event) {
|
|
7054
7192
|
try {
|
|
7055
7193
|
const path2 = worktreeEventsPath(primaryRoot);
|
|
7056
|
-
(0, import_node_fs10.mkdirSync)((0,
|
|
7194
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path9.dirname)(path2), { recursive: true });
|
|
7057
7195
|
(0, import_node_fs10.appendFileSync)(path2, `${JSON.stringify({ at: event.at ?? (/* @__PURE__ */ new Date()).toISOString(), ...event })}
|
|
7058
7196
|
`, "utf8");
|
|
7059
7197
|
} catch {
|
|
@@ -7132,7 +7270,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
7132
7270
|
const resolveRoot = deps.resolveArchiveRoot ?? repoRuntimeStatePath;
|
|
7133
7271
|
if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
|
|
7134
7272
|
if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
|
|
7135
|
-
const source = (0,
|
|
7273
|
+
const source = (0, import_node_path10.join)(args.worktreePath, ".jerv");
|
|
7136
7274
|
if (!exists(source)) return { status: "absent" };
|
|
7137
7275
|
if (!isDirectory(source)) return { status: "skipped", reason: "jerv-not-a-directory" };
|
|
7138
7276
|
const runScope = resolveJervArtifactRunScope(env);
|
|
@@ -7140,7 +7278,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
|
|
|
7140
7278
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
7141
7279
|
const dest = resolveRoot(args.primaryRoot, "jerv-artifacts", runScope, branchSlug, stamp, ".jerv");
|
|
7142
7280
|
try {
|
|
7143
|
-
mkdirp((0,
|
|
7281
|
+
mkdirp((0, import_node_path10.dirname)(dest));
|
|
7144
7282
|
copyDir(source, dest);
|
|
7145
7283
|
if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
|
|
7146
7284
|
return { status: "archived", path: dest, runScope };
|
|
@@ -7294,7 +7432,9 @@ async function sweepDeferredWorktrees(store, deps, removalContext) {
|
|
|
7294
7432
|
const owner = removalContext ? lookupWorktreeOwner(removalContext.primaryRoot, entry.path) : void 0;
|
|
7295
7433
|
if (removalContext) {
|
|
7296
7434
|
const activeRoot = removalContext.activeWorkspaceRoot ?? resolveActiveWorkspaceRoot();
|
|
7297
|
-
const activeGuard = decideActiveWorkspaceGuard(entry.path, activeRoot
|
|
7435
|
+
const activeGuard = decideActiveWorkspaceGuard(entry.path, activeRoot, process.platform, {
|
|
7436
|
+
cursorAgentHost: removalContext.cursorAgentHost ?? false
|
|
7437
|
+
});
|
|
7298
7438
|
if (activeGuard.action === "refuse") {
|
|
7299
7439
|
stillDeferred.push({ ...entry, reason: "active-workspace" });
|
|
7300
7440
|
recordWorktreeRemoval(removalContext.primaryRoot, {
|
|
@@ -7639,23 +7779,23 @@ function resolveSafeSiblingWorktreeCleanupTarget(worktreePath, siblingRoots, dep
|
|
|
7639
7779
|
return { ok: false, reason: reasons.join("; ") || "no worktrees root to check against" };
|
|
7640
7780
|
}
|
|
7641
7781
|
function siblingMmiWorktreesRoot(repoRoot2) {
|
|
7642
|
-
const parent = (0,
|
|
7643
|
-
if ((0,
|
|
7644
|
-
const grandparent = (0,
|
|
7645
|
-
if ((0,
|
|
7646
|
-
return (0,
|
|
7782
|
+
const parent = (0, import_node_path10.dirname)(repoRoot2);
|
|
7783
|
+
if ((0, import_node_path10.basename)(parent).toLowerCase() === "mmi-worktrees") return parent;
|
|
7784
|
+
const grandparent = (0, import_node_path10.dirname)(parent);
|
|
7785
|
+
if ((0, import_node_path10.basename)(grandparent).toLowerCase() === "mmi-worktrees") return grandparent;
|
|
7786
|
+
return (0, import_node_path10.join)(parent, "mmi-worktrees");
|
|
7647
7787
|
}
|
|
7648
7788
|
function agentWorktreesRoot(repoRoot2) {
|
|
7649
|
-
return (0,
|
|
7789
|
+
return (0, import_node_path10.join)(repoRoot2, ".claude", "worktrees");
|
|
7650
7790
|
}
|
|
7651
7791
|
function worktreeScanDirs(root, repoRoot2, listDirs, isRepoCheckout) {
|
|
7652
|
-
const projectsDir = (0,
|
|
7653
|
-
const ownName = (0,
|
|
7792
|
+
const projectsDir = (0, import_node_path10.dirname)(root);
|
|
7793
|
+
const ownName = (0, import_node_path10.basename)(repoRoot2).toLowerCase();
|
|
7654
7794
|
const flat = [];
|
|
7655
7795
|
let ownContainer = null;
|
|
7656
7796
|
for (const dir of listDirs(root)) {
|
|
7657
|
-
const name = (0,
|
|
7658
|
-
if (isRepoCheckout((0,
|
|
7797
|
+
const name = (0, import_node_path10.basename)(dir);
|
|
7798
|
+
if (isRepoCheckout((0, import_node_path10.join)(projectsDir, name))) {
|
|
7659
7799
|
if (name.toLowerCase() === ownName) ownContainer = dir;
|
|
7660
7800
|
continue;
|
|
7661
7801
|
}
|
|
@@ -7664,9 +7804,9 @@ function worktreeScanDirs(root, repoRoot2, listDirs, isRepoCheckout) {
|
|
|
7664
7804
|
return ownContainer ? [...flat, ...listDirs(ownContainer)] : flat;
|
|
7665
7805
|
}
|
|
7666
7806
|
function explicitRepoWorktreesRoot(root, repoRoot2, rootDirs) {
|
|
7667
|
-
const repoName2 = (0,
|
|
7807
|
+
const repoName2 = (0, import_node_path10.basename)(repoRoot2);
|
|
7668
7808
|
const repoDir = rootDirs.find((name) => name.toLowerCase() === repoName2.toLowerCase());
|
|
7669
|
-
return repoDir ? (0,
|
|
7809
|
+
return repoDir ? (0, import_node_path10.join)(root, repoDir) : root;
|
|
7670
7810
|
}
|
|
7671
7811
|
function classifySiblingWorktreeDir(entry) {
|
|
7672
7812
|
if (!entry.ownedByCurrentRepo) {
|
|
@@ -7914,7 +8054,33 @@ function buildGcPlan(inputs) {
|
|
|
7914
8054
|
const state = closedState(prSet);
|
|
7915
8055
|
return state ? { ref, branch, prState: state.state, prNumbers: state.numbers } : null;
|
|
7916
8056
|
}).filter((r) => Boolean(r));
|
|
7917
|
-
|
|
8057
|
+
const originLeftovers = classifyOriginLeftovers({
|
|
8058
|
+
remoteBranches: inputs.originBranches ?? [],
|
|
8059
|
+
localBranches: inputs.localBranches,
|
|
8060
|
+
protectedBranches,
|
|
8061
|
+
openPrBranches: new Set(
|
|
8062
|
+
[...prs.entries()].filter(([, set]) => set.some((pr2) => pr2.state === "OPEN")).map(([b]) => b)
|
|
8063
|
+
),
|
|
8064
|
+
mergedPrBranches: new Set(
|
|
8065
|
+
[...prs.entries()].filter(([, set]) => set.some((pr2) => pr2.state === "MERGED")).map(([b]) => b)
|
|
8066
|
+
),
|
|
8067
|
+
closedUnmergedBranches: new Set(
|
|
8068
|
+
[...prs.entries()].filter(([, set]) => set.some((pr2) => pr2.state === "CLOSED") && !set.some((pr2) => pr2.state === "MERGED")).map(([b]) => b)
|
|
8069
|
+
),
|
|
8070
|
+
trainOnly: inputs.trainOnly
|
|
8071
|
+
});
|
|
8072
|
+
const plannedBranches = new Set(branches.map((b) => b.branch));
|
|
8073
|
+
const reapOriginHeads = originLeftovers.filter((l) => l.autoReap && !plannedBranches.has(l.branch)).map((l) => {
|
|
8074
|
+
const prSet = prs.get(l.branch);
|
|
8075
|
+
const state = closedState(prSet);
|
|
8076
|
+
return {
|
|
8077
|
+
branch: l.branch,
|
|
8078
|
+
prState: state?.state ?? "MERGED",
|
|
8079
|
+
prNumbers: state?.numbers ?? [],
|
|
8080
|
+
...state?.headOids.length ? { reviewedHeadOids: state.headOids } : {}
|
|
8081
|
+
};
|
|
8082
|
+
});
|
|
8083
|
+
return { branches, trackingRefs, worktreeDirs, skippedWorktreeDirs, skipped, originLeftovers, reapOriginHeads };
|
|
7918
8084
|
}
|
|
7919
8085
|
function parseRemotePruneDryRun(stdout) {
|
|
7920
8086
|
const refs = [];
|
|
@@ -8229,7 +8395,9 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
8229
8395
|
report.worktree = { path: wtPath, status: "not-attempted", reason: "main-worktree" };
|
|
8230
8396
|
} else if (wtPath) {
|
|
8231
8397
|
const activeRoot = options.removalContext?.activeWorkspaceRoot ?? resolveActiveWorkspaceRoot();
|
|
8232
|
-
const activeGuard = decideActiveWorkspaceGuard(wtPath, activeRoot
|
|
8398
|
+
const activeGuard = decideActiveWorkspaceGuard(wtPath, activeRoot, process.platform, {
|
|
8399
|
+
cursorAgentHost: options.removalContext?.cursorAgentHost ?? false
|
|
8400
|
+
});
|
|
8233
8401
|
if (activeGuard.action === "refuse") {
|
|
8234
8402
|
if (options.deferredStore) {
|
|
8235
8403
|
try {
|
|
@@ -8463,9 +8631,13 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
8463
8631
|
if (wtPath) await git2(["worktree", "prune"]).catch(() => "");
|
|
8464
8632
|
return report;
|
|
8465
8633
|
}
|
|
8466
|
-
function formatGcPlan(plan, apply) {
|
|
8634
|
+
function formatGcPlan(plan, apply, auditClone) {
|
|
8467
8635
|
const lines = [`mmi-cli worktree gc: ${apply ? "apply" : "dry-run"}`];
|
|
8468
|
-
if (
|
|
8636
|
+
if (auditClone) lines.push(`audited clone: ${auditClone}`);
|
|
8637
|
+
const hasOriginNames = Boolean(plan.originLeftovers?.length);
|
|
8638
|
+
if (!plan.branches.length && !plan.trackingRefs.length && !plan.worktreeDirs.length && !plan.reapOriginHeads?.length) {
|
|
8639
|
+
lines.push(hasOriginNames ? "nothing this clone will auto-delete" : "nothing to clean");
|
|
8640
|
+
}
|
|
8469
8641
|
if (plan.branches.length) {
|
|
8470
8642
|
lines.push("local branches:");
|
|
8471
8643
|
for (const b of plan.branches) {
|
|
@@ -8507,6 +8679,12 @@ function formatGcPlan(plan, apply) {
|
|
|
8507
8679
|
lines.push(` - ${s.path}: ${s.reason}${s.detail ? ` (${s.detail})` : ""}`);
|
|
8508
8680
|
}
|
|
8509
8681
|
}
|
|
8682
|
+
if (plan.originLeftovers?.length) {
|
|
8683
|
+
lines.push("origin leftovers gc will not silently delete (use --train-only for closed-not-merged / no-PR):");
|
|
8684
|
+
for (const leftover of plan.originLeftovers) {
|
|
8685
|
+
lines.push(` - ${leftover.branch}: ${leftover.kind}${leftover.autoReap ? " (will reap)" : ""} \u2014 ${leftover.detail}`);
|
|
8686
|
+
}
|
|
8687
|
+
}
|
|
8510
8688
|
if (!apply && (plan.branches.length || plan.trackingRefs.length || plan.worktreeDirs.length)) lines.push("rerun with --apply to delete only the listed local, remote, tracking, and directory items");
|
|
8511
8689
|
return lines.join("\n");
|
|
8512
8690
|
}
|
|
@@ -8592,7 +8770,7 @@ async function gatherStaleWorktreeWarning(gitRun = defaultGitRun) {
|
|
|
8592
8770
|
|
|
8593
8771
|
// src/released-version-cache.ts
|
|
8594
8772
|
var import_node_fs12 = require("node:fs");
|
|
8595
|
-
var
|
|
8773
|
+
var import_node_path11 = require("node:path");
|
|
8596
8774
|
|
|
8597
8775
|
// src/version-lag.ts
|
|
8598
8776
|
var VERSION_LABEL = "installed plugin/adapter cache freshness";
|
|
@@ -8688,7 +8866,7 @@ function versionAutoUpdateAction(report, releasedSource) {
|
|
|
8688
8866
|
// src/released-version-cache.ts
|
|
8689
8867
|
var RELEASED_VERSION_CACHE_MS = 24 * 36e5;
|
|
8690
8868
|
function releasedVersionCachePath(runtimeRoot) {
|
|
8691
|
-
return (0,
|
|
8869
|
+
return (0, import_node_path11.join)(runtimeRoot, "head-ts", ".released-version");
|
|
8692
8870
|
}
|
|
8693
8871
|
function readReleasedVersionCache(cachePath, now = Date.now(), read = import_node_fs12.readFileSync, currentVersion = resolveClientVersion()) {
|
|
8694
8872
|
let parsed;
|
|
@@ -8708,7 +8886,7 @@ function readReleasedVersionCache(cachePath, now = Date.now(), read = import_nod
|
|
|
8708
8886
|
}
|
|
8709
8887
|
function writeReleasedVersionCache(cachePath, version, now = Date.now()) {
|
|
8710
8888
|
try {
|
|
8711
|
-
(0, import_node_fs12.mkdirSync)((0,
|
|
8889
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path11.dirname)(cachePath), { recursive: true });
|
|
8712
8890
|
(0, import_node_fs12.writeFileSync)(cachePath, JSON.stringify({ version, at: now }), "utf8");
|
|
8713
8891
|
} catch {
|
|
8714
8892
|
}
|
|
@@ -8723,10 +8901,10 @@ function cachedReadNote(cachedAt, now = Date.now()) {
|
|
|
8723
8901
|
|
|
8724
8902
|
// src/schedules-drift-cache.ts
|
|
8725
8903
|
var import_node_fs13 = require("node:fs");
|
|
8726
|
-
var
|
|
8904
|
+
var import_node_path12 = require("node:path");
|
|
8727
8905
|
var SCHEDULES_DRIFT_CACHE_MS = 6 * 36e5;
|
|
8728
8906
|
function schedulesDriftCachePath(runtimeRoot) {
|
|
8729
|
-
return (0,
|
|
8907
|
+
return (0, import_node_path12.join)(runtimeRoot, "head-ts", ".schedules-drift");
|
|
8730
8908
|
}
|
|
8731
8909
|
function readSchedulesDriftCache(cachePath, now = Date.now(), read = import_node_fs13.readFileSync) {
|
|
8732
8910
|
let parsed;
|
|
@@ -8745,7 +8923,7 @@ function readSchedulesDriftCache(cachePath, now = Date.now(), read = import_node
|
|
|
8745
8923
|
}
|
|
8746
8924
|
function writeSchedulesDriftCache(cachePath, driftLines, now = Date.now()) {
|
|
8747
8925
|
try {
|
|
8748
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
8926
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(cachePath), { recursive: true });
|
|
8749
8927
|
(0, import_node_fs13.writeFileSync)(cachePath, JSON.stringify({ driftLines, at: now }), "utf8");
|
|
8750
8928
|
} catch {
|
|
8751
8929
|
}
|
|
@@ -8901,7 +9079,7 @@ function resolveCatalogRef(probe) {
|
|
|
8901
9079
|
// src/plugin-guard-io.ts
|
|
8902
9080
|
var import_node_fs14 = require("node:fs");
|
|
8903
9081
|
var import_node_child_process6 = require("node:child_process");
|
|
8904
|
-
var
|
|
9082
|
+
var import_node_path13 = require("node:path");
|
|
8905
9083
|
var import_node_os5 = require("node:os");
|
|
8906
9084
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
8907
9085
|
|
|
@@ -9204,17 +9382,17 @@ function runHostBin(bin, args, opts) {
|
|
|
9204
9382
|
return step ? execFileHard(file, argv, { ...shared, step }) : execFileP2(file, argv, shared);
|
|
9205
9383
|
}
|
|
9206
9384
|
function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
9207
|
-
if (surface === "codex") return env.CODEX_HOME?.trim() || (0,
|
|
9208
|
-
if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0,
|
|
9209
|
-
if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0,
|
|
9210
|
-
if (surface === "cursor") return (0,
|
|
9385
|
+
if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path13.join)(home, ".codex");
|
|
9386
|
+
if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0, import_node_path13.join)(home, ".kimi-code");
|
|
9387
|
+
if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0, import_node_path13.join)(home, ".config", "kilo");
|
|
9388
|
+
if (surface === "cursor") return (0, import_node_path13.join)(home, ".cursor");
|
|
9211
9389
|
if (surface === "jervcode") {
|
|
9212
|
-
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0,
|
|
9390
|
+
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path13.join)(home, ".jerv", "agent");
|
|
9213
9391
|
}
|
|
9214
|
-
return (0,
|
|
9392
|
+
return (0, import_node_path13.join)(home, ".claude");
|
|
9215
9393
|
}
|
|
9216
9394
|
var installedPluginsPath = (surface = detectSurface(process.env)) => {
|
|
9217
|
-
return (0,
|
|
9395
|
+
return (0, import_node_path13.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
|
|
9218
9396
|
};
|
|
9219
9397
|
function readInstalledPlugins(surface = detectSurface(process.env)) {
|
|
9220
9398
|
try {
|
|
@@ -9227,15 +9405,15 @@ function marketplaceCloneCandidates(surface, home, env = process.env) {
|
|
|
9227
9405
|
if (surface === "codex") {
|
|
9228
9406
|
const root = surfaceConfigRoot(surface, env, home);
|
|
9229
9407
|
return [
|
|
9230
|
-
(0,
|
|
9231
|
-
(0,
|
|
9408
|
+
(0, import_node_path13.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
|
|
9409
|
+
(0, import_node_path13.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
|
|
9232
9410
|
];
|
|
9233
9411
|
}
|
|
9234
9412
|
if (surface === "kimi") return [];
|
|
9235
9413
|
if (surface === "kilo") return [];
|
|
9236
9414
|
if (surface === "cursor") return [];
|
|
9237
9415
|
if (surface === "jervcode") return [];
|
|
9238
|
-
return [(0,
|
|
9416
|
+
return [(0, import_node_path13.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
|
|
9239
9417
|
}
|
|
9240
9418
|
function marketplaceClonePresent(surface, home, exists = import_node_fs14.existsSync, env = process.env) {
|
|
9241
9419
|
return marketplaceCloneCandidates(surface, home, env).some(exists);
|
|
@@ -9286,11 +9464,11 @@ function codexHookTrustState(status = codexPluginStatus()) {
|
|
|
9286
9464
|
return { applicable: false, trusted: false, trustedCount: 0, requiredCount: 0 };
|
|
9287
9465
|
}
|
|
9288
9466
|
const root = surfaceConfigRoot("codex");
|
|
9289
|
-
const hooksPath = (0,
|
|
9467
|
+
const hooksPath = (0, import_node_path13.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version, "hooks", "codex-hooks.json");
|
|
9290
9468
|
const requiredCount = countCodexHookCommands(hooksPath);
|
|
9291
9469
|
let config = "";
|
|
9292
9470
|
try {
|
|
9293
|
-
config = (0, import_node_fs14.readFileSync)((0,
|
|
9471
|
+
config = (0, import_node_fs14.readFileSync)((0, import_node_path13.join)(root, "config.toml"), "utf8");
|
|
9294
9472
|
} catch {
|
|
9295
9473
|
return { applicable: true, trusted: false, trustedCount: 0, requiredCount };
|
|
9296
9474
|
}
|
|
@@ -9317,7 +9495,7 @@ var NPM_INSTALL_TIMEOUT_MS = 12e4;
|
|
|
9317
9495
|
var CLI_VERSION_PROBE_TIMEOUT_MS = 3e4;
|
|
9318
9496
|
function resolveNpmSpawn(args) {
|
|
9319
9497
|
if (!isWin) return { file: "npm", args };
|
|
9320
|
-
const cli = (0,
|
|
9498
|
+
const cli = (0, import_node_path13.join)((0, import_node_path13.dirname)(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
9321
9499
|
if ((0, import_node_fs14.existsSync)(cli)) return { file: process.execPath, args: [cli, ...args] };
|
|
9322
9500
|
return { file: "cmd.exe", args: ["/c", "npm", ...args] };
|
|
9323
9501
|
}
|
|
@@ -9346,9 +9524,9 @@ async function npmSelfUpdateCli(target, onStep, deps = {}) {
|
|
|
9346
9524
|
}
|
|
9347
9525
|
function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)(), read = (p) => (0, import_node_fs14.readFileSync)(p, "utf8"), exists = import_node_fs14.existsSync) {
|
|
9348
9526
|
const candidates = ["kilo.json", "kilo.jsonc", "opencode.json", "opencode.jsonc", "config.json"];
|
|
9349
|
-
for (const dir of [configRoot, (0,
|
|
9527
|
+
for (const dir of [configRoot, (0, import_node_path13.join)(home, ".kilo")]) {
|
|
9350
9528
|
for (const file of candidates) {
|
|
9351
|
-
const path2 = (0,
|
|
9529
|
+
const path2 = (0, import_node_path13.join)(dir, file);
|
|
9352
9530
|
if (!exists(path2)) continue;
|
|
9353
9531
|
try {
|
|
9354
9532
|
const stripped = read(path2).replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
@@ -9365,7 +9543,7 @@ function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)()
|
|
|
9365
9543
|
return false;
|
|
9366
9544
|
}
|
|
9367
9545
|
function cursorLocalPluginRoot(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
9368
|
-
return (0,
|
|
9546
|
+
return (0, import_node_path13.join)(surfaceConfigRoot("cursor", env, home), "plugins", "local", "mmi");
|
|
9369
9547
|
}
|
|
9370
9548
|
function cursorPluginTreeHealthy(root, exists = import_node_fs14.existsSync) {
|
|
9371
9549
|
return [
|
|
@@ -9374,14 +9552,14 @@ function cursorPluginTreeHealthy(root, exists = import_node_fs14.existsSync) {
|
|
|
9374
9552
|
"hooks/cursor-hooks.json",
|
|
9375
9553
|
"scripts/hook-run.mjs",
|
|
9376
9554
|
"scripts/hook-policy.mjs"
|
|
9377
|
-
].every((path2) => exists((0,
|
|
9555
|
+
].every((path2) => exists((0, import_node_path13.join)(root, ...path2.split("/"))));
|
|
9378
9556
|
}
|
|
9379
9557
|
function kimiPluginTreeHealthy(root, exists = import_node_fs14.existsSync) {
|
|
9380
9558
|
return [
|
|
9381
9559
|
".kimi-plugin/plugin.json",
|
|
9382
9560
|
"skills/mmi/SKILL.md",
|
|
9383
9561
|
"scripts/hook-run.mjs"
|
|
9384
|
-
].every((path2) => exists((0,
|
|
9562
|
+
].every((path2) => exists((0, import_node_path13.join)(root, ...path2.split("/"))));
|
|
9385
9563
|
}
|
|
9386
9564
|
var JERVCODE_WRAPPER_DIR = ".pi-plugin";
|
|
9387
9565
|
function normalizePiEntry(value) {
|
|
@@ -9404,7 +9582,7 @@ function jervcodePackageFamily(entry) {
|
|
|
9404
9582
|
function isMmiOwnedPiEntry(entry) {
|
|
9405
9583
|
if (typeof entry !== "string") return false;
|
|
9406
9584
|
try {
|
|
9407
|
-
const pkg = JSON.parse((0, import_node_fs14.readFileSync)((0,
|
|
9585
|
+
const pkg = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path13.join)(piEntryFsPath(entry), "package.json"), "utf8"));
|
|
9408
9586
|
return pkg.name === "mmi";
|
|
9409
9587
|
} catch {
|
|
9410
9588
|
return false;
|
|
@@ -9436,8 +9614,8 @@ function readPiSettings(path2) {
|
|
|
9436
9614
|
}
|
|
9437
9615
|
}
|
|
9438
9616
|
function jervcodeSettingsCandidates(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
9439
|
-
const primary = (0,
|
|
9440
|
-
const legacy = (0,
|
|
9617
|
+
const primary = (0, import_node_path13.join)(surfaceConfigRoot("jervcode", env, home), "settings.json");
|
|
9618
|
+
const legacy = (0, import_node_path13.join)(home, ".pi", "agent", "settings.json");
|
|
9441
9619
|
return legacy === primary ? [primary] : [primary, legacy];
|
|
9442
9620
|
}
|
|
9443
9621
|
function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
@@ -9456,17 +9634,17 @@ function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir
|
|
|
9456
9634
|
function mmiPiWrapperHealthy(entry) {
|
|
9457
9635
|
if (!entry) return false;
|
|
9458
9636
|
const wrapper = piEntryFsPath(entry);
|
|
9459
|
-
return isMmiOwnedPiEntry(entry) && (0, import_node_fs14.existsSync)((0,
|
|
9637
|
+
return isMmiOwnedPiEntry(entry) && (0, import_node_fs14.existsSync)((0, import_node_path13.join)((0, import_node_path13.dirname)(wrapper), "skills", "mmi", "SKILL.md"));
|
|
9460
9638
|
}
|
|
9461
9639
|
function findMmiPiSourceClone(home = (0, import_node_os5.homedir)()) {
|
|
9462
|
-
const cacheRoot = (0,
|
|
9640
|
+
const cacheRoot = (0, import_node_path13.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi");
|
|
9463
9641
|
let best = null;
|
|
9464
9642
|
try {
|
|
9465
9643
|
for (const entry of (0, import_node_fs14.readdirSync)(cacheRoot, { withFileTypes: true })) {
|
|
9466
9644
|
if (!entry.isDirectory() || !/^\d+\.\d+\.\d+$/.test(entry.name)) continue;
|
|
9467
|
-
if (!(0, import_node_fs14.existsSync)((0,
|
|
9645
|
+
if (!(0, import_node_fs14.existsSync)((0, import_node_path13.join)(cacheRoot, entry.name, JERVCODE_WRAPPER_DIR, "package.json"))) continue;
|
|
9468
9646
|
if (!best || compareVersions(entry.name, best.version) > 0) {
|
|
9469
|
-
best = { path: (0,
|
|
9647
|
+
best = { path: (0, import_node_path13.join)(cacheRoot, entry.name), version: entry.name };
|
|
9470
9648
|
}
|
|
9471
9649
|
}
|
|
9472
9650
|
} catch {
|
|
@@ -9520,7 +9698,7 @@ function healOneJervCodeSettingsFile(settingsPath2, packagePath, version, nextLa
|
|
|
9520
9698
|
}
|
|
9521
9699
|
current.packages = merged.next;
|
|
9522
9700
|
try {
|
|
9523
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
9701
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(settingsPath2), { recursive: true });
|
|
9524
9702
|
const tmp = `${settingsPath2}.tmp-${process.pid}`;
|
|
9525
9703
|
(0, import_node_fs14.writeFileSync)(tmp, `${JSON.stringify(current, null, 2)}
|
|
9526
9704
|
`, "utf8");
|
|
@@ -9551,7 +9729,7 @@ function healJervCodePackageRegistration(opts = {}) {
|
|
|
9551
9729
|
const nextLaunch = inSeat ? " \u2014 takes effect on the next seat launch" : "";
|
|
9552
9730
|
const home = opts.home ?? (0, import_node_os5.homedir)();
|
|
9553
9731
|
const agentDir = surfaceConfigRoot("jervcode", env, home);
|
|
9554
|
-
const legacyPi = (0,
|
|
9732
|
+
const legacyPi = (0, import_node_path13.join)(home, ".pi", "agent");
|
|
9555
9733
|
if (!(0, import_node_fs14.existsSync)(agentDir) && !(0, import_node_fs14.existsSync)(legacyPi)) {
|
|
9556
9734
|
return { available: false, ok: true, changed: false, version: null, detail: "skipped \u2014 no Pi/JervCode install (no agent config dir)" };
|
|
9557
9735
|
}
|
|
@@ -9560,8 +9738,8 @@ function healJervCodePackageRegistration(opts = {}) {
|
|
|
9560
9738
|
return { available: true, ok: true, changed: false, version: null, detail: "skipped \u2014 no installed MMI clone carries the pi wrapper (install the Claude plugin first)" };
|
|
9561
9739
|
}
|
|
9562
9740
|
const packagePath = `${clone.path.replace(/\\/g, "/").replace(/\/+$/, "")}/${JERVCODE_WRAPPER_DIR}`;
|
|
9563
|
-
const targets = [(0,
|
|
9564
|
-
const legacySettings = (0,
|
|
9741
|
+
const targets = [(0, import_node_path13.join)(agentDir, "settings.json")];
|
|
9742
|
+
const legacySettings = (0, import_node_path13.join)(legacyPi, "settings.json");
|
|
9565
9743
|
if ((0, import_node_fs14.existsSync)(legacyPi) && legacySettings !== targets[0]) targets.push(legacySettings);
|
|
9566
9744
|
const details = [];
|
|
9567
9745
|
let anyChanged = false;
|
|
@@ -9590,7 +9768,7 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
|
|
|
9590
9768
|
return {
|
|
9591
9769
|
isOrgRepo,
|
|
9592
9770
|
installRecordPresent: hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()) || // Kimi's managed plugin directory is its native install record; it has no Claude-style ledger.
|
|
9593
|
-
surface === "kimi" && (0, import_node_fs14.existsSync)((0,
|
|
9771
|
+
surface === "kimi" && (0, import_node_fs14.existsSync)((0, import_node_path13.join)(root, "plugins", "managed", "mmi")) || // kilo-p1: the install record is the config file itself.
|
|
9594
9772
|
surface === "kilo" && kiloConfigListsPlugin(root) || // #4188: jervcode's install record is the settings-file packages[] entry itself.
|
|
9595
9773
|
surface === "jervcode" && piEntry !== null || surface === "cursor" && (0, import_node_fs14.existsSync)(cursorLocalPluginRoot()),
|
|
9596
9774
|
// Kilo has no marketplace to clone — the config file IS the install record, so this dimension of
|
|
@@ -9599,9 +9777,9 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
|
|
|
9599
9777
|
// Kimi keeps no plugin cache dir — installs are copied to plugins/managed/<id> and run from there.
|
|
9600
9778
|
// Kilo (kilo-p1) keeps no cache dir either: the plugin's server() provisions ~/.kilo behind the
|
|
9601
9779
|
// version stamp, so the stamp's presence is the cache signal.
|
|
9602
|
-
pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0, import_node_fs14.existsSync)((0,
|
|
9603
|
-
codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs14.existsSync)((0,
|
|
9604
|
-
) : (0, import_node_fs14.existsSync)((0,
|
|
9780
|
+
pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0, import_node_fs14.existsSync)((0, import_node_path13.join)((0, import_node_os5.homedir)(), ".kilo", ".mmi-kilo-version")) : surface === "kimi" ? kimiPluginTreeHealthy((0, import_node_path13.join)(root, "plugins", "managed", "mmi")) : surface === "cursor" ? cursorPluginTreeHealthy(cursorLocalPluginRoot()) : surface === "codex" ? Boolean(
|
|
9781
|
+
codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs14.existsSync)((0, import_node_path13.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
|
|
9782
|
+
) : (0, import_node_fs14.existsSync)((0, import_node_path13.join)(root, "plugins", "cache", "mutmutco", "mmi"))
|
|
9605
9783
|
};
|
|
9606
9784
|
}
|
|
9607
9785
|
async function runHostBinLogged(bin, args, opts) {
|
|
@@ -9621,9 +9799,9 @@ async function runPluginCli(bin, args, log) {
|
|
|
9621
9799
|
function captureCodexHookLauncher() {
|
|
9622
9800
|
const status = codexPluginStatus();
|
|
9623
9801
|
if (!status.installed || !status.enabled || !status.version) return void 0;
|
|
9624
|
-
const root = (0,
|
|
9802
|
+
const root = (0, import_node_path13.join)(surfaceConfigRoot("codex"), "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version);
|
|
9625
9803
|
const files = ["mmi-hook", "mmi-hook.exe"].flatMap((name) => {
|
|
9626
|
-
const path2 = (0,
|
|
9804
|
+
const path2 = (0, import_node_path13.join)(root, "bin", name);
|
|
9627
9805
|
try {
|
|
9628
9806
|
return [{ name, content: (0, import_node_fs14.readFileSync)(path2) }];
|
|
9629
9807
|
} catch {
|
|
@@ -9633,11 +9811,11 @@ function captureCodexHookLauncher() {
|
|
|
9633
9811
|
return files.length === 2 ? { root, files } : void 0;
|
|
9634
9812
|
}
|
|
9635
9813
|
function restoreCodexHookLauncher(snapshot) {
|
|
9636
|
-
if (!snapshot || (0, import_node_fs14.existsSync)((0,
|
|
9637
|
-
const bin = (0,
|
|
9814
|
+
if (!snapshot || (0, import_node_fs14.existsSync)((0, import_node_path13.join)(snapshot.root, "scripts", "hook-run.mjs"))) return false;
|
|
9815
|
+
const bin = (0, import_node_path13.join)(snapshot.root, "bin");
|
|
9638
9816
|
(0, import_node_fs14.mkdirSync)(bin, { recursive: true });
|
|
9639
9817
|
for (const file of snapshot.files) {
|
|
9640
|
-
const path2 = (0,
|
|
9818
|
+
const path2 = (0, import_node_path13.join)(bin, file.name);
|
|
9641
9819
|
(0, import_node_fs14.writeFileSync)(path2, file.content);
|
|
9642
9820
|
if (file.name === "mmi-hook") (0, import_node_fs14.chmodSync)(path2, 493);
|
|
9643
9821
|
}
|
|
@@ -9648,8 +9826,8 @@ function canonicalCursorRemote(remote) {
|
|
|
9648
9826
|
}
|
|
9649
9827
|
async function installCursorPluginCheckout(env = process.env) {
|
|
9650
9828
|
const configRoot = surfaceConfigRoot("cursor", env);
|
|
9651
|
-
const pluginsRoot = (0,
|
|
9652
|
-
const target = (0,
|
|
9829
|
+
const pluginsRoot = (0, import_node_path13.join)(configRoot, "plugins");
|
|
9830
|
+
const target = (0, import_node_path13.join)(pluginsRoot, "local", "mmi");
|
|
9653
9831
|
const source = env.MMI_CURSOR_PLUGIN_SOURCE?.trim();
|
|
9654
9832
|
if ((0, import_node_fs14.existsSync)(target) && !source) {
|
|
9655
9833
|
try {
|
|
@@ -9661,12 +9839,12 @@ async function installCursorPluginCheckout(env = process.env) {
|
|
|
9661
9839
|
return { ok: false, detail: `refused to replace unmanaged Cursor plugin directory at ${target}` };
|
|
9662
9840
|
}
|
|
9663
9841
|
}
|
|
9664
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
9665
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
9666
|
-
(0, import_node_fs14.mkdirSync)((0,
|
|
9842
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path13.join)(pluginsRoot, "local"), { recursive: true });
|
|
9843
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path13.join)(pluginsRoot, "staging"), { recursive: true });
|
|
9844
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path13.join)(pluginsRoot, "quarantine"), { recursive: true });
|
|
9667
9845
|
const suffix = `${Date.now()}-${process.pid}`;
|
|
9668
|
-
const staged = (0,
|
|
9669
|
-
const quarantined = (0,
|
|
9846
|
+
const staged = (0, import_node_path13.join)(pluginsRoot, "staging", `mmi-${suffix}`);
|
|
9847
|
+
const quarantined = (0, import_node_path13.join)(pluginsRoot, "quarantine", `mmi-${suffix}`);
|
|
9670
9848
|
try {
|
|
9671
9849
|
if (source) {
|
|
9672
9850
|
(0, import_node_fs14.cpSync)(source, staged, {
|
|
@@ -9737,7 +9915,7 @@ async function runHealSteps(host, tableSteps, deps) {
|
|
|
9737
9915
|
const refSupported = needsRefProbe ? await marketplaceAddRefSupported(host) : true;
|
|
9738
9916
|
const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
|
|
9739
9917
|
if (deps.banner) log(deps.banner(refSupported));
|
|
9740
|
-
const pinsPath = (0,
|
|
9918
|
+
const pinsPath = (0, import_node_path13.join)((0, import_node_os5.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
|
|
9741
9919
|
const pins = host === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
|
|
9742
9920
|
let failure;
|
|
9743
9921
|
try {
|
|
@@ -10048,7 +10226,7 @@ function describeUpdatePlan(hasBinary) {
|
|
|
10048
10226
|
|
|
10049
10227
|
// src/hook-activity.ts
|
|
10050
10228
|
var import_node_fs15 = require("node:fs");
|
|
10051
|
-
var
|
|
10229
|
+
var import_node_path14 = require("node:path");
|
|
10052
10230
|
var DEFAULT_SURFACE = "claude";
|
|
10053
10231
|
function activityLogPath(cwd) {
|
|
10054
10232
|
return repoRuntimeStatePath(cwd, "hooks", "activity.jsonl");
|
|
@@ -10061,7 +10239,7 @@ function appendHookActivity(cwd, entry) {
|
|
|
10061
10239
|
surface: DEFAULT_SURFACE,
|
|
10062
10240
|
...entry
|
|
10063
10241
|
};
|
|
10064
|
-
(0, import_node_fs15.mkdirSync)((0,
|
|
10242
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path14.dirname)(path2), { recursive: true });
|
|
10065
10243
|
(0, import_node_fs15.appendFileSync)(path2, `${JSON.stringify(line)}
|
|
10066
10244
|
`, "utf8");
|
|
10067
10245
|
} catch {
|
|
@@ -10070,11 +10248,11 @@ function appendHookActivity(cwd, entry) {
|
|
|
10070
10248
|
|
|
10071
10249
|
// src/worktree.ts
|
|
10072
10250
|
var import_node_fs16 = require("node:fs");
|
|
10073
|
-
var
|
|
10251
|
+
var import_node_path16 = require("node:path");
|
|
10074
10252
|
|
|
10075
10253
|
// src/file-lock.ts
|
|
10076
10254
|
var import_promises2 = require("node:fs/promises");
|
|
10077
|
-
var
|
|
10255
|
+
var import_node_path15 = require("node:path");
|
|
10078
10256
|
var sleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
10079
10257
|
var IMMEDIATE_RETRY_BUDGET = 3;
|
|
10080
10258
|
var FileLockBusyError = class extends Error {
|
|
@@ -10159,7 +10337,7 @@ async function releaseFileLock(lockPath, guard) {
|
|
|
10159
10337
|
}
|
|
10160
10338
|
async function withFileLock(lockPath, opts, fn) {
|
|
10161
10339
|
const resolved = resolveFileLockOpts(opts);
|
|
10162
|
-
await (0, import_promises2.mkdir)((0,
|
|
10340
|
+
await (0, import_promises2.mkdir)((0, import_node_path15.dirname)(lockPath), { recursive: true }).catch(() => void 0);
|
|
10163
10341
|
const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
|
|
10164
10342
|
try {
|
|
10165
10343
|
return await fn();
|
|
@@ -10214,7 +10392,7 @@ var realFsProbe = {
|
|
|
10214
10392
|
}
|
|
10215
10393
|
};
|
|
10216
10394
|
function declaredProvision(fs2, abs) {
|
|
10217
|
-
const raw = fs2.readFile?.((0,
|
|
10395
|
+
const raw = fs2.readFile?.((0, import_node_path16.join)(abs, PKG));
|
|
10218
10396
|
if (raw === void 0) return void 0;
|
|
10219
10397
|
try {
|
|
10220
10398
|
const scripts = JSON.parse(raw).scripts;
|
|
@@ -10226,13 +10404,13 @@ function declaredProvision(fs2, abs) {
|
|
|
10226
10404
|
}
|
|
10227
10405
|
function scanInstallDirs(root, fs2 = realFsProbe) {
|
|
10228
10406
|
const factsFor = (dir) => {
|
|
10229
|
-
const abs = dir ? (0,
|
|
10230
|
-
const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0,
|
|
10231
|
-
const hasPackageJson = fs2.isFile((0,
|
|
10407
|
+
const abs = dir ? (0, import_node_path16.join)(root, dir) : root;
|
|
10408
|
+
const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0, import_node_path16.join)(abs, c.lockfile)));
|
|
10409
|
+
const hasPackageJson = fs2.isFile((0, import_node_path16.join)(abs, PKG));
|
|
10232
10410
|
return {
|
|
10233
10411
|
dir,
|
|
10234
10412
|
hasPackageJson,
|
|
10235
|
-
hasNodeModules: fs2.isDir((0,
|
|
10413
|
+
hasNodeModules: fs2.isDir((0, import_node_path16.join)(abs, NODE_MODULES)),
|
|
10236
10414
|
install: match?.command,
|
|
10237
10415
|
provision: hasPackageJson ? declaredProvision(fs2, abs) : void 0
|
|
10238
10416
|
};
|
|
@@ -10248,7 +10426,7 @@ function npmInstallTargets(dirs) {
|
|
|
10248
10426
|
}));
|
|
10249
10427
|
}
|
|
10250
10428
|
function isLinkedWorktree(root, fs2 = realFsProbe) {
|
|
10251
|
-
return fs2.isFile((0,
|
|
10429
|
+
return fs2.isFile((0, import_node_path16.join)(root, ".git"));
|
|
10252
10430
|
}
|
|
10253
10431
|
function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
10254
10432
|
if (!isLinkedWorktree(root, fs2)) return null;
|
|
@@ -10258,7 +10436,7 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
|
10258
10436
|
return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
|
|
10259
10437
|
}
|
|
10260
10438
|
function defaultCopyFile(from, to) {
|
|
10261
|
-
(0, import_node_fs16.mkdirSync)((0,
|
|
10439
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path16.dirname)(to), { recursive: true });
|
|
10262
10440
|
(0, import_node_fs16.copyFileSync)(from, to);
|
|
10263
10441
|
}
|
|
10264
10442
|
async function runDeclaredProvision(target, cwd, runInstall) {
|
|
@@ -10289,7 +10467,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
10289
10467
|
const targets = npmInstallTargets(allDirs);
|
|
10290
10468
|
if (deps.validateInstall) {
|
|
10291
10469
|
for (const dir of allDirs.filter((d) => d.hasPackageJson && (d.provision ?? d.install) && d.hasNodeModules)) {
|
|
10292
|
-
const cwd = dir.dir ? (0,
|
|
10470
|
+
const cwd = dir.dir ? (0, import_node_path16.join)(worktreeRoot, dir.dir) : worktreeRoot;
|
|
10293
10471
|
if (!await deps.validateInstall(cwd)) {
|
|
10294
10472
|
targets.push({
|
|
10295
10473
|
dir: dir.dir,
|
|
@@ -10303,7 +10481,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
10303
10481
|
const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules && !targetDirs.has(d.dir)).map((d) => d.dir);
|
|
10304
10482
|
const installed = [];
|
|
10305
10483
|
for (const target of targets) {
|
|
10306
|
-
const cwd = target.dir ? (0,
|
|
10484
|
+
const cwd = target.dir ? (0, import_node_path16.join)(worktreeRoot, target.dir) : worktreeRoot;
|
|
10307
10485
|
log(`installing deps: ${target.command} in ${target.dir || "."}`);
|
|
10308
10486
|
if (target.declared) await runDeclaredProvision(target, cwd, deps.runInstall);
|
|
10309
10487
|
else await deps.runInstall(target.command, cwd);
|
|
@@ -10313,7 +10491,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
10313
10491
|
const copySkipped = [];
|
|
10314
10492
|
const primary = await deps.primaryCheckout();
|
|
10315
10493
|
for (const rel of LOCAL_ONLY_FILES) {
|
|
10316
|
-
const dest = (0,
|
|
10494
|
+
const dest = (0, import_node_path16.join)(worktreeRoot, rel);
|
|
10317
10495
|
if (fs2.isFile(dest)) {
|
|
10318
10496
|
copySkipped.push({ file: rel, reason: "already-present" });
|
|
10319
10497
|
continue;
|
|
@@ -10322,11 +10500,11 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
10322
10500
|
copySkipped.push({ file: rel, reason: "no-primary" });
|
|
10323
10501
|
continue;
|
|
10324
10502
|
}
|
|
10325
|
-
if (!fs2.isFile((0,
|
|
10503
|
+
if (!fs2.isFile((0, import_node_path16.join)(primary, rel))) {
|
|
10326
10504
|
copySkipped.push({ file: rel, reason: "absent-in-primary" });
|
|
10327
10505
|
continue;
|
|
10328
10506
|
}
|
|
10329
|
-
copyFile((0,
|
|
10507
|
+
copyFile((0, import_node_path16.join)(primary, rel), dest);
|
|
10330
10508
|
copied.push(rel);
|
|
10331
10509
|
log(`copied local config: ${rel}`);
|
|
10332
10510
|
}
|
|
@@ -10340,12 +10518,12 @@ function capWorktreeDirName(name, max = 40) {
|
|
|
10340
10518
|
}
|
|
10341
10519
|
function defaultWorktreePath(repoRoot2, branch) {
|
|
10342
10520
|
const safe = capWorktreeDirName(branch.replace(/[/\\]+/g, "-"));
|
|
10343
|
-
return (0,
|
|
10521
|
+
return (0, import_node_path16.join)((0, import_node_path16.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path16.basename)(repoRoot2), safe);
|
|
10344
10522
|
}
|
|
10345
10523
|
async function primaryCheckoutRootOf(git2) {
|
|
10346
10524
|
try {
|
|
10347
10525
|
const out = (await git2(["rev-parse", "--path-format=absolute", "--git-common-dir"])).trim();
|
|
10348
|
-
return out ? (0,
|
|
10526
|
+
return out ? (0, import_node_path16.dirname)(out) : void 0;
|
|
10349
10527
|
} catch {
|
|
10350
10528
|
return void 0;
|
|
10351
10529
|
}
|
|
@@ -10488,7 +10666,7 @@ function commandLadderHint() {
|
|
|
10488
10666
|
}
|
|
10489
10667
|
|
|
10490
10668
|
// src/index.ts
|
|
10491
|
-
var
|
|
10669
|
+
var import_node_path46 = require("node:path");
|
|
10492
10670
|
|
|
10493
10671
|
// src/merge-ci-policy.ts
|
|
10494
10672
|
function resolveMergeCiPolicy(input) {
|
|
@@ -11162,12 +11340,12 @@ function planManagedGitignore(current) {
|
|
|
11162
11340
|
|
|
11163
11341
|
// src/docs-index-command.ts
|
|
11164
11342
|
var import_node_fs18 = require("node:fs");
|
|
11165
|
-
var
|
|
11343
|
+
var import_node_path18 = require("node:path");
|
|
11166
11344
|
|
|
11167
11345
|
// src/doc-refs-core.ts
|
|
11168
11346
|
var import_node_child_process7 = require("node:child_process");
|
|
11169
11347
|
var import_node_fs17 = require("node:fs");
|
|
11170
|
-
var
|
|
11348
|
+
var import_node_path17 = require("node:path");
|
|
11171
11349
|
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
11172
11350
|
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
11173
11351
|
var FWD_RE = /<!--\s*forward-ref:\s*(\S+?)\s*-->/;
|
|
@@ -11226,7 +11404,7 @@ function checkPins(root, readFile9, docs2) {
|
|
|
11226
11404
|
findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
|
|
11227
11405
|
continue;
|
|
11228
11406
|
}
|
|
11229
|
-
const source = readFile9((0,
|
|
11407
|
+
const source = readFile9((0, import_node_path17.join)(root, pin.file));
|
|
11230
11408
|
if (source == null) {
|
|
11231
11409
|
findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
|
|
11232
11410
|
continue;
|
|
@@ -11288,11 +11466,11 @@ function checkRefs(root, deps, docs2) {
|
|
|
11288
11466
|
for (const { ref } of extractRefs(markdown)) allFirstSegments.add(refFirstSegment(ref));
|
|
11289
11467
|
}
|
|
11290
11468
|
const tracked = allFirstSegments.size ? deps.trackedFirstSegments?.([...allFirstSegments]) ?? null : null;
|
|
11291
|
-
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0,
|
|
11469
|
+
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path17.join)(root, first));
|
|
11292
11470
|
const candidates = [];
|
|
11293
11471
|
const direct = [];
|
|
11294
11472
|
for (const [doc, markdown] of Object.entries(docs2)) {
|
|
11295
|
-
const docDir =
|
|
11473
|
+
const docDir = import_node_path17.posix.dirname(doc);
|
|
11296
11474
|
const base = docDir === "." ? "" : docDir;
|
|
11297
11475
|
const covered = /* @__PURE__ */ new Set();
|
|
11298
11476
|
const markers = [];
|
|
@@ -11301,21 +11479,21 @@ function checkRefs(root, deps, docs2) {
|
|
|
11301
11479
|
direct.push({ kind: "malformed-forward-ref", doc, line: fwd.line, detail: fwd.text });
|
|
11302
11480
|
continue;
|
|
11303
11481
|
}
|
|
11304
|
-
const docRel =
|
|
11305
|
-
const rootRel =
|
|
11482
|
+
const docRel = import_node_path17.posix.normalize(import_node_path17.posix.join(base, fwd.target));
|
|
11483
|
+
const rootRel = import_node_path17.posix.normalize(fwd.target.replace(/^\/+/, ""));
|
|
11306
11484
|
markers.push({ target: fwd.target, line: fwd.line, docRel, rootRel });
|
|
11307
11485
|
covered.add(docRel);
|
|
11308
11486
|
covered.add(rootRel);
|
|
11309
11487
|
}
|
|
11310
11488
|
const links = extractLinks(markdown).map(({ target, line }) => {
|
|
11311
|
-
const resolved =
|
|
11312
|
-
return { target, line, resolved, missing: !exists((0,
|
|
11489
|
+
const resolved = import_node_path17.posix.normalize(import_node_path17.posix.join(base, target));
|
|
11490
|
+
return { target, line, resolved, missing: !exists((0, import_node_path17.join)(root, resolved)) };
|
|
11313
11491
|
});
|
|
11314
11492
|
for (const marker of markers) {
|
|
11315
11493
|
const coversMissing = links.some(
|
|
11316
11494
|
(l) => l.missing && (l.resolved === marker.docRel || l.resolved === marker.rootRel)
|
|
11317
11495
|
);
|
|
11318
|
-
if (!coversMissing && (exists((0,
|
|
11496
|
+
if (!coversMissing && (exists((0, import_node_path17.join)(root, marker.docRel)) || exists((0, import_node_path17.join)(root, marker.rootRel)))) {
|
|
11319
11497
|
direct.push({
|
|
11320
11498
|
kind: "stale-forward-ref",
|
|
11321
11499
|
doc,
|
|
@@ -11326,7 +11504,7 @@ function checkRefs(root, deps, docs2) {
|
|
|
11326
11504
|
}
|
|
11327
11505
|
for (const { ref, line } of extractRefs(markdown)) {
|
|
11328
11506
|
if (!firstVerifiable(refFirstSegment(ref))) continue;
|
|
11329
|
-
if (!exists((0,
|
|
11507
|
+
if (!exists((0, import_node_path17.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
|
|
11330
11508
|
}
|
|
11331
11509
|
for (const { target, line, resolved, missing } of links) {
|
|
11332
11510
|
if (resolved.startsWith("..")) {
|
|
@@ -11378,18 +11556,18 @@ function readFileOrNull(path2) {
|
|
|
11378
11556
|
}
|
|
11379
11557
|
function walk(dir, root, out) {
|
|
11380
11558
|
for (const entry of (0, import_node_fs17.readdirSync)(dir)) {
|
|
11381
|
-
const full = (0,
|
|
11559
|
+
const full = (0, import_node_path17.join)(dir, entry);
|
|
11382
11560
|
if ((0, import_node_fs17.statSync)(full).isDirectory()) walk(full, root, out);
|
|
11383
11561
|
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
11384
11562
|
}
|
|
11385
11563
|
return out;
|
|
11386
11564
|
}
|
|
11387
11565
|
function defaultListDocs(root) {
|
|
11388
|
-
const docsDir = (0,
|
|
11566
|
+
const docsDir = (0, import_node_path17.join)(root, "docs");
|
|
11389
11567
|
const docs2 = ((0, import_node_fs17.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
|
|
11390
11568
|
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
11391
11569
|
);
|
|
11392
|
-
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs17.existsSync)((0,
|
|
11570
|
+
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs17.existsSync)((0, import_node_path17.join)(root, rel))), ...docs2];
|
|
11393
11571
|
}
|
|
11394
11572
|
var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
|
|
11395
11573
|
function defaultIsIgnored(root, relPaths, exec = import_node_child_process7.execFileSync) {
|
|
@@ -11449,7 +11627,7 @@ function runDocRefs(root, deps = {}) {
|
|
|
11449
11627
|
const walked = listDocs(root);
|
|
11450
11628
|
const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
|
|
11451
11629
|
const docs2 = Object.fromEntries(
|
|
11452
|
-
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0,
|
|
11630
|
+
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0, import_node_path17.join)(root, rel))]).filter(([, body]) => body != null)
|
|
11453
11631
|
);
|
|
11454
11632
|
const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs2);
|
|
11455
11633
|
const findings = [
|
|
@@ -11557,19 +11735,19 @@ function walkMarkdown(dir) {
|
|
|
11557
11735
|
while (stack.length) {
|
|
11558
11736
|
const current = stack.pop();
|
|
11559
11737
|
for (const entry of (0, import_node_fs18.readdirSync)(current, { withFileTypes: true })) {
|
|
11560
|
-
const full = (0,
|
|
11738
|
+
const full = (0, import_node_path18.join)(current, entry.name);
|
|
11561
11739
|
if (entry.isDirectory()) {
|
|
11562
11740
|
stack.push(full);
|
|
11563
11741
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
11564
|
-
out.push((0,
|
|
11742
|
+
out.push((0, import_node_path18.relative)(dir, full).split(import_node_path18.sep).join("/"));
|
|
11565
11743
|
}
|
|
11566
11744
|
}
|
|
11567
11745
|
}
|
|
11568
11746
|
return out;
|
|
11569
11747
|
}
|
|
11570
11748
|
function createDocsIndexDeps(repoRoot2) {
|
|
11571
|
-
const docsDir = (0,
|
|
11572
|
-
const indexPath = (0,
|
|
11749
|
+
const docsDir = (0, import_node_path18.join)(repoRoot2, "docs");
|
|
11750
|
+
const indexPath = (0, import_node_path18.join)(repoRoot2, DOCS_INDEX_PATH);
|
|
11573
11751
|
return {
|
|
11574
11752
|
listDocs: () => {
|
|
11575
11753
|
if (!(0, import_node_fs18.existsSync)(docsDir)) return [];
|
|
@@ -11578,7 +11756,7 @@ function createDocsIndexDeps(repoRoot2) {
|
|
|
11578
11756
|
const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
|
|
11579
11757
|
return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
|
|
11580
11758
|
},
|
|
11581
|
-
readDoc: (relPath) => (0, import_node_fs18.readFileSync)((0,
|
|
11759
|
+
readDoc: (relPath) => (0, import_node_fs18.readFileSync)((0, import_node_path18.join)(docsDir, relPath), "utf8"),
|
|
11582
11760
|
readIndex: () => (0, import_node_fs18.existsSync)(indexPath) ? (0, import_node_fs18.readFileSync)(indexPath, "utf8") : null,
|
|
11583
11761
|
writeIndex: (content) => (0, import_node_fs18.writeFileSync)(indexPath, content, "utf8")
|
|
11584
11762
|
};
|
|
@@ -12373,7 +12551,7 @@ function parseVerifyBroker(stdout) {
|
|
|
12373
12551
|
// src/train-apply.ts
|
|
12374
12552
|
var import_node_fs21 = require("node:fs");
|
|
12375
12553
|
var import_promises4 = require("node:fs/promises");
|
|
12376
|
-
var
|
|
12554
|
+
var import_node_path21 = require("node:path");
|
|
12377
12555
|
|
|
12378
12556
|
// src/bootstrap-org-ruleset.ts
|
|
12379
12557
|
var ORG_NO_AGENT_FILES_RULESET_NAME = "mmi-no-agent-files-org";
|
|
@@ -12846,7 +13024,7 @@ function renderAccessReport(report) {
|
|
|
12846
13024
|
|
|
12847
13025
|
// src/cli-doctor-shared.ts
|
|
12848
13026
|
var import_node_fs19 = require("node:fs");
|
|
12849
|
-
var
|
|
13027
|
+
var import_node_path20 = require("node:path");
|
|
12850
13028
|
var import_node_fs20 = require("node:fs");
|
|
12851
13029
|
|
|
12852
13030
|
// ../infra/registry-endpoints.mjs
|
|
@@ -12976,9 +13154,9 @@ function extractWorkflowCrons(yamlText) {
|
|
|
12976
13154
|
function workflowEntry(repo, workflowPath, yamlText) {
|
|
12977
13155
|
const crons = extractWorkflowCrons(yamlText);
|
|
12978
13156
|
if (!crons.length) return null;
|
|
12979
|
-
const
|
|
13157
|
+
const basename8 = workflowPath.split("/").pop() ?? workflowPath;
|
|
12980
13158
|
return {
|
|
12981
|
-
name: `${repo}/${
|
|
13159
|
+
name: `${repo}/${basename8.replace(/\.ya?ml$/, "")}`,
|
|
12982
13160
|
cadence: crons.join(" + "),
|
|
12983
13161
|
executor: "github-actions",
|
|
12984
13162
|
llm: llmFromHeader(yamlText),
|
|
@@ -13388,8 +13566,8 @@ function scheduleRecordFromWorkflow(repo, workflowPath, yamlText) {
|
|
|
13388
13566
|
const crons = extractWorkflowCrons(yamlText);
|
|
13389
13567
|
const header = parseScheduleHeader(yamlText);
|
|
13390
13568
|
if (!crons.length && !header.schedule) return null;
|
|
13391
|
-
const
|
|
13392
|
-
const expectedId = `${repo}/${
|
|
13569
|
+
const basename8 = workflowPath.split("/").pop() ?? workflowPath;
|
|
13570
|
+
const expectedId = `${repo}/${basename8.replace(/\.ya?ml$/, "")}`;
|
|
13393
13571
|
if (isHarbourUnmanaged(yamlText)) return null;
|
|
13394
13572
|
const missing = SCHEDULE_HEADER_FIELDS.filter((f) => !header[f]);
|
|
13395
13573
|
if (missing.length) {
|
|
@@ -13764,7 +13942,7 @@ var import_node_os7 = require("node:os");
|
|
|
13764
13942
|
// src/gh-create.ts
|
|
13765
13943
|
var import_promises3 = require("node:fs/promises");
|
|
13766
13944
|
var import_node_os6 = require("node:os");
|
|
13767
|
-
var
|
|
13945
|
+
var import_node_path19 = require("node:path");
|
|
13768
13946
|
var import_node_crypto3 = require("node:crypto");
|
|
13769
13947
|
|
|
13770
13948
|
// src/board-priority.ts
|
|
@@ -13847,8 +14025,8 @@ async function bodyArgsViaFile(args, deps = {}) {
|
|
|
13847
14025
|
const remove2 = deps.remove ?? import_promises3.unlink;
|
|
13848
14026
|
const ensureDir = deps.ensureDir ?? import_promises3.mkdir;
|
|
13849
14027
|
const dir = deps.dir ?? (0, import_node_os6.tmpdir)();
|
|
13850
|
-
const file = (0,
|
|
13851
|
-
await ensureDir((0,
|
|
14028
|
+
const file = (0, import_node_path19.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
|
|
14029
|
+
await ensureDir((0, import_node_path19.dirname)(file), { recursive: true }).catch(() => {
|
|
13852
14030
|
});
|
|
13853
14031
|
await write(file, args[i + 1], "utf8");
|
|
13854
14032
|
return {
|
|
@@ -15391,7 +15569,7 @@ async function localBranchHeads() {
|
|
|
15391
15569
|
}
|
|
15392
15570
|
async function currentRepoWorktreeGitRoot(repoRoot2) {
|
|
15393
15571
|
const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
15394
|
-
return gitCommonDir ? (0,
|
|
15572
|
+
return gitCommonDir ? (0, import_node_path20.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
|
|
15395
15573
|
}
|
|
15396
15574
|
async function worktreeBranches() {
|
|
15397
15575
|
const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
|
|
@@ -15411,7 +15589,7 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
|
|
|
15411
15589
|
const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
|
|
15412
15590
|
if (!match?.[1]) return void 0;
|
|
15413
15591
|
const raw = match[1].trim();
|
|
15414
|
-
return (0,
|
|
15592
|
+
return (0, import_node_path20.isAbsolute)(raw) ? raw : (0, import_node_path20.resolve)(worktreePath, raw);
|
|
15415
15593
|
}
|
|
15416
15594
|
function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
15417
15595
|
if (!worktreeGitRoot) return false;
|
|
@@ -15420,9 +15598,9 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
|
15420
15598
|
for (const ent of entries) {
|
|
15421
15599
|
if (!ent.isDirectory()) continue;
|
|
15422
15600
|
try {
|
|
15423
|
-
const gitdirPath = (0, import_node_fs19.readFileSync)((0,
|
|
15424
|
-
const resolvedGitdir = (0,
|
|
15425
|
-
if (sameWorktreeMetadataPath((0,
|
|
15601
|
+
const gitdirPath = (0, import_node_fs19.readFileSync)((0, import_node_path20.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
|
|
15602
|
+
const resolvedGitdir = (0, import_node_path20.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path20.resolve)(worktreeGitRoot, ent.name, gitdirPath);
|
|
15603
|
+
if (sameWorktreeMetadataPath((0, import_node_path20.dirname)(resolvedGitdir), worktreePath)) return true;
|
|
15426
15604
|
} catch {
|
|
15427
15605
|
}
|
|
15428
15606
|
}
|
|
@@ -15441,7 +15619,7 @@ function pathExistsKnown(path2) {
|
|
|
15441
15619
|
}
|
|
15442
15620
|
}
|
|
15443
15621
|
function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
15444
|
-
const gitPath = (0,
|
|
15622
|
+
const gitPath = (0, import_node_path20.join)(path2, ".git");
|
|
15445
15623
|
let st;
|
|
15446
15624
|
try {
|
|
15447
15625
|
st = (0, import_node_fs20.lstatSync)(gitPath);
|
|
@@ -15495,24 +15673,25 @@ async function preservedBranches() {
|
|
|
15495
15673
|
async function siblingWorktreeDirs(explicitRoot) {
|
|
15496
15674
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
15497
15675
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
15498
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
15676
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path20.dirname)((0, import_node_path20.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
15499
15677
|
try {
|
|
15500
15678
|
const dirs = explicitRoot ? listDirsIn(resolveExplicitScanRoot(explicitRoot, primaryRepoRoot)) : worktreeScanDirs(siblingMmiWorktreesRoot(primaryRepoRoot), primaryRepoRoot, listDirsIn, isRepoCheckoutDir);
|
|
15501
15679
|
const agentDirs2 = listDirsIn(agentWorktreesRoot(primaryRepoRoot));
|
|
15502
|
-
|
|
15680
|
+
const repoLocalWorktrees = listDirsIn((0, import_node_path20.join)(primaryRepoRoot, ".worktrees"));
|
|
15681
|
+
return [...dirs, ...agentDirs2, ...repoLocalWorktrees].map((dir) => inspectSiblingWorktreeDir(dir, worktreeGitRoot)).filter((entry) => Boolean(entry));
|
|
15503
15682
|
} catch {
|
|
15504
15683
|
return [];
|
|
15505
15684
|
}
|
|
15506
15685
|
}
|
|
15507
15686
|
function listDirsIn(dir) {
|
|
15508
15687
|
try {
|
|
15509
|
-
return (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0,
|
|
15688
|
+
return (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path20.join)(dir, ent.name));
|
|
15510
15689
|
} catch {
|
|
15511
15690
|
return [];
|
|
15512
15691
|
}
|
|
15513
15692
|
}
|
|
15514
15693
|
function isRepoCheckoutDir(dir) {
|
|
15515
|
-
return (0, import_node_fs20.existsSync)((0,
|
|
15694
|
+
return (0, import_node_fs20.existsSync)((0, import_node_path20.join)(dir, ".git"));
|
|
15516
15695
|
}
|
|
15517
15696
|
function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
|
|
15518
15697
|
let rootDirs;
|
|
@@ -15524,7 +15703,7 @@ function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
|
|
|
15524
15703
|
return explicitRepoWorktreesRoot(explicitRoot, repoRoot2, rootDirs);
|
|
15525
15704
|
}
|
|
15526
15705
|
async function gcPlan(remote, limit, opts = {}) {
|
|
15527
|
-
const [branches, heads, current, stale, worktrees, siblingDirs, preserved, mergedIntoBase] = await Promise.all([
|
|
15706
|
+
const [branches, heads, current, stale, worktrees, siblingDirs, preserved, mergedIntoBase, originListed] = await Promise.all([
|
|
15528
15707
|
gitOut(["branch", "--format=%(refname:short)"]),
|
|
15529
15708
|
localBranchHeads(),
|
|
15530
15709
|
gitOut(["rev-parse", "--abbrev-ref", "HEAD"]),
|
|
@@ -15534,11 +15713,18 @@ async function gcPlan(remote, limit, opts = {}) {
|
|
|
15534
15713
|
worktreeBranches(),
|
|
15535
15714
|
siblingWorktreeDirs(opts.root),
|
|
15536
15715
|
preservedBranches(),
|
|
15537
|
-
branchesMergedIntoBase(remote)
|
|
15716
|
+
branchesMergedIntoBase(remote),
|
|
15717
|
+
gitOut(["branch", "-r", "--format=%(refname:short)"]).catch(() => "")
|
|
15538
15718
|
]);
|
|
15539
15719
|
const localBranches = branches.split(/\r?\n/).map((b) => b.trim()).filter(Boolean);
|
|
15720
|
+
const originBranches = originListed.split(/\r?\n/).map((b) => b.trim()).filter((b) => b.startsWith(`${remote}/`) && b !== `${remote}/HEAD`);
|
|
15721
|
+
const originNames = originBranches.map((b) => b.slice(remote.length + 1));
|
|
15540
15722
|
const { prs, failures } = await resolveBranchPrs(
|
|
15541
|
-
[
|
|
15723
|
+
[.../* @__PURE__ */ new Set([
|
|
15724
|
+
...localBranches,
|
|
15725
|
+
...stale.map((ref) => branchForTrackingRef(ref, remote)).filter((b) => Boolean(b)),
|
|
15726
|
+
...originNames
|
|
15727
|
+
])].filter((b) => !isProtectedBranch(b)),
|
|
15542
15728
|
limit
|
|
15543
15729
|
);
|
|
15544
15730
|
return buildGcPlan({
|
|
@@ -15552,7 +15738,9 @@ async function gcPlan(remote, limit, opts = {}) {
|
|
|
15552
15738
|
worktrees,
|
|
15553
15739
|
remote,
|
|
15554
15740
|
preservedBranches: preserved,
|
|
15555
|
-
mergedIntoBase
|
|
15741
|
+
mergedIntoBase,
|
|
15742
|
+
originBranches,
|
|
15743
|
+
trainOnly: opts.trainOnly
|
|
15556
15744
|
});
|
|
15557
15745
|
}
|
|
15558
15746
|
async function branchesMergedIntoBase(remote) {
|
|
@@ -15849,10 +16037,10 @@ var rollout_plan_default = {
|
|
|
15849
16037
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
15850
16038
|
},
|
|
15851
16039
|
baseline: {
|
|
15852
|
-
version: "3.
|
|
15853
|
-
tag: "v3.
|
|
15854
|
-
commit: "
|
|
15855
|
-
npm: "@mutmutco/cli@3.
|
|
16040
|
+
version: "3.128.0",
|
|
16041
|
+
tag: "v3.128.0",
|
|
16042
|
+
commit: "95241fa22be9",
|
|
16043
|
+
npm: "@mutmutco/cli@3.128.0"
|
|
15856
16044
|
},
|
|
15857
16045
|
exitCriterion: "fleet-n-of-n",
|
|
15858
16046
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15869,14 +16057,14 @@ var rollout_plan_default = {
|
|
|
15869
16057
|
repo: "mutmutco/mmi-hub",
|
|
15870
16058
|
role: "canary",
|
|
15871
16059
|
schedule: "train",
|
|
15872
|
-
v3Target: "v3.
|
|
16060
|
+
v3Target: "v3.128.0"
|
|
15873
16061
|
}
|
|
15874
16062
|
],
|
|
15875
16063
|
rollbackTrigger: "Any red inside the post-cut soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a v3 client refused while the compat window must still admit it (SUPPORTED_MINOR_WINDOW=2, MIN_CLIENT_VERSION 0.0.0 \u2014 D6a), or npm consumer install/doctor failure on the v4 dist.",
|
|
15876
16064
|
rollback: {
|
|
15877
16065
|
independent: true,
|
|
15878
|
-
mechanism: "npm dist-tag latest -> 3.
|
|
15879
|
-
v3Target: "v3.
|
|
16066
|
+
mechanism: "npm dist-tag latest -> 3.128.0 and redeploy the Hub Lambda from tag v3.128.0 (95241fa22be9); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
16067
|
+
v3Target: "v3.128.0 (@mutmutco/cli@3.128.0, tag commit 95241fa22be9 \u2014 the preserved latest-v3 distribution, D6b)"
|
|
15880
16068
|
}
|
|
15881
16069
|
},
|
|
15882
16070
|
{
|
|
@@ -18125,7 +18313,7 @@ function publishVisibilityFor(surfaceId) {
|
|
|
18125
18313
|
}
|
|
18126
18314
|
function npmPackArtifactName(packagePath) {
|
|
18127
18315
|
try {
|
|
18128
|
-
const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0,
|
|
18316
|
+
const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path21.join)(packagePath, "package.json"), "utf8"));
|
|
18129
18317
|
return pkg.name || void 0;
|
|
18130
18318
|
} catch {
|
|
18131
18319
|
return void 0;
|
|
@@ -19296,7 +19484,7 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
|
|
|
19296
19484
|
return { note: `no manual dispatch: ${model} repo deploys via its own push-triggered workflow`, deployStatus: "pending" };
|
|
19297
19485
|
}
|
|
19298
19486
|
function readLocalGateWorkflows() {
|
|
19299
|
-
const dir = (0,
|
|
19487
|
+
const dir = (0, import_node_path21.join)(".github", "workflows");
|
|
19300
19488
|
let names;
|
|
19301
19489
|
try {
|
|
19302
19490
|
names = (0, import_node_fs21.readdirSync)(dir);
|
|
@@ -19306,7 +19494,7 @@ function readLocalGateWorkflows() {
|
|
|
19306
19494
|
const files = [];
|
|
19307
19495
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
19308
19496
|
try {
|
|
19309
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs21.readFileSync)((0,
|
|
19497
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs21.readFileSync)((0, import_node_path21.join)(dir, name), "utf8") });
|
|
19310
19498
|
} catch {
|
|
19311
19499
|
}
|
|
19312
19500
|
}
|
|
@@ -21543,7 +21731,7 @@ var import_node_fs23 = require("node:fs");
|
|
|
21543
21731
|
// src/stage-runner.ts
|
|
21544
21732
|
var import_node_child_process9 = require("node:child_process");
|
|
21545
21733
|
var import_node_fs22 = require("node:fs");
|
|
21546
|
-
var
|
|
21734
|
+
var import_node_path22 = require("node:path");
|
|
21547
21735
|
var import_node_net = require("node:net");
|
|
21548
21736
|
var import_node_util5 = require("node:util");
|
|
21549
21737
|
|
|
@@ -21682,11 +21870,11 @@ function appendForceRecreate(up) {
|
|
|
21682
21870
|
return `${up.trimEnd()} --force-recreate`;
|
|
21683
21871
|
}
|
|
21684
21872
|
function stageStatePath(cwd = process.cwd()) {
|
|
21685
|
-
return (0,
|
|
21873
|
+
return (0, import_node_path22.join)(cwd, "tmp", "stage", "state.json");
|
|
21686
21874
|
}
|
|
21687
21875
|
function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
|
|
21688
|
-
const dir = (0,
|
|
21689
|
-
return (0,
|
|
21876
|
+
const dir = (0, import_node_path22.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path22.resolve)(cwd, gitCommonDir);
|
|
21877
|
+
return (0, import_node_path22.join)(dir, "mmi", "stage", "state.json");
|
|
21690
21878
|
}
|
|
21691
21879
|
function normPath3(path2) {
|
|
21692
21880
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -21910,8 +22098,8 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
21910
22098
|
}
|
|
21911
22099
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
21912
22100
|
if (!config.ensureEnv) return;
|
|
21913
|
-
const target = (0,
|
|
21914
|
-
const example = (0,
|
|
22101
|
+
const target = (0, import_node_path22.join)(cwd, config.ensureEnv.target);
|
|
22102
|
+
const example = (0, import_node_path22.join)(cwd, config.ensureEnv.example);
|
|
21915
22103
|
if (!(0, import_node_fs22.existsSync)(target) && (0, import_node_fs22.existsSync)(example)) {
|
|
21916
22104
|
(0, import_node_fs22.copyFileSync)(example, target);
|
|
21917
22105
|
} else if ((0, import_node_fs22.existsSync)(target) && (0, import_node_fs22.existsSync)(example)) {
|
|
@@ -22276,13 +22464,13 @@ async function executeWaveLand(plan, deps, opts = { preserveWorktree: true }) {
|
|
|
22276
22464
|
}
|
|
22277
22465
|
|
|
22278
22466
|
// src/index.ts
|
|
22279
|
-
var
|
|
22467
|
+
var import_node_os20 = require("node:os");
|
|
22280
22468
|
|
|
22281
22469
|
// src/board.ts
|
|
22282
22470
|
var import_node_child_process10 = require("node:child_process");
|
|
22283
22471
|
var import_node_fs24 = require("node:fs");
|
|
22284
22472
|
var import_node_os8 = require("node:os");
|
|
22285
|
-
var
|
|
22473
|
+
var import_node_path23 = require("node:path");
|
|
22286
22474
|
var import_node_util6 = require("node:util");
|
|
22287
22475
|
|
|
22288
22476
|
// src/board-dependency.ts
|
|
@@ -24025,14 +24213,14 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
24025
24213
|
claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
|
|
24026
24214
|
return state;
|
|
24027
24215
|
};
|
|
24028
|
-
const root = (0,
|
|
24216
|
+
const root = (0, import_node_path23.join)((0, import_node_os8.homedir)(), ".claude", "projects");
|
|
24029
24217
|
try {
|
|
24030
24218
|
const wanted = `${marker.session}.jsonl`.toLowerCase();
|
|
24031
24219
|
const pending = [root];
|
|
24032
24220
|
while (pending.length) {
|
|
24033
24221
|
const dir = pending.pop();
|
|
24034
24222
|
for (const entry of (0, import_node_fs24.readdirSync)(dir, { withFileTypes: true })) {
|
|
24035
|
-
const path2 = (0,
|
|
24223
|
+
const path2 = (0, import_node_path23.join)(dir, entry.name);
|
|
24036
24224
|
if (entry.isDirectory()) pending.push(path2);
|
|
24037
24225
|
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
24038
24226
|
return remember(now - (0, import_node_fs24.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
@@ -24938,7 +25126,7 @@ function consolidateCommandNamespaces(program3) {
|
|
|
24938
25126
|
|
|
24939
25127
|
// src/pi-plugin-registration.ts
|
|
24940
25128
|
var import_node_fs25 = require("node:fs");
|
|
24941
|
-
var
|
|
25129
|
+
var import_node_path24 = require("node:path");
|
|
24942
25130
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
24943
25131
|
|
|
24944
25132
|
// src/plugin-cache-prune.ts
|
|
@@ -25201,17 +25389,17 @@ function newestExistingPiPlugin(home) {
|
|
|
25201
25389
|
return void 0;
|
|
25202
25390
|
}
|
|
25203
25391
|
for (const version of names.filter(isVersionDirName).sort((a, b) => compareVersions(b, a))) {
|
|
25204
|
-
const candidate = (0,
|
|
25392
|
+
const candidate = (0, import_node_path24.join)(cacheRoot, version, ".pi-plugin");
|
|
25205
25393
|
if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
|
|
25206
25394
|
}
|
|
25207
25395
|
return void 0;
|
|
25208
25396
|
}
|
|
25209
25397
|
function expectedPiPluginPath(home, env, installedVersion) {
|
|
25210
25398
|
const root = env.CLAUDE_PLUGIN_ROOT?.trim();
|
|
25211
|
-
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0,
|
|
25399
|
+
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path24.join)(root, ".pi-plugin");
|
|
25212
25400
|
const version = installedVersion ?? runningPluginVersion(env);
|
|
25213
25401
|
if (version) {
|
|
25214
|
-
const pinned = (0,
|
|
25402
|
+
const pinned = (0, import_node_path24.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
|
|
25215
25403
|
if ((0, import_node_fs25.existsSync)(pinned)) return pinned;
|
|
25216
25404
|
}
|
|
25217
25405
|
return newestExistingPiPlugin(home);
|
|
@@ -25219,15 +25407,15 @@ function expectedPiPluginPath(home, env, installedVersion) {
|
|
|
25219
25407
|
function agentDirs(home, env = process.env) {
|
|
25220
25408
|
const override = env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
|
|
25221
25409
|
if (override) return [override];
|
|
25222
|
-
const jerv = (0,
|
|
25223
|
-
const pi = (0,
|
|
25410
|
+
const jerv = (0, import_node_path24.join)(home, ".jerv", "agent");
|
|
25411
|
+
const pi = (0, import_node_path24.join)(home, ".pi", "agent");
|
|
25224
25412
|
if (!(0, import_node_fs25.existsSync)(jerv) && !(0, import_node_fs25.existsSync)(pi)) return [];
|
|
25225
25413
|
const dirs = [jerv];
|
|
25226
25414
|
if ((0, import_node_fs25.existsSync)(pi) && pi !== jerv) dirs.push(pi);
|
|
25227
25415
|
return dirs;
|
|
25228
25416
|
}
|
|
25229
25417
|
function settingsPath(agentDir) {
|
|
25230
|
-
return (0,
|
|
25418
|
+
return (0, import_node_path24.join)(agentDir, "settings.json");
|
|
25231
25419
|
}
|
|
25232
25420
|
function readPiPluginState(home, env, installedVersion) {
|
|
25233
25421
|
const dirs = agentDirs(home, env);
|
|
@@ -25261,7 +25449,7 @@ function acquirePiSettingsLock2(settingsFile) {
|
|
|
25261
25449
|
return void 0;
|
|
25262
25450
|
}
|
|
25263
25451
|
function atomicWriteSettings(file, body) {
|
|
25264
|
-
(0, import_node_fs25.mkdirSync)((0,
|
|
25452
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path24.dirname)(file), { recursive: true });
|
|
25265
25453
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
25266
25454
|
(0, import_node_fs25.writeFileSync)(tmp, body, "utf8");
|
|
25267
25455
|
try {
|
|
@@ -25339,18 +25527,18 @@ function healPiPluginRegistration(home, env, installedVersion) {
|
|
|
25339
25527
|
// src/claude-binary-doctor.ts
|
|
25340
25528
|
var import_node_fs27 = require("node:fs");
|
|
25341
25529
|
var import_node_os11 = require("node:os");
|
|
25342
|
-
var
|
|
25530
|
+
var import_node_path26 = require("node:path");
|
|
25343
25531
|
|
|
25344
25532
|
// src/jerv-cli-spawn.ts
|
|
25345
25533
|
var import_node_fs26 = require("node:fs");
|
|
25346
25534
|
var import_node_os10 = require("node:os");
|
|
25347
|
-
var
|
|
25535
|
+
var import_node_path25 = require("node:path");
|
|
25348
25536
|
var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
|
|
25349
25537
|
var POSIX_NAMES = ["jerv-cli"];
|
|
25350
|
-
var JERV_CLI_ENTRY = (0,
|
|
25538
|
+
var JERV_CLI_ENTRY = (0, import_node_path25.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
25351
25539
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
25352
25540
|
if (platform2 !== "win32") {
|
|
25353
|
-
return pathEnv.split(
|
|
25541
|
+
return pathEnv.split(import_node_path25.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
25354
25542
|
}
|
|
25355
25543
|
if (pathEnv.includes(";")) {
|
|
25356
25544
|
return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
|
|
@@ -25383,10 +25571,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os10.hom
|
|
|
25383
25571
|
push(normalizeSpawnPathEntry(entry, platform2));
|
|
25384
25572
|
}
|
|
25385
25573
|
if (platform2 === "win32") {
|
|
25386
|
-
if (env.APPDATA) push((0,
|
|
25387
|
-
if (env.LOCALAPPDATA) push((0,
|
|
25574
|
+
if (env.APPDATA) push((0, import_node_path25.join)(env.APPDATA, "npm"));
|
|
25575
|
+
if (env.LOCALAPPDATA) push((0, import_node_path25.join)(env.LOCALAPPDATA, "npm"));
|
|
25388
25576
|
} else {
|
|
25389
|
-
push((0,
|
|
25577
|
+
push((0, import_node_path25.join)(home, ".local", "bin"));
|
|
25390
25578
|
}
|
|
25391
25579
|
return out;
|
|
25392
25580
|
}
|
|
@@ -25394,7 +25582,7 @@ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os10.ho
|
|
|
25394
25582
|
const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
|
|
25395
25583
|
const out = [];
|
|
25396
25584
|
for (const dir of jervCliCandidateDirs(env, home, platform2)) {
|
|
25397
|
-
for (const name of names) out.push((0,
|
|
25585
|
+
for (const name of names) out.push((0, import_node_path25.join)(dir, name));
|
|
25398
25586
|
}
|
|
25399
25587
|
return out;
|
|
25400
25588
|
}
|
|
@@ -25405,7 +25593,7 @@ function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homed
|
|
|
25405
25593
|
return void 0;
|
|
25406
25594
|
}
|
|
25407
25595
|
function resolveJervCliNodeEntry(shimPath, exists = import_node_fs26.existsSync) {
|
|
25408
|
-
const entry = (0,
|
|
25596
|
+
const entry = (0, import_node_path25.join)((0, import_node_path25.dirname)(shimPath), JERV_CLI_ENTRY);
|
|
25409
25597
|
return exists(entry) ? entry : void 0;
|
|
25410
25598
|
}
|
|
25411
25599
|
function jervCliExecFileArgs(args, opts = {}) {
|
|
@@ -25500,10 +25688,10 @@ function globalNodeModulesRoots(host) {
|
|
|
25500
25688
|
out.push(dir);
|
|
25501
25689
|
};
|
|
25502
25690
|
const prefix = env.npm_config_prefix?.trim();
|
|
25503
|
-
if (prefix) push(platform2 === "win32" ? (0,
|
|
25691
|
+
if (prefix) push(platform2 === "win32" ? (0, import_node_path26.join)(prefix, "node_modules") : (0, import_node_path26.join)(prefix, "lib", "node_modules"));
|
|
25504
25692
|
for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os11.homedir)(), platform2)) {
|
|
25505
|
-
push((0,
|
|
25506
|
-
push((0,
|
|
25693
|
+
push((0, import_node_path26.join)(dir, "node_modules"));
|
|
25694
|
+
push((0, import_node_path26.join)((0, import_node_path26.dirname)(dir), "lib", "node_modules"));
|
|
25507
25695
|
}
|
|
25508
25696
|
return out;
|
|
25509
25697
|
}
|
|
@@ -25541,17 +25729,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25541
25729
|
const arch = host.arch ?? process.arch;
|
|
25542
25730
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
25543
25731
|
if (!magic) return void 0;
|
|
25544
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0,
|
|
25732
|
+
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path26.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs27.existsSync)((0, import_node_path26.join)(dir, "package.json")));
|
|
25545
25733
|
if (!packageRoot) return void 0;
|
|
25546
25734
|
const keys = platformPackageKeys(platform2, arch);
|
|
25547
25735
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
25548
25736
|
let manifest;
|
|
25549
25737
|
try {
|
|
25550
|
-
manifest = JSON.parse((0, import_node_fs27.readFileSync)((0,
|
|
25738
|
+
manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path26.join)(packageRoot, "package.json"), "utf8"));
|
|
25551
25739
|
} catch (e) {
|
|
25552
25740
|
return {
|
|
25553
25741
|
state: "unreadable",
|
|
25554
|
-
binPath: (0,
|
|
25742
|
+
binPath: (0, import_node_path26.join)(packageRoot, "package.json"),
|
|
25555
25743
|
expectedMagic: magic.name,
|
|
25556
25744
|
platformPackage: fallbackPackage,
|
|
25557
25745
|
error: `package.json could not be read \u2014 ${e.message}`
|
|
@@ -25568,15 +25756,15 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25568
25756
|
error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
|
|
25569
25757
|
};
|
|
25570
25758
|
}
|
|
25571
|
-
const binPath = (0,
|
|
25572
|
-
const binName = (0,
|
|
25759
|
+
const binPath = (0, import_node_path26.join)(packageRoot, binRelative);
|
|
25760
|
+
const binName = (0, import_node_path26.basename)(binRelative);
|
|
25573
25761
|
const optional = manifest.optionalDependencies;
|
|
25574
25762
|
const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
|
|
25575
25763
|
const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
|
|
25576
25764
|
if (published.length === 0) return void 0;
|
|
25577
25765
|
const binIn = (name) => [
|
|
25578
|
-
(0,
|
|
25579
|
-
(0,
|
|
25766
|
+
(0, import_node_path26.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
25767
|
+
(0, import_node_path26.join)((0, import_node_path26.dirname)((0, import_node_path26.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
25580
25768
|
];
|
|
25581
25769
|
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
|
|
25582
25770
|
const platformPackage = found?.name ?? published[0];
|
|
@@ -25901,7 +26089,7 @@ function renderVerifyBroker(input) {
|
|
|
25901
26089
|
var import_node_crypto4 = require("node:crypto");
|
|
25902
26090
|
var import_node_fs28 = require("node:fs");
|
|
25903
26091
|
var import_promises5 = require("node:fs/promises");
|
|
25904
|
-
var
|
|
26092
|
+
var import_node_path27 = require("node:path");
|
|
25905
26093
|
var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
25906
26094
|
var MAX_BYTES = 5 * 1024 * 1024 * 1024;
|
|
25907
26095
|
async function sha256File(path2) {
|
|
@@ -25911,7 +26099,7 @@ async function sha256File(path2) {
|
|
|
25911
26099
|
}
|
|
25912
26100
|
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
25913
26101
|
if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
|
|
25914
|
-
const path2 = (0,
|
|
26102
|
+
const path2 = (0, import_node_path27.resolve)(inputPath);
|
|
25915
26103
|
const info = await (0, import_promises5.stat)(path2);
|
|
25916
26104
|
if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
|
|
25917
26105
|
if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES} bytes`);
|
|
@@ -27048,7 +27236,7 @@ async function announceRelease(deps, args) {
|
|
|
27048
27236
|
var import_node_crypto5 = require("node:crypto");
|
|
27049
27237
|
var import_node_child_process13 = require("node:child_process");
|
|
27050
27238
|
var import_node_fs29 = require("node:fs");
|
|
27051
|
-
var
|
|
27239
|
+
var import_node_path28 = require("node:path");
|
|
27052
27240
|
var REPO_INDEX_SCHEMA = 1;
|
|
27053
27241
|
var HARD_DENY = [
|
|
27054
27242
|
/(^|\/)\.env(\.|$)/i,
|
|
@@ -27173,7 +27361,7 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27173
27361
|
}
|
|
27174
27362
|
for (const rel of readmes) {
|
|
27175
27363
|
if (isHardDeniedPath(rel)) continue;
|
|
27176
|
-
const abs = (0,
|
|
27364
|
+
const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
|
|
27177
27365
|
if (!(0, import_node_fs29.existsSync)(abs)) continue;
|
|
27178
27366
|
let text;
|
|
27179
27367
|
try {
|
|
@@ -27190,7 +27378,7 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27190
27378
|
return hints;
|
|
27191
27379
|
}
|
|
27192
27380
|
function toPosix(p) {
|
|
27193
|
-
return p.split(
|
|
27381
|
+
return p.split(import_node_path28.sep).join("/");
|
|
27194
27382
|
}
|
|
27195
27383
|
function listCandidatePaths(cwd, exec = import_node_child_process13.execFileSync) {
|
|
27196
27384
|
try {
|
|
@@ -27212,7 +27400,7 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27212
27400
|
for (const rel of candidates) {
|
|
27213
27401
|
if (ignored.has(rel)) continue;
|
|
27214
27402
|
if (isHardDeniedPath(rel)) continue;
|
|
27215
|
-
const abs = (0,
|
|
27403
|
+
const abs = (0, import_node_path28.join)(cwd, ...rel.split("/"));
|
|
27216
27404
|
if (!(0, import_node_fs29.existsSync)(abs)) continue;
|
|
27217
27405
|
let text;
|
|
27218
27406
|
try {
|
|
@@ -27241,7 +27429,7 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27241
27429
|
entries
|
|
27242
27430
|
};
|
|
27243
27431
|
const store = repoIndexStorePath(cwd);
|
|
27244
|
-
(0, import_node_fs29.mkdirSync)((0,
|
|
27432
|
+
(0, import_node_fs29.mkdirSync)((0, import_node_path28.dirname)(store), { recursive: true });
|
|
27245
27433
|
(0, import_node_fs29.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
|
|
27246
27434
|
`, "utf8");
|
|
27247
27435
|
return projection;
|
|
@@ -27322,7 +27510,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process13.execFileSync) {
|
|
|
27322
27510
|
if (m?.[1]) return m[1].toLowerCase();
|
|
27323
27511
|
} catch {
|
|
27324
27512
|
}
|
|
27325
|
-
return ((0,
|
|
27513
|
+
return ((0, import_node_path28.basename)(cwd) || "local").toLowerCase();
|
|
27326
27514
|
}
|
|
27327
27515
|
|
|
27328
27516
|
// src/repo-index-cloud-client.ts
|
|
@@ -27464,7 +27652,7 @@ async function gcRepoIndexCloud(deps) {
|
|
|
27464
27652
|
// src/repo-index-sync.ts
|
|
27465
27653
|
var import_node_fs30 = require("node:fs");
|
|
27466
27654
|
var import_node_os12 = require("node:os");
|
|
27467
|
-
var
|
|
27655
|
+
var import_node_path29 = require("node:path");
|
|
27468
27656
|
var import_node_child_process14 = require("node:child_process");
|
|
27469
27657
|
var MAX_EMBED_BACKFILL_ROUNDS = 40;
|
|
27470
27658
|
function normalizeRepo(raw) {
|
|
@@ -27508,7 +27696,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27508
27696
|
const failed = [];
|
|
27509
27697
|
const skipped = [];
|
|
27510
27698
|
for (const repo of repos) {
|
|
27511
|
-
const dir = (0, import_node_fs30.mkdtempSync)((0,
|
|
27699
|
+
const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path29.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
|
|
27512
27700
|
try {
|
|
27513
27701
|
shallowClone(repo, dir, opts.githubToken);
|
|
27514
27702
|
const built = rebuildRepoIndex(dir, repo);
|
|
@@ -27764,7 +27952,7 @@ async function runRepoIndexHealth(opts) {
|
|
|
27764
27952
|
// src/spawn-policy-core.ts
|
|
27765
27953
|
var import_node_child_process15 = require("node:child_process");
|
|
27766
27954
|
var import_node_fs32 = require("node:fs");
|
|
27767
|
-
var
|
|
27955
|
+
var import_node_path30 = require("node:path");
|
|
27768
27956
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
27769
27957
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
27770
27958
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -27850,7 +28038,7 @@ function runSpawnPolicy(root) {
|
|
|
27850
28038
|
for (const file of files) {
|
|
27851
28039
|
let raw;
|
|
27852
28040
|
try {
|
|
27853
|
-
raw = (0, import_node_fs32.readFileSync)((0,
|
|
28041
|
+
raw = (0, import_node_fs32.readFileSync)((0, import_node_path30.join)(root, file), "utf8");
|
|
27854
28042
|
} catch {
|
|
27855
28043
|
continue;
|
|
27856
28044
|
}
|
|
@@ -27869,7 +28057,7 @@ function runSpawnPolicy(root) {
|
|
|
27869
28057
|
// src/test-policy-core.ts
|
|
27870
28058
|
var import_node_child_process16 = require("node:child_process");
|
|
27871
28059
|
var import_node_fs33 = require("node:fs");
|
|
27872
|
-
var
|
|
28060
|
+
var import_node_path31 = require("node:path");
|
|
27873
28061
|
var POLICY_FILE = "test-policy.json";
|
|
27874
28062
|
var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
27875
28063
|
var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
|
|
@@ -27922,7 +28110,7 @@ function isTestPath(path2) {
|
|
|
27922
28110
|
return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
|
|
27923
28111
|
}
|
|
27924
28112
|
function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
27925
|
-
const raw = readFile9((0,
|
|
28113
|
+
const raw = readFile9((0, import_node_path31.join)(root, POLICY_FILE));
|
|
27926
28114
|
if (raw == null) return { mandatory: [], declared: false };
|
|
27927
28115
|
try {
|
|
27928
28116
|
return { ...JSON.parse(raw), declared: true };
|
|
@@ -27960,11 +28148,11 @@ function classify(changed, policy, present = () => false) {
|
|
|
27960
28148
|
return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
|
|
27961
28149
|
}
|
|
27962
28150
|
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
|
|
27963
|
-
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0,
|
|
28151
|
+
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path31.join)(root, p)));
|
|
27964
28152
|
}
|
|
27965
28153
|
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs33.existsSync)(path2)) {
|
|
27966
28154
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
27967
|
-
return [...new Set(declared)].filter((p) => !exists((0,
|
|
28155
|
+
return [...new Set(declared)].filter((p) => !exists((0, import_node_path31.join)(root, p)));
|
|
27968
28156
|
}
|
|
27969
28157
|
function evaluate(changed, policy, present = () => false) {
|
|
27970
28158
|
const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
|
|
@@ -28152,7 +28340,7 @@ function runTestPolicy(root, deps = {}) {
|
|
|
28152
28340
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
28153
28341
|
const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
|
|
28154
28342
|
const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
|
|
28155
|
-
const present = (path2) => exists((0,
|
|
28343
|
+
const present = (path2) => exists((0, import_node_path31.join)(root, path2));
|
|
28156
28344
|
const removedByThisDiff = removedPaths(changed);
|
|
28157
28345
|
const staleFindings = [];
|
|
28158
28346
|
const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
|
|
@@ -28191,7 +28379,7 @@ function runTestPolicy(root, deps = {}) {
|
|
|
28191
28379
|
|
|
28192
28380
|
// src/project-info-sync.ts
|
|
28193
28381
|
var import_node_fs34 = require("node:fs");
|
|
28194
|
-
var
|
|
28382
|
+
var import_node_path32 = require("node:path");
|
|
28195
28383
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
28196
28384
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
28197
28385
|
projectV2 { id }
|
|
@@ -28236,7 +28424,7 @@ function sharedName(entries, fallback) {
|
|
|
28236
28424
|
}
|
|
28237
28425
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
28238
28426
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
28239
|
-
const readmePath = (0,
|
|
28427
|
+
const readmePath = (0, import_node_path32.join)(repoRoot2, "README.md");
|
|
28240
28428
|
if (!(0, import_node_fs34.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
28241
28429
|
const entries = entriesFor(project2, projects);
|
|
28242
28430
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
@@ -28262,8 +28450,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
28262
28450
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
28263
28451
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
28264
28452
|
const orgDocs = [
|
|
28265
|
-
(0, import_node_fs34.existsSync)((0,
|
|
28266
|
-
(0, import_node_fs34.existsSync)((0,
|
|
28453
|
+
(0, import_node_fs34.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
|
|
28454
|
+
(0, import_node_fs34.existsSync)((0, import_node_path32.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
|
|
28267
28455
|
].filter(Boolean);
|
|
28268
28456
|
if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
|
|
28269
28457
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
|
|
@@ -29090,7 +29278,7 @@ function writeError(res) {
|
|
|
29090
29278
|
|
|
29091
29279
|
// src/secrets-commands.ts
|
|
29092
29280
|
var import_node_fs35 = require("node:fs");
|
|
29093
|
-
var
|
|
29281
|
+
var import_node_path33 = require("node:path");
|
|
29094
29282
|
var import_node_os13 = require("node:os");
|
|
29095
29283
|
|
|
29096
29284
|
// src/secrets-diff.ts
|
|
@@ -29193,11 +29381,11 @@ function collectMap(value, previous = []) {
|
|
|
29193
29381
|
return [...previous, value];
|
|
29194
29382
|
}
|
|
29195
29383
|
async function decryptRailsCredentials(input) {
|
|
29196
|
-
const appDir = (0,
|
|
29384
|
+
const appDir = (0, import_node_path33.resolve)(input.appDir ?? process.cwd());
|
|
29197
29385
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
29198
29386
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
29199
|
-
const credentialsPath = (0,
|
|
29200
|
-
const masterKeyPath = (0,
|
|
29387
|
+
const credentialsPath = (0, import_node_path33.resolve)(appDir, credentialsFile);
|
|
29388
|
+
const masterKeyPath = (0, import_node_path33.resolve)(appDir, masterKeyFile);
|
|
29201
29389
|
const env = {
|
|
29202
29390
|
...process.env,
|
|
29203
29391
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
@@ -29214,8 +29402,8 @@ async function decryptRailsCredentials(input) {
|
|
|
29214
29402
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
29215
29403
|
"puts JSON.generate(config.config)"
|
|
29216
29404
|
].join("\n");
|
|
29217
|
-
const scriptDir = (0, import_node_fs35.mkdtempSync)((0,
|
|
29218
|
-
const scriptPath = (0,
|
|
29405
|
+
const scriptDir = (0, import_node_fs35.mkdtempSync)((0, import_node_path33.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
|
|
29406
|
+
const scriptPath = (0, import_node_path33.join)(scriptDir, "decrypt.rb");
|
|
29219
29407
|
(0, import_node_fs35.writeFileSync)(scriptPath, script, "utf8");
|
|
29220
29408
|
try {
|
|
29221
29409
|
const args = ["exec", "ruby", scriptPath];
|
|
@@ -29318,7 +29506,7 @@ function registerSecretsCommands(program3) {
|
|
|
29318
29506
|
let body;
|
|
29319
29507
|
if (o.file) {
|
|
29320
29508
|
try {
|
|
29321
|
-
body = (0, import_node_fs35.readFileSync)((0,
|
|
29509
|
+
body = (0, import_node_fs35.readFileSync)((0, import_node_path33.resolve)(o.file), "utf8");
|
|
29322
29510
|
} catch (e) {
|
|
29323
29511
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
29324
29512
|
}
|
|
@@ -29423,7 +29611,7 @@ function registerSecretsCommands(program3) {
|
|
|
29423
29611
|
{
|
|
29424
29612
|
...d,
|
|
29425
29613
|
decryptRailsCredentials,
|
|
29426
|
-
removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0,
|
|
29614
|
+
removeFile: (path2) => (0, import_node_fs35.unlinkSync)((0, import_node_path33.resolve)(o.appDir ?? process.cwd(), path2))
|
|
29427
29615
|
},
|
|
29428
29616
|
{
|
|
29429
29617
|
repo: o.repo,
|
|
@@ -29877,8 +30065,8 @@ async function repoWorkflowEntries(client, repo) {
|
|
|
29877
30065
|
for (const wf of workflowsList) {
|
|
29878
30066
|
if (typeof wf?.path !== "string" || !wf.path) continue;
|
|
29879
30067
|
if (!wf.path.startsWith(".github/workflows/")) continue;
|
|
29880
|
-
const
|
|
29881
|
-
const name = `${repo}/${
|
|
30068
|
+
const basename8 = wf.path.split("/").pop() ?? wf.path;
|
|
30069
|
+
const name = `${repo}/${basename8.replace(/\.ya?ml$/, "")}`;
|
|
29882
30070
|
if (wf.state !== "active") {
|
|
29883
30071
|
disabled.push(name);
|
|
29884
30072
|
continue;
|
|
@@ -30150,7 +30338,7 @@ function registerSchedulesCommands(program3) {
|
|
|
30150
30338
|
|
|
30151
30339
|
// src/schedules-lift-command.ts
|
|
30152
30340
|
var import_promises7 = require("node:fs/promises");
|
|
30153
|
-
var
|
|
30341
|
+
var import_node_path34 = require("node:path");
|
|
30154
30342
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
30155
30343
|
var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
|
|
30156
30344
|
var SchedulesLiftUsageError = class extends Error {
|
|
@@ -30177,7 +30365,7 @@ async function readWorkflowFiles(dir) {
|
|
|
30177
30365
|
const files = [];
|
|
30178
30366
|
for (const name of names.sort()) {
|
|
30179
30367
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
30180
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0,
|
|
30368
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises7.readFile)((0, import_node_path34.join)(dir, name), "utf8") });
|
|
30181
30369
|
}
|
|
30182
30370
|
return files;
|
|
30183
30371
|
}
|
|
@@ -30327,7 +30515,7 @@ function registerEdgeCommands(program3) {
|
|
|
30327
30515
|
// src/bootstrap-commands.ts
|
|
30328
30516
|
var import_node_fs37 = require("node:fs");
|
|
30329
30517
|
var import_node_os14 = require("node:os");
|
|
30330
|
-
var
|
|
30518
|
+
var import_node_path35 = require("node:path");
|
|
30331
30519
|
|
|
30332
30520
|
// src/bootstrap-drift.ts
|
|
30333
30521
|
var import_node_crypto7 = require("node:crypto");
|
|
@@ -31369,7 +31557,7 @@ function registerBootstrapCommands(program3) {
|
|
|
31369
31557
|
const readFile9 = (p) => (0, import_node_fs37.existsSync)(p) ? (0, import_node_fs37.readFileSync)(p, "utf8") : null;
|
|
31370
31558
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31371
31559
|
const putSeed = async (target, content, ref, sha) => {
|
|
31372
|
-
const tmp = (0,
|
|
31560
|
+
const tmp = (0, import_node_path35.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31373
31561
|
(0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
31374
31562
|
try {
|
|
31375
31563
|
await gh(contentPutInputArgs(repo, target, tmp));
|
|
@@ -31780,7 +31968,7 @@ LIVE apply to ${repo}:
|
|
|
31780
31968
|
} catch {
|
|
31781
31969
|
existingSha = void 0;
|
|
31782
31970
|
}
|
|
31783
|
-
const tmp = (0,
|
|
31971
|
+
const tmp = (0, import_node_path35.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31784
31972
|
(0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
|
|
31785
31973
|
try {
|
|
31786
31974
|
await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
@@ -31936,7 +32124,7 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31936
32124
|
} catch {
|
|
31937
32125
|
existingSha = void 0;
|
|
31938
32126
|
}
|
|
31939
|
-
const tmp = (0,
|
|
32127
|
+
const tmp = (0, import_node_path35.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31940
32128
|
(0, import_node_fs37.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
31941
32129
|
try {
|
|
31942
32130
|
await gh(contentPutInputArgs(repo, seed.target, tmp));
|
|
@@ -31965,11 +32153,11 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31965
32153
|
|
|
31966
32154
|
// src/stage-commands.ts
|
|
31967
32155
|
var import_node_fs39 = require("node:fs");
|
|
31968
|
-
var
|
|
32156
|
+
var import_node_path37 = require("node:path");
|
|
31969
32157
|
|
|
31970
32158
|
// src/port-registry.ts
|
|
31971
32159
|
var import_node_fs38 = require("node:fs");
|
|
31972
|
-
var
|
|
32160
|
+
var import_node_path36 = require("node:path");
|
|
31973
32161
|
|
|
31974
32162
|
// ../infra/port-geometry.mjs
|
|
31975
32163
|
var PORT_BLOCK = 100;
|
|
@@ -32022,22 +32210,22 @@ function existingPortRange(repo, registry2) {
|
|
|
32022
32210
|
return registry2[repo] ?? null;
|
|
32023
32211
|
}
|
|
32024
32212
|
function portRangeInfraAt(root, source) {
|
|
32025
|
-
const registryPath = (0,
|
|
32026
|
-
const ddbScriptPath = (0,
|
|
32213
|
+
const registryPath = (0, import_node_path36.join)(root, "infra", "port-ranges.json");
|
|
32214
|
+
const ddbScriptPath = (0, import_node_path36.join)(root, "infra", "port-ddb.mjs");
|
|
32027
32215
|
if (!(0, import_node_fs38.existsSync)(registryPath) || !(0, import_node_fs38.existsSync)(ddbScriptPath)) return null;
|
|
32028
32216
|
return { root, source, registryPath, ddbScriptPath };
|
|
32029
32217
|
}
|
|
32030
32218
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
32031
32219
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
32032
32220
|
if (direct) return direct;
|
|
32033
|
-
for (let dir = cwd; ; dir = (0,
|
|
32034
|
-
const sibling = portRangeInfraAt((0,
|
|
32221
|
+
for (let dir = cwd; ; dir = (0, import_node_path36.dirname)(dir)) {
|
|
32222
|
+
const sibling = portRangeInfraAt((0, import_node_path36.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
32035
32223
|
if (sibling) return sibling;
|
|
32036
|
-
const parent = (0,
|
|
32224
|
+
const parent = (0, import_node_path36.dirname)(dir);
|
|
32037
32225
|
if (parent === dir) break;
|
|
32038
32226
|
}
|
|
32039
32227
|
if (packageDir) {
|
|
32040
|
-
const pkgRoot = (0,
|
|
32228
|
+
const pkgRoot = (0, import_node_path36.join)(packageDir, "..", "..");
|
|
32041
32229
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
32042
32230
|
if (pkgFrom) return pkgFrom;
|
|
32043
32231
|
}
|
|
@@ -32231,8 +32419,8 @@ function registerStageCommands(program3) {
|
|
|
32231
32419
|
const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
|
|
32232
32420
|
return decideStage({
|
|
32233
32421
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
32234
|
-
hasCompose: (0, import_node_fs39.existsSync)((0,
|
|
32235
|
-
hasEnvExample: (0, import_node_fs39.existsSync)((0,
|
|
32422
|
+
hasCompose: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), "docker-compose.yml")),
|
|
32423
|
+
hasEnvExample: (0, import_node_fs39.existsSync)((0, import_node_path37.join)(process.cwd(), ".env.example"))
|
|
32236
32424
|
});
|
|
32237
32425
|
}
|
|
32238
32426
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -32726,7 +32914,7 @@ function registerBoardCommands(program3) {
|
|
|
32726
32914
|
// src/merge-cleanup.ts
|
|
32727
32915
|
var import_node_fs40 = require("node:fs");
|
|
32728
32916
|
var import_promises9 = require("node:fs/promises");
|
|
32729
|
-
var
|
|
32917
|
+
var import_node_path39 = require("node:path");
|
|
32730
32918
|
var import_node_os15 = require("node:os");
|
|
32731
32919
|
var import_node_child_process18 = require("node:child_process");
|
|
32732
32920
|
|
|
@@ -32814,7 +33002,7 @@ function boardAdvanceFailureMessage(result) {
|
|
|
32814
33002
|
|
|
32815
33003
|
// src/deferred-registry-store.ts
|
|
32816
33004
|
var import_promises8 = require("node:fs/promises");
|
|
32817
|
-
var
|
|
33005
|
+
var import_node_path38 = require("node:path");
|
|
32818
33006
|
var sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
32819
33007
|
async function atomicWrite(target, contents) {
|
|
32820
33008
|
const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
@@ -32865,12 +33053,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
32865
33053
|
},
|
|
32866
33054
|
// Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
|
|
32867
33055
|
write: async (entries) => {
|
|
32868
|
-
await (0, import_promises8.mkdir)((0,
|
|
33056
|
+
await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
|
|
32869
33057
|
await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
|
|
32870
33058
|
},
|
|
32871
33059
|
// Serialized read-modify-write under the repo-wide lock (#2846).
|
|
32872
33060
|
update: async (mutate) => {
|
|
32873
|
-
await (0, import_promises8.mkdir)((0,
|
|
33061
|
+
await (0, import_promises8.mkdir)((0, import_node_path38.dirname)(registryPath), { recursive: true });
|
|
32874
33062
|
const deadline = Date.now() + opts.maxWaitMs;
|
|
32875
33063
|
for (; ; ) {
|
|
32876
33064
|
const guard = await acquireLock(lockPath, opts, deadline);
|
|
@@ -33034,6 +33222,23 @@ ${err.stderr ?? ""}`;
|
|
|
33034
33222
|
return { step, status: `failed: ${msg}` };
|
|
33035
33223
|
}
|
|
33036
33224
|
}
|
|
33225
|
+
async function bestEffortCloseMissingWorktreeLeases(leaseDir = (0, import_node_path39.join)((0, import_node_os15.homedir)(), ".jerv", "leases"), exists = import_node_fs40.existsSync) {
|
|
33226
|
+
let names = [];
|
|
33227
|
+
try {
|
|
33228
|
+
names = (0, import_node_fs40.readdirSync)(leaseDir);
|
|
33229
|
+
} catch {
|
|
33230
|
+
return;
|
|
33231
|
+
}
|
|
33232
|
+
for (const name of names) {
|
|
33233
|
+
if (!name.endsWith(".json")) continue;
|
|
33234
|
+
try {
|
|
33235
|
+
const rec = JSON.parse((0, import_node_fs40.readFileSync)((0, import_node_path39.join)(leaseDir, name), "utf8"));
|
|
33236
|
+
if (rec.kind !== "worktree" || rec.state === "closed" || typeof rec.ref !== "string" || !rec.ref.trim()) continue;
|
|
33237
|
+
if (!exists(rec.ref)) await bestEffortLeaseClose(rec.ref);
|
|
33238
|
+
} catch {
|
|
33239
|
+
}
|
|
33240
|
+
}
|
|
33241
|
+
}
|
|
33037
33242
|
async function applyGcPlan(plan, remote, opts = {}) {
|
|
33038
33243
|
const result = { removedBranches: [], removedRemoteBranches: [], removedTrackingRefs: [], removedWorktreeDirs: [], refused: [], failed: [], pruned: false };
|
|
33039
33244
|
const beforeWorktrees = parseWorktreePorcelain(
|
|
@@ -33041,7 +33246,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
33041
33246
|
);
|
|
33042
33247
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
33043
33248
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
33044
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
33249
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
33045
33250
|
const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
|
|
33046
33251
|
const owners = readWorktreeOwners(primaryRepoRoot);
|
|
33047
33252
|
const removalNow = Date.now();
|
|
@@ -33050,7 +33255,9 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
33050
33255
|
const activeWorkspaceDeferred = [];
|
|
33051
33256
|
const refusesRemoval = (path2, branch) => {
|
|
33052
33257
|
if (!path2) return false;
|
|
33053
|
-
const activeGuard = decideActiveWorkspaceGuard(path2, activeWorkspaceRoot
|
|
33258
|
+
const activeGuard = decideActiveWorkspaceGuard(path2, activeWorkspaceRoot, process.platform, {
|
|
33259
|
+
cursorAgentHost: isCursorAgentHost()
|
|
33260
|
+
});
|
|
33054
33261
|
if (activeGuard.action === "refuse") {
|
|
33055
33262
|
result.refused.push(activeGuard.message);
|
|
33056
33263
|
const owner2 = findWorktreeOwner(owners, path2);
|
|
@@ -33129,7 +33336,8 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
33129
33336
|
const removeDeps = worktreeRemoveDeps(async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
|
|
33130
33337
|
const cleanupRoots = [
|
|
33131
33338
|
opts.root ? resolveExplicitScanRoot(opts.root, primaryRepoRoot) : siblingMmiWorktreesRoot(primaryRepoRoot),
|
|
33132
|
-
agentWorktreesRoot(primaryRepoRoot)
|
|
33339
|
+
agentWorktreesRoot(primaryRepoRoot),
|
|
33340
|
+
...helperWorktreeRoots(primaryRepoRoot)
|
|
33133
33341
|
];
|
|
33134
33342
|
for (const wt of worktreeDirsToRemove) {
|
|
33135
33343
|
const owner = findWorktreeOwner(owners, wt.path);
|
|
@@ -33181,12 +33389,27 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
33181
33389
|
}
|
|
33182
33390
|
}
|
|
33183
33391
|
}
|
|
33392
|
+
for (const head of plan.reapOriginHeads ?? []) {
|
|
33393
|
+
try {
|
|
33394
|
+
await execFileP2("git", ["push", remote, "--delete", head.branch], { timeout: GIT_TIMEOUT_MS });
|
|
33395
|
+
result.removedRemoteBranches.push(head.branch);
|
|
33396
|
+
} catch (e) {
|
|
33397
|
+
const detail = `${e.message}
|
|
33398
|
+
${e.stderr ?? ""}`;
|
|
33399
|
+
if (/not found|does not exist|unable to delete|remote ref does not exist/i.test(detail)) {
|
|
33400
|
+
result.removedRemoteBranches.push(head.branch);
|
|
33401
|
+
} else {
|
|
33402
|
+
result.failed.push(`${head.branch}: origin delete failed (${e.message.split("\n")[0]})`);
|
|
33403
|
+
}
|
|
33404
|
+
}
|
|
33405
|
+
}
|
|
33184
33406
|
try {
|
|
33185
33407
|
await execFileP2("git", ["worktree", "prune"], { timeout: GIT_TIMEOUT_MS });
|
|
33186
33408
|
result.pruned = true;
|
|
33187
33409
|
} catch (e) {
|
|
33188
33410
|
result.failed.push(`worktree prune: ${e.message.split("\n")[0]}`);
|
|
33189
33411
|
}
|
|
33412
|
+
await bestEffortCloseMissingWorktreeLeases();
|
|
33190
33413
|
return result;
|
|
33191
33414
|
}
|
|
33192
33415
|
async function pollGhPrChecks(prNumber, repoArgs) {
|
|
@@ -33223,8 +33446,8 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
|
|
|
33223
33446
|
const commits = JSON.parse(raw).commits ?? [];
|
|
33224
33447
|
const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
|
|
33225
33448
|
if (!body) return void 0;
|
|
33226
|
-
const dir = (0, import_node_fs40.mkdtempSync)((0,
|
|
33227
|
-
const path2 = (0,
|
|
33449
|
+
const dir = (0, import_node_fs40.mkdtempSync)((0, import_node_path39.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
|
|
33450
|
+
const path2 = (0, import_node_path39.join)(dir, "body.txt");
|
|
33228
33451
|
(0, import_node_fs40.writeFileSync)(path2, `${body}
|
|
33229
33452
|
`, "utf8");
|
|
33230
33453
|
return { path: path2, cleanup: () => {
|
|
@@ -33349,15 +33572,16 @@ async function createDeferredWorktreeStore() {
|
|
|
33349
33572
|
}
|
|
33350
33573
|
var realWorktreeDirRemover = {
|
|
33351
33574
|
probe: (p) => {
|
|
33575
|
+
const target = win32LongPath(p);
|
|
33352
33576
|
let st;
|
|
33353
33577
|
try {
|
|
33354
|
-
st = (0, import_node_fs40.lstatSync)(
|
|
33578
|
+
st = (0, import_node_fs40.lstatSync)(target);
|
|
33355
33579
|
} catch {
|
|
33356
33580
|
return null;
|
|
33357
33581
|
}
|
|
33358
33582
|
if (st.isSymbolicLink()) return "link";
|
|
33359
33583
|
try {
|
|
33360
|
-
(0, import_node_fs40.readlinkSync)(
|
|
33584
|
+
(0, import_node_fs40.readlinkSync)(target);
|
|
33361
33585
|
return "link";
|
|
33362
33586
|
} catch {
|
|
33363
33587
|
}
|
|
@@ -33365,7 +33589,7 @@ var realWorktreeDirRemover = {
|
|
|
33365
33589
|
},
|
|
33366
33590
|
readdir: (p) => {
|
|
33367
33591
|
try {
|
|
33368
|
-
return (0, import_node_fs40.readdirSync)(p);
|
|
33592
|
+
return (0, import_node_fs40.readdirSync)(win32LongPath(p));
|
|
33369
33593
|
} catch {
|
|
33370
33594
|
return [];
|
|
33371
33595
|
}
|
|
@@ -33373,13 +33597,16 @@ var realWorktreeDirRemover = {
|
|
|
33373
33597
|
// A directory reparse point (junction / dir-symlink) is detached with rmdir (unlinks the mount point,
|
|
33374
33598
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
33375
33599
|
detachLink: (p) => {
|
|
33600
|
+
const target = win32LongPath(p);
|
|
33376
33601
|
try {
|
|
33377
|
-
(0, import_node_fs40.rmdirSync)(
|
|
33602
|
+
(0, import_node_fs40.rmdirSync)(target);
|
|
33378
33603
|
} catch {
|
|
33379
|
-
(0, import_node_fs40.unlinkSync)(
|
|
33604
|
+
(0, import_node_fs40.unlinkSync)(target);
|
|
33380
33605
|
}
|
|
33381
33606
|
},
|
|
33382
|
-
|
|
33607
|
+
// #4904: Windows MAX_PATH aborts git worktree remove; the fallback must use \\?\ so the dir
|
|
33608
|
+
// (and its lease) do not survive as an unregistered leftover.
|
|
33609
|
+
removeTree: (p) => (0, import_promises9.rm)(win32LongPath(p), { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
33383
33610
|
};
|
|
33384
33611
|
async function resolvePrimaryCheckout(execGit) {
|
|
33385
33612
|
try {
|
|
@@ -33850,12 +34077,13 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
33850
34077
|
// src/worktree-lifecycle-commands.ts
|
|
33851
34078
|
var import_node_fs42 = require("node:fs");
|
|
33852
34079
|
var import_promises10 = require("node:fs/promises");
|
|
33853
|
-
var
|
|
34080
|
+
var import_node_os16 = require("node:os");
|
|
34081
|
+
var import_node_path41 = require("node:path");
|
|
33854
34082
|
|
|
33855
34083
|
// src/worktree-install-cache.ts
|
|
33856
34084
|
var import_node_crypto8 = require("node:crypto");
|
|
33857
34085
|
var import_node_fs41 = require("node:fs");
|
|
33858
|
-
var
|
|
34086
|
+
var import_node_path40 = require("node:path");
|
|
33859
34087
|
var CACHE_DIR = "worktree-install-cache";
|
|
33860
34088
|
var MANIFEST = "manifest.json";
|
|
33861
34089
|
var NODE_MODULES2 = "node_modules";
|
|
@@ -33885,7 +34113,7 @@ function hashLockfileBytes(contents) {
|
|
|
33885
34113
|
}
|
|
33886
34114
|
function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33887
34115
|
for (const name of LOCKFILE_NAMES) {
|
|
33888
|
-
const path2 = (0,
|
|
34116
|
+
const path2 = (0, import_node_path40.join)(packageDir, name);
|
|
33889
34117
|
if (!fs2.exists(path2)) continue;
|
|
33890
34118
|
try {
|
|
33891
34119
|
const hash = hashLockfileBytes(fs2.readFile(path2));
|
|
@@ -33900,8 +34128,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
|
|
|
33900
34128
|
const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
|
|
33901
34129
|
return {
|
|
33902
34130
|
root,
|
|
33903
|
-
manifestPath: (0,
|
|
33904
|
-
nodeModulesPath: (0,
|
|
34131
|
+
manifestPath: (0, import_node_path40.join)(root, MANIFEST),
|
|
34132
|
+
nodeModulesPath: (0, import_node_path40.join)(root, NODE_MODULES2)
|
|
33905
34133
|
};
|
|
33906
34134
|
}
|
|
33907
34135
|
function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
|
|
@@ -33941,7 +34169,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
|
|
|
33941
34169
|
}
|
|
33942
34170
|
}
|
|
33943
34171
|
function removeMaterializedTree(packageDir, fs2) {
|
|
33944
|
-
const dest = (0,
|
|
34172
|
+
const dest = (0, import_node_path40.join)(packageDir, NODE_MODULES2);
|
|
33945
34173
|
if (!fs2.exists(dest)) return;
|
|
33946
34174
|
fs2.rm(dest);
|
|
33947
34175
|
if (fs2.exists(dest)) {
|
|
@@ -33949,7 +34177,7 @@ function removeMaterializedTree(packageDir, fs2) {
|
|
|
33949
34177
|
}
|
|
33950
34178
|
}
|
|
33951
34179
|
function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33952
|
-
const dest = (0,
|
|
34180
|
+
const dest = (0, import_node_path40.join)(destPackageDir, NODE_MODULES2);
|
|
33953
34181
|
try {
|
|
33954
34182
|
if (fs2.exists(dest)) fs2.rm(dest);
|
|
33955
34183
|
fs2.mkdirp(destPackageDir);
|
|
@@ -33964,7 +34192,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
|
|
|
33964
34192
|
}
|
|
33965
34193
|
}
|
|
33966
34194
|
async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile3, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
|
|
33967
|
-
const source = (0,
|
|
34195
|
+
const source = (0, import_node_path40.join)(sourcePackageDir, NODE_MODULES2);
|
|
33968
34196
|
if (!isMaterializableNodeModulesDir(source, fs2)) return;
|
|
33969
34197
|
const entry = worktreeInstallCacheEntry(primaryRoot, lockfile3.hash);
|
|
33970
34198
|
const manifest = {
|
|
@@ -34219,12 +34447,36 @@ function classifyStaleLeaks(input) {
|
|
|
34219
34447
|
remediation: "mmi-cli worktree gc --apply"
|
|
34220
34448
|
});
|
|
34221
34449
|
}
|
|
34450
|
+
for (const leftover of input.originLeftovers ?? []) {
|
|
34451
|
+
leaks.push({
|
|
34452
|
+
kind: "origin-leftover",
|
|
34453
|
+
ref: leftover.branch,
|
|
34454
|
+
detail: leftover.detail,
|
|
34455
|
+
remediation: leftover.autoReap ? "mmi-cli worktree gc --apply (conservative merged-head reap)" : leftover.kind === "open-pr" ? "leave open \u2014 gc will not delete an open PR head" : "mmi-cli worktree gc --apply --train-only (explicit; will not silently delete every non-train branch)"
|
|
34456
|
+
});
|
|
34457
|
+
}
|
|
34458
|
+
for (const helper of input.helperWorktrees ?? []) {
|
|
34459
|
+
leaks.push({
|
|
34460
|
+
kind: "helper-worktree",
|
|
34461
|
+
ref: helper.path,
|
|
34462
|
+
detail: helper.detail,
|
|
34463
|
+
remediation: helper.reapable ? "mmi-cli worktree gc --apply" : "inspect / git -C <primary> worktree remove --force after the helper is abandoned"
|
|
34464
|
+
});
|
|
34465
|
+
}
|
|
34466
|
+
for (const ref of input.missingLeaseRefs ?? []) {
|
|
34467
|
+
leaks.push({
|
|
34468
|
+
kind: "missing-lease",
|
|
34469
|
+
ref,
|
|
34470
|
+
detail: `jerv worktree lease still active but path is gone`,
|
|
34471
|
+
remediation: "mmi-cli worktree gc --apply (closes the lease; JPT #5548 also reaps on sweep)"
|
|
34472
|
+
});
|
|
34473
|
+
}
|
|
34222
34474
|
return leaks;
|
|
34223
34475
|
}
|
|
34224
34476
|
var defaultOrphanDirScanDeps = {
|
|
34225
34477
|
listDirs: (root) => {
|
|
34226
34478
|
try {
|
|
34227
|
-
return (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0,
|
|
34479
|
+
return (0, import_node_fs42.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path41.join)(root, e.name));
|
|
34228
34480
|
} catch {
|
|
34229
34481
|
return [];
|
|
34230
34482
|
}
|
|
@@ -34239,8 +34491,12 @@ function scanOrphanDirs(worktreesRoot, worktreeGitRoot, deps = defaultOrphanDirS
|
|
|
34239
34491
|
}
|
|
34240
34492
|
return candidates;
|
|
34241
34493
|
}
|
|
34242
|
-
function formatStaleLeaks(leaks, prLookupFailures = []) {
|
|
34243
|
-
const
|
|
34494
|
+
function formatStaleLeaks(leaks, prLookupFailures = [], audit) {
|
|
34495
|
+
const blocked = Boolean(audit?.blocksGreen);
|
|
34496
|
+
const lines = leaks.length ? [`worktree list --stale: ${leaks.length} leak(s)`] : blocked ? ["worktree list --stale: incomplete \u2014 refusing a clean report"] : ["worktree list --stale: no leaks found"];
|
|
34497
|
+
if (audit) {
|
|
34498
|
+
for (const line of formatEstateAuditLines(audit)) lines.push(` ${line}`);
|
|
34499
|
+
}
|
|
34244
34500
|
for (const leak of leaks) {
|
|
34245
34501
|
lines.push(` [${leak.kind}] ${leak.ref} \u2014 ${leak.detail}`);
|
|
34246
34502
|
lines.push(` fix: ${leak.remediation}`);
|
|
@@ -34390,13 +34646,13 @@ function registerWorktreeCommands(program3) {
|
|
|
34390
34646
|
const detached = headBorn && !symbolicBranch;
|
|
34391
34647
|
const branch = symbolicBranch || (detached ? "HEAD" : "");
|
|
34392
34648
|
if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
|
|
34393
|
-
const gitFile = (0,
|
|
34649
|
+
const gitFile = (0, import_node_path41.join)(wtPath, ".git");
|
|
34394
34650
|
const isLinked = (0, import_node_fs42.existsSync)(gitFile) && (0, import_node_fs42.statSync)(gitFile).isFile();
|
|
34395
34651
|
if (apply && !isLinked) {
|
|
34396
34652
|
return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
|
|
34397
34653
|
}
|
|
34398
34654
|
const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
34399
|
-
const primaryCheckout = commonDir ? (0,
|
|
34655
|
+
const primaryCheckout = commonDir ? (0, import_node_path41.dirname)(commonDir) : wtPath;
|
|
34400
34656
|
const localBranchNames = await execFileP2("git", ["-C", primaryCheckout, "for-each-ref", "--format=%(refname:short)", "refs/heads"], { timeout: GIT_TIMEOUT_MS }).then(({ stdout }) => new Set((stdout || "").split("\n").map((l) => l.trim()).filter(Boolean))).catch(() => void 0);
|
|
34401
34657
|
const orphan = classifyOrphanedWorktree({
|
|
34402
34658
|
branch,
|
|
@@ -34460,7 +34716,9 @@ function registerWorktreeCommands(program3) {
|
|
|
34460
34716
|
const reportedMergeState = treeOnly ? "not-checked" : mergeVerdict.state;
|
|
34461
34717
|
const landOwner = lookupWorktreeOwner(primaryCheckout, wtPath);
|
|
34462
34718
|
const activeWorkspaceRoot = resolveActiveWorkspaceRoot();
|
|
34463
|
-
const activeGuard = decideActiveWorkspaceGuard(wtPath, activeWorkspaceRoot
|
|
34719
|
+
const activeGuard = decideActiveWorkspaceGuard(wtPath, activeWorkspaceRoot, process.platform, {
|
|
34720
|
+
cursorAgentHost: isCursorAgentHost()
|
|
34721
|
+
});
|
|
34464
34722
|
if (activeGuard.action === "refuse") {
|
|
34465
34723
|
const deferredStore = await createDeferredWorktreeStore();
|
|
34466
34724
|
if (deferredStore) {
|
|
@@ -34536,6 +34794,9 @@ function registerWorktreeCommands(program3) {
|
|
|
34536
34794
|
step: "remove worktree",
|
|
34537
34795
|
status: removeOutcome.status === "removed" ? removeOutcome.recovery ? `done (${removeOutcome.recovery})` : "done" : removeOutcome.remainsOnDisk ? `failed: ${removeOutcome.error ?? "lock held"} \u2014 the directory "${wtPath}" is still on disk; cd every shell out of it (a cwd inside holds it open on Windows), then delete that directory` : `failed: ${removeOutcome.error ?? "lock held"} \u2014 run: git -C "${primaryCheckout}" worktree remove --force "${wtPath}"`
|
|
34538
34796
|
});
|
|
34797
|
+
if (!removeOutcome.remainsOnDisk) {
|
|
34798
|
+
report.push(await bestEffortLeaseClose(wtPath));
|
|
34799
|
+
}
|
|
34539
34800
|
if (!shouldContinueLandCleanup(removeOutcome.status)) {
|
|
34540
34801
|
const result2 = {
|
|
34541
34802
|
dryRun: false,
|
|
@@ -34620,8 +34881,17 @@ function registerWorktreeCommands(program3) {
|
|
|
34620
34881
|
if (o.stale) {
|
|
34621
34882
|
const leaks = classifyStaleLeaks(ctx);
|
|
34622
34883
|
const failures = ctx.prLookupFailures ?? [];
|
|
34623
|
-
|
|
34624
|
-
|
|
34884
|
+
const complete = failures.length === 0 && !ctx.audit?.blocksGreen;
|
|
34885
|
+
if (o.json) {
|
|
34886
|
+
return console.log(JSON.stringify({
|
|
34887
|
+
stale: leaks,
|
|
34888
|
+
count: leaks.length,
|
|
34889
|
+
prLookupFailures: failures,
|
|
34890
|
+
complete,
|
|
34891
|
+
audit: ctx.audit
|
|
34892
|
+
}, null, 2));
|
|
34893
|
+
}
|
|
34894
|
+
return console.log(formatStaleLeaks(leaks, failures, ctx.audit));
|
|
34625
34895
|
}
|
|
34626
34896
|
if (o.json) return console.log(JSON.stringify({ worktrees: ctx.worktrees }, null, 2));
|
|
34627
34897
|
if (!ctx.worktrees.length) return console.log("worktree list: no worktrees");
|
|
@@ -34645,10 +34915,18 @@ async function gatherWorktreeContext() {
|
|
|
34645
34915
|
const branchOut = (await execFileP2("git", ["branch", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
34646
34916
|
const localBranches = branchOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
34647
34917
|
const currentBranch2 = (await execFileP2("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || void 0;
|
|
34648
|
-
const
|
|
34918
|
+
const remoteBranchOut = (await execFileP2("git", ["branch", "-r", "--format=%(refname:short)"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
34919
|
+
const remoteBranches = remoteBranchOut.split(/\r?\n/).map((l) => l.trim()).filter((b) => b.startsWith("origin/") && b !== "origin/HEAD");
|
|
34920
|
+
const remoteNames = remoteBranches.map((b) => b.replace(/^origin\//, ""));
|
|
34921
|
+
const prTargets = [.../* @__PURE__ */ new Set([
|
|
34922
|
+
...localBranches.filter((b) => !PROTECTED_BRANCHES2.has(b)),
|
|
34923
|
+
...remoteNames.filter((b) => !PROTECTED_BRANCHES2.has(b))
|
|
34924
|
+
])];
|
|
34925
|
+
const { prs, failures: prLookupFailures } = await resolveBranchPrs(prTargets, STALE_PR_LOOKUP_LIMIT);
|
|
34649
34926
|
const openPrBranches = /* @__PURE__ */ new Set();
|
|
34650
34927
|
const closedBranches = /* @__PURE__ */ new Set();
|
|
34651
34928
|
const closedUnmergedBranches = /* @__PURE__ */ new Set();
|
|
34929
|
+
const mergedPrBranches = /* @__PURE__ */ new Set();
|
|
34652
34930
|
const byBranch = /* @__PURE__ */ new Map();
|
|
34653
34931
|
for (const pr2 of prs) {
|
|
34654
34932
|
const arr = byBranch.get(pr2.headRefName) ?? [];
|
|
@@ -34659,6 +34937,7 @@ async function gatherWorktreeContext() {
|
|
|
34659
34937
|
if (states.some((s) => s === "OPEN")) openPrBranches.add(br);
|
|
34660
34938
|
else if (states.some((s) => s === "MERGED" || s === "CLOSED")) {
|
|
34661
34939
|
closedBranches.add(br);
|
|
34940
|
+
if (states.some((s) => s === "MERGED")) mergedPrBranches.add(br);
|
|
34662
34941
|
if (!states.some((s) => s === "MERGED") && states.some((s) => s === "CLOSED")) {
|
|
34663
34942
|
closedUnmergedBranches.add(br);
|
|
34664
34943
|
}
|
|
@@ -34670,7 +34949,7 @@ async function gatherWorktreeContext() {
|
|
|
34670
34949
|
if (s) stages.push({ path: wt.path, port: s.port });
|
|
34671
34950
|
}
|
|
34672
34951
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
34673
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
34952
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path41.dirname)((0, import_node_path41.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
34674
34953
|
const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
|
|
34675
34954
|
let orphanDirs = [];
|
|
34676
34955
|
if ((0, import_node_fs42.existsSync)(wtRoot)) {
|
|
@@ -34679,6 +34958,44 @@ async function gatherWorktreeContext() {
|
|
|
34679
34958
|
listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
|
|
34680
34959
|
});
|
|
34681
34960
|
}
|
|
34961
|
+
const repoContainer = worktreesRootOf(primaryRepoRoot);
|
|
34962
|
+
if ((0, import_node_fs42.existsSync)(repoContainer)) {
|
|
34963
|
+
for (const dir of defaultOrphanDirScanDeps.listDirs(repoContainer)) {
|
|
34964
|
+
if (orphanDirs.some((o) => o.path === dir)) continue;
|
|
34965
|
+
const inspected = inspectSiblingWorktreeDir(dir, worktreeGitRoot);
|
|
34966
|
+
const classified = classifySiblingWorktreeDir(inspected);
|
|
34967
|
+
if (classified.cleanup) {
|
|
34968
|
+
orphanDirs.push({ path: dir, reason: classified.cleanup.reason });
|
|
34969
|
+
continue;
|
|
34970
|
+
}
|
|
34971
|
+
if (inspected.gitType === "missing" && pathProvesRepoContainerOwnership(dir, repoContainer)) {
|
|
34972
|
+
orphanDirs.push({ path: dir, reason: "orphaned-folder" });
|
|
34973
|
+
}
|
|
34974
|
+
}
|
|
34975
|
+
}
|
|
34976
|
+
const originLeftovers = classifyOriginLeftovers({
|
|
34977
|
+
remoteBranches,
|
|
34978
|
+
localBranches,
|
|
34979
|
+
protectedBranches: PROTECTED_BRANCHES2,
|
|
34980
|
+
openPrBranches,
|
|
34981
|
+
mergedPrBranches,
|
|
34982
|
+
closedUnmergedBranches
|
|
34983
|
+
});
|
|
34984
|
+
const helperWorktrees = scanHelperWorktrees(primaryRepoRoot, worktreeGitRoot);
|
|
34985
|
+
const leaseRefs = readJervWorktreeLeaseRefs();
|
|
34986
|
+
const missingLeaseRefs = leaseRefs.filter((ref) => !(0, import_node_fs42.existsSync)(ref));
|
|
34987
|
+
const remoteUrls = await gitRemoteUrls();
|
|
34988
|
+
const otherCheckouts = discoverOtherPrimaries(primaryRepoRoot).map((path2) => ({
|
|
34989
|
+
path: path2,
|
|
34990
|
+
remoteUrls: gitConfigRemoteUrls(path2)
|
|
34991
|
+
}));
|
|
34992
|
+
const audit = classifyEstateAudit({
|
|
34993
|
+
auditedClone: primaryRepoRoot,
|
|
34994
|
+
remoteUrls,
|
|
34995
|
+
otherCheckouts,
|
|
34996
|
+
leaseRefs,
|
|
34997
|
+
thisWorktreesRoot: repoContainer
|
|
34998
|
+
});
|
|
34682
34999
|
return {
|
|
34683
35000
|
worktrees,
|
|
34684
35001
|
localBranches,
|
|
@@ -34688,9 +35005,96 @@ async function gatherWorktreeContext() {
|
|
|
34688
35005
|
closedUnmergedBranches,
|
|
34689
35006
|
stages,
|
|
34690
35007
|
orphanDirs,
|
|
34691
|
-
prLookupFailures
|
|
35008
|
+
prLookupFailures,
|
|
35009
|
+
originLeftovers,
|
|
35010
|
+
helperWorktrees,
|
|
35011
|
+
missingLeaseRefs,
|
|
35012
|
+
audit
|
|
34692
35013
|
};
|
|
34693
35014
|
}
|
|
35015
|
+
function gitConfigRemoteUrls(checkout) {
|
|
35016
|
+
const gitPath = (0, import_node_path41.join)(checkout, ".git");
|
|
35017
|
+
let configPath = (0, import_node_path41.join)(checkout, ".git", "config");
|
|
35018
|
+
try {
|
|
35019
|
+
const st = (0, import_node_fs42.statSync)(gitPath);
|
|
35020
|
+
if (st.isFile()) return [];
|
|
35021
|
+
} catch {
|
|
35022
|
+
return [];
|
|
35023
|
+
}
|
|
35024
|
+
try {
|
|
35025
|
+
const text = (0, import_node_fs42.readFileSync)(configPath, "utf8");
|
|
35026
|
+
return [...text.matchAll(/^\s*url\s*=\s*(.+)$/gm)].map((m) => m[1].trim());
|
|
35027
|
+
} catch {
|
|
35028
|
+
return [];
|
|
35029
|
+
}
|
|
35030
|
+
}
|
|
35031
|
+
async function gitRemoteUrls() {
|
|
35032
|
+
const out = (await execFileP2("git", ["remote", "-v"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
35033
|
+
return [...new Set(
|
|
35034
|
+
out.split(/\r?\n/).map((line) => line.trim().split(/\s+/)[1]).filter((url) => Boolean(url))
|
|
35035
|
+
)];
|
|
35036
|
+
}
|
|
35037
|
+
function discoverOtherPrimaries(primaryRepoRoot) {
|
|
35038
|
+
const found = /* @__PURE__ */ new Set();
|
|
35039
|
+
const parent = (0, import_node_path41.dirname)(primaryRepoRoot);
|
|
35040
|
+
try {
|
|
35041
|
+
for (const name of (0, import_node_fs42.readdirSync)(parent)) {
|
|
35042
|
+
const path2 = (0, import_node_path41.join)(parent, name);
|
|
35043
|
+
if (path2 === primaryRepoRoot) continue;
|
|
35044
|
+
if ((0, import_node_fs42.existsSync)((0, import_node_path41.join)(path2, ".git"))) found.add(path2);
|
|
35045
|
+
}
|
|
35046
|
+
} catch {
|
|
35047
|
+
}
|
|
35048
|
+
const mirror = (0, import_node_path41.join)((0, import_node_os16.homedir)(), "Projects", (0, import_node_path41.basename)(primaryRepoRoot));
|
|
35049
|
+
if (mirror !== primaryRepoRoot && (0, import_node_fs42.existsSync)((0, import_node_path41.join)(mirror, ".git"))) found.add(mirror);
|
|
35050
|
+
return [...found];
|
|
35051
|
+
}
|
|
35052
|
+
function readJervWorktreeLeaseRefs(leaseDir = (0, import_node_path41.join)((0, import_node_os16.homedir)(), ".jerv", "leases")) {
|
|
35053
|
+
try {
|
|
35054
|
+
const refs = [];
|
|
35055
|
+
for (const name of (0, import_node_fs42.readdirSync)(leaseDir)) {
|
|
35056
|
+
if (!name.endsWith(".json")) continue;
|
|
35057
|
+
try {
|
|
35058
|
+
const rec = JSON.parse((0, import_node_fs42.readFileSync)((0, import_node_path41.join)(leaseDir, name), "utf8"));
|
|
35059
|
+
if (rec.kind === "worktree" && rec.state !== "closed" && typeof rec.ref === "string" && rec.ref.trim()) {
|
|
35060
|
+
refs.push(rec.ref);
|
|
35061
|
+
}
|
|
35062
|
+
} catch {
|
|
35063
|
+
}
|
|
35064
|
+
}
|
|
35065
|
+
return refs;
|
|
35066
|
+
} catch {
|
|
35067
|
+
return [];
|
|
35068
|
+
}
|
|
35069
|
+
}
|
|
35070
|
+
function scanHelperWorktrees(thisPrimary, thisWorktreeGitRoot) {
|
|
35071
|
+
const primaries = [thisPrimary, ...discoverOtherPrimaries(thisPrimary)];
|
|
35072
|
+
const out = [];
|
|
35073
|
+
for (const primary of primaries) {
|
|
35074
|
+
const gitRoot = primary === thisPrimary ? thisWorktreeGitRoot : (0, import_node_path41.join)(primary, ".git", "worktrees");
|
|
35075
|
+
for (const root of helperWorktreeRoots(primary)) {
|
|
35076
|
+
if (!(0, import_node_fs42.existsSync)(root)) continue;
|
|
35077
|
+
for (const dir of defaultOrphanDirScanDeps.listDirs(root)) {
|
|
35078
|
+
const inspected = inspectSiblingWorktreeDir(dir, gitRoot);
|
|
35079
|
+
const classified = classifySiblingWorktreeDir(inspected);
|
|
35080
|
+
if (classified.cleanup) {
|
|
35081
|
+
out.push({
|
|
35082
|
+
path: dir,
|
|
35083
|
+
detail: `${classified.cleanup.reason} helper worktree under ${root}`,
|
|
35084
|
+
reapable: true
|
|
35085
|
+
});
|
|
35086
|
+
} else {
|
|
35087
|
+
out.push({
|
|
35088
|
+
path: dir,
|
|
35089
|
+
detail: `helper worktree outside ../mmi-worktrees (${classified.skip?.reason ?? inspected.gitType}) at ${dir}`,
|
|
35090
|
+
reapable: false
|
|
35091
|
+
});
|
|
35092
|
+
}
|
|
35093
|
+
}
|
|
35094
|
+
}
|
|
35095
|
+
}
|
|
35096
|
+
return out;
|
|
35097
|
+
}
|
|
34694
35098
|
async function bestEffortGit(args, cwd, step, timeoutMs = GIT_TIMEOUT_MS) {
|
|
34695
35099
|
try {
|
|
34696
35100
|
const fullArgs = cwd ? ["-C", cwd, ...args] : args;
|
|
@@ -35408,7 +35812,7 @@ ${lines}`, {
|
|
|
35408
35812
|
|
|
35409
35813
|
// src/train-commands.ts
|
|
35410
35814
|
var import_node_fs44 = require("node:fs");
|
|
35411
|
-
var
|
|
35815
|
+
var import_node_path42 = require("node:path");
|
|
35412
35816
|
var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
35413
35817
|
function resolveReleaseBumpIntent(raw) {
|
|
35414
35818
|
const intent = typeof raw === "string" ? raw.trim() : "";
|
|
@@ -35419,7 +35823,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
35419
35823
|
}
|
|
35420
35824
|
function readRepoVersion() {
|
|
35421
35825
|
try {
|
|
35422
|
-
return JSON.parse((0, import_node_fs44.readFileSync)((0,
|
|
35826
|
+
return JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path42.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
35423
35827
|
} catch {
|
|
35424
35828
|
return void 0;
|
|
35425
35829
|
}
|
|
@@ -35577,8 +35981,8 @@ function registerDeployCommands(program3) {
|
|
|
35577
35981
|
|
|
35578
35982
|
// src/discovery-commands.ts
|
|
35579
35983
|
var import_node_fs45 = require("node:fs");
|
|
35580
|
-
var
|
|
35581
|
-
var
|
|
35984
|
+
var import_node_os17 = require("node:os");
|
|
35985
|
+
var import_node_path43 = require("node:path");
|
|
35582
35986
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
35583
35987
|
async function collectStatus() {
|
|
35584
35988
|
const repo = await resolveRepo();
|
|
@@ -35766,10 +36170,10 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
35766
36170
|
else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
|
|
35767
36171
|
else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
|
|
35768
36172
|
}
|
|
35769
|
-
const home = (0,
|
|
36173
|
+
const home = (0, import_node_os17.homedir)();
|
|
35770
36174
|
const plugin = onboardPluginGate({
|
|
35771
|
-
readKnown: () => readFileSyncSafe((0,
|
|
35772
|
-
readSettings: () => readFileSyncSafe((0,
|
|
36175
|
+
readKnown: () => readFileSyncSafe((0, import_node_path43.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs45.readFileSync),
|
|
36176
|
+
readSettings: () => readFileSyncSafe((0, import_node_path43.join)(home, ".claude", "settings.json"), import_node_fs45.readFileSync)
|
|
35773
36177
|
});
|
|
35774
36178
|
return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
|
|
35775
36179
|
}
|
|
@@ -36905,18 +37309,18 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
36905
37309
|
|
|
36906
37310
|
// src/plugin-release-catchup.ts
|
|
36907
37311
|
var import_node_fs46 = require("node:fs");
|
|
36908
|
-
var
|
|
36909
|
-
var
|
|
37312
|
+
var import_node_path44 = require("node:path");
|
|
37313
|
+
var import_node_os18 = require("node:os");
|
|
36910
37314
|
var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
36911
37315
|
var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
|
|
36912
37316
|
function releaseCatchupStatePath(env = process.env) {
|
|
36913
37317
|
if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
|
|
36914
37318
|
if (process.platform === "win32") {
|
|
36915
|
-
const base2 = env.LOCALAPPDATA || (0,
|
|
36916
|
-
return (0,
|
|
37319
|
+
const base2 = env.LOCALAPPDATA || (0, import_node_path44.join)((0, import_node_os18.homedir)(), "AppData", "Local");
|
|
37320
|
+
return (0, import_node_path44.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
|
|
36917
37321
|
}
|
|
36918
|
-
const base = env.XDG_STATE_HOME || (0,
|
|
36919
|
-
return (0,
|
|
37322
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path44.join)((0, import_node_os18.homedir)(), ".local", "state");
|
|
37323
|
+
return (0, import_node_path44.join)(base, "mmi-cli", "release-catchup.json");
|
|
36920
37324
|
}
|
|
36921
37325
|
function releaseCatchupDue(state, now, force = false) {
|
|
36922
37326
|
if (force) return true;
|
|
@@ -36934,15 +37338,15 @@ function newestCachedPluginVersion(home) {
|
|
|
36934
37338
|
}
|
|
36935
37339
|
function marketplaceClonePath(home) {
|
|
36936
37340
|
try {
|
|
36937
|
-
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0,
|
|
37341
|
+
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
|
|
36938
37342
|
if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
|
|
36939
37343
|
} catch {
|
|
36940
37344
|
}
|
|
36941
|
-
return (0,
|
|
37345
|
+
return (0, import_node_path44.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
|
|
36942
37346
|
}
|
|
36943
37347
|
function readCatalogVersion(home) {
|
|
36944
37348
|
try {
|
|
36945
|
-
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0,
|
|
37349
|
+
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
|
|
36946
37350
|
return parsed.plugins?.find((p) => p.name === "mmi")?.version;
|
|
36947
37351
|
} catch {
|
|
36948
37352
|
return void 0;
|
|
@@ -36950,7 +37354,7 @@ function readCatalogVersion(home) {
|
|
|
36950
37354
|
}
|
|
36951
37355
|
function readMmiInstallRecord(home) {
|
|
36952
37356
|
try {
|
|
36953
|
-
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0,
|
|
37357
|
+
const parsed = JSON.parse((0, import_node_fs46.readFileSync)((0, import_node_path44.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
|
|
36954
37358
|
const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
|
|
36955
37359
|
return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
|
|
36956
37360
|
} catch {
|
|
@@ -37012,7 +37416,7 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
37012
37416
|
return { ok: false, detail: `${cliUpdateDetail}; plugin install record could not be cleared (still ${prior.version})` };
|
|
37013
37417
|
}
|
|
37014
37418
|
const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
|
|
37015
|
-
const payload = (0,
|
|
37419
|
+
const payload = (0, import_node_path44.join)(pluginCacheRoot(home), latest, ".pi-plugin");
|
|
37016
37420
|
if (!installed || !(0, import_node_fs46.existsSync)(payload)) {
|
|
37017
37421
|
const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
|
|
37018
37422
|
if (!prior) return { ok: false, detail: `${cliUpdateDetail}; ${why}; no prior record to restore` };
|
|
@@ -38048,10 +38452,10 @@ function checkRepoWorktrees(probe) {
|
|
|
38048
38452
|
ok: !(probe.isOrgRepo && probe.hasRepoLocalWorktrees),
|
|
38049
38453
|
id: "repo-worktrees",
|
|
38050
38454
|
label: "repo worktrees",
|
|
38051
|
-
fix: "repo-local `.worktrees/`
|
|
38455
|
+
fix: "repo-local `.worktrees/` / `.claude/worktrees` are not the canonical path \u2014 use `mmi-cli worktree create <branch>` (sibling `../mmi-worktrees/<Repo>/`), then `mmi-cli worktree gc --apply` for abandoned helper trees",
|
|
38052
38456
|
verbose: [
|
|
38053
38457
|
`org repo: ${probe.isOrgRepo ? "yes" : "no"}`,
|
|
38054
|
-
`repo-local .worktrees/: ${probe.hasRepoLocalWorktrees ? "present" : "absent"}`
|
|
38458
|
+
`repo-local .worktrees/ or .claude/worktrees/: ${probe.hasRepoLocalWorktrees ? "present" : "absent"}`
|
|
38055
38459
|
]
|
|
38056
38460
|
};
|
|
38057
38461
|
}
|
|
@@ -39238,17 +39642,17 @@ function parseOriginRepo(remoteUrl) {
|
|
|
39238
39642
|
}
|
|
39239
39643
|
function ghHostsConfigPath(env, platform2) {
|
|
39240
39644
|
const sep3 = platform2 === "win32" ? "\\" : "/";
|
|
39241
|
-
const
|
|
39645
|
+
const join41 = (...parts) => parts.join(sep3);
|
|
39242
39646
|
const explicit = env.GH_CONFIG_DIR?.trim();
|
|
39243
|
-
if (explicit) return
|
|
39647
|
+
if (explicit) return join41(explicit, "hosts.yml");
|
|
39244
39648
|
if (platform2 === "win32") {
|
|
39245
39649
|
const appData = (env.AppData ?? env.APPDATA)?.trim();
|
|
39246
|
-
return appData ?
|
|
39650
|
+
return appData ? join41(appData, "GitHub CLI", "hosts.yml") : void 0;
|
|
39247
39651
|
}
|
|
39248
39652
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
39249
|
-
if (xdg) return
|
|
39653
|
+
if (xdg) return join41(xdg, "gh", "hosts.yml");
|
|
39250
39654
|
const home = env.HOME?.trim();
|
|
39251
|
-
return home ?
|
|
39655
|
+
return home ? join41(home, ".config", "gh", "hosts.yml") : void 0;
|
|
39252
39656
|
}
|
|
39253
39657
|
function parseGhHostsAccounts(yaml, host = "github.com") {
|
|
39254
39658
|
let hostIndent = null;
|
|
@@ -39299,8 +39703,8 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
39299
39703
|
|
|
39300
39704
|
// src/doctor-io.ts
|
|
39301
39705
|
var import_node_fs47 = require("node:fs");
|
|
39302
|
-
var
|
|
39303
|
-
var
|
|
39706
|
+
var import_node_os19 = require("node:os");
|
|
39707
|
+
var import_node_path45 = require("node:path");
|
|
39304
39708
|
var import_node_child_process19 = require("node:child_process");
|
|
39305
39709
|
var import_node_util8 = require("node:util");
|
|
39306
39710
|
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
|
|
@@ -39308,7 +39712,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
39308
39712
|
function installedClaudePluginVersion() {
|
|
39309
39713
|
try {
|
|
39310
39714
|
const file = JSON.parse(
|
|
39311
|
-
(0, import_node_fs47.readFileSync)((0,
|
|
39715
|
+
(0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os19.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
39312
39716
|
);
|
|
39313
39717
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
39314
39718
|
if (versions.length === 0) return void 0;
|
|
@@ -39329,22 +39733,22 @@ function installedSurfacePluginVersion(surface) {
|
|
|
39329
39733
|
const token = surfaceToken(surface);
|
|
39330
39734
|
if (token === "kilo") {
|
|
39331
39735
|
try {
|
|
39332
|
-
const stamp = (0, import_node_fs47.readFileSync)((0,
|
|
39736
|
+
const stamp = (0, import_node_fs47.readFileSync)((0, import_node_path45.join)((0, import_node_os19.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
|
|
39333
39737
|
return stamp || void 0;
|
|
39334
39738
|
} catch {
|
|
39335
39739
|
return void 0;
|
|
39336
39740
|
}
|
|
39337
39741
|
}
|
|
39338
39742
|
if (token === "cursor") {
|
|
39339
|
-
return manifestVersion((0,
|
|
39743
|
+
return manifestVersion((0, import_node_path45.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
39340
39744
|
}
|
|
39341
39745
|
if (token === "jervcode") {
|
|
39342
39746
|
const entry = mmiPiWrapperEntry();
|
|
39343
39747
|
if (!entry) return void 0;
|
|
39344
|
-
return manifestVersion((0,
|
|
39748
|
+
return manifestVersion((0, import_node_path45.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
|
|
39345
39749
|
}
|
|
39346
39750
|
if (token === "kimi") {
|
|
39347
|
-
return manifestVersion((0,
|
|
39751
|
+
return manifestVersion((0, import_node_path45.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
|
|
39348
39752
|
}
|
|
39349
39753
|
if (token === "claude") return installedClaudePluginVersion();
|
|
39350
39754
|
if (token !== "codex") return void 0;
|
|
@@ -39382,7 +39786,7 @@ function worktreeRootSync() {
|
|
|
39382
39786
|
}
|
|
39383
39787
|
var gitignorePath = () => {
|
|
39384
39788
|
const root = worktreeRootSync();
|
|
39385
|
-
return root === null ? null : (0,
|
|
39789
|
+
return root === null ? null : (0, import_node_path45.join)(root, ".gitignore");
|
|
39386
39790
|
};
|
|
39387
39791
|
function readGitignore() {
|
|
39388
39792
|
const path2 = gitignorePath();
|
|
@@ -39416,7 +39820,7 @@ async function repoRoot() {
|
|
|
39416
39820
|
}
|
|
39417
39821
|
function hasRepoLocalWorktrees() {
|
|
39418
39822
|
const root = worktreeRootSync();
|
|
39419
|
-
return root !== null && (0, import_node_fs47.existsSync)((0,
|
|
39823
|
+
return root !== null && ((0, import_node_fs47.existsSync)((0, import_node_path45.join)(root, ".worktrees")) || (0, import_node_fs47.existsSync)((0, import_node_path45.join)(root, ".claude", "worktrees")));
|
|
39420
39824
|
}
|
|
39421
39825
|
|
|
39422
39826
|
// src/cross-repo-filing-issue.ts
|
|
@@ -39512,7 +39916,7 @@ function binaryOnPath(bin) {
|
|
|
39512
39916
|
for (const dir of pathEnvEntries(process.env.PATH ?? "")) {
|
|
39513
39917
|
for (const ext of exts) {
|
|
39514
39918
|
try {
|
|
39515
|
-
if ((0, import_node_fs48.existsSync)((0,
|
|
39919
|
+
if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(dir, `${bin}${ext}`))) return true;
|
|
39516
39920
|
} catch {
|
|
39517
39921
|
}
|
|
39518
39922
|
}
|
|
@@ -39543,12 +39947,12 @@ function ghMultiAccountCaveat(announcedLogin) {
|
|
|
39543
39947
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
39544
39948
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
39545
39949
|
function envHealLockPath(home) {
|
|
39546
|
-
return (0,
|
|
39950
|
+
return (0, import_node_path46.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
39547
39951
|
}
|
|
39548
39952
|
async function withEnvHealLock(what, run) {
|
|
39549
39953
|
try {
|
|
39550
39954
|
return await withFileLock(
|
|
39551
|
-
envHealLockPath((0,
|
|
39955
|
+
envHealLockPath((0, import_node_os20.homedir)()),
|
|
39552
39956
|
{ staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
|
|
39553
39957
|
run
|
|
39554
39958
|
);
|
|
@@ -39645,7 +40049,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39645
40049
|
const configRoot = surfaceConfigRoot(surface);
|
|
39646
40050
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
39647
40051
|
const plan = buildPluginCachePlan(
|
|
39648
|
-
(0,
|
|
40052
|
+
(0, import_node_os20.homedir)(),
|
|
39649
40053
|
running,
|
|
39650
40054
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
39651
40055
|
{ configRoot, includeStaging: surface !== "codex" }
|
|
@@ -39669,7 +40073,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39669
40073
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
39670
40074
|
const installed = installedActivePluginVersion(surface);
|
|
39671
40075
|
const plan = buildPluginCachePlan(
|
|
39672
|
-
(0,
|
|
40076
|
+
(0, import_node_os20.homedir)(),
|
|
39673
40077
|
running,
|
|
39674
40078
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
39675
40079
|
{ configRoot, includeStaging: surface !== "codex", installedVersion: installed }
|
|
@@ -39704,12 +40108,12 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39704
40108
|
piPluginState: () => {
|
|
39705
40109
|
const env = { ...process.env };
|
|
39706
40110
|
delete env.CLAUDE_PLUGIN_ROOT;
|
|
39707
|
-
return readPiPluginState((0,
|
|
40111
|
+
return readPiPluginState((0, import_node_os20.homedir)(), env);
|
|
39708
40112
|
},
|
|
39709
40113
|
healPiPlugin: () => {
|
|
39710
40114
|
const env = { ...process.env };
|
|
39711
40115
|
delete env.CLAUDE_PLUGIN_ROOT;
|
|
39712
|
-
return healPiPluginRegistration((0,
|
|
40116
|
+
return healPiPluginRegistration((0, import_node_os20.homedir)(), env);
|
|
39713
40117
|
},
|
|
39714
40118
|
// #4743: the global `claude` binary left as a ~500-byte placeholder by a self-update that died
|
|
39715
40119
|
// EBUSY mid-install. A local read (package.json + the first bytes of two files) — no npm spawn:
|
|
@@ -39748,7 +40152,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39748
40152
|
disableAutoUpdate: () => {
|
|
39749
40153
|
if (detectSurface(process.env) === "codex") return void 0;
|
|
39750
40154
|
return disableOrgMarketplaceBackgroundUpdates(
|
|
39751
|
-
(0,
|
|
40155
|
+
(0, import_node_path46.join)((0, import_node_os20.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE),
|
|
39752
40156
|
[MMI_MARKETPLACE_NAME]
|
|
39753
40157
|
);
|
|
39754
40158
|
}
|
|
@@ -39762,7 +40166,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39762
40166
|
// adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
|
|
39763
40167
|
// get a permanent — demanding an artifact it never asked for.
|
|
39764
40168
|
docsIndexState: (root) => {
|
|
39765
|
-
if (!(0, import_node_fs48.existsSync)((0,
|
|
40169
|
+
if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
39766
40170
|
const real = createDocsIndexDeps(root);
|
|
39767
40171
|
let docs2;
|
|
39768
40172
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39771,7 +40175,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39771
40175
|
},
|
|
39772
40176
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
39773
40177
|
healDocsIndex: (root) => {
|
|
39774
|
-
if (!(0, import_node_fs48.existsSync)((0,
|
|
40178
|
+
if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
39775
40179
|
const real = createDocsIndexDeps(root);
|
|
39776
40180
|
let docs2;
|
|
39777
40181
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -40137,7 +40541,7 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
40137
40541
|
});
|
|
40138
40542
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
40139
40543
|
rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
|
|
40140
|
-
const path2 = (0,
|
|
40544
|
+
const path2 = (0, import_node_path46.join)(process.cwd(), ".gitignore");
|
|
40141
40545
|
const current = (0, import_node_fs48.existsSync)(path2) ? (0, import_node_fs48.readFileSync)(path2, "utf8") : null;
|
|
40142
40546
|
const plan = planManagedGitignore(current);
|
|
40143
40547
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
@@ -40291,7 +40695,7 @@ gcCmd.command("sweep-deferred").description("retry IDE-locked deferred worktree
|
|
|
40291
40695
|
process.exit(process.exitCode ?? 0);
|
|
40292
40696
|
});
|
|
40293
40697
|
});
|
|
40294
|
-
gcCmd.option("--dry-run", "show what would be deleted (default)").option("--apply", "delete only the listed clean merged/closed PR local+remote branches, linked worktrees, and stale tracking refs").option("--json", "machine-readable output").option("--scratch", "prune safe local scratch (#1864) instead of git branches/refs; local plans are surfaced advisory-only, never auto-pruned").option("--remote <name>", "remote name", "origin").option("--limit <n>", "PRs to read PER BRANCH \u2014 an effort bound, not a correctness one: merge state is resolved per branch, so no branch is ever skipped for being old (#4227)", "200").option("--force", "remove worktrees even when the ownership registry shows another session created or worked in them recently (#3580), or when a dead worktree directory still holds leftover files (#4779)").option("--root <path>", "sweep an explicitly named worktrees root instead of the authoritative ../mmi-worktrees (#3471) \u2014 descends into this repo container when present; ownership, dead-dir, and content guards still apply").action(async (o) => {
|
|
40698
|
+
gcCmd.option("--dry-run", "show what would be deleted (default)").option("--apply", "delete only the listed clean merged/closed PR local+remote branches, linked worktrees, and stale tracking refs").option("--json", "machine-readable output").option("--scratch", "prune safe local scratch (#1864) instead of git branches/refs; local plans are surfaced advisory-only, never auto-pruned").option("--remote <name>", "remote name", "origin").option("--limit <n>", "PRs to read PER BRANCH \u2014 an effort bound, not a correctness one: merge state is resolved per branch, so no branch is ever skipped for being old (#4227)", "200").option("--force", "remove worktrees even when the ownership registry shows another session created or worked in them recently (#3580), or when a dead worktree directory still holds leftover files (#4779)").option("--root <path>", "sweep an explicitly named worktrees root instead of the authoritative ../mmi-worktrees (#3471) \u2014 descends into this repo container when present; ownership, dead-dir, and content guards still apply").option("--train-only", "explicit keep-only-train path: also reap closed-not-merged / no-PR origin leftovers; never deletes open PR heads (#4903)").action(async (o) => {
|
|
40295
40699
|
if (o.apply && o.dryRun) return fail("worktree gc: choose either --dry-run or --apply");
|
|
40296
40700
|
if (o.scratch) {
|
|
40297
40701
|
try {
|
|
@@ -40308,7 +40712,7 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
40308
40712
|
if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
|
|
40309
40713
|
let root;
|
|
40310
40714
|
if (o.root !== void 0) {
|
|
40311
|
-
root = (0,
|
|
40715
|
+
root = (0, import_node_path46.resolve)(o.root);
|
|
40312
40716
|
if (!(0, import_node_fs48.existsSync)(root) || !(0, import_node_fs48.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
|
|
40313
40717
|
const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
40314
40718
|
if (isPathUnderDirectory2(gcRepoRoot, root)) {
|
|
@@ -40316,10 +40720,11 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
40316
40720
|
}
|
|
40317
40721
|
}
|
|
40318
40722
|
try {
|
|
40319
|
-
const plan = await gcPlan(o.remote, limit, { root });
|
|
40723
|
+
const plan = await gcPlan(o.remote, limit, { root, trainOnly: o.trainOnly });
|
|
40724
|
+
const auditedClone = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
40320
40725
|
if (root && !o.json) console.log(`worktree gc: scanning the explicitly named root ${root} for worktrees proven to belong to this repo
|
|
40321
40726
|
`);
|
|
40322
|
-
if (o.apply && !o.json) console.log(formatGcPlan(plan, true));
|
|
40727
|
+
if (o.apply && !o.json) console.log(formatGcPlan(plan, true, auditedClone));
|
|
40323
40728
|
let applyResult;
|
|
40324
40729
|
if (o.apply) {
|
|
40325
40730
|
const deferredStore = await createDeferredWorktreeStore();
|
|
@@ -40338,7 +40743,7 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
40338
40743
|
if (o.json) {
|
|
40339
40744
|
console.log(JSON.stringify({ dryRun: !o.apply, remote: o.remote, ...root ? { root } : {}, plan, applyResult }, null, 2));
|
|
40340
40745
|
} else if (!o.apply) {
|
|
40341
|
-
console.log(formatGcPlan(plan, false));
|
|
40746
|
+
console.log(formatGcPlan(plan, false, auditedClone));
|
|
40342
40747
|
} else {
|
|
40343
40748
|
if (applyResult) console.log(`
|
|
40344
40749
|
${renderGcApplyResult(applyResult, plan.skipped)}`);
|
|
@@ -40402,7 +40807,8 @@ async function currentWorktreeRemovalContext(command, force) {
|
|
|
40402
40807
|
actor: describeActor({ env: process.env, surface: detectSurface(process.env), cwd }),
|
|
40403
40808
|
command,
|
|
40404
40809
|
...force ? { force: true } : {},
|
|
40405
|
-
...activeWorkspaceRoot ? { activeWorkspaceRoot } : {}
|
|
40810
|
+
...activeWorkspaceRoot ? { activeWorkspaceRoot } : {},
|
|
40811
|
+
cursorAgentHost: isCursorAgentHost()
|
|
40406
40812
|
};
|
|
40407
40813
|
}
|
|
40408
40814
|
async function unprovenWorktreeReason(wtPath, repoRoot2) {
|
|
@@ -40450,7 +40856,7 @@ function acquireWorktreeSetupLock(worktreeRoot) {
|
|
|
40450
40856
|
};
|
|
40451
40857
|
};
|
|
40452
40858
|
try {
|
|
40453
|
-
(0, import_node_fs48.mkdirSync)((0,
|
|
40859
|
+
(0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(lockPath), { recursive: true });
|
|
40454
40860
|
return take();
|
|
40455
40861
|
} catch {
|
|
40456
40862
|
try {
|
|
@@ -42136,11 +42542,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
42136
42542
|
}
|
|
42137
42543
|
});
|
|
42138
42544
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
42139
|
-
const wfDir = (0,
|
|
42545
|
+
const wfDir = (0, import_node_path46.join)(cwd, ".github", "workflows");
|
|
42140
42546
|
if (!(0, import_node_fs48.existsSync)(wfDir)) return [];
|
|
42141
42547
|
return (0, import_node_fs48.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
42142
42548
|
try {
|
|
42143
|
-
return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0,
|
|
42549
|
+
return workflowReportsPrChecks((0, import_node_fs48.readFileSync)((0, import_node_path46.join)(wfDir, name), "utf8"));
|
|
42144
42550
|
} catch {
|
|
42145
42551
|
return true;
|
|
42146
42552
|
}
|
|
@@ -42192,16 +42598,16 @@ function ciAuditDeps() {
|
|
|
42192
42598
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
42193
42599
|
readSeedFile: (path2) => {
|
|
42194
42600
|
if (!root) return null;
|
|
42195
|
-
const fullPath = (0,
|
|
42601
|
+
const fullPath = (0, import_node_path46.join)(root, path2);
|
|
42196
42602
|
return (0, import_node_fs48.existsSync)(fullPath) ? (0, import_node_fs48.readFileSync)(fullPath, "utf8") : null;
|
|
42197
42603
|
}
|
|
42198
42604
|
};
|
|
42199
42605
|
}
|
|
42200
42606
|
function hubRoot() {
|
|
42201
|
-
const fromPkg = (0,
|
|
42607
|
+
const fromPkg = (0, import_node_path46.join)(__dirname, "..", "..");
|
|
42202
42608
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
42203
|
-
if ((0, import_node_fs48.existsSync)((0,
|
|
42204
|
-
if ((0, import_node_fs48.existsSync)((0,
|
|
42609
|
+
if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(fromPkg, marker))) return fromPkg;
|
|
42610
|
+
if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(process.cwd(), marker))) return process.cwd();
|
|
42205
42611
|
return null;
|
|
42206
42612
|
}
|
|
42207
42613
|
async function waitLoopCorePool(label) {
|
|
@@ -43257,7 +43663,7 @@ function directoryBytes(path2) {
|
|
|
43257
43663
|
return 0;
|
|
43258
43664
|
}
|
|
43259
43665
|
for (const entry of entries) {
|
|
43260
|
-
const child2 = (0,
|
|
43666
|
+
const child2 = (0, import_node_path46.join)(path2, entry.name);
|
|
43261
43667
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
43262
43668
|
else {
|
|
43263
43669
|
try {
|
|
@@ -43287,7 +43693,7 @@ function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
|
43287
43693
|
dirBytes,
|
|
43288
43694
|
listStagingDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
43289
43695
|
try {
|
|
43290
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
43696
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path46.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs48.statSync)(p).mtimeMs) };
|
|
43291
43697
|
} catch {
|
|
43292
43698
|
return { name: d.name, mtimeMs: Date.now() };
|
|
43293
43699
|
}
|
|
@@ -43301,7 +43707,7 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
43301
43707
|
return {
|
|
43302
43708
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
43303
43709
|
mtimeMs: (name) => {
|
|
43304
|
-
const p = (0,
|
|
43710
|
+
const p = (0, import_node_path46.join)(stagingRoot, name);
|
|
43305
43711
|
if (!(0, import_node_fs48.existsSync)(p)) return null;
|
|
43306
43712
|
try {
|
|
43307
43713
|
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs48.statSync)(q).mtimeMs);
|
|
@@ -43324,7 +43730,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
43324
43730
|
return;
|
|
43325
43731
|
}
|
|
43326
43732
|
const plan = buildPluginCachePlan(
|
|
43327
|
-
(0,
|
|
43733
|
+
(0, import_node_os20.homedir)(),
|
|
43328
43734
|
running,
|
|
43329
43735
|
pluginCacheFsDeps(configRoot, directoryBytes),
|
|
43330
43736
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
@@ -43346,7 +43752,7 @@ function readReleaseCatchupState(path2) {
|
|
|
43346
43752
|
}
|
|
43347
43753
|
function writeReleaseCatchupState(path2, state) {
|
|
43348
43754
|
try {
|
|
43349
|
-
(0, import_node_fs48.mkdirSync)((0,
|
|
43755
|
+
(0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(path2), { recursive: true });
|
|
43350
43756
|
(0, import_node_fs48.writeFileSync)(path2, `${JSON.stringify(state)}
|
|
43351
43757
|
`);
|
|
43352
43758
|
} catch {
|
|
@@ -43355,7 +43761,7 @@ function writeReleaseCatchupState(path2, state) {
|
|
|
43355
43761
|
program2.command("plugin-release-catchup").description("install a newer released MMI plugin clone non-destructively and re-point the Pi registration (#4297); TTL-gated no-op when current").option("--force", "skip the 24h TTL (acceptance proof / manual run)").option("--quiet", "print only failures (the detached session-start lane)").option("--json", "machine-readable output").action(async (o) => {
|
|
43356
43762
|
const outcome = await withEnvHealLock(
|
|
43357
43763
|
"plugin release catch-up",
|
|
43358
|
-
() => runReleaseCatchup((0,
|
|
43764
|
+
() => runReleaseCatchup((0, import_node_os20.homedir)(), process.env, {
|
|
43359
43765
|
fetchReleased: fetchNpmReleasedVersion,
|
|
43360
43766
|
runClaude: (args, step) => runPluginCli("claude", args, (msg) => {
|
|
43361
43767
|
if (!o.quiet && !o.json) console.log(msg);
|
|
@@ -43371,7 +43777,7 @@ program2.command("plugin-release-catchup").description("install a newer released
|
|
|
43371
43777
|
},
|
|
43372
43778
|
readState: readReleaseCatchupState,
|
|
43373
43779
|
writeState: writeReleaseCatchupState,
|
|
43374
|
-
healRegistration: defaultRegistrationHeal((0,
|
|
43780
|
+
healRegistration: defaultRegistrationHeal((0, import_node_os20.homedir)(), process.env),
|
|
43375
43781
|
now: () => Date.now()
|
|
43376
43782
|
}, { force: o.force })
|
|
43377
43783
|
);
|
|
@@ -43439,7 +43845,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
|
|
|
43439
43845
|
spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process20.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
|
|
43440
43846
|
bannerIo.log(worktreeBanner);
|
|
43441
43847
|
}
|
|
43442
|
-
if (shouldSpawnReleaseCatchup((0,
|
|
43848
|
+
if (shouldSpawnReleaseCatchup((0, import_node_os20.homedir)(), process.env, readReleaseCatchupState)) {
|
|
43443
43849
|
spawnDetachedSelf(["plugin", "release-catchup", "--quiet"], { spawn: import_node_child_process20.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
|
|
43444
43850
|
}
|
|
43445
43851
|
if (isLinkedWorktree(process.cwd())) {
|