@mutmutco/cli 3.117.1 → 3.118.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +567 -519
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -5000,7 +5000,7 @@ var program = new Command();
|
|
|
5000
5000
|
|
|
5001
5001
|
// src/index.ts
|
|
5002
5002
|
var import_promises11 = require("node:fs/promises");
|
|
5003
|
-
var
|
|
5003
|
+
var import_node_fs47 = require("node:fs");
|
|
5004
5004
|
var import_node_child_process20 = require("node:child_process");
|
|
5005
5005
|
|
|
5006
5006
|
// src/cli-shared.ts
|
|
@@ -8708,6 +8708,40 @@ function cachedReadNote(cachedAt, now = Date.now()) {
|
|
|
8708
8708
|
return `(cached ${hours < 1 ? "<1" : hours}h ago \u2014 the banner reads npm at most once a day)`;
|
|
8709
8709
|
}
|
|
8710
8710
|
|
|
8711
|
+
// src/schedules-drift-cache.ts
|
|
8712
|
+
var import_node_fs13 = require("node:fs");
|
|
8713
|
+
var import_node_path11 = require("node:path");
|
|
8714
|
+
var SCHEDULES_DRIFT_CACHE_MS = 6 * 36e5;
|
|
8715
|
+
function schedulesDriftCachePath(runtimeRoot) {
|
|
8716
|
+
return (0, import_node_path11.join)(runtimeRoot, "head-ts", ".schedules-drift");
|
|
8717
|
+
}
|
|
8718
|
+
function readSchedulesDriftCache(cachePath, now = Date.now(), read = import_node_fs13.readFileSync) {
|
|
8719
|
+
let parsed;
|
|
8720
|
+
try {
|
|
8721
|
+
parsed = JSON.parse(read(cachePath, "utf8"));
|
|
8722
|
+
} catch {
|
|
8723
|
+
return void 0;
|
|
8724
|
+
}
|
|
8725
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
8726
|
+
const { driftLines, at } = parsed;
|
|
8727
|
+
if (!Array.isArray(driftLines) || driftLines.some((l) => typeof l !== "string")) return void 0;
|
|
8728
|
+
if (typeof at !== "number" || !Number.isFinite(at)) return void 0;
|
|
8729
|
+
const age = now - at;
|
|
8730
|
+
if (age < 0 || age >= SCHEDULES_DRIFT_CACHE_MS) return void 0;
|
|
8731
|
+
return { driftLines, at };
|
|
8732
|
+
}
|
|
8733
|
+
function writeSchedulesDriftCache(cachePath, driftLines, now = Date.now()) {
|
|
8734
|
+
try {
|
|
8735
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(cachePath), { recursive: true });
|
|
8736
|
+
(0, import_node_fs13.writeFileSync)(cachePath, JSON.stringify({ driftLines, at: now }), "utf8");
|
|
8737
|
+
} catch {
|
|
8738
|
+
}
|
|
8739
|
+
}
|
|
8740
|
+
function cachedSweepNote(cachedAt, now = Date.now()) {
|
|
8741
|
+
const hours = cacheAgeHours(cachedAt, now);
|
|
8742
|
+
return `cached ${hours < 1 ? "<1" : hours}h ago \u2014 doctor sweeps the org notebook at most every ${SCHEDULES_DRIFT_CACHE_MS / 36e5}h (run \`mmi-cli harbour org schedules\` for a live read)`;
|
|
8743
|
+
}
|
|
8744
|
+
|
|
8711
8745
|
// src/marketplace-autoupdate.ts
|
|
8712
8746
|
var KNOWN_MARKETPLACES_RELATIVE = [".claude", "plugins", "known_marketplaces.json"];
|
|
8713
8747
|
var MMI_MARKETPLACE_NAME = "mutmutco";
|
|
@@ -8919,8 +8953,8 @@ function marketplaceRows(name, known, settings, remedy = "manual") {
|
|
|
8919
8953
|
}
|
|
8920
8954
|
|
|
8921
8955
|
// src/hook-activity.ts
|
|
8922
|
-
var
|
|
8923
|
-
var
|
|
8956
|
+
var import_node_fs14 = require("node:fs");
|
|
8957
|
+
var import_node_path12 = require("node:path");
|
|
8924
8958
|
var DEFAULT_SURFACE = "claude";
|
|
8925
8959
|
function activityLogPath(cwd) {
|
|
8926
8960
|
return repoRuntimeStatePath(cwd, "hooks", "activity.jsonl");
|
|
@@ -8933,20 +8967,20 @@ function appendHookActivity(cwd, entry) {
|
|
|
8933
8967
|
surface: DEFAULT_SURFACE,
|
|
8934
8968
|
...entry
|
|
8935
8969
|
};
|
|
8936
|
-
(0,
|
|
8937
|
-
(0,
|
|
8970
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path12.dirname)(path2), { recursive: true });
|
|
8971
|
+
(0, import_node_fs14.appendFileSync)(path2, `${JSON.stringify(line)}
|
|
8938
8972
|
`, "utf8");
|
|
8939
8973
|
} catch {
|
|
8940
8974
|
}
|
|
8941
8975
|
}
|
|
8942
8976
|
|
|
8943
8977
|
// src/worktree.ts
|
|
8944
|
-
var
|
|
8945
|
-
var
|
|
8978
|
+
var import_node_fs15 = require("node:fs");
|
|
8979
|
+
var import_node_path14 = require("node:path");
|
|
8946
8980
|
|
|
8947
8981
|
// src/file-lock.ts
|
|
8948
8982
|
var import_promises2 = require("node:fs/promises");
|
|
8949
|
-
var
|
|
8983
|
+
var import_node_path13 = require("node:path");
|
|
8950
8984
|
var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
8951
8985
|
var IMMEDIATE_RETRY_BUDGET = 3;
|
|
8952
8986
|
var FileLockBusyError = class extends Error {
|
|
@@ -9031,7 +9065,7 @@ async function releaseFileLock(lockPath, guard) {
|
|
|
9031
9065
|
}
|
|
9032
9066
|
async function withFileLock(lockPath, opts, fn) {
|
|
9033
9067
|
const resolved = resolveFileLockOpts(opts);
|
|
9034
|
-
await (0, import_promises2.mkdir)((0,
|
|
9068
|
+
await (0, import_promises2.mkdir)((0, import_node_path13.dirname)(lockPath), { recursive: true }).catch(() => void 0);
|
|
9035
9069
|
const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
|
|
9036
9070
|
try {
|
|
9037
9071
|
return await fn();
|
|
@@ -9058,35 +9092,35 @@ var PROVISION_ENV_MARKER = "MMI_PROVISION_RUNNING";
|
|
|
9058
9092
|
var realFsProbe = {
|
|
9059
9093
|
isDir: (p) => {
|
|
9060
9094
|
try {
|
|
9061
|
-
return (0,
|
|
9095
|
+
return (0, import_node_fs15.statSync)(p).isDirectory();
|
|
9062
9096
|
} catch {
|
|
9063
9097
|
return false;
|
|
9064
9098
|
}
|
|
9065
9099
|
},
|
|
9066
9100
|
isFile: (p) => {
|
|
9067
9101
|
try {
|
|
9068
|
-
return (0,
|
|
9102
|
+
return (0, import_node_fs15.statSync)(p).isFile();
|
|
9069
9103
|
} catch {
|
|
9070
9104
|
return false;
|
|
9071
9105
|
}
|
|
9072
9106
|
},
|
|
9073
9107
|
listDirs: (p) => {
|
|
9074
9108
|
try {
|
|
9075
|
-
return (0,
|
|
9109
|
+
return (0, import_node_fs15.readdirSync)(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
9076
9110
|
} catch {
|
|
9077
9111
|
return [];
|
|
9078
9112
|
}
|
|
9079
9113
|
},
|
|
9080
9114
|
readFile: (p) => {
|
|
9081
9115
|
try {
|
|
9082
|
-
return (0,
|
|
9116
|
+
return (0, import_node_fs15.readFileSync)(p, "utf8");
|
|
9083
9117
|
} catch {
|
|
9084
9118
|
return void 0;
|
|
9085
9119
|
}
|
|
9086
9120
|
}
|
|
9087
9121
|
};
|
|
9088
9122
|
function declaredProvision(fs2, abs) {
|
|
9089
|
-
const raw = fs2.readFile?.((0,
|
|
9123
|
+
const raw = fs2.readFile?.((0, import_node_path14.join)(abs, PKG));
|
|
9090
9124
|
if (raw === void 0) return void 0;
|
|
9091
9125
|
try {
|
|
9092
9126
|
const scripts = JSON.parse(raw).scripts;
|
|
@@ -9098,13 +9132,13 @@ function declaredProvision(fs2, abs) {
|
|
|
9098
9132
|
}
|
|
9099
9133
|
function scanInstallDirs(root, fs2 = realFsProbe) {
|
|
9100
9134
|
const factsFor = (dir) => {
|
|
9101
|
-
const abs = dir ? (0,
|
|
9102
|
-
const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0,
|
|
9103
|
-
const hasPackageJson = fs2.isFile((0,
|
|
9135
|
+
const abs = dir ? (0, import_node_path14.join)(root, dir) : root;
|
|
9136
|
+
const match = LOCKFILE_INSTALLS.find((c) => fs2.isFile((0, import_node_path14.join)(abs, c.lockfile)));
|
|
9137
|
+
const hasPackageJson = fs2.isFile((0, import_node_path14.join)(abs, PKG));
|
|
9104
9138
|
return {
|
|
9105
9139
|
dir,
|
|
9106
9140
|
hasPackageJson,
|
|
9107
|
-
hasNodeModules: fs2.isDir((0,
|
|
9141
|
+
hasNodeModules: fs2.isDir((0, import_node_path14.join)(abs, NODE_MODULES)),
|
|
9108
9142
|
install: match?.command,
|
|
9109
9143
|
provision: hasPackageJson ? declaredProvision(fs2, abs) : void 0
|
|
9110
9144
|
};
|
|
@@ -9120,7 +9154,7 @@ function npmInstallTargets(dirs) {
|
|
|
9120
9154
|
}));
|
|
9121
9155
|
}
|
|
9122
9156
|
function isLinkedWorktree(root, fs2 = realFsProbe) {
|
|
9123
|
-
return fs2.isFile((0,
|
|
9157
|
+
return fs2.isFile((0, import_node_path14.join)(root, ".git"));
|
|
9124
9158
|
}
|
|
9125
9159
|
function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
9126
9160
|
if (!isLinkedWorktree(root, fs2)) return null;
|
|
@@ -9130,8 +9164,8 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
|
9130
9164
|
return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
|
|
9131
9165
|
}
|
|
9132
9166
|
function defaultCopyFile(from, to) {
|
|
9133
|
-
(0,
|
|
9134
|
-
(0,
|
|
9167
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path14.dirname)(to), { recursive: true });
|
|
9168
|
+
(0, import_node_fs15.copyFileSync)(from, to);
|
|
9135
9169
|
}
|
|
9136
9170
|
async function runDeclaredProvision(target, cwd, runInstall) {
|
|
9137
9171
|
const previous = process.env[PROVISION_ENV_MARKER];
|
|
@@ -9161,7 +9195,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9161
9195
|
const targets = npmInstallTargets(allDirs);
|
|
9162
9196
|
if (deps.validateInstall) {
|
|
9163
9197
|
for (const dir of allDirs.filter((d) => d.hasPackageJson && (d.provision ?? d.install) && d.hasNodeModules)) {
|
|
9164
|
-
const cwd = dir.dir ? (0,
|
|
9198
|
+
const cwd = dir.dir ? (0, import_node_path14.join)(worktreeRoot, dir.dir) : worktreeRoot;
|
|
9165
9199
|
if (!await deps.validateInstall(cwd)) {
|
|
9166
9200
|
targets.push({
|
|
9167
9201
|
dir: dir.dir,
|
|
@@ -9175,7 +9209,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9175
9209
|
const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules && !targetDirs.has(d.dir)).map((d) => d.dir);
|
|
9176
9210
|
const installed = [];
|
|
9177
9211
|
for (const target of targets) {
|
|
9178
|
-
const cwd = target.dir ? (0,
|
|
9212
|
+
const cwd = target.dir ? (0, import_node_path14.join)(worktreeRoot, target.dir) : worktreeRoot;
|
|
9179
9213
|
log(`installing deps: ${target.command} in ${target.dir || "."}`);
|
|
9180
9214
|
if (target.declared) await runDeclaredProvision(target, cwd, deps.runInstall);
|
|
9181
9215
|
else await deps.runInstall(target.command, cwd);
|
|
@@ -9185,7 +9219,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9185
9219
|
const copySkipped = [];
|
|
9186
9220
|
const primary = await deps.primaryCheckout();
|
|
9187
9221
|
for (const rel of LOCAL_ONLY_FILES) {
|
|
9188
|
-
const dest = (0,
|
|
9222
|
+
const dest = (0, import_node_path14.join)(worktreeRoot, rel);
|
|
9189
9223
|
if (fs2.isFile(dest)) {
|
|
9190
9224
|
copySkipped.push({ file: rel, reason: "already-present" });
|
|
9191
9225
|
continue;
|
|
@@ -9194,11 +9228,11 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
9194
9228
|
copySkipped.push({ file: rel, reason: "no-primary" });
|
|
9195
9229
|
continue;
|
|
9196
9230
|
}
|
|
9197
|
-
if (!fs2.isFile((0,
|
|
9231
|
+
if (!fs2.isFile((0, import_node_path14.join)(primary, rel))) {
|
|
9198
9232
|
copySkipped.push({ file: rel, reason: "absent-in-primary" });
|
|
9199
9233
|
continue;
|
|
9200
9234
|
}
|
|
9201
|
-
copyFile((0,
|
|
9235
|
+
copyFile((0, import_node_path14.join)(primary, rel), dest);
|
|
9202
9236
|
copied.push(rel);
|
|
9203
9237
|
log(`copied local config: ${rel}`);
|
|
9204
9238
|
}
|
|
@@ -9212,12 +9246,12 @@ function capWorktreeDirName(name, max = 40) {
|
|
|
9212
9246
|
}
|
|
9213
9247
|
function defaultWorktreePath(repoRoot2, branch) {
|
|
9214
9248
|
const safe = capWorktreeDirName(branch.replace(/[/\\]+/g, "-"));
|
|
9215
|
-
return (0,
|
|
9249
|
+
return (0, import_node_path14.join)((0, import_node_path14.dirname)(repoRoot2), "mmi-worktrees", (0, import_node_path14.basename)(repoRoot2), safe);
|
|
9216
9250
|
}
|
|
9217
9251
|
async function primaryCheckoutRootOf(git2) {
|
|
9218
9252
|
try {
|
|
9219
9253
|
const out = (await git2(["rev-parse", "--path-format=absolute", "--git-common-dir"])).trim();
|
|
9220
|
-
return out ? (0,
|
|
9254
|
+
return out ? (0, import_node_path14.dirname)(out) : void 0;
|
|
9221
9255
|
} catch {
|
|
9222
9256
|
return void 0;
|
|
9223
9257
|
}
|
|
@@ -9355,7 +9389,7 @@ function commandLadderHint() {
|
|
|
9355
9389
|
}
|
|
9356
9390
|
|
|
9357
9391
|
// src/index.ts
|
|
9358
|
-
var
|
|
9392
|
+
var import_node_path44 = require("node:path");
|
|
9359
9393
|
|
|
9360
9394
|
// src/merge-ci-policy.ts
|
|
9361
9395
|
function resolveMergeCiPolicy(input) {
|
|
@@ -10015,13 +10049,13 @@ function planManagedGitignore(current) {
|
|
|
10015
10049
|
}
|
|
10016
10050
|
|
|
10017
10051
|
// src/docs-index-command.ts
|
|
10018
|
-
var
|
|
10019
|
-
var
|
|
10052
|
+
var import_node_fs17 = require("node:fs");
|
|
10053
|
+
var import_node_path16 = require("node:path");
|
|
10020
10054
|
|
|
10021
10055
|
// src/doc-refs-core.ts
|
|
10022
10056
|
var import_node_child_process5 = require("node:child_process");
|
|
10023
|
-
var
|
|
10024
|
-
var
|
|
10057
|
+
var import_node_fs16 = require("node:fs");
|
|
10058
|
+
var import_node_path15 = require("node:path");
|
|
10025
10059
|
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
10026
10060
|
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
10027
10061
|
var FWD_RE = /<!--\s*forward-ref:\s*(\S+?)\s*-->/;
|
|
@@ -10080,7 +10114,7 @@ function checkPins(root, readFile9, docs2) {
|
|
|
10080
10114
|
findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
|
|
10081
10115
|
continue;
|
|
10082
10116
|
}
|
|
10083
|
-
const source = readFile9((0,
|
|
10117
|
+
const source = readFile9((0, import_node_path15.join)(root, pin.file));
|
|
10084
10118
|
if (source == null) {
|
|
10085
10119
|
findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
|
|
10086
10120
|
continue;
|
|
@@ -10142,11 +10176,11 @@ function checkRefs(root, deps, docs2) {
|
|
|
10142
10176
|
for (const { ref } of extractRefs(markdown)) allFirstSegments.add(refFirstSegment(ref));
|
|
10143
10177
|
}
|
|
10144
10178
|
const tracked = allFirstSegments.size ? deps.trackedFirstSegments?.([...allFirstSegments]) ?? null : null;
|
|
10145
|
-
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0,
|
|
10179
|
+
const firstVerifiable = (first) => tracked ? tracked.has(first) : exists((0, import_node_path15.join)(root, first));
|
|
10146
10180
|
const candidates = [];
|
|
10147
10181
|
const direct = [];
|
|
10148
10182
|
for (const [doc, markdown] of Object.entries(docs2)) {
|
|
10149
|
-
const docDir =
|
|
10183
|
+
const docDir = import_node_path15.posix.dirname(doc);
|
|
10150
10184
|
const base = docDir === "." ? "" : docDir;
|
|
10151
10185
|
const covered = /* @__PURE__ */ new Set();
|
|
10152
10186
|
const markers = [];
|
|
@@ -10155,21 +10189,21 @@ function checkRefs(root, deps, docs2) {
|
|
|
10155
10189
|
direct.push({ kind: "malformed-forward-ref", doc, line: fwd.line, detail: fwd.text });
|
|
10156
10190
|
continue;
|
|
10157
10191
|
}
|
|
10158
|
-
const docRel =
|
|
10159
|
-
const rootRel =
|
|
10192
|
+
const docRel = import_node_path15.posix.normalize(import_node_path15.posix.join(base, fwd.target));
|
|
10193
|
+
const rootRel = import_node_path15.posix.normalize(fwd.target.replace(/^\/+/, ""));
|
|
10160
10194
|
markers.push({ target: fwd.target, line: fwd.line, docRel, rootRel });
|
|
10161
10195
|
covered.add(docRel);
|
|
10162
10196
|
covered.add(rootRel);
|
|
10163
10197
|
}
|
|
10164
10198
|
const links = extractLinks(markdown).map(({ target, line }) => {
|
|
10165
|
-
const resolved =
|
|
10166
|
-
return { target, line, resolved, missing: !exists((0,
|
|
10199
|
+
const resolved = import_node_path15.posix.normalize(import_node_path15.posix.join(base, target));
|
|
10200
|
+
return { target, line, resolved, missing: !exists((0, import_node_path15.join)(root, resolved)) };
|
|
10167
10201
|
});
|
|
10168
10202
|
for (const marker of markers) {
|
|
10169
10203
|
const coversMissing = links.some(
|
|
10170
10204
|
(l) => l.missing && (l.resolved === marker.docRel || l.resolved === marker.rootRel)
|
|
10171
10205
|
);
|
|
10172
|
-
if (!coversMissing && (exists((0,
|
|
10206
|
+
if (!coversMissing && (exists((0, import_node_path15.join)(root, marker.docRel)) || exists((0, import_node_path15.join)(root, marker.rootRel)))) {
|
|
10173
10207
|
direct.push({
|
|
10174
10208
|
kind: "stale-forward-ref",
|
|
10175
10209
|
doc,
|
|
@@ -10180,7 +10214,7 @@ function checkRefs(root, deps, docs2) {
|
|
|
10180
10214
|
}
|
|
10181
10215
|
for (const { ref, line } of extractRefs(markdown)) {
|
|
10182
10216
|
if (!firstVerifiable(refFirstSegment(ref))) continue;
|
|
10183
|
-
if (!exists((0,
|
|
10217
|
+
if (!exists((0, import_node_path15.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
|
|
10184
10218
|
}
|
|
10185
10219
|
for (const { target, line, resolved, missing } of links) {
|
|
10186
10220
|
if (resolved.startsWith("..")) {
|
|
@@ -10228,22 +10262,22 @@ function checkCommands(docs2, commandPaths) {
|
|
|
10228
10262
|
return { ok: findings.length === 0, findings, warnings: [] };
|
|
10229
10263
|
}
|
|
10230
10264
|
function readFileOrNull(path2) {
|
|
10231
|
-
return (0,
|
|
10265
|
+
return (0, import_node_fs16.existsSync)(path2) ? (0, import_node_fs16.readFileSync)(path2, "utf8") : null;
|
|
10232
10266
|
}
|
|
10233
10267
|
function walk(dir, root, out) {
|
|
10234
|
-
for (const entry of (0,
|
|
10235
|
-
const full = (0,
|
|
10236
|
-
if ((0,
|
|
10268
|
+
for (const entry of (0, import_node_fs16.readdirSync)(dir)) {
|
|
10269
|
+
const full = (0, import_node_path15.join)(dir, entry);
|
|
10270
|
+
if ((0, import_node_fs16.statSync)(full).isDirectory()) walk(full, root, out);
|
|
10237
10271
|
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
10238
10272
|
}
|
|
10239
10273
|
return out;
|
|
10240
10274
|
}
|
|
10241
10275
|
function defaultListDocs(root) {
|
|
10242
|
-
const docsDir = (0,
|
|
10243
|
-
const docs2 = ((0,
|
|
10276
|
+
const docsDir = (0, import_node_path15.join)(root, "docs");
|
|
10277
|
+
const docs2 = ((0, import_node_fs16.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
|
|
10244
10278
|
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
10245
10279
|
);
|
|
10246
|
-
return [...ROOT_DOCS.filter((rel) => (0,
|
|
10280
|
+
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs16.existsSync)((0, import_node_path15.join)(root, rel))), ...docs2];
|
|
10247
10281
|
}
|
|
10248
10282
|
var CHECK_IGNORE_MAX_BUFFER = 32 * 1024 * 1024;
|
|
10249
10283
|
function defaultIsIgnored(root, relPaths, exec = import_node_child_process5.execFileSync) {
|
|
@@ -10295,7 +10329,7 @@ function defaultTrackedFirstSegments(root, firstSegments, exec = import_node_chi
|
|
|
10295
10329
|
}
|
|
10296
10330
|
function runDocRefs(root, deps = {}) {
|
|
10297
10331
|
const readFile9 = deps.readFile ?? readFileOrNull;
|
|
10298
|
-
const exists = deps.exists ??
|
|
10332
|
+
const exists = deps.exists ?? import_node_fs16.existsSync;
|
|
10299
10333
|
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
10300
10334
|
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
10301
10335
|
const trackedFirstSegments = deps.trackedFirstSegments ?? ((segs) => defaultTrackedFirstSegments(root, segs));
|
|
@@ -10303,7 +10337,7 @@ function runDocRefs(root, deps = {}) {
|
|
|
10303
10337
|
const walked = listDocs(root);
|
|
10304
10338
|
const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
|
|
10305
10339
|
const docs2 = Object.fromEntries(
|
|
10306
|
-
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0,
|
|
10340
|
+
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile9((0, import_node_path15.join)(root, rel))]).filter(([, body]) => body != null)
|
|
10307
10341
|
);
|
|
10308
10342
|
const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs2);
|
|
10309
10343
|
const findings = [
|
|
@@ -10410,31 +10444,31 @@ function walkMarkdown(dir) {
|
|
|
10410
10444
|
const stack = [dir];
|
|
10411
10445
|
while (stack.length) {
|
|
10412
10446
|
const current = stack.pop();
|
|
10413
|
-
for (const entry of (0,
|
|
10414
|
-
const full = (0,
|
|
10447
|
+
for (const entry of (0, import_node_fs17.readdirSync)(current, { withFileTypes: true })) {
|
|
10448
|
+
const full = (0, import_node_path16.join)(current, entry.name);
|
|
10415
10449
|
if (entry.isDirectory()) {
|
|
10416
10450
|
stack.push(full);
|
|
10417
10451
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
10418
|
-
out.push((0,
|
|
10452
|
+
out.push((0, import_node_path16.relative)(dir, full).split(import_node_path16.sep).join("/"));
|
|
10419
10453
|
}
|
|
10420
10454
|
}
|
|
10421
10455
|
}
|
|
10422
10456
|
return out;
|
|
10423
10457
|
}
|
|
10424
10458
|
function createDocsIndexDeps(repoRoot2) {
|
|
10425
|
-
const docsDir = (0,
|
|
10426
|
-
const indexPath = (0,
|
|
10459
|
+
const docsDir = (0, import_node_path16.join)(repoRoot2, "docs");
|
|
10460
|
+
const indexPath = (0, import_node_path16.join)(repoRoot2, DOCS_INDEX_PATH);
|
|
10427
10461
|
return {
|
|
10428
10462
|
listDocs: () => {
|
|
10429
|
-
if (!(0,
|
|
10463
|
+
if (!(0, import_node_fs17.existsSync)(docsDir)) return [];
|
|
10430
10464
|
const walked = walkMarkdown(docsDir).filter(isRoutableDocsPath);
|
|
10431
10465
|
if (!walked.length) return [];
|
|
10432
10466
|
const ignored = defaultIsIgnored(repoRoot2, walked.map((rel) => `docs/${rel}`));
|
|
10433
10467
|
return walked.filter((rel) => !ignored.has(`docs/${rel}`)).sort();
|
|
10434
10468
|
},
|
|
10435
|
-
readDoc: (relPath) => (0,
|
|
10436
|
-
readIndex: () => (0,
|
|
10437
|
-
writeIndex: (content) => (0,
|
|
10469
|
+
readDoc: (relPath) => (0, import_node_fs17.readFileSync)((0, import_node_path16.join)(docsDir, relPath), "utf8"),
|
|
10470
|
+
readIndex: () => (0, import_node_fs17.existsSync)(indexPath) ? (0, import_node_fs17.readFileSync)(indexPath, "utf8") : null,
|
|
10471
|
+
writeIndex: (content) => (0, import_node_fs17.writeFileSync)(indexPath, content, "utf8")
|
|
10438
10472
|
};
|
|
10439
10473
|
}
|
|
10440
10474
|
|
|
@@ -11219,14 +11253,14 @@ function parseVerifyBroker(stdout) {
|
|
|
11219
11253
|
}
|
|
11220
11254
|
|
|
11221
11255
|
// src/train-apply.ts
|
|
11222
|
-
var
|
|
11256
|
+
var import_node_fs21 = require("node:fs");
|
|
11223
11257
|
var import_promises4 = require("node:fs/promises");
|
|
11224
|
-
var
|
|
11258
|
+
var import_node_path20 = require("node:path");
|
|
11225
11259
|
|
|
11226
11260
|
// src/plugin-guard-io.ts
|
|
11227
|
-
var
|
|
11261
|
+
var import_node_fs18 = require("node:fs");
|
|
11228
11262
|
var import_node_child_process7 = require("node:child_process");
|
|
11229
|
-
var
|
|
11263
|
+
var import_node_path17 = require("node:path");
|
|
11230
11264
|
var import_node_os5 = require("node:os");
|
|
11231
11265
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
11232
11266
|
|
|
@@ -11529,21 +11563,21 @@ function runHostBin(bin, args, opts) {
|
|
|
11529
11563
|
return step ? execFileHard(file, argv, { ...shared, step }) : execFileP2(file, argv, shared);
|
|
11530
11564
|
}
|
|
11531
11565
|
function surfaceConfigRoot(surface, env = process.env, home = (0, import_node_os5.homedir)()) {
|
|
11532
|
-
if (surface === "codex") return env.CODEX_HOME?.trim() || (0,
|
|
11533
|
-
if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0,
|
|
11534
|
-
if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0,
|
|
11535
|
-
if (surface === "cursor") return (0,
|
|
11566
|
+
if (surface === "codex") return env.CODEX_HOME?.trim() || (0, import_node_path17.join)(home, ".codex");
|
|
11567
|
+
if (surface === "kimi") return env.KIMI_CODE_HOME?.trim() || (0, import_node_path17.join)(home, ".kimi-code");
|
|
11568
|
+
if (surface === "kilo") return env.KILO_CONFIG_DIR?.trim() || (0, import_node_path17.join)(home, ".config", "kilo");
|
|
11569
|
+
if (surface === "cursor") return (0, import_node_path17.join)(home, ".cursor");
|
|
11536
11570
|
if (surface === "jervcode") {
|
|
11537
|
-
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0,
|
|
11571
|
+
return env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim() || (0, import_node_path17.join)(home, ".jerv", "agent");
|
|
11538
11572
|
}
|
|
11539
|
-
return (0,
|
|
11573
|
+
return (0, import_node_path17.join)(home, ".claude");
|
|
11540
11574
|
}
|
|
11541
11575
|
var installedPluginsPath = (surface = detectSurface(process.env)) => {
|
|
11542
|
-
return (0,
|
|
11576
|
+
return (0, import_node_path17.join)(surfaceConfigRoot(surface), "plugins", "installed_plugins.json");
|
|
11543
11577
|
};
|
|
11544
11578
|
function readInstalledPlugins(surface = detectSurface(process.env)) {
|
|
11545
11579
|
try {
|
|
11546
|
-
return JSON.parse((0,
|
|
11580
|
+
return JSON.parse((0, import_node_fs18.readFileSync)(installedPluginsPath(surface), "utf8"));
|
|
11547
11581
|
} catch {
|
|
11548
11582
|
return null;
|
|
11549
11583
|
}
|
|
@@ -11552,17 +11586,17 @@ function marketplaceCloneCandidates(surface, home, env = process.env) {
|
|
|
11552
11586
|
if (surface === "codex") {
|
|
11553
11587
|
const root = surfaceConfigRoot(surface, env, home);
|
|
11554
11588
|
return [
|
|
11555
|
-
(0,
|
|
11556
|
-
(0,
|
|
11589
|
+
(0, import_node_path17.join)(root, ".tmp", "marketplaces", CODEX_MARKETPLACE),
|
|
11590
|
+
(0, import_node_path17.join)(root, "plugins", "marketplaces", CODEX_MARKETPLACE)
|
|
11557
11591
|
];
|
|
11558
11592
|
}
|
|
11559
11593
|
if (surface === "kimi") return [];
|
|
11560
11594
|
if (surface === "kilo") return [];
|
|
11561
11595
|
if (surface === "cursor") return [];
|
|
11562
11596
|
if (surface === "jervcode") return [];
|
|
11563
|
-
return [(0,
|
|
11597
|
+
return [(0, import_node_path17.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
|
|
11564
11598
|
}
|
|
11565
|
-
function marketplaceClonePresent(surface, home, exists =
|
|
11599
|
+
function marketplaceClonePresent(surface, home, exists = import_node_fs18.existsSync, env = process.env) {
|
|
11566
11600
|
return marketplaceCloneCandidates(surface, home, env).some(exists);
|
|
11567
11601
|
}
|
|
11568
11602
|
function runHostBinSync(bin, args) {
|
|
@@ -11594,7 +11628,7 @@ function codexPluginStatus() {
|
|
|
11594
11628
|
}
|
|
11595
11629
|
function countCodexHookCommands(path2) {
|
|
11596
11630
|
try {
|
|
11597
|
-
const parsed = JSON.parse((0,
|
|
11631
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path2, "utf8"));
|
|
11598
11632
|
let count = 0;
|
|
11599
11633
|
for (const groups of Object.values(parsed.hooks ?? {})) {
|
|
11600
11634
|
for (const group of groups) {
|
|
@@ -11611,11 +11645,11 @@ function codexHookTrustState(status = codexPluginStatus()) {
|
|
|
11611
11645
|
return { applicable: false, trusted: false, trustedCount: 0, requiredCount: 0 };
|
|
11612
11646
|
}
|
|
11613
11647
|
const root = surfaceConfigRoot("codex");
|
|
11614
|
-
const hooksPath = (0,
|
|
11648
|
+
const hooksPath = (0, import_node_path17.join)(root, "plugins", "cache", CODEX_MARKETPLACE, "mmi", status.version, "hooks", "codex-hooks.json");
|
|
11615
11649
|
const requiredCount = countCodexHookCommands(hooksPath);
|
|
11616
11650
|
let config = "";
|
|
11617
11651
|
try {
|
|
11618
|
-
config = (0,
|
|
11652
|
+
config = (0, import_node_fs18.readFileSync)((0, import_node_path17.join)(root, "config.toml"), "utf8");
|
|
11619
11653
|
} catch {
|
|
11620
11654
|
return { applicable: true, trusted: false, trustedCount: 0, requiredCount };
|
|
11621
11655
|
}
|
|
@@ -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.118.0",
|
|
15824
|
+
tag: "v3.118.0",
|
|
15825
|
+
commit: "4f9600d3bf89",
|
|
15826
|
+
npm: "@mutmutco/cli@3.118.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.118.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.118.0 and redeploy the Hub Lambda from tag v3.118.0 (4f9600d3bf89); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15850
|
+
v3Target: "v3.118.0 (@mutmutco/cli@3.118.0, tag commit 4f9600d3bf89 \u2014 the preserved latest-v3 distribution, D6b)"
|
|
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
|
}
|
|
@@ -24864,8 +24898,8 @@ function consolidateCommandNamespaces(program3) {
|
|
|
24864
24898
|
}
|
|
24865
24899
|
|
|
24866
24900
|
// src/pi-plugin-registration.ts
|
|
24867
|
-
var
|
|
24868
|
-
var
|
|
24901
|
+
var import_node_fs25 = require("node:fs");
|
|
24902
|
+
var import_node_path23 = require("node:path");
|
|
24869
24903
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
24870
24904
|
|
|
24871
24905
|
// src/plugin-cache-prune.ts
|
|
@@ -25123,48 +25157,48 @@ function newestExistingPiPlugin(home) {
|
|
|
25123
25157
|
const cacheRoot = pluginCacheRoot(home);
|
|
25124
25158
|
let names;
|
|
25125
25159
|
try {
|
|
25126
|
-
names = (0,
|
|
25160
|
+
names = (0, import_node_fs25.readdirSync)(cacheRoot);
|
|
25127
25161
|
} catch {
|
|
25128
25162
|
return void 0;
|
|
25129
25163
|
}
|
|
25130
25164
|
for (const version of names.filter(isVersionDirName).sort((a, b) => compareVersions(b, a))) {
|
|
25131
|
-
const candidate = (0,
|
|
25132
|
-
if ((0,
|
|
25165
|
+
const candidate = (0, import_node_path23.join)(cacheRoot, version, ".pi-plugin");
|
|
25166
|
+
if ((0, import_node_fs25.existsSync)(candidate)) return candidate;
|
|
25133
25167
|
}
|
|
25134
25168
|
return void 0;
|
|
25135
25169
|
}
|
|
25136
25170
|
function expectedPiPluginPath(home, env, installedVersion) {
|
|
25137
25171
|
const root = env.CLAUDE_PLUGIN_ROOT?.trim();
|
|
25138
|
-
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0,
|
|
25172
|
+
if (root && /[\\/]mutmutco[\\/]mmi[\\/]/.test(root)) return (0, import_node_path23.join)(root, ".pi-plugin");
|
|
25139
25173
|
const version = installedVersion ?? runningPluginVersion(env);
|
|
25140
25174
|
if (version) {
|
|
25141
|
-
const pinned = (0,
|
|
25142
|
-
if ((0,
|
|
25175
|
+
const pinned = (0, import_node_path23.join)(home, ".claude", "plugins", "cache", "mutmutco", "mmi", version, ".pi-plugin");
|
|
25176
|
+
if ((0, import_node_fs25.existsSync)(pinned)) return pinned;
|
|
25143
25177
|
}
|
|
25144
25178
|
return newestExistingPiPlugin(home);
|
|
25145
25179
|
}
|
|
25146
25180
|
function agentDirs(home, env = process.env) {
|
|
25147
25181
|
const override = env.JERVCODE_CODING_AGENT_DIR?.trim() || env.PI_CODING_AGENT_DIR?.trim();
|
|
25148
25182
|
if (override) return [override];
|
|
25149
|
-
const jerv = (0,
|
|
25150
|
-
const pi = (0,
|
|
25151
|
-
if (!(0,
|
|
25183
|
+
const jerv = (0, import_node_path23.join)(home, ".jerv", "agent");
|
|
25184
|
+
const pi = (0, import_node_path23.join)(home, ".pi", "agent");
|
|
25185
|
+
if (!(0, import_node_fs25.existsSync)(jerv) && !(0, import_node_fs25.existsSync)(pi)) return [];
|
|
25152
25186
|
const dirs = [jerv];
|
|
25153
|
-
if ((0,
|
|
25187
|
+
if ((0, import_node_fs25.existsSync)(pi) && pi !== jerv) dirs.push(pi);
|
|
25154
25188
|
return dirs;
|
|
25155
25189
|
}
|
|
25156
25190
|
function settingsPath(agentDir) {
|
|
25157
|
-
return (0,
|
|
25191
|
+
return (0, import_node_path23.join)(agentDir, "settings.json");
|
|
25158
25192
|
}
|
|
25159
25193
|
function readPiPluginState(home, env, installedVersion) {
|
|
25160
25194
|
const dirs = agentDirs(home, env);
|
|
25161
25195
|
if (dirs.length === 0) return void 0;
|
|
25162
25196
|
const expectedPath = expectedPiPluginPath(home, env, installedVersion);
|
|
25163
25197
|
if (!expectedPath) return void 0;
|
|
25164
|
-
const file = dirs.map(settingsPath).find((p) => (0,
|
|
25165
|
-
if (!(0,
|
|
25198
|
+
const file = dirs.map(settingsPath).find((p) => (0, import_node_fs25.existsSync)(p)) ?? settingsPath(dirs[0]);
|
|
25199
|
+
if (!(0, import_node_fs25.existsSync)(file)) return { expectedPath, settingsReadable: true };
|
|
25166
25200
|
try {
|
|
25167
|
-
const parsed = JSON.parse((0,
|
|
25201
|
+
const parsed = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf8"));
|
|
25168
25202
|
const packages = Array.isArray(parsed.packages) ? parsed.packages : [];
|
|
25169
25203
|
return { expectedPath, registeredPath: packages.find((p) => typeof p === "string" && isMmiPiPackage(p)), settingsReadable: true };
|
|
25170
25204
|
} catch {
|
|
@@ -25188,20 +25222,20 @@ function acquirePiSettingsLock2(settingsFile) {
|
|
|
25188
25222
|
return void 0;
|
|
25189
25223
|
}
|
|
25190
25224
|
function atomicWriteSettings(file, body) {
|
|
25191
|
-
(0,
|
|
25225
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(file), { recursive: true });
|
|
25192
25226
|
const tmp = `${file}.tmp-${process.pid}`;
|
|
25193
|
-
(0,
|
|
25227
|
+
(0, import_node_fs25.writeFileSync)(tmp, body, "utf8");
|
|
25194
25228
|
try {
|
|
25195
|
-
(0,
|
|
25229
|
+
(0, import_node_fs25.renameSync)(tmp, file);
|
|
25196
25230
|
} catch (renameError) {
|
|
25197
|
-
(0,
|
|
25231
|
+
(0, import_node_fs25.rmSync)(tmp, { force: true });
|
|
25198
25232
|
throw renameError;
|
|
25199
25233
|
}
|
|
25200
25234
|
}
|
|
25201
25235
|
function healOneAgentDir(agentDir, expectedPath) {
|
|
25202
25236
|
const file = settingsPath(agentDir);
|
|
25203
|
-
const release = (0,
|
|
25204
|
-
if ((0,
|
|
25237
|
+
const release = (0, import_node_fs25.existsSync)(file) ? acquirePiSettingsLock2(file) : void 0;
|
|
25238
|
+
if ((0, import_node_fs25.existsSync)(file) && !release) {
|
|
25205
25239
|
return {
|
|
25206
25240
|
ok: false,
|
|
25207
25241
|
detail: `Pi's settings lock (${file}.lock) is held by another process; nothing written, retry on the next doctor run`,
|
|
@@ -25210,9 +25244,9 @@ function healOneAgentDir(agentDir, expectedPath) {
|
|
|
25210
25244
|
}
|
|
25211
25245
|
try {
|
|
25212
25246
|
let parsed = {};
|
|
25213
|
-
if ((0,
|
|
25247
|
+
if ((0, import_node_fs25.existsSync)(file)) {
|
|
25214
25248
|
try {
|
|
25215
|
-
const raw = JSON.parse((0,
|
|
25249
|
+
const raw = JSON.parse((0, import_node_fs25.readFileSync)(file, "utf8"));
|
|
25216
25250
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25217
25251
|
return { ok: false, detail: "settings.json unreadable \u2014 nothing written (fail closed)" };
|
|
25218
25252
|
}
|
|
@@ -25264,20 +25298,20 @@ function healPiPluginRegistration(home, env, installedVersion) {
|
|
|
25264
25298
|
}
|
|
25265
25299
|
|
|
25266
25300
|
// src/claude-binary-doctor.ts
|
|
25267
|
-
var
|
|
25301
|
+
var import_node_fs27 = require("node:fs");
|
|
25268
25302
|
var import_node_os11 = require("node:os");
|
|
25269
|
-
var
|
|
25303
|
+
var import_node_path25 = require("node:path");
|
|
25270
25304
|
|
|
25271
25305
|
// src/jerv-cli-spawn.ts
|
|
25272
|
-
var
|
|
25306
|
+
var import_node_fs26 = require("node:fs");
|
|
25273
25307
|
var import_node_os10 = require("node:os");
|
|
25274
|
-
var
|
|
25308
|
+
var import_node_path24 = require("node:path");
|
|
25275
25309
|
var WIN_NAMES = ["jerv-cli.cmd", "jerv-cli.exe", "jerv-cli"];
|
|
25276
25310
|
var POSIX_NAMES = ["jerv-cli"];
|
|
25277
|
-
var JERV_CLI_ENTRY = (0,
|
|
25311
|
+
var JERV_CLI_ENTRY = (0, import_node_path24.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
25278
25312
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
25279
25313
|
if (platform2 !== "win32") {
|
|
25280
|
-
return pathEnv.split(
|
|
25314
|
+
return pathEnv.split(import_node_path24.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
25281
25315
|
}
|
|
25282
25316
|
if (pathEnv.includes(";")) {
|
|
25283
25317
|
return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
|
|
@@ -25310,10 +25344,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os10.hom
|
|
|
25310
25344
|
push(normalizeSpawnPathEntry(entry, platform2));
|
|
25311
25345
|
}
|
|
25312
25346
|
if (platform2 === "win32") {
|
|
25313
|
-
if (env.APPDATA) push((0,
|
|
25314
|
-
if (env.LOCALAPPDATA) push((0,
|
|
25347
|
+
if (env.APPDATA) push((0, import_node_path24.join)(env.APPDATA, "npm"));
|
|
25348
|
+
if (env.LOCALAPPDATA) push((0, import_node_path24.join)(env.LOCALAPPDATA, "npm"));
|
|
25315
25349
|
} else {
|
|
25316
|
-
push((0,
|
|
25350
|
+
push((0, import_node_path24.join)(home, ".local", "bin"));
|
|
25317
25351
|
}
|
|
25318
25352
|
return out;
|
|
25319
25353
|
}
|
|
@@ -25321,23 +25355,23 @@ function jervCliCandidatePaths(env = process.env, home = (0, import_node_os10.ho
|
|
|
25321
25355
|
const names = platform2 === "win32" ? WIN_NAMES : POSIX_NAMES;
|
|
25322
25356
|
const out = [];
|
|
25323
25357
|
for (const dir of jervCliCandidateDirs(env, home, platform2)) {
|
|
25324
|
-
for (const name of names) out.push((0,
|
|
25358
|
+
for (const name of names) out.push((0, import_node_path24.join)(dir, name));
|
|
25325
25359
|
}
|
|
25326
25360
|
return out;
|
|
25327
25361
|
}
|
|
25328
|
-
function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homedir)(), platform2 = process.platform, exists =
|
|
25362
|
+
function resolveJervCliPath(env = process.env, home = (0, import_node_os10.homedir)(), platform2 = process.platform, exists = import_node_fs26.existsSync) {
|
|
25329
25363
|
for (const candidate of jervCliCandidatePaths(env, home, platform2)) {
|
|
25330
25364
|
if (exists(candidate)) return candidate;
|
|
25331
25365
|
}
|
|
25332
25366
|
return void 0;
|
|
25333
25367
|
}
|
|
25334
|
-
function resolveJervCliNodeEntry(shimPath, exists =
|
|
25335
|
-
const entry = (0,
|
|
25368
|
+
function resolveJervCliNodeEntry(shimPath, exists = import_node_fs26.existsSync) {
|
|
25369
|
+
const entry = (0, import_node_path24.join)((0, import_node_path24.dirname)(shimPath), JERV_CLI_ENTRY);
|
|
25336
25370
|
return exists(entry) ? entry : void 0;
|
|
25337
25371
|
}
|
|
25338
25372
|
function jervCliExecFileArgs(args, opts = {}) {
|
|
25339
25373
|
const platform2 = opts.platform ?? process.platform;
|
|
25340
|
-
const exists = opts.exists ??
|
|
25374
|
+
const exists = opts.exists ?? import_node_fs26.existsSync;
|
|
25341
25375
|
const resolved = resolveJervCliPath(opts.env ?? process.env, opts.home ?? (0, import_node_os10.homedir)(), platform2, exists);
|
|
25342
25376
|
if (resolved) {
|
|
25343
25377
|
const entry = resolveJervCliNodeEntry(resolved, exists);
|
|
@@ -25427,26 +25461,26 @@ function globalNodeModulesRoots(host) {
|
|
|
25427
25461
|
out.push(dir);
|
|
25428
25462
|
};
|
|
25429
25463
|
const prefix = env.npm_config_prefix?.trim();
|
|
25430
|
-
if (prefix) push(platform2 === "win32" ? (0,
|
|
25464
|
+
if (prefix) push(platform2 === "win32" ? (0, import_node_path25.join)(prefix, "node_modules") : (0, import_node_path25.join)(prefix, "lib", "node_modules"));
|
|
25431
25465
|
for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os11.homedir)(), platform2)) {
|
|
25432
|
-
push((0,
|
|
25433
|
-
push((0,
|
|
25466
|
+
push((0, import_node_path25.join)(dir, "node_modules"));
|
|
25467
|
+
push((0, import_node_path25.join)((0, import_node_path25.dirname)(dir), "lib", "node_modules"));
|
|
25434
25468
|
}
|
|
25435
25469
|
return out;
|
|
25436
25470
|
}
|
|
25437
25471
|
function readHead(path2) {
|
|
25438
25472
|
let fd;
|
|
25439
25473
|
try {
|
|
25440
|
-
fd = (0,
|
|
25474
|
+
fd = (0, import_node_fs27.openSync)(path2, "r");
|
|
25441
25475
|
const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
|
|
25442
|
-
const read = (0,
|
|
25476
|
+
const read = (0, import_node_fs27.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
|
|
25443
25477
|
return buffer.subarray(0, read);
|
|
25444
25478
|
} catch {
|
|
25445
25479
|
return void 0;
|
|
25446
25480
|
} finally {
|
|
25447
25481
|
if (fd !== void 0) {
|
|
25448
25482
|
try {
|
|
25449
|
-
(0,
|
|
25483
|
+
(0, import_node_fs27.closeSync)(fd);
|
|
25450
25484
|
} catch {
|
|
25451
25485
|
}
|
|
25452
25486
|
}
|
|
@@ -25454,7 +25488,7 @@ function readHead(path2) {
|
|
|
25454
25488
|
}
|
|
25455
25489
|
function fileBytes(path2) {
|
|
25456
25490
|
try {
|
|
25457
|
-
return (0,
|
|
25491
|
+
return (0, import_node_fs27.statSync)(path2).size;
|
|
25458
25492
|
} catch {
|
|
25459
25493
|
return void 0;
|
|
25460
25494
|
}
|
|
@@ -25468,17 +25502,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25468
25502
|
const arch = host.arch ?? process.arch;
|
|
25469
25503
|
const magic = EXECUTABLE_MAGIC[platform2];
|
|
25470
25504
|
if (!magic) return void 0;
|
|
25471
|
-
const packageRoot = globalNodeModulesRoots(host).map((root) => (0,
|
|
25505
|
+
const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path25.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs27.existsSync)((0, import_node_path25.join)(dir, "package.json")));
|
|
25472
25506
|
if (!packageRoot) return void 0;
|
|
25473
25507
|
const keys = platformPackageKeys(platform2, arch);
|
|
25474
25508
|
const fallbackPackage = `${PACKAGE}-${keys[0]}`;
|
|
25475
25509
|
let manifest;
|
|
25476
25510
|
try {
|
|
25477
|
-
manifest = JSON.parse((0,
|
|
25511
|
+
manifest = JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path25.join)(packageRoot, "package.json"), "utf8"));
|
|
25478
25512
|
} catch (e) {
|
|
25479
25513
|
return {
|
|
25480
25514
|
state: "unreadable",
|
|
25481
|
-
binPath: (0,
|
|
25515
|
+
binPath: (0, import_node_path25.join)(packageRoot, "package.json"),
|
|
25482
25516
|
expectedMagic: magic.name,
|
|
25483
25517
|
platformPackage: fallbackPackage,
|
|
25484
25518
|
error: `package.json could not be read \u2014 ${e.message}`
|
|
@@ -25495,17 +25529,17 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25495
25529
|
error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
|
|
25496
25530
|
};
|
|
25497
25531
|
}
|
|
25498
|
-
const binPath = (0,
|
|
25499
|
-
const binName = (0,
|
|
25532
|
+
const binPath = (0, import_node_path25.join)(packageRoot, binRelative);
|
|
25533
|
+
const binName = (0, import_node_path25.basename)(binRelative);
|
|
25500
25534
|
const optional = manifest.optionalDependencies;
|
|
25501
25535
|
const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
|
|
25502
25536
|
const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
|
|
25503
25537
|
if (published.length === 0) return void 0;
|
|
25504
25538
|
const binIn = (name) => [
|
|
25505
|
-
(0,
|
|
25506
|
-
(0,
|
|
25539
|
+
(0, import_node_path25.join)(packageRoot, "node_modules", ...name.split("/"), binName),
|
|
25540
|
+
(0, import_node_path25.join)((0, import_node_path25.dirname)((0, import_node_path25.dirname)(packageRoot)), ...name.split("/"), binName)
|
|
25507
25541
|
];
|
|
25508
|
-
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0,
|
|
25542
|
+
const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs27.existsSync)(file)) })).find((c) => c.path);
|
|
25509
25543
|
const platformPackage = found?.name ?? published[0];
|
|
25510
25544
|
let source;
|
|
25511
25545
|
let sourceProblem;
|
|
@@ -25516,7 +25550,7 @@ function readClaudeBinaryState(host = {}) {
|
|
|
25516
25550
|
} else {
|
|
25517
25551
|
source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
|
|
25518
25552
|
}
|
|
25519
|
-
if (!(0,
|
|
25553
|
+
if (!(0, import_node_fs27.existsSync)(binPath)) {
|
|
25520
25554
|
return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
|
|
25521
25555
|
}
|
|
25522
25556
|
const head = readHead(binPath);
|
|
@@ -25559,9 +25593,9 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25559
25593
|
const platform2 = host.platform ?? process.platform;
|
|
25560
25594
|
const aside = `${probe.binPath}.stub-${Date.now()}`;
|
|
25561
25595
|
let renamed = false;
|
|
25562
|
-
if ((0,
|
|
25596
|
+
if ((0, import_node_fs27.existsSync)(probe.binPath)) {
|
|
25563
25597
|
try {
|
|
25564
|
-
(0,
|
|
25598
|
+
(0, import_node_fs27.renameSync)(probe.binPath, aside);
|
|
25565
25599
|
renamed = true;
|
|
25566
25600
|
onStep?.(`renamed the stub aside: ${aside}`);
|
|
25567
25601
|
} catch (e) {
|
|
@@ -25570,12 +25604,12 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25570
25604
|
}
|
|
25571
25605
|
try {
|
|
25572
25606
|
onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
|
|
25573
|
-
(0,
|
|
25574
|
-
if (platform2 !== "win32") (0,
|
|
25607
|
+
(0, import_node_fs27.copyFileSync)(probe.source.path, probe.binPath);
|
|
25608
|
+
if (platform2 !== "win32") (0, import_node_fs27.chmodSync)(probe.binPath, 493);
|
|
25575
25609
|
} catch (e) {
|
|
25576
25610
|
if (renamed) {
|
|
25577
25611
|
try {
|
|
25578
|
-
(0,
|
|
25612
|
+
(0, import_node_fs27.renameSync)(aside, probe.binPath);
|
|
25579
25613
|
} catch {
|
|
25580
25614
|
return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
|
|
25581
25615
|
}
|
|
@@ -25589,7 +25623,7 @@ function healClaudeBinary(host = {}, onStep) {
|
|
|
25589
25623
|
let kept = false;
|
|
25590
25624
|
if (renamed) {
|
|
25591
25625
|
try {
|
|
25592
|
-
(0,
|
|
25626
|
+
(0, import_node_fs27.rmSync)(aside);
|
|
25593
25627
|
} catch {
|
|
25594
25628
|
kept = true;
|
|
25595
25629
|
}
|
|
@@ -26923,8 +26957,8 @@ async function announceRelease(deps, args) {
|
|
|
26923
26957
|
// src/repo-index.ts
|
|
26924
26958
|
var import_node_crypto4 = require("node:crypto");
|
|
26925
26959
|
var import_node_child_process13 = require("node:child_process");
|
|
26926
|
-
var
|
|
26927
|
-
var
|
|
26960
|
+
var import_node_fs28 = require("node:fs");
|
|
26961
|
+
var import_node_path26 = require("node:path");
|
|
26928
26962
|
var REPO_INDEX_SCHEMA = 1;
|
|
26929
26963
|
var HARD_DENY = [
|
|
26930
26964
|
/(^|\/)\.env(\.|$)/i,
|
|
@@ -27049,11 +27083,11 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27049
27083
|
}
|
|
27050
27084
|
for (const rel of readmes) {
|
|
27051
27085
|
if (isHardDeniedPath(rel)) continue;
|
|
27052
|
-
const abs = (0,
|
|
27053
|
-
if (!(0,
|
|
27086
|
+
const abs = (0, import_node_path26.join)(cwd, ...rel.split("/"));
|
|
27087
|
+
if (!(0, import_node_fs28.existsSync)(abs)) continue;
|
|
27054
27088
|
let text;
|
|
27055
27089
|
try {
|
|
27056
|
-
text = (0,
|
|
27090
|
+
text = (0, import_node_fs28.readFileSync)(abs, "utf8");
|
|
27057
27091
|
} catch {
|
|
27058
27092
|
continue;
|
|
27059
27093
|
}
|
|
@@ -27066,7 +27100,7 @@ function loadReadmeHints(cwd, candidatePaths) {
|
|
|
27066
27100
|
return hints;
|
|
27067
27101
|
}
|
|
27068
27102
|
function toPosix(p) {
|
|
27069
|
-
return p.split(
|
|
27103
|
+
return p.split(import_node_path26.sep).join("/");
|
|
27070
27104
|
}
|
|
27071
27105
|
function listCandidatePaths(cwd, exec = import_node_child_process13.execFileSync) {
|
|
27072
27106
|
try {
|
|
@@ -27088,11 +27122,11 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27088
27122
|
for (const rel of candidates) {
|
|
27089
27123
|
if (ignored.has(rel)) continue;
|
|
27090
27124
|
if (isHardDeniedPath(rel)) continue;
|
|
27091
|
-
const abs = (0,
|
|
27092
|
-
if (!(0,
|
|
27125
|
+
const abs = (0, import_node_path26.join)(cwd, ...rel.split("/"));
|
|
27126
|
+
if (!(0, import_node_fs28.existsSync)(abs)) continue;
|
|
27093
27127
|
let text;
|
|
27094
27128
|
try {
|
|
27095
|
-
text = (0,
|
|
27129
|
+
text = (0, import_node_fs28.readFileSync)(abs, "utf8");
|
|
27096
27130
|
} catch {
|
|
27097
27131
|
continue;
|
|
27098
27132
|
}
|
|
@@ -27117,16 +27151,16 @@ function rebuildRepoIndex(cwd, repoSlug2) {
|
|
|
27117
27151
|
entries
|
|
27118
27152
|
};
|
|
27119
27153
|
const store = repoIndexStorePath(cwd);
|
|
27120
|
-
(0,
|
|
27121
|
-
(0,
|
|
27154
|
+
(0, import_node_fs28.mkdirSync)((0, import_node_path26.dirname)(store), { recursive: true });
|
|
27155
|
+
(0, import_node_fs28.writeFileSync)(store, `${JSON.stringify(projection, null, 2)}
|
|
27122
27156
|
`, "utf8");
|
|
27123
27157
|
return projection;
|
|
27124
27158
|
}
|
|
27125
27159
|
function loadRepoIndex(cwd) {
|
|
27126
27160
|
const store = repoIndexStorePath(cwd);
|
|
27127
|
-
if (!(0,
|
|
27161
|
+
if (!(0, import_node_fs28.existsSync)(store)) return null;
|
|
27128
27162
|
try {
|
|
27129
|
-
const raw = JSON.parse((0,
|
|
27163
|
+
const raw = JSON.parse((0, import_node_fs28.readFileSync)(store, "utf8"));
|
|
27130
27164
|
if (raw?.schema !== REPO_INDEX_SCHEMA || !Array.isArray(raw.entries)) return null;
|
|
27131
27165
|
return raw;
|
|
27132
27166
|
} catch {
|
|
@@ -27198,7 +27232,7 @@ function inferRepoSlug(cwd, exec = import_node_child_process13.execFileSync) {
|
|
|
27198
27232
|
if (m?.[1]) return m[1].toLowerCase();
|
|
27199
27233
|
} catch {
|
|
27200
27234
|
}
|
|
27201
|
-
return ((0,
|
|
27235
|
+
return ((0, import_node_path26.basename)(cwd) || "local").toLowerCase();
|
|
27202
27236
|
}
|
|
27203
27237
|
|
|
27204
27238
|
// src/repo-index-cloud-client.ts
|
|
@@ -27338,9 +27372,9 @@ async function gcRepoIndexCloud(deps) {
|
|
|
27338
27372
|
}
|
|
27339
27373
|
|
|
27340
27374
|
// src/repo-index-sync.ts
|
|
27341
|
-
var
|
|
27375
|
+
var import_node_fs29 = require("node:fs");
|
|
27342
27376
|
var import_node_os12 = require("node:os");
|
|
27343
|
-
var
|
|
27377
|
+
var import_node_path27 = require("node:path");
|
|
27344
27378
|
var import_node_child_process14 = require("node:child_process");
|
|
27345
27379
|
var MAX_EMBED_BACKFILL_ROUNDS = 40;
|
|
27346
27380
|
function normalizeRepo(raw) {
|
|
@@ -27384,7 +27418,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27384
27418
|
const failed = [];
|
|
27385
27419
|
const skipped = [];
|
|
27386
27420
|
for (const repo of repos) {
|
|
27387
|
-
const dir = (0,
|
|
27421
|
+
const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path27.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-"));
|
|
27388
27422
|
try {
|
|
27389
27423
|
shallowClone(repo, dir, opts.githubToken);
|
|
27390
27424
|
const built = rebuildRepoIndex(dir, repo);
|
|
@@ -27434,7 +27468,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27434
27468
|
failed.push({ repo, error: e.message });
|
|
27435
27469
|
} finally {
|
|
27436
27470
|
try {
|
|
27437
|
-
(0,
|
|
27471
|
+
(0, import_node_fs29.rmSync)(dir, { recursive: true, force: true });
|
|
27438
27472
|
} catch {
|
|
27439
27473
|
}
|
|
27440
27474
|
}
|
|
@@ -27443,7 +27477,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
27443
27477
|
}
|
|
27444
27478
|
|
|
27445
27479
|
// src/repo-index-health.ts
|
|
27446
|
-
var
|
|
27480
|
+
var import_node_fs30 = require("node:fs");
|
|
27447
27481
|
|
|
27448
27482
|
// testdata/repo-index-golden-queries.json
|
|
27449
27483
|
var repo_index_golden_queries_default = {
|
|
@@ -27485,7 +27519,7 @@ function assertGoldenSuite(raw, source) {
|
|
|
27485
27519
|
function loadGoldenSuite(path2) {
|
|
27486
27520
|
let text;
|
|
27487
27521
|
try {
|
|
27488
|
-
text = (0,
|
|
27522
|
+
text = (0, import_node_fs30.readFileSync)(path2, "utf8");
|
|
27489
27523
|
} catch (e) {
|
|
27490
27524
|
throw new Error(`golden suite unreadable at ${path2}: ${e.message}`);
|
|
27491
27525
|
}
|
|
@@ -27631,8 +27665,8 @@ async function runRepoIndexHealth(opts) {
|
|
|
27631
27665
|
|
|
27632
27666
|
// src/spawn-policy-core.ts
|
|
27633
27667
|
var import_node_child_process15 = require("node:child_process");
|
|
27634
|
-
var
|
|
27635
|
-
var
|
|
27668
|
+
var import_node_fs31 = require("node:fs");
|
|
27669
|
+
var import_node_path28 = require("node:path");
|
|
27636
27670
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
27637
27671
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
27638
27672
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -27718,7 +27752,7 @@ function runSpawnPolicy(root) {
|
|
|
27718
27752
|
for (const file of files) {
|
|
27719
27753
|
let raw;
|
|
27720
27754
|
try {
|
|
27721
|
-
raw = (0,
|
|
27755
|
+
raw = (0, import_node_fs31.readFileSync)((0, import_node_path28.join)(root, file), "utf8");
|
|
27722
27756
|
} catch {
|
|
27723
27757
|
continue;
|
|
27724
27758
|
}
|
|
@@ -27736,8 +27770,8 @@ function runSpawnPolicy(root) {
|
|
|
27736
27770
|
|
|
27737
27771
|
// src/test-policy-core.ts
|
|
27738
27772
|
var import_node_child_process16 = require("node:child_process");
|
|
27739
|
-
var
|
|
27740
|
-
var
|
|
27773
|
+
var import_node_fs32 = require("node:fs");
|
|
27774
|
+
var import_node_path29 = require("node:path");
|
|
27741
27775
|
var POLICY_FILE = "test-policy.json";
|
|
27742
27776
|
var TEST_RE = /\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
27743
27777
|
var PY_TEST_RE = /(?:^|\/)test_[^/]*\.py$|_test\.py$/;
|
|
@@ -27790,7 +27824,7 @@ function isTestPath(path2) {
|
|
|
27790
27824
|
return TEST_RE.test(path2) || PY_TEST_RE.test(path2);
|
|
27791
27825
|
}
|
|
27792
27826
|
function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
27793
|
-
const raw = readFile9((0,
|
|
27827
|
+
const raw = readFile9((0, import_node_path29.join)(root, POLICY_FILE));
|
|
27794
27828
|
if (raw == null) return { mandatory: [], declared: false };
|
|
27795
27829
|
try {
|
|
27796
27830
|
return { ...JSON.parse(raw), declared: true };
|
|
@@ -27800,7 +27834,7 @@ function loadPolicy(root, readFile9 = readFileOrNull2) {
|
|
|
27800
27834
|
}
|
|
27801
27835
|
function readFileOrNull2(path2) {
|
|
27802
27836
|
try {
|
|
27803
|
-
return (0,
|
|
27837
|
+
return (0, import_node_fs32.readFileSync)(path2, "utf8");
|
|
27804
27838
|
} catch {
|
|
27805
27839
|
return null;
|
|
27806
27840
|
}
|
|
@@ -27827,12 +27861,12 @@ function classify(changed, policy, present = () => false) {
|
|
|
27827
27861
|
const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
|
|
27828
27862
|
return { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected };
|
|
27829
27863
|
}
|
|
27830
|
-
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0,
|
|
27831
|
-
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0,
|
|
27864
|
+
function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
27865
|
+
return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path29.join)(root, p)));
|
|
27832
27866
|
}
|
|
27833
|
-
function unresolvedSatisfiers(policy, root, exists = (path2) => (0,
|
|
27867
|
+
function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs32.existsSync)(path2)) {
|
|
27834
27868
|
const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
|
|
27835
|
-
return [...new Set(declared)].filter((p) => !exists((0,
|
|
27869
|
+
return [...new Set(declared)].filter((p) => !exists((0, import_node_path29.join)(root, p)));
|
|
27836
27870
|
}
|
|
27837
27871
|
function evaluate(changed, policy, present = () => false) {
|
|
27838
27872
|
const { mandatoryHits, untestedHits, testChanges, addedTests, removedProtected } = classify(changed, policy, present);
|
|
@@ -28014,13 +28048,13 @@ function changedFilesSince(base, cwd) {
|
|
|
28014
28048
|
}
|
|
28015
28049
|
function runTestPolicy(root, deps = {}) {
|
|
28016
28050
|
const policy = deps.policy ?? loadPolicy(root);
|
|
28017
|
-
const exists = deps.exists ?? ((path2) => (0,
|
|
28051
|
+
const exists = deps.exists ?? ((path2) => (0, import_node_fs32.existsSync)(path2));
|
|
28018
28052
|
const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
|
|
28019
28053
|
const base = deps.changed ? "(injected)" : resolveBase(root, deps.base);
|
|
28020
28054
|
const refusal = deps.changed ? null : untrustworthyRange(root, base);
|
|
28021
28055
|
const changed = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
|
|
28022
28056
|
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,
|
|
28057
|
+
const present = (path2) => exists((0, import_node_path29.join)(root, path2));
|
|
28024
28058
|
const removedByThisDiff = removedPaths(changed);
|
|
28025
28059
|
const staleFindings = [];
|
|
28026
28060
|
const unresolved = unresolvedProtectedEntries(policy, root, exists).filter((p) => !removedByThisDiff.has(p));
|
|
@@ -28058,8 +28092,8 @@ function runTestPolicy(root, deps = {}) {
|
|
|
28058
28092
|
}
|
|
28059
28093
|
|
|
28060
28094
|
// src/project-info-sync.ts
|
|
28061
|
-
var
|
|
28062
|
-
var
|
|
28095
|
+
var import_node_fs33 = require("node:fs");
|
|
28096
|
+
var import_node_path30 = require("node:path");
|
|
28063
28097
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
28064
28098
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
28065
28099
|
projectV2 { id }
|
|
@@ -28104,14 +28138,14 @@ function sharedName(entries, fallback) {
|
|
|
28104
28138
|
}
|
|
28105
28139
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
28106
28140
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
28107
|
-
const readmePath = (0,
|
|
28108
|
-
if (!(0,
|
|
28141
|
+
const readmePath = (0, import_node_path30.join)(repoRoot2, "README.md");
|
|
28142
|
+
if (!(0, import_node_fs33.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
28109
28143
|
const entries = entriesFor(project2, projects);
|
|
28110
28144
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
28111
28145
|
const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
|
|
28112
28146
|
if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
|
|
28113
28147
|
const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
|
|
28114
|
-
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0,
|
|
28148
|
+
const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs33.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
|
|
28115
28149
|
const lines = [
|
|
28116
28150
|
`# ${projectName}`,
|
|
28117
28151
|
"",
|
|
@@ -28130,8 +28164,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
28130
28164
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
28131
28165
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
28132
28166
|
const orgDocs = [
|
|
28133
|
-
(0,
|
|
28134
|
-
(0,
|
|
28167
|
+
(0, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-readme.md")) ? `- [Org identity](${targetBase}/blob/${targetBranch}/docs/org-readme.md)` : "",
|
|
28168
|
+
(0, import_node_fs33.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "org-architecture.md")) ? `- [Org architecture](${targetBase}/blob/${targetBranch}/docs/org-architecture.md)` : ""
|
|
28135
28169
|
].filter(Boolean);
|
|
28136
28170
|
if (orgDocs.length) lines.push("", "## Organisation docs", "", ...orgDocs);
|
|
28137
28171
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines.join("\n")}
|
|
@@ -28916,8 +28950,8 @@ function writeError(res) {
|
|
|
28916
28950
|
}
|
|
28917
28951
|
|
|
28918
28952
|
// src/secrets-commands.ts
|
|
28919
|
-
var
|
|
28920
|
-
var
|
|
28953
|
+
var import_node_fs34 = require("node:fs");
|
|
28954
|
+
var import_node_path31 = require("node:path");
|
|
28921
28955
|
var import_node_os13 = require("node:os");
|
|
28922
28956
|
|
|
28923
28957
|
// src/secrets-diff.ts
|
|
@@ -29020,18 +29054,18 @@ function collectMap(value, previous = []) {
|
|
|
29020
29054
|
return [...previous, value];
|
|
29021
29055
|
}
|
|
29022
29056
|
async function decryptRailsCredentials(input) {
|
|
29023
|
-
const appDir = (0,
|
|
29057
|
+
const appDir = (0, import_node_path31.resolve)(input.appDir ?? process.cwd());
|
|
29024
29058
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
29025
29059
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
29026
|
-
const credentialsPath = (0,
|
|
29027
|
-
const masterKeyPath = (0,
|
|
29060
|
+
const credentialsPath = (0, import_node_path31.resolve)(appDir, credentialsFile);
|
|
29061
|
+
const masterKeyPath = (0, import_node_path31.resolve)(appDir, masterKeyFile);
|
|
29028
29062
|
const env = {
|
|
29029
29063
|
...process.env,
|
|
29030
29064
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
29031
29065
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
29032
29066
|
};
|
|
29033
|
-
if ((0,
|
|
29034
|
-
env.RAILS_MASTER_KEY = (0,
|
|
29067
|
+
if ((0, import_node_fs34.existsSync)(masterKeyPath)) {
|
|
29068
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs34.readFileSync)(masterKeyPath, "utf8").trim();
|
|
29035
29069
|
}
|
|
29036
29070
|
const script = [
|
|
29037
29071
|
'require "json"',
|
|
@@ -29041,9 +29075,9 @@ async function decryptRailsCredentials(input) {
|
|
|
29041
29075
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
29042
29076
|
"puts JSON.generate(config.config)"
|
|
29043
29077
|
].join("\n");
|
|
29044
|
-
const scriptDir = (0,
|
|
29045
|
-
const scriptPath = (0,
|
|
29046
|
-
(0,
|
|
29078
|
+
const scriptDir = (0, import_node_fs34.mkdtempSync)((0, import_node_path31.join)((0, import_node_os13.tmpdir)(), "mmi-rails-decrypt-"));
|
|
29079
|
+
const scriptPath = (0, import_node_path31.join)(scriptDir, "decrypt.rb");
|
|
29080
|
+
(0, import_node_fs34.writeFileSync)(scriptPath, script, "utf8");
|
|
29047
29081
|
try {
|
|
29048
29082
|
const args = ["exec", "ruby", scriptPath];
|
|
29049
29083
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -29055,7 +29089,7 @@ async function decryptRailsCredentials(input) {
|
|
|
29055
29089
|
});
|
|
29056
29090
|
return JSON.parse(stdout);
|
|
29057
29091
|
} finally {
|
|
29058
|
-
(0,
|
|
29092
|
+
(0, import_node_fs34.rmSync)(scriptDir, { recursive: true, force: true });
|
|
29059
29093
|
}
|
|
29060
29094
|
}
|
|
29061
29095
|
async function readSecretStdin() {
|
|
@@ -29145,7 +29179,7 @@ function registerSecretsCommands(program3) {
|
|
|
29145
29179
|
let body;
|
|
29146
29180
|
if (o.file) {
|
|
29147
29181
|
try {
|
|
29148
|
-
body = (0,
|
|
29182
|
+
body = (0, import_node_fs34.readFileSync)((0, import_node_path31.resolve)(o.file), "utf8");
|
|
29149
29183
|
} catch (e) {
|
|
29150
29184
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
29151
29185
|
}
|
|
@@ -29250,7 +29284,7 @@ function registerSecretsCommands(program3) {
|
|
|
29250
29284
|
{
|
|
29251
29285
|
...d,
|
|
29252
29286
|
decryptRailsCredentials,
|
|
29253
|
-
removeFile: (path2) => (0,
|
|
29287
|
+
removeFile: (path2) => (0, import_node_fs34.unlinkSync)((0, import_node_path31.resolve)(o.appDir ?? process.cwd(), path2))
|
|
29254
29288
|
},
|
|
29255
29289
|
{
|
|
29256
29290
|
repo: o.repo,
|
|
@@ -29455,7 +29489,7 @@ function emitCliCallTelemetry(command) {
|
|
|
29455
29489
|
}
|
|
29456
29490
|
|
|
29457
29491
|
// src/box-commands.ts
|
|
29458
|
-
var
|
|
29492
|
+
var import_node_fs35 = require("node:fs");
|
|
29459
29493
|
|
|
29460
29494
|
// src/box.ts
|
|
29461
29495
|
var BOX_KEYS = {
|
|
@@ -29658,7 +29692,7 @@ function registerBoxCommands(program3) {
|
|
|
29658
29692
|
}
|
|
29659
29693
|
if (o.json) console.log(JSON.stringify({ box: found, incomplete }, null, 2));
|
|
29660
29694
|
else if (o.ssh && o.script) {
|
|
29661
|
-
(0,
|
|
29695
|
+
(0, import_node_fs35.writeFileSync)(o.script, sshRecipeScript(found), "utf8");
|
|
29662
29696
|
console.log(`wrote ${o.script} \u2014 run: bash "${o.script}"`);
|
|
29663
29697
|
} else if (o.ssh) console.log(`${formatSshRecipe(found)}
|
|
29664
29698
|
${SSH_RECIPE_AGENT_NOTE}`);
|
|
@@ -29977,7 +30011,7 @@ function registerSchedulesCommands(program3) {
|
|
|
29977
30011
|
|
|
29978
30012
|
// src/schedules-lift-command.ts
|
|
29979
30013
|
var import_promises6 = require("node:fs/promises");
|
|
29980
|
-
var
|
|
30014
|
+
var import_node_path32 = require("node:path");
|
|
29981
30015
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
29982
30016
|
var SCHEDULE_REPO_RE = /^[A-Za-z0-9_.-]+$/;
|
|
29983
30017
|
var SchedulesLiftUsageError = class extends Error {
|
|
@@ -30004,7 +30038,7 @@ async function readWorkflowFiles(dir) {
|
|
|
30004
30038
|
const files = [];
|
|
30005
30039
|
for (const name of names.sort()) {
|
|
30006
30040
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
30007
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0,
|
|
30041
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises6.readFile)((0, import_node_path32.join)(dir, name), "utf8") });
|
|
30008
30042
|
}
|
|
30009
30043
|
return files;
|
|
30010
30044
|
}
|
|
@@ -30152,9 +30186,9 @@ function registerEdgeCommands(program3) {
|
|
|
30152
30186
|
}
|
|
30153
30187
|
|
|
30154
30188
|
// src/bootstrap-commands.ts
|
|
30155
|
-
var
|
|
30189
|
+
var import_node_fs36 = require("node:fs");
|
|
30156
30190
|
var import_node_os14 = require("node:os");
|
|
30157
|
-
var
|
|
30191
|
+
var import_node_path33 = require("node:path");
|
|
30158
30192
|
|
|
30159
30193
|
// src/bootstrap-drift.ts
|
|
30160
30194
|
var import_node_crypto6 = require("node:crypto");
|
|
@@ -31034,13 +31068,13 @@ function registerBootstrapCommands(program3) {
|
|
|
31034
31068
|
client: defaultGitHubClient(),
|
|
31035
31069
|
projectMeta: meta,
|
|
31036
31070
|
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
31037
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
31071
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs36.existsSync)(path2) ? (0, import_node_fs36.readFileSync)(path2, "utf8") : null,
|
|
31038
31072
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
31039
31073
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
31040
31074
|
// #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
|
|
31041
31075
|
// permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
|
|
31042
31076
|
// sanction, which is the pre-#3664 behaviour.
|
|
31043
|
-
sanctionedAdmins: (0,
|
|
31077
|
+
sanctionedAdmins: (0, import_node_fs36.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs36.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
|
|
31044
31078
|
requiredGcpApis: (() => {
|
|
31045
31079
|
const v = meta?.requiredGcpApis;
|
|
31046
31080
|
if (Array.isArray(v)) return v;
|
|
@@ -31093,14 +31127,14 @@ function registerBootstrapCommands(program3) {
|
|
|
31093
31127
|
bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
|
|
31094
31128
|
const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
|
|
31095
31129
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31096
|
-
if (!(0,
|
|
31130
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
|
|
31097
31131
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31098
31132
|
if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
|
|
31099
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31133
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31100
31134
|
const hubContents = /* @__PURE__ */ new Map();
|
|
31101
31135
|
for (const s of manifest.seeds) {
|
|
31102
31136
|
if (s.ownership !== "org" || s.source !== "self") continue;
|
|
31103
|
-
hubContents.set(s.target, (0,
|
|
31137
|
+
hubContents.set(s.target, (0, import_node_fs36.existsSync)(s.target) ? (0, import_node_fs36.readFileSync)(s.target, "utf8") : null);
|
|
31104
31138
|
}
|
|
31105
31139
|
let targets;
|
|
31106
31140
|
let classOf = (_repo) => "deployable";
|
|
@@ -31179,10 +31213,10 @@ function registerBootstrapCommands(program3) {
|
|
|
31179
31213
|
return fail(`bootstrap apply: ${e.message}`);
|
|
31180
31214
|
}
|
|
31181
31215
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31182
|
-
if (!(0,
|
|
31216
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
|
|
31183
31217
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31184
31218
|
if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
|
|
31185
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31219
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31186
31220
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
31187
31221
|
const slug = parsedRepo.slug;
|
|
31188
31222
|
const onlyTarget = o.only.trim();
|
|
@@ -31193,16 +31227,16 @@ function registerBootstrapCommands(program3) {
|
|
|
31193
31227
|
${known}`);
|
|
31194
31228
|
}
|
|
31195
31229
|
const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
|
|
31196
|
-
const readFile9 = (p) => (0,
|
|
31230
|
+
const readFile9 = (p) => (0, import_node_fs36.existsSync)(p) ? (0, import_node_fs36.readFileSync)(p, "utf8") : null;
|
|
31197
31231
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31198
31232
|
const putSeed = async (target, content, ref, sha) => {
|
|
31199
|
-
const tmp = (0,
|
|
31200
|
-
(0,
|
|
31233
|
+
const tmp = (0, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31234
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
31201
31235
|
try {
|
|
31202
31236
|
await gh(contentPutInputArgs(repo, target, tmp));
|
|
31203
31237
|
} finally {
|
|
31204
31238
|
try {
|
|
31205
|
-
(0,
|
|
31239
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31206
31240
|
} catch {
|
|
31207
31241
|
}
|
|
31208
31242
|
}
|
|
@@ -31467,10 +31501,10 @@ LIVE apply to ${repo}:
|
|
|
31467
31501
|
bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an ownership:org + source:self seed, e.g. .github/workflows/agent-pr.yml)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
|
|
31468
31502
|
const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
|
|
31469
31503
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31470
|
-
if (!(0,
|
|
31504
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
|
|
31471
31505
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31472
31506
|
if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
|
|
31473
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31507
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31474
31508
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31475
31509
|
if (!o.target) {
|
|
31476
31510
|
return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
|
|
@@ -31479,8 +31513,8 @@ LIVE apply to ${repo}:
|
|
|
31479
31513
|
const seed = propagatable.find((s) => s.target === o.target);
|
|
31480
31514
|
if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no ownership:org + source:self seed in ${manifestPath}. Propagatable targets:
|
|
31481
31515
|
${propagatable.map((s) => s.target).join("\n ")}`);
|
|
31482
|
-
if (!(0,
|
|
31483
|
-
const hubContent = (0,
|
|
31516
|
+
if (!(0, import_node_fs36.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
|
|
31517
|
+
const hubContent = (0, import_node_fs36.readFileSync)(seed.target, "utf8");
|
|
31484
31518
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
31485
31519
|
const cfg = await loadConfig();
|
|
31486
31520
|
const projects = await fetchProjectsList(registryClientDeps(cfg));
|
|
@@ -31489,9 +31523,9 @@ LIVE apply to ${repo}:
|
|
|
31489
31523
|
}
|
|
31490
31524
|
const rosterRepos2 = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
|
|
31491
31525
|
let independentCount = rosterRepos2.length;
|
|
31492
|
-
if ((0,
|
|
31526
|
+
if ((0, import_node_fs36.existsSync)("projects.json")) {
|
|
31493
31527
|
try {
|
|
31494
|
-
const local = JSON.parse((0,
|
|
31528
|
+
const local = JSON.parse((0, import_node_fs36.readFileSync)("projects.json", "utf8"));
|
|
31495
31529
|
const localRepos = /* @__PURE__ */ new Set();
|
|
31496
31530
|
for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
|
|
31497
31531
|
const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
|
|
@@ -31607,13 +31641,13 @@ LIVE apply to ${repo}:
|
|
|
31607
31641
|
} catch {
|
|
31608
31642
|
existingSha = void 0;
|
|
31609
31643
|
}
|
|
31610
|
-
const tmp = (0,
|
|
31611
|
-
(0,
|
|
31644
|
+
const tmp = (0, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31645
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, hubContent, branch, existingSha)), "utf8");
|
|
31612
31646
|
try {
|
|
31613
31647
|
await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
|
|
31614
31648
|
} finally {
|
|
31615
31649
|
try {
|
|
31616
|
-
(0,
|
|
31650
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31617
31651
|
} catch {
|
|
31618
31652
|
}
|
|
31619
31653
|
}
|
|
@@ -31671,10 +31705,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31671
31705
|
return fail(`bootstrap rollback: ${e.message}`);
|
|
31672
31706
|
}
|
|
31673
31707
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
31674
|
-
if (!(0,
|
|
31708
|
+
if (!(0, import_node_fs36.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
|
|
31675
31709
|
const seedSource = await resolveHubSeedSource(execGitForSeedSource);
|
|
31676
31710
|
if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
|
|
31677
|
-
const manifest = loadBootstrapSeeds((0,
|
|
31711
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs36.readFileSync)(manifestPath, "utf8"));
|
|
31678
31712
|
const propagatable = manifest.seeds.filter((s) => s.ownership === "org" && s.source === "self");
|
|
31679
31713
|
if (!o.target) {
|
|
31680
31714
|
return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
|
|
@@ -31691,10 +31725,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31691
31725
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
31692
31726
|
let candidates;
|
|
31693
31727
|
if (o.record) {
|
|
31694
|
-
if (!(0,
|
|
31728
|
+
if (!(0, import_node_fs36.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
|
|
31695
31729
|
let parsed;
|
|
31696
31730
|
try {
|
|
31697
|
-
parsed = JSON.parse((0,
|
|
31731
|
+
parsed = JSON.parse((0, import_node_fs36.readFileSync)(o.record, "utf8"));
|
|
31698
31732
|
} catch (e) {
|
|
31699
31733
|
return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
|
|
31700
31734
|
}
|
|
@@ -31763,13 +31797,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31763
31797
|
} catch {
|
|
31764
31798
|
existingSha = void 0;
|
|
31765
31799
|
}
|
|
31766
|
-
const tmp = (0,
|
|
31767
|
-
(0,
|
|
31800
|
+
const tmp = (0, import_node_path33.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
31801
|
+
(0, import_node_fs36.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
31768
31802
|
try {
|
|
31769
31803
|
await gh(contentPutInputArgs(repo, seed.target, tmp));
|
|
31770
31804
|
} finally {
|
|
31771
31805
|
try {
|
|
31772
|
-
(0,
|
|
31806
|
+
(0, import_node_fs36.unlinkSync)(tmp);
|
|
31773
31807
|
} catch {
|
|
31774
31808
|
}
|
|
31775
31809
|
}
|
|
@@ -31791,12 +31825,12 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
31791
31825
|
}
|
|
31792
31826
|
|
|
31793
31827
|
// src/stage-commands.ts
|
|
31794
|
-
var
|
|
31795
|
-
var
|
|
31828
|
+
var import_node_fs38 = require("node:fs");
|
|
31829
|
+
var import_node_path35 = require("node:path");
|
|
31796
31830
|
|
|
31797
31831
|
// src/port-registry.ts
|
|
31798
|
-
var
|
|
31799
|
-
var
|
|
31832
|
+
var import_node_fs37 = require("node:fs");
|
|
31833
|
+
var import_node_path34 = require("node:path");
|
|
31800
31834
|
|
|
31801
31835
|
// ../infra/port-geometry.mjs
|
|
31802
31836
|
var PORT_BLOCK = 100;
|
|
@@ -31810,8 +31844,8 @@ function nextPortBlock(registry2) {
|
|
|
31810
31844
|
return [base, base + PORT_SPAN];
|
|
31811
31845
|
}
|
|
31812
31846
|
function loadPortRegistry(path2) {
|
|
31813
|
-
if (!(0,
|
|
31814
|
-
const raw = JSON.parse((0,
|
|
31847
|
+
if (!(0, import_node_fs37.existsSync)(path2)) return {};
|
|
31848
|
+
const raw = JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8"));
|
|
31815
31849
|
const out = {};
|
|
31816
31850
|
for (const [key, value] of Object.entries(raw)) {
|
|
31817
31851
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -31825,9 +31859,9 @@ function ensurePortRange(repo, path2) {
|
|
|
31825
31859
|
const existing = registry2[repo];
|
|
31826
31860
|
if (existing) return existing;
|
|
31827
31861
|
const range = nextPortBlock(registry2);
|
|
31828
|
-
const raw = (0,
|
|
31862
|
+
const raw = (0, import_node_fs37.existsSync)(path2) ? JSON.parse((0, import_node_fs37.readFileSync)(path2, "utf8")) : {};
|
|
31829
31863
|
raw[repo] = range;
|
|
31830
|
-
(0,
|
|
31864
|
+
(0, import_node_fs37.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
|
|
31831
31865
|
return range;
|
|
31832
31866
|
}
|
|
31833
31867
|
function portCursorSeed(registry2) {
|
|
@@ -31849,22 +31883,22 @@ function existingPortRange(repo, registry2) {
|
|
|
31849
31883
|
return registry2[repo] ?? null;
|
|
31850
31884
|
}
|
|
31851
31885
|
function portRangeInfraAt(root, source) {
|
|
31852
|
-
const registryPath = (0,
|
|
31853
|
-
const ddbScriptPath = (0,
|
|
31854
|
-
if (!(0,
|
|
31886
|
+
const registryPath = (0, import_node_path34.join)(root, "infra", "port-ranges.json");
|
|
31887
|
+
const ddbScriptPath = (0, import_node_path34.join)(root, "infra", "port-ddb.mjs");
|
|
31888
|
+
if (!(0, import_node_fs37.existsSync)(registryPath) || !(0, import_node_fs37.existsSync)(ddbScriptPath)) return null;
|
|
31855
31889
|
return { root, source, registryPath, ddbScriptPath };
|
|
31856
31890
|
}
|
|
31857
31891
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
31858
31892
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
31859
31893
|
if (direct) return direct;
|
|
31860
|
-
for (let dir = cwd; ; dir = (0,
|
|
31861
|
-
const sibling = portRangeInfraAt((0,
|
|
31894
|
+
for (let dir = cwd; ; dir = (0, import_node_path34.dirname)(dir)) {
|
|
31895
|
+
const sibling = portRangeInfraAt((0, import_node_path34.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
31862
31896
|
if (sibling) return sibling;
|
|
31863
|
-
const parent = (0,
|
|
31897
|
+
const parent = (0, import_node_path34.dirname)(dir);
|
|
31864
31898
|
if (parent === dir) break;
|
|
31865
31899
|
}
|
|
31866
31900
|
if (packageDir) {
|
|
31867
|
-
const pkgRoot = (0,
|
|
31901
|
+
const pkgRoot = (0, import_node_path34.join)(packageDir, "..", "..");
|
|
31868
31902
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
31869
31903
|
if (pkgFrom) return pkgFrom;
|
|
31870
31904
|
}
|
|
@@ -32058,8 +32092,8 @@ function registerStageCommands(program3) {
|
|
|
32058
32092
|
const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
|
|
32059
32093
|
return decideStage({
|
|
32060
32094
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
32061
|
-
hasCompose: (0,
|
|
32062
|
-
hasEnvExample: (0,
|
|
32095
|
+
hasCompose: (0, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), "docker-compose.yml")),
|
|
32096
|
+
hasEnvExample: (0, import_node_fs38.existsSync)((0, import_node_path35.join)(process.cwd(), ".env.example"))
|
|
32063
32097
|
});
|
|
32064
32098
|
}
|
|
32065
32099
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -32550,9 +32584,9 @@ function registerBoardCommands(program3) {
|
|
|
32550
32584
|
}
|
|
32551
32585
|
|
|
32552
32586
|
// src/merge-cleanup.ts
|
|
32553
|
-
var
|
|
32587
|
+
var import_node_fs39 = require("node:fs");
|
|
32554
32588
|
var import_promises8 = require("node:fs/promises");
|
|
32555
|
-
var
|
|
32589
|
+
var import_node_path37 = require("node:path");
|
|
32556
32590
|
var import_node_os15 = require("node:os");
|
|
32557
32591
|
var import_node_child_process18 = require("node:child_process");
|
|
32558
32592
|
|
|
@@ -32640,7 +32674,7 @@ function boardAdvanceFailureMessage(result) {
|
|
|
32640
32674
|
|
|
32641
32675
|
// src/deferred-registry-store.ts
|
|
32642
32676
|
var import_promises7 = require("node:fs/promises");
|
|
32643
|
-
var
|
|
32677
|
+
var import_node_path36 = require("node:path");
|
|
32644
32678
|
var sleep2 = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
32645
32679
|
async function atomicWrite(target, contents) {
|
|
32646
32680
|
const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
@@ -32691,12 +32725,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
32691
32725
|
},
|
|
32692
32726
|
// Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
|
|
32693
32727
|
write: async (entries) => {
|
|
32694
|
-
await (0, import_promises7.mkdir)((0,
|
|
32728
|
+
await (0, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
|
|
32695
32729
|
await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
|
|
32696
32730
|
},
|
|
32697
32731
|
// Serialized read-modify-write under the repo-wide lock (#2846).
|
|
32698
32732
|
update: async (mutate) => {
|
|
32699
|
-
await (0, import_promises7.mkdir)((0,
|
|
32733
|
+
await (0, import_promises7.mkdir)((0, import_node_path36.dirname)(registryPath), { recursive: true });
|
|
32700
32734
|
const deadline = Date.now() + opts.maxWaitMs;
|
|
32701
32735
|
for (; ; ) {
|
|
32702
32736
|
const guard = await acquireLock(lockPath, opts, deadline);
|
|
@@ -32867,7 +32901,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32867
32901
|
);
|
|
32868
32902
|
const repoRoot2 = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
32869
32903
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
32870
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
32904
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path37.dirname)((0, import_node_path37.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
32871
32905
|
const gcActor = describeActor({ env: process.env, surface: detectSurface(process.env), cwd: process.cwd() });
|
|
32872
32906
|
const owners = readWorktreeOwners(primaryRepoRoot);
|
|
32873
32907
|
const removalNow = Date.now();
|
|
@@ -32924,7 +32958,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32924
32958
|
const cleanup = await cleanupPrMergeLocalBranch(branch.branch, {
|
|
32925
32959
|
beforeWorktrees,
|
|
32926
32960
|
startingPath: branch.worktreePath,
|
|
32927
|
-
pathExists: (p) => (0,
|
|
32961
|
+
pathExists: (p) => (0, import_node_fs39.existsSync)(p),
|
|
32928
32962
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
32929
32963
|
teardownWorktreeStage,
|
|
32930
32964
|
deferredStore,
|
|
@@ -32962,7 +32996,7 @@ async function applyGcPlan(plan, remote, opts = {}) {
|
|
|
32962
32996
|
let removalAttempted = false;
|
|
32963
32997
|
try {
|
|
32964
32998
|
const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, cleanupRoots, {
|
|
32965
|
-
realpath: (path2) => (0,
|
|
32999
|
+
realpath: (path2) => (0, import_node_fs39.realpathSync)(path2)
|
|
32966
33000
|
});
|
|
32967
33001
|
if (!cleanupTarget.ok) {
|
|
32968
33002
|
result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
|
|
@@ -33049,13 +33083,13 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
|
|
|
33049
33083
|
const commits = JSON.parse(raw).commits ?? [];
|
|
33050
33084
|
const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
|
|
33051
33085
|
if (!body) return void 0;
|
|
33052
|
-
const dir = (0,
|
|
33053
|
-
const path2 = (0,
|
|
33054
|
-
(0,
|
|
33086
|
+
const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os15.tmpdir)(), "mmi-squash-body-"));
|
|
33087
|
+
const path2 = (0, import_node_path37.join)(dir, "body.txt");
|
|
33088
|
+
(0, import_node_fs39.writeFileSync)(path2, `${body}
|
|
33055
33089
|
`, "utf8");
|
|
33056
33090
|
return { path: path2, cleanup: () => {
|
|
33057
33091
|
try {
|
|
33058
|
-
(0,
|
|
33092
|
+
(0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
|
|
33059
33093
|
} catch {
|
|
33060
33094
|
}
|
|
33061
33095
|
} };
|
|
@@ -33177,13 +33211,13 @@ var realWorktreeDirRemover = {
|
|
|
33177
33211
|
probe: (p) => {
|
|
33178
33212
|
let st;
|
|
33179
33213
|
try {
|
|
33180
|
-
st = (0,
|
|
33214
|
+
st = (0, import_node_fs39.lstatSync)(p);
|
|
33181
33215
|
} catch {
|
|
33182
33216
|
return null;
|
|
33183
33217
|
}
|
|
33184
33218
|
if (st.isSymbolicLink()) return "link";
|
|
33185
33219
|
try {
|
|
33186
|
-
(0,
|
|
33220
|
+
(0, import_node_fs39.readlinkSync)(p);
|
|
33187
33221
|
return "link";
|
|
33188
33222
|
} catch {
|
|
33189
33223
|
}
|
|
@@ -33191,7 +33225,7 @@ var realWorktreeDirRemover = {
|
|
|
33191
33225
|
},
|
|
33192
33226
|
readdir: (p) => {
|
|
33193
33227
|
try {
|
|
33194
|
-
return (0,
|
|
33228
|
+
return (0, import_node_fs39.readdirSync)(p);
|
|
33195
33229
|
} catch {
|
|
33196
33230
|
return [];
|
|
33197
33231
|
}
|
|
@@ -33200,9 +33234,9 @@ var realWorktreeDirRemover = {
|
|
|
33200
33234
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
33201
33235
|
detachLink: (p) => {
|
|
33202
33236
|
try {
|
|
33203
|
-
(0,
|
|
33237
|
+
(0, import_node_fs39.rmdirSync)(p);
|
|
33204
33238
|
} catch {
|
|
33205
|
-
(0,
|
|
33239
|
+
(0, import_node_fs39.unlinkSync)(p);
|
|
33206
33240
|
}
|
|
33207
33241
|
},
|
|
33208
33242
|
removeTree: (p) => (0, import_promises8.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
@@ -33235,9 +33269,9 @@ async function worktreeHasStageState(worktreePath) {
|
|
|
33235
33269
|
}
|
|
33236
33270
|
}
|
|
33237
33271
|
function stageStateFileBelongsToWorktree(statePath, worktreePath) {
|
|
33238
|
-
if (!(0,
|
|
33272
|
+
if (!(0, import_node_fs39.existsSync)(statePath)) return false;
|
|
33239
33273
|
try {
|
|
33240
|
-
const state = JSON.parse((0,
|
|
33274
|
+
const state = JSON.parse((0, import_node_fs39.readFileSync)(statePath, "utf8"));
|
|
33241
33275
|
const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
|
|
33242
33276
|
return Boolean(recordedCwd && isPathUnderDirectory2(recordedCwd, worktreePath));
|
|
33243
33277
|
} catch {
|
|
@@ -33672,14 +33706,14 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
33672
33706
|
}
|
|
33673
33707
|
|
|
33674
33708
|
// src/worktree-lifecycle-commands.ts
|
|
33675
|
-
var
|
|
33709
|
+
var import_node_fs41 = require("node:fs");
|
|
33676
33710
|
var import_promises9 = require("node:fs/promises");
|
|
33677
|
-
var
|
|
33711
|
+
var import_node_path39 = require("node:path");
|
|
33678
33712
|
|
|
33679
33713
|
// src/worktree-install-cache.ts
|
|
33680
33714
|
var import_node_crypto7 = require("node:crypto");
|
|
33681
|
-
var
|
|
33682
|
-
var
|
|
33715
|
+
var import_node_fs40 = require("node:fs");
|
|
33716
|
+
var import_node_path38 = require("node:path");
|
|
33683
33717
|
var CACHE_DIR = "worktree-install-cache";
|
|
33684
33718
|
var MANIFEST = "manifest.json";
|
|
33685
33719
|
var NODE_MODULES2 = "node_modules";
|
|
@@ -33692,16 +33726,16 @@ var LOCKFILE_NAMES = [
|
|
|
33692
33726
|
"package-lock.json"
|
|
33693
33727
|
];
|
|
33694
33728
|
var realWorktreeInstallCacheFs = {
|
|
33695
|
-
exists:
|
|
33696
|
-
readFile: (path2) => (0,
|
|
33697
|
-
lstat: (path2) => (0,
|
|
33698
|
-
copyDir: (from, to) => (0,
|
|
33729
|
+
exists: import_node_fs40.existsSync,
|
|
33730
|
+
readFile: (path2) => (0, import_node_fs40.readFileSync)(path2, "utf8"),
|
|
33731
|
+
lstat: (path2) => (0, import_node_fs40.lstatSync)(path2),
|
|
33732
|
+
copyDir: (from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }),
|
|
33699
33733
|
mkdirp: (path2) => {
|
|
33700
|
-
(0,
|
|
33734
|
+
(0, import_node_fs40.mkdirSync)(path2, { recursive: true });
|
|
33701
33735
|
},
|
|
33702
|
-
writeFile: (path2, contents) => (0,
|
|
33736
|
+
writeFile: (path2, contents) => (0, import_node_fs40.writeFileSync)(path2, contents, "utf8"),
|
|
33703
33737
|
rm: (path2) => {
|
|
33704
|
-
(0,
|
|
33738
|
+
(0, import_node_fs40.rmSync)(path2, { recursive: true, force: true });
|
|
33705
33739
|
}
|
|
33706
33740
|
};
|
|
33707
33741
|
function hashLockfileBytes(contents) {
|
|
@@ -33709,7 +33743,7 @@ function hashLockfileBytes(contents) {
|
|
|
33709
33743
|
}
|
|
33710
33744
|
function resolveWorktreeInstallLockfile(packageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33711
33745
|
for (const name of LOCKFILE_NAMES) {
|
|
33712
|
-
const path2 = (0,
|
|
33746
|
+
const path2 = (0, import_node_path38.join)(packageDir, name);
|
|
33713
33747
|
if (!fs2.exists(path2)) continue;
|
|
33714
33748
|
try {
|
|
33715
33749
|
const hash = hashLockfileBytes(fs2.readFile(path2));
|
|
@@ -33724,8 +33758,8 @@ function worktreeInstallCacheEntry(primaryRoot, lockfileHash) {
|
|
|
33724
33758
|
const root = repoRuntimeStatePath(primaryRoot, CACHE_DIR, lockfileHash);
|
|
33725
33759
|
return {
|
|
33726
33760
|
root,
|
|
33727
|
-
manifestPath: (0,
|
|
33728
|
-
nodeModulesPath: (0,
|
|
33761
|
+
manifestPath: (0, import_node_path38.join)(root, MANIFEST),
|
|
33762
|
+
nodeModulesPath: (0, import_node_path38.join)(root, NODE_MODULES2)
|
|
33729
33763
|
};
|
|
33730
33764
|
}
|
|
33731
33765
|
function readWorktreeInstallCacheManifest(manifestPath, fs2 = realWorktreeInstallCacheFs) {
|
|
@@ -33765,7 +33799,7 @@ function invalidateWorktreeInstallCacheEntry(entry, fs2 = realWorktreeInstallCac
|
|
|
33765
33799
|
}
|
|
33766
33800
|
}
|
|
33767
33801
|
function removeMaterializedTree(packageDir, fs2) {
|
|
33768
|
-
const dest = (0,
|
|
33802
|
+
const dest = (0, import_node_path38.join)(packageDir, NODE_MODULES2);
|
|
33769
33803
|
if (!fs2.exists(dest)) return;
|
|
33770
33804
|
fs2.rm(dest);
|
|
33771
33805
|
if (fs2.exists(dest)) {
|
|
@@ -33773,7 +33807,7 @@ function removeMaterializedTree(packageDir, fs2) {
|
|
|
33773
33807
|
}
|
|
33774
33808
|
}
|
|
33775
33809
|
function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeInstallCacheFs) {
|
|
33776
|
-
const dest = (0,
|
|
33810
|
+
const dest = (0, import_node_path38.join)(destPackageDir, NODE_MODULES2);
|
|
33777
33811
|
try {
|
|
33778
33812
|
if (fs2.exists(dest)) fs2.rm(dest);
|
|
33779
33813
|
fs2.mkdirp(destPackageDir);
|
|
@@ -33788,7 +33822,7 @@ function materializeCachedNodeModules(entry, destPackageDir, fs2 = realWorktreeI
|
|
|
33788
33822
|
}
|
|
33789
33823
|
}
|
|
33790
33824
|
async function storeWorktreeInstallCacheEntry(primaryRoot, lockfile3, command, sourcePackageDir, fs2 = realWorktreeInstallCacheFs, now = Date.now()) {
|
|
33791
|
-
const source = (0,
|
|
33825
|
+
const source = (0, import_node_path38.join)(sourcePackageDir, NODE_MODULES2);
|
|
33792
33826
|
if (!isMaterializableNodeModulesDir(source, fs2)) return;
|
|
33793
33827
|
const entry = worktreeInstallCacheEntry(primaryRoot, lockfile3.hash);
|
|
33794
33828
|
const manifest = {
|
|
@@ -34048,7 +34082,7 @@ function classifyStaleLeaks(input) {
|
|
|
34048
34082
|
var defaultOrphanDirScanDeps = {
|
|
34049
34083
|
listDirs: (root) => {
|
|
34050
34084
|
try {
|
|
34051
|
-
return (0,
|
|
34085
|
+
return (0, import_node_fs41.readdirSync)(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path39.join)(root, e.name));
|
|
34052
34086
|
} catch {
|
|
34053
34087
|
return [];
|
|
34054
34088
|
}
|
|
@@ -34214,13 +34248,13 @@ function registerWorktreeCommands(program3) {
|
|
|
34214
34248
|
const detached = headBorn && !symbolicBranch;
|
|
34215
34249
|
const branch = symbolicBranch || (detached ? "HEAD" : "");
|
|
34216
34250
|
if (!wtPath || !branch) return fail("worktree land: not inside a git worktree");
|
|
34217
|
-
const gitFile = (0,
|
|
34218
|
-
const isLinked = (0,
|
|
34251
|
+
const gitFile = (0, import_node_path39.join)(wtPath, ".git");
|
|
34252
|
+
const isLinked = (0, import_node_fs41.existsSync)(gitFile) && (0, import_node_fs41.statSync)(gitFile).isFile();
|
|
34219
34253
|
if (apply && !isLinked) {
|
|
34220
34254
|
return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
|
|
34221
34255
|
}
|
|
34222
34256
|
const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
34223
|
-
const primaryCheckout = commonDir ? (0,
|
|
34257
|
+
const primaryCheckout = commonDir ? (0, import_node_path39.dirname)(commonDir) : wtPath;
|
|
34224
34258
|
const localBranchNames = await execFileP2("git", ["-C", primaryCheckout, "for-each-ref", "--format=%(refname:short)", "refs/heads"], { timeout: GIT_TIMEOUT_MS }).then(({ stdout }) => new Set((stdout || "").split("\n").map((l) => l.trim()).filter(Boolean))).catch(() => void 0);
|
|
34225
34259
|
const orphan = classifyOrphanedWorktree({
|
|
34226
34260
|
branch,
|
|
@@ -34494,10 +34528,10 @@ async function gatherWorktreeContext() {
|
|
|
34494
34528
|
if (s) stages.push({ path: wt.path, port: s.port });
|
|
34495
34529
|
}
|
|
34496
34530
|
const worktreeGitRoot = await currentRepoWorktreeGitRoot(repoRoot2);
|
|
34497
|
-
const primaryRepoRoot = worktreeGitRoot ? (0,
|
|
34531
|
+
const primaryRepoRoot = worktreeGitRoot ? (0, import_node_path39.dirname)((0, import_node_path39.dirname)(worktreeGitRoot)) : repoRoot2;
|
|
34498
34532
|
const wtRoot = siblingMmiWorktreesRoot(primaryRepoRoot);
|
|
34499
34533
|
let orphanDirs = [];
|
|
34500
|
-
if ((0,
|
|
34534
|
+
if ((0, import_node_fs41.existsSync)(wtRoot)) {
|
|
34501
34535
|
orphanDirs = scanOrphanDirs(wtRoot, worktreeGitRoot, {
|
|
34502
34536
|
...defaultOrphanDirScanDeps,
|
|
34503
34537
|
listDirs: (root) => worktreeScanDirs(root, primaryRepoRoot, defaultOrphanDirScanDeps.listDirs, isRepoCheckoutDir)
|
|
@@ -34533,7 +34567,7 @@ ${err.stderr ?? ""}`;
|
|
|
34533
34567
|
}
|
|
34534
34568
|
|
|
34535
34569
|
// src/issue-commands.ts
|
|
34536
|
-
var
|
|
34570
|
+
var import_node_fs42 = require("node:fs");
|
|
34537
34571
|
var import_node_crypto8 = require("node:crypto");
|
|
34538
34572
|
var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
|
|
34539
34573
|
var ReparentConflictError = class extends Error {
|
|
@@ -34551,7 +34585,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
34551
34585
|
const url = `https://github.com/${repo}/issues/${parsed.number}`;
|
|
34552
34586
|
const patch = {};
|
|
34553
34587
|
let bodyChanged = false;
|
|
34554
|
-
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
34588
|
+
const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs42.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
34555
34589
|
if (options.titleFile !== void 0) {
|
|
34556
34590
|
patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
|
|
34557
34591
|
} else if (options.title !== void 0) {
|
|
@@ -35156,7 +35190,7 @@ function extendCreateCommand(issue2, batchAttach) {
|
|
|
35156
35190
|
if (opts.batch) {
|
|
35157
35191
|
let specs;
|
|
35158
35192
|
try {
|
|
35159
|
-
const raw = (0,
|
|
35193
|
+
const raw = (0, import_node_fs42.readFileSync)(opts.batch, "utf8");
|
|
35160
35194
|
specs = JSON.parse(raw);
|
|
35161
35195
|
if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
|
|
35162
35196
|
} catch (e) {
|
|
@@ -35231,8 +35265,8 @@ ${lines}`, {
|
|
|
35231
35265
|
}
|
|
35232
35266
|
|
|
35233
35267
|
// src/train-commands.ts
|
|
35234
|
-
var
|
|
35235
|
-
var
|
|
35268
|
+
var import_node_fs43 = require("node:fs");
|
|
35269
|
+
var import_node_path40 = require("node:path");
|
|
35236
35270
|
var RELEASE_BUMP_INTENTS = ["major", "minor", "patch"];
|
|
35237
35271
|
function resolveReleaseBumpIntent(raw) {
|
|
35238
35272
|
const intent = typeof raw === "string" ? raw.trim() : "";
|
|
@@ -35243,7 +35277,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
35243
35277
|
}
|
|
35244
35278
|
function readRepoVersion() {
|
|
35245
35279
|
try {
|
|
35246
|
-
return JSON.parse((0,
|
|
35280
|
+
return JSON.parse((0, import_node_fs43.readFileSync)((0, import_node_path40.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
35247
35281
|
} catch {
|
|
35248
35282
|
return void 0;
|
|
35249
35283
|
}
|
|
@@ -35400,9 +35434,9 @@ function registerDeployCommands(program3) {
|
|
|
35400
35434
|
}
|
|
35401
35435
|
|
|
35402
35436
|
// src/discovery-commands.ts
|
|
35403
|
-
var
|
|
35437
|
+
var import_node_fs44 = require("node:fs");
|
|
35404
35438
|
var import_node_os16 = require("node:os");
|
|
35405
|
-
var
|
|
35439
|
+
var import_node_path41 = require("node:path");
|
|
35406
35440
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
35407
35441
|
async function collectStatus() {
|
|
35408
35442
|
const repo = await resolveRepo();
|
|
@@ -35592,8 +35626,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
35592
35626
|
}
|
|
35593
35627
|
const home = (0, import_node_os16.homedir)();
|
|
35594
35628
|
const plugin = onboardPluginGate({
|
|
35595
|
-
readKnown: () => readFileSyncSafe((0,
|
|
35596
|
-
readSettings: () => readFileSyncSafe((0,
|
|
35629
|
+
readKnown: () => readFileSyncSafe((0, import_node_path41.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs44.readFileSync),
|
|
35630
|
+
readSettings: () => readFileSyncSafe((0, import_node_path41.join)(home, ".claude", "settings.json"), import_node_fs44.readFileSync)
|
|
35597
35631
|
});
|
|
35598
35632
|
return { track, board, registry: registry2, secrets, plugin, estateCli, doors: opts.doors ?? [], nextCommand };
|
|
35599
35633
|
}
|
|
@@ -36692,19 +36726,19 @@ function registerOrgHealthQuery(program3, deps = defaultOrgHealthQueryDeps()) {
|
|
|
36692
36726
|
}
|
|
36693
36727
|
|
|
36694
36728
|
// src/plugin-release-catchup.ts
|
|
36695
|
-
var
|
|
36696
|
-
var
|
|
36729
|
+
var import_node_fs45 = require("node:fs");
|
|
36730
|
+
var import_node_path42 = require("node:path");
|
|
36697
36731
|
var import_node_os17 = require("node:os");
|
|
36698
36732
|
var RELEASE_CATCHUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
36699
36733
|
var RELEASE_CATCHUP_DISABLE_ENV = "MMI_NO_RELEASE_CATCHUP";
|
|
36700
36734
|
function releaseCatchupStatePath(env = process.env) {
|
|
36701
36735
|
if (env.MMI_RELEASE_CATCHUP_STATE) return env.MMI_RELEASE_CATCHUP_STATE;
|
|
36702
36736
|
if (process.platform === "win32") {
|
|
36703
|
-
const base2 = env.LOCALAPPDATA || (0,
|
|
36704
|
-
return (0,
|
|
36737
|
+
const base2 = env.LOCALAPPDATA || (0, import_node_path42.join)((0, import_node_os17.homedir)(), "AppData", "Local");
|
|
36738
|
+
return (0, import_node_path42.join)(base2, "MMI Future", "mmi-cli", "release-catchup.json");
|
|
36705
36739
|
}
|
|
36706
|
-
const base = env.XDG_STATE_HOME || (0,
|
|
36707
|
-
return (0,
|
|
36740
|
+
const base = env.XDG_STATE_HOME || (0, import_node_path42.join)((0, import_node_os17.homedir)(), ".local", "state");
|
|
36741
|
+
return (0, import_node_path42.join)(base, "mmi-cli", "release-catchup.json");
|
|
36708
36742
|
}
|
|
36709
36743
|
function releaseCatchupDue(state, now, force = false) {
|
|
36710
36744
|
if (force) return true;
|
|
@@ -36714,7 +36748,7 @@ function releaseCatchupDue(state, now, force = false) {
|
|
|
36714
36748
|
function newestCachedPluginVersion(home) {
|
|
36715
36749
|
let names;
|
|
36716
36750
|
try {
|
|
36717
|
-
names = (0,
|
|
36751
|
+
names = (0, import_node_fs45.readdirSync)(pluginCacheRoot(home));
|
|
36718
36752
|
} catch {
|
|
36719
36753
|
return void 0;
|
|
36720
36754
|
}
|
|
@@ -36722,15 +36756,15 @@ function newestCachedPluginVersion(home) {
|
|
|
36722
36756
|
}
|
|
36723
36757
|
function marketplaceClonePath(home) {
|
|
36724
36758
|
try {
|
|
36725
|
-
const parsed = JSON.parse((0,
|
|
36759
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "known_marketplaces.json"), "utf8"));
|
|
36726
36760
|
if (parsed.mutmutco?.installLocation) return parsed.mutmutco.installLocation;
|
|
36727
36761
|
} catch {
|
|
36728
36762
|
}
|
|
36729
|
-
return (0,
|
|
36763
|
+
return (0, import_node_path42.join)(home, ".claude", "plugins", "marketplaces", "mutmutco");
|
|
36730
36764
|
}
|
|
36731
36765
|
function readCatalogVersion(home) {
|
|
36732
36766
|
try {
|
|
36733
|
-
const parsed = JSON.parse((0,
|
|
36767
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(marketplaceClonePath(home), ".claude-plugin", "marketplace.json"), "utf8"));
|
|
36734
36768
|
return parsed.plugins?.find((p) => p.name === "mmi")?.version;
|
|
36735
36769
|
} catch {
|
|
36736
36770
|
return void 0;
|
|
@@ -36738,7 +36772,7 @@ function readCatalogVersion(home) {
|
|
|
36738
36772
|
}
|
|
36739
36773
|
function readMmiInstallRecord(home) {
|
|
36740
36774
|
try {
|
|
36741
|
-
const parsed = JSON.parse((0,
|
|
36775
|
+
const parsed = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(home, ".claude", "plugins", "installed_plugins.json"), "utf8"));
|
|
36742
36776
|
const record = parsed.plugins?.["mmi@mutmutco"]?.[0];
|
|
36743
36777
|
return record?.version ? { version: record.version, gitCommitSha: record.gitCommitSha } : void 0;
|
|
36744
36778
|
} catch {
|
|
@@ -36767,7 +36801,7 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36767
36801
|
cliUpdated = true;
|
|
36768
36802
|
}
|
|
36769
36803
|
const cliUpdateDetail = cliUpdated ? `CLI ${runningCli} \u2192 ${latest}; the next mmi-cli invocation runs ${latest}` : `CLI ${runningCli} is current against released ${latest}`;
|
|
36770
|
-
if (!(0,
|
|
36804
|
+
if (!(0, import_node_fs45.existsSync)(pluginCacheRoot(home))) {
|
|
36771
36805
|
deps.writeState(statePath, { checkedAt: deps.now(), latest });
|
|
36772
36806
|
return {
|
|
36773
36807
|
ok: true,
|
|
@@ -36800,8 +36834,8 @@ async function runReleaseCatchup(home, env, deps, opts = {}) {
|
|
|
36800
36834
|
return { ok: false, detail: `${cliUpdateDetail}; plugin install record could not be cleared (still ${prior.version})` };
|
|
36801
36835
|
}
|
|
36802
36836
|
const installed = await deps.runClaude(["plugin", "install", "mmi@mutmutco"], "claude plugin install mmi@mutmutco");
|
|
36803
|
-
const payload = (0,
|
|
36804
|
-
if (!installed || !(0,
|
|
36837
|
+
const payload = (0, import_node_path42.join)(pluginCacheRoot(home), latest, ".pi-plugin");
|
|
36838
|
+
if (!installed || !(0, import_node_fs45.existsSync)(payload)) {
|
|
36805
36839
|
const why = installed ? `install of ${latest} did not produce a verifiable .pi-plugin payload` : `install of ${latest} failed`;
|
|
36806
36840
|
if (!prior) return { ok: false, detail: `${cliUpdateDetail}; ${why}; no prior record to restore` };
|
|
36807
36841
|
const rollback = await restorePriorRecord(home, prior, deps);
|
|
@@ -38774,6 +38808,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38774
38808
|
});
|
|
38775
38809
|
return;
|
|
38776
38810
|
}
|
|
38811
|
+
const provenance = state.cachedAt === void 0 ? [] : [cachedSweepNote(state.cachedAt)];
|
|
38777
38812
|
if (state.driftLines.length === 0) {
|
|
38778
38813
|
emitNow({
|
|
38779
38814
|
ok: true,
|
|
@@ -38781,7 +38816,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38781
38816
|
id: "schedules-drift",
|
|
38782
38817
|
label: "schedules drift",
|
|
38783
38818
|
detail: "no drift",
|
|
38784
|
-
verbose: ["no drift lines"]
|
|
38819
|
+
verbose: ["no drift lines", ...provenance]
|
|
38785
38820
|
});
|
|
38786
38821
|
return;
|
|
38787
38822
|
}
|
|
@@ -38792,7 +38827,7 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
38792
38827
|
label: "schedules drift",
|
|
38793
38828
|
detail: `${state.driftLines.length} drift line(s)`,
|
|
38794
38829
|
fix: "run `mmi-cli harbour org schedules` / `org schedules register`",
|
|
38795
|
-
verbose: state.driftLines
|
|
38830
|
+
verbose: [...state.driftLines, ...provenance]
|
|
38796
38831
|
});
|
|
38797
38832
|
} catch (e) {
|
|
38798
38833
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -39009,17 +39044,17 @@ function parseOriginRepo(remoteUrl) {
|
|
|
39009
39044
|
}
|
|
39010
39045
|
function ghHostsConfigPath(env, platform2) {
|
|
39011
39046
|
const sep3 = platform2 === "win32" ? "\\" : "/";
|
|
39012
|
-
const
|
|
39047
|
+
const join40 = (...parts) => parts.join(sep3);
|
|
39013
39048
|
const explicit = env.GH_CONFIG_DIR?.trim();
|
|
39014
|
-
if (explicit) return
|
|
39049
|
+
if (explicit) return join40(explicit, "hosts.yml");
|
|
39015
39050
|
if (platform2 === "win32") {
|
|
39016
39051
|
const appData = (env.AppData ?? env.APPDATA)?.trim();
|
|
39017
|
-
return appData ?
|
|
39052
|
+
return appData ? join40(appData, "GitHub CLI", "hosts.yml") : void 0;
|
|
39018
39053
|
}
|
|
39019
39054
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
39020
|
-
if (xdg) return
|
|
39055
|
+
if (xdg) return join40(xdg, "gh", "hosts.yml");
|
|
39021
39056
|
const home = env.HOME?.trim();
|
|
39022
|
-
return home ?
|
|
39057
|
+
return home ? join40(home, ".config", "gh", "hosts.yml") : void 0;
|
|
39023
39058
|
}
|
|
39024
39059
|
function parseGhHostsAccounts(yaml, host = "github.com") {
|
|
39025
39060
|
let hostIndent = null;
|
|
@@ -39069,9 +39104,9 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
39069
39104
|
}
|
|
39070
39105
|
|
|
39071
39106
|
// src/doctor-io.ts
|
|
39072
|
-
var
|
|
39107
|
+
var import_node_fs46 = require("node:fs");
|
|
39073
39108
|
var import_node_os18 = require("node:os");
|
|
39074
|
-
var
|
|
39109
|
+
var import_node_path43 = require("node:path");
|
|
39075
39110
|
var import_node_child_process19 = require("node:child_process");
|
|
39076
39111
|
var import_node_util8 = require("node:util");
|
|
39077
39112
|
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process19.execFile);
|
|
@@ -39079,7 +39114,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
39079
39114
|
function installedClaudePluginVersion() {
|
|
39080
39115
|
try {
|
|
39081
39116
|
const file = JSON.parse(
|
|
39082
|
-
(0,
|
|
39117
|
+
(0, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
39083
39118
|
);
|
|
39084
39119
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
39085
39120
|
if (versions.length === 0) return void 0;
|
|
@@ -39090,7 +39125,7 @@ function installedClaudePluginVersion() {
|
|
|
39090
39125
|
}
|
|
39091
39126
|
function manifestVersion(path2) {
|
|
39092
39127
|
try {
|
|
39093
|
-
const manifest = JSON.parse((0,
|
|
39128
|
+
const manifest = JSON.parse((0, import_node_fs46.readFileSync)(path2, "utf8"));
|
|
39094
39129
|
return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
|
|
39095
39130
|
} catch {
|
|
39096
39131
|
return void 0;
|
|
@@ -39100,22 +39135,22 @@ function installedSurfacePluginVersion(surface) {
|
|
|
39100
39135
|
const token = surfaceToken(surface);
|
|
39101
39136
|
if (token === "kilo") {
|
|
39102
39137
|
try {
|
|
39103
|
-
const stamp = (0,
|
|
39138
|
+
const stamp = (0, import_node_fs46.readFileSync)((0, import_node_path43.join)((0, import_node_os18.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
|
|
39104
39139
|
return stamp || void 0;
|
|
39105
39140
|
} catch {
|
|
39106
39141
|
return void 0;
|
|
39107
39142
|
}
|
|
39108
39143
|
}
|
|
39109
39144
|
if (token === "cursor") {
|
|
39110
|
-
return manifestVersion((0,
|
|
39145
|
+
return manifestVersion((0, import_node_path43.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
|
|
39111
39146
|
}
|
|
39112
39147
|
if (token === "jervcode") {
|
|
39113
39148
|
const entry = mmiPiWrapperEntry();
|
|
39114
39149
|
if (!entry) return void 0;
|
|
39115
|
-
return manifestVersion((0,
|
|
39150
|
+
return manifestVersion((0, import_node_path43.join)(decodeURIComponent(entry.replace(/^file:\/\/\/?/, "")), "package.json"));
|
|
39116
39151
|
}
|
|
39117
39152
|
if (token === "kimi") {
|
|
39118
|
-
return manifestVersion((0,
|
|
39153
|
+
return manifestVersion((0, import_node_path43.join)(surfaceConfigRoot(surface), "plugins", "managed", "mmi", ".kimi-plugin", "plugin.json"));
|
|
39119
39154
|
}
|
|
39120
39155
|
if (token === "claude") return installedClaudePluginVersion();
|
|
39121
39156
|
if (token !== "codex") return void 0;
|
|
@@ -39153,13 +39188,13 @@ function worktreeRootSync() {
|
|
|
39153
39188
|
}
|
|
39154
39189
|
var gitignorePath = () => {
|
|
39155
39190
|
const root = worktreeRootSync();
|
|
39156
|
-
return root === null ? null : (0,
|
|
39191
|
+
return root === null ? null : (0, import_node_path43.join)(root, ".gitignore");
|
|
39157
39192
|
};
|
|
39158
39193
|
function readGitignore() {
|
|
39159
39194
|
const path2 = gitignorePath();
|
|
39160
39195
|
if (path2 === null) return null;
|
|
39161
39196
|
try {
|
|
39162
|
-
return (0,
|
|
39197
|
+
return (0, import_node_fs46.readFileSync)(path2, "utf8");
|
|
39163
39198
|
} catch {
|
|
39164
39199
|
return null;
|
|
39165
39200
|
}
|
|
@@ -39168,7 +39203,7 @@ function writeGitignore(content) {
|
|
|
39168
39203
|
const path2 = gitignorePath();
|
|
39169
39204
|
if (path2 === null) return false;
|
|
39170
39205
|
try {
|
|
39171
|
-
(0,
|
|
39206
|
+
(0, import_node_fs46.writeFileSync)(path2, content, "utf8");
|
|
39172
39207
|
return true;
|
|
39173
39208
|
} catch {
|
|
39174
39209
|
return false;
|
|
@@ -39187,7 +39222,7 @@ async function repoRoot() {
|
|
|
39187
39222
|
}
|
|
39188
39223
|
function hasRepoLocalWorktrees() {
|
|
39189
39224
|
const root = worktreeRootSync();
|
|
39190
|
-
return root !== null && (0,
|
|
39225
|
+
return root !== null && (0, import_node_fs46.existsSync)((0, import_node_path43.join)(root, ".worktrees"));
|
|
39191
39226
|
}
|
|
39192
39227
|
|
|
39193
39228
|
// src/index.ts
|
|
@@ -39206,8 +39241,8 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
39206
39241
|
function ghMultiAccountCaveat(announcedLogin) {
|
|
39207
39242
|
try {
|
|
39208
39243
|
const hostsPath = ghHostsConfigPath(process.env, process.platform);
|
|
39209
|
-
if (!hostsPath || !(0,
|
|
39210
|
-
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0,
|
|
39244
|
+
if (!hostsPath || !(0, import_node_fs47.existsSync)(hostsPath)) return void 0;
|
|
39245
|
+
return ghAccountCaveat(announcedLogin, parseGhHostsAccounts((0, import_node_fs47.readFileSync)(hostsPath, "utf8")));
|
|
39211
39246
|
} catch {
|
|
39212
39247
|
return void 0;
|
|
39213
39248
|
}
|
|
@@ -39215,7 +39250,7 @@ function ghMultiAccountCaveat(announcedLogin) {
|
|
|
39215
39250
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
39216
39251
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
39217
39252
|
function envHealLockPath(home) {
|
|
39218
|
-
return (0,
|
|
39253
|
+
return (0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
39219
39254
|
}
|
|
39220
39255
|
async function withEnvHealLock(what, run) {
|
|
39221
39256
|
try {
|
|
@@ -39348,7 +39383,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39348
39383
|
);
|
|
39349
39384
|
const result = applyPluginCachePlan(
|
|
39350
39385
|
plan,
|
|
39351
|
-
(p) => (0,
|
|
39386
|
+
(p) => (0, import_node_fs47.rmSync)(p, { recursive: true }),
|
|
39352
39387
|
stagingApplyFsGuard(configRoot)
|
|
39353
39388
|
);
|
|
39354
39389
|
return {
|
|
@@ -39402,8 +39437,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39402
39437
|
const home = (0, import_node_os19.homedir)();
|
|
39403
39438
|
const rows = marketplaceRows(
|
|
39404
39439
|
MMI_MARKETPLACE_NAME,
|
|
39405
|
-
readFileSyncSafe((0,
|
|
39406
|
-
readFileSyncSafe((0,
|
|
39440
|
+
readFileSyncSafe((0, import_node_path44.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs47.readFileSync),
|
|
39441
|
+
readFileSyncSafe((0, import_node_path44.join)(home, ".claude", "settings.json"), import_node_fs47.readFileSync),
|
|
39407
39442
|
// #3974: this CLI heals these rows, so report mode names the doctor run rather than the hand
|
|
39408
39443
|
// edit. #4792 narrows WHICH run: `applyOrgMarketplacePins` declines outright while Claude Code
|
|
39409
39444
|
// is up, because the host owns this file and rewrites it from its own copy (#4083). Naming the
|
|
@@ -39415,7 +39450,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39415
39450
|
hostBlocked ?? claudeCodeEnvMarkerPresent() ? "host-running" : "doctor"
|
|
39416
39451
|
);
|
|
39417
39452
|
const pending = readMarketplacePinPending(
|
|
39418
|
-
(0,
|
|
39453
|
+
(0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"),
|
|
39419
39454
|
MMI_MARKETPLACE_NAME
|
|
39420
39455
|
);
|
|
39421
39456
|
if (!pending) return rows;
|
|
@@ -39441,9 +39476,9 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39441
39476
|
if (detectSurface(process.env) === "codex") return void 0;
|
|
39442
39477
|
const home = (0, import_node_os19.homedir)();
|
|
39443
39478
|
const names = [MMI_MARKETPLACE_NAME];
|
|
39444
|
-
const result = applyOrgMarketplacePins((0,
|
|
39479
|
+
const result = applyOrgMarketplacePins((0, import_node_path44.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), names);
|
|
39445
39480
|
if (result?.wrote) {
|
|
39446
|
-
writeMarketplacePinPending((0,
|
|
39481
|
+
writeMarketplacePinPending((0, import_node_path44.join)(home, ".claude", "plugins", ".mmi-marketplace-pin-pending.json"), names);
|
|
39447
39482
|
}
|
|
39448
39483
|
return result;
|
|
39449
39484
|
} catch {
|
|
@@ -39459,7 +39494,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39459
39494
|
// adopted the generated routing index (MMG-Unlive: `docs/Archive/**` only, no index, no gate.yml) would
|
|
39460
39495
|
// get a permanent — demanding an artifact it never asked for.
|
|
39461
39496
|
docsIndexState: (root) => {
|
|
39462
|
-
if (!(0,
|
|
39497
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
39463
39498
|
const real = createDocsIndexDeps(root);
|
|
39464
39499
|
let docs2;
|
|
39465
39500
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39468,7 +39503,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39468
39503
|
},
|
|
39469
39504
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
39470
39505
|
healDocsIndex: (root) => {
|
|
39471
|
-
if (!(0,
|
|
39506
|
+
if (!(0, import_node_fs47.existsSync)((0, import_node_path44.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
39472
39507
|
const real = createDocsIndexDeps(root);
|
|
39473
39508
|
let docs2;
|
|
39474
39509
|
const listDocs = () => docs2 ??= real.listDocs();
|
|
@@ -39496,6 +39531,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39496
39531
|
// #4170: light board doctor with 15s ceiling. skipClaimLiveness keeps Phase 3 off.
|
|
39497
39532
|
boardDoctorFix: async ({ fix } = {}) => {
|
|
39498
39533
|
const BOARD_DOCTOR_TIMEOUT_MS = 15e3;
|
|
39534
|
+
let ceiling;
|
|
39499
39535
|
try {
|
|
39500
39536
|
const cfg = await loadConfigForRepo();
|
|
39501
39537
|
const work = boardDoctor({
|
|
@@ -39506,7 +39542,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39506
39542
|
const raced = await Promise.race([
|
|
39507
39543
|
work.then((r) => ({ ...r, timedOut: false })),
|
|
39508
39544
|
new Promise((resolve5) => {
|
|
39509
|
-
setTimeout(() => resolve5({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39545
|
+
ceiling = setTimeout(() => resolve5({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
39510
39546
|
})
|
|
39511
39547
|
]);
|
|
39512
39548
|
if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
|
|
@@ -39518,11 +39554,20 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39518
39554
|
};
|
|
39519
39555
|
} catch (e) {
|
|
39520
39556
|
return { scanned: 0, findings: 0, fixed: 0, failed: 0, readFailed: true, error: e instanceof Error ? e.message : String(e) };
|
|
39557
|
+
} finally {
|
|
39558
|
+
clearTimeout(ceiling);
|
|
39521
39559
|
}
|
|
39522
39560
|
},
|
|
39523
39561
|
// #4171: schedules drift notebook — report-only, ~20s ceiling.
|
|
39562
|
+
// #4815: and throttled. The sweep behind it reads every workflow file in every org repo — 12s of a
|
|
39563
|
+
// 22s doctor — so a cached notebook under six hours old answers the row instead, saying so in its
|
|
39564
|
+
// evidence. Only a COMPLETE sweep is cached (see schedules-drift-cache.ts).
|
|
39524
39565
|
schedulesDriftState: async () => {
|
|
39525
39566
|
const SCHEDULES_DRIFT_TIMEOUT_MS = 2e4;
|
|
39567
|
+
const cachePath = schedulesDriftCachePath(repoRuntimeStatePath(process.cwd()));
|
|
39568
|
+
const cached = readSchedulesDriftCache(cachePath);
|
|
39569
|
+
if (cached) return { driftLines: cached.driftLines, incomplete: [], cachedAt: cached.at };
|
|
39570
|
+
let ceiling;
|
|
39526
39571
|
try {
|
|
39527
39572
|
const raced = await Promise.race([
|
|
39528
39573
|
fetchNotebook().then((nb) => ({
|
|
@@ -39531,12 +39576,15 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
39531
39576
|
timedOut: false
|
|
39532
39577
|
})),
|
|
39533
39578
|
new Promise((resolve5) => {
|
|
39534
|
-
setTimeout(() => resolve5({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39579
|
+
ceiling = setTimeout(() => resolve5({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
39535
39580
|
})
|
|
39536
39581
|
]);
|
|
39582
|
+
if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
|
|
39537
39583
|
return raced;
|
|
39538
39584
|
} catch (e) {
|
|
39539
39585
|
return { driftLines: [], incomplete: [], readFailed: true, error: e instanceof Error ? e.message : String(e) };
|
|
39586
|
+
} finally {
|
|
39587
|
+
clearTimeout(ceiling);
|
|
39540
39588
|
}
|
|
39541
39589
|
},
|
|
39542
39590
|
// #4173: estate commands absent from the running Commander program (stale global CLI).
|
|
@@ -39818,19 +39866,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
39818
39866
|
});
|
|
39819
39867
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
39820
39868
|
rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
|
|
39821
|
-
const path2 = (0,
|
|
39822
|
-
const current = (0,
|
|
39869
|
+
const path2 = (0, import_node_path44.join)(process.cwd(), ".gitignore");
|
|
39870
|
+
const current = (0, import_node_fs47.existsSync)(path2) ? (0, import_node_fs47.readFileSync)(path2, "utf8") : null;
|
|
39823
39871
|
const plan = planManagedGitignore(current);
|
|
39824
39872
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
39825
39873
|
if (opts.json) {
|
|
39826
|
-
if (opts.write && plan.changed) (0,
|
|
39874
|
+
if (opts.write && plan.changed) (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
39827
39875
|
console.log(JSON.stringify(plan, null, 2));
|
|
39828
39876
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
39829
39877
|
return;
|
|
39830
39878
|
}
|
|
39831
39879
|
if (opts.write) {
|
|
39832
39880
|
if (plan.changed) {
|
|
39833
|
-
(0,
|
|
39881
|
+
(0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
|
|
39834
39882
|
console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
|
|
39835
39883
|
} else {
|
|
39836
39884
|
console.log("mmi-cli devops org rules gitignore: up to date");
|
|
@@ -39989,8 +40037,8 @@ gcCmd.option("--dry-run", "show what would be deleted (default)").option("--appl
|
|
|
39989
40037
|
if (!Number.isFinite(limit) || limit < 1) return fail("worktree gc: --limit must be a positive integer");
|
|
39990
40038
|
let root;
|
|
39991
40039
|
if (o.root !== void 0) {
|
|
39992
|
-
root = (0,
|
|
39993
|
-
if (!(0,
|
|
40040
|
+
root = (0, import_node_path44.resolve)(o.root);
|
|
40041
|
+
if (!(0, import_node_fs47.existsSync)(root) || !(0, import_node_fs47.statSync)(root).isDirectory()) return fail(`worktree gc: --root ${o.root} is not a directory`);
|
|
39994
40042
|
const gcRepoRoot = (await execFileP2("git", ["rev-parse", "--show-toplevel"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim() || process.cwd();
|
|
39995
40043
|
if (isPathUnderDirectory2(gcRepoRoot, root)) {
|
|
39996
40044
|
return fail(`worktree gc: --root ${root} contains this checkout \u2014 name a worktrees root, not the repo or an ancestor of it`);
|
|
@@ -40087,7 +40135,7 @@ async function currentWorktreeRemovalContext(command, force) {
|
|
|
40087
40135
|
};
|
|
40088
40136
|
}
|
|
40089
40137
|
async function unprovenWorktreeReason(wtPath, repoRoot2) {
|
|
40090
|
-
if (!(0,
|
|
40138
|
+
if (!(0, import_node_fs47.existsSync)(wtPath)) return `${wtPath} does not exist on disk`;
|
|
40091
40139
|
const porcelain = (await execFileP2("git", ["-C", repoRoot2, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout;
|
|
40092
40140
|
const registered = parseWorktreePorcelainEntries(porcelain);
|
|
40093
40141
|
if (!registered.length) {
|
|
@@ -40117,26 +40165,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
40117
40165
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
40118
40166
|
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
40119
40167
|
const take = () => {
|
|
40120
|
-
const fd = (0,
|
|
40168
|
+
const fd = (0, import_node_fs47.openSync)(lockPath, "wx");
|
|
40121
40169
|
try {
|
|
40122
|
-
(0,
|
|
40170
|
+
(0, import_node_fs47.writeSync)(fd, String(Date.now()));
|
|
40123
40171
|
} finally {
|
|
40124
|
-
(0,
|
|
40172
|
+
(0, import_node_fs47.closeSync)(fd);
|
|
40125
40173
|
}
|
|
40126
40174
|
return () => {
|
|
40127
40175
|
try {
|
|
40128
|
-
(0,
|
|
40176
|
+
(0, import_node_fs47.rmSync)(lockPath, { force: true });
|
|
40129
40177
|
} catch {
|
|
40130
40178
|
}
|
|
40131
40179
|
};
|
|
40132
40180
|
};
|
|
40133
40181
|
try {
|
|
40134
|
-
(0,
|
|
40182
|
+
(0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(lockPath), { recursive: true });
|
|
40135
40183
|
return take();
|
|
40136
40184
|
} catch {
|
|
40137
40185
|
try {
|
|
40138
|
-
if (Date.now() - (0,
|
|
40139
|
-
(0,
|
|
40186
|
+
if (Date.now() - (0, import_node_fs47.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
|
|
40187
|
+
(0, import_node_fs47.rmSync)(lockPath, { force: true });
|
|
40140
40188
|
return take();
|
|
40141
40189
|
}
|
|
40142
40190
|
} catch {
|
|
@@ -41000,7 +41048,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
41000
41048
|
if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
|
|
41001
41049
|
if (o.secretsFile) {
|
|
41002
41050
|
try {
|
|
41003
|
-
vars.push(`secrets=${(0,
|
|
41051
|
+
vars.push(`secrets=${(0, import_node_fs47.readFileSync)(o.secretsFile, "utf8")}`);
|
|
41004
41052
|
} catch (e) {
|
|
41005
41053
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
41006
41054
|
}
|
|
@@ -41768,11 +41816,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
41768
41816
|
}
|
|
41769
41817
|
});
|
|
41770
41818
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
41771
|
-
const wfDir = (0,
|
|
41772
|
-
if (!(0,
|
|
41773
|
-
return (0,
|
|
41819
|
+
const wfDir = (0, import_node_path44.join)(cwd, ".github", "workflows");
|
|
41820
|
+
if (!(0, import_node_fs47.existsSync)(wfDir)) return [];
|
|
41821
|
+
return (0, import_node_fs47.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
41774
41822
|
try {
|
|
41775
|
-
return workflowReportsPrChecks((0,
|
|
41823
|
+
return workflowReportsPrChecks((0, import_node_fs47.readFileSync)((0, import_node_path44.join)(wfDir, name), "utf8"));
|
|
41776
41824
|
} catch {
|
|
41777
41825
|
return true;
|
|
41778
41826
|
}
|
|
@@ -41824,16 +41872,16 @@ function ciAuditDeps() {
|
|
|
41824
41872
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
41825
41873
|
readSeedFile: (path2) => {
|
|
41826
41874
|
if (!root) return null;
|
|
41827
|
-
const fullPath = (0,
|
|
41828
|
-
return (0,
|
|
41875
|
+
const fullPath = (0, import_node_path44.join)(root, path2);
|
|
41876
|
+
return (0, import_node_fs47.existsSync)(fullPath) ? (0, import_node_fs47.readFileSync)(fullPath, "utf8") : null;
|
|
41829
41877
|
}
|
|
41830
41878
|
};
|
|
41831
41879
|
}
|
|
41832
41880
|
function hubRoot() {
|
|
41833
|
-
const fromPkg = (0,
|
|
41881
|
+
const fromPkg = (0, import_node_path44.join)(__dirname, "..", "..");
|
|
41834
41882
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
41835
|
-
if ((0,
|
|
41836
|
-
if ((0,
|
|
41883
|
+
if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(fromPkg, marker))) return fromPkg;
|
|
41884
|
+
if ((0, import_node_fs47.existsSync)((0, import_node_path44.join)(process.cwd(), marker))) return process.cwd();
|
|
41837
41885
|
return null;
|
|
41838
41886
|
}
|
|
41839
41887
|
async function waitLoopCorePool(label) {
|
|
@@ -42141,7 +42189,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42141
42189
|
}
|
|
42142
42190
|
if (!repoForPostCleanup) throw e;
|
|
42143
42191
|
console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
|
|
42144
|
-
const commitMessage = bodyFile ? (0,
|
|
42192
|
+
const commitMessage = bodyFile ? (0, import_node_fs47.readFileSync)(bodyFile, "utf8") : void 0;
|
|
42145
42193
|
await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
|
|
42146
42194
|
body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
|
|
42147
42195
|
timeoutMs: GH_MUTATION_TIMEOUT_MS
|
|
@@ -42237,7 +42285,7 @@ jsonParity(pr.command("merge <number>").description("merge a PR (squash by defau
|
|
|
42237
42285
|
localCleanup = await cleanupPrMergeLocalBranch(headRef, {
|
|
42238
42286
|
beforeWorktrees,
|
|
42239
42287
|
startingPath,
|
|
42240
|
-
pathExists: (p) => (0,
|
|
42288
|
+
pathExists: (p) => (0, import_node_fs47.existsSync)(p),
|
|
42241
42289
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
42242
42290
|
teardownWorktreeStage,
|
|
42243
42291
|
deferredStore,
|
|
@@ -42815,12 +42863,12 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
42815
42863
|
targets = resolution.targets;
|
|
42816
42864
|
}
|
|
42817
42865
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
42818
|
-
const fileMatrix = (0,
|
|
42866
|
+
const fileMatrix = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
42819
42867
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
42820
42868
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
42821
|
-
const fileContracts = (0,
|
|
42869
|
+
const fileContracts = (0, import_node_fs47.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs47.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
|
|
42822
42870
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
42823
|
-
const sanctioned = (0,
|
|
42871
|
+
const sanctioned = (0, import_node_fs47.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs47.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
42824
42872
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
|
|
42825
42873
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
42826
42874
|
if (!report.ok) process.exitCode = 1;
|
|
@@ -42852,16 +42900,16 @@ function directoryBytes(path2) {
|
|
|
42852
42900
|
let total = 0;
|
|
42853
42901
|
let entries;
|
|
42854
42902
|
try {
|
|
42855
|
-
entries = (0,
|
|
42903
|
+
entries = (0, import_node_fs47.readdirSync)(path2, { withFileTypes: true });
|
|
42856
42904
|
} catch {
|
|
42857
42905
|
return 0;
|
|
42858
42906
|
}
|
|
42859
42907
|
for (const entry of entries) {
|
|
42860
|
-
const child2 = (0,
|
|
42908
|
+
const child2 = (0, import_node_path44.join)(path2, entry.name);
|
|
42861
42909
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
42862
42910
|
else {
|
|
42863
42911
|
try {
|
|
42864
|
-
total += (0,
|
|
42912
|
+
total += (0, import_node_fs47.statSync)(child2).size;
|
|
42865
42913
|
} catch {
|
|
42866
42914
|
}
|
|
42867
42915
|
}
|
|
@@ -42869,25 +42917,25 @@ function directoryBytes(path2) {
|
|
|
42869
42917
|
return total;
|
|
42870
42918
|
}
|
|
42871
42919
|
function listDirEntries(dir) {
|
|
42872
|
-
return (0,
|
|
42920
|
+
return (0, import_node_fs47.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
42873
42921
|
}
|
|
42874
42922
|
function readInstalledPluginRefs(configRoot) {
|
|
42875
42923
|
const p = installedPluginsPathForConfig(configRoot);
|
|
42876
|
-
if (!(0,
|
|
42924
|
+
if (!(0, import_node_fs47.existsSync)(p)) return [];
|
|
42877
42925
|
try {
|
|
42878
|
-
return installedPluginPaths((0,
|
|
42926
|
+
return installedPluginPaths((0, import_node_fs47.readFileSync)(p, "utf8"));
|
|
42879
42927
|
} catch {
|
|
42880
42928
|
return null;
|
|
42881
42929
|
}
|
|
42882
42930
|
}
|
|
42883
42931
|
function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
42884
42932
|
return {
|
|
42885
|
-
exists: (p) => (0,
|
|
42886
|
-
listVersionDirs: (root) => (0,
|
|
42933
|
+
exists: (p) => (0, import_node_fs47.existsSync)(p),
|
|
42934
|
+
listVersionDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
42887
42935
|
dirBytes,
|
|
42888
|
-
listStagingDirs: (root) => (0,
|
|
42936
|
+
listStagingDirs: (root) => (0, import_node_fs47.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
42889
42937
|
try {
|
|
42890
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
42938
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path44.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs47.statSync)(p).mtimeMs) };
|
|
42891
42939
|
} catch {
|
|
42892
42940
|
return { name: d.name, mtimeMs: Date.now() };
|
|
42893
42941
|
}
|
|
@@ -42901,10 +42949,10 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
42901
42949
|
return {
|
|
42902
42950
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
42903
42951
|
mtimeMs: (name) => {
|
|
42904
|
-
const p = (0,
|
|
42905
|
-
if (!(0,
|
|
42952
|
+
const p = (0, import_node_path44.join)(stagingRoot, name);
|
|
42953
|
+
if (!(0, import_node_fs47.existsSync)(p)) return null;
|
|
42906
42954
|
try {
|
|
42907
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
42955
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs47.statSync)(q).mtimeMs);
|
|
42908
42956
|
} catch {
|
|
42909
42957
|
return null;
|
|
42910
42958
|
}
|
|
@@ -42930,7 +42978,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
42930
42978
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
42931
42979
|
);
|
|
42932
42980
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
42933
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
42981
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs47.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
|
|
42934
42982
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
42935
42983
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
42936
42984
|
else console.log(renderPluginCachePlan(plan, result));
|
|
@@ -42938,7 +42986,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
42938
42986
|
});
|
|
42939
42987
|
function readReleaseCatchupState(path2) {
|
|
42940
42988
|
try {
|
|
42941
|
-
const parsed = JSON.parse((0,
|
|
42989
|
+
const parsed = JSON.parse((0, import_node_fs47.readFileSync)(path2, "utf8"));
|
|
42942
42990
|
return typeof parsed?.checkedAt === "number" ? parsed : void 0;
|
|
42943
42991
|
} catch {
|
|
42944
42992
|
return void 0;
|
|
@@ -42946,8 +42994,8 @@ function readReleaseCatchupState(path2) {
|
|
|
42946
42994
|
}
|
|
42947
42995
|
function writeReleaseCatchupState(path2, state) {
|
|
42948
42996
|
try {
|
|
42949
|
-
(0,
|
|
42950
|
-
(0,
|
|
42997
|
+
(0, import_node_fs47.mkdirSync)((0, import_node_path44.dirname)(path2), { recursive: true });
|
|
42998
|
+
(0, import_node_fs47.writeFileSync)(path2, `${JSON.stringify(state)}
|
|
42951
42999
|
`);
|
|
42952
43000
|
} catch {
|
|
42953
43001
|
}
|