@mutmutco/cli 3.117.0 → 3.118.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 +574 -519
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -5000,7 +5000,7 @@ var program = new Command();
|
|
|
5000
5000
|
|
|
5001
5001
|
// src/index.ts
|
|
5002
5002
|
var import_promises11 = require("node:fs/promises");
|
|
5003
|
-
var
|
|
5003
|
+
var import_node_fs47 = require("node:fs");
|
|
5004
5004
|
var import_node_child_process20 = require("node:child_process");
|
|
5005
5005
|
|
|
5006
5006
|
// src/cli-shared.ts
|
|
@@ -8708,6 +8708,40 @@ function cachedReadNote(cachedAt, now = Date.now()) {
|
|
|
8708
8708
|
return `(cached ${hours < 1 ? "<1" : hours}h ago \u2014 the banner reads npm at most once a day)`;
|
|
8709
8709
|
}
|
|
8710
8710
|
|
|
8711
|
+
// src/schedules-drift-cache.ts
|
|
8712
|
+
var import_node_fs13 = require("node:fs");
|
|
8713
|
+
var import_node_path11 = require("node:path");
|
|
8714
|
+
var SCHEDULES_DRIFT_CACHE_MS = 6 * 36e5;
|
|
8715
|
+
function schedulesDriftCachePath(runtimeRoot) {
|
|
8716
|
+
return (0, import_node_path11.join)(runtimeRoot, "head-ts", ".schedules-drift");
|
|
8717
|
+
}
|
|
8718
|
+
function readSchedulesDriftCache(cachePath, now = Date.now(), read = import_node_fs13.readFileSync) {
|
|
8719
|
+
let parsed;
|
|
8720
|
+
try {
|
|
8721
|
+
parsed = JSON.parse(read(cachePath, "utf8"));
|
|
8722
|
+
} catch {
|
|
8723
|
+
return void 0;
|
|
8724
|
+
}
|
|
8725
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
8726
|
+
const { driftLines, at } = parsed;
|
|
8727
|
+
if (!Array.isArray(driftLines) || driftLines.some((l) => typeof l !== "string")) return void 0;
|
|
8728
|
+
if (typeof at !== "number" || !Number.isFinite(at)) return void 0;
|
|
8729
|
+
const age = now - at;
|
|
8730
|
+
if (age < 0 || age >= SCHEDULES_DRIFT_CACHE_MS) return void 0;
|
|
8731
|
+
return { driftLines, at };
|
|
8732
|
+
}
|
|
8733
|
+
function writeSchedulesDriftCache(cachePath, driftLines, now = Date.now()) {
|
|
8734
|
+
try {
|
|
8735
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(cachePath), { recursive: true });
|
|
8736
|
+
(0, import_node_fs13.writeFileSync)(cachePath, JSON.stringify({ driftLines, at: now }), "utf8");
|
|
8737
|
+
} catch {
|
|
8738
|
+
}
|
|
8739
|
+
}
|
|
8740
|
+
function cachedSweepNote(cachedAt, now = Date.now()) {
|
|
8741
|
+
const hours = cacheAgeHours(cachedAt, now);
|
|
8742
|
+
return `cached ${hours < 1 ? "<1" : hours}h ago \u2014 doctor sweeps the org notebook at most every ${SCHEDULES_DRIFT_CACHE_MS / 36e5}h (run \`mmi-cli harbour org schedules\` for a live read)`;
|
|
8743
|
+
}
|
|
8744
|
+
|
|
8711
8745
|
// src/marketplace-autoupdate.ts
|
|
8712
8746
|
var KNOWN_MARKETPLACES_RELATIVE = [".claude", "plugins", "known_marketplaces.json"];
|
|
8713
8747
|
var MMI_MARKETPLACE_NAME = "mutmutco";
|
|
@@ -8919,8 +8953,8 @@ function marketplaceRows(name, known, settings, remedy = "manual") {
|
|
|
8919
8953
|
}
|
|
8920
8954
|
|
|
8921
8955
|
// src/hook-activity.ts
|
|
8922
|
-
var
|
|
8923
|
-
var
|
|
8956
|
+
var import_node_fs14 = require("node:fs");
|
|
8957
|
+
var import_node_path12 = require("node:path");
|
|
8924
8958
|
var DEFAULT_SURFACE = "claude";
|
|
8925
8959
|
function activityLogPath(cwd) {
|
|
8926
8960
|
return repoRuntimeStatePath(cwd, "hooks", "activity.jsonl");
|
|
@@ -8933,20 +8967,20 @@ function appendHookActivity(cwd, entry) {
|
|
|
8933
8967
|
surface: DEFAULT_SURFACE,
|
|
8934
8968
|
...entry
|
|
8935
8969
|
};
|
|
8936
|
-
(0,
|
|
8937
|
-
(0,
|
|
8970
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path12.dirname)(path2), { recursive: true });
|
|
8971
|
+
(0, import_node_fs14.appendFileSync)(path2, `${JSON.stringify(line)}
|
|
8938
8972
|
`, "utf8");
|
|
8939
8973
|
} catch {
|
|
8940
8974
|
}
|
|
8941
8975
|
}
|
|
8942
8976
|
|
|
8943
8977
|
// src/worktree.ts
|
|
8944
|
-
var
|
|
8945
|
-
var
|
|
8978
|
+
var import_node_fs15 = require("node:fs");
|
|
8979
|
+
var import_node_path14 = require("node:path");
|
|
8946
8980
|
|
|
8947
8981
|
// src/file-lock.ts
|
|
8948
8982
|
var import_promises2 = require("node:fs/promises");
|
|
8949
|
-
var
|
|
8983
|
+
var import_node_path13 = require("node:path");
|
|
8950
8984
|
var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
8951
8985
|
var IMMEDIATE_RETRY_BUDGET = 3;
|
|
8952
8986
|
var FileLockBusyError = class extends Error {
|
|
@@ -9031,7 +9065,7 @@ async function releaseFileLock(lockPath, guard) {
|
|
|
9031
9065
|
}
|
|
9032
9066
|
async function withFileLock(lockPath, opts, fn) {
|
|
9033
9067
|
const resolved = resolveFileLockOpts(opts);
|
|
9034
|
-
await (0, import_promises2.mkdir)((0,
|
|
9068
|
+
await (0, import_promises2.mkdir)((0, import_node_path13.dirname)(lockPath), { recursive: true }).catch(() => void 0);
|
|
9035
9069
|
const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
|
|
9036
9070
|
try {
|
|
9037
9071
|
return await fn();
|
|
@@ -9058,35 +9092,35 @@ var PROVISION_ENV_MARKER = "MMI_PROVISION_RUNNING";
|
|
|
9058
9092
|
var realFsProbe = {
|
|
9059
9093
|
isDir: (p) => {
|
|
9060
9094
|
try {
|
|
9061
|
-
return (0,
|
|
9095
|
+
return (0, import_node_fs15.statSync)(p).isDirectory();
|
|
9062
9096
|
} catch {
|
|
9063
9097
|
return false;
|
|
9064
9098
|
}
|
|
9065
9099
|
},
|
|
9066
9100
|
isFile: (p) => {
|
|
9067
9101
|
try {
|
|
9068
|
-
return (0,
|
|
9102
|
+
return (0, import_node_fs15.statSync)(p).isFile();
|
|
9069
9103
|
} catch {
|
|
9070
9104
|
return false;
|
|
9071
9105
|
}
|
|
9072
9106
|
},
|
|
9073
9107
|
listDirs: (p) => {
|
|
9074
9108
|
try {
|
|
9075
|
-
return (0,
|
|
9109
|
+
return (0, import_node_fs15.readdirSync)(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
9076
9110
|
} catch {
|
|
9077
9111
|
return [];
|
|
9078
9112
|
}
|
|
9079
9113
|
},
|
|
9080
9114
|
readFile: (p) => {
|
|
9081
9115
|
try {
|
|
9082
|
-
return (0,
|
|
9116
|
+
return (0, import_node_fs15.readFileSync)(p, "utf8");
|
|
9083
9117
|
} catch {
|
|
9084
9118
|
return void 0;
|
|
9085
9119
|
}
|
|
9086
9120
|
}
|
|
9087
9121
|
};
|
|
9088
9122
|
function declaredProvision(fs2, abs) {
|
|
9089
|
-
const raw = fs2.readFile?.((0,
|
|
9123
|
+
const raw = fs2.readFile?.((0, import_node_path14.join)(abs, PKG));
|
|
9090
9124
|
if (raw === void 0) return void 0;
|
|
9091
9125
|
try {
|
|
9092
9126
|
const scripts = JSON.parse(raw).scripts;
|
|
@@ -9098,13 +9132,13 @@ function declaredProvision(fs2, abs) {
|
|
|
9098
9132
|
}
|
|
9099
9133
|
function scanInstallDirs(root, fs2 = realFsProbe) {
|
|
9100
9134
|
const factsFor = (dir) => {
|
|
9101
|
-
const abs = dir ? (0,
|
|
9102
|
-
const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0,
|
|
9103
|
-
const hasPackageJson = fs2.isFile((0,
|
|
9135
|
+
const abs = dir ? (0, import_node_path14.join)(root, dir) : root;
|
|
9136
|
+
const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0, import_node_path14.join)(abs, c.lockfile)));
|
|
9137
|
+
const hasPackageJson = fs2.isFile((0, import_node_path14.join)(abs, PKG));
|
|
9104
9138
|
return {
|
|
9105
9139
|
dir,
|
|
9106
9140
|
hasPackageJson,
|
|
9107
|
-
hasNodeModules: fs2.isDir((0,
|
|
9141
|
+
hasNodeModules: fs2.isDir((0, import_node_path14.join)(abs, NODE_MODULES)),
|
|
9108
9142
|
install: match?.command,
|
|
9109
9143
|
provision: hasPackageJson ? declaredProvision(fs2, abs) : void 0
|
|
9110
9144
|
};
|
|
@@ -9120,7 +9154,7 @@ function npmInstallTargets(dirs) {
|
|
|
9120
9154
|
}));
|
|
9121
9155
|
}
|
|
9122
9156
|
function isLinkedWorktree(root, fs2 = realFsProbe) {
|
|
9123
|
-
return fs2.isFile((0,
|
|
9157
|
+
return fs2.isFile((0, import_node_path14.join)(root, ".git"));
|
|
9124
9158
|
}
|
|
9125
9159
|
function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
9126
9160
|
if (!isLinkedWorktree(root, fs2)) return null;
|
|
@@ -9130,8 +9164,8 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
|
9130
9164
|
return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
|
|
9131
9165
|
}
|
|
9132
9166
|
function defaultCopyFile(from, to) {
|
|
9133
|
-
(0,
|
|
9134
|
-
(0,
|
|
9167
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path14.dirname)(to), { recursive: true });
|
|
9168
|
+
(0, import_node_fs15.copyFileSync)(from, to);
|
|
9135
9169
|
}
|
|
9136
9170
|
async function runDeclaredProvision(target, cwd, runInstall) {
|
|
9137
9171
|
const previous = process.env[PROVISION_ENV_MARKER];
|
|
@@ -9161,7 +9195,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9161
9195
|
const targets = npmInstallTargets(allDirs);
|
|
9162
9196
|
if (deps.validateInstall) {
|
|
9163
9197
|
for (const dir of allDirs.filter((d) => d.hasPackageJson && (d.provision ?? d.install) && d.hasNodeModules)) {
|
|
9164
|
-
const cwd = dir.dir ? (0,
|
|
9198
|
+
const cwd = dir.dir ? (0, import_node_path14.join)(worktreeRoot, dir.dir) : worktreeRoot;
|
|
9165
9199
|
if (!await deps.validateInstall(cwd)) {
|
|
9166
9200
|
targets.push({
|
|
9167
9201
|
dir: dir.dir,
|
|
@@ -9175,7 +9209,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9175
9209
|
const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules && !targetDirs.has(d.dir)).map((d) => d.dir);
|
|
9176
9210
|
const installed = [];
|
|
9177
9211
|
for (const target of targets) {
|
|
9178
|
-
const cwd = target.dir ? (0,
|
|
9212
|
+
const cwd = target.dir ? (0, import_node_path14.join)(worktreeRoot, target.dir) : worktreeRoot;
|
|
9179
9213
|
log(`installing deps: ${target.command} in ${target.dir || "."}`);
|
|
9180
9214
|
if (target.declared) await runDeclaredProvision(target, cwd, deps.runInstall);
|
|
9181
9215
|
else await deps.runInstall(target.command, cwd);
|
|
@@ -9185,7 +9219,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9185
9219
|
const copySkipped = [];
|
|
9186
9220
|
const primary = await deps.primaryCheckout();
|
|
9187
9221
|
for (const rel of LOCAL_ONLY_FILES) {
|
|
9188
|
-
const dest = (0,
|
|
9222
|
+
const dest = (0, import_node_path14.join)(worktreeRoot, rel);
|
|
9189
9223
|
if (fs2.isFile(dest)) {
|
|
9190
9224
|
copySkipped.push({ file: rel, reason: "already-present" });
|
|
9191
9225
|
continue;
|
|
@@ -9194,11 +9228,11 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9194
9228
|
copySkipped.push({ file: rel, reason: "no-primary" });
|
|
9195
9229
|
continue;
|
|
9196
9230
|
}
|
|
9197
|
-
if (!fs2.isFile((0,
|
|
9231
|
+
if (!fs2.isFile((0, import_node_path14.join)(primary, rel))) {
|
|
9198
9232
|
copySkipped.push({ file: rel, reason: "absent-in-primary" });
|
|
9199
9233
|
continue;
|
|
9200
9234
|
}
|
|
9201
|
-
copyFile((0,
|
|
9235
|
+
copyFile((0, import_node_path14.join)(primary, rel), dest);
|
|
9202
9236
|
copied.push(rel);
|
|
9203
9237
|
log(`copied local config: ${rel}`);
|
|
9204
9238
|
}
|
|
@@ -9212,12 +9246,12 @@ function capWorktreeDirName(name, max = 40) {
|
|
|
9212
9246
|
}
|
|
9213
9247
|
function defaultWorktreePath(repoRoot2, branch) {
|
|
9214
9248
|
const safe = capWorktreeDirName(branch.replace(/[/\\]+/g, "-"));
|
|
9215
|
-
return (0,
|
|
9249
|
+
return (0, import_node_path14.join)((0, import_node_path14.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path14.basename)(repoRoot2), safe);
|
|
9216
9250
|
}
|
|
9217
9251
|
async function primaryCheckoutRootOf(git2) {
|
|
9218
9252
|
try {
|
|
9219
9253
|
const out = (await git2(["rev-parse", "--path-format=absolute", "--git-common-dir"])).trim();
|
|
9220
|
-
return out ? (0,
|
|
9254
|
+
return out ? (0, import_node_path14.dirname)(out) : void 0;
|
|
9221
9255
|
} catch {
|
|
9222
9256
|
return void 0;
|
|
9223
9257
|
}
|
|
@@ -9355,7 +9389,7 @@ function commandLadderHint() {
|
|
|
9355
9389
|
}
|
|
9356
9390
|
|
|
9357
9391
|
// src/index.ts
|
|
9358
|
-
var
|
|
9392
|
+
var import_node_path44 = require("node:path");
|
|
9359
9393
|
|
|
9360
9394
|
// src/merge-ci-policy.ts
|
|
9361
9395
|
function resolveMergeCiPolicy(input) {
|
|
@@ -10015,13 +10049,13 @@ function planManagedGitignore(current) {
|
|
|
10015
10049
|
}
|
|
10016
10050
|
|
|
10017
10051
|
// src/docs-index-command.ts
|
|
10018
|
-
var
|
|
10019
|
-
var
|
|
10052
|
+
var import_node_fs17 = require("node:fs");
|
|
10053
|
+
var import_node_path16 = require("node:path");
|
|
10020
10054
|
|
|
10021
10055
|
// src/doc-refs-core.ts
|
|
10022
10056
|
var import_node_child_process5 = require("node:child_process");
|
|
10023
|
-
var
|
|
10024
|
-
var
|
|
10057
|
+
var import_node_fs16 = require("node:fs");
|
|
10058
|
+
var import_node_path15 = require("node:path");
|
|
10025
10059
|
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
10026
10060
|
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
10027
10061
|
var FWD_RE = /<!--\s*forward-ref:\s*(\S+?)\s*-->/;
|
|
@@ -10080,7 +10114,7 @@ function checkPins(root, readFile9, docs2) {
|
|
|
10080
10114
|
findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
|
|
10081
10115
|
continue;
|
|
10082
10116
|
}
|
|
10083
|
-
const source = readFile9((0,
|
|
10117
|
+
const source = readFile9((0, import_node_path15.join)(root, pin.file));
|
|
10084
10118
|
if (source == null) {
|
|
10085
10119
|
findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
|
|
10086
10120
|
continue;
|
|
@@ -10142,11 +10176,11 @@ function checkRefs(root, deps, docs2) {
|
|
|
10142
10176
|
for (const { ref } of extractRefs(markdown)) allFirstSegments.add(refFirstSegment(ref));
|
|
10143
10177
|
}
|
|
10144
10178
|
const tracked = allFirstSegments.size ? deps.trackedFirstSegments?.([...allFirstSegments]) ?? null : null;
|
|
10145
|
-
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0,
|
|
10179
|
+
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path15.join)(root, first));
|
|
10146
10180
|
const candidates = [];
|
|
10147
10181
|
const direct = [];
|
|
10148
10182
|
for (const [doc, markdown] of Object.entries(docs2)) {
|
|
10149
|
-
const docDir =
|
|
10183
|
+
const docDir = import_node_path15.posix.dirname(doc);
|
|
10150
10184
|
const base = docDir === "." ? "" : docDir;
|
|
10151
10185
|
const covered = /* @__PURE__ */ new Set();
|
|
10152
10186
|
const markers = [];
|
|
@@ -10155,21 +10189,21 @@ function checkRefs(root, deps, docs2) {
|
|
|
10155
10189
|
direct.push({ kind: "malformed-forward-ref", doc, line: fwd.line, detail: fwd.text });
|
|
10156
10190
|
continue;
|
|
10157
10191
|
}
|
|
10158
|
-
const docRel =
|
|
10159
|
-
const rootRel =
|
|
10192
|
+
const docRel = import_node_path15.posix.normalize(import_node_path15.posix.join(base, fwd.target));
|
|
10193
|
+
const rootRel = import_node_path15.posix.normalize(fwd.target.replace(/^\/+/, ""));
|
|
10160
10194
|
markers.push({ target: fwd.target, line: fwd.line, docRel, rootRel });
|
|
10161
10195
|
covered.add(docRel);
|
|
10162
10196
|
covered.add(rootRel);
|
|
10163
10197
|
}
|
|
10164
10198
|
const links = extractLinks(markdown).map(({ target, line }) => {
|
|
10165
|
-
const resolved =
|
|
10166
|
-
return { target, line, resolved, missing: !exists((0,
|
|
10199
|
+
const resolved = import_node_path15.posix.normalize(import_node_path15.posix.join(base, target));
|
|
10200
|
+
return { target, line, resolved, missing: !exists((0, import_node_path15.join)(root, resolved)) };
|
|
10167
10201
|
});
|
|
10168
10202
|
for (const marker of markers) {
|
|
10169
10203
|
const coversMissing = links.some(
|
|
10170
10204
|
(l) => l.missing && (l.resolved === marker.docRel || l.resolved === marker.rootRel)
|
|
10171
10205
|
);
|
|
10172
|
-
if (!coversMissing && (exists((0,
|
|
10206
|
+
if (!coversMissing && (exists((0, import_node_path15.join)(root, marker.docRel)) || exists((0, import_node_path15.join)(root, marker.rootRel)))) {
|
|
10173
10207
|
direct.push({
|
|
10174
10208
|
kind: "stale-forward-ref",
|
|
10175
10209
|
doc,
|
|
@@ -10180,7 +10214,7 @@ function checkRefs(root, deps, docs2) {
|
|
|
10180
10214
|
}
|
|
10181
10215
|
for (const { ref, line } of extractRefs(markdown)) {
|
|
10182
10216
|
if (!firstVerifiable(refFirstSegment(ref))) continue;
|
|
10183
|
-
if (!exists((0,
|
|
10217
|
+
if (!exists((0, import_node_path15.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
|
|
10184
10218
|
}
|
|
10185
10219
|
for (const { target, line, resolved, missing } of links) {
|
|
10186
10220
|
if (resolved.startsWith("..")) {
|
|
@@ -10228,22 +10262,22 @@ function checkCommands(docs2, commandPaths) {
|
|
|
10228
10262
|
return { ok: findings.length === 0, findings, warnings: [] };
|
|
10229
10263
|
}
|
|
10230
10264
|
function readFileOrNull(path2) {
|
|
10231
|
-
return (0,
|
|
10265
|
+
return (0, import_node_fs16.existsSync)(path2) ? (0, import_node_fs16.readFileSync)(path2, "utf8") : null;
|
|
10232
10266
|
}
|
|
10233
10267
|
function walk(dir, root, out) {
|
|
10234
|
-
for (const entry of (0,
|
|
10235
|
-
const full = (0,
|
|
10236
|
-
if ((0,
|
|
10268
|
+
for (const entry of (0, import_node_fs16.readdirSync)(dir)) {
|
|
10269
|
+
const full = (0, import_node_path15.join)(dir, entry);
|
|
10270
|
+
if ((0, import_node_fs16.statSync)(full).isDirectory()) walk(full, root, out);
|
|
10237
10271
|
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
10238
10272
|
}
|
|
10239
10273
|
return out;
|
|
10240
10274
|
}
|
|
10241
10275
|
function defaultListDocs(root) {
|
|
10242
|
-
const docsDir = (0,
|
|
10243
|
-
const docs2 = ((0,
|
|
10276
|
+
const docsDir = (0, import_node_path15.join)(root, "docs");
|
|
10277
|
+
const docs2 = ((0, import_node_fs16.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
|
|
10244
10278
|
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
10245
10279
|
);
|
|
10246
|
-
return [...ROOT_DOCS.filter((rel) => (0,
|
|
10280
|
+
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs16.existsSync)((0, import_node_path15.join)(root, rel))), ...docs2];
|
|
10247
10281
|
}
|
|
10248
10282
|
var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
|
|
10249
10283
|
function defaultIsIgnored(root, relPaths, exec = import_node_child_process5.execFileSync) {
|
|
@@ -10295,7 +10329,7 @@ function defaultTrackedFirstSegments(root, firstSegments, exec = import_node_chi
|
|
|
10295
10329
|
}
|
|
10296
10330
|
function runDocRefs(root, deps = {}) {
|
|
10297
10331
|
const readFile9 = deps.readFile ?? readFileOrNull;
|
|
10298
|
-
const exists = deps.exists ??
|
|
10332
|
+
const exists = deps.exists ?? import_node_fs16.existsSync;
|
|
10299
10333
|
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
10300
10334
|
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
10301
10335
|
const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
|
|
@@ -10303,7 +10337,7 @@ function runDocRefs(root, deps = {}) {
|
|
|
10303
10337
|
const walked = listDocs(root);
|
|
10304
10338
|
const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
|
|
10305
10339
|
const docs2 = Object.fromEntries(
|
|
10306
|
-
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0,
|
|
10340
|
+
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0, import_node_path15.join)(root, rel))]).filter(([, body]) => body != null)
|
|
10307
10341
|
);
|
|
10308
10342
|
const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs2);
|
|
10309
10343
|
const findings = [
|
|
@@ -10410,31 +10444,31 @@ function walkMarkdown(dir) {
|
|
|
10410
10444
|
const stack = [dir];
|
|
10411
10445
|
while (stack.length) {
|
|
10412
10446
|
const current = stack.pop();
|
|
10413
|
-
for (const entry of (0,
|
|
10414
|
-
const full = (0,
|
|
10447
|
+
for (const entry of (0, import_node_fs17.readdirSync)(current, { withFileTypes: true })) {
|
|
10448
|
+
const full = (0, import_node_path16.join)(current, entry.name);
|
|
10415
10449
|
if (entry.isDirectory()) {
|
|
10416
10450
|
stack.push(full);
|
|
10417
10451
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
10418
|
-
out.push((0,
|
|
10452
|
+
out.push((0, import_node_path16.relative)(dir, full).split(import_node_path16.sep).join("/"));
|
|
10419
10453
|
}
|
|
10420
10454
|
}
|
|
10421
10455
|
}
|
|
10422
10456
|
return out;
|
|
10423
10457
|
}
|
|
10424
10458
|
function createDocsIndexDeps(repoRoot2) {
|
|
10425
|
-
const docsDir = (0,
|
|
10426
|
-
const indexPath = (0,
|
|
10459
|
+
const docsDir = (0, import_node_path16.join)(repoRoot2, "docs");
|
|
10460
|
+
const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
|
|
10427
10461
|
return {
|
|
10428
10462
|
listDocs: () => {
|
|
10429
|
-
if (!(0,
|
|
10463
|
+
if (!(0, import_node_fs17.existsSync)(docsDir)) return [];
|
|
10430
10464
|
const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
|
|
10431
10465
|
if (!walked.length) return [];
|
|
10432
10466
|
const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
|
|
10433
10467
|
return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
|
|
10434
10468
|
},
|
|
10435
|
-
readDoc: (relPath) => (0,
|
|
10436
|
-
readIndex: () => (0,
|
|
10437
|
-
writeIndex: (content) => (0,
|
|
10469
|
+
readDoc: (relPath) => (0, import_node_fs17.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
|
|
10470
|
+
readIndex: () => (0, import_node_fs17.existsSync)(indexPath) ? (0, import_node_fs17.readFileSync)(indexPath, "utf8") : null,
|
|
10471
|
+
writeIndex: (content) => (0, import_node_fs17.writeFileSync)(indexPath, content, "utf8")
|
|
10438
10472
|
};
|
|
10439
10473
|
}
|
|
10440
10474
|
|
|
@@ -11219,14 +11253,14 @@ function parseVerifyBroker(stdout) {
|
|
|
11219
11253
|
}
|
|
11220
11254
|
|
|
11221
11255
|
// src/train-apply.ts
|
|
11222
|
-
var
|
|
11256
|
+
var import_node_fs21 = require("node:fs");
|
|
11223
11257
|
var import_promises4 = require("node:fs/promises");
|
|
11224
|
-
var
|
|
11258
|
+
var import_node_path20 = require("node:path");
|
|
11225
11259
|
|
|
11226
11260
|
// src/plugin-guard-io.ts
|
|
11227
|
-
var
|
|
11261
|
+
var import_node_fs18 = require("node:fs");
|
|
11228
11262
|
var import_node_child_process7 = require("node:child_process");
|
|
11229
|
-
var
|
|
11263
|
+
var import_node_path17 = require("node:path");
|
|
11230
11264
|
var import_node_os5 = require("node:os");
|
|
11231
11265
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
11232
11266
|
|
|
@@ -11529,21 +11563,21 @@ function runHostBin(bin, args, opts) {
|
|
|
11529
11563
|
return step ? execFileHard(file, argv, { ...shared, step }) : execFileP2(file, argv, shared);
|
|
11530
11564
|
}
|
|
11531
11565
|
function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
11532
|
-
if (surface === "codex") return env.CODEX_HOME?.trim() || (0,
|
|
11533
|
-
if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0,
|
|
11534
|
-
if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0,
|
|
11535
|
-
if (surface === "cursor") return (0,
|
|
11566
|
+
if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path17.join)(home, ".codex");
|
|
11567
|
+
if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0, import_node_path17.join)(home, ".kimi-code");
|
|
11568
|
+
if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0, import_node_path17.join)(home, ".config", "kilo");
|
|
11569
|
+
if (surface === "cursor") return (0, import_node_path17.join)(home, ".cursor");
|
|
11536
11570
|
if (surface === "jervcode") {
|
|
11537
|
-
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0,
|
|
11571
|
+
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path17.join)(home, ".jerv", "agent");
|
|
11538
11572
|
}
|
|
11539
|
-
return (0,
|
|
11573
|
+
return (0, import_node_path17.join)(home, ".claude");
|
|
11540
11574
|
}
|
|
11541
11575
|
var installedPluginsPath = (surface = detectSurface(process.env)) => {
|
|
11542
|
-
return (0,
|
|
11576
|
+
return (0, import_node_path17.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
|
|
11543
11577
|
};
|
|
11544
11578
|
function readInstalledPlugins(surface = detectSurface(process.env)) {
|
|
11545
11579
|
try {
|
|
11546
|
-
return JSON.parse((0,
|
|
11580
|
+
return JSON.parse((0, import_node_fs18.readFileSync)(installedPluginsPath(surface), "utf8"));
|
|
11547
11581
|
} catch {
|
|
11548
11582
|
return null;
|
|
11549
11583
|
}
|
|
@@ -11552,17 +11586,17 @@ function marketplaceCloneCandidates(surface, home, env = process.env) {
|
|
|
11552
11586
|
if (surface === "codex") {
|
|
11553
11587
|
const root = surfaceConfigRoot(surface, env, home);
|
|
11554
11588
|
return [
|
|
11555
|
-
(0,
|
|
11556
|
-
(0,
|
|
11589
|
+
(0, import_node_path17.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
|
|
11590
|
+
(0, import_node_path17.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
|
|
11557
11591
|
];
|
|
11558
11592
|
}
|
|
11559
11593
|
if (surface === "kimi") return [];
|
|
11560
11594
|
if (surface === "kilo") return [];
|
|
11561
11595
|
if (surface === "cursor") return [];
|
|
11562
11596
|
if (surface === "jervcode") return [];
|
|
11563
|
-
return [(0,
|
|
11597
|
+
return [(0, import_node_path17.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
|
|
11564
11598
|
}
|
|
11565
|
-
function marketplaceClonePresent(surface, home, exists =
|
|
11599
|
+
function marketplaceClonePresent(surface, home, exists = import_node_fs18.existsSync, env = process.env) {
|
|
11566
11600
|
return marketplaceCloneCandidates(surface, home, env).some(exists);
|
|
11567
11601
|
}
|
|
11568
11602
|
function runHostBinSync(bin, args) {
|
|
@@ -11594,7 +11628,7 @@ function codexPluginStatus() {
|
|
|
11594
11628
|
}
|
|
11595
11629
|
function countCodexHookCommands(path2) {
|
|
11596
11630
|
try {
|
|
11597
|
-
const parsed = JSON.parse((0,
|
|
11631
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
|
|
11598
11632
|
let count = 0;
|
|
11599
11633
|
for (const groups of Object.values(parsed.hooks ?? {})) {
|
|
11600
11634
|
for (const group of groups) {
|
|
@@ -11611,11 +11645,11 @@ function codexHookTrustState(status = codexPluginStatus()) {
|
|
|
11611
11645
|
return { applicable: false, trusted: false, trustedCount: 0, requiredCount: 0 };
|
|
11612
11646
|
}
|
|
11613
11647
|
const root = surfaceConfigRoot("codex");
|
|
11614
|
-
const hooksPath = (0,
|
|
11648
|
+
const hooksPath = (0, import_node_path17.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version, "hooks", "codex-hooks.json");
|
|
11615
11649
|
const requiredCount = countCodexHookCommands(hooksPath);
|
|
11616
11650
|
let config = "";
|
|
11617
11651
|
try {
|
|
11618
|
-
config = (0,
|
|
11652
|
+
config = (0, import_node_fs18.readFileSync)((0, import_node_path17.join)(root, "config.toml"), "utf8");
|
|
11619
11653
|
} catch {
|
|
11620
11654
|
return { applicable: true, trusted: false, trustedCount: 0, requiredCount };
|
|
11621
11655
|
}
|
|
@@ -11640,14 +11674,21 @@ async function fetchNpmReleasedVersion() {
|
|
|
11640
11674
|
}
|
|
11641
11675
|
var NPM_INSTALL_TIMEOUT_MS = 12e4;
|
|
11642
11676
|
var CLI_VERSION_PROBE_TIMEOUT_MS = 3e4;
|
|
11677
|
+
function resolveNpmSpawn(args) {
|
|
11678
|
+
if (!isWin) return { file: "npm", args };
|
|
11679
|
+
const cli = (0, import_node_path17.join)((0, import_node_path17.dirname)(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
11680
|
+
if ((0, import_node_fs18.existsSync)(cli)) return { file: process.execPath, args: [cli, ...args] };
|
|
11681
|
+
return { file: "cmd.exe", args: ["/c", "npm", ...args] };
|
|
11682
|
+
}
|
|
11643
11683
|
async function npmSelfUpdateCli(target, onStep, deps = {}) {
|
|
11644
11684
|
const command = cliUpdateCommand(target);
|
|
11645
11685
|
const args = npmSelfUpdateArgs(`@mutmutco/cli@${target ?? "latest"}`);
|
|
11646
11686
|
onStep?.(command);
|
|
11647
11687
|
let last = "";
|
|
11688
|
+
const spawnSpec = resolveNpmSpawn(args);
|
|
11648
11689
|
const result = await (deps.run ?? runNpmStreaming)({
|
|
11649
|
-
file:
|
|
11650
|
-
args:
|
|
11690
|
+
file: spawnSpec.file,
|
|
11691
|
+
args: spawnSpec.args,
|
|
11651
11692
|
timeoutMs: NPM_INSTALL_TIMEOUT_MS,
|
|
11652
11693
|
onLine: (line) => {
|
|
11653
11694
|
const message = narrateNpmLine(line);
|
|
@@ -11662,11 +11703,11 @@ async function npmSelfUpdateCli(target, onStep, deps = {}) {
|
|
|
11662
11703
|
onStep?.(verified.detail, { alwaysShow: true });
|
|
11663
11704
|
return verified.ok ? { ok: true, detail: `${command} exited 0 \u2014 ${verified.detail}` } : { ok: false, detail: `${command} exited 0 but ${verified.detail}` };
|
|
11664
11705
|
}
|
|
11665
|
-
function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)(), read = (p) => (0,
|
|
11706
|
+
function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)(), read = (p) => (0, import_node_fs18.readFileSync)(p, "utf8"), exists = import_node_fs18.existsSync) {
|
|
11666
11707
|
const candidates = ["kilo.json", "kilo.jsonc", "opencode.json", "opencode.jsonc", "config.json"];
|
|
11667
|
-
for (const dir of [configRoot, (0,
|
|
11708
|
+
for (const dir of [configRoot, (0, import_node_path17.join)(home, ".kilo")]) {
|
|
11668
11709
|
for (const file of candidates) {
|
|
11669
|
-
const path2 = (0,
|
|
11710
|
+
const path2 = (0, import_node_path17.join)(dir, file);
|
|
11670
11711
|
if (!exists(path2)) continue;
|
|
11671
11712
|
try {
|
|
11672
11713
|
const stripped = read(path2).replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
@@ -11683,23 +11724,23 @@ function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)()
|
|
|
11683
11724
|
return false;
|
|
11684
11725
|
}
|
|
11685
11726
|
function cursorLocalPluginRoot(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
11686
|
-
return (0,
|
|
11727
|
+
return (0, import_node_path17.join)(surfaceConfigRoot("cursor", env, home), "plugins", "local", "mmi");
|
|
11687
11728
|
}
|
|
11688
|
-
function cursorPluginTreeHealthy(root, exists =
|
|
11729
|
+
function cursorPluginTreeHealthy(root, exists = import_node_fs18.existsSync) {
|
|
11689
11730
|
return [
|
|
11690
11731
|
".cursor-plugin/plugin.json",
|
|
11691
11732
|
"skills/mmi/SKILL.md",
|
|
11692
11733
|
"hooks/cursor-hooks.json",
|
|
11693
11734
|
"scripts/hook-run.mjs",
|
|
11694
11735
|
"scripts/hook-policy.mjs"
|
|
11695
|
-
].every((path2) => exists((0,
|
|
11736
|
+
].every((path2) => exists((0, import_node_path17.join)(root, ...path2.split("/"))));
|
|
11696
11737
|
}
|
|
11697
|
-
function kimiPluginTreeHealthy(root, exists =
|
|
11738
|
+
function kimiPluginTreeHealthy(root, exists = import_node_fs18.existsSync) {
|
|
11698
11739
|
return [
|
|
11699
11740
|
".kimi-plugin/plugin.json",
|
|
11700
11741
|
"skills/mmi/SKILL.md",
|
|
11701
11742
|
"scripts/hook-run.mjs"
|
|
11702
|
-
].every((path2) => exists((0,
|
|
11743
|
+
].every((path2) => exists((0, import_node_path17.join)(root, ...path2.split("/"))));
|
|
11703
11744
|
}
|
|
11704
11745
|
var JERVCODE_WRAPPER_DIR = ".pi-plugin";
|
|
11705
11746
|
function normalizePiEntry(value) {
|
|
@@ -11722,7 +11763,7 @@ function jervcodePackageFamily(entry) {
|
|
|
11722
11763
|
function isMmiOwnedPiEntry(entry) {
|
|
11723
11764
|
if (typeof entry !== "string") return false;
|
|
11724
11765
|
try {
|
|
11725
|
-
const pkg = JSON.parse((0,
|
|
11766
|
+
const pkg = JSON.parse((0, import_node_fs18.readFileSync)((0, import_node_path17.join)(piEntryFsPath(entry), "package.json"), "utf8"));
|
|
11726
11767
|
return pkg.name === "mmi";
|
|
11727
11768
|
} catch {
|
|
11728
11769
|
return false;
|
|
@@ -11744,9 +11785,9 @@ function mergeMmiPiPackageEntries(entries, packagePath) {
|
|
|
11744
11785
|
};
|
|
11745
11786
|
}
|
|
11746
11787
|
function readPiSettings(path2) {
|
|
11747
|
-
if (!(0,
|
|
11788
|
+
if (!(0, import_node_fs18.existsSync)(path2)) return void 0;
|
|
11748
11789
|
try {
|
|
11749
|
-
const parsed = JSON.parse((0,
|
|
11790
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
|
|
11750
11791
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
11751
11792
|
return parsed;
|
|
11752
11793
|
} catch {
|
|
@@ -11754,8 +11795,8 @@ function readPiSettings(path2) {
|
|
|
11754
11795
|
}
|
|
11755
11796
|
}
|
|
11756
11797
|
function jervcodeSettingsCandidates(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
11757
|
-
const primary = (0,
|
|
11758
|
-
const legacy = (0,
|
|
11798
|
+
const primary = (0, import_node_path17.join)(surfaceConfigRoot("jervcode", env, home), "settings.json");
|
|
11799
|
+
const legacy = (0, import_node_path17.join)(home, ".pi", "agent", "settings.json");
|
|
11759
11800
|
return legacy === primary ? [primary] : [primary, legacy];
|
|
11760
11801
|
}
|
|
11761
11802
|
function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
@@ -11774,17 +11815,17 @@ function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir
|
|
|
11774
11815
|
function mmiPiWrapperHealthy(entry) {
|
|
11775
11816
|
if (!entry) return false;
|
|
11776
11817
|
const wrapper = piEntryFsPath(entry);
|
|
11777
|
-
return isMmiOwnedPiEntry(entry) && (0,
|
|
11818
|
+
return isMmiOwnedPiEntry(entry) && (0, import_node_fs18.existsSync)((0, import_node_path17.join)((0, import_node_path17.dirname)(wrapper), "skills", "mmi", "SKILL.md"));
|
|
11778
11819
|
}
|
|
11779
11820
|
function findMmiPiSourceClone(home = (0, import_node_os5.homedir)()) {
|
|
11780
|
-
const cacheRoot = (0,
|
|
11821
|
+
const cacheRoot = (0, import_node_path17.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi");
|
|
11781
11822
|
let best = null;
|
|
11782
11823
|
try {
|
|
11783
|
-
for (const entry of (0,
|
|
11824
|
+
for (const entry of (0, import_node_fs18.readdirSync)(cacheRoot, { withFileTypes: true })) {
|
|
11784
11825
|
if (!entry.isDirectory() || !/^\d+\.\d+\.\d+$/.test(entry.name)) continue;
|
|
11785
|
-
if (!(0,
|
|
11826
|
+
if (!(0, import_node_fs18.existsSync)((0, import_node_path17.join)(cacheRoot, entry.name, JERVCODE_WRAPPER_DIR, "package.json"))) continue;
|
|
11786
11827
|
if (!best || compareVersions(entry.name, best.version) > 0) {
|
|
11787
|
-
best = { path: (0,
|
|
11828
|
+
best = { path: (0, import_node_path17.join)(cacheRoot, entry.name), version: entry.name };
|
|
11788
11829
|
}
|
|
11789
11830
|
}
|
|
11790
11831
|
} catch {
|
|
@@ -11809,8 +11850,8 @@ function acquirePiSettingsLock(settingsPath2) {
|
|
|
11809
11850
|
return void 0;
|
|
11810
11851
|
}
|
|
11811
11852
|
function healOneJervCodeSettingsFile(settingsPath2, packagePath, version, nextLaunch) {
|
|
11812
|
-
const release = (0,
|
|
11813
|
-
if ((0,
|
|
11853
|
+
const release = (0, import_node_fs18.existsSync)(settingsPath2) ? acquirePiSettingsLock(settingsPath2) : void 0;
|
|
11854
|
+
if ((0, import_node_fs18.existsSync)(settingsPath2) && !release) {
|
|
11814
11855
|
return {
|
|
11815
11856
|
available: true,
|
|
11816
11857
|
ok: false,
|
|
@@ -11838,14 +11879,14 @@ function healOneJervCodeSettingsFile(settingsPath2, packagePath, version, nextLa
|
|
|
11838
11879
|
}
|
|
11839
11880
|
current.packages = merged.next;
|
|
11840
11881
|
try {
|
|
11841
|
-
(0,
|
|
11882
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path17.dirname)(settingsPath2), { recursive: true });
|
|
11842
11883
|
const tmp = `${settingsPath2}.tmp-${process.pid}`;
|
|
11843
|
-
(0,
|
|
11884
|
+
(0, import_node_fs18.writeFileSync)(tmp, `${JSON.stringify(current, null, 2)}
|
|
11844
11885
|
`, "utf8");
|
|
11845
11886
|
try {
|
|
11846
|
-
(0,
|
|
11887
|
+
(0, import_node_fs18.renameSync)(tmp, settingsPath2);
|
|
11847
11888
|
} catch (renameError) {
|
|
11848
|
-
(0,
|
|
11889
|
+
(0, import_node_fs18.rmSync)(tmp, { force: true });
|
|
11849
11890
|
throw renameError;
|
|
11850
11891
|
}
|
|
11851
11892
|
} catch (error) {
|
|
@@ -11869,8 +11910,8 @@ function healJervCodePackageRegistration(opts = {}) {
|
|
|
11869
11910
|
const nextLaunch = inSeat ? " \u2014 takes effect on the next seat launch" : "";
|
|
11870
11911
|
const home = opts.home ?? (0, import_node_os5.homedir)();
|
|
11871
11912
|
const agentDir = surfaceConfigRoot("jervcode", env, home);
|
|
11872
|
-
const legacyPi = (0,
|
|
11873
|
-
if (!(0,
|
|
11913
|
+
const legacyPi = (0, import_node_path17.join)(home, ".pi", "agent");
|
|
11914
|
+
if (!(0, import_node_fs18.existsSync)(agentDir) && !(0, import_node_fs18.existsSync)(legacyPi)) {
|
|
11874
11915
|
return { available: false, ok: true, changed: false, version: null, detail: "skipped \u2014 no Pi/JervCode install (no agent config dir)" };
|
|
11875
11916
|
}
|
|
11876
11917
|
const clone = opts.clone === void 0 ? findMmiPiSourceClone(home) : opts.clone;
|
|
@@ -11878,9 +11919,9 @@ function healJervCodePackageRegistration(opts = {}) {
|
|
|
11878
11919
|
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)" };
|
|
11879
11920
|
}
|
|
11880
11921
|
const packagePath = `${clone.path.replace(/\\/g, "/").replace(/\/+$/, "")}/${JERVCODE_WRAPPER_DIR}`;
|
|
11881
|
-
const targets = [(0,
|
|
11882
|
-
const legacySettings = (0,
|
|
11883
|
-
if ((0,
|
|
11922
|
+
const targets = [(0, import_node_path17.join)(agentDir, "settings.json")];
|
|
11923
|
+
const legacySettings = (0, import_node_path17.join)(legacyPi, "settings.json");
|
|
11924
|
+
if ((0, import_node_fs18.existsSync)(legacyPi) && legacySettings !== targets[0]) targets.push(legacySettings);
|
|
11884
11925
|
const details = [];
|
|
11885
11926
|
let anyChanged = false;
|
|
11886
11927
|
for (const settingsPath2 of targets) {
|
|
@@ -11908,18 +11949,18 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
|
|
|
11908
11949
|
return {
|
|
11909
11950
|
isOrgRepo,
|
|
11910
11951
|
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.
|
|
11911
|
-
surface === "kimi" && (0,
|
|
11952
|
+
surface === "kimi" && (0, import_node_fs18.existsSync)((0, import_node_path17.join)(root, "plugins", "managed", "mmi")) || // kilo-p1: the install record is the config file itself.
|
|
11912
11953
|
surface === "kilo" && kiloConfigListsPlugin(root) || // #4188: jervcode's install record is the settings-file packages[] entry itself.
|
|
11913
|
-
surface === "jervcode" && piEntry !== null || surface === "cursor" && (0,
|
|
11954
|
+
surface === "jervcode" && piEntry !== null || surface === "cursor" && (0, import_node_fs18.existsSync)(cursorLocalPluginRoot()),
|
|
11914
11955
|
// Kilo has no marketplace to clone — the config file IS the install record, so this dimension of
|
|
11915
11956
|
// the shared guard table is vacuously satisfied. Same for jervcode's settings entry.
|
|
11916
11957
|
marketplaceClonePresent: surface === "kimi" || surface === "kilo" || surface === "cursor" || surface === "jervcode" ? true : marketplaceClonePresent(surface, (0, import_node_os5.homedir)()),
|
|
11917
11958
|
// Kimi keeps no plugin cache dir — installs are copied to plugins/managed/<id> and run from there.
|
|
11918
11959
|
// Kilo (kilo-p1) keeps no cache dir either: the plugin's server() provisions ~/.kilo behind the
|
|
11919
11960
|
// version stamp, so the stamp's presence is the cache signal.
|
|
11920
|
-
pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0,
|
|
11921
|
-
codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0,
|
|
11922
|
-
) : (0,
|
|
11961
|
+
pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0, import_node_fs18.existsSync)((0, import_node_path17.join)((0, import_node_os5.homedir)(), ".kilo", ".mmi-kilo-version")) : surface === "kimi" ? kimiPluginTreeHealthy((0, import_node_path17.join)(root, "plugins", "managed", "mmi")) : surface === "cursor" ? cursorPluginTreeHealthy(cursorLocalPluginRoot()) : surface === "codex" ? Boolean(
|
|
11962
|
+
codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0, import_node_fs18.existsSync)((0, import_node_path17.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", codexStatus.version))
|
|
11963
|
+
) : (0, import_node_fs18.existsSync)((0, import_node_path17.join)(root, "plugins", "cache", "mutmutco", "mmi"))
|
|
11923
11964
|
};
|
|
11924
11965
|
}
|
|
11925
11966
|
async function runHostBinLogged(bin, args, opts) {
|
|
@@ -11939,11 +11980,11 @@ async function runPluginCli(bin, args, log) {
|
|
|
11939
11980
|
function captureCodexHookLauncher() {
|
|
11940
11981
|
const status = codexPluginStatus();
|
|
11941
11982
|
if (!status.installed || !status.enabled || !status.version) return void 0;
|
|
11942
|
-
const root = (0,
|
|
11983
|
+
const root = (0, import_node_path17.join)(surfaceConfigRoot("codex"), "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version);
|
|
11943
11984
|
const files = ["mmi-hook", "mmi-hook.exe"].flatMap((name) => {
|
|
11944
|
-
const path2 = (0,
|
|
11985
|
+
const path2 = (0, import_node_path17.join)(root, "bin", name);
|
|
11945
11986
|
try {
|
|
11946
|
-
return [{ name, content: (0,
|
|
11987
|
+
return [{ name, content: (0, import_node_fs18.readFileSync)(path2) }];
|
|
11947
11988
|
} catch {
|
|
11948
11989
|
return [];
|
|
11949
11990
|
}
|
|
@@ -11951,13 +11992,13 @@ function captureCodexHookLauncher() {
|
|
|
11951
11992
|
return files.length === 2 ? { root, files } : void 0;
|
|
11952
11993
|
}
|
|
11953
11994
|
function restoreCodexHookLauncher(snapshot) {
|
|
11954
|
-
if (!snapshot || (0,
|
|
11955
|
-
const bin = (0,
|
|
11956
|
-
(0,
|
|
11995
|
+
if (!snapshot || (0, import_node_fs18.existsSync)((0, import_node_path17.join)(snapshot.root, "scripts", "hook-run.mjs"))) return false;
|
|
11996
|
+
const bin = (0, import_node_path17.join)(snapshot.root, "bin");
|
|
11997
|
+
(0, import_node_fs18.mkdirSync)(bin, { recursive: true });
|
|
11957
11998
|
for (const file of snapshot.files) {
|
|
11958
|
-
const path2 = (0,
|
|
11959
|
-
(0,
|
|
11960
|
-
if (file.name === "mmi-hook") (0,
|
|
11999
|
+
const path2 = (0, import_node_path17.join)(bin, file.name);
|
|
12000
|
+
(0, import_node_fs18.writeFileSync)(path2, file.content);
|
|
12001
|
+
if (file.name === "mmi-hook") (0, import_node_fs18.chmodSync)(path2, 493);
|
|
11961
12002
|
}
|
|
11962
12003
|
return true;
|
|
11963
12004
|
}
|
|
@@ -11966,10 +12007,10 @@ function canonicalCursorRemote(remote) {
|
|
|
11966
12007
|
}
|
|
11967
12008
|
async function installCursorPluginCheckout(env = process.env) {
|
|
11968
12009
|
const configRoot = surfaceConfigRoot("cursor", env);
|
|
11969
|
-
const pluginsRoot = (0,
|
|
11970
|
-
const target = (0,
|
|
12010
|
+
const pluginsRoot = (0, import_node_path17.join)(configRoot, "plugins");
|
|
12011
|
+
const target = (0, import_node_path17.join)(pluginsRoot, "local", "mmi");
|
|
11971
12012
|
const source = env.MMI_CURSOR_PLUGIN_SOURCE?.trim();
|
|
11972
|
-
if ((0,
|
|
12013
|
+
if ((0, import_node_fs18.existsSync)(target) && !source) {
|
|
11973
12014
|
try {
|
|
11974
12015
|
const { stdout } = await runHostBin("git", ["-C", target, "remote", "get-url", "origin"], { timeout: 15e3 });
|
|
11975
12016
|
if (!canonicalCursorRemote(stdout)) {
|
|
@@ -11979,15 +12020,15 @@ async function installCursorPluginCheckout(env = process.env) {
|
|
|
11979
12020
|
return { ok: false, detail: `refused to replace unmanaged Cursor plugin directory at ${target}` };
|
|
11980
12021
|
}
|
|
11981
12022
|
}
|
|
11982
|
-
(0,
|
|
11983
|
-
(0,
|
|
11984
|
-
(0,
|
|
12023
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path17.join)(pluginsRoot, "local"), { recursive: true });
|
|
12024
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path17.join)(pluginsRoot, "staging"), { recursive: true });
|
|
12025
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path17.join)(pluginsRoot, "quarantine"), { recursive: true });
|
|
11985
12026
|
const suffix = `${Date.now()}-${process.pid}`;
|
|
11986
|
-
const staged = (0,
|
|
11987
|
-
const quarantined = (0,
|
|
12027
|
+
const staged = (0, import_node_path17.join)(pluginsRoot, "staging", `mmi-${suffix}`);
|
|
12028
|
+
const quarantined = (0, import_node_path17.join)(pluginsRoot, "quarantine", `mmi-${suffix}`);
|
|
11988
12029
|
try {
|
|
11989
12030
|
if (source) {
|
|
11990
|
-
(0,
|
|
12031
|
+
(0, import_node_fs18.cpSync)(source, staged, {
|
|
11991
12032
|
recursive: true,
|
|
11992
12033
|
filter: (path2) => !path2.split(/[\\/]/).some((part) => part === ".git" || part === "node_modules")
|
|
11993
12034
|
});
|
|
@@ -11998,18 +12039,18 @@ async function installCursorPluginCheckout(env = process.env) {
|
|
|
11998
12039
|
});
|
|
11999
12040
|
}
|
|
12000
12041
|
if (!cursorPluginTreeHealthy(staged)) {
|
|
12001
|
-
(0,
|
|
12042
|
+
(0, import_node_fs18.rmSync)(staged, { recursive: true, force: true });
|
|
12002
12043
|
return { ok: false, detail: "downloaded Cursor plugin is incomplete; existing install was preserved" };
|
|
12003
12044
|
}
|
|
12004
12045
|
let movedOld = false;
|
|
12005
|
-
if ((0,
|
|
12006
|
-
(0,
|
|
12046
|
+
if ((0, import_node_fs18.existsSync)(target)) {
|
|
12047
|
+
(0, import_node_fs18.renameSync)(target, quarantined);
|
|
12007
12048
|
movedOld = true;
|
|
12008
12049
|
}
|
|
12009
12050
|
try {
|
|
12010
|
-
(0,
|
|
12051
|
+
(0, import_node_fs18.renameSync)(staged, target);
|
|
12011
12052
|
} catch (error) {
|
|
12012
|
-
if (movedOld && !(0,
|
|
12053
|
+
if (movedOld && !(0, import_node_fs18.existsSync)(target)) (0, import_node_fs18.renameSync)(quarantined, target);
|
|
12013
12054
|
throw error;
|
|
12014
12055
|
}
|
|
12015
12056
|
return {
|
|
@@ -12017,7 +12058,7 @@ async function installCursorPluginCheckout(env = process.env) {
|
|
|
12017
12058
|
detail: movedOld ? `installed canonical Cursor plugin; previous checkout quarantined at ${quarantined}` : `installed canonical Cursor plugin at ${target}`
|
|
12018
12059
|
};
|
|
12019
12060
|
} catch (error) {
|
|
12020
|
-
if ((0,
|
|
12061
|
+
if ((0, import_node_fs18.existsSync)(staged)) (0, import_node_fs18.rmSync)(staged, { recursive: true, force: true });
|
|
12021
12062
|
return { ok: false, detail: error.message.trim().slice(0, 240).replace(/\s+/g, " ") };
|
|
12022
12063
|
}
|
|
12023
12064
|
}
|
|
@@ -12067,7 +12108,7 @@ async function applyPluginHeal(surface, log, opts) {
|
|
|
12067
12108
|
const refSupported = await marketplaceAddRefSupported(bin);
|
|
12068
12109
|
const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
|
|
12069
12110
|
log(healBannerLine(bin, token, refSupported));
|
|
12070
|
-
const pinsPath = (0,
|
|
12111
|
+
const pinsPath = (0, import_node_path17.join)((0, import_node_os5.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
|
|
12071
12112
|
const pins = token === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
|
|
12072
12113
|
try {
|
|
12073
12114
|
for (const step of steps) {
|
|
@@ -12142,7 +12183,7 @@ async function healActivePluginForDoctor(surface = detectSurface(process.env), o
|
|
|
12142
12183
|
}
|
|
12143
12184
|
function readKnownMarketplacesFile(path2) {
|
|
12144
12185
|
try {
|
|
12145
|
-
return (0,
|
|
12186
|
+
return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : void 0;
|
|
12146
12187
|
} catch {
|
|
12147
12188
|
return void 0;
|
|
12148
12189
|
}
|
|
@@ -12172,7 +12213,7 @@ function writeMarketplacePinsOnDisk(path2, pins, succeeded, failedVerb, declineW
|
|
|
12172
12213
|
const declined = declineWhileHostLive?.();
|
|
12173
12214
|
if (declined) return declined;
|
|
12174
12215
|
try {
|
|
12175
|
-
(0,
|
|
12216
|
+
(0, import_node_fs18.writeFileSync)(path2, next, "utf8");
|
|
12176
12217
|
} catch {
|
|
12177
12218
|
return `could NOT ${failedVerb} ${[...pins.keys()].join(", ")} \u2014 set it by hand`;
|
|
12178
12219
|
}
|
|
@@ -12212,15 +12253,15 @@ function applyOrgMarketplacePins(path2, names, hostIsRunning = claudeCodeIsRunni
|
|
|
12212
12253
|
}
|
|
12213
12254
|
function writeMarketplacePinPending(path2, names, now = Date.now()) {
|
|
12214
12255
|
try {
|
|
12215
|
-
(0,
|
|
12216
|
-
(0,
|
|
12256
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path17.dirname)(path2), { recursive: true });
|
|
12257
|
+
(0, import_node_fs18.writeFileSync)(path2, `${JSON.stringify({ v: 1, names: [...names], at: new Date(now).toISOString() })}
|
|
12217
12258
|
`, "utf8");
|
|
12218
12259
|
} catch {
|
|
12219
12260
|
}
|
|
12220
12261
|
}
|
|
12221
12262
|
function readMarketplacePinPending(path2, name, now = Date.now()) {
|
|
12222
12263
|
try {
|
|
12223
|
-
const parsed = JSON.parse((0,
|
|
12264
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
|
|
12224
12265
|
const at = typeof parsed.at === "string" ? Date.parse(parsed.at) : Number.NaN;
|
|
12225
12266
|
if (parsed.v !== 1 || !Array.isArray(parsed.names) || !parsed.names.includes(name) || !Number.isFinite(at)) return void 0;
|
|
12226
12267
|
if (now - at < 0 || now - at > 12 * 60 * 6e4) return void 0;
|
|
@@ -12778,9 +12819,9 @@ function renderAccessReport(report) {
|
|
|
12778
12819
|
}
|
|
12779
12820
|
|
|
12780
12821
|
// src/cli-doctor-shared.ts
|
|
12781
|
-
var import_node_fs18 = require("node:fs");
|
|
12782
|
-
var import_node_path18 = require("node:path");
|
|
12783
12822
|
var import_node_fs19 = require("node:fs");
|
|
12823
|
+
var import_node_path19 = require("node:path");
|
|
12824
|
+
var import_node_fs20 = require("node:fs");
|
|
12784
12825
|
|
|
12785
12826
|
// ../infra/registry-endpoints.mjs
|
|
12786
12827
|
var PROJECTS_LIST_PATH = "/projects/list";
|
|
@@ -13694,7 +13735,7 @@ var import_node_os7 = require("node:os");
|
|
|
13694
13735
|
// src/gh-create.ts
|
|
13695
13736
|
var import_promises3 = require("node:fs/promises");
|
|
13696
13737
|
var import_node_os6 = require("node:os");
|
|
13697
|
-
var
|
|
13738
|
+
var import_node_path18 = require("node:path");
|
|
13698
13739
|
var import_node_crypto3 = require("node:crypto");
|
|
13699
13740
|
|
|
13700
13741
|
// src/board-priority.ts
|
|
@@ -13777,8 +13818,8 @@ async function bodyArgsViaFile(args, deps = {}) {
|
|
|
13777
13818
|
const remove2 = deps.remove ?? import_promises3.unlink;
|
|
13778
13819
|
const ensureDir = deps.ensureDir ?? import_promises3.mkdir;
|
|
13779
13820
|
const dir = deps.dir ?? (0, import_node_os6.tmpdir)();
|
|
13780
|
-
const file = (0,
|
|
13781
|
-
await ensureDir((0,
|
|
13821
|
+
const file = (0, import_node_path18.join)(dir, `mmi-gh-body-${process.pid}-${(0, import_node_crypto3.randomBytes)(4).toString("hex")}.md`);
|
|
13822
|
+
await ensureDir((0, import_node_path18.dirname)(file), { recursive: true }).catch(() => {
|
|
13782
13823
|
});
|
|
13783
13824
|
await write(file, args[i + 1], "utf8");
|
|
13784
13825
|
return {
|
|
@@ -15321,7 +15362,7 @@ async function localBranchHeads() {
|
|
|
15321
15362
|
}
|
|
15322
15363
|
async function currentRepoWorktreeGitRoot(repoRoot2) {
|
|
15323
15364
|
const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
15324
|
-
return gitCommonDir ? (0,
|
|
15365
|
+
return gitCommonDir ? (0, import_node_path19.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
|
|
15325
15366
|
}
|
|
15326
15367
|
async function worktreeBranches() {
|
|
15327
15368
|
const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
|
|
@@ -15341,18 +15382,18 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
|
|
|
15341
15382
|
const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
|
|
15342
15383
|
if (!match?.[1]) return void 0;
|
|
15343
15384
|
const raw = match[1].trim();
|
|
15344
|
-
return (0,
|
|
15385
|
+
return (0, import_node_path19.isAbsolute)(raw) ? raw : (0, import_node_path19.resolve)(worktreePath, raw);
|
|
15345
15386
|
}
|
|
15346
15387
|
function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
15347
15388
|
if (!worktreeGitRoot) return false;
|
|
15348
15389
|
try {
|
|
15349
|
-
const entries = (0,
|
|
15390
|
+
const entries = (0, import_node_fs20.readdirSync)(worktreeGitRoot, { withFileTypes: true });
|
|
15350
15391
|
for (const ent of entries) {
|
|
15351
15392
|
if (!ent.isDirectory()) continue;
|
|
15352
15393
|
try {
|
|
15353
|
-
const gitdirPath = (0,
|
|
15354
|
-
const resolvedGitdir = (0,
|
|
15355
|
-
if (sameWorktreeMetadataPath((0,
|
|
15394
|
+
const gitdirPath = (0, import_node_fs19.readFileSync)((0, import_node_path19.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
|
|
15395
|
+
const resolvedGitdir = (0, import_node_path19.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path19.resolve)(worktreeGitRoot, ent.name, gitdirPath);
|
|
15396
|
+
if (sameWorktreeMetadataPath((0, import_node_path19.dirname)(resolvedGitdir), worktreePath)) return true;
|
|
15356
15397
|
} catch {
|
|
15357
15398
|
}
|
|
15358
15399
|
}
|
|
@@ -15362,7 +15403,7 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
|
15362
15403
|
}
|
|
15363
15404
|
function pathExistsKnown(path2) {
|
|
15364
15405
|
try {
|
|
15365
|
-
(0,
|
|
15406
|
+
(0, import_node_fs20.statSync)(path2);
|
|
15366
15407
|
return true;
|
|
15367
15408
|
} catch (e) {
|
|
15368
15409
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
@@ -15371,10 +15412,10 @@ function pathExistsKnown(path2) {
|
|
|
15371
15412
|
}
|
|
15372
15413
|
}
|
|
15373
15414
|
function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
15374
|
-
const gitPath = (0,
|
|
15415
|
+
const gitPath = (0, import_node_path19.join)(path2, ".git");
|
|
15375
15416
|
let st;
|
|
15376
15417
|
try {
|
|
15377
|
-
st = (0,
|
|
15418
|
+
st = (0, import_node_fs20.lstatSync)(gitPath);
|
|
15378
15419
|
} catch (e) {
|
|
15379
15420
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
15380
15421
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -15391,7 +15432,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
|
15391
15432
|
if (st.isDirectory()) return { path: path2, gitType: "dir" };
|
|
15392
15433
|
if (!st.isFile()) return { path: path2, gitType: "other" };
|
|
15393
15434
|
try {
|
|
15394
|
-
const gitFileContent = (0,
|
|
15435
|
+
const gitFileContent = (0, import_node_fs19.readFileSync)(gitPath, "utf8");
|
|
15395
15436
|
const gitdir = resolveGitdirForWorktreeFile(path2, gitFileContent);
|
|
15396
15437
|
const gitDirExists = gitdir ? pathExistsKnown(gitdir) : false;
|
|
15397
15438
|
return {
|
|
@@ -15408,7 +15449,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
|
15408
15449
|
}
|
|
15409
15450
|
function inspectDeadWorktreeDirContent(path2) {
|
|
15410
15451
|
try {
|
|
15411
|
-
return { entries: (0,
|
|
15452
|
+
return { entries: (0, import_node_fs20.readdirSync)(path2) };
|
|
15412
15453
|
} catch (e) {
|
|
15413
15454
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
15414
15455
|
return { error: code ? `unable to inspect directory contents (${code})` : "unable to inspect directory contents" };
|
|
@@ -15425,7 +15466,7 @@ async function preservedBranches() {
|
|
|
15425
15466
|
async function siblingWorktreeDirs(explicitRoot) {
|
|
15426
15467
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
15427
15468
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
15428
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
15469
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path19.dirname)((0, import_node_path19.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
15429
15470
|
try {
|
|
15430
15471
|
const dirs = explicitRoot ? listDirsIn(resolveExplicitScanRoot(explicitRoot, primaryRepoRoot)) : worktreeScanDirs(siblingMmiWorktreesRoot(primaryRepoRoot), primaryRepoRoot, listDirsIn, isRepoCheckoutDir);
|
|
15431
15472
|
const agentDirs2 = listDirsIn(agentWorktreesRoot(primaryRepoRoot));
|
|
@@ -15436,18 +15477,18 @@ async function siblingWorktreeDirs(explicitRoot) {
|
|
|
15436
15477
|
}
|
|
15437
15478
|
function listDirsIn(dir) {
|
|
15438
15479
|
try {
|
|
15439
|
-
return (0,
|
|
15480
|
+
return (0, import_node_fs20.readdirSync)(dir, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => (0, import_node_path19.join)(dir, ent.name));
|
|
15440
15481
|
} catch {
|
|
15441
15482
|
return [];
|
|
15442
15483
|
}
|
|
15443
15484
|
}
|
|
15444
15485
|
function isRepoCheckoutDir(dir) {
|
|
15445
|
-
return (0,
|
|
15486
|
+
return (0, import_node_fs20.existsSync)((0, import_node_path19.join)(dir, ".git"));
|
|
15446
15487
|
}
|
|
15447
15488
|
function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
|
|
15448
15489
|
let rootDirs;
|
|
15449
15490
|
try {
|
|
15450
|
-
rootDirs = (0,
|
|
15491
|
+
rootDirs = (0, import_node_fs20.readdirSync)(explicitRoot, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => ent.name);
|
|
15451
15492
|
} catch {
|
|
15452
15493
|
return explicitRoot;
|
|
15453
15494
|
}
|
|
@@ -15779,10 +15820,10 @@ var rollout_plan_default = {
|
|
|
15779
15820
|
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)."
|
|
15780
15821
|
},
|
|
15781
15822
|
baseline: {
|
|
15782
|
-
version: "3.
|
|
15783
|
-
tag: "v3.
|
|
15784
|
-
commit: "
|
|
15785
|
-
npm: "@mutmutco/cli@3.
|
|
15823
|
+
version: "3.118.0",
|
|
15824
|
+
tag: "v3.118.0",
|
|
15825
|
+
commit: "4f9600d3bf89",
|
|
15826
|
+
npm: "@mutmutco/cli@3.118.0"
|
|
15786
15827
|
},
|
|
15787
15828
|
exitCriterion: "fleet-n-of-n",
|
|
15788
15829
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15799,14 +15840,14 @@ var rollout_plan_default = {
|
|
|
15799
15840
|
repo: "mutmutco/mmi-hub",
|
|
15800
15841
|
role: "canary",
|
|
15801
15842
|
schedule: "train",
|
|
15802
|
-
v3Target: "v3.
|
|
15843
|
+
v3Target: "v3.118.0"
|
|
15803
15844
|
}
|
|
15804
15845
|
],
|
|
15805
15846
|
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.",
|
|
15806
15847
|
rollback: {
|
|
15807
15848
|
independent: true,
|
|
15808
|
-
mechanism: "npm dist-tag latest -> 3.
|
|
15809
|
-
v3Target: "v3.
|
|
15849
|
+
mechanism: "npm dist-tag latest -> 3.118.0 and redeploy the Hub Lambda from tag v3.118.0 (4f9600d3bf89); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15850
|
+
v3Target: "v3.118.0 (@mutmutco/cli@3.118.0, tag commit 4f9600d3bf89 \u2014 the preserved latest-v3 distribution, D6b)"
|
|
15810
15851
|
}
|
|
15811
15852
|
},
|
|
15812
15853
|
{
|
|
@@ -17890,7 +17931,7 @@ function planTrainApplyRepoGuard(applyRepo, cwdRepo, rerun) {
|
|
|
17890
17931
|
async function resolveFoldPaths(deps, model) {
|
|
17891
17932
|
const helper = "scripts/release-distribution.mjs";
|
|
17892
17933
|
if (model === "hub-serverless" || model === "registry-publish") {
|
|
17893
|
-
if ((0,
|
|
17934
|
+
if ((0, import_node_fs21.existsSync)(helper)) {
|
|
17894
17935
|
let out;
|
|
17895
17936
|
try {
|
|
17896
17937
|
out = await deps.run("node", [helper, "changed-files"]);
|
|
@@ -18009,7 +18050,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
18009
18050
|
if (mainBom.version !== version) return void 0;
|
|
18010
18051
|
let localBom;
|
|
18011
18052
|
try {
|
|
18012
|
-
localBom = JSON.parse((0,
|
|
18053
|
+
localBom = JSON.parse((0, import_node_fs21.readFileSync)(bomPath, "utf8"));
|
|
18013
18054
|
} catch (e) {
|
|
18014
18055
|
throw new Error(
|
|
18015
18056
|
`version fold refused: ${bomPath} written by this fold's prepare is unreadable (${describeReadError(e)}) \u2014 cannot restore the published ${version} npm-pack identities from origin/main (#4503/#4713).`
|
|
@@ -18027,14 +18068,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
18027
18068
|
restored += 1;
|
|
18028
18069
|
}
|
|
18029
18070
|
if (restored === 0) return void 0;
|
|
18030
|
-
(0,
|
|
18071
|
+
(0, import_node_fs21.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
|
|
18031
18072
|
`);
|
|
18032
18073
|
return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
|
|
18033
18074
|
}
|
|
18034
18075
|
function publishVisibilityFor(surfaceId) {
|
|
18035
18076
|
let raw;
|
|
18036
18077
|
try {
|
|
18037
|
-
raw = (0,
|
|
18078
|
+
raw = (0, import_node_fs21.readFileSync)("surfaces.json", "utf8");
|
|
18038
18079
|
} catch (e) {
|
|
18039
18080
|
if (e.code === "ENOENT") return "unknown";
|
|
18040
18081
|
throw trainReadFailure(
|
|
@@ -18055,7 +18096,7 @@ function publishVisibilityFor(surfaceId) {
|
|
|
18055
18096
|
}
|
|
18056
18097
|
function npmPackArtifactName(packagePath) {
|
|
18057
18098
|
try {
|
|
18058
|
-
const pkg = JSON.parse((0,
|
|
18099
|
+
const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path20.join)(packagePath, "package.json"), "utf8"));
|
|
18059
18100
|
return pkg.name || void 0;
|
|
18060
18101
|
} catch {
|
|
18061
18102
|
return void 0;
|
|
@@ -18064,7 +18105,7 @@ function npmPackArtifactName(packagePath) {
|
|
|
18064
18105
|
async function refuseDivergentPublishedNpmPack(deps, version) {
|
|
18065
18106
|
let localBom;
|
|
18066
18107
|
try {
|
|
18067
|
-
localBom = JSON.parse((0,
|
|
18108
|
+
localBom = JSON.parse((0, import_node_fs21.readFileSync)("distribution-bom.json", "utf8"));
|
|
18068
18109
|
} catch (e) {
|
|
18069
18110
|
throw new Error(
|
|
18070
18111
|
`version fold refused: distribution-bom.json written by this fold's prepare is unreadable (${e instanceof Error ? e.message.split("\n")[0] : String(e)}) \u2014 cannot compare the same-PATCH ${version} npm-pack identities against published npm (#4503/#4662).`
|
|
@@ -19226,17 +19267,17 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
|
|
|
19226
19267
|
return { note: `no manual dispatch: ${model} repo deploys via its own push-triggered workflow`, deployStatus: "pending" };
|
|
19227
19268
|
}
|
|
19228
19269
|
function readLocalGateWorkflows() {
|
|
19229
|
-
const dir = (0,
|
|
19270
|
+
const dir = (0, import_node_path20.join)(".github", "workflows");
|
|
19230
19271
|
let names;
|
|
19231
19272
|
try {
|
|
19232
|
-
names = (0,
|
|
19273
|
+
names = (0, import_node_fs21.readdirSync)(dir);
|
|
19233
19274
|
} catch {
|
|
19234
19275
|
return null;
|
|
19235
19276
|
}
|
|
19236
19277
|
const files = [];
|
|
19237
19278
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
19238
19279
|
try {
|
|
19239
|
-
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0,
|
|
19280
|
+
files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs21.readFileSync)((0, import_node_path20.join)(dir, name), "utf8") });
|
|
19240
19281
|
} catch {
|
|
19241
19282
|
}
|
|
19242
19283
|
}
|
|
@@ -21457,12 +21498,12 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
21457
21498
|
}
|
|
21458
21499
|
|
|
21459
21500
|
// src/wave-status.ts
|
|
21460
|
-
var
|
|
21501
|
+
var import_node_fs23 = require("node:fs");
|
|
21461
21502
|
|
|
21462
21503
|
// src/stage-runner.ts
|
|
21463
21504
|
var import_node_child_process9 = require("node:child_process");
|
|
21464
|
-
var
|
|
21465
|
-
var
|
|
21505
|
+
var import_node_fs22 = require("node:fs");
|
|
21506
|
+
var import_node_path21 = require("node:path");
|
|
21466
21507
|
var import_node_net = require("node:net");
|
|
21467
21508
|
var import_node_util5 = require("node:util");
|
|
21468
21509
|
|
|
@@ -21601,11 +21642,11 @@ function appendForceRecreate(up) {
|
|
|
21601
21642
|
return `${up.trimEnd()} --force-recreate`;
|
|
21602
21643
|
}
|
|
21603
21644
|
function stageStatePath(cwd = process.cwd()) {
|
|
21604
|
-
return (0,
|
|
21645
|
+
return (0, import_node_path21.join)(cwd, "tmp", "stage", "state.json");
|
|
21605
21646
|
}
|
|
21606
21647
|
function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
|
|
21607
|
-
const dir = (0,
|
|
21608
|
-
return (0,
|
|
21648
|
+
const dir = (0, import_node_path21.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path21.resolve)(cwd, gitCommonDir);
|
|
21649
|
+
return (0, import_node_path21.join)(dir, "mmi", "stage", "state.json");
|
|
21609
21650
|
}
|
|
21610
21651
|
function normPath3(path2) {
|
|
21611
21652
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -21829,14 +21870,14 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
21829
21870
|
}
|
|
21830
21871
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
21831
21872
|
if (!config.ensureEnv) return;
|
|
21832
|
-
const target = (0,
|
|
21833
|
-
const example = (0,
|
|
21834
|
-
if (!(0,
|
|
21835
|
-
(0,
|
|
21836
|
-
} else if ((0,
|
|
21837
|
-
const stale = detectStaleEnvFile((0,
|
|
21838
|
-
exampleMtimeMs: (0,
|
|
21839
|
-
targetMtimeMs: (0,
|
|
21873
|
+
const target = (0, import_node_path21.join)(cwd, config.ensureEnv.target);
|
|
21874
|
+
const example = (0, import_node_path21.join)(cwd, config.ensureEnv.example);
|
|
21875
|
+
if (!(0, import_node_fs22.existsSync)(target) && (0, import_node_fs22.existsSync)(example)) {
|
|
21876
|
+
(0, import_node_fs22.copyFileSync)(example, target);
|
|
21877
|
+
} else if ((0, import_node_fs22.existsSync)(target) && (0, import_node_fs22.existsSync)(example)) {
|
|
21878
|
+
const stale = detectStaleEnvFile((0, import_node_fs22.readFileSync)(example, "utf8"), (0, import_node_fs22.readFileSync)(target, "utf8"), {
|
|
21879
|
+
exampleMtimeMs: (0, import_node_fs22.statSync)(example).mtimeMs,
|
|
21880
|
+
targetMtimeMs: (0, import_node_fs22.statSync)(target).mtimeMs
|
|
21840
21881
|
});
|
|
21841
21882
|
if (stale) {
|
|
21842
21883
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -21844,8 +21885,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
21844
21885
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
21845
21886
|
}
|
|
21846
21887
|
}
|
|
21847
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
21848
|
-
(0,
|
|
21888
|
+
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs22.existsSync)(target)) {
|
|
21889
|
+
(0, import_node_fs22.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs22.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
|
|
21849
21890
|
}
|
|
21850
21891
|
}
|
|
21851
21892
|
async function gitText(cwd, args) {
|
|
@@ -21875,20 +21916,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
21875
21916
|
return void 0;
|
|
21876
21917
|
}
|
|
21877
21918
|
function readState(path2) {
|
|
21878
|
-
if (!(0,
|
|
21919
|
+
if (!(0, import_node_fs22.existsSync)(path2)) return null;
|
|
21879
21920
|
try {
|
|
21880
|
-
return JSON.parse((0,
|
|
21921
|
+
return JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
21881
21922
|
} catch {
|
|
21882
21923
|
return null;
|
|
21883
21924
|
}
|
|
21884
21925
|
}
|
|
21885
21926
|
function mkdirFor(path2) {
|
|
21886
21927
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
21887
|
-
(0,
|
|
21928
|
+
(0, import_node_fs22.mkdirSync)(dir, { recursive: true });
|
|
21888
21929
|
}
|
|
21889
21930
|
function writeState(path2, state) {
|
|
21890
21931
|
mkdirFor(path2);
|
|
21891
|
-
(0,
|
|
21932
|
+
(0, import_node_fs22.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
21892
21933
|
}
|
|
21893
21934
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
21894
21935
|
const reservation = {
|
|
@@ -21908,7 +21949,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd) {
|
|
|
21908
21949
|
await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, Math.max(timeoutMs, 1e4));
|
|
21909
21950
|
}
|
|
21910
21951
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
21911
|
-
(0,
|
|
21952
|
+
(0, import_node_fs22.rmSync)(path2, { force: true });
|
|
21912
21953
|
}
|
|
21913
21954
|
}
|
|
21914
21955
|
async function killTree(pid) {
|
|
@@ -22066,8 +22107,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
22066
22107
|
await ensureStageRuntimeEnv(config, opts, cwd);
|
|
22067
22108
|
if (build) await shell(sub(build), cwd, timeoutMs, stageProcessEnv(stagePort, extraEnv));
|
|
22068
22109
|
} catch (e) {
|
|
22069
|
-
(0,
|
|
22070
|
-
if (globalStatePath && globalStatePath !== statePath) (0,
|
|
22110
|
+
(0, import_node_fs22.rmSync)(statePath, { force: true });
|
|
22111
|
+
if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs22.rmSync)(globalStatePath, { force: true });
|
|
22071
22112
|
throw e;
|
|
22072
22113
|
}
|
|
22073
22114
|
const started = await startStage(config, {
|
|
@@ -22088,9 +22129,9 @@ function parseNextFromHead(headText) {
|
|
|
22088
22129
|
}
|
|
22089
22130
|
function readStageSummary(worktreePath) {
|
|
22090
22131
|
const statePath = stageStatePath(worktreePath);
|
|
22091
|
-
if (!(0,
|
|
22132
|
+
if (!(0, import_node_fs23.existsSync)(statePath)) return void 0;
|
|
22092
22133
|
try {
|
|
22093
|
-
const state = JSON.parse((0,
|
|
22134
|
+
const state = JSON.parse((0, import_node_fs23.readFileSync)(statePath, "utf8"));
|
|
22094
22135
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
22095
22136
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
22096
22137
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -22199,9 +22240,9 @@ var import_node_os19 = require("node:os");
|
|
|
22199
22240
|
|
|
22200
22241
|
// src/board.ts
|
|
22201
22242
|
var import_node_child_process10 = require("node:child_process");
|
|
22202
|
-
var
|
|
22243
|
+
var import_node_fs24 = require("node:fs");
|
|
22203
22244
|
var import_node_os8 = require("node:os");
|
|
22204
|
-
var
|
|
22245
|
+
var import_node_path22 = require("node:path");
|
|
22205
22246
|
var import_node_util6 = require("node:util");
|
|
22206
22247
|
|
|
22207
22248
|
// src/board-dependency.ts
|
|
@@ -23948,17 +23989,17 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
23948
23989
|
claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
|
|
23949
23990
|
return state;
|
|
23950
23991
|
};
|
|
23951
|
-
const root = (0,
|
|
23992
|
+
const root = (0, import_node_path22.join)((0, import_node_os8.homedir)(), ".claude", "projects");
|
|
23952
23993
|
try {
|
|
23953
23994
|
const wanted = `${marker.session}.jsonl`.toLowerCase();
|
|
23954
23995
|
const pending = [root];
|
|
23955
23996
|
while (pending.length) {
|
|
23956
23997
|
const dir = pending.pop();
|
|
23957
|
-
for (const entry of (0,
|
|
23958
|
-
const path2 = (0,
|
|
23998
|
+
for (const entry of (0, import_node_fs24.readdirSync)(dir, { withFileTypes: true })) {
|
|
23999
|
+
const path2 = (0, import_node_path22.join)(dir, entry.name);
|
|
23959
24000
|
if (entry.isDirectory()) pending.push(path2);
|
|
23960
24001
|
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
23961
|
-
return remember(now - (0,
|
|
24002
|
+
return remember(now - (0, import_node_fs24.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
23962
24003
|
}
|
|
23963
24004
|
}
|
|
23964
24005
|
}
|
|
@@ -24857,8 +24898,8 @@ function consolidateCommandNamespaces(program3) {
|
|
|
24857
24898
|
}
|
|
24858
24899
|
|
|
24859
24900
|
// src/pi-plugin-registration.ts
|
|
24860
|
-
var
|
|
24861
|
-
var
|
|
24901
|
+
var import_node_fs25 = require("node:fs");
|
|
24902
|
+
var import_node_path23 = require("node:path");
|
|
24862
24903
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
24863
24904
|
|
|
24864
24905
|
// src/plugin-cache-prune.ts
|
|
@@ -25116,48 +25157,48 @@ function newestExistingPiPlugin(home) {
|
|
|
25116
25157
|
const cacheRoot = pluginCacheRoot(home);
|
|
25117
25158
|
let names;
|
|
25118
25159
|
try {
|
|
25119
|
-
names = (0,
|
|
25160
|
+
names = (0, import_node_fs25.readdirSync)(cacheRoot);
|
|
25120
25161
|
} catch {
|
|
25121
25162
|
return void 0;
|
|
25122
25163
|
}
|
|
25123
25164
|
for (const version of names.filter(isVersionDirName).sort((a, b) => compareVersions(b, a))) {
|
|
25124
|
-
const candidate = (0,
|
|
25125
|
-
if ((0,
|
|
25165
|
+
const candidate = (0, import_node_path23.join)(cacheRoot, version, ".pi-plugin");
|
|
25166
|
+
if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
|
|
25126
25167
|
}
|
|
25127
25168
|
return void 0;
|
|
25128
25169
|
}
|
|
25129
25170
|
function expectedPiPluginPath(home, env, installedVersion) {
|
|
25130
25171
|
const root = env.CLAUDE_PLUGIN_ROOT?.trim();
|
|
25131
|
-
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0,
|
|
25172
|
+
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path23.join)(root, ".pi-plugin");
|
|
25132
25173
|
const version = installedVersion ?? runningPluginVersion(env);
|
|
25133
25174
|
if (version) {
|
|
25134
|
-
const pinned = (0,
|
|
25135
|
-
if ((0,
|
|
25175
|
+
const pinned = (0, import_node_path23.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
|
|
25176
|
+
if ((0, import_node_fs25.existsSync)(pinned)) return pinned;
|
|
25136
25177
|
}
|
|
25137
25178
|
return newestExistingPiPlugin(home);
|
|
25138
25179
|
}
|
|
25139
25180
|
function agentDirs(home, env = process.env) {
|
|
25140
25181
|
const override = env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
|
|
25141
25182
|
if (override) return [override];
|
|
25142
|
-
const jerv = (0,
|
|
25143
|
-
const pi = (0,
|
|
25144
|
-
if (!(0,
|
|
25183
|
+
const jerv = (0, import_node_path23.join)(home, ".jerv", "agent");
|
|
25184
|
+
const pi = (0, import_node_path23.join)(home, ".pi", "agent");
|
|
25185
|
+
if (!(0, import_node_fs25.existsSync)(jerv) && !(0, import_node_fs25.existsSync)(pi)) return [];
|
|
25145
25186
|
const dirs = [jerv];
|
|
25146
|
-
if ((0,
|
|
25187
|
+
if ((0, import_node_fs25.existsSync)(pi) && pi !== jerv) dirs.push(pi);
|
|
25147
25188
|
return dirs;
|
|
25148
25189
|
}
|
|
25149
25190
|
function settingsPath(agentDir) {
|
|
25150
|
-
return (0,
|
|
25191
|
+
return (0, import_node_path23.join)(agentDir, "settings.json");
|
|
25151
25192
|
}
|
|
25152
25193
|
function readPiPluginState(home, env, installedVersion) {
|
|
25153
25194
|
const dirs = agentDirs(home, env);
|
|
25154
25195
|
if (dirs.length === 0) return void 0;
|
|
25155
25196
|
const expectedPath = expectedPiPluginPath(home, env, installedVersion);
|
|
25156
25197
|
if (!expectedPath) return void 0;
|
|
25157
|
-
const file = dirs.map(settingsPath).find((p) => (0,
|
|
25158
|
-
if (!(0,
|
|
25198
|
+
const file = dirs.map(settingsPath).find((p) => (0, import_node_fs25.existsSync)(p)) ?? settingsPath(dirs[0]);
|
|
25199
|
+
if (!(0, import_node_fs25.existsSync)(file)) return { expectedPath, settingsReadable: true };
|
|
25159
25200
|
try {
|
|
25160
|
-
const parsed = JSON.parse((0,
|
|
25201
|
+
const parsed = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf8"));
|
|
25161
25202
|
const packages = Array.isArray(parsed.packages) ? parsed.packages : [];
|
|
25162
25203
|
return { expectedPath, registeredPath: packages.find((p) => typeof p === "string" && isMmiPiPackage(p)), settingsReadable: true };
|
|
25163
25204
|
} catch {
|
|
@@ -25181,20 +25222,20 @@ function acquirePiSettingsLock2(settingsFile) {
|
|
|
25181
25222
|
return void 0;
|
|
25182
25223
|
}
|
|
25183
25224
|
function atomicWriteSettings(file, body) {
|
|
25184
|
-
(0,
|
|
25225
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(file), { recursive: true });
|
|
25185
25226
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
25186
|
-
(0,
|
|
25227
|
+
(0, import_node_fs25.writeFileSync)(tmp, body, "utf8");
|
|
25187
25228
|
try {
|
|
25188
|
-
(0,
|
|
25229
|
+
(0, import_node_fs25.renameSync)(tmp, file);
|
|
25189
25230
|
} catch (renameError) {
|
|
25190
|
-
(0,
|
|
25231
|
+
(0, import_node_fs25.rmSync)(tmp, { force: true });
|
|
25191
25232
|
throw renameError;
|
|
25192
25233
|
}
|
|
25193
25234
|
}
|
|
25194
25235
|
function healOneAgentDir(agentDir, expectedPath) {
|
|
25195
25236
|
const file = settingsPath(agentDir);
|
|
25196
|
-
const release = (0,
|
|
25197
|
-
if ((0,
|
|
25237
|
+
const release = (0, import_node_fs25.existsSync)(file) ? acquirePiSettingsLock2(file) : void 0;
|
|
25238
|
+
if ((0, import_node_fs25.existsSync)(file) && !release) {
|
|
25198
25239
|
return {
|
|
25199
25240
|
ok: false,
|
|
25200
25241
|
detail: `Pi's settings lock (${file}.lock) is held by another process; nothing written, retry on the next doctor run`,
|
|
@@ -25203,9 +25244,9 @@ function healOneAgentDir(agentDir, expectedPath) {
|
|
|
25203
25244
|
}
|
|
25204
25245
|
try {
|
|
25205
25246
|
let parsed = {};
|
|
25206
|
-
if ((0,
|
|
25247
|
+
if ((0, import_node_fs25.existsSync)(file)) {
|
|
25207
25248
|
try {
|
|
25208
|
-
const raw = JSON.parse((0,
|
|
25249
|
+
const raw = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf8"));
|
|
25209
25250
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25210
25251
|
return { ok: false, detail: "settings.json unreadable \u2014 nothing written (fail closed)" };
|
|
25211
25252
|
}
|
|
@@ -25257,20 +25298,20 @@ function healPiPluginRegistration(home, env, installedVersion) {
|
|
|
25257
25298
|
}
|
|
25258
25299
|
|
|
25259
25300
|
// src/claude-binary-doctor.ts
|
|
25260
|
-
var
|
|
25301
|
+
var import_node_fs27 = require("node:fs");
|
|
25261
25302
|
var import_node_os11 = require("node:os");
|
|
25262
|
-
var
|
|
25303
|
+
var import_node_path25 = require("node:path");
|
|
25263
25304
|
|
|
25264
25305
|
// src/jerv-cli-spawn.ts
|
|
25265
|
-
var
|
|
25306
|
+
var import_node_fs26 = require("node:fs");
|
|
25266
25307
|
var import_node_os10 = require("node:os");
|
|
25267
|
-
var
|
|
25308
|
+
var import_node_path24 = require("node:path");
|
|
25268
25309
|
var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
|
|
25269
25310
|
var POSIX_NAMES = ["jerv-cli"];
|
|
25270
|
-
var JERV_CLI_ENTRY = (0,
|
|
25311
|
+
var JERV_CLI_ENTRY = (0, import_node_path24.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
25271
25312
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
25272
25313
|
if (platform2 !== "win32") {
|
|
25273
|
-
return pathEnv.split(
|
|
25314
|
+
return pathEnv.split(import_node_path24.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
25274
25315
|
}
|
|
25275
25316
|
if (pathEnv.includes(";")) {
|
|
25276
25317
|
return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
|
|
@@ -25303,10 +25344,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os10.hom
|
|
|
25303
25344
|
push(normalizeSpawnPathEntry(entry, platform2));
|
|
25304
25345
|
}
|
|
25305
25346
|
if (platform2 === "win32") {
|
|
25306
|
-
if (env.APPDATA) push((0,
|
|
25307
|
-
if (env.LOCALAPPDATA) push((0,
|
|
25347
|
+
if (env.APPDATA) push((0, import_node_path24.join)(env.APPDATA, "npm"));
|
|
25348
|
+
if (env.LOCALAPPDATA) push((0, import_node_path24.join)(env.LOCALAPPDATA, "npm"));
|
|
25308
25349
|
} else {
|
|
25309
|
-
push((0,
|
|
25350
|
+
push((0, import_node_path24.join)(home, ".local", "bin"));
|
|
25310
25351
|
}
|
|
25311
25352
|
return out;
|
|
25312
25353
|
}
|
|
@@ -25314,23 +25355,23 @@ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os10.ho
|
|
|
25314
25355
|
const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
|
|
25315
25356
|
const out = [];
|
|
25316
25357
|
for (const dir of jervCliCandidateDirs(env, home, platform2)) {
|
|
25317
|
-
for (const name of names) out.push((0,
|
|
25358
|
+
for (const name of names) out.push((0, import_node_path24.join)(dir, name));
|
|
25318
25359
|
}
|
|
25319
25360
|
return out;
|
|
25320
25361
|
}
|
|
25321
|
-
function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homedir)(), platform2 = process.platform, exists =
|
|
25362
|
+
function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homedir)(), platform2 = process.platform, exists = import_node_fs26.existsSync) {
|
|
25322
25363
|
for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
|
|
25323
25364
|
if (exists(candidate)) return candidate;
|
|
25324
25365
|
}
|
|
25325
25366
|
return void 0;
|
|
25326
25367
|
}
|
|
25327
|
-
function resolveJervCliNodeEntry(shimPath, exists =
|
|
25328
|
-
const entry = (0,
|
|
25368
|
+
function resolveJervCliNodeEntry(shimPath, exists = import_node_fs26.existsSync) {
|
|
25369
|
+
const entry = (0, import_node_path24.join)((0, import_node_path24.dirname)(shimPath), JERV_CLI_ENTRY);
|
|
25329
25370
|
return exists(entry) ? entry : void 0;
|
|
25330
25371
|
}
|
|
25331
25372
|
function jervCliExecFileArgs(args, opts = {}) {
|
|
25332
25373
|
const platform2 = opts.platform ?? process.platform;
|
|
25333
|
-
const exists = opts.exists ??
|
|
25374
|
+
const exists = opts.exists ?? import_node_fs26.existsSync;
|
|
25334
25375
|
const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os10.homedir)(), platform2, exists);
|
|
25335
25376
|
if (resolved) {
|
|
25336
25377
|
const entry = resolveJervCliNodeEntry(resolved, exists);
|
|
@@ -25420,26 +25461,26 @@ function globalNodeModulesRoots(host) {
|
|
|
25420
25461
|
out.push(dir);
|
|
25421
25462
|
};
|
|
25422
25463
|
const prefix = env.npm_config_prefix?.trim();
|
|
25423
|
-
if (prefix) push(platform2 === "win32" ? (0,
|
|
25464
|
+
if (prefix) push(platform2 === "win32" ? (0, import_node_path25.join)(prefix, "node_modules") : (0, import_node_path25.join)(prefix, "lib", "node_modules"));
|
|
25424
25465
|
for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os11.homedir)(), platform2)) {
|
|
25425
|
-
push((0,
|
|
25426
|
-
push((0,
|
|
25466
|
+
push((0, import_node_path25.join)(dir, "node_modules"));
|
|
25467
|
+
push((0, import_node_path25.join)((0, import_node_path25.dirname)(dir), "lib", "node_modules"));
|
|
25427
25468
|
}
|
|
25428
25469
|
return out;
|
|
25429
25470
|
}
|
|
25430
25471
|
function readHead(path2) {
|
|
25431
25472
|
let fd;
|
|
25432
25473
|
try {
|
|
25433
|
-
fd = (0,
|
|
25474
|
+
fd = (0, import_node_fs27.openSync)(path2, "r");
|
|
25434
25475
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
25435
|
-
const read = (0,
|
|
25476
|
+
const read = (0, import_node_fs27.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
25436
25477
|
return buffer.subarray(0, read);
|
|
25437
25478
|
} catch {
|
|
25438
25479
|
return void 0;
|
|
25439
25480
|
} finally {
|
|
25440
25481
|
if (fd !== void 0) {
|
|
25441
25482
|
try {
|
|
25442
|
-
(0,
|
|
25483
|
+
(0, import_node_fs27.closeSync)(fd);
|
|
25443
25484
|
} catch {
|
|
25444
25485
|
}
|
|
25445
25486
|
}
|
|
@@ -25447,7 +25488,7 @@ function readHead(path2) {
|
|
|
25447
25488
|
}
|
|
25448
25489
|
function fileBytes(path2) {
|
|
25449
25490
|
try {
|
|
25450
|
-
return (0,
|
|
25491
|
+
return (0, import_node_fs27.statSync)(path2).size;
|
|
25451
25492
|
} catch {
|
|
25452
25493
|
return void 0;
|
|
25453
25494
|
}
|
|
@@ -25461,17 +25502,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25461
25502
|
const arch = host.arch ?? process.arch;
|
|
25462
25503
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
25463
25504
|
if (!magic) return void 0;
|
|
25464
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0,
|
|
25505
|
+
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path25.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs27.existsSync)((0, import_node_path25.join)(dir, "package.json")));
|
|
25465
25506
|
if (!packageRoot) return void 0;
|
|
25466
25507
|
const keys = platformPackageKeys(platform2, arch);
|
|
25467
25508
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
25468
25509
|
let manifest;
|
|
25469
25510
|
try {
|
|
25470
|
-
manifest = JSON.parse((0,
|
|
25511
|
+
manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path25.join)(packageRoot, "package.json"), "utf8"));
|
|
25471
25512
|
} catch (e) {
|
|
25472
25513
|
return {
|
|
25473
25514
|
state: "unreadable",
|
|
25474
|
-
binPath: (0,
|
|
25515
|
+
binPath: (0, import_node_path25.join)(packageRoot, "package.json"),
|
|
25475
25516
|
expectedMagic: magic.name,
|
|
25476
25517
|
platformPackage: fallbackPackage,
|
|
25477
25518
|
error: `package.json could not be read \u2014 ${e.message}`
|
|
@@ -25488,17 +25529,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25488
25529
|
error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
|
|
25489
25530
|
};
|
|
25490
25531
|
}
|
|
25491
|
-
const binPath = (0,
|
|
25492
|
-
const binName = (0,
|
|
25532
|
+
const binPath = (0, import_node_path25.join)(packageRoot, binRelative);
|
|
25533
|
+
const binName = (0, import_node_path25.basename)(binRelative);
|
|
25493
25534
|
const optional = manifest.optionalDependencies;
|
|
25494
25535
|
const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
|
|
25495
25536
|
const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
|
|
25496
25537
|
if (published.length === 0) return void 0;
|
|
25497
25538
|
const binIn = (name) => [
|
|
25498
|
-
(0,
|
|
25499
|
-
(0,
|
|
25539
|
+
(0, import_node_path25.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
25540
|
+
(0, import_node_path25.join)((0, import_node_path25.dirname)((0, import_node_path25.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
25500
25541
|
];
|
|
25501
|
-
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0,
|
|
25542
|
+
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
|
|
25502
25543
|
const platformPackage = found?.name ?? published[0];
|
|
25503
25544
|
let source;
|
|
25504
25545
|
let sourceProblem;
|
|
@@ -25509,7 +25550,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25509
25550
|
} else {
|
|
25510
25551
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
25511
25552
|
}
|
|
25512
|
-
if (!(0,
|
|
25553
|
+
if (!(0, import_node_fs27.existsSync)(binPath)) {
|
|
25513
25554
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
25514
25555
|
}
|
|
25515
25556
|
const head = readHead(binPath);
|
|
@@ -25552,9 +25593,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25552
25593
|
const platform2 = host.platform ?? process.platform;
|
|
25553
25594
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
25554
25595
|
let renamed = false;
|
|
25555
|
-
if ((0,
|
|
25596
|
+
if ((0, import_node_fs27.existsSync)(probe.binPath)) {
|
|
25556
25597
|
try {
|
|
25557
|
-
(0,
|
|
25598
|
+
(0, import_node_fs27.renameSync)(probe.binPath, aside);
|
|
25558
25599
|
renamed = true;
|
|
25559
25600
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
25560
25601
|
} catch (e) {
|
|
@@ -25563,12 +25604,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25563
25604
|
}
|
|
25564
25605
|
try {
|
|
25565
25606
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
25566
|
-
(0,
|
|
25567
|
-
if (platform2 !== "win32") (0,
|
|
25607
|
+
(0, import_node_fs27.copyFileSync)(probe.source.path, probe.binPath);
|
|
25608
|
+
if (platform2 !== "win32") (0, import_node_fs27.chmodSync)(probe.binPath, 493);
|
|
25568
25609
|
} catch (e) {
|
|
25569
25610
|
if (renamed) {
|
|
25570
25611
|
try {
|
|
25571
|
-
(0,
|
|
25612
|
+
(0, import_node_fs27.renameSync)(aside, probe.binPath);
|
|
25572
25613
|
} catch {
|
|
25573
25614
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
25574
25615
|
}
|
|
@@ -25582,7 +25623,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25582
25623
|
let kept = false;
|
|
25583
25624
|
if (renamed) {
|
|
25584
25625
|
try {
|
|
25585
|
-
(0,
|
|
25626
|
+
(0, import_node_fs27.rmSync)(aside);
|
|
25586
25627
|
} catch {
|
|
25587
25628
|
kept = true;
|
|
25588
25629
|
}
|
|
@@ -26916,8 +26957,8 @@ async function announceRelease(deps, args) {
|
|
|
26916
26957
|
// src/repo-index.ts
|
|
26917
26958
|
var import_node_crypto4 = require("node:crypto");
|
|
26918
26959
|
var import_node_child_process13 = require("node:child_process");
|
|
26919
|
-
var
|
|
26920
|
-
var
|
|
26960
|
+
var import_node_fs28 = require("node:fs");
|
|
26961
|
+
var import_node_path26 = require("node:path");
|
|
26921
26962
|
var REPO_INDEX_SCHEMA = 1;
|
|
26922
26963
|
var HARD_DENY = [
|
|
26923
26964
|
/(^|\/)\.env(\.|$)/i,
|
|
@@ -27042,11 +27083,11 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27042
27083
|
}
|
|
27043
27084
|
for (const rel of readmes) {
|
|
27044
27085
|
if (isHardDeniedPath(rel)) continue;
|
|
27045
|
-
const abs = (0,
|
|
27046
|
-
if (!(0,
|
|
27086
|
+
const abs = (0, import_node_path26.join)(cwd, ...rel.split("/"));
|
|
27087
|
+
if (!(0, import_node_fs28.existsSync)(abs)) continue;
|
|
27047
27088
|
let text;
|
|
27048
27089
|
try {
|
|
27049
|
-
text = (0,
|
|
27090
|
+
text = (0, import_node_fs28.readFileSync)(abs, "utf8");
|
|
27050
27091
|
} catch {
|
|
27051
27092
|
continue;
|
|
27052
27093
|
}
|
|
@@ -27059,7 +27100,7 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27059
27100
|
return hints;
|
|
27060
27101
|
}
|
|
27061
27102
|
function toPosix(p) {
|
|
27062
|
-
return p.split(
|
|
27103
|
+
return p.split(import_node_path26.sep).join("/");
|
|
27063
27104
|
}
|
|
27064
27105
|
function listCandidatePaths(cwd, exec = import_node_child_process13.execFileSync) {
|
|
27065
27106
|
try {
|
|
@@ -27081,11 +27122,11 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27081
27122
|
for (const rel of candidates) {
|
|
27082
27123
|
if (ignored.has(rel)) continue;
|
|
27083
27124
|
if (isHardDeniedPath(rel)) continue;
|
|
27084
|
-
const abs = (0,
|
|
27085
|
-
if (!(0,
|
|
27125
|
+
const abs = (0, import_node_path26.join)(cwd, ...rel.split("/"));
|
|
27126
|
+
if (!(0, import_node_fs28.existsSync)(abs)) continue;
|
|
27086
27127
|
let text;
|
|
27087
27128
|
try {
|
|
27088
|
-
text = (0,
|
|
27129
|
+
text = (0, import_node_fs28.readFileSync)(abs, "utf8");
|
|
27089
27130
|
} catch {
|
|
27090
27131
|
continue;
|
|
27091
27132
|
}
|
|
@@ -27110,16 +27151,16 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27110
27151
|
entries
|
|
27111
27152
|
};
|
|
27112
27153
|
const store = repoIndexStorePath(cwd);
|
|
27113
|
-
(0,
|
|
27114
|
-
(0,
|
|
27154
|
+
(0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(store), { recursive: true });
|
|
27155
|
+
(0, import_node_fs28.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
|
|
27115
27156
|
`, "utf8");
|
|
27116
27157
|
return projection;
|
|
27117
27158
|
}
|
|
27118
27159
|
function loadRepoIndex(cwd) {
|
|
27119
27160
|
const store = repoIndexStorePath(cwd);
|
|
27120
|
-
if (!(0,
|
|
27161
|
+
if (!(0, import_node_fs28.existsSync)(store)) return null;
|
|
27121
27162
|
try {
|
|
27122
|
-
const raw = JSON.parse((0,
|
|
27163
|
+
const raw = JSON.parse((0, import_node_fs28.readFileSync)(store, "utf8"));
|
|
27123
27164
|
if (raw?.schema !== REPO_INDEX_SCHEMA || !Array.isArray(raw.entries)) return null;
|
|
27124
27165
|
return raw;
|
|
27125
27166
|
} catch {
|
|
@@ -27191,7 +27232,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process13.execFileSync) {
|
|
|
27191
27232
|
if (m?.[1]) return m[1].toLowerCase();
|
|
27192
27233
|
} catch {
|
|
27193
27234
|
}
|
|
27194
|
-
return ((0,
|
|
27235
|
+
return ((0, import_node_path26.basename)(cwd) || "local").toLowerCase();
|
|
27195
27236
|
}
|
|
27196
27237
|
|
|
27197
27238
|
// src/repo-index-cloud-client.ts
|
|
@@ -27331,9 +27372,9 @@ async function gcRepoIndexCloud(deps) {
|
|
|
27331
27372
|
}
|
|
27332
27373
|
|
|
27333
27374
|
// src/repo-index-sync.ts
|
|
27334
|
-
var
|
|
27375
|
+
var import_node_fs29 = require("node:fs");
|
|
27335
27376
|
var import_node_os12 = require("node:os");
|
|
27336
|
-
var
|
|
27377
|
+
var import_node_path27 = require("node:path");
|
|
27337
27378
|
var import_node_child_process14 = require("node:child_process");
|
|
27338
27379
|
var MAX_EMBED_BACKFILL_ROUNDS = 40;
|
|
27339
27380
|
function normalizeRepo(raw) {
|
|
@@ -27377,7 +27418,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27377
27418
|
const failed = [];
|
|
27378
27419
|
const skipped = [];
|
|
27379
27420
|
for (const repo of repos) {
|
|
27380
|
-
const dir = (0,
|
|
27421
|
+
const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path27.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
|
|
27381
27422
|
try {
|
|
27382
27423
|
shallowClone(repo, dir, opts.githubToken);
|
|
27383
27424
|
const built = rebuildRepoIndex(dir, repo);
|
|
@@ -27427,7 +27468,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27427
27468
|
failed.push({ repo, error: e.message });
|
|
27428
27469
|
} finally {
|
|
27429
27470
|
try {
|
|
27430
|
-
(0,
|
|
27471
|
+
(0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
|
|
27431
27472
|
} catch {
|
|
27432
27473
|
}
|
|
27433
27474
|
}
|
|
@@ -27436,7 +27477,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27436
27477
|
}
|
|
27437
27478
|
|
|
27438
27479
|
// src/repo-index-health.ts
|
|
27439
|
-
var
|
|
27480
|
+
var import_node_fs30 = require("node:fs");
|
|
27440
27481
|
|
|
27441
27482
|
// testdata/repo-index-golden-queries.json
|
|
27442
27483
|
var repo_index_golden_queries_default = {
|
|
@@ -27478,7 +27519,7 @@ function assertGoldenSuite(raw, source) {
|
|
|
27478
27519
|
function loadGoldenSuite(path2) {
|
|
27479
27520
|
let text;
|
|
27480
27521
|
try {
|
|
27481
|
-
text = (0,
|
|
27522
|
+
text = (0, import_node_fs30.readFileSync)(path2, "utf8");
|
|
27482
27523
|
} catch (e) {
|
|
27483
27524
|
throw new Error(`golden suite unreadable at ${path2}: ${e.message}`);
|
|
27484
27525
|
}
|
|
@@ -27624,8 +27665,8 @@ async function runRepoIndexHealth(opts) {
|
|
|
27624
27665
|
|
|
27625
27666
|
// src/spawn-policy-core.ts
|
|
27626
27667
|
var import_node_child_process15 = require("node:child_process");
|
|
27627
|
-
var
|
|
27628
|
-
var
|
|
27668
|
+
var import_node_fs31 = require("node:fs");
|
|
27669
|
+
var import_node_path28 = require("node:path");
|
|
27629
27670
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
27630
27671
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
27631
27672
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -27711,7 +27752,7 @@ function runSpawnPolicy(root) {
|
|
|
27711
27752
|
for (const file of files) {
|
|
27712
27753
|
let raw;
|
|
27713
27754
|
try {
|
|
27714
|
-
raw = (0,
|
|
27755
|
+
raw = (0, import_node_fs31.readFileSync)((0, import_node_path28.join)(root, file), "utf8");
|
|
27715
27756
|
} catch {
|
|
27716
27757
|
continue;
|
|
27717
27758
|
}
|
|
@@ -27729,8 +27770,8 @@ function runSpawnPolicy(root) {
|
|
|
27729
27770
|
|
|
27730
27771
|
// src/test-policy-core.ts
|
|
27731
27772
|
var import_node_child_process16 = require("node:child_process");
|
|
27732
|
-
var
|
|
27733
|
-
var
|
|
27773
|
+
var import_node_fs32 = require("node:fs");
|
|
27774
|
+
var import_node_path29 = require("node:path");
|
|
27734
27775
|
var POLICY_FILE = "test-policy.json";
|
|
27735
27776
|
var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
27736
27777
|
var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
|
|
@@ -27783,7 +27824,7 @@ function isTestPath(path2) {
|
|
|
27783
27824
|
return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
|
|
27784
27825
|
}
|
|
27785
27826
|
function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
27786
|
-
const raw = readFile9((0,
|
|
27827
|
+
const raw = readFile9((0, import_node_path29.join)(root, POLICY_FILE));
|
|
27787
27828
|
if (raw == null) return { mandatory: [], declared: false };
|
|
27788
27829
|
try {
|
|
27789
27830
|
return { ...JSON.parse(raw), declared: true };
|
|
@@ -27793,7 +27834,7 @@ function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
|
27793
27834
|
}
|
|
27794
27835
|
function readFileOrNull2(path2) {
|
|
27795
27836
|
try {
|
|
27796
|
-
return (0,
|
|
27837
|
+
return (0, import_node_fs32.readFileSync)(path2, "utf8");
|
|
27797
27838
|
} catch {
|
|
27798
27839
|
return null;
|
|
27799
27840
|
}
|
|
@@ -27820,12 +27861,12 @@ function classify(changed, policy, present = () => false) {
|
|
|
27820
27861
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
27821
27862
|
return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
|
|
27822
27863
|
}
|
|
27823
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
27824
|
-
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0,
|
|
27864
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
27865
|
+
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path29.join)(root, p)));
|
|
27825
27866
|
}
|
|
27826
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
27867
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
27827
27868
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
27828
|
-
return [...new Set(declared)].filter((p) => !exists((0,
|
|
27869
|
+
return [...new Set(declared)].filter((p) => !exists((0, import_node_path29.join)(root, p)));
|
|
27829
27870
|
}
|
|
27830
27871
|
function evaluate(changed, policy, present = () => false) {
|
|
27831
27872
|
const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
|
|
@@ -28007,13 +28048,13 @@ function changedFilesSince(base, cwd) {
|
|
|
28007
28048
|
}
|
|
28008
28049
|
function runTestPolicy(root, deps = {}) {
|
|
28009
28050
|
const policy = deps.policy ?? loadPolicy(root);
|
|
28010
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
28051
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs32.existsSync)(path2));
|
|
28011
28052
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
28012
28053
|
const base = deps.changed ? "(injected)" : resolveBase(root, deps.base);
|
|
28013
28054
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
28014
28055
|
const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
|
|
28015
28056
|
const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
|
|
28016
|
-
const present = (path2) => exists((0,
|
|
28057
|
+
const present = (path2) => exists((0, import_node_path29.join)(root, path2));
|
|
28017
28058
|
const removedByThisDiff = removedPaths(changed);
|
|
28018
28059
|
const staleFindings = [];
|
|
28019
28060
|
const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
|
|
@@ -28051,8 +28092,8 @@ function runTestPolicy(root, deps = {}) {
|
|
|
28051
28092
|
}
|
|
28052
28093
|
|
|
28053
28094
|
// src/project-info-sync.ts
|
|
28054
|
-
var
|
|
28055
|
-
var
|
|
28095
|
+
var import_node_fs33 = require("node:fs");
|
|
28096
|
+
var import_node_path30 = require("node:path");
|
|
28056
28097
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
28057
28098
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
28058
28099
|
projectV2 { id }
|
|
@@ -28097,14 +28138,14 @@ function sharedName(entries, fallback) {
|
|
|
28097
28138
|
}
|
|
28098
28139
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
28099
28140
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
28100
|
-
const readmePath = (0,
|
|
28101
|
-
if (!(0,
|
|
28141
|
+
const readmePath = (0, import_node_path30.join)(repoRoot2, "README.md");
|
|
28142
|
+
if (!(0, import_node_fs33.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
28102
28143
|
const entries = entriesFor(project2, projects);
|
|
28103
28144
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
28104
28145
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
28105
28146
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
28106
28147
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
28107
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
28148
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs33.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
28108
28149
|
const lines = [
|
|
28109
28150
|
`# ${projectName}`,
|
|
28110
28151
|
"",
|
|
@@ -28123,8 +28164,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
28123
28164
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
28124
28165
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
28125
28166
|
const orgDocs = [
|
|
28126
|
-
(0,
|
|
28127
|
-
(0,
|
|
28167
|
+
(0, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
|
|
28168
|
+
(0, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
|
|
28128
28169
|
].filter(Boolean);
|
|
28129
28170
|
if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
|
|
28130
28171
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
|
|
@@ -28909,8 +28950,8 @@ function writeError(res) {
|
|
|
28909
28950
|
}
|
|
28910
28951
|
|
|
28911
28952
|
// src/secrets-commands.ts
|
|
28912
|
-
var
|
|
28913
|
-
var
|
|
28953
|
+
var import_node_fs34 = require("node:fs");
|
|
28954
|
+
var import_node_path31 = require("node:path");
|
|
28914
28955
|
var import_node_os13 = require("node:os");
|
|
28915
28956
|
|
|
28916
28957
|
// src/secrets-diff.ts
|
|
@@ -29013,18 +29054,18 @@ function collectMap(value, previous = []) {
|
|
|
29013
29054
|
return [...previous, value];
|
|
29014
29055
|
}
|
|
29015
29056
|
async function decryptRailsCredentials(input) {
|
|
29016
|
-
const appDir = (0,
|
|
29057
|
+
const appDir = (0, import_node_path31.resolve)(input.appDir ?? process.cwd());
|
|
29017
29058
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
29018
29059
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
29019
|
-
const credentialsPath = (0,
|
|
29020
|
-
const masterKeyPath = (0,
|
|
29060
|
+
const credentialsPath = (0, import_node_path31.resolve)(appDir, credentialsFile);
|
|
29061
|
+
const masterKeyPath = (0, import_node_path31.resolve)(appDir, masterKeyFile);
|
|
29021
29062
|
const env = {
|
|
29022
29063
|
...process.env,
|
|
29023
29064
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
29024
29065
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
29025
29066
|
};
|
|
29026
|
-
if ((0,
|
|
29027
|
-
env.RAILS_MASTER_KEY = (0,
|
|
29067
|
+
if ((0, import_node_fs34.existsSync)(masterKeyPath)) {
|
|
29068
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs34.readFileSync)(masterKeyPath, "utf8").trim();
|
|
29028
29069
|
}
|
|
29029
29070
|
const script = [
|
|
29030
29071
|
'require "json"',
|
|
@@ -29034,9 +29075,9 @@ async function decryptRailsCredentials(input) {
|
|
|
29034
29075
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
29035
29076
|
"puts JSON.generate(config.config)"
|
|
29036
29077
|
].join("\n");
|
|
29037
|
-
const scriptDir = (0,
|
|
29038
|
-
const scriptPath = (0,
|
|
29039
|
-
(0,
|
|
29078
|
+
const scriptDir = (0, import_node_fs34.mkdtempSync)((0, import_node_path31.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
|
|
29079
|
+
const scriptPath = (0, import_node_path31.join)(scriptDir, "decrypt.rb");
|
|
29080
|
+
(0, import_node_fs34.writeFileSync)(scriptPath, script, "utf8");
|
|
29040
29081
|
try {
|
|
29041
29082
|
const args = ["exec", "ruby", scriptPath];
|
|
29042
29083
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -29048,7 +29089,7 @@ async function decryptRailsCredentials(input) {
|
|
|
29048
29089
|
});
|
|
29049
29090
|
return JSON.parse(stdout);
|
|
29050
29091
|
} finally {
|
|
29051
|
-
(0,
|
|
29092
|
+
(0, import_node_fs34.rmSync)(scriptDir, { recursive: true, force: true });
|
|
29052
29093
|
}
|
|
29053
29094
|
}
|
|
29054
29095
|
async function readSecretStdin() {
|
|
@@ -29138,7 +29179,7 @@ function registerSecretsCommands(program3) {
|
|
|
29138
29179
|
let body;
|
|
29139
29180
|
if (o.file) {
|
|
29140
29181
|
try {
|
|
29141
|
-
body = (0,
|
|
29182
|
+
body = (0, import_node_fs34.readFileSync)((0, import_node_path31.resolve)(o.file), "utf8");
|
|
29142
29183
|
} catch (e) {
|
|
29143
29184
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
29144
29185
|
}
|
|
@@ -29243,7 +29284,7 @@ function registerSecretsCommands(program3) {
|
|
|
29243
29284
|
{
|
|
29244
29285
|
...d,
|
|
29245
29286
|
decryptRailsCredentials,
|
|
29246
|
-
removeFile: (path2) => (0,
|
|
29287
|
+
removeFile: (path2) => (0, import_node_fs34.unlinkSync)((0, import_node_path31.resolve)(o.appDir ?? process.cwd(), path2))
|
|
29247
29288
|
},
|
|
29248
29289
|
{
|
|
29249
29290
|
repo: o.repo,
|
|
@@ -29448,7 +29489,7 @@ function emitCliCallTelemetry(command) {
|
|
|
29448
29489
|
}
|
|
29449
29490
|
|
|
29450
29491
|
// src/box-commands.ts
|
|
29451
|
-
var
|
|
29492
|
+
var import_node_fs35 = require("node:fs");
|
|
29452
29493
|
|
|
29453
29494
|
// src/box.ts
|
|
29454
29495
|
var BOX_KEYS = {
|
|
@@ -29651,7 +29692,7 @@ function registerBoxCommands(program3) {
|
|
|
29651
29692
|
}
|
|
29652
29693
|
if (o.json) console.log(JSON.stringify({ box: found, incomplete }, null, 2));
|
|
29653
29694
|
else if (o.ssh && o.script) {
|
|
29654
|
-
(0,
|
|
29695
|
+
(0, import_node_fs35.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
|
|
29655
29696
|
console.log(`wrote ${o.script} \u2014 run: bash "${o.script}"`);
|
|
29656
29697
|
} else if (o.ssh) console.log(`${formatSshRecipe(found)}
|
|
29657
29698
|
${SSH_RECIPE_AGENT_NOTE}`);
|
|
@@ -29970,7 +30011,7 @@ function registerSchedulesCommands(program3) {
|
|
|
29970
30011
|
|
|
29971
30012
|
// src/schedules-lift-command.ts
|
|
29972
30013
|
var import_promises6 = require("node:fs/promises");
|
|
29973
|
-
var
|
|
30014
|
+
var import_node_path32 = require("node:path");
|
|
29974
30015
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
29975
30016
|
var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
|
|
29976
30017
|
var SchedulesLiftUsageError = class extends Error {
|
|
@@ -29997,7 +30038,7 @@ async function readWorkflowFiles(dir) {
|
|
|
29997
30038
|
const files = [];
|
|
29998
30039
|
for (const name of names.sort()) {
|
|
29999
30040
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
30000
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0,
|
|
30041
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0, import_node_path32.join)(dir, name), "utf8") });
|
|
30001
30042
|
}
|
|
30002
30043
|
return files;
|
|
30003
30044
|
}
|
|
@@ -30145,9 +30186,9 @@ function registerEdgeCommands(program3) {
|
|
|
30145
30186
|
}
|
|
30146
30187
|
|
|
30147
30188
|
// src/bootstrap-commands.ts
|
|
30148
|
-
var
|
|
30189
|
+
var import_node_fs36 = require("node:fs");
|
|
30149
30190
|
var import_node_os14 = require("node:os");
|
|
30150
|
-
var
|
|
30191
|
+
var import_node_path33 = require("node:path");
|
|
30151
30192
|
|
|
30152
30193
|
// src/bootstrap-drift.ts
|
|
30153
30194
|
var import_node_crypto6 = require("node:crypto");
|
|
@@ -31027,13 +31068,13 @@ function registerBootstrapCommands(program3) {
|
|
|
31027
31068
|
client: defaultGitHubClient(),
|
|
31028
31069
|
projectMeta: meta,
|
|
31029
31070
|
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
31030
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
31071
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs36.existsSync)(path2) ? (0, import_node_fs36.readFileSync)(path2, "utf8") : null,
|
|
31031
31072
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
31032
31073
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
31033
31074
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
31034
31075
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
31035
31076
|
// sanction, which is the pre-#3664 behaviour.
|
|
31036
|
-
sanctionedAdmins: (0,
|
|
31077
|
+
sanctionedAdmins: (0, import_node_fs36.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs36.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
31037
31078
|
requiredGcpApis: (() => {
|
|
31038
31079
|
const v = meta?.requiredGcpApis;
|
|
31039
31080
|
if (Array.isArray(v)) return v;
|
|
@@ -31086,14 +31127,14 @@ function registerBootstrapCommands(program3) {
|
|
|
31086
31127
|
bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
|
|
31087
31128
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
31088
31129
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31089
|
-
if (!(0,
|
|
31130
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
|
|
31090
31131
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31091
31132
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
31092
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31133
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31093
31134
|
const hubContents = /* @__PURE__ */ new Map();
|
|
31094
31135
|
for (const s of manifest.seeds) {
|
|
31095
31136
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
31096
|
-
hubContents.set(s.target, (0,
|
|
31137
|
+
hubContents.set(s.target, (0, import_node_fs36.existsSync)(s.target) ? (0, import_node_fs36.readFileSync)(s.target, "utf8") : null);
|
|
31097
31138
|
}
|
|
31098
31139
|
let targets;
|
|
31099
31140
|
let classOf = (_repo) => "deployable";
|
|
@@ -31172,10 +31213,10 @@ function registerBootstrapCommands(program3) {
|
|
|
31172
31213
|
return fail(`bootstrap apply: ${e.message}`);
|
|
31173
31214
|
}
|
|
31174
31215
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31175
|
-
if (!(0,
|
|
31216
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
|
|
31176
31217
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31177
31218
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
31178
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31219
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31179
31220
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
31180
31221
|
const slug = parsedRepo.slug;
|
|
31181
31222
|
const onlyTarget = o.only.trim();
|
|
@@ -31186,16 +31227,16 @@ function registerBootstrapCommands(program3) {
|
|
|
31186
31227
|
${known}`);
|
|
31187
31228
|
}
|
|
31188
31229
|
const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
|
|
31189
|
-
const readFile9 = (p) => (0,
|
|
31230
|
+
const readFile9 = (p) => (0, import_node_fs36.existsSync)(p) ? (0, import_node_fs36.readFileSync)(p, "utf8") : null;
|
|
31190
31231
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31191
31232
|
const putSeed = async (target, content, ref, sha) => {
|
|
31192
|
-
const tmp = (0,
|
|
31193
|
-
(0,
|
|
31233
|
+
const tmp = (0, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31234
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
31194
31235
|
try {
|
|
31195
31236
|
await gh(contentPutInputArgs(repo, target, tmp));
|
|
31196
31237
|
} finally {
|
|
31197
31238
|
try {
|
|
31198
|
-
(0,
|
|
31239
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31199
31240
|
} catch {
|
|
31200
31241
|
}
|
|
31201
31242
|
}
|
|
@@ -31460,10 +31501,10 @@ LIVE apply to ${repo}:
|
|
|
31460
31501
|
bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an ownership:org + source:self seed, e.g. .github/workflows/agent-pr.yml)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
|
|
31461
31502
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
31462
31503
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31463
|
-
if (!(0,
|
|
31504
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
|
|
31464
31505
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31465
31506
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
31466
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31507
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31467
31508
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31468
31509
|
if (!o.target) {
|
|
31469
31510
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -31472,8 +31513,8 @@ LIVE apply to ${repo}:
|
|
|
31472
31513
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
31473
31514
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no ownership:org + source:self seed in ${manifestPath}. Propagatable targets:
|
|
31474
31515
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
31475
|
-
if (!(0,
|
|
31476
|
-
const hubContent = (0,
|
|
31516
|
+
if (!(0, import_node_fs36.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
|
|
31517
|
+
const hubContent = (0, import_node_fs36.readFileSync)(seed.target, "utf8");
|
|
31477
31518
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
31478
31519
|
const cfg = await loadConfig();
|
|
31479
31520
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -31482,9 +31523,9 @@ LIVE apply to ${repo}:
|
|
|
31482
31523
|
}
|
|
31483
31524
|
const rosterRepos2 = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
31484
31525
|
let independentCount = rosterRepos2.length;
|
|
31485
|
-
if ((0,
|
|
31526
|
+
if ((0, import_node_fs36.existsSync)("projects.json")) {
|
|
31486
31527
|
try {
|
|
31487
|
-
const local = JSON.parse((0,
|
|
31528
|
+
const local = JSON.parse((0, import_node_fs36.readFileSync)("projects.json", "utf8"));
|
|
31488
31529
|
const localRepos = /* @__PURE__ */ new Set();
|
|
31489
31530
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
31490
31531
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -31600,13 +31641,13 @@ LIVE apply to ${repo}:
|
|
|
31600
31641
|
} catch {
|
|
31601
31642
|
existingSha = void 0;
|
|
31602
31643
|
}
|
|
31603
|
-
const tmp = (0,
|
|
31604
|
-
(0,
|
|
31644
|
+
const tmp = (0, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31645
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
|
|
31605
31646
|
try {
|
|
31606
31647
|
await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
31607
31648
|
} finally {
|
|
31608
31649
|
try {
|
|
31609
|
-
(0,
|
|
31650
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31610
31651
|
} catch {
|
|
31611
31652
|
}
|
|
31612
31653
|
}
|
|
@@ -31664,10 +31705,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31664
31705
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
31665
31706
|
}
|
|
31666
31707
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31667
|
-
if (!(0,
|
|
31708
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
|
|
31668
31709
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31669
31710
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
31670
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31711
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31671
31712
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31672
31713
|
if (!o.target) {
|
|
31673
31714
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -31684,10 +31725,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31684
31725
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31685
31726
|
let candidates;
|
|
31686
31727
|
if (o.record) {
|
|
31687
|
-
if (!(0,
|
|
31728
|
+
if (!(0, import_node_fs36.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
31688
31729
|
let parsed;
|
|
31689
31730
|
try {
|
|
31690
|
-
parsed = JSON.parse((0,
|
|
31731
|
+
parsed = JSON.parse((0, import_node_fs36.readFileSync)(o.record, "utf8"));
|
|
31691
31732
|
} catch (e) {
|
|
31692
31733
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
31693
31734
|
}
|
|
@@ -31756,13 +31797,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31756
31797
|
} catch {
|
|
31757
31798
|
existingSha = void 0;
|
|
31758
31799
|
}
|
|
31759
|
-
const tmp = (0,
|
|
31760
|
-
(0,
|
|
31800
|
+
const tmp = (0, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31801
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
31761
31802
|
try {
|
|
31762
31803
|
await gh(contentPutInputArgs(repo, seed.target, tmp));
|
|
31763
31804
|
} finally {
|
|
31764
31805
|
try {
|
|
31765
|
-
(0,
|
|
31806
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31766
31807
|
} catch {
|
|
31767
31808
|
}
|
|
31768
31809
|
}
|
|
@@ -31784,12 +31825,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31784
31825
|
}
|
|
31785
31826
|
|
|
31786
31827
|
// src/stage-commands.ts
|
|
31787
|
-
var
|
|
31788
|
-
var
|
|
31828
|
+
var import_node_fs38 = require("node:fs");
|
|
31829
|
+
var import_node_path35 = require("node:path");
|
|
31789
31830
|
|
|
31790
31831
|
// src/port-registry.ts
|
|
31791
|
-
var
|
|
31792
|
-
var
|
|
31832
|
+
var import_node_fs37 = require("node:fs");
|
|
31833
|
+
var import_node_path34 = require("node:path");
|
|
31793
31834
|
|
|
31794
31835
|
// ../infra/port-geometry.mjs
|
|
31795
31836
|
var PORT_BLOCK = 100;
|
|
@@ -31803,8 +31844,8 @@ function nextPortBlock(registry2) {
|
|
|
31803
31844
|
return [base, base + PORT_SPAN];
|
|
31804
31845
|
}
|
|
31805
31846
|
function loadPortRegistry(path2) {
|
|
31806
|
-
if (!(0,
|
|
31807
|
-
const raw = JSON.parse((0,
|
|
31847
|
+
if (!(0, import_node_fs37.existsSync)(path2)) return {};
|
|
31848
|
+
const raw = JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8"));
|
|
31808
31849
|
const out = {};
|
|
31809
31850
|
for (const [key, value] of Object.entries(raw)) {
|
|
31810
31851
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -31818,9 +31859,9 @@ function ensurePortRange(repo, path2) {
|
|
|
31818
31859
|
const existing = registry2[repo];
|
|
31819
31860
|
if (existing) return existing;
|
|
31820
31861
|
const range = nextPortBlock(registry2);
|
|
31821
|
-
const raw = (0,
|
|
31862
|
+
const raw = (0, import_node_fs37.existsSync)(path2) ? JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8")) : {};
|
|
31822
31863
|
raw[repo] = range;
|
|
31823
|
-
(0,
|
|
31864
|
+
(0, import_node_fs37.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
|
|
31824
31865
|
return range;
|
|
31825
31866
|
}
|
|
31826
31867
|
function portCursorSeed(registry2) {
|
|
@@ -31842,22 +31883,22 @@ function existingPortRange(repo, registry2) {
|
|
|
31842
31883
|
return registry2[repo] ?? null;
|
|
31843
31884
|
}
|
|
31844
31885
|
function portRangeInfraAt(root, source) {
|
|
31845
|
-
const registryPath = (0,
|
|
31846
|
-
const ddbScriptPath = (0,
|
|
31847
|
-
if (!(0,
|
|
31886
|
+
const registryPath = (0, import_node_path34.join)(root, "infra", "port-ranges.json");
|
|
31887
|
+
const ddbScriptPath = (0, import_node_path34.join)(root, "infra", "port-ddb.mjs");
|
|
31888
|
+
if (!(0, import_node_fs37.existsSync)(registryPath) || !(0, import_node_fs37.existsSync)(ddbScriptPath)) return null;
|
|
31848
31889
|
return { root, source, registryPath, ddbScriptPath };
|
|
31849
31890
|
}
|
|
31850
31891
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
31851
31892
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
31852
31893
|
if (direct) return direct;
|
|
31853
|
-
for (let dir = cwd; ; dir = (0,
|
|
31854
|
-
const sibling = portRangeInfraAt((0,
|
|
31894
|
+
for (let dir = cwd; ; dir = (0, import_node_path34.dirname)(dir)) {
|
|
31895
|
+
const sibling = portRangeInfraAt((0, import_node_path34.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
31855
31896
|
if (sibling) return sibling;
|
|
31856
|
-
const parent = (0,
|
|
31897
|
+
const parent = (0, import_node_path34.dirname)(dir);
|
|
31857
31898
|
if (parent === dir) break;
|
|
31858
31899
|
}
|
|
31859
31900
|
if (packageDir) {
|
|
31860
|
-
const pkgRoot = (0,
|
|
31901
|
+
const pkgRoot = (0, import_node_path34.join)(packageDir, "..", "..");
|
|
31861
31902
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
31862
31903
|
if (pkgFrom) return pkgFrom;
|
|
31863
31904
|
}
|
|
@@ -32051,8 +32092,8 @@ function registerStageCommands(program3) {
|
|
|
32051
32092
|
const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
|
|
32052
32093
|
return decideStage({
|
|
32053
32094
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
32054
|
-
hasCompose: (0,
|
|
32055
|
-
hasEnvExample: (0,
|
|
32095
|
+
hasCompose: (0, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), "docker-compose.yml")),
|
|
32096
|
+
hasEnvExample: (0, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), ".env.example"))
|
|
32056
32097
|
});
|
|
32057
32098
|
}
|
|
32058
32099
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -32543,9 +32584,9 @@ function registerBoardCommands(program3) {
|
|
|
32543
32584
|
}
|
|
32544
32585
|
|
|
32545
32586
|
// src/merge-cleanup.ts
|
|
32546
|
-
var
|
|
32587
|
+
var import_node_fs39 = require("node:fs");
|
|
32547
32588
|
var import_promises8 = require("node:fs/promises");
|
|
32548
|
-
var
|
|
32589
|
+
var import_node_path37 = require("node:path");
|
|
32549
32590
|
var import_node_os15 = require("node:os");
|
|
32550
32591
|
var import_node_child_process18 = require("node:child_process");
|
|
32551
32592
|
|
|
@@ -32633,7 +32674,7 @@ function boardAdvanceFailureMessage(result) {
|
|
|
32633
32674
|
|
|
32634
32675
|
// src/deferred-registry-store.ts
|
|
32635
32676
|
var import_promises7 = require("node:fs/promises");
|
|
32636
|
-
var
|
|
32677
|
+
var import_node_path36 = require("node:path");
|
|
32637
32678
|
var sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
32638
32679
|
async function atomicWrite(target, contents) {
|
|
32639
32680
|
const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
@@ -32684,12 +32725,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
32684
32725
|
},
|
|
32685
32726
|
// Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
|
|
32686
32727
|
write: async (entries) => {
|
|
32687
|
-
await (0, import_promises7.mkdir)((0,
|
|
32728
|
+
await (0, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
|
|
32688
32729
|
await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
|
|
32689
32730
|
},
|
|
32690
32731
|
// Serialized read-modify-write under the repo-wide lock (#2846).
|
|
32691
32732
|
update: async (mutate) => {
|
|
32692
|
-
await (0, import_promises7.mkdir)((0,
|
|
32733
|
+
await (0, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
|
|
32693
32734
|
const deadline = Date.now() + opts.maxWaitMs;
|
|
32694
32735
|
for (; ; ) {
|
|
32695
32736
|
const guard = await acquireLock(lockPath, opts, deadline);
|
|
@@ -32860,7 +32901,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32860
32901
|
);
|
|
32861
32902
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
32862
32903
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
32863
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
32904
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path37.dirname)((0, import_node_path37.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
32864
32905
|
const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
|
|
32865
32906
|
const owners = readWorktreeOwners(primaryRepoRoot);
|
|
32866
32907
|
const removalNow = Date.now();
|
|
@@ -32917,7 +32958,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32917
32958
|
const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
|
|
32918
32959
|
beforeWorktrees,
|
|
32919
32960
|
startingPath: branch.worktreePath,
|
|
32920
|
-
pathExists: (p) => (0,
|
|
32961
|
+
pathExists: (p) => (0, import_node_fs39.existsSync)(p),
|
|
32921
32962
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
32922
32963
|
teardownWorktreeStage,
|
|
32923
32964
|
deferredStore,
|
|
@@ -32955,7 +32996,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32955
32996
|
let removalAttempted = false;
|
|
32956
32997
|
try {
|
|
32957
32998
|
const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, cleanupRoots, {
|
|
32958
|
-
realpath: (path2) => (0,
|
|
32999
|
+
realpath: (path2) => (0, import_node_fs39.realpathSync)(path2)
|
|
32959
33000
|
});
|
|
32960
33001
|
if (!cleanupTarget.ok) {
|
|
32961
33002
|
result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
|
|
@@ -33042,13 +33083,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
|
|
|
33042
33083
|
const commits = JSON.parse(raw).commits ?? [];
|
|
33043
33084
|
const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
|
|
33044
33085
|
if (!body) return void 0;
|
|
33045
|
-
const dir = (0,
|
|
33046
|
-
const path2 = (0,
|
|
33047
|
-
(0,
|
|
33086
|
+
const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
|
|
33087
|
+
const path2 = (0, import_node_path37.join)(dir, "body.txt");
|
|
33088
|
+
(0, import_node_fs39.writeFileSync)(path2, `${body}
|
|
33048
33089
|
`, "utf8");
|
|
33049
33090
|
return { path: path2, cleanup: () => {
|
|
33050
33091
|
try {
|
|
33051
|
-
(0,
|
|
33092
|
+
(0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
|
|
33052
33093
|
} catch {
|
|
33053
33094
|
}
|
|
33054
33095
|
} };
|
|
@@ -33170,13 +33211,13 @@ var realWorktreeDirRemover = {
|
|
|
33170
33211
|
probe: (p) => {
|
|
33171
33212
|
let st;
|
|
33172
33213
|
try {
|
|
33173
|
-
st = (0,
|
|
33214
|
+
st = (0, import_node_fs39.lstatSync)(p);
|
|
33174
33215
|
} catch {
|
|
33175
33216
|
return null;
|
|
33176
33217
|
}
|
|
33177
33218
|
if (st.isSymbolicLink()) return "link";
|
|
33178
33219
|
try {
|
|
33179
|
-
(0,
|
|
33220
|
+
(0, import_node_fs39.readlinkSync)(p);
|
|
33180
33221
|
return "link";
|
|
33181
33222
|
} catch {
|
|
33182
33223
|
}
|
|
@@ -33184,7 +33225,7 @@ var realWorktreeDirRemover = {
|
|
|
33184
33225
|
},
|
|
33185
33226
|
readdir: (p) => {
|
|
33186
33227
|
try {
|
|
33187
|
-
return (0,
|
|
33228
|
+
return (0, import_node_fs39.readdirSync)(p);
|
|
33188
33229
|
} catch {
|
|
33189
33230
|
return [];
|
|
33190
33231
|
}
|
|
@@ -33193,9 +33234,9 @@ var realWorktreeDirRemover = {
|
|
|
33193
33234
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
33194
33235
|
detachLink: (p) => {
|
|
33195
33236
|
try {
|
|
33196
|
-
(0,
|
|
33237
|
+
(0, import_node_fs39.rmdirSync)(p);
|
|
33197
33238
|
} catch {
|
|
33198
|
-
(0,
|
|
33239
|
+
(0, import_node_fs39.unlinkSync)(p);
|
|
33199
33240
|
}
|
|
33200
33241
|
},
|
|
33201
33242
|
removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
@@ -33228,9 +33269,9 @@ async function worktreeHasStageState(worktreePath) {
|
|
|
33228
33269
|
}
|
|
33229
33270
|
}
|
|
33230
33271
|
function stageStateFileBelongsToWorktree(statePath, worktreePath) {
|
|
33231
|
-
if (!(0,
|
|
33272
|
+
if (!(0, import_node_fs39.existsSync)(statePath)) return false;
|
|
33232
33273
|
try {
|
|
33233
|
-
const state = JSON.parse((0,
|
|
33274
|
+
const state = JSON.parse((0, import_node_fs39.readFileSync)(statePath, "utf8"));
|
|
33234
33275
|
const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
|
|
33235
33276
|
return Boolean(recordedCwd && isPathUnderDirectory2(recordedCwd, worktreePath));
|
|
33236
33277
|
} catch {
|
|
@@ -33665,14 +33706,14 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
33665
33706
|
}
|
|
33666
33707
|
|
|
33667
33708
|
// src/worktree-lifecycle-commands.ts
|
|
33668
|
-
var
|
|
33709
|
+
var import_node_fs41 = require("node:fs");
|
|
33669
33710
|
var import_promises9 = require("node:fs/promises");
|
|
33670
|
-
var
|
|
33711
|
+
var import_node_path39 = require("node:path");
|
|
33671
33712
|
|
|
33672
33713
|
// src/worktree-install-cache.ts
|
|
33673
33714
|
var import_node_crypto7 = require("node:crypto");
|
|
33674
|
-
var
|
|
33675
|
-
var
|
|
33715
|
+
var import_node_fs40 = require("node:fs");
|
|
33716
|
+
var import_node_path38 = require("node:path");
|
|
33676
33717
|
var CACHE_DIR = "worktree-install-cache";
|
|
33677
33718
|
var MANIFEST = "manifest.json";
|
|
33678
33719
|
var NODE_MODULES2 = "node_modules";
|
|
@@ -33685,16 +33726,16 @@ var LOCKFILE_NAMES = [
|
|
|
33685
33726
|
"package-lock.json"
|
|
33686
33727
|
];
|
|
33687
33728
|
var realWorktreeInstallCacheFs = {
|
|
33688
|
-
exists:
|
|
33689
|
-
readFile: (path2) => (0,
|
|
33690
|
-
lstat: (path2) => (0,
|
|
33691
|
-
copyDir: (from, to) => (0,
|
|
33729
|
+
exists: import_node_fs40.existsSync,
|
|
33730
|
+
readFile: (path2) => (0, import_node_fs40.readFileSync)(path2, "utf8"),
|
|
33731
|
+
lstat: (path2) => (0, import_node_fs40.lstatSync)(path2),
|
|
33732
|
+
copyDir: (from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }),
|
|
33692
33733
|
mkdirp: (path2) => {
|
|
33693
|
-
(0,
|
|
33734
|
+
(0, import_node_fs40.mkdirSync)(path2, { recursive: true });
|
|
33694
33735
|
},
|
|
33695
|
-
writeFile: (path2, contents) => (0,
|
|
33736
|
+
writeFile: (path2, contents) => (0, import_node_fs40.writeFileSync)(path2, contents, "utf8"),
|
|
33696
33737
|
rm: (path2) => {
|
|
33697
|
-
(0,
|
|
33738
|
+
(0, import_node_fs40.rmSync)(path2, { recursive: true, force: true });
|
|
33698
33739
|
}
|
|
33699
33740
|
};
|
|
33700
33741
|
function hashLockfileBytes(contents) {
|
|
@@ -33702,7 +33743,7 @@ function hashLockfileBytes(contents) {
|
|
|
33702
33743
|
}
|
|
33703
33744
|
function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33704
33745
|
for (const name of LOCKFILE_NAMES) {
|
|
33705
|
-
const path2 = (0,
|
|
33746
|
+
const path2 = (0, import_node_path38.join)(packageDir, name);
|
|
33706
33747
|
if (!fs2.exists(path2)) continue;
|
|
33707
33748
|
try {
|
|
33708
33749
|
const hash = hashLockfileBytes(fs2.readFile(path2));
|
|
@@ -33717,8 +33758,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
|
|
|
33717
33758
|
const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
|
|
33718
33759
|
return {
|
|
33719
33760
|
root,
|
|
33720
|
-
manifestPath: (0,
|
|
33721
|
-
nodeModulesPath: (0,
|
|
33761
|
+
manifestPath: (0, import_node_path38.join)(root, MANIFEST),
|
|
33762
|
+
nodeModulesPath: (0, import_node_path38.join)(root, NODE_MODULES2)
|
|
33722
33763
|
};
|
|
33723
33764
|
}
|
|
33724
33765
|
function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
|
|
@@ -33758,7 +33799,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
|
|
|
33758
33799
|
}
|
|
33759
33800
|
}
|
|
33760
33801
|
function removeMaterializedTree(packageDir, fs2) {
|
|
33761
|
-
const dest = (0,
|
|
33802
|
+
const dest = (0, import_node_path38.join)(packageDir, NODE_MODULES2);
|
|
33762
33803
|
if (!fs2.exists(dest)) return;
|
|
33763
33804
|
fs2.rm(dest);
|
|
33764
33805
|
if (fs2.exists(dest)) {
|
|
@@ -33766,7 +33807,7 @@ function removeMaterializedTree(packageDir, fs2) {
|
|
|
33766
33807
|
}
|
|
33767
33808
|
}
|
|
33768
33809
|
function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33769
|
-
const dest = (0,
|
|
33810
|
+
const dest = (0, import_node_path38.join)(destPackageDir, NODE_MODULES2);
|
|
33770
33811
|
try {
|
|
33771
33812
|
if (fs2.exists(dest)) fs2.rm(dest);
|
|
33772
33813
|
fs2.mkdirp(destPackageDir);
|
|
@@ -33781,7 +33822,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
|
|
|
33781
33822
|
}
|
|
33782
33823
|
}
|
|
33783
33824
|
async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile3, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
|
|
33784
|
-
const source = (0,
|
|
33825
|
+
const source = (0, import_node_path38.join)(sourcePackageDir, NODE_MODULES2);
|
|
33785
33826
|
if (!isMaterializableNodeModulesDir(source, fs2)) return;
|
|
33786
33827
|
const entry = worktreeInstallCacheEntry(primaryRoot, lockfile3.hash);
|
|
33787
33828
|
const manifest = {
|
|
@@ -34041,7 +34082,7 @@ function classifyStaleLeaks(input) {
|
|
|
34041
34082
|
var defaultOrphanDirScanDeps = {
|
|
34042
34083
|
listDirs: (root) => {
|
|
34043
34084
|
try {
|
|
34044
|
-
return (0,
|
|
34085
|
+
return (0, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path39.join)(root, e.name));
|
|
34045
34086
|
} catch {
|
|
34046
34087
|
return [];
|
|
34047
34088
|
}
|
|
@@ -34207,13 +34248,13 @@ function registerWorktreeCommands(program3) {
|
|
|
34207
34248
|
const detached = headBorn && !symbolicBranch;
|
|
34208
34249
|
const branch = symbolicBranch || (detached ? "HEAD" : "");
|
|
34209
34250
|
if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
|
|
34210
|
-
const gitFile = (0,
|
|
34211
|
-
const isLinked = (0,
|
|
34251
|
+
const gitFile = (0, import_node_path39.join)(wtPath, ".git");
|
|
34252
|
+
const isLinked = (0, import_node_fs41.existsSync)(gitFile) && (0, import_node_fs41.statSync)(gitFile).isFile();
|
|
34212
34253
|
if (apply && !isLinked) {
|
|
34213
34254
|
return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
|
|
34214
34255
|
}
|
|
34215
34256
|
const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
34216
|
-
const primaryCheckout = commonDir ? (0,
|
|
34257
|
+
const primaryCheckout = commonDir ? (0, import_node_path39.dirname)(commonDir) : wtPath;
|
|
34217
34258
|
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);
|
|
34218
34259
|
const orphan = classifyOrphanedWorktree({
|
|
34219
34260
|
branch,
|
|
@@ -34487,10 +34528,10 @@ async function gatherWorktreeContext() {
|
|
|
34487
34528
|
if (s) stages.push({ path: wt.path, port: s.port });
|
|
34488
34529
|
}
|
|
34489
34530
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
34490
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
34531
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
34491
34532
|
const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
|
|
34492
34533
|
let orphanDirs = [];
|
|
34493
|
-
if ((0,
|
|
34534
|
+
if ((0, import_node_fs41.existsSync)(wtRoot)) {
|
|
34494
34535
|
orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
|
|
34495
34536
|
...defaultOrphanDirScanDeps,
|
|
34496
34537
|
listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
|
|
@@ -34526,7 +34567,7 @@ ${err.stderr ?? ""}`;
|
|
|
34526
34567
|
}
|
|
34527
34568
|
|
|
34528
34569
|
// src/issue-commands.ts
|
|
34529
|
-
var
|
|
34570
|
+
var import_node_fs42 = require("node:fs");
|
|
34530
34571
|
var import_node_crypto8 = require("node:crypto");
|
|
34531
34572
|
var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
|
|
34532
34573
|
var ReparentConflictError = class extends Error {
|
|
@@ -34544,7 +34585,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
34544
34585
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
34545
34586
|
const patch = {};
|
|
34546
34587
|
let bodyChanged = false;
|
|
34547
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
34588
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs42.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
34548
34589
|
if (options.titleFile !== void 0) {
|
|
34549
34590
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
34550
34591
|
} else if (options.title !== void 0) {
|
|
@@ -35149,7 +35190,7 @@ function extendCreateCommand(issue2, batchAttach) {
|
|
|
35149
35190
|
if (opts.batch) {
|
|
35150
35191
|
let specs;
|
|
35151
35192
|
try {
|
|
35152
|
-
const raw = (0,
|
|
35193
|
+
const raw = (0, import_node_fs42.readFileSync)(opts.batch, "utf8");
|
|
35153
35194
|
specs = JSON.parse(raw);
|
|
35154
35195
|
if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
|
|
35155
35196
|
} catch (e) {
|
|
@@ -35224,8 +35265,8 @@ ${lines}`, {
|
|
|
35224
35265
|
}
|
|
35225
35266
|
|
|
35226
35267
|
// src/train-commands.ts
|
|
35227
|
-
var
|
|
35228
|
-
var
|
|
35268
|
+
var import_node_fs43 = require("node:fs");
|
|
35269
|
+
var import_node_path40 = require("node:path");
|
|
35229
35270
|
var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
35230
35271
|
function resolveReleaseBumpIntent(raw) {
|
|
35231
35272
|
const intent = typeof raw === "string" ? raw.trim() : "";
|
|
@@ -35236,7 +35277,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
35236
35277
|
}
|
|
35237
35278
|
function readRepoVersion() {
|
|
35238
35279
|
try {
|
|
35239
|
-
return JSON.parse((0,
|
|
35280
|
+
return JSON.parse((0, import_node_fs43.readFileSync)((0, import_node_path40.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
35240
35281
|
} catch {
|
|
35241
35282
|
return void 0;
|
|
35242
35283
|
}
|
|
@@ -35393,9 +35434,9 @@ function registerDeployCommands(program3) {
|
|
|
35393
35434
|
}
|
|
35394
35435
|
|
|
35395
35436
|
// src/discovery-commands.ts
|
|
35396
|
-
var
|
|
35437
|
+
var import_node_fs44 = require("node:fs");
|
|
35397
35438
|
var import_node_os16 = require("node:os");
|
|
35398
|
-
var
|
|
35439
|
+
var import_node_path41 = require("node:path");
|
|
35399
35440
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
35400
35441
|
async function collectStatus() {
|
|
35401
35442
|
const repo = await resolveRepo();
|
|
@@ -35585,8 +35626,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
35585
35626
|
}
|
|
35586
35627
|
const home = (0, import_node_os16.homedir)();
|
|
35587
35628
|
const plugin = onboardPluginGate({
|
|
35588
|
-
readKnown: () => readFileSyncSafe((0,
|
|
35589
|
-
readSettings: () => readFileSyncSafe((0,
|
|
35629
|
+
readKnown: () => readFileSyncSafe((0, import_node_path41.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs44.readFileSync),
|
|
35630
|
+
readSettings: () => readFileSyncSafe((0, import_node_path41.join)(home, ".claude", "settings.json"), import_node_fs44.readFileSync)
|
|
35590
35631
|
});
|
|
35591
35632
|
return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
|
|
35592
35633
|
}
|
|
@@ -36685,19 +36726,19 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
36685
36726
|
}
|
|
36686
36727
|
|
|
36687
36728
|
// src/plugin-release-catchup.ts
|
|
36688
|
-
var
|
|
36689
|
-
var
|
|
36729
|
+
var import_node_fs45 = require("node:fs");
|
|
36730
|
+
var import_node_path42 = require("node:path");
|
|
36690
36731
|
var import_node_os17 = require("node:os");
|
|
36691
36732
|
var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
36692
36733
|
var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
|
|
36693
36734
|
function releaseCatchupStatePath(env = process.env) {
|
|
36694
36735
|
if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
|
|
36695
36736
|
if (process.platform === "win32") {
|
|
36696
|
-
const base2 = env.LOCALAPPDATA || (0,
|
|
36697
|
-
return (0,
|
|
36737
|
+
const base2 = env.LOCALAPPDATA || (0, import_node_path42.join)((0, import_node_os17.homedir)(), "AppData", "Local");
|
|
36738
|
+
return (0, import_node_path42.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
|
|
36698
36739
|
}
|
|
36699
|
-
const base = env.XDG_STATE_HOME || (0,
|
|
36700
|
-
return (0,
|
|
36740
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path42.join)((0, import_node_os17.homedir)(), ".local", "state");
|
|
36741
|
+
return (0, import_node_path42.join)(base, "mmi-cli", "release-catchup.json");
|
|
36701
36742
|
}
|
|
36702
36743
|
function releaseCatchupDue(state, now, force = false) {
|
|
36703
36744
|
if (force) return true;
|
|
@@ -36707,7 +36748,7 @@ function releaseCatchupDue(state, now, force = false) {
|
|
|
36707
36748
|
function newestCachedPluginVersion(home) {
|
|
36708
36749
|
let names;
|
|
36709
36750
|
try {
|
|
36710
|
-
names = (0,
|
|
36751
|
+
names = (0, import_node_fs45.readdirSync)(pluginCacheRoot(home));
|
|
36711
36752
|
} catch {
|
|
36712
36753
|
return void 0;
|
|
36713
36754
|
}
|
|
@@ -36715,15 +36756,15 @@ function newestCachedPluginVersion(home) {
|
|
|
36715
36756
|
}
|
|
36716
36757
|
function marketplaceClonePath(home) {
|
|
36717
36758
|
try {
|
|
36718
|
-
const parsed = JSON.parse((0,
|
|
36759
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
|
|
36719
36760
|
if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
|
|
36720
36761
|
} catch {
|
|
36721
36762
|
}
|
|
36722
|
-
return (0,
|
|
36763
|
+
return (0, import_node_path42.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
|
|
36723
36764
|
}
|
|
36724
36765
|
function readCatalogVersion(home) {
|
|
36725
36766
|
try {
|
|
36726
|
-
const parsed = JSON.parse((0,
|
|
36767
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
|
|
36727
36768
|
return parsed.plugins?.find((p) => p.name === "mmi")?.version;
|
|
36728
36769
|
} catch {
|
|
36729
36770
|
return void 0;
|
|
@@ -36731,7 +36772,7 @@ function readCatalogVersion(home) {
|
|
|
36731
36772
|
}
|
|
36732
36773
|
function readMmiInstallRecord(home) {
|
|
36733
36774
|
try {
|
|
36734
|
-
const parsed = JSON.parse((0,
|
|
36775
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
|
|
36735
36776
|
const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
|
|
36736
36777
|
return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
|
|
36737
36778
|
} catch {
|
|
@@ -36760,7 +36801,7 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36760
36801
|
cliUpdated = true;
|
|
36761
36802
|
}
|
|
36762
36803
|
const cliUpdateDetail = cliUpdated ? `CLI ${runningCli} \u2192 ${latest}; the next mmi-cli invocation runs ${latest}` : `CLI ${runningCli} is current against released ${latest}`;
|
|
36763
|
-
if (!(0,
|
|
36804
|
+
if (!(0, import_node_fs45.existsSync)(pluginCacheRoot(home))) {
|
|
36764
36805
|
deps.writeState(statePath, { checkedAt: deps.now(), latest });
|
|
36765
36806
|
return {
|
|
36766
36807
|
ok: true,
|
|
@@ -36793,8 +36834,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36793
36834
|
return { ok: false, detail: `${cliUpdateDetail}; plugin install record could not be cleared (still ${prior.version})` };
|
|
36794
36835
|
}
|
|
36795
36836
|
const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
|
|
36796
|
-
const payload = (0,
|
|
36797
|
-
if (!installed || !(0,
|
|
36837
|
+
const payload = (0, import_node_path42.join)(pluginCacheRoot(home), latest, ".pi-plugin");
|
|
36838
|
+
if (!installed || !(0, import_node_fs45.existsSync)(payload)) {
|
|
36798
36839
|
const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
|
|
36799
36840
|
if (!prior) return { ok: false, detail: `${cliUpdateDetail}; ${why}; no prior record to restore` };
|
|
36800
36841
|
const rollback = await restorePriorRecord(home, prior, deps);
|
|
@@ -38767,6 +38808,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38767
38808
|
});
|
|
38768
38809
|
return;
|
|
38769
38810
|
}
|
|
38811
|
+
const provenance = state.cachedAt === void 0 ? [] : [cachedSweepNote(state.cachedAt)];
|
|
38770
38812
|
if (state.driftLines.length === 0) {
|
|
38771
38813
|
emitNow({
|
|
38772
38814
|
ok: true,
|
|
@@ -38774,7 +38816,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38774
38816
|
id: "schedules-drift",
|
|
38775
38817
|
label: "schedules drift",
|
|
38776
38818
|
detail: "no drift",
|
|
38777
|
-
verbose: ["no drift lines"]
|
|
38819
|
+
verbose: ["no drift lines", ...provenance]
|
|
38778
38820
|
});
|
|
38779
38821
|
return;
|
|
38780
38822
|
}
|
|
@@ -38785,7 +38827,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38785
38827
|
label: "schedules drift",
|
|
38786
38828
|
detail: `${state.driftLines.length} drift line(s)`,
|
|
38787
38829
|
fix: "run `mmi-cli harbour org schedules` / `org schedules register`",
|
|
38788
|
-
verbose: state.driftLines
|
|
38830
|
+
verbose: [...state.driftLines, ...provenance]
|
|
38789
38831
|
});
|
|
38790
38832
|
} catch (e) {
|
|
38791
38833
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -39002,17 +39044,17 @@ function parseOriginRepo(remoteUrl) {
|
|
|
39002
39044
|
}
|
|
39003
39045
|
function ghHostsConfigPath(env, platform2) {
|
|
39004
39046
|
const sep3 = platform2 === "win32" ? "\\" : "/";
|
|
39005
|
-
const
|
|
39047
|
+
const join40 = (...parts) => parts.join(sep3);
|
|
39006
39048
|
const explicit = env.GH_CONFIG_DIR?.trim();
|
|
39007
|
-
if (explicit) return
|
|
39049
|
+
if (explicit) return join40(explicit, "hosts.yml");
|
|
39008
39050
|
if (platform2 === "win32") {
|
|
39009
39051
|
const appData = (env.AppData ?? env.APPDATA)?.trim();
|
|
39010
|
-
return appData ?
|
|
39052
|
+
return appData ? join40(appData, "GitHub CLI", "hosts.yml") : void 0;
|
|
39011
39053
|
}
|
|
39012
39054
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
39013
|
-
if (xdg) return
|
|
39055
|
+
if (xdg) return join40(xdg, "gh", "hosts.yml");
|
|
39014
39056
|
const home = env.HOME?.trim();
|
|
39015
|
-
return home ?
|
|
39057
|
+
return home ? join40(home, ".config", "gh", "hosts.yml") : void 0;
|
|
39016
39058
|
}
|
|
39017
39059
|
function parseGhHostsAccounts(yaml, host = "github.com") {
|
|
39018
39060
|
let hostIndent = null;
|
|
@@ -39062,9 +39104,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
39062
39104
|
}
|
|
39063
39105
|
|
|
39064
39106
|
// src/doctor-io.ts
|
|
39065
|
-
var
|
|
39107
|
+
var import_node_fs46 = require("node:fs");
|
|
39066
39108
|
var import_node_os18 = require("node:os");
|
|
39067
|
-
var
|
|
39109
|
+
var import_node_path43 = require("node:path");
|
|
39068
39110
|
var import_node_child_process19 = require("node:child_process");
|
|
39069
39111
|
var import_node_util8 = require("node:util");
|
|
39070
39112
|
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
|
|
@@ -39072,7 +39114,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
39072
39114
|
function installedClaudePluginVersion() {
|
|
39073
39115
|
try {
|
|
39074
39116
|
const file = JSON.parse(
|
|
39075
|
-
(0,
|
|
39117
|
+
(0, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
39076
39118
|
);
|
|
39077
39119
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
39078
39120
|
if (versions.length === 0) return void 0;
|
|
@@ -39083,7 +39125,7 @@ function installedClaudePluginVersion() {
|
|
|
39083
39125
|
}
|
|
39084
39126
|
function manifestVersion(path2) {
|
|
39085
39127
|
try {
|
|
39086
|
-
const manifest = JSON.parse((0,
|
|
39128
|
+
const manifest = JSON.parse((0, import_node_fs46.readFileSync)(path2, "utf8"));
|
|
39087
39129
|
return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
|
|
39088
39130
|
} catch {
|
|
39089
39131
|
return void 0;
|
|
@@ -39093,22 +39135,22 @@ function installedSurfacePluginVersion(surface) {
|
|
|
39093
39135
|
const token = surfaceToken(surface);
|
|
39094
39136
|
if (token === "kilo") {
|
|
39095
39137
|
try {
|
|
39096
|
-
const stamp = (0,
|
|
39138
|
+
const stamp = (0, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
|
|
39097
39139
|
return stamp || void 0;
|
|
39098
39140
|
} catch {
|
|
39099
39141
|
return void 0;
|
|
39100
39142
|
}
|
|
39101
39143
|
}
|
|
39102
39144
|
if (token === "cursor") {
|
|
39103
|
-
return manifestVersion((0,
|
|
39145
|
+
return manifestVersion((0, import_node_path43.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
39104
39146
|
}
|
|
39105
39147
|
if (token === "jervcode") {
|
|
39106
39148
|
const entry = mmiPiWrapperEntry();
|
|
39107
39149
|
if (!entry) return void 0;
|
|
39108
|
-
return manifestVersion((0,
|
|
39150
|
+
return manifestVersion((0, import_node_path43.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
|
|
39109
39151
|
}
|
|
39110
39152
|
if (token === "kimi") {
|
|
39111
|
-
return manifestVersion((0,
|
|
39153
|
+
return manifestVersion((0, import_node_path43.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
|
|
39112
39154
|
}
|
|
39113
39155
|
if (token === "claude") return installedClaudePluginVersion();
|
|
39114
39156
|
if (token !== "codex") return void 0;
|
|
@@ -39146,13 +39188,13 @@ function worktreeRootSync() {
|
|
|
39146
39188
|
}
|
|
39147
39189
|
var gitignorePath = () => {
|
|
39148
39190
|
const root = worktreeRootSync();
|
|
39149
|
-
return root === null ? null : (0,
|
|
39191
|
+
return root === null ? null : (0, import_node_path43.join)(root, ".gitignore");
|
|
39150
39192
|
};
|
|
39151
39193
|
function readGitignore() {
|
|
39152
39194
|
const path2 = gitignorePath();
|
|
39153
39195
|
if (path2 === null) return null;
|
|
39154
39196
|
try {
|
|
39155
|
-
return (0,
|
|
39197
|
+
return (0, import_node_fs46.readFileSync)(path2, "utf8");
|
|
39156
39198
|
} catch {
|
|
39157
39199
|
return null;
|
|
39158
39200
|
}
|
|
@@ -39161,7 +39203,7 @@ function writeGitignore(content) {
|
|
|
39161
39203
|
const path2 = gitignorePath();
|
|
39162
39204
|
if (path2 === null) return false;
|
|
39163
39205
|
try {
|
|
39164
|
-
(0,
|
|
39206
|
+
(0, import_node_fs46.writeFileSync)(path2, content, "utf8");
|
|
39165
39207
|
return true;
|
|
39166
39208
|
} catch {
|
|
39167
39209
|
return false;
|
|
@@ -39180,7 +39222,7 @@ async function repoRoot() {
|
|
|
39180
39222
|
}
|
|
39181
39223
|
function hasRepoLocalWorktrees() {
|
|
39182
39224
|
const root = worktreeRootSync();
|
|
39183
|
-
return root !== null && (0,
|
|
39225
|
+
return root !== null && (0, import_node_fs46.existsSync)((0, import_node_path43.join)(root, ".worktrees"));
|
|
39184
39226
|
}
|
|
39185
39227
|
|
|
39186
39228
|
// src/index.ts
|
|
@@ -39199,8 +39241,8 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
39199
39241
|
function ghMultiAccountCaveat(announcedLogin) {
|
|
39200
39242
|
try {
|
|
39201
39243
|
const hostsPath = ghHostsConfigPath(process.env, process.platform);
|
|
39202
|
-
if (!hostsPath || !(0,
|
|
39203
|
-
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0,
|
|
39244
|
+
if (!hostsPath || !(0, import_node_fs47.existsSync)(hostsPath)) return void 0;
|
|
39245
|
+
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs47.readFileSync)(hostsPath, "utf8")));
|
|
39204
39246
|
} catch {
|
|
39205
39247
|
return void 0;
|
|
39206
39248
|
}
|
|
@@ -39208,7 +39250,7 @@ function ghMultiAccountCaveat(announcedLogin) {
|
|
|
39208
39250
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
39209
39251
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
39210
39252
|
function envHealLockPath(home) {
|
|
39211
|
-
return (0,
|
|
39253
|
+
return (0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
39212
39254
|
}
|
|
39213
39255
|
async function withEnvHealLock(what, run) {
|
|
39214
39256
|
try {
|
|
@@ -39341,7 +39383,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39341
39383
|
);
|
|
39342
39384
|
const result = applyPluginCachePlan(
|
|
39343
39385
|
plan,
|
|
39344
|
-
(p) => (0,
|
|
39386
|
+
(p) => (0, import_node_fs47.rmSync)(p, { recursive: true }),
|
|
39345
39387
|
stagingApplyFsGuard(configRoot)
|
|
39346
39388
|
);
|
|
39347
39389
|
return {
|
|
@@ -39395,8 +39437,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39395
39437
|
const home = (0, import_node_os19.homedir)();
|
|
39396
39438
|
const rows = marketplaceRows(
|
|
39397
39439
|
MMI_MARKETPLACE_NAME,
|
|
39398
|
-
readFileSyncSafe((0,
|
|
39399
|
-
readFileSyncSafe((0,
|
|
39440
|
+
readFileSyncSafe((0, import_node_path44.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs47.readFileSync),
|
|
39441
|
+
readFileSyncSafe((0, import_node_path44.join)(home, ".claude", "settings.json"), import_node_fs47.readFileSync),
|
|
39400
39442
|
// #3974: this CLI heals these rows, so report mode names the doctor run rather than the hand
|
|
39401
39443
|
// edit. #4792 narrows WHICH run: `applyOrgMarketplacePins` declines outright while Claude Code
|
|
39402
39444
|
// is up, because the host owns this file and rewrites it from its own copy (#4083). Naming the
|
|
@@ -39408,7 +39450,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39408
39450
|
hostBlocked ?? claudeCodeEnvMarkerPresent() ? "host-running" : "doctor"
|
|
39409
39451
|
);
|
|
39410
39452
|
const pending = readMarketplacePinPending(
|
|
39411
|
-
(0,
|
|
39453
|
+
(0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
|
|
39412
39454
|
MMI_MARKETPLACE_NAME
|
|
39413
39455
|
);
|
|
39414
39456
|
if (!pending) return rows;
|
|
@@ -39434,9 +39476,9 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39434
39476
|
if (detectSurface(process.env) === "codex") return void 0;
|
|
39435
39477
|
const home = (0, import_node_os19.homedir)();
|
|
39436
39478
|
const names = [MMI_MARKETPLACE_NAME];
|
|
39437
|
-
const result = applyOrgMarketplacePins((0,
|
|
39479
|
+
const result = applyOrgMarketplacePins((0, import_node_path44.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
|
|
39438
39480
|
if (result?.wrote) {
|
|
39439
|
-
writeMarketplacePinPending((0,
|
|
39481
|
+
writeMarketplacePinPending((0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
|
|
39440
39482
|
}
|
|
39441
39483
|
return result;
|
|
39442
39484
|
} catch {
|
|
@@ -39452,7 +39494,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39452
39494
|
// adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
|
|
39453
39495
|
// get a permanent — demanding an artifact it never asked for.
|
|
39454
39496
|
docsIndexState: (root) => {
|
|
39455
|
-
if (!(0,
|
|
39497
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
39456
39498
|
const real = createDocsIndexDeps(root);
|
|
39457
39499
|
let docs2;
|
|
39458
39500
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39461,7 +39503,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39461
39503
|
},
|
|
39462
39504
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
39463
39505
|
healDocsIndex: (root) => {
|
|
39464
|
-
if (!(0,
|
|
39506
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
39465
39507
|
const real = createDocsIndexDeps(root);
|
|
39466
39508
|
let docs2;
|
|
39467
39509
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39489,6 +39531,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39489
39531
|
// #4170: light board doctor with 15s ceiling. skipClaimLiveness keeps Phase 3 off.
|
|
39490
39532
|
boardDoctorFix: async ({ fix } = {}) => {
|
|
39491
39533
|
const BOARD_DOCTOR_TIMEOUT_MS = 15e3;
|
|
39534
|
+
let ceiling;
|
|
39492
39535
|
try {
|
|
39493
39536
|
const cfg = await loadConfigForRepo();
|
|
39494
39537
|
const work = boardDoctor({
|
|
@@ -39499,7 +39542,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39499
39542
|
const raced = await Promise.race([
|
|
39500
39543
|
work.then((r) => ({ ...r, timedOut: false })),
|
|
39501
39544
|
new Promise((resolve5) => {
|
|
39502
|
-
setTimeout(() => resolve5({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39545
|
+
ceiling = setTimeout(() => resolve5({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39503
39546
|
})
|
|
39504
39547
|
]);
|
|
39505
39548
|
if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
|
|
@@ -39511,11 +39554,20 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39511
39554
|
};
|
|
39512
39555
|
} catch (e) {
|
|
39513
39556
|
return { scanned: 0, findings: 0, fixed: 0, failed: 0, readFailed: true, error: e instanceof Error ? e.message : String(e) };
|
|
39557
|
+
} finally {
|
|
39558
|
+
clearTimeout(ceiling);
|
|
39514
39559
|
}
|
|
39515
39560
|
},
|
|
39516
39561
|
// #4171: schedules drift notebook — report-only, ~20s ceiling.
|
|
39562
|
+
// #4815: and throttled. The sweep behind it reads every workflow file in every org repo — 12s of a
|
|
39563
|
+
// 22s doctor — so a cached notebook under six hours old answers the row instead, saying so in its
|
|
39564
|
+
// evidence. Only a COMPLETE sweep is cached (see schedules-drift-cache.ts).
|
|
39517
39565
|
schedulesDriftState: async () => {
|
|
39518
39566
|
const SCHEDULES_DRIFT_TIMEOUT_MS = 2e4;
|
|
39567
|
+
const cachePath = schedulesDriftCachePath(repoRuntimeStatePath(process.cwd()));
|
|
39568
|
+
const cached = readSchedulesDriftCache(cachePath);
|
|
39569
|
+
if (cached) return { driftLines: cached.driftLines, incomplete: [], cachedAt: cached.at };
|
|
39570
|
+
let ceiling;
|
|
39519
39571
|
try {
|
|
39520
39572
|
const raced = await Promise.race([
|
|
39521
39573
|
fetchNotebook().then((nb) => ({
|
|
@@ -39524,12 +39576,15 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39524
39576
|
timedOut: false
|
|
39525
39577
|
})),
|
|
39526
39578
|
new Promise((resolve5) => {
|
|
39527
|
-
setTimeout(() => resolve5({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39579
|
+
ceiling = setTimeout(() => resolve5({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39528
39580
|
})
|
|
39529
39581
|
]);
|
|
39582
|
+
if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
|
|
39530
39583
|
return raced;
|
|
39531
39584
|
} catch (e) {
|
|
39532
39585
|
return { driftLines: [], incomplete: [], readFailed: true, error: e instanceof Error ? e.message : String(e) };
|
|
39586
|
+
} finally {
|
|
39587
|
+
clearTimeout(ceiling);
|
|
39533
39588
|
}
|
|
39534
39589
|
},
|
|
39535
39590
|
// #4173: estate commands absent from the running Commander program (stale global CLI).
|
|
@@ -39811,19 +39866,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
39811
39866
|
});
|
|
39812
39867
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
39813
39868
|
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) => {
|
|
39814
|
-
const path2 = (0,
|
|
39815
|
-
const current = (0,
|
|
39869
|
+
const path2 = (0, import_node_path44.join)(process.cwd(), ".gitignore");
|
|
39870
|
+
const current = (0, import_node_fs47.existsSync)(path2) ? (0, import_node_fs47.readFileSync)(path2, "utf8") : null;
|
|
39816
39871
|
const plan = planManagedGitignore(current);
|
|
39817
39872
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
39818
39873
|
if (opts.json) {
|
|
39819
|
-
if (opts.write && plan.changed) (0,
|
|
39874
|
+
if (opts.write && plan.changed) (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
39820
39875
|
console.log(JSON.stringify(plan, null, 2));
|
|
39821
39876
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
39822
39877
|
return;
|
|
39823
39878
|
}
|
|
39824
39879
|
if (opts.write) {
|
|
39825
39880
|
if (plan.changed) {
|
|
39826
|
-
(0,
|
|
39881
|
+
(0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
39827
39882
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
39828
39883
|
} else {
|
|
39829
39884
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -39982,8 +40037,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
39982
40037
|
if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
|
|
39983
40038
|
let root;
|
|
39984
40039
|
if (o.root !== void 0) {
|
|
39985
|
-
root = (0,
|
|
39986
|
-
if (!(0,
|
|
40040
|
+
root = (0, import_node_path44.resolve)(o.root);
|
|
40041
|
+
if (!(0, import_node_fs47.existsSync)(root) || !(0, import_node_fs47.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
|
|
39987
40042
|
const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
39988
40043
|
if (isPathUnderDirectory2(gcRepoRoot, root)) {
|
|
39989
40044
|
return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
|
|
@@ -40080,7 +40135,7 @@ async function currentWorktreeRemovalContext(command, force) {
|
|
|
40080
40135
|
};
|
|
40081
40136
|
}
|
|
40082
40137
|
async function unprovenWorktreeReason(wtPath, repoRoot2) {
|
|
40083
|
-
if (!(0,
|
|
40138
|
+
if (!(0, import_node_fs47.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
|
|
40084
40139
|
const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
40085
40140
|
const registered = parseWorktreePorcelainEntries(porcelain);
|
|
40086
40141
|
if (!registered.length) {
|
|
@@ -40110,26 +40165,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
40110
40165
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
40111
40166
|
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
40112
40167
|
const take = () => {
|
|
40113
|
-
const fd = (0,
|
|
40168
|
+
const fd = (0, import_node_fs47.openSync)(lockPath, "wx");
|
|
40114
40169
|
try {
|
|
40115
|
-
(0,
|
|
40170
|
+
(0, import_node_fs47.writeSync)(fd, String(Date.now()));
|
|
40116
40171
|
} finally {
|
|
40117
|
-
(0,
|
|
40172
|
+
(0, import_node_fs47.closeSync)(fd);
|
|
40118
40173
|
}
|
|
40119
40174
|
return () => {
|
|
40120
40175
|
try {
|
|
40121
|
-
(0,
|
|
40176
|
+
(0, import_node_fs47.rmSync)(lockPath, { force: true });
|
|
40122
40177
|
} catch {
|
|
40123
40178
|
}
|
|
40124
40179
|
};
|
|
40125
40180
|
};
|
|
40126
40181
|
try {
|
|
40127
|
-
(0,
|
|
40182
|
+
(0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(lockPath), { recursive: true });
|
|
40128
40183
|
return take();
|
|
40129
40184
|
} catch {
|
|
40130
40185
|
try {
|
|
40131
|
-
if (Date.now() - (0,
|
|
40132
|
-
(0,
|
|
40186
|
+
if (Date.now() - (0, import_node_fs47.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
|
|
40187
|
+
(0, import_node_fs47.rmSync)(lockPath, { force: true });
|
|
40133
40188
|
return take();
|
|
40134
40189
|
}
|
|
40135
40190
|
} catch {
|
|
@@ -40993,7 +41048,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
40993
41048
|
if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
|
|
40994
41049
|
if (o.secretsFile) {
|
|
40995
41050
|
try {
|
|
40996
|
-
vars.push(`secrets=${(0,
|
|
41051
|
+
vars.push(`secrets=${(0, import_node_fs47.readFileSync)(o.secretsFile, "utf8")}`);
|
|
40997
41052
|
} catch (e) {
|
|
40998
41053
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
40999
41054
|
}
|
|
@@ -41761,11 +41816,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
41761
41816
|
}
|
|
41762
41817
|
});
|
|
41763
41818
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
41764
|
-
const wfDir = (0,
|
|
41765
|
-
if (!(0,
|
|
41766
|
-
return (0,
|
|
41819
|
+
const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
|
|
41820
|
+
if (!(0, import_node_fs47.existsSync)(wfDir)) return [];
|
|
41821
|
+
return (0, import_node_fs47.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
41767
41822
|
try {
|
|
41768
|
-
return workflowReportsPrChecks((0,
|
|
41823
|
+
return workflowReportsPrChecks((0, import_node_fs47.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
|
|
41769
41824
|
} catch {
|
|
41770
41825
|
return true;
|
|
41771
41826
|
}
|
|
@@ -41817,16 +41872,16 @@ function ciAuditDeps() {
|
|
|
41817
41872
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
41818
41873
|
readSeedFile: (path2) => {
|
|
41819
41874
|
if (!root) return null;
|
|
41820
|
-
const fullPath = (0,
|
|
41821
|
-
return (0,
|
|
41875
|
+
const fullPath = (0, import_node_path44.join)(root, path2);
|
|
41876
|
+
return (0, import_node_fs47.existsSync)(fullPath) ? (0, import_node_fs47.readFileSync)(fullPath, "utf8") : null;
|
|
41822
41877
|
}
|
|
41823
41878
|
};
|
|
41824
41879
|
}
|
|
41825
41880
|
function hubRoot() {
|
|
41826
|
-
const fromPkg = (0,
|
|
41881
|
+
const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
|
|
41827
41882
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
41828
|
-
if ((0,
|
|
41829
|
-
if ((0,
|
|
41883
|
+
if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
|
|
41884
|
+
if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
|
|
41830
41885
|
return null;
|
|
41831
41886
|
}
|
|
41832
41887
|
async function waitLoopCorePool(label) {
|
|
@@ -42134,7 +42189,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42134
42189
|
}
|
|
42135
42190
|
if (!repoForPostCleanup) throw e;
|
|
42136
42191
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
42137
|
-
const commitMessage = bodyFile ? (0,
|
|
42192
|
+
const commitMessage = bodyFile ? (0, import_node_fs47.readFileSync)(bodyFile, "utf8") : void 0;
|
|
42138
42193
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
42139
42194
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
42140
42195
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -42230,7 +42285,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42230
42285
|
localCleanup = await cleanupPrMergeLocalBranch(headRef, {
|
|
42231
42286
|
beforeWorktrees,
|
|
42232
42287
|
startingPath,
|
|
42233
|
-
pathExists: (p) => (0,
|
|
42288
|
+
pathExists: (p) => (0, import_node_fs47.existsSync)(p),
|
|
42234
42289
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
42235
42290
|
teardownWorktreeStage,
|
|
42236
42291
|
deferredStore,
|
|
@@ -42808,12 +42863,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
42808
42863
|
targets = resolution.targets;
|
|
42809
42864
|
}
|
|
42810
42865
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
42811
|
-
const fileMatrix = (0,
|
|
42866
|
+
const fileMatrix = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
42812
42867
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
42813
42868
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
42814
|
-
const fileContracts = (0,
|
|
42869
|
+
const fileContracts = (0, import_node_fs47.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs47.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
|
|
42815
42870
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
42816
|
-
const sanctioned = (0,
|
|
42871
|
+
const sanctioned = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
42817
42872
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
42818
42873
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
42819
42874
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -42845,16 +42900,16 @@ function directoryBytes(path2) {
|
|
|
42845
42900
|
let total = 0;
|
|
42846
42901
|
let entries;
|
|
42847
42902
|
try {
|
|
42848
|
-
entries = (0,
|
|
42903
|
+
entries = (0, import_node_fs47.readdirSync)(path2, { withFileTypes: true });
|
|
42849
42904
|
} catch {
|
|
42850
42905
|
return 0;
|
|
42851
42906
|
}
|
|
42852
42907
|
for (const entry of entries) {
|
|
42853
|
-
const child2 = (0,
|
|
42908
|
+
const child2 = (0, import_node_path44.join)(path2, entry.name);
|
|
42854
42909
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
42855
42910
|
else {
|
|
42856
42911
|
try {
|
|
42857
|
-
total += (0,
|
|
42912
|
+
total += (0, import_node_fs47.statSync)(child2).size;
|
|
42858
42913
|
} catch {
|
|
42859
42914
|
}
|
|
42860
42915
|
}
|
|
@@ -42862,25 +42917,25 @@ function directoryBytes(path2) {
|
|
|
42862
42917
|
return total;
|
|
42863
42918
|
}
|
|
42864
42919
|
function listDirEntries(dir) {
|
|
42865
|
-
return (0,
|
|
42920
|
+
return (0, import_node_fs47.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
42866
42921
|
}
|
|
42867
42922
|
function readInstalledPluginRefs(configRoot) {
|
|
42868
42923
|
const p = installedPluginsPathForConfig(configRoot);
|
|
42869
|
-
if (!(0,
|
|
42924
|
+
if (!(0, import_node_fs47.existsSync)(p)) return [];
|
|
42870
42925
|
try {
|
|
42871
|
-
return installedPluginPaths((0,
|
|
42926
|
+
return installedPluginPaths((0, import_node_fs47.readFileSync)(p, "utf8"));
|
|
42872
42927
|
} catch {
|
|
42873
42928
|
return null;
|
|
42874
42929
|
}
|
|
42875
42930
|
}
|
|
42876
42931
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
42877
42932
|
return {
|
|
42878
|
-
exists: (p) => (0,
|
|
42879
|
-
listVersionDirs: (root) => (0,
|
|
42933
|
+
exists: (p) => (0, import_node_fs47.existsSync)(p),
|
|
42934
|
+
listVersionDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
42880
42935
|
dirBytes,
|
|
42881
|
-
listStagingDirs: (root) => (0,
|
|
42936
|
+
listStagingDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
42882
42937
|
try {
|
|
42883
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
42938
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path44.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs47.statSync)(p).mtimeMs) };
|
|
42884
42939
|
} catch {
|
|
42885
42940
|
return { name: d.name, mtimeMs: Date.now() };
|
|
42886
42941
|
}
|
|
@@ -42894,10 +42949,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
42894
42949
|
return {
|
|
42895
42950
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
42896
42951
|
mtimeMs: (name) => {
|
|
42897
|
-
const p = (0,
|
|
42898
|
-
if (!(0,
|
|
42952
|
+
const p = (0, import_node_path44.join)(stagingRoot, name);
|
|
42953
|
+
if (!(0, import_node_fs47.existsSync)(p)) return null;
|
|
42899
42954
|
try {
|
|
42900
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
42955
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs47.statSync)(q).mtimeMs);
|
|
42901
42956
|
} catch {
|
|
42902
42957
|
return null;
|
|
42903
42958
|
}
|
|
@@ -42923,7 +42978,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
42923
42978
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
42924
42979
|
);
|
|
42925
42980
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
42926
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
42981
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs47.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
42927
42982
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
42928
42983
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
42929
42984
|
else console.log(renderPluginCachePlan(plan, result));
|
|
@@ -42931,7 +42986,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
42931
42986
|
});
|
|
42932
42987
|
function readReleaseCatchupState(path2) {
|
|
42933
42988
|
try {
|
|
42934
|
-
const parsed = JSON.parse((0,
|
|
42989
|
+
const parsed = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
|
|
42935
42990
|
return typeof parsed?.checkedAt === "number" ? parsed : void 0;
|
|
42936
42991
|
} catch {
|
|
42937
42992
|
return void 0;
|
|
@@ -42939,8 +42994,8 @@ function readReleaseCatchupState(path2) {
|
|
|
42939
42994
|
}
|
|
42940
42995
|
function writeReleaseCatchupState(path2, state) {
|
|
42941
42996
|
try {
|
|
42942
|
-
(0,
|
|
42943
|
-
(0,
|
|
42997
|
+
(0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
|
|
42998
|
+
(0, import_node_fs47.writeFileSync)(path2, `${JSON.stringify(state)}
|
|
42944
42999
|
`);
|
|
42945
43000
|
} catch {
|
|
42946
43001
|
}
|