@mutmutco/cli 3.117.1 → 3.119.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 +580 -526
- package/package.json +2 -2
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
|
}
|
|
@@ -11642,8 +11676,8 @@ var NPM_INSTALL_TIMEOUT_MS = 12e4;
|
|
|
11642
11676
|
var CLI_VERSION_PROBE_TIMEOUT_MS = 3e4;
|
|
11643
11677
|
function resolveNpmSpawn(args) {
|
|
11644
11678
|
if (!isWin) return { file: "npm", args };
|
|
11645
|
-
const cli = (0,
|
|
11646
|
-
if ((0,
|
|
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] };
|
|
11647
11681
|
return { file: "cmd.exe", args: ["/c", "npm", ...args] };
|
|
11648
11682
|
}
|
|
11649
11683
|
async function npmSelfUpdateCli(target, onStep, deps = {}) {
|
|
@@ -11669,11 +11703,11 @@ async function npmSelfUpdateCli(target, onStep, deps = {}) {
|
|
|
11669
11703
|
onStep?.(verified.detail, { alwaysShow: true });
|
|
11670
11704
|
return verified.ok ? { ok: true, detail: `${command} exited 0 \u2014 ${verified.detail}` } : { ok: false, detail: `${command} exited 0 but ${verified.detail}` };
|
|
11671
11705
|
}
|
|
11672
|
-
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) {
|
|
11673
11707
|
const candidates = ["kilo.json", "kilo.jsonc", "opencode.json", "opencode.jsonc", "config.json"];
|
|
11674
|
-
for (const dir of [configRoot, (0,
|
|
11708
|
+
for (const dir of [configRoot, (0, import_node_path17.join)(home, ".kilo")]) {
|
|
11675
11709
|
for (const file of candidates) {
|
|
11676
|
-
const path2 = (0,
|
|
11710
|
+
const path2 = (0, import_node_path17.join)(dir, file);
|
|
11677
11711
|
if (!exists(path2)) continue;
|
|
11678
11712
|
try {
|
|
11679
11713
|
const stripped = read(path2).replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
@@ -11690,23 +11724,23 @@ function kiloConfigListsPlugin(configRoot, home = (0, import_node_os5.homedir)()
|
|
|
11690
11724
|
return false;
|
|
11691
11725
|
}
|
|
11692
11726
|
function cursorLocalPluginRoot(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
11693
|
-
return (0,
|
|
11727
|
+
return (0, import_node_path17.join)(surfaceConfigRoot("cursor", env, home), "plugins", "local", "mmi");
|
|
11694
11728
|
}
|
|
11695
|
-
function cursorPluginTreeHealthy(root, exists =
|
|
11729
|
+
function cursorPluginTreeHealthy(root, exists = import_node_fs18.existsSync) {
|
|
11696
11730
|
return [
|
|
11697
11731
|
".cursor-plugin/plugin.json",
|
|
11698
11732
|
"skills/mmi/SKILL.md",
|
|
11699
11733
|
"hooks/cursor-hooks.json",
|
|
11700
11734
|
"scripts/hook-run.mjs",
|
|
11701
11735
|
"scripts/hook-policy.mjs"
|
|
11702
|
-
].every((path2) => exists((0,
|
|
11736
|
+
].every((path2) => exists((0, import_node_path17.join)(root, ...path2.split("/"))));
|
|
11703
11737
|
}
|
|
11704
|
-
function kimiPluginTreeHealthy(root, exists =
|
|
11738
|
+
function kimiPluginTreeHealthy(root, exists = import_node_fs18.existsSync) {
|
|
11705
11739
|
return [
|
|
11706
11740
|
".kimi-plugin/plugin.json",
|
|
11707
11741
|
"skills/mmi/SKILL.md",
|
|
11708
11742
|
"scripts/hook-run.mjs"
|
|
11709
|
-
].every((path2) => exists((0,
|
|
11743
|
+
].every((path2) => exists((0, import_node_path17.join)(root, ...path2.split("/"))));
|
|
11710
11744
|
}
|
|
11711
11745
|
var JERVCODE_WRAPPER_DIR = ".pi-plugin";
|
|
11712
11746
|
function normalizePiEntry(value) {
|
|
@@ -11729,7 +11763,7 @@ function jervcodePackageFamily(entry) {
|
|
|
11729
11763
|
function isMmiOwnedPiEntry(entry) {
|
|
11730
11764
|
if (typeof entry !== "string") return false;
|
|
11731
11765
|
try {
|
|
11732
|
-
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"));
|
|
11733
11767
|
return pkg.name === "mmi";
|
|
11734
11768
|
} catch {
|
|
11735
11769
|
return false;
|
|
@@ -11751,9 +11785,9 @@ function mergeMmiPiPackageEntries(entries, packagePath) {
|
|
|
11751
11785
|
};
|
|
11752
11786
|
}
|
|
11753
11787
|
function readPiSettings(path2) {
|
|
11754
|
-
if (!(0,
|
|
11788
|
+
if (!(0, import_node_fs18.existsSync)(path2)) return void 0;
|
|
11755
11789
|
try {
|
|
11756
|
-
const parsed = JSON.parse((0,
|
|
11790
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
|
|
11757
11791
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
11758
11792
|
return parsed;
|
|
11759
11793
|
} catch {
|
|
@@ -11761,8 +11795,8 @@ function readPiSettings(path2) {
|
|
|
11761
11795
|
}
|
|
11762
11796
|
}
|
|
11763
11797
|
function jervcodeSettingsCandidates(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
11764
|
-
const primary = (0,
|
|
11765
|
-
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");
|
|
11766
11800
|
return legacy === primary ? [primary] : [primary, legacy];
|
|
11767
11801
|
}
|
|
11768
11802
|
function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
@@ -11781,17 +11815,17 @@ function mmiPiWrapperEntry(env = process.env, home = (0, import_node_os5.homedir
|
|
|
11781
11815
|
function mmiPiWrapperHealthy(entry) {
|
|
11782
11816
|
if (!entry) return false;
|
|
11783
11817
|
const wrapper = piEntryFsPath(entry);
|
|
11784
|
-
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"));
|
|
11785
11819
|
}
|
|
11786
11820
|
function findMmiPiSourceClone(home = (0, import_node_os5.homedir)()) {
|
|
11787
|
-
const cacheRoot = (0,
|
|
11821
|
+
const cacheRoot = (0, import_node_path17.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi");
|
|
11788
11822
|
let best = null;
|
|
11789
11823
|
try {
|
|
11790
|
-
for (const entry of (0,
|
|
11824
|
+
for (const entry of (0, import_node_fs18.readdirSync)(cacheRoot, { withFileTypes: true })) {
|
|
11791
11825
|
if (!entry.isDirectory() || !/^\d+\.\d+\.\d+$/.test(entry.name)) continue;
|
|
11792
|
-
if (!(0,
|
|
11826
|
+
if (!(0, import_node_fs18.existsSync)((0, import_node_path17.join)(cacheRoot, entry.name, JERVCODE_WRAPPER_DIR, "package.json"))) continue;
|
|
11793
11827
|
if (!best || compareVersions(entry.name, best.version) > 0) {
|
|
11794
|
-
best = { path: (0,
|
|
11828
|
+
best = { path: (0, import_node_path17.join)(cacheRoot, entry.name), version: entry.name };
|
|
11795
11829
|
}
|
|
11796
11830
|
}
|
|
11797
11831
|
} catch {
|
|
@@ -11816,8 +11850,8 @@ function acquirePiSettingsLock(settingsPath2) {
|
|
|
11816
11850
|
return void 0;
|
|
11817
11851
|
}
|
|
11818
11852
|
function healOneJervCodeSettingsFile(settingsPath2, packagePath, version, nextLaunch) {
|
|
11819
|
-
const release = (0,
|
|
11820
|
-
if ((0,
|
|
11853
|
+
const release = (0, import_node_fs18.existsSync)(settingsPath2) ? acquirePiSettingsLock(settingsPath2) : void 0;
|
|
11854
|
+
if ((0, import_node_fs18.existsSync)(settingsPath2) && !release) {
|
|
11821
11855
|
return {
|
|
11822
11856
|
available: true,
|
|
11823
11857
|
ok: false,
|
|
@@ -11845,14 +11879,14 @@ function healOneJervCodeSettingsFile(settingsPath2, packagePath, version, nextLa
|
|
|
11845
11879
|
}
|
|
11846
11880
|
current.packages = merged.next;
|
|
11847
11881
|
try {
|
|
11848
|
-
(0,
|
|
11882
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path17.dirname)(settingsPath2), { recursive: true });
|
|
11849
11883
|
const tmp = `${settingsPath2}.tmp-${process.pid}`;
|
|
11850
|
-
(0,
|
|
11884
|
+
(0, import_node_fs18.writeFileSync)(tmp, `${JSON.stringify(current, null, 2)}
|
|
11851
11885
|
`, "utf8");
|
|
11852
11886
|
try {
|
|
11853
|
-
(0,
|
|
11887
|
+
(0, import_node_fs18.renameSync)(tmp, settingsPath2);
|
|
11854
11888
|
} catch (renameError) {
|
|
11855
|
-
(0,
|
|
11889
|
+
(0, import_node_fs18.rmSync)(tmp, { force: true });
|
|
11856
11890
|
throw renameError;
|
|
11857
11891
|
}
|
|
11858
11892
|
} catch (error) {
|
|
@@ -11876,8 +11910,8 @@ function healJervCodePackageRegistration(opts = {}) {
|
|
|
11876
11910
|
const nextLaunch = inSeat ? " \u2014 takes effect on the next seat launch" : "";
|
|
11877
11911
|
const home = opts.home ?? (0, import_node_os5.homedir)();
|
|
11878
11912
|
const agentDir = surfaceConfigRoot("jervcode", env, home);
|
|
11879
|
-
const legacyPi = (0,
|
|
11880
|
-
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)) {
|
|
11881
11915
|
return { available: false, ok: true, changed: false, version: null, detail: "skipped \u2014 no Pi/JervCode install (no agent config dir)" };
|
|
11882
11916
|
}
|
|
11883
11917
|
const clone = opts.clone === void 0 ? findMmiPiSourceClone(home) : opts.clone;
|
|
@@ -11885,9 +11919,9 @@ function healJervCodePackageRegistration(opts = {}) {
|
|
|
11885
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)" };
|
|
11886
11920
|
}
|
|
11887
11921
|
const packagePath = `${clone.path.replace(/\\/g, "/").replace(/\/+$/, "")}/${JERVCODE_WRAPPER_DIR}`;
|
|
11888
|
-
const targets = [(0,
|
|
11889
|
-
const legacySettings = (0,
|
|
11890
|
-
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);
|
|
11891
11925
|
const details = [];
|
|
11892
11926
|
let anyChanged = false;
|
|
11893
11927
|
for (const settingsPath2 of targets) {
|
|
@@ -11915,18 +11949,18 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
|
|
|
11915
11949
|
return {
|
|
11916
11950
|
isOrgRepo,
|
|
11917
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.
|
|
11918
|
-
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.
|
|
11919
11953
|
surface === "kilo" && kiloConfigListsPlugin(root) || // #4188: jervcode's install record is the settings-file packages[] entry itself.
|
|
11920
|
-
surface === "jervcode" && piEntry !== null || surface === "cursor" && (0,
|
|
11954
|
+
surface === "jervcode" && piEntry !== null || surface === "cursor" && (0, import_node_fs18.existsSync)(cursorLocalPluginRoot()),
|
|
11921
11955
|
// Kilo has no marketplace to clone — the config file IS the install record, so this dimension of
|
|
11922
11956
|
// the shared guard table is vacuously satisfied. Same for jervcode's settings entry.
|
|
11923
11957
|
marketplaceClonePresent: surface === "kimi" || surface === "kilo" || surface === "cursor" || surface === "jervcode" ? true : marketplaceClonePresent(surface, (0, import_node_os5.homedir)()),
|
|
11924
11958
|
// Kimi keeps no plugin cache dir — installs are copied to plugins/managed/<id> and run from there.
|
|
11925
11959
|
// Kilo (kilo-p1) keeps no cache dir either: the plugin's server() provisions ~/.kilo behind the
|
|
11926
11960
|
// version stamp, so the stamp's presence is the cache signal.
|
|
11927
|
-
pluginCachePresent: surface === "jervcode" ? mmiPiWrapperHealthy(piEntry) : surface === "kilo" ? (0,
|
|
11928
|
-
codexStatus?.installed && codexStatus.enabled && codexStatus.version && (0,
|
|
11929
|
-
) : (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"))
|
|
11930
11964
|
};
|
|
11931
11965
|
}
|
|
11932
11966
|
async function runHostBinLogged(bin, args, opts) {
|
|
@@ -11946,11 +11980,11 @@ async function runPluginCli(bin, args, log) {
|
|
|
11946
11980
|
function captureCodexHookLauncher() {
|
|
11947
11981
|
const status = codexPluginStatus();
|
|
11948
11982
|
if (!status.installed || !status.enabled || !status.version) return void 0;
|
|
11949
|
-
const root = (0,
|
|
11983
|
+
const root = (0, import_node_path17.join)(surfaceConfigRoot("codex"), "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version);
|
|
11950
11984
|
const files = ["mmi-hook", "mmi-hook.exe"].flatMap((name) => {
|
|
11951
|
-
const path2 = (0,
|
|
11985
|
+
const path2 = (0, import_node_path17.join)(root, "bin", name);
|
|
11952
11986
|
try {
|
|
11953
|
-
return [{ name, content: (0,
|
|
11987
|
+
return [{ name, content: (0, import_node_fs18.readFileSync)(path2) }];
|
|
11954
11988
|
} catch {
|
|
11955
11989
|
return [];
|
|
11956
11990
|
}
|
|
@@ -11958,13 +11992,13 @@ function captureCodexHookLauncher() {
|
|
|
11958
11992
|
return files.length === 2 ? { root, files } : void 0;
|
|
11959
11993
|
}
|
|
11960
11994
|
function restoreCodexHookLauncher(snapshot) {
|
|
11961
|
-
if (!snapshot || (0,
|
|
11962
|
-
const bin = (0,
|
|
11963
|
-
(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 });
|
|
11964
11998
|
for (const file of snapshot.files) {
|
|
11965
|
-
const path2 = (0,
|
|
11966
|
-
(0,
|
|
11967
|
-
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);
|
|
11968
12002
|
}
|
|
11969
12003
|
return true;
|
|
11970
12004
|
}
|
|
@@ -11973,10 +12007,10 @@ function canonicalCursorRemote(remote) {
|
|
|
11973
12007
|
}
|
|
11974
12008
|
async function installCursorPluginCheckout(env = process.env) {
|
|
11975
12009
|
const configRoot = surfaceConfigRoot("cursor", env);
|
|
11976
|
-
const pluginsRoot = (0,
|
|
11977
|
-
const target = (0,
|
|
12010
|
+
const pluginsRoot = (0, import_node_path17.join)(configRoot, "plugins");
|
|
12011
|
+
const target = (0, import_node_path17.join)(pluginsRoot, "local", "mmi");
|
|
11978
12012
|
const source = env.MMI_CURSOR_PLUGIN_SOURCE?.trim();
|
|
11979
|
-
if ((0,
|
|
12013
|
+
if ((0, import_node_fs18.existsSync)(target) && !source) {
|
|
11980
12014
|
try {
|
|
11981
12015
|
const { stdout } = await runHostBin("git", ["-C", target, "remote", "get-url", "origin"], { timeout: 15e3 });
|
|
11982
12016
|
if (!canonicalCursorRemote(stdout)) {
|
|
@@ -11986,15 +12020,15 @@ async function installCursorPluginCheckout(env = process.env) {
|
|
|
11986
12020
|
return { ok: false, detail: `refused to replace unmanaged Cursor plugin directory at ${target}` };
|
|
11987
12021
|
}
|
|
11988
12022
|
}
|
|
11989
|
-
(0,
|
|
11990
|
-
(0,
|
|
11991
|
-
(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 });
|
|
11992
12026
|
const suffix = `${Date.now()}-${process.pid}`;
|
|
11993
|
-
const staged = (0,
|
|
11994
|
-
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}`);
|
|
11995
12029
|
try {
|
|
11996
12030
|
if (source) {
|
|
11997
|
-
(0,
|
|
12031
|
+
(0, import_node_fs18.cpSync)(source, staged, {
|
|
11998
12032
|
recursive: true,
|
|
11999
12033
|
filter: (path2) => !path2.split(/[\\/]/).some((part) => part === ".git" || part === "node_modules")
|
|
12000
12034
|
});
|
|
@@ -12005,18 +12039,18 @@ async function installCursorPluginCheckout(env = process.env) {
|
|
|
12005
12039
|
});
|
|
12006
12040
|
}
|
|
12007
12041
|
if (!cursorPluginTreeHealthy(staged)) {
|
|
12008
|
-
(0,
|
|
12042
|
+
(0, import_node_fs18.rmSync)(staged, { recursive: true, force: true });
|
|
12009
12043
|
return { ok: false, detail: "downloaded Cursor plugin is incomplete; existing install was preserved" };
|
|
12010
12044
|
}
|
|
12011
12045
|
let movedOld = false;
|
|
12012
|
-
if ((0,
|
|
12013
|
-
(0,
|
|
12046
|
+
if ((0, import_node_fs18.existsSync)(target)) {
|
|
12047
|
+
(0, import_node_fs18.renameSync)(target, quarantined);
|
|
12014
12048
|
movedOld = true;
|
|
12015
12049
|
}
|
|
12016
12050
|
try {
|
|
12017
|
-
(0,
|
|
12051
|
+
(0, import_node_fs18.renameSync)(staged, target);
|
|
12018
12052
|
} catch (error) {
|
|
12019
|
-
if (movedOld && !(0,
|
|
12053
|
+
if (movedOld && !(0, import_node_fs18.existsSync)(target)) (0, import_node_fs18.renameSync)(quarantined, target);
|
|
12020
12054
|
throw error;
|
|
12021
12055
|
}
|
|
12022
12056
|
return {
|
|
@@ -12024,7 +12058,7 @@ async function installCursorPluginCheckout(env = process.env) {
|
|
|
12024
12058
|
detail: movedOld ? `installed canonical Cursor plugin; previous checkout quarantined at ${quarantined}` : `installed canonical Cursor plugin at ${target}`
|
|
12025
12059
|
};
|
|
12026
12060
|
} catch (error) {
|
|
12027
|
-
if ((0,
|
|
12061
|
+
if ((0, import_node_fs18.existsSync)(staged)) (0, import_node_fs18.rmSync)(staged, { recursive: true, force: true });
|
|
12028
12062
|
return { ok: false, detail: error.message.trim().slice(0, 240).replace(/\s+/g, " ") };
|
|
12029
12063
|
}
|
|
12030
12064
|
}
|
|
@@ -12074,7 +12108,7 @@ async function applyPluginHeal(surface, log, opts) {
|
|
|
12074
12108
|
const refSupported = await marketplaceAddRefSupported(bin);
|
|
12075
12109
|
const { steps } = adaptHealStepsForRefSupport(tableSteps, refSupported);
|
|
12076
12110
|
log(healBannerLine(bin, token, refSupported));
|
|
12077
|
-
const pinsPath = (0,
|
|
12111
|
+
const pinsPath = (0, import_node_path17.join)((0, import_node_os5.homedir)(), ...KNOWN_MARKETPLACES_RELATIVE);
|
|
12078
12112
|
const pins = token === "claude" ? captureMarketplacePins(readKnownMarketplacesFile(pinsPath), [MMI_MARKETPLACE_NAME, JERV_MARKETPLACE_NAME]) : /* @__PURE__ */ new Map();
|
|
12079
12113
|
try {
|
|
12080
12114
|
for (const step of steps) {
|
|
@@ -12149,7 +12183,7 @@ async function healActivePluginForDoctor(surface = detectSurface(process.env), o
|
|
|
12149
12183
|
}
|
|
12150
12184
|
function readKnownMarketplacesFile(path2) {
|
|
12151
12185
|
try {
|
|
12152
|
-
return (0,
|
|
12186
|
+
return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : void 0;
|
|
12153
12187
|
} catch {
|
|
12154
12188
|
return void 0;
|
|
12155
12189
|
}
|
|
@@ -12179,7 +12213,7 @@ function writeMarketplacePinsOnDisk(path2, pins, succeeded, failedVerb, declineW
|
|
|
12179
12213
|
const declined = declineWhileHostLive?.();
|
|
12180
12214
|
if (declined) return declined;
|
|
12181
12215
|
try {
|
|
12182
|
-
(0,
|
|
12216
|
+
(0, import_node_fs18.writeFileSync)(path2, next, "utf8");
|
|
12183
12217
|
} catch {
|
|
12184
12218
|
return `could NOT ${failedVerb} ${[...pins.keys()].join(", ")} \u2014 set it by hand`;
|
|
12185
12219
|
}
|
|
@@ -12219,15 +12253,15 @@ function applyOrgMarketplacePins(path2, names, hostIsRunning = claudeCodeIsRunni
|
|
|
12219
12253
|
}
|
|
12220
12254
|
function writeMarketplacePinPending(path2, names, now = Date.now()) {
|
|
12221
12255
|
try {
|
|
12222
|
-
(0,
|
|
12223
|
-
(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() })}
|
|
12224
12258
|
`, "utf8");
|
|
12225
12259
|
} catch {
|
|
12226
12260
|
}
|
|
12227
12261
|
}
|
|
12228
12262
|
function readMarketplacePinPending(path2, name, now = Date.now()) {
|
|
12229
12263
|
try {
|
|
12230
|
-
const parsed = JSON.parse((0,
|
|
12264
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
|
|
12231
12265
|
const at = typeof parsed.at === "string" ? Date.parse(parsed.at) : Number.NaN;
|
|
12232
12266
|
if (parsed.v !== 1 || !Array.isArray(parsed.names) || !parsed.names.includes(name) || !Number.isFinite(at)) return void 0;
|
|
12233
12267
|
if (now - at < 0 || now - at > 12 * 60 * 6e4) return void 0;
|
|
@@ -12785,9 +12819,9 @@ function renderAccessReport(report) {
|
|
|
12785
12819
|
}
|
|
12786
12820
|
|
|
12787
12821
|
// src/cli-doctor-shared.ts
|
|
12788
|
-
var import_node_fs18 = require("node:fs");
|
|
12789
|
-
var import_node_path18 = require("node:path");
|
|
12790
12822
|
var import_node_fs19 = require("node:fs");
|
|
12823
|
+
var import_node_path19 = require("node:path");
|
|
12824
|
+
var import_node_fs20 = require("node:fs");
|
|
12791
12825
|
|
|
12792
12826
|
// ../infra/registry-endpoints.mjs
|
|
12793
12827
|
var PROJECTS_LIST_PATH = "/projects/list";
|
|
@@ -13701,7 +13735,7 @@ var import_node_os7 = require("node:os");
|
|
|
13701
13735
|
// src/gh-create.ts
|
|
13702
13736
|
var import_promises3 = require("node:fs/promises");
|
|
13703
13737
|
var import_node_os6 = require("node:os");
|
|
13704
|
-
var
|
|
13738
|
+
var import_node_path18 = require("node:path");
|
|
13705
13739
|
var import_node_crypto3 = require("node:crypto");
|
|
13706
13740
|
|
|
13707
13741
|
// src/board-priority.ts
|
|
@@ -13784,8 +13818,8 @@ async function bodyArgsViaFile(args, deps = {}) {
|
|
|
13784
13818
|
const remove2 = deps.remove ?? import_promises3.unlink;
|
|
13785
13819
|
const ensureDir = deps.ensureDir ?? import_promises3.mkdir;
|
|
13786
13820
|
const dir = deps.dir ?? (0, import_node_os6.tmpdir)();
|
|
13787
|
-
const file = (0,
|
|
13788
|
-
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(() => {
|
|
13789
13823
|
});
|
|
13790
13824
|
await write(file, args[i + 1], "utf8");
|
|
13791
13825
|
return {
|
|
@@ -15328,7 +15362,7 @@ async function localBranchHeads() {
|
|
|
15328
15362
|
}
|
|
15329
15363
|
async function currentRepoWorktreeGitRoot(repoRoot2) {
|
|
15330
15364
|
const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
15331
|
-
return gitCommonDir ? (0,
|
|
15365
|
+
return gitCommonDir ? (0, import_node_path19.resolve)(repoRoot2, gitCommonDir, "worktrees") : "";
|
|
15332
15366
|
}
|
|
15333
15367
|
async function worktreeBranches() {
|
|
15334
15368
|
const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
|
|
@@ -15348,18 +15382,18 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
|
|
|
15348
15382
|
const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
|
|
15349
15383
|
if (!match?.[1]) return void 0;
|
|
15350
15384
|
const raw = match[1].trim();
|
|
15351
|
-
return (0,
|
|
15385
|
+
return (0, import_node_path19.isAbsolute)(raw) ? raw : (0, import_node_path19.resolve)(worktreePath, raw);
|
|
15352
15386
|
}
|
|
15353
15387
|
function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
15354
15388
|
if (!worktreeGitRoot) return false;
|
|
15355
15389
|
try {
|
|
15356
|
-
const entries = (0,
|
|
15390
|
+
const entries = (0, import_node_fs20.readdirSync)(worktreeGitRoot, { withFileTypes: true });
|
|
15357
15391
|
for (const ent of entries) {
|
|
15358
15392
|
if (!ent.isDirectory()) continue;
|
|
15359
15393
|
try {
|
|
15360
|
-
const gitdirPath = (0,
|
|
15361
|
-
const resolvedGitdir = (0,
|
|
15362
|
-
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;
|
|
15363
15397
|
} catch {
|
|
15364
15398
|
}
|
|
15365
15399
|
}
|
|
@@ -15369,7 +15403,7 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
|
15369
15403
|
}
|
|
15370
15404
|
function pathExistsKnown(path2) {
|
|
15371
15405
|
try {
|
|
15372
|
-
(0,
|
|
15406
|
+
(0, import_node_fs20.statSync)(path2);
|
|
15373
15407
|
return true;
|
|
15374
15408
|
} catch (e) {
|
|
15375
15409
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
@@ -15378,10 +15412,10 @@ function pathExistsKnown(path2) {
|
|
|
15378
15412
|
}
|
|
15379
15413
|
}
|
|
15380
15414
|
function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
15381
|
-
const gitPath = (0,
|
|
15415
|
+
const gitPath = (0, import_node_path19.join)(path2, ".git");
|
|
15382
15416
|
let st;
|
|
15383
15417
|
try {
|
|
15384
|
-
st = (0,
|
|
15418
|
+
st = (0, import_node_fs20.lstatSync)(gitPath);
|
|
15385
15419
|
} catch (e) {
|
|
15386
15420
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
15387
15421
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -15398,7 +15432,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
|
15398
15432
|
if (st.isDirectory()) return { path: path2, gitType: "dir" };
|
|
15399
15433
|
if (!st.isFile()) return { path: path2, gitType: "other" };
|
|
15400
15434
|
try {
|
|
15401
|
-
const gitFileContent = (0,
|
|
15435
|
+
const gitFileContent = (0, import_node_fs19.readFileSync)(gitPath, "utf8");
|
|
15402
15436
|
const gitdir = resolveGitdirForWorktreeFile(path2, gitFileContent);
|
|
15403
15437
|
const gitDirExists = gitdir ? pathExistsKnown(gitdir) : false;
|
|
15404
15438
|
return {
|
|
@@ -15415,7 +15449,7 @@ function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
|
15415
15449
|
}
|
|
15416
15450
|
function inspectDeadWorktreeDirContent(path2) {
|
|
15417
15451
|
try {
|
|
15418
|
-
return { entries: (0,
|
|
15452
|
+
return { entries: (0, import_node_fs20.readdirSync)(path2) };
|
|
15419
15453
|
} catch (e) {
|
|
15420
15454
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
15421
15455
|
return { error: code ? `unable to inspect directory contents (${code})` : "unable to inspect directory contents" };
|
|
@@ -15432,7 +15466,7 @@ async function preservedBranches() {
|
|
|
15432
15466
|
async function siblingWorktreeDirs(explicitRoot) {
|
|
15433
15467
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
15434
15468
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
15435
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
15469
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path19.dirname)((0, import_node_path19.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
15436
15470
|
try {
|
|
15437
15471
|
const dirs = explicitRoot ? listDirsIn(resolveExplicitScanRoot(explicitRoot, primaryRepoRoot)) : worktreeScanDirs(siblingMmiWorktreesRoot(primaryRepoRoot), primaryRepoRoot, listDirsIn, isRepoCheckoutDir);
|
|
15438
15472
|
const agentDirs2 = listDirsIn(agentWorktreesRoot(primaryRepoRoot));
|
|
@@ -15443,18 +15477,18 @@ async function siblingWorktreeDirs(explicitRoot) {
|
|
|
15443
15477
|
}
|
|
15444
15478
|
function listDirsIn(dir) {
|
|
15445
15479
|
try {
|
|
15446
|
-
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));
|
|
15447
15481
|
} catch {
|
|
15448
15482
|
return [];
|
|
15449
15483
|
}
|
|
15450
15484
|
}
|
|
15451
15485
|
function isRepoCheckoutDir(dir) {
|
|
15452
|
-
return (0,
|
|
15486
|
+
return (0, import_node_fs20.existsSync)((0, import_node_path19.join)(dir, ".git"));
|
|
15453
15487
|
}
|
|
15454
15488
|
function resolveExplicitScanRoot(explicitRoot, repoRoot2) {
|
|
15455
15489
|
let rootDirs;
|
|
15456
15490
|
try {
|
|
15457
|
-
rootDirs = (0,
|
|
15491
|
+
rootDirs = (0, import_node_fs20.readdirSync)(explicitRoot, { withFileTypes: true }).filter((ent) => ent.isDirectory()).map((ent) => ent.name);
|
|
15458
15492
|
} catch {
|
|
15459
15493
|
return explicitRoot;
|
|
15460
15494
|
}
|
|
@@ -15786,10 +15820,10 @@ var rollout_plan_default = {
|
|
|
15786
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)."
|
|
15787
15821
|
},
|
|
15788
15822
|
baseline: {
|
|
15789
|
-
version: "3.
|
|
15790
|
-
tag: "v3.
|
|
15791
|
-
commit: "
|
|
15792
|
-
npm: "@mutmutco/cli@3.
|
|
15823
|
+
version: "3.119.0",
|
|
15824
|
+
tag: "v3.119.0",
|
|
15825
|
+
commit: "32fef9b214ee",
|
|
15826
|
+
npm: "@mutmutco/cli@3.119.0"
|
|
15793
15827
|
},
|
|
15794
15828
|
exitCriterion: "fleet-n-of-n",
|
|
15795
15829
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15806,14 +15840,14 @@ var rollout_plan_default = {
|
|
|
15806
15840
|
repo: "mutmutco/mmi-hub",
|
|
15807
15841
|
role: "canary",
|
|
15808
15842
|
schedule: "train",
|
|
15809
|
-
v3Target: "v3.
|
|
15843
|
+
v3Target: "v3.119.0"
|
|
15810
15844
|
}
|
|
15811
15845
|
],
|
|
15812
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.",
|
|
15813
15847
|
rollback: {
|
|
15814
15848
|
independent: true,
|
|
15815
|
-
mechanism: "npm dist-tag latest -> 3.
|
|
15816
|
-
v3Target: "v3.
|
|
15849
|
+
mechanism: "npm dist-tag latest -> 3.119.0 and redeploy the Hub Lambda from tag v3.119.0 (32fef9b214ee); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15850
|
+
v3Target: "v3.119.0 (@mutmutco/cli@3.119.0, tag commit 32fef9b214ee \u2014 the preserved latest-v3 distribution, D6b)"
|
|
15817
15851
|
}
|
|
15818
15852
|
},
|
|
15819
15853
|
{
|
|
@@ -17897,7 +17931,7 @@ function planTrainApplyRepoGuard(applyRepo, cwdRepo, rerun) {
|
|
|
17897
17931
|
async function resolveFoldPaths(deps, model) {
|
|
17898
17932
|
const helper = "scripts/release-distribution.mjs";
|
|
17899
17933
|
if (model === "hub-serverless" || model === "registry-publish") {
|
|
17900
|
-
if ((0,
|
|
17934
|
+
if ((0, import_node_fs21.existsSync)(helper)) {
|
|
17901
17935
|
let out;
|
|
17902
17936
|
try {
|
|
17903
17937
|
out = await deps.run("node", [helper, "changed-files"]);
|
|
@@ -18016,7 +18050,7 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
18016
18050
|
if (mainBom.version !== version) return void 0;
|
|
18017
18051
|
let localBom;
|
|
18018
18052
|
try {
|
|
18019
|
-
localBom = JSON.parse((0,
|
|
18053
|
+
localBom = JSON.parse((0, import_node_fs21.readFileSync)(bomPath, "utf8"));
|
|
18020
18054
|
} catch (e) {
|
|
18021
18055
|
throw new Error(
|
|
18022
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).`
|
|
@@ -18034,14 +18068,14 @@ async function restoreMainNpmPackIdentities(deps, version) {
|
|
|
18034
18068
|
restored += 1;
|
|
18035
18069
|
}
|
|
18036
18070
|
if (restored === 0) return void 0;
|
|
18037
|
-
(0,
|
|
18071
|
+
(0, import_node_fs21.writeFileSync)(bomPath, `${JSON.stringify(localBom, null, 2)}
|
|
18038
18072
|
`);
|
|
18039
18073
|
return `restored ${restored} npm-pack BOM identit${restored === 1 ? "y" : "ies"} from origin/main (#4503)`;
|
|
18040
18074
|
}
|
|
18041
18075
|
function publishVisibilityFor(surfaceId) {
|
|
18042
18076
|
let raw;
|
|
18043
18077
|
try {
|
|
18044
|
-
raw = (0,
|
|
18078
|
+
raw = (0, import_node_fs21.readFileSync)("surfaces.json", "utf8");
|
|
18045
18079
|
} catch (e) {
|
|
18046
18080
|
if (e.code === "ENOENT") return "unknown";
|
|
18047
18081
|
throw trainReadFailure(
|
|
@@ -18062,7 +18096,7 @@ function publishVisibilityFor(surfaceId) {
|
|
|
18062
18096
|
}
|
|
18063
18097
|
function npmPackArtifactName(packagePath) {
|
|
18064
18098
|
try {
|
|
18065
|
-
const pkg = JSON.parse((0,
|
|
18099
|
+
const pkg = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path20.join)(packagePath, "package.json"), "utf8"));
|
|
18066
18100
|
return pkg.name || void 0;
|
|
18067
18101
|
} catch {
|
|
18068
18102
|
return void 0;
|
|
@@ -18071,7 +18105,7 @@ function npmPackArtifactName(packagePath) {
|
|
|
18071
18105
|
async function refuseDivergentPublishedNpmPack(deps, version) {
|
|
18072
18106
|
let localBom;
|
|
18073
18107
|
try {
|
|
18074
|
-
localBom = JSON.parse((0,
|
|
18108
|
+
localBom = JSON.parse((0, import_node_fs21.readFileSync)("distribution-bom.json", "utf8"));
|
|
18075
18109
|
} catch (e) {
|
|
18076
18110
|
throw new Error(
|
|
18077
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).`
|
|
@@ -19233,17 +19267,17 @@ async function dispatchDeploy(deps, ctx, stage, ref, model, watch, autoRunSince,
|
|
|
19233
19267
|
return { note: `no manual dispatch: ${model} repo deploys via its own push-triggered workflow`, deployStatus: "pending" };
|
|
19234
19268
|
}
|
|
19235
19269
|
function readLocalGateWorkflows() {
|
|
19236
|
-
const dir = (0,
|
|
19270
|
+
const dir = (0, import_node_path20.join)(".github", "workflows");
|
|
19237
19271
|
let names;
|
|
19238
19272
|
try {
|
|
19239
|
-
names = (0,
|
|
19273
|
+
names = (0, import_node_fs21.readdirSync)(dir);
|
|
19240
19274
|
} catch {
|
|
19241
19275
|
return null;
|
|
19242
19276
|
}
|
|
19243
19277
|
const files = [];
|
|
19244
19278
|
for (const name of names.filter(isGateWorkflowPath)) {
|
|
19245
19279
|
try {
|
|
19246
|
-
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") });
|
|
19247
19281
|
} catch {
|
|
19248
19282
|
}
|
|
19249
19283
|
}
|
|
@@ -21464,12 +21498,12 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
21464
21498
|
}
|
|
21465
21499
|
|
|
21466
21500
|
// src/wave-status.ts
|
|
21467
|
-
var
|
|
21501
|
+
var import_node_fs23 = require("node:fs");
|
|
21468
21502
|
|
|
21469
21503
|
// src/stage-runner.ts
|
|
21470
21504
|
var import_node_child_process9 = require("node:child_process");
|
|
21471
|
-
var
|
|
21472
|
-
var
|
|
21505
|
+
var import_node_fs22 = require("node:fs");
|
|
21506
|
+
var import_node_path21 = require("node:path");
|
|
21473
21507
|
var import_node_net = require("node:net");
|
|
21474
21508
|
var import_node_util5 = require("node:util");
|
|
21475
21509
|
|
|
@@ -21608,11 +21642,11 @@ function appendForceRecreate(up) {
|
|
|
21608
21642
|
return `${up.trimEnd()} --force-recreate`;
|
|
21609
21643
|
}
|
|
21610
21644
|
function stageStatePath(cwd = process.cwd()) {
|
|
21611
|
-
return (0,
|
|
21645
|
+
return (0, import_node_path21.join)(cwd, "tmp", "stage", "state.json");
|
|
21612
21646
|
}
|
|
21613
21647
|
function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
|
|
21614
|
-
const dir = (0,
|
|
21615
|
-
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");
|
|
21616
21650
|
}
|
|
21617
21651
|
function normPath3(path2) {
|
|
21618
21652
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -21836,14 +21870,14 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
21836
21870
|
}
|
|
21837
21871
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
21838
21872
|
if (!config.ensureEnv) return;
|
|
21839
|
-
const target = (0,
|
|
21840
|
-
const example = (0,
|
|
21841
|
-
if (!(0,
|
|
21842
|
-
(0,
|
|
21843
|
-
} else if ((0,
|
|
21844
|
-
const stale = detectStaleEnvFile((0,
|
|
21845
|
-
exampleMtimeMs: (0,
|
|
21846
|
-
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
|
|
21847
21881
|
});
|
|
21848
21882
|
if (stale) {
|
|
21849
21883
|
const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
|
|
@@ -21851,8 +21885,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
|
21851
21885
|
console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
|
|
21852
21886
|
}
|
|
21853
21887
|
}
|
|
21854
|
-
if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0,
|
|
21855
|
-
(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");
|
|
21856
21890
|
}
|
|
21857
21891
|
}
|
|
21858
21892
|
async function gitText(cwd, args) {
|
|
@@ -21882,20 +21916,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
|
|
|
21882
21916
|
return void 0;
|
|
21883
21917
|
}
|
|
21884
21918
|
function readState(path2) {
|
|
21885
|
-
if (!(0,
|
|
21919
|
+
if (!(0, import_node_fs22.existsSync)(path2)) return null;
|
|
21886
21920
|
try {
|
|
21887
|
-
return JSON.parse((0,
|
|
21921
|
+
return JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
21888
21922
|
} catch {
|
|
21889
21923
|
return null;
|
|
21890
21924
|
}
|
|
21891
21925
|
}
|
|
21892
21926
|
function mkdirFor(path2) {
|
|
21893
21927
|
const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
|
|
21894
|
-
(0,
|
|
21928
|
+
(0, import_node_fs22.mkdirSync)(dir, { recursive: true });
|
|
21895
21929
|
}
|
|
21896
21930
|
function writeState(path2, state) {
|
|
21897
21931
|
mkdirFor(path2);
|
|
21898
|
-
(0,
|
|
21932
|
+
(0, import_node_fs22.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
|
|
21899
21933
|
}
|
|
21900
21934
|
function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
|
|
21901
21935
|
const reservation = {
|
|
@@ -21915,7 +21949,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd) {
|
|
|
21915
21949
|
await shell(state.teardown.command.trim(), state.teardown.cwd || state.cwd || fallbackCwd, Math.max(timeoutMs, 1e4));
|
|
21916
21950
|
}
|
|
21917
21951
|
for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
|
|
21918
|
-
(0,
|
|
21952
|
+
(0, import_node_fs22.rmSync)(path2, { force: true });
|
|
21919
21953
|
}
|
|
21920
21954
|
}
|
|
21921
21955
|
async function killTree(pid) {
|
|
@@ -22073,8 +22107,8 @@ async function runStage(config = {}, opts = {}) {
|
|
|
22073
22107
|
await ensureStageRuntimeEnv(config, opts, cwd);
|
|
22074
22108
|
if (build) await shell(sub(build), cwd, timeoutMs, stageProcessEnv(stagePort, extraEnv));
|
|
22075
22109
|
} catch (e) {
|
|
22076
|
-
(0,
|
|
22077
|
-
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 });
|
|
22078
22112
|
throw e;
|
|
22079
22113
|
}
|
|
22080
22114
|
const started = await startStage(config, {
|
|
@@ -22095,9 +22129,9 @@ function parseNextFromHead(headText) {
|
|
|
22095
22129
|
}
|
|
22096
22130
|
function readStageSummary(worktreePath) {
|
|
22097
22131
|
const statePath = stageStatePath(worktreePath);
|
|
22098
|
-
if (!(0,
|
|
22132
|
+
if (!(0, import_node_fs23.existsSync)(statePath)) return void 0;
|
|
22099
22133
|
try {
|
|
22100
|
-
const state = JSON.parse((0,
|
|
22134
|
+
const state = JSON.parse((0, import_node_fs23.readFileSync)(statePath, "utf8"));
|
|
22101
22135
|
const port = typeof state.port === "number" ? state.port : void 0;
|
|
22102
22136
|
if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
|
|
22103
22137
|
return { port, url: typeof state.url === "string" ? state.url : void 0 };
|
|
@@ -22206,9 +22240,9 @@ var import_node_os19 = require("node:os");
|
|
|
22206
22240
|
|
|
22207
22241
|
// src/board.ts
|
|
22208
22242
|
var import_node_child_process10 = require("node:child_process");
|
|
22209
|
-
var
|
|
22243
|
+
var import_node_fs24 = require("node:fs");
|
|
22210
22244
|
var import_node_os8 = require("node:os");
|
|
22211
|
-
var
|
|
22245
|
+
var import_node_path22 = require("node:path");
|
|
22212
22246
|
var import_node_util6 = require("node:util");
|
|
22213
22247
|
|
|
22214
22248
|
// src/board-dependency.ts
|
|
@@ -23955,17 +23989,17 @@ function probeLocalClaimSession(marker, now = Date.now()) {
|
|
|
23955
23989
|
claimSessionProbeCache.set(cacheKey, { checkedAt: now, state });
|
|
23956
23990
|
return state;
|
|
23957
23991
|
};
|
|
23958
|
-
const root = (0,
|
|
23992
|
+
const root = (0, import_node_path22.join)((0, import_node_os8.homedir)(), ".claude", "projects");
|
|
23959
23993
|
try {
|
|
23960
23994
|
const wanted = `${marker.session}.jsonl`.toLowerCase();
|
|
23961
23995
|
const pending = [root];
|
|
23962
23996
|
while (pending.length) {
|
|
23963
23997
|
const dir = pending.pop();
|
|
23964
|
-
for (const entry of (0,
|
|
23965
|
-
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);
|
|
23966
24000
|
if (entry.isDirectory()) pending.push(path2);
|
|
23967
24001
|
else if (entry.isFile() && entry.name.toLowerCase() === wanted) {
|
|
23968
|
-
return remember(now - (0,
|
|
24002
|
+
return remember(now - (0, import_node_fs24.statSync)(path2).mtimeMs <= CLAIM_SESSION_ACTIVITY_MS ? "live" : "dead");
|
|
23969
24003
|
}
|
|
23970
24004
|
}
|
|
23971
24005
|
}
|
|
@@ -24623,6 +24657,7 @@ function buildCommand(cmd, path2) {
|
|
|
24623
24657
|
path: path2,
|
|
24624
24658
|
...aliases.length ? { aliases: [...aliases] } : {},
|
|
24625
24659
|
house,
|
|
24660
|
+
canonical: canonicalPathFor(path2) ?? path2,
|
|
24626
24661
|
arguments: cmd.registeredArguments.map(buildArgument),
|
|
24627
24662
|
// A hand-parsed command registers no Commander options, so its declared set is merged in (#3682).
|
|
24628
24663
|
options: [...cmd.options.map(buildOption), ...readDeclaredOptions(cmd)],
|
|
@@ -24864,8 +24899,8 @@ function consolidateCommandNamespaces(program3) {
|
|
|
24864
24899
|
}
|
|
24865
24900
|
|
|
24866
24901
|
// src/pi-plugin-registration.ts
|
|
24867
|
-
var
|
|
24868
|
-
var
|
|
24902
|
+
var import_node_fs25 = require("node:fs");
|
|
24903
|
+
var import_node_path23 = require("node:path");
|
|
24869
24904
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
24870
24905
|
|
|
24871
24906
|
// src/plugin-cache-prune.ts
|
|
@@ -25123,48 +25158,48 @@ function newestExistingPiPlugin(home) {
|
|
|
25123
25158
|
const cacheRoot = pluginCacheRoot(home);
|
|
25124
25159
|
let names;
|
|
25125
25160
|
try {
|
|
25126
|
-
names = (0,
|
|
25161
|
+
names = (0, import_node_fs25.readdirSync)(cacheRoot);
|
|
25127
25162
|
} catch {
|
|
25128
25163
|
return void 0;
|
|
25129
25164
|
}
|
|
25130
25165
|
for (const version of names.filter(isVersionDirName).sort((a, b) => compareVersions(b, a))) {
|
|
25131
|
-
const candidate = (0,
|
|
25132
|
-
if ((0,
|
|
25166
|
+
const candidate = (0, import_node_path23.join)(cacheRoot, version, ".pi-plugin");
|
|
25167
|
+
if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
|
|
25133
25168
|
}
|
|
25134
25169
|
return void 0;
|
|
25135
25170
|
}
|
|
25136
25171
|
function expectedPiPluginPath(home, env, installedVersion) {
|
|
25137
25172
|
const root = env.CLAUDE_PLUGIN_ROOT?.trim();
|
|
25138
|
-
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0,
|
|
25173
|
+
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path23.join)(root, ".pi-plugin");
|
|
25139
25174
|
const version = installedVersion ?? runningPluginVersion(env);
|
|
25140
25175
|
if (version) {
|
|
25141
|
-
const pinned = (0,
|
|
25142
|
-
if ((0,
|
|
25176
|
+
const pinned = (0, import_node_path23.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
|
|
25177
|
+
if ((0, import_node_fs25.existsSync)(pinned)) return pinned;
|
|
25143
25178
|
}
|
|
25144
25179
|
return newestExistingPiPlugin(home);
|
|
25145
25180
|
}
|
|
25146
25181
|
function agentDirs(home, env = process.env) {
|
|
25147
25182
|
const override = env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
|
|
25148
25183
|
if (override) return [override];
|
|
25149
|
-
const jerv = (0,
|
|
25150
|
-
const pi = (0,
|
|
25151
|
-
if (!(0,
|
|
25184
|
+
const jerv = (0, import_node_path23.join)(home, ".jerv", "agent");
|
|
25185
|
+
const pi = (0, import_node_path23.join)(home, ".pi", "agent");
|
|
25186
|
+
if (!(0, import_node_fs25.existsSync)(jerv) && !(0, import_node_fs25.existsSync)(pi)) return [];
|
|
25152
25187
|
const dirs = [jerv];
|
|
25153
|
-
if ((0,
|
|
25188
|
+
if ((0, import_node_fs25.existsSync)(pi) && pi !== jerv) dirs.push(pi);
|
|
25154
25189
|
return dirs;
|
|
25155
25190
|
}
|
|
25156
25191
|
function settingsPath(agentDir) {
|
|
25157
|
-
return (0,
|
|
25192
|
+
return (0, import_node_path23.join)(agentDir, "settings.json");
|
|
25158
25193
|
}
|
|
25159
25194
|
function readPiPluginState(home, env, installedVersion) {
|
|
25160
25195
|
const dirs = agentDirs(home, env);
|
|
25161
25196
|
if (dirs.length === 0) return void 0;
|
|
25162
25197
|
const expectedPath = expectedPiPluginPath(home, env, installedVersion);
|
|
25163
25198
|
if (!expectedPath) return void 0;
|
|
25164
|
-
const file = dirs.map(settingsPath).find((p) => (0,
|
|
25165
|
-
if (!(0,
|
|
25199
|
+
const file = dirs.map(settingsPath).find((p) => (0, import_node_fs25.existsSync)(p)) ?? settingsPath(dirs[0]);
|
|
25200
|
+
if (!(0, import_node_fs25.existsSync)(file)) return { expectedPath, settingsReadable: true };
|
|
25166
25201
|
try {
|
|
25167
|
-
const parsed = JSON.parse((0,
|
|
25202
|
+
const parsed = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf8"));
|
|
25168
25203
|
const packages = Array.isArray(parsed.packages) ? parsed.packages : [];
|
|
25169
25204
|
return { expectedPath, registeredPath: packages.find((p) => typeof p === "string" && isMmiPiPackage(p)), settingsReadable: true };
|
|
25170
25205
|
} catch {
|
|
@@ -25188,20 +25223,20 @@ function acquirePiSettingsLock2(settingsFile) {
|
|
|
25188
25223
|
return void 0;
|
|
25189
25224
|
}
|
|
25190
25225
|
function atomicWriteSettings(file, body) {
|
|
25191
|
-
(0,
|
|
25226
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(file), { recursive: true });
|
|
25192
25227
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
25193
|
-
(0,
|
|
25228
|
+
(0, import_node_fs25.writeFileSync)(tmp, body, "utf8");
|
|
25194
25229
|
try {
|
|
25195
|
-
(0,
|
|
25230
|
+
(0, import_node_fs25.renameSync)(tmp, file);
|
|
25196
25231
|
} catch (renameError) {
|
|
25197
|
-
(0,
|
|
25232
|
+
(0, import_node_fs25.rmSync)(tmp, { force: true });
|
|
25198
25233
|
throw renameError;
|
|
25199
25234
|
}
|
|
25200
25235
|
}
|
|
25201
25236
|
function healOneAgentDir(agentDir, expectedPath) {
|
|
25202
25237
|
const file = settingsPath(agentDir);
|
|
25203
|
-
const release = (0,
|
|
25204
|
-
if ((0,
|
|
25238
|
+
const release = (0, import_node_fs25.existsSync)(file) ? acquirePiSettingsLock2(file) : void 0;
|
|
25239
|
+
if ((0, import_node_fs25.existsSync)(file) && !release) {
|
|
25205
25240
|
return {
|
|
25206
25241
|
ok: false,
|
|
25207
25242
|
detail: `Pi's settings lock (${file}.lock) is held by another process; nothing written, retry on the next doctor run`,
|
|
@@ -25210,9 +25245,9 @@ function healOneAgentDir(agentDir, expectedPath) {
|
|
|
25210
25245
|
}
|
|
25211
25246
|
try {
|
|
25212
25247
|
let parsed = {};
|
|
25213
|
-
if ((0,
|
|
25248
|
+
if ((0, import_node_fs25.existsSync)(file)) {
|
|
25214
25249
|
try {
|
|
25215
|
-
const raw = JSON.parse((0,
|
|
25250
|
+
const raw = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf8"));
|
|
25216
25251
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25217
25252
|
return { ok: false, detail: "settings.json unreadable \u2014 nothing written (fail closed)" };
|
|
25218
25253
|
}
|
|
@@ -25264,20 +25299,20 @@ function healPiPluginRegistration(home, env, installedVersion) {
|
|
|
25264
25299
|
}
|
|
25265
25300
|
|
|
25266
25301
|
// src/claude-binary-doctor.ts
|
|
25267
|
-
var
|
|
25302
|
+
var import_node_fs27 = require("node:fs");
|
|
25268
25303
|
var import_node_os11 = require("node:os");
|
|
25269
|
-
var
|
|
25304
|
+
var import_node_path25 = require("node:path");
|
|
25270
25305
|
|
|
25271
25306
|
// src/jerv-cli-spawn.ts
|
|
25272
|
-
var
|
|
25307
|
+
var import_node_fs26 = require("node:fs");
|
|
25273
25308
|
var import_node_os10 = require("node:os");
|
|
25274
|
-
var
|
|
25309
|
+
var import_node_path24 = require("node:path");
|
|
25275
25310
|
var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
|
|
25276
25311
|
var POSIX_NAMES = ["jerv-cli"];
|
|
25277
|
-
var JERV_CLI_ENTRY = (0,
|
|
25312
|
+
var JERV_CLI_ENTRY = (0, import_node_path24.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
25278
25313
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
25279
25314
|
if (platform2 !== "win32") {
|
|
25280
|
-
return pathEnv.split(
|
|
25315
|
+
return pathEnv.split(import_node_path24.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
25281
25316
|
}
|
|
25282
25317
|
if (pathEnv.includes(";")) {
|
|
25283
25318
|
return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
|
|
@@ -25310,10 +25345,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os10.hom
|
|
|
25310
25345
|
push(normalizeSpawnPathEntry(entry, platform2));
|
|
25311
25346
|
}
|
|
25312
25347
|
if (platform2 === "win32") {
|
|
25313
|
-
if (env.APPDATA) push((0,
|
|
25314
|
-
if (env.LOCALAPPDATA) push((0,
|
|
25348
|
+
if (env.APPDATA) push((0, import_node_path24.join)(env.APPDATA, "npm"));
|
|
25349
|
+
if (env.LOCALAPPDATA) push((0, import_node_path24.join)(env.LOCALAPPDATA, "npm"));
|
|
25315
25350
|
} else {
|
|
25316
|
-
push((0,
|
|
25351
|
+
push((0, import_node_path24.join)(home, ".local", "bin"));
|
|
25317
25352
|
}
|
|
25318
25353
|
return out;
|
|
25319
25354
|
}
|
|
@@ -25321,23 +25356,23 @@ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os10.ho
|
|
|
25321
25356
|
const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
|
|
25322
25357
|
const out = [];
|
|
25323
25358
|
for (const dir of jervCliCandidateDirs(env, home, platform2)) {
|
|
25324
|
-
for (const name of names) out.push((0,
|
|
25359
|
+
for (const name of names) out.push((0, import_node_path24.join)(dir, name));
|
|
25325
25360
|
}
|
|
25326
25361
|
return out;
|
|
25327
25362
|
}
|
|
25328
|
-
function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homedir)(), platform2 = process.platform, exists =
|
|
25363
|
+
function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homedir)(), platform2 = process.platform, exists = import_node_fs26.existsSync) {
|
|
25329
25364
|
for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
|
|
25330
25365
|
if (exists(candidate)) return candidate;
|
|
25331
25366
|
}
|
|
25332
25367
|
return void 0;
|
|
25333
25368
|
}
|
|
25334
|
-
function resolveJervCliNodeEntry(shimPath, exists =
|
|
25335
|
-
const entry = (0,
|
|
25369
|
+
function resolveJervCliNodeEntry(shimPath, exists = import_node_fs26.existsSync) {
|
|
25370
|
+
const entry = (0, import_node_path24.join)((0, import_node_path24.dirname)(shimPath), JERV_CLI_ENTRY);
|
|
25336
25371
|
return exists(entry) ? entry : void 0;
|
|
25337
25372
|
}
|
|
25338
25373
|
function jervCliExecFileArgs(args, opts = {}) {
|
|
25339
25374
|
const platform2 = opts.platform ?? process.platform;
|
|
25340
|
-
const exists = opts.exists ??
|
|
25375
|
+
const exists = opts.exists ?? import_node_fs26.existsSync;
|
|
25341
25376
|
const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os10.homedir)(), platform2, exists);
|
|
25342
25377
|
if (resolved) {
|
|
25343
25378
|
const entry = resolveJervCliNodeEntry(resolved, exists);
|
|
@@ -25427,26 +25462,26 @@ function globalNodeModulesRoots(host) {
|
|
|
25427
25462
|
out.push(dir);
|
|
25428
25463
|
};
|
|
25429
25464
|
const prefix = env.npm_config_prefix?.trim();
|
|
25430
|
-
if (prefix) push(platform2 === "win32" ? (0,
|
|
25465
|
+
if (prefix) push(platform2 === "win32" ? (0, import_node_path25.join)(prefix, "node_modules") : (0, import_node_path25.join)(prefix, "lib", "node_modules"));
|
|
25431
25466
|
for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os11.homedir)(), platform2)) {
|
|
25432
|
-
push((0,
|
|
25433
|
-
push((0,
|
|
25467
|
+
push((0, import_node_path25.join)(dir, "node_modules"));
|
|
25468
|
+
push((0, import_node_path25.join)((0, import_node_path25.dirname)(dir), "lib", "node_modules"));
|
|
25434
25469
|
}
|
|
25435
25470
|
return out;
|
|
25436
25471
|
}
|
|
25437
25472
|
function readHead(path2) {
|
|
25438
25473
|
let fd;
|
|
25439
25474
|
try {
|
|
25440
|
-
fd = (0,
|
|
25475
|
+
fd = (0, import_node_fs27.openSync)(path2, "r");
|
|
25441
25476
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
25442
|
-
const read = (0,
|
|
25477
|
+
const read = (0, import_node_fs27.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
25443
25478
|
return buffer.subarray(0, read);
|
|
25444
25479
|
} catch {
|
|
25445
25480
|
return void 0;
|
|
25446
25481
|
} finally {
|
|
25447
25482
|
if (fd !== void 0) {
|
|
25448
25483
|
try {
|
|
25449
|
-
(0,
|
|
25484
|
+
(0, import_node_fs27.closeSync)(fd);
|
|
25450
25485
|
} catch {
|
|
25451
25486
|
}
|
|
25452
25487
|
}
|
|
@@ -25454,7 +25489,7 @@ function readHead(path2) {
|
|
|
25454
25489
|
}
|
|
25455
25490
|
function fileBytes(path2) {
|
|
25456
25491
|
try {
|
|
25457
|
-
return (0,
|
|
25492
|
+
return (0, import_node_fs27.statSync)(path2).size;
|
|
25458
25493
|
} catch {
|
|
25459
25494
|
return void 0;
|
|
25460
25495
|
}
|
|
@@ -25468,17 +25503,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25468
25503
|
const arch = host.arch ?? process.arch;
|
|
25469
25504
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
25470
25505
|
if (!magic) return void 0;
|
|
25471
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0,
|
|
25506
|
+
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")));
|
|
25472
25507
|
if (!packageRoot) return void 0;
|
|
25473
25508
|
const keys = platformPackageKeys(platform2, arch);
|
|
25474
25509
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
25475
25510
|
let manifest;
|
|
25476
25511
|
try {
|
|
25477
|
-
manifest = JSON.parse((0,
|
|
25512
|
+
manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path25.join)(packageRoot, "package.json"), "utf8"));
|
|
25478
25513
|
} catch (e) {
|
|
25479
25514
|
return {
|
|
25480
25515
|
state: "unreadable",
|
|
25481
|
-
binPath: (0,
|
|
25516
|
+
binPath: (0, import_node_path25.join)(packageRoot, "package.json"),
|
|
25482
25517
|
expectedMagic: magic.name,
|
|
25483
25518
|
platformPackage: fallbackPackage,
|
|
25484
25519
|
error: `package.json could not be read \u2014 ${e.message}`
|
|
@@ -25495,17 +25530,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25495
25530
|
error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
|
|
25496
25531
|
};
|
|
25497
25532
|
}
|
|
25498
|
-
const binPath = (0,
|
|
25499
|
-
const binName = (0,
|
|
25533
|
+
const binPath = (0, import_node_path25.join)(packageRoot, binRelative);
|
|
25534
|
+
const binName = (0, import_node_path25.basename)(binRelative);
|
|
25500
25535
|
const optional = manifest.optionalDependencies;
|
|
25501
25536
|
const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
|
|
25502
25537
|
const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
|
|
25503
25538
|
if (published.length === 0) return void 0;
|
|
25504
25539
|
const binIn = (name) => [
|
|
25505
|
-
(0,
|
|
25506
|
-
(0,
|
|
25540
|
+
(0, import_node_path25.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
25541
|
+
(0, import_node_path25.join)((0, import_node_path25.dirname)((0, import_node_path25.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
25507
25542
|
];
|
|
25508
|
-
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0,
|
|
25543
|
+
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
|
|
25509
25544
|
const platformPackage = found?.name ?? published[0];
|
|
25510
25545
|
let source;
|
|
25511
25546
|
let sourceProblem;
|
|
@@ -25516,7 +25551,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25516
25551
|
} else {
|
|
25517
25552
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
25518
25553
|
}
|
|
25519
|
-
if (!(0,
|
|
25554
|
+
if (!(0, import_node_fs27.existsSync)(binPath)) {
|
|
25520
25555
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
25521
25556
|
}
|
|
25522
25557
|
const head = readHead(binPath);
|
|
@@ -25559,9 +25594,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25559
25594
|
const platform2 = host.platform ?? process.platform;
|
|
25560
25595
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
25561
25596
|
let renamed = false;
|
|
25562
|
-
if ((0,
|
|
25597
|
+
if ((0, import_node_fs27.existsSync)(probe.binPath)) {
|
|
25563
25598
|
try {
|
|
25564
|
-
(0,
|
|
25599
|
+
(0, import_node_fs27.renameSync)(probe.binPath, aside);
|
|
25565
25600
|
renamed = true;
|
|
25566
25601
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
25567
25602
|
} catch (e) {
|
|
@@ -25570,12 +25605,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25570
25605
|
}
|
|
25571
25606
|
try {
|
|
25572
25607
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
25573
|
-
(0,
|
|
25574
|
-
if (platform2 !== "win32") (0,
|
|
25608
|
+
(0, import_node_fs27.copyFileSync)(probe.source.path, probe.binPath);
|
|
25609
|
+
if (platform2 !== "win32") (0, import_node_fs27.chmodSync)(probe.binPath, 493);
|
|
25575
25610
|
} catch (e) {
|
|
25576
25611
|
if (renamed) {
|
|
25577
25612
|
try {
|
|
25578
|
-
(0,
|
|
25613
|
+
(0, import_node_fs27.renameSync)(aside, probe.binPath);
|
|
25579
25614
|
} catch {
|
|
25580
25615
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
25581
25616
|
}
|
|
@@ -25589,7 +25624,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25589
25624
|
let kept = false;
|
|
25590
25625
|
if (renamed) {
|
|
25591
25626
|
try {
|
|
25592
|
-
(0,
|
|
25627
|
+
(0, import_node_fs27.rmSync)(aside);
|
|
25593
25628
|
} catch {
|
|
25594
25629
|
kept = true;
|
|
25595
25630
|
}
|
|
@@ -26923,8 +26958,8 @@ async function announceRelease(deps, args) {
|
|
|
26923
26958
|
// src/repo-index.ts
|
|
26924
26959
|
var import_node_crypto4 = require("node:crypto");
|
|
26925
26960
|
var import_node_child_process13 = require("node:child_process");
|
|
26926
|
-
var
|
|
26927
|
-
var
|
|
26961
|
+
var import_node_fs28 = require("node:fs");
|
|
26962
|
+
var import_node_path26 = require("node:path");
|
|
26928
26963
|
var REPO_INDEX_SCHEMA = 1;
|
|
26929
26964
|
var HARD_DENY = [
|
|
26930
26965
|
/(^|\/)\.env(\.|$)/i,
|
|
@@ -27049,11 +27084,11 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27049
27084
|
}
|
|
27050
27085
|
for (const rel of readmes) {
|
|
27051
27086
|
if (isHardDeniedPath(rel)) continue;
|
|
27052
|
-
const abs = (0,
|
|
27053
|
-
if (!(0,
|
|
27087
|
+
const abs = (0, import_node_path26.join)(cwd, ...rel.split("/"));
|
|
27088
|
+
if (!(0, import_node_fs28.existsSync)(abs)) continue;
|
|
27054
27089
|
let text;
|
|
27055
27090
|
try {
|
|
27056
|
-
text = (0,
|
|
27091
|
+
text = (0, import_node_fs28.readFileSync)(abs, "utf8");
|
|
27057
27092
|
} catch {
|
|
27058
27093
|
continue;
|
|
27059
27094
|
}
|
|
@@ -27066,7 +27101,7 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27066
27101
|
return hints;
|
|
27067
27102
|
}
|
|
27068
27103
|
function toPosix(p) {
|
|
27069
|
-
return p.split(
|
|
27104
|
+
return p.split(import_node_path26.sep).join("/");
|
|
27070
27105
|
}
|
|
27071
27106
|
function listCandidatePaths(cwd, exec = import_node_child_process13.execFileSync) {
|
|
27072
27107
|
try {
|
|
@@ -27088,11 +27123,11 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27088
27123
|
for (const rel of candidates) {
|
|
27089
27124
|
if (ignored.has(rel)) continue;
|
|
27090
27125
|
if (isHardDeniedPath(rel)) continue;
|
|
27091
|
-
const abs = (0,
|
|
27092
|
-
if (!(0,
|
|
27126
|
+
const abs = (0, import_node_path26.join)(cwd, ...rel.split("/"));
|
|
27127
|
+
if (!(0, import_node_fs28.existsSync)(abs)) continue;
|
|
27093
27128
|
let text;
|
|
27094
27129
|
try {
|
|
27095
|
-
text = (0,
|
|
27130
|
+
text = (0, import_node_fs28.readFileSync)(abs, "utf8");
|
|
27096
27131
|
} catch {
|
|
27097
27132
|
continue;
|
|
27098
27133
|
}
|
|
@@ -27117,16 +27152,16 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27117
27152
|
entries
|
|
27118
27153
|
};
|
|
27119
27154
|
const store = repoIndexStorePath(cwd);
|
|
27120
|
-
(0,
|
|
27121
|
-
(0,
|
|
27155
|
+
(0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(store), { recursive: true });
|
|
27156
|
+
(0, import_node_fs28.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
|
|
27122
27157
|
`, "utf8");
|
|
27123
27158
|
return projection;
|
|
27124
27159
|
}
|
|
27125
27160
|
function loadRepoIndex(cwd) {
|
|
27126
27161
|
const store = repoIndexStorePath(cwd);
|
|
27127
|
-
if (!(0,
|
|
27162
|
+
if (!(0, import_node_fs28.existsSync)(store)) return null;
|
|
27128
27163
|
try {
|
|
27129
|
-
const raw = JSON.parse((0,
|
|
27164
|
+
const raw = JSON.parse((0, import_node_fs28.readFileSync)(store, "utf8"));
|
|
27130
27165
|
if (raw?.schema !== REPO_INDEX_SCHEMA || !Array.isArray(raw.entries)) return null;
|
|
27131
27166
|
return raw;
|
|
27132
27167
|
} catch {
|
|
@@ -27198,7 +27233,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process13.execFileSync) {
|
|
|
27198
27233
|
if (m?.[1]) return m[1].toLowerCase();
|
|
27199
27234
|
} catch {
|
|
27200
27235
|
}
|
|
27201
|
-
return ((0,
|
|
27236
|
+
return ((0, import_node_path26.basename)(cwd) || "local").toLowerCase();
|
|
27202
27237
|
}
|
|
27203
27238
|
|
|
27204
27239
|
// src/repo-index-cloud-client.ts
|
|
@@ -27338,9 +27373,9 @@ async function gcRepoIndexCloud(deps) {
|
|
|
27338
27373
|
}
|
|
27339
27374
|
|
|
27340
27375
|
// src/repo-index-sync.ts
|
|
27341
|
-
var
|
|
27376
|
+
var import_node_fs29 = require("node:fs");
|
|
27342
27377
|
var import_node_os12 = require("node:os");
|
|
27343
|
-
var
|
|
27378
|
+
var import_node_path27 = require("node:path");
|
|
27344
27379
|
var import_node_child_process14 = require("node:child_process");
|
|
27345
27380
|
var MAX_EMBED_BACKFILL_ROUNDS = 40;
|
|
27346
27381
|
function normalizeRepo(raw) {
|
|
@@ -27384,7 +27419,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27384
27419
|
const failed = [];
|
|
27385
27420
|
const skipped = [];
|
|
27386
27421
|
for (const repo of repos) {
|
|
27387
|
-
const dir = (0,
|
|
27422
|
+
const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path27.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
|
|
27388
27423
|
try {
|
|
27389
27424
|
shallowClone(repo, dir, opts.githubToken);
|
|
27390
27425
|
const built = rebuildRepoIndex(dir, repo);
|
|
@@ -27434,7 +27469,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27434
27469
|
failed.push({ repo, error: e.message });
|
|
27435
27470
|
} finally {
|
|
27436
27471
|
try {
|
|
27437
|
-
(0,
|
|
27472
|
+
(0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
|
|
27438
27473
|
} catch {
|
|
27439
27474
|
}
|
|
27440
27475
|
}
|
|
@@ -27443,7 +27478,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27443
27478
|
}
|
|
27444
27479
|
|
|
27445
27480
|
// src/repo-index-health.ts
|
|
27446
|
-
var
|
|
27481
|
+
var import_node_fs30 = require("node:fs");
|
|
27447
27482
|
|
|
27448
27483
|
// testdata/repo-index-golden-queries.json
|
|
27449
27484
|
var repo_index_golden_queries_default = {
|
|
@@ -27485,7 +27520,7 @@ function assertGoldenSuite(raw, source) {
|
|
|
27485
27520
|
function loadGoldenSuite(path2) {
|
|
27486
27521
|
let text;
|
|
27487
27522
|
try {
|
|
27488
|
-
text = (0,
|
|
27523
|
+
text = (0, import_node_fs30.readFileSync)(path2, "utf8");
|
|
27489
27524
|
} catch (e) {
|
|
27490
27525
|
throw new Error(`golden suite unreadable at ${path2}: ${e.message}`);
|
|
27491
27526
|
}
|
|
@@ -27631,8 +27666,8 @@ async function runRepoIndexHealth(opts) {
|
|
|
27631
27666
|
|
|
27632
27667
|
// src/spawn-policy-core.ts
|
|
27633
27668
|
var import_node_child_process15 = require("node:child_process");
|
|
27634
|
-
var
|
|
27635
|
-
var
|
|
27669
|
+
var import_node_fs31 = require("node:fs");
|
|
27670
|
+
var import_node_path28 = require("node:path");
|
|
27636
27671
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
27637
27672
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
27638
27673
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -27718,7 +27753,7 @@ function runSpawnPolicy(root) {
|
|
|
27718
27753
|
for (const file of files) {
|
|
27719
27754
|
let raw;
|
|
27720
27755
|
try {
|
|
27721
|
-
raw = (0,
|
|
27756
|
+
raw = (0, import_node_fs31.readFileSync)((0, import_node_path28.join)(root, file), "utf8");
|
|
27722
27757
|
} catch {
|
|
27723
27758
|
continue;
|
|
27724
27759
|
}
|
|
@@ -27736,8 +27771,8 @@ function runSpawnPolicy(root) {
|
|
|
27736
27771
|
|
|
27737
27772
|
// src/test-policy-core.ts
|
|
27738
27773
|
var import_node_child_process16 = require("node:child_process");
|
|
27739
|
-
var
|
|
27740
|
-
var
|
|
27774
|
+
var import_node_fs32 = require("node:fs");
|
|
27775
|
+
var import_node_path29 = require("node:path");
|
|
27741
27776
|
var POLICY_FILE = "test-policy.json";
|
|
27742
27777
|
var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
27743
27778
|
var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
|
|
@@ -27790,7 +27825,7 @@ function isTestPath(path2) {
|
|
|
27790
27825
|
return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
|
|
27791
27826
|
}
|
|
27792
27827
|
function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
27793
|
-
const raw = readFile9((0,
|
|
27828
|
+
const raw = readFile9((0, import_node_path29.join)(root, POLICY_FILE));
|
|
27794
27829
|
if (raw == null) return { mandatory: [], declared: false };
|
|
27795
27830
|
try {
|
|
27796
27831
|
return { ...JSON.parse(raw), declared: true };
|
|
@@ -27800,7 +27835,7 @@ function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
|
27800
27835
|
}
|
|
27801
27836
|
function readFileOrNull2(path2) {
|
|
27802
27837
|
try {
|
|
27803
|
-
return (0,
|
|
27838
|
+
return (0, import_node_fs32.readFileSync)(path2, "utf8");
|
|
27804
27839
|
} catch {
|
|
27805
27840
|
return null;
|
|
27806
27841
|
}
|
|
@@ -27827,12 +27862,12 @@ function classify(changed, policy, present = () => false) {
|
|
|
27827
27862
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
27828
27863
|
return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
|
|
27829
27864
|
}
|
|
27830
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
27831
|
-
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0,
|
|
27865
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
27866
|
+
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path29.join)(root, p)));
|
|
27832
27867
|
}
|
|
27833
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
27868
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
27834
27869
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
27835
|
-
return [...new Set(declared)].filter((p) => !exists((0,
|
|
27870
|
+
return [...new Set(declared)].filter((p) => !exists((0, import_node_path29.join)(root, p)));
|
|
27836
27871
|
}
|
|
27837
27872
|
function evaluate(changed, policy, present = () => false) {
|
|
27838
27873
|
const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
|
|
@@ -28014,13 +28049,13 @@ function changedFilesSince(base, cwd) {
|
|
|
28014
28049
|
}
|
|
28015
28050
|
function runTestPolicy(root, deps = {}) {
|
|
28016
28051
|
const policy = deps.policy ?? loadPolicy(root);
|
|
28017
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
28052
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs32.existsSync)(path2));
|
|
28018
28053
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
28019
28054
|
const base = deps.changed ? "(injected)" : resolveBase(root, deps.base);
|
|
28020
28055
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
28021
28056
|
const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
|
|
28022
28057
|
const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride(base, root) : { override: null, refusals: [] };
|
|
28023
|
-
const present = (path2) => exists((0,
|
|
28058
|
+
const present = (path2) => exists((0, import_node_path29.join)(root, path2));
|
|
28024
28059
|
const removedByThisDiff = removedPaths(changed);
|
|
28025
28060
|
const staleFindings = [];
|
|
28026
28061
|
const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
|
|
@@ -28058,8 +28093,8 @@ function runTestPolicy(root, deps = {}) {
|
|
|
28058
28093
|
}
|
|
28059
28094
|
|
|
28060
28095
|
// src/project-info-sync.ts
|
|
28061
|
-
var
|
|
28062
|
-
var
|
|
28096
|
+
var import_node_fs33 = require("node:fs");
|
|
28097
|
+
var import_node_path30 = require("node:path");
|
|
28063
28098
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
28064
28099
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
28065
28100
|
projectV2 { id }
|
|
@@ -28104,14 +28139,14 @@ function sharedName(entries, fallback) {
|
|
|
28104
28139
|
}
|
|
28105
28140
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
28106
28141
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
28107
|
-
const readmePath = (0,
|
|
28108
|
-
if (!(0,
|
|
28142
|
+
const readmePath = (0, import_node_path30.join)(repoRoot2, "README.md");
|
|
28143
|
+
if (!(0, import_node_fs33.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
28109
28144
|
const entries = entriesFor(project2, projects);
|
|
28110
28145
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
28111
28146
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
28112
28147
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
28113
28148
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
28114
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
28149
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs33.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
28115
28150
|
const lines = [
|
|
28116
28151
|
`# ${projectName}`,
|
|
28117
28152
|
"",
|
|
@@ -28130,8 +28165,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
28130
28165
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
28131
28166
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
28132
28167
|
const orgDocs = [
|
|
28133
|
-
(0,
|
|
28134
|
-
(0,
|
|
28168
|
+
(0, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
|
|
28169
|
+
(0, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
|
|
28135
28170
|
].filter(Boolean);
|
|
28136
28171
|
if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
|
|
28137
28172
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
|
|
@@ -28916,8 +28951,8 @@ function writeError(res) {
|
|
|
28916
28951
|
}
|
|
28917
28952
|
|
|
28918
28953
|
// src/secrets-commands.ts
|
|
28919
|
-
var
|
|
28920
|
-
var
|
|
28954
|
+
var import_node_fs34 = require("node:fs");
|
|
28955
|
+
var import_node_path31 = require("node:path");
|
|
28921
28956
|
var import_node_os13 = require("node:os");
|
|
28922
28957
|
|
|
28923
28958
|
// src/secrets-diff.ts
|
|
@@ -29020,18 +29055,18 @@ function collectMap(value, previous = []) {
|
|
|
29020
29055
|
return [...previous, value];
|
|
29021
29056
|
}
|
|
29022
29057
|
async function decryptRailsCredentials(input) {
|
|
29023
|
-
const appDir = (0,
|
|
29058
|
+
const appDir = (0, import_node_path31.resolve)(input.appDir ?? process.cwd());
|
|
29024
29059
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
29025
29060
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
29026
|
-
const credentialsPath = (0,
|
|
29027
|
-
const masterKeyPath = (0,
|
|
29061
|
+
const credentialsPath = (0, import_node_path31.resolve)(appDir, credentialsFile);
|
|
29062
|
+
const masterKeyPath = (0, import_node_path31.resolve)(appDir, masterKeyFile);
|
|
29028
29063
|
const env = {
|
|
29029
29064
|
...process.env,
|
|
29030
29065
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
29031
29066
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
29032
29067
|
};
|
|
29033
|
-
if ((0,
|
|
29034
|
-
env.RAILS_MASTER_KEY = (0,
|
|
29068
|
+
if ((0, import_node_fs34.existsSync)(masterKeyPath)) {
|
|
29069
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs34.readFileSync)(masterKeyPath, "utf8").trim();
|
|
29035
29070
|
}
|
|
29036
29071
|
const script = [
|
|
29037
29072
|
'require "json"',
|
|
@@ -29041,9 +29076,9 @@ async function decryptRailsCredentials(input) {
|
|
|
29041
29076
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
29042
29077
|
"puts JSON.generate(config.config)"
|
|
29043
29078
|
].join("\n");
|
|
29044
|
-
const scriptDir = (0,
|
|
29045
|
-
const scriptPath = (0,
|
|
29046
|
-
(0,
|
|
29079
|
+
const scriptDir = (0, import_node_fs34.mkdtempSync)((0, import_node_path31.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
|
|
29080
|
+
const scriptPath = (0, import_node_path31.join)(scriptDir, "decrypt.rb");
|
|
29081
|
+
(0, import_node_fs34.writeFileSync)(scriptPath, script, "utf8");
|
|
29047
29082
|
try {
|
|
29048
29083
|
const args = ["exec", "ruby", scriptPath];
|
|
29049
29084
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -29055,7 +29090,7 @@ async function decryptRailsCredentials(input) {
|
|
|
29055
29090
|
});
|
|
29056
29091
|
return JSON.parse(stdout);
|
|
29057
29092
|
} finally {
|
|
29058
|
-
(0,
|
|
29093
|
+
(0, import_node_fs34.rmSync)(scriptDir, { recursive: true, force: true });
|
|
29059
29094
|
}
|
|
29060
29095
|
}
|
|
29061
29096
|
async function readSecretStdin() {
|
|
@@ -29145,7 +29180,7 @@ function registerSecretsCommands(program3) {
|
|
|
29145
29180
|
let body;
|
|
29146
29181
|
if (o.file) {
|
|
29147
29182
|
try {
|
|
29148
|
-
body = (0,
|
|
29183
|
+
body = (0, import_node_fs34.readFileSync)((0, import_node_path31.resolve)(o.file), "utf8");
|
|
29149
29184
|
} catch (e) {
|
|
29150
29185
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
29151
29186
|
}
|
|
@@ -29250,7 +29285,7 @@ function registerSecretsCommands(program3) {
|
|
|
29250
29285
|
{
|
|
29251
29286
|
...d,
|
|
29252
29287
|
decryptRailsCredentials,
|
|
29253
|
-
removeFile: (path2) => (0,
|
|
29288
|
+
removeFile: (path2) => (0, import_node_fs34.unlinkSync)((0, import_node_path31.resolve)(o.appDir ?? process.cwd(), path2))
|
|
29254
29289
|
},
|
|
29255
29290
|
{
|
|
29256
29291
|
repo: o.repo,
|
|
@@ -29455,7 +29490,7 @@ function emitCliCallTelemetry(command) {
|
|
|
29455
29490
|
}
|
|
29456
29491
|
|
|
29457
29492
|
// src/box-commands.ts
|
|
29458
|
-
var
|
|
29493
|
+
var import_node_fs35 = require("node:fs");
|
|
29459
29494
|
|
|
29460
29495
|
// src/box.ts
|
|
29461
29496
|
var BOX_KEYS = {
|
|
@@ -29658,7 +29693,7 @@ function registerBoxCommands(program3) {
|
|
|
29658
29693
|
}
|
|
29659
29694
|
if (o.json) console.log(JSON.stringify({ box: found, incomplete }, null, 2));
|
|
29660
29695
|
else if (o.ssh && o.script) {
|
|
29661
|
-
(0,
|
|
29696
|
+
(0, import_node_fs35.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
|
|
29662
29697
|
console.log(`wrote ${o.script} \u2014 run: bash "${o.script}"`);
|
|
29663
29698
|
} else if (o.ssh) console.log(`${formatSshRecipe(found)}
|
|
29664
29699
|
${SSH_RECIPE_AGENT_NOTE}`);
|
|
@@ -29977,7 +30012,7 @@ function registerSchedulesCommands(program3) {
|
|
|
29977
30012
|
|
|
29978
30013
|
// src/schedules-lift-command.ts
|
|
29979
30014
|
var import_promises6 = require("node:fs/promises");
|
|
29980
|
-
var
|
|
30015
|
+
var import_node_path32 = require("node:path");
|
|
29981
30016
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
29982
30017
|
var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
|
|
29983
30018
|
var SchedulesLiftUsageError = class extends Error {
|
|
@@ -30004,7 +30039,7 @@ async function readWorkflowFiles(dir) {
|
|
|
30004
30039
|
const files = [];
|
|
30005
30040
|
for (const name of names.sort()) {
|
|
30006
30041
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
30007
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0,
|
|
30042
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0, import_node_path32.join)(dir, name), "utf8") });
|
|
30008
30043
|
}
|
|
30009
30044
|
return files;
|
|
30010
30045
|
}
|
|
@@ -30152,9 +30187,9 @@ function registerEdgeCommands(program3) {
|
|
|
30152
30187
|
}
|
|
30153
30188
|
|
|
30154
30189
|
// src/bootstrap-commands.ts
|
|
30155
|
-
var
|
|
30190
|
+
var import_node_fs36 = require("node:fs");
|
|
30156
30191
|
var import_node_os14 = require("node:os");
|
|
30157
|
-
var
|
|
30192
|
+
var import_node_path33 = require("node:path");
|
|
30158
30193
|
|
|
30159
30194
|
// src/bootstrap-drift.ts
|
|
30160
30195
|
var import_node_crypto6 = require("node:crypto");
|
|
@@ -31034,13 +31069,13 @@ function registerBootstrapCommands(program3) {
|
|
|
31034
31069
|
client: defaultGitHubClient(),
|
|
31035
31070
|
projectMeta: meta,
|
|
31036
31071
|
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
31037
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
31072
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs36.existsSync)(path2) ? (0, import_node_fs36.readFileSync)(path2, "utf8") : null,
|
|
31038
31073
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
31039
31074
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
31040
31075
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
31041
31076
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
31042
31077
|
// sanction, which is the pre-#3664 behaviour.
|
|
31043
|
-
sanctionedAdmins: (0,
|
|
31078
|
+
sanctionedAdmins: (0, import_node_fs36.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs36.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
31044
31079
|
requiredGcpApis: (() => {
|
|
31045
31080
|
const v = meta?.requiredGcpApis;
|
|
31046
31081
|
if (Array.isArray(v)) return v;
|
|
@@ -31093,14 +31128,14 @@ function registerBootstrapCommands(program3) {
|
|
|
31093
31128
|
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 () => {
|
|
31094
31129
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
31095
31130
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31096
|
-
if (!(0,
|
|
31131
|
+
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`);
|
|
31097
31132
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31098
31133
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
31099
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31134
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31100
31135
|
const hubContents = /* @__PURE__ */ new Map();
|
|
31101
31136
|
for (const s of manifest.seeds) {
|
|
31102
31137
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
31103
|
-
hubContents.set(s.target, (0,
|
|
31138
|
+
hubContents.set(s.target, (0, import_node_fs36.existsSync)(s.target) ? (0, import_node_fs36.readFileSync)(s.target, "utf8") : null);
|
|
31104
31139
|
}
|
|
31105
31140
|
let targets;
|
|
31106
31141
|
let classOf = (_repo) => "deployable";
|
|
@@ -31179,10 +31214,10 @@ function registerBootstrapCommands(program3) {
|
|
|
31179
31214
|
return fail(`bootstrap apply: ${e.message}`);
|
|
31180
31215
|
}
|
|
31181
31216
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31182
|
-
if (!(0,
|
|
31217
|
+
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`);
|
|
31183
31218
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31184
31219
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
31185
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31220
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31186
31221
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
31187
31222
|
const slug = parsedRepo.slug;
|
|
31188
31223
|
const onlyTarget = o.only.trim();
|
|
@@ -31193,16 +31228,16 @@ function registerBootstrapCommands(program3) {
|
|
|
31193
31228
|
${known}`);
|
|
31194
31229
|
}
|
|
31195
31230
|
const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
|
|
31196
|
-
const readFile9 = (p) => (0,
|
|
31231
|
+
const readFile9 = (p) => (0, import_node_fs36.existsSync)(p) ? (0, import_node_fs36.readFileSync)(p, "utf8") : null;
|
|
31197
31232
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31198
31233
|
const putSeed = async (target, content, ref, sha) => {
|
|
31199
|
-
const tmp = (0,
|
|
31200
|
-
(0,
|
|
31234
|
+
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`);
|
|
31235
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
31201
31236
|
try {
|
|
31202
31237
|
await gh(contentPutInputArgs(repo, target, tmp));
|
|
31203
31238
|
} finally {
|
|
31204
31239
|
try {
|
|
31205
|
-
(0,
|
|
31240
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31206
31241
|
} catch {
|
|
31207
31242
|
}
|
|
31208
31243
|
}
|
|
@@ -31467,10 +31502,10 @@ LIVE apply to ${repo}:
|
|
|
31467
31502
|
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 () => {
|
|
31468
31503
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
31469
31504
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31470
|
-
if (!(0,
|
|
31505
|
+
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`);
|
|
31471
31506
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31472
31507
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
31473
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31508
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31474
31509
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31475
31510
|
if (!o.target) {
|
|
31476
31511
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -31479,8 +31514,8 @@ LIVE apply to ${repo}:
|
|
|
31479
31514
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
31480
31515
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no ownership:org + source:self seed in ${manifestPath}. Propagatable targets:
|
|
31481
31516
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
31482
|
-
if (!(0,
|
|
31483
|
-
const hubContent = (0,
|
|
31517
|
+
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`);
|
|
31518
|
+
const hubContent = (0, import_node_fs36.readFileSync)(seed.target, "utf8");
|
|
31484
31519
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
31485
31520
|
const cfg = await loadConfig();
|
|
31486
31521
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -31489,9 +31524,9 @@ LIVE apply to ${repo}:
|
|
|
31489
31524
|
}
|
|
31490
31525
|
const rosterRepos2 = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
31491
31526
|
let independentCount = rosterRepos2.length;
|
|
31492
|
-
if ((0,
|
|
31527
|
+
if ((0, import_node_fs36.existsSync)("projects.json")) {
|
|
31493
31528
|
try {
|
|
31494
|
-
const local = JSON.parse((0,
|
|
31529
|
+
const local = JSON.parse((0, import_node_fs36.readFileSync)("projects.json", "utf8"));
|
|
31495
31530
|
const localRepos = /* @__PURE__ */ new Set();
|
|
31496
31531
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
31497
31532
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -31607,13 +31642,13 @@ LIVE apply to ${repo}:
|
|
|
31607
31642
|
} catch {
|
|
31608
31643
|
existingSha = void 0;
|
|
31609
31644
|
}
|
|
31610
|
-
const tmp = (0,
|
|
31611
|
-
(0,
|
|
31645
|
+
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`);
|
|
31646
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
|
|
31612
31647
|
try {
|
|
31613
31648
|
await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
31614
31649
|
} finally {
|
|
31615
31650
|
try {
|
|
31616
|
-
(0,
|
|
31651
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31617
31652
|
} catch {
|
|
31618
31653
|
}
|
|
31619
31654
|
}
|
|
@@ -31671,10 +31706,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31671
31706
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
31672
31707
|
}
|
|
31673
31708
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31674
|
-
if (!(0,
|
|
31709
|
+
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)`);
|
|
31675
31710
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31676
31711
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
31677
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31712
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31678
31713
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31679
31714
|
if (!o.target) {
|
|
31680
31715
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -31691,10 +31726,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31691
31726
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31692
31727
|
let candidates;
|
|
31693
31728
|
if (o.record) {
|
|
31694
|
-
if (!(0,
|
|
31729
|
+
if (!(0, import_node_fs36.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
31695
31730
|
let parsed;
|
|
31696
31731
|
try {
|
|
31697
|
-
parsed = JSON.parse((0,
|
|
31732
|
+
parsed = JSON.parse((0, import_node_fs36.readFileSync)(o.record, "utf8"));
|
|
31698
31733
|
} catch (e) {
|
|
31699
31734
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
31700
31735
|
}
|
|
@@ -31763,13 +31798,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31763
31798
|
} catch {
|
|
31764
31799
|
existingSha = void 0;
|
|
31765
31800
|
}
|
|
31766
|
-
const tmp = (0,
|
|
31767
|
-
(0,
|
|
31801
|
+
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`);
|
|
31802
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
31768
31803
|
try {
|
|
31769
31804
|
await gh(contentPutInputArgs(repo, seed.target, tmp));
|
|
31770
31805
|
} finally {
|
|
31771
31806
|
try {
|
|
31772
|
-
(0,
|
|
31807
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31773
31808
|
} catch {
|
|
31774
31809
|
}
|
|
31775
31810
|
}
|
|
@@ -31791,12 +31826,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31791
31826
|
}
|
|
31792
31827
|
|
|
31793
31828
|
// src/stage-commands.ts
|
|
31794
|
-
var
|
|
31795
|
-
var
|
|
31829
|
+
var import_node_fs38 = require("node:fs");
|
|
31830
|
+
var import_node_path35 = require("node:path");
|
|
31796
31831
|
|
|
31797
31832
|
// src/port-registry.ts
|
|
31798
|
-
var
|
|
31799
|
-
var
|
|
31833
|
+
var import_node_fs37 = require("node:fs");
|
|
31834
|
+
var import_node_path34 = require("node:path");
|
|
31800
31835
|
|
|
31801
31836
|
// ../infra/port-geometry.mjs
|
|
31802
31837
|
var PORT_BLOCK = 100;
|
|
@@ -31810,8 +31845,8 @@ function nextPortBlock(registry2) {
|
|
|
31810
31845
|
return [base, base + PORT_SPAN];
|
|
31811
31846
|
}
|
|
31812
31847
|
function loadPortRegistry(path2) {
|
|
31813
|
-
if (!(0,
|
|
31814
|
-
const raw = JSON.parse((0,
|
|
31848
|
+
if (!(0, import_node_fs37.existsSync)(path2)) return {};
|
|
31849
|
+
const raw = JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8"));
|
|
31815
31850
|
const out = {};
|
|
31816
31851
|
for (const [key, value] of Object.entries(raw)) {
|
|
31817
31852
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -31825,9 +31860,9 @@ function ensurePortRange(repo, path2) {
|
|
|
31825
31860
|
const existing = registry2[repo];
|
|
31826
31861
|
if (existing) return existing;
|
|
31827
31862
|
const range = nextPortBlock(registry2);
|
|
31828
|
-
const raw = (0,
|
|
31863
|
+
const raw = (0, import_node_fs37.existsSync)(path2) ? JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8")) : {};
|
|
31829
31864
|
raw[repo] = range;
|
|
31830
|
-
(0,
|
|
31865
|
+
(0, import_node_fs37.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
|
|
31831
31866
|
return range;
|
|
31832
31867
|
}
|
|
31833
31868
|
function portCursorSeed(registry2) {
|
|
@@ -31849,22 +31884,22 @@ function existingPortRange(repo, registry2) {
|
|
|
31849
31884
|
return registry2[repo] ?? null;
|
|
31850
31885
|
}
|
|
31851
31886
|
function portRangeInfraAt(root, source) {
|
|
31852
|
-
const registryPath = (0,
|
|
31853
|
-
const ddbScriptPath = (0,
|
|
31854
|
-
if (!(0,
|
|
31887
|
+
const registryPath = (0, import_node_path34.join)(root, "infra", "port-ranges.json");
|
|
31888
|
+
const ddbScriptPath = (0, import_node_path34.join)(root, "infra", "port-ddb.mjs");
|
|
31889
|
+
if (!(0, import_node_fs37.existsSync)(registryPath) || !(0, import_node_fs37.existsSync)(ddbScriptPath)) return null;
|
|
31855
31890
|
return { root, source, registryPath, ddbScriptPath };
|
|
31856
31891
|
}
|
|
31857
31892
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
31858
31893
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
31859
31894
|
if (direct) return direct;
|
|
31860
|
-
for (let dir = cwd; ; dir = (0,
|
|
31861
|
-
const sibling = portRangeInfraAt((0,
|
|
31895
|
+
for (let dir = cwd; ; dir = (0, import_node_path34.dirname)(dir)) {
|
|
31896
|
+
const sibling = portRangeInfraAt((0, import_node_path34.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
31862
31897
|
if (sibling) return sibling;
|
|
31863
|
-
const parent = (0,
|
|
31898
|
+
const parent = (0, import_node_path34.dirname)(dir);
|
|
31864
31899
|
if (parent === dir) break;
|
|
31865
31900
|
}
|
|
31866
31901
|
if (packageDir) {
|
|
31867
|
-
const pkgRoot = (0,
|
|
31902
|
+
const pkgRoot = (0, import_node_path34.join)(packageDir, "..", "..");
|
|
31868
31903
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
31869
31904
|
if (pkgFrom) return pkgFrom;
|
|
31870
31905
|
}
|
|
@@ -32058,8 +32093,8 @@ function registerStageCommands(program3) {
|
|
|
32058
32093
|
const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
|
|
32059
32094
|
return decideStage({
|
|
32060
32095
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
32061
|
-
hasCompose: (0,
|
|
32062
|
-
hasEnvExample: (0,
|
|
32096
|
+
hasCompose: (0, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), "docker-compose.yml")),
|
|
32097
|
+
hasEnvExample: (0, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), ".env.example"))
|
|
32063
32098
|
});
|
|
32064
32099
|
}
|
|
32065
32100
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -32550,9 +32585,9 @@ function registerBoardCommands(program3) {
|
|
|
32550
32585
|
}
|
|
32551
32586
|
|
|
32552
32587
|
// src/merge-cleanup.ts
|
|
32553
|
-
var
|
|
32588
|
+
var import_node_fs39 = require("node:fs");
|
|
32554
32589
|
var import_promises8 = require("node:fs/promises");
|
|
32555
|
-
var
|
|
32590
|
+
var import_node_path37 = require("node:path");
|
|
32556
32591
|
var import_node_os15 = require("node:os");
|
|
32557
32592
|
var import_node_child_process18 = require("node:child_process");
|
|
32558
32593
|
|
|
@@ -32640,7 +32675,7 @@ function boardAdvanceFailureMessage(result) {
|
|
|
32640
32675
|
|
|
32641
32676
|
// src/deferred-registry-store.ts
|
|
32642
32677
|
var import_promises7 = require("node:fs/promises");
|
|
32643
|
-
var
|
|
32678
|
+
var import_node_path36 = require("node:path");
|
|
32644
32679
|
var sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
32645
32680
|
async function atomicWrite(target, contents) {
|
|
32646
32681
|
const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
@@ -32691,12 +32726,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
32691
32726
|
},
|
|
32692
32727
|
// Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
|
|
32693
32728
|
write: async (entries) => {
|
|
32694
|
-
await (0, import_promises7.mkdir)((0,
|
|
32729
|
+
await (0, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
|
|
32695
32730
|
await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
|
|
32696
32731
|
},
|
|
32697
32732
|
// Serialized read-modify-write under the repo-wide lock (#2846).
|
|
32698
32733
|
update: async (mutate) => {
|
|
32699
|
-
await (0, import_promises7.mkdir)((0,
|
|
32734
|
+
await (0, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
|
|
32700
32735
|
const deadline = Date.now() + opts.maxWaitMs;
|
|
32701
32736
|
for (; ; ) {
|
|
32702
32737
|
const guard = await acquireLock(lockPath, opts, deadline);
|
|
@@ -32847,7 +32882,7 @@ var defaultLeaseCloseExec = (_cmd, args) => execJervCli(args, { timeout: GIT_TIM
|
|
|
32847
32882
|
async function bestEffortLeaseClose(wtPath, exec = defaultLeaseCloseExec) {
|
|
32848
32883
|
const step = "close jerv worktree lease";
|
|
32849
32884
|
try {
|
|
32850
|
-
await exec("jerv-cli", ["lease", "close", "--ref", wtPath]);
|
|
32885
|
+
await exec("jerv-cli", ["cli", "lease", "close", "--ref", wtPath]);
|
|
32851
32886
|
return { step, status: "done" };
|
|
32852
32887
|
} catch (e) {
|
|
32853
32888
|
const err = e;
|
|
@@ -32867,7 +32902,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32867
32902
|
);
|
|
32868
32903
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
32869
32904
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
32870
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
32905
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path37.dirname)((0, import_node_path37.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
32871
32906
|
const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
|
|
32872
32907
|
const owners = readWorktreeOwners(primaryRepoRoot);
|
|
32873
32908
|
const removalNow = Date.now();
|
|
@@ -32924,7 +32959,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32924
32959
|
const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
|
|
32925
32960
|
beforeWorktrees,
|
|
32926
32961
|
startingPath: branch.worktreePath,
|
|
32927
|
-
pathExists: (p) => (0,
|
|
32962
|
+
pathExists: (p) => (0, import_node_fs39.existsSync)(p),
|
|
32928
32963
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
32929
32964
|
teardownWorktreeStage,
|
|
32930
32965
|
deferredStore,
|
|
@@ -32962,7 +32997,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32962
32997
|
let removalAttempted = false;
|
|
32963
32998
|
try {
|
|
32964
32999
|
const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, cleanupRoots, {
|
|
32965
|
-
realpath: (path2) => (0,
|
|
33000
|
+
realpath: (path2) => (0, import_node_fs39.realpathSync)(path2)
|
|
32966
33001
|
});
|
|
32967
33002
|
if (!cleanupTarget.ok) {
|
|
32968
33003
|
result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
|
|
@@ -33049,13 +33084,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
|
|
|
33049
33084
|
const commits = JSON.parse(raw).commits ?? [];
|
|
33050
33085
|
const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
|
|
33051
33086
|
if (!body) return void 0;
|
|
33052
|
-
const dir = (0,
|
|
33053
|
-
const path2 = (0,
|
|
33054
|
-
(0,
|
|
33087
|
+
const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
|
|
33088
|
+
const path2 = (0, import_node_path37.join)(dir, "body.txt");
|
|
33089
|
+
(0, import_node_fs39.writeFileSync)(path2, `${body}
|
|
33055
33090
|
`, "utf8");
|
|
33056
33091
|
return { path: path2, cleanup: () => {
|
|
33057
33092
|
try {
|
|
33058
|
-
(0,
|
|
33093
|
+
(0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
|
|
33059
33094
|
} catch {
|
|
33060
33095
|
}
|
|
33061
33096
|
} };
|
|
@@ -33177,13 +33212,13 @@ var realWorktreeDirRemover = {
|
|
|
33177
33212
|
probe: (p) => {
|
|
33178
33213
|
let st;
|
|
33179
33214
|
try {
|
|
33180
|
-
st = (0,
|
|
33215
|
+
st = (0, import_node_fs39.lstatSync)(p);
|
|
33181
33216
|
} catch {
|
|
33182
33217
|
return null;
|
|
33183
33218
|
}
|
|
33184
33219
|
if (st.isSymbolicLink()) return "link";
|
|
33185
33220
|
try {
|
|
33186
|
-
(0,
|
|
33221
|
+
(0, import_node_fs39.readlinkSync)(p);
|
|
33187
33222
|
return "link";
|
|
33188
33223
|
} catch {
|
|
33189
33224
|
}
|
|
@@ -33191,7 +33226,7 @@ var realWorktreeDirRemover = {
|
|
|
33191
33226
|
},
|
|
33192
33227
|
readdir: (p) => {
|
|
33193
33228
|
try {
|
|
33194
|
-
return (0,
|
|
33229
|
+
return (0, import_node_fs39.readdirSync)(p);
|
|
33195
33230
|
} catch {
|
|
33196
33231
|
return [];
|
|
33197
33232
|
}
|
|
@@ -33200,9 +33235,9 @@ var realWorktreeDirRemover = {
|
|
|
33200
33235
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
33201
33236
|
detachLink: (p) => {
|
|
33202
33237
|
try {
|
|
33203
|
-
(0,
|
|
33238
|
+
(0, import_node_fs39.rmdirSync)(p);
|
|
33204
33239
|
} catch {
|
|
33205
|
-
(0,
|
|
33240
|
+
(0, import_node_fs39.unlinkSync)(p);
|
|
33206
33241
|
}
|
|
33207
33242
|
},
|
|
33208
33243
|
removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
@@ -33235,9 +33270,9 @@ async function worktreeHasStageState(worktreePath) {
|
|
|
33235
33270
|
}
|
|
33236
33271
|
}
|
|
33237
33272
|
function stageStateFileBelongsToWorktree(statePath, worktreePath) {
|
|
33238
|
-
if (!(0,
|
|
33273
|
+
if (!(0, import_node_fs39.existsSync)(statePath)) return false;
|
|
33239
33274
|
try {
|
|
33240
|
-
const state = JSON.parse((0,
|
|
33275
|
+
const state = JSON.parse((0, import_node_fs39.readFileSync)(statePath, "utf8"));
|
|
33241
33276
|
const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
|
|
33242
33277
|
return Boolean(recordedCwd && isPathUnderDirectory2(recordedCwd, worktreePath));
|
|
33243
33278
|
} catch {
|
|
@@ -33672,14 +33707,14 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
33672
33707
|
}
|
|
33673
33708
|
|
|
33674
33709
|
// src/worktree-lifecycle-commands.ts
|
|
33675
|
-
var
|
|
33710
|
+
var import_node_fs41 = require("node:fs");
|
|
33676
33711
|
var import_promises9 = require("node:fs/promises");
|
|
33677
|
-
var
|
|
33712
|
+
var import_node_path39 = require("node:path");
|
|
33678
33713
|
|
|
33679
33714
|
// src/worktree-install-cache.ts
|
|
33680
33715
|
var import_node_crypto7 = require("node:crypto");
|
|
33681
|
-
var
|
|
33682
|
-
var
|
|
33716
|
+
var import_node_fs40 = require("node:fs");
|
|
33717
|
+
var import_node_path38 = require("node:path");
|
|
33683
33718
|
var CACHE_DIR = "worktree-install-cache";
|
|
33684
33719
|
var MANIFEST = "manifest.json";
|
|
33685
33720
|
var NODE_MODULES2 = "node_modules";
|
|
@@ -33692,16 +33727,16 @@ var LOCKFILE_NAMES = [
|
|
|
33692
33727
|
"package-lock.json"
|
|
33693
33728
|
];
|
|
33694
33729
|
var realWorktreeInstallCacheFs = {
|
|
33695
|
-
exists:
|
|
33696
|
-
readFile: (path2) => (0,
|
|
33697
|
-
lstat: (path2) => (0,
|
|
33698
|
-
copyDir: (from, to) => (0,
|
|
33730
|
+
exists: import_node_fs40.existsSync,
|
|
33731
|
+
readFile: (path2) => (0, import_node_fs40.readFileSync)(path2, "utf8"),
|
|
33732
|
+
lstat: (path2) => (0, import_node_fs40.lstatSync)(path2),
|
|
33733
|
+
copyDir: (from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }),
|
|
33699
33734
|
mkdirp: (path2) => {
|
|
33700
|
-
(0,
|
|
33735
|
+
(0, import_node_fs40.mkdirSync)(path2, { recursive: true });
|
|
33701
33736
|
},
|
|
33702
|
-
writeFile: (path2, contents) => (0,
|
|
33737
|
+
writeFile: (path2, contents) => (0, import_node_fs40.writeFileSync)(path2, contents, "utf8"),
|
|
33703
33738
|
rm: (path2) => {
|
|
33704
|
-
(0,
|
|
33739
|
+
(0, import_node_fs40.rmSync)(path2, { recursive: true, force: true });
|
|
33705
33740
|
}
|
|
33706
33741
|
};
|
|
33707
33742
|
function hashLockfileBytes(contents) {
|
|
@@ -33709,7 +33744,7 @@ function hashLockfileBytes(contents) {
|
|
|
33709
33744
|
}
|
|
33710
33745
|
function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33711
33746
|
for (const name of LOCKFILE_NAMES) {
|
|
33712
|
-
const path2 = (0,
|
|
33747
|
+
const path2 = (0, import_node_path38.join)(packageDir, name);
|
|
33713
33748
|
if (!fs2.exists(path2)) continue;
|
|
33714
33749
|
try {
|
|
33715
33750
|
const hash = hashLockfileBytes(fs2.readFile(path2));
|
|
@@ -33724,8 +33759,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
|
|
|
33724
33759
|
const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
|
|
33725
33760
|
return {
|
|
33726
33761
|
root,
|
|
33727
|
-
manifestPath: (0,
|
|
33728
|
-
nodeModulesPath: (0,
|
|
33762
|
+
manifestPath: (0, import_node_path38.join)(root, MANIFEST),
|
|
33763
|
+
nodeModulesPath: (0, import_node_path38.join)(root, NODE_MODULES2)
|
|
33729
33764
|
};
|
|
33730
33765
|
}
|
|
33731
33766
|
function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
|
|
@@ -33765,7 +33800,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
|
|
|
33765
33800
|
}
|
|
33766
33801
|
}
|
|
33767
33802
|
function removeMaterializedTree(packageDir, fs2) {
|
|
33768
|
-
const dest = (0,
|
|
33803
|
+
const dest = (0, import_node_path38.join)(packageDir, NODE_MODULES2);
|
|
33769
33804
|
if (!fs2.exists(dest)) return;
|
|
33770
33805
|
fs2.rm(dest);
|
|
33771
33806
|
if (fs2.exists(dest)) {
|
|
@@ -33773,7 +33808,7 @@ function removeMaterializedTree(packageDir, fs2) {
|
|
|
33773
33808
|
}
|
|
33774
33809
|
}
|
|
33775
33810
|
function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33776
|
-
const dest = (0,
|
|
33811
|
+
const dest = (0, import_node_path38.join)(destPackageDir, NODE_MODULES2);
|
|
33777
33812
|
try {
|
|
33778
33813
|
if (fs2.exists(dest)) fs2.rm(dest);
|
|
33779
33814
|
fs2.mkdirp(destPackageDir);
|
|
@@ -33788,7 +33823,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
|
|
|
33788
33823
|
}
|
|
33789
33824
|
}
|
|
33790
33825
|
async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile3, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
|
|
33791
|
-
const source = (0,
|
|
33826
|
+
const source = (0, import_node_path38.join)(sourcePackageDir, NODE_MODULES2);
|
|
33792
33827
|
if (!isMaterializableNodeModulesDir(source, fs2)) return;
|
|
33793
33828
|
const entry = worktreeInstallCacheEntry(primaryRoot, lockfile3.hash);
|
|
33794
33829
|
const manifest = {
|
|
@@ -34048,7 +34083,7 @@ function classifyStaleLeaks(input) {
|
|
|
34048
34083
|
var defaultOrphanDirScanDeps = {
|
|
34049
34084
|
listDirs: (root) => {
|
|
34050
34085
|
try {
|
|
34051
|
-
return (0,
|
|
34086
|
+
return (0, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path39.join)(root, e.name));
|
|
34052
34087
|
} catch {
|
|
34053
34088
|
return [];
|
|
34054
34089
|
}
|
|
@@ -34214,13 +34249,13 @@ function registerWorktreeCommands(program3) {
|
|
|
34214
34249
|
const detached = headBorn && !symbolicBranch;
|
|
34215
34250
|
const branch = symbolicBranch || (detached ? "HEAD" : "");
|
|
34216
34251
|
if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
|
|
34217
|
-
const gitFile = (0,
|
|
34218
|
-
const isLinked = (0,
|
|
34252
|
+
const gitFile = (0, import_node_path39.join)(wtPath, ".git");
|
|
34253
|
+
const isLinked = (0, import_node_fs41.existsSync)(gitFile) && (0, import_node_fs41.statSync)(gitFile).isFile();
|
|
34219
34254
|
if (apply && !isLinked) {
|
|
34220
34255
|
return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
|
|
34221
34256
|
}
|
|
34222
34257
|
const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
34223
|
-
const primaryCheckout = commonDir ? (0,
|
|
34258
|
+
const primaryCheckout = commonDir ? (0, import_node_path39.dirname)(commonDir) : wtPath;
|
|
34224
34259
|
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);
|
|
34225
34260
|
const orphan = classifyOrphanedWorktree({
|
|
34226
34261
|
branch,
|
|
@@ -34494,10 +34529,10 @@ async function gatherWorktreeContext() {
|
|
|
34494
34529
|
if (s) stages.push({ path: wt.path, port: s.port });
|
|
34495
34530
|
}
|
|
34496
34531
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
34497
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
34532
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
34498
34533
|
const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
|
|
34499
34534
|
let orphanDirs = [];
|
|
34500
|
-
if ((0,
|
|
34535
|
+
if ((0, import_node_fs41.existsSync)(wtRoot)) {
|
|
34501
34536
|
orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
|
|
34502
34537
|
...defaultOrphanDirScanDeps,
|
|
34503
34538
|
listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
|
|
@@ -34533,7 +34568,7 @@ ${err.stderr ?? ""}`;
|
|
|
34533
34568
|
}
|
|
34534
34569
|
|
|
34535
34570
|
// src/issue-commands.ts
|
|
34536
|
-
var
|
|
34571
|
+
var import_node_fs42 = require("node:fs");
|
|
34537
34572
|
var import_node_crypto8 = require("node:crypto");
|
|
34538
34573
|
var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
|
|
34539
34574
|
var ReparentConflictError = class extends Error {
|
|
@@ -34551,7 +34586,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
34551
34586
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
34552
34587
|
const patch = {};
|
|
34553
34588
|
let bodyChanged = false;
|
|
34554
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
34589
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs42.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
34555
34590
|
if (options.titleFile !== void 0) {
|
|
34556
34591
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
34557
34592
|
} else if (options.title !== void 0) {
|
|
@@ -35156,7 +35191,7 @@ function extendCreateCommand(issue2, batchAttach) {
|
|
|
35156
35191
|
if (opts.batch) {
|
|
35157
35192
|
let specs;
|
|
35158
35193
|
try {
|
|
35159
|
-
const raw = (0,
|
|
35194
|
+
const raw = (0, import_node_fs42.readFileSync)(opts.batch, "utf8");
|
|
35160
35195
|
specs = JSON.parse(raw);
|
|
35161
35196
|
if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
|
|
35162
35197
|
} catch (e) {
|
|
@@ -35231,8 +35266,8 @@ ${lines}`, {
|
|
|
35231
35266
|
}
|
|
35232
35267
|
|
|
35233
35268
|
// src/train-commands.ts
|
|
35234
|
-
var
|
|
35235
|
-
var
|
|
35269
|
+
var import_node_fs43 = require("node:fs");
|
|
35270
|
+
var import_node_path40 = require("node:path");
|
|
35236
35271
|
var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
35237
35272
|
function resolveReleaseBumpIntent(raw) {
|
|
35238
35273
|
const intent = typeof raw === "string" ? raw.trim() : "";
|
|
@@ -35243,7 +35278,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
35243
35278
|
}
|
|
35244
35279
|
function readRepoVersion() {
|
|
35245
35280
|
try {
|
|
35246
|
-
return JSON.parse((0,
|
|
35281
|
+
return JSON.parse((0, import_node_fs43.readFileSync)((0, import_node_path40.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
35247
35282
|
} catch {
|
|
35248
35283
|
return void 0;
|
|
35249
35284
|
}
|
|
@@ -35400,9 +35435,9 @@ function registerDeployCommands(program3) {
|
|
|
35400
35435
|
}
|
|
35401
35436
|
|
|
35402
35437
|
// src/discovery-commands.ts
|
|
35403
|
-
var
|
|
35438
|
+
var import_node_fs44 = require("node:fs");
|
|
35404
35439
|
var import_node_os16 = require("node:os");
|
|
35405
|
-
var
|
|
35440
|
+
var import_node_path41 = require("node:path");
|
|
35406
35441
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
35407
35442
|
async function collectStatus() {
|
|
35408
35443
|
const repo = await resolveRepo();
|
|
@@ -35592,8 +35627,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
35592
35627
|
}
|
|
35593
35628
|
const home = (0, import_node_os16.homedir)();
|
|
35594
35629
|
const plugin = onboardPluginGate({
|
|
35595
|
-
readKnown: () => readFileSyncSafe((0,
|
|
35596
|
-
readSettings: () => readFileSyncSafe((0,
|
|
35630
|
+
readKnown: () => readFileSyncSafe((0, import_node_path41.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs44.readFileSync),
|
|
35631
|
+
readSettings: () => readFileSyncSafe((0, import_node_path41.join)(home, ".claude", "settings.json"), import_node_fs44.readFileSync)
|
|
35597
35632
|
});
|
|
35598
35633
|
return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
|
|
35599
35634
|
}
|
|
@@ -35753,8 +35788,9 @@ function formatExplainCommand(cmd, rootName) {
|
|
|
35753
35788
|
return lines.join("\n").trimEnd();
|
|
35754
35789
|
}
|
|
35755
35790
|
function formatExplainGroup(cmd, rootName) {
|
|
35791
|
+
const canonical = (node) => canonicalPathFor(node.path) ?? node.path;
|
|
35756
35792
|
const lines = [
|
|
35757
|
-
`${rootName} ${cmd
|
|
35793
|
+
`${rootName} ${canonical(cmd)}${cmd.description ? ` \u2014 ${cmd.description}` : ""}`,
|
|
35758
35794
|
`Category: ${cmd.category} \xB7 Discovery: ${cmd.discovery}`,
|
|
35759
35795
|
"",
|
|
35760
35796
|
"Commands:"
|
|
@@ -35764,7 +35800,7 @@ function formatExplainGroup(cmd, rootName) {
|
|
|
35764
35800
|
const name = arg.variadic ? `${arg.name}...` : arg.name;
|
|
35765
35801
|
return arg.required ? `<${name}>` : `[${name}]`;
|
|
35766
35802
|
}).join(" ");
|
|
35767
|
-
lines.push(` ${child2
|
|
35803
|
+
lines.push(` ${canonical(child2)}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
|
|
35768
35804
|
}
|
|
35769
35805
|
return lines.join("\n");
|
|
35770
35806
|
}
|
|
@@ -35778,7 +35814,7 @@ function formatExplainLoop(playbook) {
|
|
|
35778
35814
|
}
|
|
35779
35815
|
function findCommandInManifest(manifest, commandPath3) {
|
|
35780
35816
|
const visit = (command) => {
|
|
35781
|
-
if (command.path === commandPath3) return command;
|
|
35817
|
+
if (command.path === commandPath3 || canonicalPathFor(command.path) === commandPath3) return command;
|
|
35782
35818
|
for (const child2 of command.subcommands) {
|
|
35783
35819
|
const found = visit(child2);
|
|
35784
35820
|
if (found) return found;
|
|
@@ -36692,19 +36728,19 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
36692
36728
|
}
|
|
36693
36729
|
|
|
36694
36730
|
// src/plugin-release-catchup.ts
|
|
36695
|
-
var
|
|
36696
|
-
var
|
|
36731
|
+
var import_node_fs45 = require("node:fs");
|
|
36732
|
+
var import_node_path42 = require("node:path");
|
|
36697
36733
|
var import_node_os17 = require("node:os");
|
|
36698
36734
|
var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
36699
36735
|
var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
|
|
36700
36736
|
function releaseCatchupStatePath(env = process.env) {
|
|
36701
36737
|
if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
|
|
36702
36738
|
if (process.platform === "win32") {
|
|
36703
|
-
const base2 = env.LOCALAPPDATA || (0,
|
|
36704
|
-
return (0,
|
|
36739
|
+
const base2 = env.LOCALAPPDATA || (0, import_node_path42.join)((0, import_node_os17.homedir)(), "AppData", "Local");
|
|
36740
|
+
return (0, import_node_path42.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
|
|
36705
36741
|
}
|
|
36706
|
-
const base = env.XDG_STATE_HOME || (0,
|
|
36707
|
-
return (0,
|
|
36742
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path42.join)((0, import_node_os17.homedir)(), ".local", "state");
|
|
36743
|
+
return (0, import_node_path42.join)(base, "mmi-cli", "release-catchup.json");
|
|
36708
36744
|
}
|
|
36709
36745
|
function releaseCatchupDue(state, now, force = false) {
|
|
36710
36746
|
if (force) return true;
|
|
@@ -36714,7 +36750,7 @@ function releaseCatchupDue(state, now, force = false) {
|
|
|
36714
36750
|
function newestCachedPluginVersion(home) {
|
|
36715
36751
|
let names;
|
|
36716
36752
|
try {
|
|
36717
|
-
names = (0,
|
|
36753
|
+
names = (0, import_node_fs45.readdirSync)(pluginCacheRoot(home));
|
|
36718
36754
|
} catch {
|
|
36719
36755
|
return void 0;
|
|
36720
36756
|
}
|
|
@@ -36722,15 +36758,15 @@ function newestCachedPluginVersion(home) {
|
|
|
36722
36758
|
}
|
|
36723
36759
|
function marketplaceClonePath(home) {
|
|
36724
36760
|
try {
|
|
36725
|
-
const parsed = JSON.parse((0,
|
|
36761
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
|
|
36726
36762
|
if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
|
|
36727
36763
|
} catch {
|
|
36728
36764
|
}
|
|
36729
|
-
return (0,
|
|
36765
|
+
return (0, import_node_path42.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
|
|
36730
36766
|
}
|
|
36731
36767
|
function readCatalogVersion(home) {
|
|
36732
36768
|
try {
|
|
36733
|
-
const parsed = JSON.parse((0,
|
|
36769
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
|
|
36734
36770
|
return parsed.plugins?.find((p) => p.name === "mmi")?.version;
|
|
36735
36771
|
} catch {
|
|
36736
36772
|
return void 0;
|
|
@@ -36738,7 +36774,7 @@ function readCatalogVersion(home) {
|
|
|
36738
36774
|
}
|
|
36739
36775
|
function readMmiInstallRecord(home) {
|
|
36740
36776
|
try {
|
|
36741
|
-
const parsed = JSON.parse((0,
|
|
36777
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
|
|
36742
36778
|
const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
|
|
36743
36779
|
return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
|
|
36744
36780
|
} catch {
|
|
@@ -36767,7 +36803,7 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36767
36803
|
cliUpdated = true;
|
|
36768
36804
|
}
|
|
36769
36805
|
const cliUpdateDetail = cliUpdated ? `CLI ${runningCli} \u2192 ${latest}; the next mmi-cli invocation runs ${latest}` : `CLI ${runningCli} is current against released ${latest}`;
|
|
36770
|
-
if (!(0,
|
|
36806
|
+
if (!(0, import_node_fs45.existsSync)(pluginCacheRoot(home))) {
|
|
36771
36807
|
deps.writeState(statePath, { checkedAt: deps.now(), latest });
|
|
36772
36808
|
return {
|
|
36773
36809
|
ok: true,
|
|
@@ -36800,8 +36836,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36800
36836
|
return { ok: false, detail: `${cliUpdateDetail}; plugin install record could not be cleared (still ${prior.version})` };
|
|
36801
36837
|
}
|
|
36802
36838
|
const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
|
|
36803
|
-
const payload = (0,
|
|
36804
|
-
if (!installed || !(0,
|
|
36839
|
+
const payload = (0, import_node_path42.join)(pluginCacheRoot(home), latest, ".pi-plugin");
|
|
36840
|
+
if (!installed || !(0, import_node_fs45.existsSync)(payload)) {
|
|
36805
36841
|
const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
|
|
36806
36842
|
if (!prior) return { ok: false, detail: `${cliUpdateDetail}; ${why}; no prior record to restore` };
|
|
36807
36843
|
const rollback = await restorePriorRecord(home, prior, deps);
|
|
@@ -38774,6 +38810,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38774
38810
|
});
|
|
38775
38811
|
return;
|
|
38776
38812
|
}
|
|
38813
|
+
const provenance = state.cachedAt === void 0 ? [] : [cachedSweepNote(state.cachedAt)];
|
|
38777
38814
|
if (state.driftLines.length === 0) {
|
|
38778
38815
|
emitNow({
|
|
38779
38816
|
ok: true,
|
|
@@ -38781,7 +38818,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38781
38818
|
id: "schedules-drift",
|
|
38782
38819
|
label: "schedules drift",
|
|
38783
38820
|
detail: "no drift",
|
|
38784
|
-
verbose: ["no drift lines"]
|
|
38821
|
+
verbose: ["no drift lines", ...provenance]
|
|
38785
38822
|
});
|
|
38786
38823
|
return;
|
|
38787
38824
|
}
|
|
@@ -38792,7 +38829,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38792
38829
|
label: "schedules drift",
|
|
38793
38830
|
detail: `${state.driftLines.length} drift line(s)`,
|
|
38794
38831
|
fix: "run `mmi-cli harbour org schedules` / `org schedules register`",
|
|
38795
|
-
verbose: state.driftLines
|
|
38832
|
+
verbose: [...state.driftLines, ...provenance]
|
|
38796
38833
|
});
|
|
38797
38834
|
} catch (e) {
|
|
38798
38835
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -39009,17 +39046,17 @@ function parseOriginRepo(remoteUrl) {
|
|
|
39009
39046
|
}
|
|
39010
39047
|
function ghHostsConfigPath(env, platform2) {
|
|
39011
39048
|
const sep3 = platform2 === "win32" ? "\\" : "/";
|
|
39012
|
-
const
|
|
39049
|
+
const join40 = (...parts) => parts.join(sep3);
|
|
39013
39050
|
const explicit = env.GH_CONFIG_DIR?.trim();
|
|
39014
|
-
if (explicit) return
|
|
39051
|
+
if (explicit) return join40(explicit, "hosts.yml");
|
|
39015
39052
|
if (platform2 === "win32") {
|
|
39016
39053
|
const appData = (env.AppData ?? env.APPDATA)?.trim();
|
|
39017
|
-
return appData ?
|
|
39054
|
+
return appData ? join40(appData, "GitHub CLI", "hosts.yml") : void 0;
|
|
39018
39055
|
}
|
|
39019
39056
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
39020
|
-
if (xdg) return
|
|
39057
|
+
if (xdg) return join40(xdg, "gh", "hosts.yml");
|
|
39021
39058
|
const home = env.HOME?.trim();
|
|
39022
|
-
return home ?
|
|
39059
|
+
return home ? join40(home, ".config", "gh", "hosts.yml") : void 0;
|
|
39023
39060
|
}
|
|
39024
39061
|
function parseGhHostsAccounts(yaml, host = "github.com") {
|
|
39025
39062
|
let hostIndent = null;
|
|
@@ -39069,9 +39106,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
39069
39106
|
}
|
|
39070
39107
|
|
|
39071
39108
|
// src/doctor-io.ts
|
|
39072
|
-
var
|
|
39109
|
+
var import_node_fs46 = require("node:fs");
|
|
39073
39110
|
var import_node_os18 = require("node:os");
|
|
39074
|
-
var
|
|
39111
|
+
var import_node_path43 = require("node:path");
|
|
39075
39112
|
var import_node_child_process19 = require("node:child_process");
|
|
39076
39113
|
var import_node_util8 = require("node:util");
|
|
39077
39114
|
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
|
|
@@ -39079,7 +39116,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
39079
39116
|
function installedClaudePluginVersion() {
|
|
39080
39117
|
try {
|
|
39081
39118
|
const file = JSON.parse(
|
|
39082
|
-
(0,
|
|
39119
|
+
(0, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
39083
39120
|
);
|
|
39084
39121
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
39085
39122
|
if (versions.length === 0) return void 0;
|
|
@@ -39090,7 +39127,7 @@ function installedClaudePluginVersion() {
|
|
|
39090
39127
|
}
|
|
39091
39128
|
function manifestVersion(path2) {
|
|
39092
39129
|
try {
|
|
39093
|
-
const manifest = JSON.parse((0,
|
|
39130
|
+
const manifest = JSON.parse((0, import_node_fs46.readFileSync)(path2, "utf8"));
|
|
39094
39131
|
return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
|
|
39095
39132
|
} catch {
|
|
39096
39133
|
return void 0;
|
|
@@ -39100,22 +39137,22 @@ function installedSurfacePluginVersion(surface) {
|
|
|
39100
39137
|
const token = surfaceToken(surface);
|
|
39101
39138
|
if (token === "kilo") {
|
|
39102
39139
|
try {
|
|
39103
|
-
const stamp = (0,
|
|
39140
|
+
const stamp = (0, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
|
|
39104
39141
|
return stamp || void 0;
|
|
39105
39142
|
} catch {
|
|
39106
39143
|
return void 0;
|
|
39107
39144
|
}
|
|
39108
39145
|
}
|
|
39109
39146
|
if (token === "cursor") {
|
|
39110
|
-
return manifestVersion((0,
|
|
39147
|
+
return manifestVersion((0, import_node_path43.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
39111
39148
|
}
|
|
39112
39149
|
if (token === "jervcode") {
|
|
39113
39150
|
const entry = mmiPiWrapperEntry();
|
|
39114
39151
|
if (!entry) return void 0;
|
|
39115
|
-
return manifestVersion((0,
|
|
39152
|
+
return manifestVersion((0, import_node_path43.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
|
|
39116
39153
|
}
|
|
39117
39154
|
if (token === "kimi") {
|
|
39118
|
-
return manifestVersion((0,
|
|
39155
|
+
return manifestVersion((0, import_node_path43.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
|
|
39119
39156
|
}
|
|
39120
39157
|
if (token === "claude") return installedClaudePluginVersion();
|
|
39121
39158
|
if (token !== "codex") return void 0;
|
|
@@ -39153,13 +39190,13 @@ function worktreeRootSync() {
|
|
|
39153
39190
|
}
|
|
39154
39191
|
var gitignorePath = () => {
|
|
39155
39192
|
const root = worktreeRootSync();
|
|
39156
|
-
return root === null ? null : (0,
|
|
39193
|
+
return root === null ? null : (0, import_node_path43.join)(root, ".gitignore");
|
|
39157
39194
|
};
|
|
39158
39195
|
function readGitignore() {
|
|
39159
39196
|
const path2 = gitignorePath();
|
|
39160
39197
|
if (path2 === null) return null;
|
|
39161
39198
|
try {
|
|
39162
|
-
return (0,
|
|
39199
|
+
return (0, import_node_fs46.readFileSync)(path2, "utf8");
|
|
39163
39200
|
} catch {
|
|
39164
39201
|
return null;
|
|
39165
39202
|
}
|
|
@@ -39168,7 +39205,7 @@ function writeGitignore(content) {
|
|
|
39168
39205
|
const path2 = gitignorePath();
|
|
39169
39206
|
if (path2 === null) return false;
|
|
39170
39207
|
try {
|
|
39171
|
-
(0,
|
|
39208
|
+
(0, import_node_fs46.writeFileSync)(path2, content, "utf8");
|
|
39172
39209
|
return true;
|
|
39173
39210
|
} catch {
|
|
39174
39211
|
return false;
|
|
@@ -39187,7 +39224,7 @@ async function repoRoot() {
|
|
|
39187
39224
|
}
|
|
39188
39225
|
function hasRepoLocalWorktrees() {
|
|
39189
39226
|
const root = worktreeRootSync();
|
|
39190
|
-
return root !== null && (0,
|
|
39227
|
+
return root !== null && (0, import_node_fs46.existsSync)((0, import_node_path43.join)(root, ".worktrees"));
|
|
39191
39228
|
}
|
|
39192
39229
|
|
|
39193
39230
|
// src/index.ts
|
|
@@ -39206,8 +39243,8 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
39206
39243
|
function ghMultiAccountCaveat(announcedLogin) {
|
|
39207
39244
|
try {
|
|
39208
39245
|
const hostsPath = ghHostsConfigPath(process.env, process.platform);
|
|
39209
|
-
if (!hostsPath || !(0,
|
|
39210
|
-
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0,
|
|
39246
|
+
if (!hostsPath || !(0, import_node_fs47.existsSync)(hostsPath)) return void 0;
|
|
39247
|
+
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs47.readFileSync)(hostsPath, "utf8")));
|
|
39211
39248
|
} catch {
|
|
39212
39249
|
return void 0;
|
|
39213
39250
|
}
|
|
@@ -39215,7 +39252,7 @@ function ghMultiAccountCaveat(announcedLogin) {
|
|
|
39215
39252
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
39216
39253
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
39217
39254
|
function envHealLockPath(home) {
|
|
39218
|
-
return (0,
|
|
39255
|
+
return (0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
39219
39256
|
}
|
|
39220
39257
|
async function withEnvHealLock(what, run) {
|
|
39221
39258
|
try {
|
|
@@ -39348,7 +39385,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39348
39385
|
);
|
|
39349
39386
|
const result = applyPluginCachePlan(
|
|
39350
39387
|
plan,
|
|
39351
|
-
(p) => (0,
|
|
39388
|
+
(p) => (0, import_node_fs47.rmSync)(p, { recursive: true }),
|
|
39352
39389
|
stagingApplyFsGuard(configRoot)
|
|
39353
39390
|
);
|
|
39354
39391
|
return {
|
|
@@ -39402,8 +39439,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39402
39439
|
const home = (0, import_node_os19.homedir)();
|
|
39403
39440
|
const rows = marketplaceRows(
|
|
39404
39441
|
MMI_MARKETPLACE_NAME,
|
|
39405
|
-
readFileSyncSafe((0,
|
|
39406
|
-
readFileSyncSafe((0,
|
|
39442
|
+
readFileSyncSafe((0, import_node_path44.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs47.readFileSync),
|
|
39443
|
+
readFileSyncSafe((0, import_node_path44.join)(home, ".claude", "settings.json"), import_node_fs47.readFileSync),
|
|
39407
39444
|
// #3974: this CLI heals these rows, so report mode names the doctor run rather than the hand
|
|
39408
39445
|
// edit. #4792 narrows WHICH run: `applyOrgMarketplacePins` declines outright while Claude Code
|
|
39409
39446
|
// is up, because the host owns this file and rewrites it from its own copy (#4083). Naming the
|
|
@@ -39415,7 +39452,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39415
39452
|
hostBlocked ?? claudeCodeEnvMarkerPresent() ? "host-running" : "doctor"
|
|
39416
39453
|
);
|
|
39417
39454
|
const pending = readMarketplacePinPending(
|
|
39418
|
-
(0,
|
|
39455
|
+
(0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
|
|
39419
39456
|
MMI_MARKETPLACE_NAME
|
|
39420
39457
|
);
|
|
39421
39458
|
if (!pending) return rows;
|
|
@@ -39441,9 +39478,9 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39441
39478
|
if (detectSurface(process.env) === "codex") return void 0;
|
|
39442
39479
|
const home = (0, import_node_os19.homedir)();
|
|
39443
39480
|
const names = [MMI_MARKETPLACE_NAME];
|
|
39444
|
-
const result = applyOrgMarketplacePins((0,
|
|
39481
|
+
const result = applyOrgMarketplacePins((0, import_node_path44.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
|
|
39445
39482
|
if (result?.wrote) {
|
|
39446
|
-
writeMarketplacePinPending((0,
|
|
39483
|
+
writeMarketplacePinPending((0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
|
|
39447
39484
|
}
|
|
39448
39485
|
return result;
|
|
39449
39486
|
} catch {
|
|
@@ -39459,7 +39496,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39459
39496
|
// adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
|
|
39460
39497
|
// get a permanent — demanding an artifact it never asked for.
|
|
39461
39498
|
docsIndexState: (root) => {
|
|
39462
|
-
if (!(0,
|
|
39499
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
39463
39500
|
const real = createDocsIndexDeps(root);
|
|
39464
39501
|
let docs2;
|
|
39465
39502
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39468,7 +39505,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39468
39505
|
},
|
|
39469
39506
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
39470
39507
|
healDocsIndex: (root) => {
|
|
39471
|
-
if (!(0,
|
|
39508
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
39472
39509
|
const real = createDocsIndexDeps(root);
|
|
39473
39510
|
let docs2;
|
|
39474
39511
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39496,6 +39533,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39496
39533
|
// #4170: light board doctor with 15s ceiling. skipClaimLiveness keeps Phase 3 off.
|
|
39497
39534
|
boardDoctorFix: async ({ fix } = {}) => {
|
|
39498
39535
|
const BOARD_DOCTOR_TIMEOUT_MS = 15e3;
|
|
39536
|
+
let ceiling;
|
|
39499
39537
|
try {
|
|
39500
39538
|
const cfg = await loadConfigForRepo();
|
|
39501
39539
|
const work = boardDoctor({
|
|
@@ -39506,7 +39544,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39506
39544
|
const raced = await Promise.race([
|
|
39507
39545
|
work.then((r) => ({ ...r, timedOut: false })),
|
|
39508
39546
|
new Promise((resolve5) => {
|
|
39509
|
-
setTimeout(() => resolve5({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39547
|
+
ceiling = setTimeout(() => resolve5({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39510
39548
|
})
|
|
39511
39549
|
]);
|
|
39512
39550
|
if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
|
|
@@ -39518,11 +39556,20 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39518
39556
|
};
|
|
39519
39557
|
} catch (e) {
|
|
39520
39558
|
return { scanned: 0, findings: 0, fixed: 0, failed: 0, readFailed: true, error: e instanceof Error ? e.message : String(e) };
|
|
39559
|
+
} finally {
|
|
39560
|
+
clearTimeout(ceiling);
|
|
39521
39561
|
}
|
|
39522
39562
|
},
|
|
39523
39563
|
// #4171: schedules drift notebook — report-only, ~20s ceiling.
|
|
39564
|
+
// #4815: and throttled. The sweep behind it reads every workflow file in every org repo — 12s of a
|
|
39565
|
+
// 22s doctor — so a cached notebook under six hours old answers the row instead, saying so in its
|
|
39566
|
+
// evidence. Only a COMPLETE sweep is cached (see schedules-drift-cache.ts).
|
|
39524
39567
|
schedulesDriftState: async () => {
|
|
39525
39568
|
const SCHEDULES_DRIFT_TIMEOUT_MS = 2e4;
|
|
39569
|
+
const cachePath = schedulesDriftCachePath(repoRuntimeStatePath(process.cwd()));
|
|
39570
|
+
const cached = readSchedulesDriftCache(cachePath);
|
|
39571
|
+
if (cached) return { driftLines: cached.driftLines, incomplete: [], cachedAt: cached.at };
|
|
39572
|
+
let ceiling;
|
|
39526
39573
|
try {
|
|
39527
39574
|
const raced = await Promise.race([
|
|
39528
39575
|
fetchNotebook().then((nb) => ({
|
|
@@ -39531,12 +39578,15 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39531
39578
|
timedOut: false
|
|
39532
39579
|
})),
|
|
39533
39580
|
new Promise((resolve5) => {
|
|
39534
|
-
setTimeout(() => resolve5({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39581
|
+
ceiling = setTimeout(() => resolve5({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39535
39582
|
})
|
|
39536
39583
|
]);
|
|
39584
|
+
if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
|
|
39537
39585
|
return raced;
|
|
39538
39586
|
} catch (e) {
|
|
39539
39587
|
return { driftLines: [], incomplete: [], readFailed: true, error: e instanceof Error ? e.message : String(e) };
|
|
39588
|
+
} finally {
|
|
39589
|
+
clearTimeout(ceiling);
|
|
39540
39590
|
}
|
|
39541
39591
|
},
|
|
39542
39592
|
// #4173: estate commands absent from the running Commander program (stale global CLI).
|
|
@@ -39703,12 +39753,15 @@ function positionalTargetForm(cmd, opts = {}) {
|
|
|
39703
39753
|
const args = cmd.registeredArguments ?? [];
|
|
39704
39754
|
const first = args[0];
|
|
39705
39755
|
if (!first) return void 0;
|
|
39706
|
-
return formatPositionalTarget(commandPath2(cmd), first.name(), opts);
|
|
39756
|
+
return formatPositionalTarget(canonicalPathFor(commandPath2(cmd)) ?? commandPath2(cmd), first.name(), opts);
|
|
39707
39757
|
}
|
|
39708
39758
|
function resolveParseHint() {
|
|
39709
39759
|
if (lastParseErrorKind === "unknown-command") {
|
|
39710
|
-
const
|
|
39711
|
-
|
|
39760
|
+
const parent = resolveCommandFromArgv(program2, process.argv.slice(2));
|
|
39761
|
+
const candidates = parent && parent.commands.length ? parent.commands.filter((child2) => commandMetadata(child2)?.category !== "internal").map(commandPath2) : allCommandPaths();
|
|
39762
|
+
const path3 = lastUnknownCommand ? suggestCommandPath(lastUnknownCommand, candidates) : void 0;
|
|
39763
|
+
const canonical = path3 ? canonicalPathFor(path3) ?? path3 : void 0;
|
|
39764
|
+
return canonical ? `(did you mean \`mmi-cli ${canonical}\`? ${DISCOVERY_HINT})` : STALE_HINT;
|
|
39712
39765
|
}
|
|
39713
39766
|
if (lastParseErrorKind !== "bad-arguments") return STALE_HINT;
|
|
39714
39767
|
const cmd = resolveCommandFromArgv(program2, process.argv.slice(2));
|
|
@@ -39818,19 +39871,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
39818
39871
|
});
|
|
39819
39872
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
39820
39873
|
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) => {
|
|
39821
|
-
const path2 = (0,
|
|
39822
|
-
const current = (0,
|
|
39874
|
+
const path2 = (0, import_node_path44.join)(process.cwd(), ".gitignore");
|
|
39875
|
+
const current = (0, import_node_fs47.existsSync)(path2) ? (0, import_node_fs47.readFileSync)(path2, "utf8") : null;
|
|
39823
39876
|
const plan = planManagedGitignore(current);
|
|
39824
39877
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
39825
39878
|
if (opts.json) {
|
|
39826
|
-
if (opts.write && plan.changed) (0,
|
|
39879
|
+
if (opts.write && plan.changed) (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
39827
39880
|
console.log(JSON.stringify(plan, null, 2));
|
|
39828
39881
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
39829
39882
|
return;
|
|
39830
39883
|
}
|
|
39831
39884
|
if (opts.write) {
|
|
39832
39885
|
if (plan.changed) {
|
|
39833
|
-
(0,
|
|
39886
|
+
(0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
39834
39887
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
39835
39888
|
} else {
|
|
39836
39889
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -39989,8 +40042,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
39989
40042
|
if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
|
|
39990
40043
|
let root;
|
|
39991
40044
|
if (o.root !== void 0) {
|
|
39992
|
-
root = (0,
|
|
39993
|
-
if (!(0,
|
|
40045
|
+
root = (0, import_node_path44.resolve)(o.root);
|
|
40046
|
+
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`);
|
|
39994
40047
|
const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
39995
40048
|
if (isPathUnderDirectory2(gcRepoRoot, root)) {
|
|
39996
40049
|
return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
|
|
@@ -40087,7 +40140,7 @@ async function currentWorktreeRemovalContext(command, force) {
|
|
|
40087
40140
|
};
|
|
40088
40141
|
}
|
|
40089
40142
|
async function unprovenWorktreeReason(wtPath, repoRoot2) {
|
|
40090
|
-
if (!(0,
|
|
40143
|
+
if (!(0, import_node_fs47.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
|
|
40091
40144
|
const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
40092
40145
|
const registered = parseWorktreePorcelainEntries(porcelain);
|
|
40093
40146
|
if (!registered.length) {
|
|
@@ -40117,26 +40170,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
40117
40170
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
40118
40171
|
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
40119
40172
|
const take = () => {
|
|
40120
|
-
const fd = (0,
|
|
40173
|
+
const fd = (0, import_node_fs47.openSync)(lockPath, "wx");
|
|
40121
40174
|
try {
|
|
40122
|
-
(0,
|
|
40175
|
+
(0, import_node_fs47.writeSync)(fd, String(Date.now()));
|
|
40123
40176
|
} finally {
|
|
40124
|
-
(0,
|
|
40177
|
+
(0, import_node_fs47.closeSync)(fd);
|
|
40125
40178
|
}
|
|
40126
40179
|
return () => {
|
|
40127
40180
|
try {
|
|
40128
|
-
(0,
|
|
40181
|
+
(0, import_node_fs47.rmSync)(lockPath, { force: true });
|
|
40129
40182
|
} catch {
|
|
40130
40183
|
}
|
|
40131
40184
|
};
|
|
40132
40185
|
};
|
|
40133
40186
|
try {
|
|
40134
|
-
(0,
|
|
40187
|
+
(0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(lockPath), { recursive: true });
|
|
40135
40188
|
return take();
|
|
40136
40189
|
} catch {
|
|
40137
40190
|
try {
|
|
40138
|
-
if (Date.now() - (0,
|
|
40139
|
-
(0,
|
|
40191
|
+
if (Date.now() - (0, import_node_fs47.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
|
|
40192
|
+
(0, import_node_fs47.rmSync)(lockPath, { force: true });
|
|
40140
40193
|
return take();
|
|
40141
40194
|
}
|
|
40142
40195
|
} catch {
|
|
@@ -40282,6 +40335,7 @@ withExamples(mutating(
|
|
|
40282
40335
|
let lease;
|
|
40283
40336
|
try {
|
|
40284
40337
|
await execJervCli([
|
|
40338
|
+
"cli",
|
|
40285
40339
|
"lease",
|
|
40286
40340
|
"open",
|
|
40287
40341
|
"--kind",
|
|
@@ -41000,7 +41054,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
41000
41054
|
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`);
|
|
41001
41055
|
if (o.secretsFile) {
|
|
41002
41056
|
try {
|
|
41003
|
-
vars.push(`secrets=${(0,
|
|
41057
|
+
vars.push(`secrets=${(0, import_node_fs47.readFileSync)(o.secretsFile, "utf8")}`);
|
|
41004
41058
|
} catch (e) {
|
|
41005
41059
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
41006
41060
|
}
|
|
@@ -41768,11 +41822,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
41768
41822
|
}
|
|
41769
41823
|
});
|
|
41770
41824
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
41771
|
-
const wfDir = (0,
|
|
41772
|
-
if (!(0,
|
|
41773
|
-
return (0,
|
|
41825
|
+
const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
|
|
41826
|
+
if (!(0, import_node_fs47.existsSync)(wfDir)) return [];
|
|
41827
|
+
return (0, import_node_fs47.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
41774
41828
|
try {
|
|
41775
|
-
return workflowReportsPrChecks((0,
|
|
41829
|
+
return workflowReportsPrChecks((0, import_node_fs47.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
|
|
41776
41830
|
} catch {
|
|
41777
41831
|
return true;
|
|
41778
41832
|
}
|
|
@@ -41824,16 +41878,16 @@ function ciAuditDeps() {
|
|
|
41824
41878
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
41825
41879
|
readSeedFile: (path2) => {
|
|
41826
41880
|
if (!root) return null;
|
|
41827
|
-
const fullPath = (0,
|
|
41828
|
-
return (0,
|
|
41881
|
+
const fullPath = (0, import_node_path44.join)(root, path2);
|
|
41882
|
+
return (0, import_node_fs47.existsSync)(fullPath) ? (0, import_node_fs47.readFileSync)(fullPath, "utf8") : null;
|
|
41829
41883
|
}
|
|
41830
41884
|
};
|
|
41831
41885
|
}
|
|
41832
41886
|
function hubRoot() {
|
|
41833
|
-
const fromPkg = (0,
|
|
41887
|
+
const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
|
|
41834
41888
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
41835
|
-
if ((0,
|
|
41836
|
-
if ((0,
|
|
41889
|
+
if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
|
|
41890
|
+
if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
|
|
41837
41891
|
return null;
|
|
41838
41892
|
}
|
|
41839
41893
|
async function waitLoopCorePool(label) {
|
|
@@ -42141,7 +42195,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42141
42195
|
}
|
|
42142
42196
|
if (!repoForPostCleanup) throw e;
|
|
42143
42197
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
42144
|
-
const commitMessage = bodyFile ? (0,
|
|
42198
|
+
const commitMessage = bodyFile ? (0, import_node_fs47.readFileSync)(bodyFile, "utf8") : void 0;
|
|
42145
42199
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
42146
42200
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
42147
42201
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -42237,7 +42291,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42237
42291
|
localCleanup = await cleanupPrMergeLocalBranch(headRef, {
|
|
42238
42292
|
beforeWorktrees,
|
|
42239
42293
|
startingPath,
|
|
42240
|
-
pathExists: (p) => (0,
|
|
42294
|
+
pathExists: (p) => (0, import_node_fs47.existsSync)(p),
|
|
42241
42295
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
42242
42296
|
teardownWorktreeStage,
|
|
42243
42297
|
deferredStore,
|
|
@@ -42815,12 +42869,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
42815
42869
|
targets = resolution.targets;
|
|
42816
42870
|
}
|
|
42817
42871
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
42818
|
-
const fileMatrix = (0,
|
|
42872
|
+
const fileMatrix = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
42819
42873
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
42820
42874
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
42821
|
-
const fileContracts = (0,
|
|
42875
|
+
const fileContracts = (0, import_node_fs47.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs47.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
|
|
42822
42876
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
42823
|
-
const sanctioned = (0,
|
|
42877
|
+
const sanctioned = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
42824
42878
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
42825
42879
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
42826
42880
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -42852,16 +42906,16 @@ function directoryBytes(path2) {
|
|
|
42852
42906
|
let total = 0;
|
|
42853
42907
|
let entries;
|
|
42854
42908
|
try {
|
|
42855
|
-
entries = (0,
|
|
42909
|
+
entries = (0, import_node_fs47.readdirSync)(path2, { withFileTypes: true });
|
|
42856
42910
|
} catch {
|
|
42857
42911
|
return 0;
|
|
42858
42912
|
}
|
|
42859
42913
|
for (const entry of entries) {
|
|
42860
|
-
const child2 = (0,
|
|
42914
|
+
const child2 = (0, import_node_path44.join)(path2, entry.name);
|
|
42861
42915
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
42862
42916
|
else {
|
|
42863
42917
|
try {
|
|
42864
|
-
total += (0,
|
|
42918
|
+
total += (0, import_node_fs47.statSync)(child2).size;
|
|
42865
42919
|
} catch {
|
|
42866
42920
|
}
|
|
42867
42921
|
}
|
|
@@ -42869,25 +42923,25 @@ function directoryBytes(path2) {
|
|
|
42869
42923
|
return total;
|
|
42870
42924
|
}
|
|
42871
42925
|
function listDirEntries(dir) {
|
|
42872
|
-
return (0,
|
|
42926
|
+
return (0, import_node_fs47.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
42873
42927
|
}
|
|
42874
42928
|
function readInstalledPluginRefs(configRoot) {
|
|
42875
42929
|
const p = installedPluginsPathForConfig(configRoot);
|
|
42876
|
-
if (!(0,
|
|
42930
|
+
if (!(0, import_node_fs47.existsSync)(p)) return [];
|
|
42877
42931
|
try {
|
|
42878
|
-
return installedPluginPaths((0,
|
|
42932
|
+
return installedPluginPaths((0, import_node_fs47.readFileSync)(p, "utf8"));
|
|
42879
42933
|
} catch {
|
|
42880
42934
|
return null;
|
|
42881
42935
|
}
|
|
42882
42936
|
}
|
|
42883
42937
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
42884
42938
|
return {
|
|
42885
|
-
exists: (p) => (0,
|
|
42886
|
-
listVersionDirs: (root) => (0,
|
|
42939
|
+
exists: (p) => (0, import_node_fs47.existsSync)(p),
|
|
42940
|
+
listVersionDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
42887
42941
|
dirBytes,
|
|
42888
|
-
listStagingDirs: (root) => (0,
|
|
42942
|
+
listStagingDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
42889
42943
|
try {
|
|
42890
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
42944
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path44.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs47.statSync)(p).mtimeMs) };
|
|
42891
42945
|
} catch {
|
|
42892
42946
|
return { name: d.name, mtimeMs: Date.now() };
|
|
42893
42947
|
}
|
|
@@ -42901,10 +42955,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
42901
42955
|
return {
|
|
42902
42956
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
42903
42957
|
mtimeMs: (name) => {
|
|
42904
|
-
const p = (0,
|
|
42905
|
-
if (!(0,
|
|
42958
|
+
const p = (0, import_node_path44.join)(stagingRoot, name);
|
|
42959
|
+
if (!(0, import_node_fs47.existsSync)(p)) return null;
|
|
42906
42960
|
try {
|
|
42907
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
42961
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs47.statSync)(q).mtimeMs);
|
|
42908
42962
|
} catch {
|
|
42909
42963
|
return null;
|
|
42910
42964
|
}
|
|
@@ -42930,7 +42984,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
42930
42984
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
42931
42985
|
);
|
|
42932
42986
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
42933
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
42987
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs47.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
42934
42988
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
42935
42989
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
42936
42990
|
else console.log(renderPluginCachePlan(plan, result));
|
|
@@ -42938,7 +42992,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
42938
42992
|
});
|
|
42939
42993
|
function readReleaseCatchupState(path2) {
|
|
42940
42994
|
try {
|
|
42941
|
-
const parsed = JSON.parse((0,
|
|
42995
|
+
const parsed = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
|
|
42942
42996
|
return typeof parsed?.checkedAt === "number" ? parsed : void 0;
|
|
42943
42997
|
} catch {
|
|
42944
42998
|
return void 0;
|
|
@@ -42946,8 +43000,8 @@ function readReleaseCatchupState(path2) {
|
|
|
42946
43000
|
}
|
|
42947
43001
|
function writeReleaseCatchupState(path2, state) {
|
|
42948
43002
|
try {
|
|
42949
|
-
(0,
|
|
42950
|
-
(0,
|
|
43003
|
+
(0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
|
|
43004
|
+
(0, import_node_fs47.writeFileSync)(path2, `${JSON.stringify(state)}
|
|
42951
43005
|
`);
|
|
42952
43006
|
} catch {
|
|
42953
43007
|
}
|