@mutmutco/cli 2.51.0 → 2.52.1
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 +253 -192
- package/dist/saga.cjs +14 -7
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -5571,6 +5571,7 @@ var import_node_child_process13 = require("node:child_process");
|
|
|
5571
5571
|
// src/cli-shared.ts
|
|
5572
5572
|
var import_promises = require("node:fs/promises");
|
|
5573
5573
|
var import_node_fs7 = require("node:fs");
|
|
5574
|
+
var import_node_path7 = require("node:path");
|
|
5574
5575
|
var import_node_crypto2 = require("node:crypto");
|
|
5575
5576
|
var import_node_child_process4 = require("node:child_process");
|
|
5576
5577
|
var import_node_util4 = require("node:util");
|
|
@@ -6326,16 +6327,20 @@ async function hubHeaders(extra = {}) {
|
|
|
6326
6327
|
const base = { ...clientVersionHeaders(), ...extra };
|
|
6327
6328
|
return t ? { ...base, Authorization: `Bearer ${t}` } : base;
|
|
6328
6329
|
}
|
|
6330
|
+
var CONFIG_FILE = ".mmi/config.json";
|
|
6329
6331
|
async function loadConfig() {
|
|
6330
6332
|
let file = {};
|
|
6331
6333
|
try {
|
|
6332
|
-
file = JSON.parse(await (0, import_promises.readFile)(
|
|
6334
|
+
file = JSON.parse(await (0, import_promises.readFile)(CONFIG_FILE, "utf8"));
|
|
6333
6335
|
} catch {
|
|
6334
6336
|
file = {};
|
|
6335
6337
|
}
|
|
6336
6338
|
if (!file.sagaApiUrl) file.sagaApiUrl = defaultHubUrl();
|
|
6337
6339
|
return file;
|
|
6338
6340
|
}
|
|
6341
|
+
function isOrgRepoRoot(cwd = process.cwd(), exists = import_node_fs7.existsSync) {
|
|
6342
|
+
return exists((0, import_node_path7.join)(cwd, CONFIG_FILE));
|
|
6343
|
+
}
|
|
6339
6344
|
var SESSION_FILE = ".mmi/.session";
|
|
6340
6345
|
var gitOut = async (args) => {
|
|
6341
6346
|
try {
|
|
@@ -6568,8 +6573,8 @@ function memorySyncBanner(report) {
|
|
|
6568
6573
|
|
|
6569
6574
|
// src/continuity.ts
|
|
6570
6575
|
var import_node_fs8 = require("node:fs");
|
|
6571
|
-
var
|
|
6572
|
-
var CONTINUITY_FILE = (0,
|
|
6576
|
+
var import_node_path8 = require("node:path");
|
|
6577
|
+
var CONTINUITY_FILE = (0, import_node_path8.join)(".mmi", "continuity.json");
|
|
6573
6578
|
function parseContinuityStamp(raw) {
|
|
6574
6579
|
if (!raw) return {};
|
|
6575
6580
|
try {
|
|
@@ -6595,7 +6600,7 @@ function readContinuityStamp(path2 = CONTINUITY_FILE) {
|
|
|
6595
6600
|
function stampSagaNoteContinuity(now = (/* @__PURE__ */ new Date()).toISOString(), path2 = CONTINUITY_FILE) {
|
|
6596
6601
|
try {
|
|
6597
6602
|
const current = readContinuityStamp(path2);
|
|
6598
|
-
(0, import_node_fs8.mkdirSync)((0,
|
|
6603
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
|
|
6599
6604
|
(0, import_node_fs8.writeFileSync)(path2, serializeContinuityStamp({ ...current, lastSagaNoteAt: now }), "utf8");
|
|
6600
6605
|
} catch {
|
|
6601
6606
|
}
|
|
@@ -6954,7 +6959,7 @@ var import_node_fs10 = require("node:fs");
|
|
|
6954
6959
|
// src/stage-runner.ts
|
|
6955
6960
|
var import_node_child_process5 = require("node:child_process");
|
|
6956
6961
|
var import_node_fs9 = require("node:fs");
|
|
6957
|
-
var
|
|
6962
|
+
var import_node_path9 = require("node:path");
|
|
6958
6963
|
var import_node_net = require("node:net");
|
|
6959
6964
|
var import_node_util5 = require("node:util");
|
|
6960
6965
|
var execFileP3 = (0, import_node_util5.promisify)(import_node_child_process5.execFile);
|
|
@@ -7071,11 +7076,11 @@ function appendForceRecreate(up) {
|
|
|
7071
7076
|
return `${up.trimEnd()} --force-recreate`;
|
|
7072
7077
|
}
|
|
7073
7078
|
function stageStatePath(cwd = process.cwd()) {
|
|
7074
|
-
return (0,
|
|
7079
|
+
return (0, import_node_path9.join)(cwd, "tmp", "stage", "state.json");
|
|
7075
7080
|
}
|
|
7076
7081
|
function stageGlobalStatePath(cwd = process.cwd(), gitCommonDir = ".git") {
|
|
7077
|
-
const dir = (0,
|
|
7078
|
-
return (0,
|
|
7082
|
+
const dir = (0, import_node_path9.isAbsolute)(gitCommonDir) ? gitCommonDir : (0, import_node_path9.resolve)(cwd, gitCommonDir);
|
|
7083
|
+
return (0, import_node_path9.join)(dir, "mmi", "stage", "state.json");
|
|
7079
7084
|
}
|
|
7080
7085
|
function normPath2(path2) {
|
|
7081
7086
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -7299,8 +7304,8 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
7299
7304
|
}
|
|
7300
7305
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
7301
7306
|
if (!config.ensureEnv) return;
|
|
7302
|
-
const target = (0,
|
|
7303
|
-
const example = (0,
|
|
7307
|
+
const target = (0, import_node_path9.join)(cwd, config.ensureEnv.target);
|
|
7308
|
+
const example = (0, import_node_path9.join)(cwd, config.ensureEnv.example);
|
|
7304
7309
|
if (!(0, import_node_fs9.existsSync)(target) && (0, import_node_fs9.existsSync)(example)) {
|
|
7305
7310
|
(0, import_node_fs9.copyFileSync)(example, target);
|
|
7306
7311
|
} else if ((0, import_node_fs9.existsSync)(target) && (0, import_node_fs9.existsSync)(example)) {
|
|
@@ -7811,12 +7816,14 @@ function registerSagaCommands(program3) {
|
|
|
7811
7816
|
saga.command("flush").option("--json", "machine-readable {flushed, dropped, remaining}").option("--run", "detached worker: drain the queue silently (spawned by note/capture)").description("roll the local pending-note queue forward (re-POST queued saga writes); reports what landed").action((o) => runSagaFlush(o));
|
|
7812
7817
|
saga.command("show").option("--quiet", "no-op silently when unconfigured/unreachable (SessionStart hook)").option("--latest-anywhere", "resume the newest saga across all repos (default: current repo)").description("print your resume block \u2014 current repo HEAD + project memory (where you left off)").action((opts) => runSagaShow(opts));
|
|
7813
7818
|
saga.command("capture").option("--quiet", "capture silently (for the Stop hook)").description("per-turn deterministic capture (Stop hook): turn boundary + current sha + gated HEAD-update").action(async (opts) => {
|
|
7819
|
+
if (!isOrgRepoRoot()) return;
|
|
7814
7820
|
const hook = parseHookInput(await readStdin());
|
|
7815
7821
|
if (hook.session_id) persistSession(hook.session_id);
|
|
7816
7822
|
await postCapture({ event: "stop", id: (0, import_node_crypto3.randomUUID)(), source: "hook", sha: await gitOut(["rev-parse", "--short", "HEAD"]), surface: agentSurface() }, opts.quiet ?? false);
|
|
7817
7823
|
await maybeSpawnHeadUpdate();
|
|
7818
7824
|
});
|
|
7819
7825
|
saga.command("session").option("--quiet", "silent (for the SessionStart hook)").description("persist the harness session id for this repo (SessionStart hook)").action(async () => {
|
|
7826
|
+
if (!isOrgRepoRoot()) return;
|
|
7820
7827
|
const hook = parseHookInput(await readStdin());
|
|
7821
7828
|
if (hook.session_id) persistSession(hook.session_id);
|
|
7822
7829
|
});
|
|
@@ -8230,16 +8237,16 @@ var import_node_child_process7 = require("node:child_process");
|
|
|
8230
8237
|
|
|
8231
8238
|
// src/session-start.ts
|
|
8232
8239
|
var import_node_fs13 = require("node:fs");
|
|
8233
|
-
var
|
|
8240
|
+
var import_node_path12 = require("node:path");
|
|
8234
8241
|
|
|
8235
8242
|
// src/scratch-gc.ts
|
|
8236
8243
|
var import_node_child_process6 = require("node:child_process");
|
|
8237
8244
|
var import_node_fs12 = require("node:fs");
|
|
8238
|
-
var
|
|
8245
|
+
var import_node_path11 = require("node:path");
|
|
8239
8246
|
|
|
8240
8247
|
// src/plan.ts
|
|
8241
8248
|
var import_node_fs11 = require("node:fs");
|
|
8242
|
-
var
|
|
8249
|
+
var import_node_path10 = require("node:path");
|
|
8243
8250
|
|
|
8244
8251
|
// src/frontmatter.ts
|
|
8245
8252
|
function splitFrontmatter(content) {
|
|
@@ -8322,8 +8329,8 @@ function rankPlansByRelevance(plans, signals, opts = {}) {
|
|
|
8322
8329
|
|
|
8323
8330
|
// src/plan.ts
|
|
8324
8331
|
var PLANS_DIR = "plans";
|
|
8325
|
-
var META_FILE = (0,
|
|
8326
|
-
var planPath = (slug) => (0,
|
|
8332
|
+
var META_FILE = (0, import_node_path10.join)(PLANS_DIR, ".plan-meta.json");
|
|
8333
|
+
var planPath = (slug) => (0, import_node_path10.join)(PLANS_DIR, `${slug}.md`);
|
|
8327
8334
|
var metaKey = (project2, slug) => `${project2}/${slug}`;
|
|
8328
8335
|
function parseMeta(raw) {
|
|
8329
8336
|
if (!raw) return {};
|
|
@@ -8348,7 +8355,7 @@ function hashContent(s) {
|
|
|
8348
8355
|
function staleHint(slug) {
|
|
8349
8356
|
return `remote "${slug}" is newer \u2014 run \`mmi-cli northstar pull ${slug}\` first (your local is based on an older version), or re-push with \`--force\` to overwrite`;
|
|
8350
8357
|
}
|
|
8351
|
-
var INDEX_FILE = (0,
|
|
8358
|
+
var INDEX_FILE = (0, import_node_path10.join)(PLANS_DIR, ".index.json");
|
|
8352
8359
|
var INDEX_TTL_MS = 6e4;
|
|
8353
8360
|
function parseIndex(raw) {
|
|
8354
8361
|
if (!raw) return null;
|
|
@@ -8377,7 +8384,7 @@ function mergeIndex(idx, scope, plans, now) {
|
|
|
8377
8384
|
const mergedScope = idx.scope === null ? null : [.../* @__PURE__ */ new Set([...idx.scope, ...scope])];
|
|
8378
8385
|
return { fetchedAt: now, scope: mergedScope, plans: [...kept, ...plans] };
|
|
8379
8386
|
}
|
|
8380
|
-
var QUEUE_FILE = (0,
|
|
8387
|
+
var QUEUE_FILE = (0, import_node_path10.join)(PLANS_DIR, ".sync-queue.json");
|
|
8381
8388
|
var QUEUE_MAX_ATTEMPTS = 10;
|
|
8382
8389
|
function isValidQueueEntry(e) {
|
|
8383
8390
|
if (!e || typeof e !== "object") return false;
|
|
@@ -8498,8 +8505,8 @@ function dropQueued(deps, project2, slug) {
|
|
|
8498
8505
|
}
|
|
8499
8506
|
function parsePlanSlugFromPath(cwd, filePath) {
|
|
8500
8507
|
const norm = (s) => s.replace(/\\/g, "/");
|
|
8501
|
-
const cwdNorm = norm((0,
|
|
8502
|
-
const pathNorm = norm((0,
|
|
8508
|
+
const cwdNorm = norm((0, import_node_path10.resolve)(cwd)).replace(/\/+$/, "");
|
|
8509
|
+
const pathNorm = norm((0, import_node_path10.resolve)(filePath));
|
|
8503
8510
|
const rel = pathNorm.startsWith(`${cwdNorm}/`) ? pathNorm.slice(cwdNorm.length + 1) : norm(filePath);
|
|
8504
8511
|
const m = /^plans\/([A-Za-z0-9][A-Za-z0-9_-]*)\.md$/.exec(rel);
|
|
8505
8512
|
return m ? m[1] : null;
|
|
@@ -9082,7 +9089,7 @@ var PLAN_ADVISORY_AGE_MS = 30 * 24 * 36e5;
|
|
|
9082
9089
|
var ROOT_SCRATCH_STALE_MS = 24 * 36e5;
|
|
9083
9090
|
var SCRATCH_GC_THROTTLE_MS = 24 * 36e5;
|
|
9084
9091
|
function scratchGcThrottlePath(mmiRoot) {
|
|
9085
|
-
return (0,
|
|
9092
|
+
return (0, import_node_path11.join)(mmiRoot, "head-ts", ".scratch-gc-last");
|
|
9086
9093
|
}
|
|
9087
9094
|
function scratchGcDue(stampPath, now = Date.now(), read = import_node_fs12.readFileSync) {
|
|
9088
9095
|
try {
|
|
@@ -9093,7 +9100,7 @@ function scratchGcDue(stampPath, now = Date.now(), read = import_node_fs12.readF
|
|
|
9093
9100
|
}
|
|
9094
9101
|
function markScratchGcRun(stampPath, now = Date.now()) {
|
|
9095
9102
|
try {
|
|
9096
|
-
(0, import_node_fs12.mkdirSync)((0,
|
|
9103
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path11.dirname)(stampPath), { recursive: true });
|
|
9097
9104
|
(0, import_node_fs12.writeFileSync)(stampPath, String(now), "utf8");
|
|
9098
9105
|
} catch {
|
|
9099
9106
|
}
|
|
@@ -9153,7 +9160,7 @@ function isTmpSidecar(name) {
|
|
|
9153
9160
|
function planScratchGc(snap, now = Date.now()) {
|
|
9154
9161
|
const candidates = [];
|
|
9155
9162
|
const normalizePath = (p) => p.replace(/\\/g, "/");
|
|
9156
|
-
const repoRoot = normalizePath((snap.repoRoot ?? (0,
|
|
9163
|
+
const repoRoot = normalizePath((snap.repoRoot ?? (0, import_node_path11.dirname)(snap.mmiRoot)).replace(/[\\/]+$/, ""));
|
|
9157
9164
|
const mmiPaths = new Set(snap.mmiFiles.map((f) => normalizePath(f.path)));
|
|
9158
9165
|
const headTsPrefix = `${snap.mmiRoot.replace(/[\\/]+$/, "")}/head-ts/`.replace(/\\/g, "/");
|
|
9159
9166
|
const days = (ms) => `${Math.floor(ms / 864e5)}d`;
|
|
@@ -9202,7 +9209,7 @@ function planScratchGc(snap, now = Date.now()) {
|
|
|
9202
9209
|
continue;
|
|
9203
9210
|
}
|
|
9204
9211
|
const orig = conflictCopyOriginal(f.name);
|
|
9205
|
-
if (orig && CONFLICT_COPY_ALLOWLIST.has(orig) && mmiPaths.has(normalizePath((0,
|
|
9212
|
+
if (orig && CONFLICT_COPY_ALLOWLIST.has(orig) && mmiPaths.has(normalizePath((0, import_node_path11.join)(f.dir, orig))) && age > CONFLICT_COPY_STALE_MS) {
|
|
9206
9213
|
add("conflict-copy", `cloud-sync conflict copy of ${orig} (${days(age)} old)`);
|
|
9207
9214
|
}
|
|
9208
9215
|
}
|
|
@@ -9272,7 +9279,7 @@ function syncedPlanMetaEntry(meta, project2, slug, hash) {
|
|
|
9272
9279
|
}
|
|
9273
9280
|
function readProject(repoRoot) {
|
|
9274
9281
|
try {
|
|
9275
|
-
const cfg = JSON.parse((0, import_node_fs12.readFileSync)((0,
|
|
9282
|
+
const cfg = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path11.join)(repoRoot, ".mmi", "config.json"), "utf8"));
|
|
9276
9283
|
if (typeof cfg.project === "string" && cfg.project.trim()) return cfg.project.trim();
|
|
9277
9284
|
} catch {
|
|
9278
9285
|
}
|
|
@@ -9280,7 +9287,7 @@ function readProject(repoRoot) {
|
|
|
9280
9287
|
}
|
|
9281
9288
|
function readPlanMeta(plansRoot) {
|
|
9282
9289
|
try {
|
|
9283
|
-
return parseMeta((0, import_node_fs12.readFileSync)((0,
|
|
9290
|
+
return parseMeta((0, import_node_fs12.readFileSync)((0, import_node_path11.join)(plansRoot, ".plan-meta.json"), "utf8"));
|
|
9284
9291
|
} catch {
|
|
9285
9292
|
return null;
|
|
9286
9293
|
}
|
|
@@ -9288,7 +9295,7 @@ function readPlanMeta(plansRoot) {
|
|
|
9288
9295
|
function readSyncQueueSlugs(plansRoot) {
|
|
9289
9296
|
let queueRaw;
|
|
9290
9297
|
try {
|
|
9291
|
-
queueRaw = (0, import_node_fs12.readFileSync)((0,
|
|
9298
|
+
queueRaw = (0, import_node_fs12.readFileSync)((0, import_node_path11.join)(plansRoot, ".sync-queue.json"), "utf8");
|
|
9292
9299
|
} catch (e) {
|
|
9293
9300
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
9294
9301
|
return code === "ENOENT" || code === "ENOTDIR" ? /* @__PURE__ */ new Set() : null;
|
|
@@ -9303,8 +9310,8 @@ function readSyncQueueSlugs(plansRoot) {
|
|
|
9303
9310
|
}
|
|
9304
9311
|
function physicalPlanCandidateStillAllowed(candidatePath, repoAnchor, lstat = import_node_fs12.lstatSync) {
|
|
9305
9312
|
const path2 = candidatePath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
9306
|
-
const parent = (0,
|
|
9307
|
-
const name = (0,
|
|
9313
|
+
const parent = (0, import_node_path11.dirname)(path2).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
9314
|
+
const name = (0, import_node_path11.basename)(path2);
|
|
9308
9315
|
const plansDir = `${repoAnchor}/plans`;
|
|
9309
9316
|
if (parent !== plansDir || !name.endsWith(".md")) return false;
|
|
9310
9317
|
try {
|
|
@@ -9352,7 +9359,7 @@ function treeOlderThan(root, now, floor) {
|
|
|
9352
9359
|
if (now - st.mtimeMs <= floor) return false;
|
|
9353
9360
|
if (!st.isDirectory()) continue;
|
|
9354
9361
|
for (const ent of (0, import_node_fs12.readdirSync)(current, { withFileTypes: true })) {
|
|
9355
|
-
const child = (0,
|
|
9362
|
+
const child = (0, import_node_path11.join)(current, ent.name);
|
|
9356
9363
|
if (isLinkLike(child, ent.isSymbolicLink())) return false;
|
|
9357
9364
|
stack.push(child);
|
|
9358
9365
|
}
|
|
@@ -9364,7 +9371,7 @@ function applyScratchGc(plan2, mmiRoot, now = Date.now()) {
|
|
|
9364
9371
|
let repoAnchor;
|
|
9365
9372
|
let anchor;
|
|
9366
9373
|
try {
|
|
9367
|
-
repoAnchor = (0, import_node_fs12.realpathSync)((0,
|
|
9374
|
+
repoAnchor = (0, import_node_fs12.realpathSync)((0, import_node_path11.dirname)(mmiRoot)).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
9368
9375
|
} catch {
|
|
9369
9376
|
return result;
|
|
9370
9377
|
}
|
|
@@ -9406,7 +9413,7 @@ function applyScratchGc(plan2, mmiRoot, now = Date.now()) {
|
|
|
9406
9413
|
continue;
|
|
9407
9414
|
}
|
|
9408
9415
|
const plansRoot = `${repoAnchor}/plans`;
|
|
9409
|
-
const slug = (0,
|
|
9416
|
+
const slug = (0, import_node_path11.basename)(c.path).replace(/\.md$/, "");
|
|
9410
9417
|
const pending = readSyncQueueSlugs(plansRoot);
|
|
9411
9418
|
if (pending === null || pending.has(slug)) {
|
|
9412
9419
|
result.skipped += 1;
|
|
@@ -9448,15 +9455,15 @@ function pathContained(real, anchor) {
|
|
|
9448
9455
|
}
|
|
9449
9456
|
function rootCandidateStillAllowed(c, repoAnchor) {
|
|
9450
9457
|
const path2 = c.path.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
9451
|
-
const parent = (0,
|
|
9452
|
-
const name = (0,
|
|
9458
|
+
const parent = (0, import_node_path11.dirname)(path2).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
9459
|
+
const name = (0, import_node_path11.basename)(path2);
|
|
9453
9460
|
if (c.family === "scratch-dir") return c.kind === "dir" && parent === repoAnchor && ROOT_SCRATCH_DIRS.has(name);
|
|
9454
9461
|
if (c.family === "scratch-file") return (c.kind ?? "file") === "file" && parent === repoAnchor && ROOT_SCRATCH_FILE_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
9455
9462
|
if (c.family === "plan") return physicalPlanCandidateStillAllowed(c.path, repoAnchor);
|
|
9456
9463
|
return false;
|
|
9457
9464
|
}
|
|
9458
9465
|
function trackedPathStatus(c, repoAnchor) {
|
|
9459
|
-
const rel = (0,
|
|
9466
|
+
const rel = (0, import_node_path11.relative)(repoAnchor, c.path).replace(/\\/g, "/");
|
|
9460
9467
|
if (!rel || rel.startsWith("../") || rel === "..") return null;
|
|
9461
9468
|
const gitPath = c.kind === "dir" ? `${rel.replace(/\/+$/, "")}/` : rel;
|
|
9462
9469
|
try {
|
|
@@ -9487,7 +9494,7 @@ function rootScratchDirSnapshot(root, readdir, stat) {
|
|
|
9487
9494
|
while (stack.length) {
|
|
9488
9495
|
const current = stack.pop();
|
|
9489
9496
|
for (const ent of readdir(current, { withFileTypes: true })) {
|
|
9490
|
-
const child = (0,
|
|
9497
|
+
const child = (0, import_node_path11.join)(current, ent.name);
|
|
9491
9498
|
if (ent.isSymbolicLink?.()) return null;
|
|
9492
9499
|
try {
|
|
9493
9500
|
(0, import_node_fs12.readlinkSync)(child);
|
|
@@ -9509,8 +9516,8 @@ function collectScratchSnapshot(repoRoot, deps = {}) {
|
|
|
9509
9516
|
const readdir = deps.readdir ?? import_node_fs12.readdirSync;
|
|
9510
9517
|
const stat = deps.stat ?? import_node_fs12.statSync;
|
|
9511
9518
|
const readFile7 = deps.readFile ?? import_node_fs12.readFileSync;
|
|
9512
|
-
const mmiRoot = (0,
|
|
9513
|
-
const plansRoot = (0,
|
|
9519
|
+
const mmiRoot = (0, import_node_path11.join)(repoRoot, ".mmi");
|
|
9520
|
+
const plansRoot = (0, import_node_path11.join)(repoRoot, "plans");
|
|
9514
9521
|
const rootScratchFiles = [];
|
|
9515
9522
|
try {
|
|
9516
9523
|
for (const ent of readdir(repoRoot, { withFileTypes: true })) {
|
|
@@ -9519,7 +9526,7 @@ function collectScratchSnapshot(repoRoot, deps = {}) {
|
|
|
9519
9526
|
if (!(isDir && ROOT_SCRATCH_DIRS.has(ent.name)) && !(isFile && ROOT_SCRATCH_FILE_PREFIXES.some((prefix) => ent.name.startsWith(prefix)))) {
|
|
9520
9527
|
continue;
|
|
9521
9528
|
}
|
|
9522
|
-
const full = (0,
|
|
9529
|
+
const full = (0, import_node_path11.join)(repoRoot, ent.name);
|
|
9523
9530
|
try {
|
|
9524
9531
|
if (isDir) {
|
|
9525
9532
|
const snap = rootScratchDirSnapshot(full, readdir, stat);
|
|
@@ -9538,7 +9545,7 @@ function collectScratchSnapshot(repoRoot, deps = {}) {
|
|
|
9538
9545
|
for (const ent of readdir(mmiRoot, { recursive: true, withFileTypes: true })) {
|
|
9539
9546
|
if (!ent.isFile()) continue;
|
|
9540
9547
|
const dir = ent.parentPath ?? ent.path ?? mmiRoot;
|
|
9541
|
-
const full = (0,
|
|
9548
|
+
const full = (0, import_node_path11.join)(dir, ent.name);
|
|
9542
9549
|
try {
|
|
9543
9550
|
const st = stat(full);
|
|
9544
9551
|
mmiFiles.push({ path: full, dir, name: ent.name, mtimeMs: st.mtimeMs, bytes: st.size });
|
|
@@ -9551,7 +9558,7 @@ function collectScratchSnapshot(repoRoot, deps = {}) {
|
|
|
9551
9558
|
try {
|
|
9552
9559
|
for (const ent of readdir(plansRoot, { withFileTypes: true })) {
|
|
9553
9560
|
if (!ent.isFile() || !ent.name.endsWith(".md")) continue;
|
|
9554
|
-
const full = (0,
|
|
9561
|
+
const full = (0, import_node_path11.join)(plansRoot, ent.name);
|
|
9555
9562
|
try {
|
|
9556
9563
|
const st = stat(full);
|
|
9557
9564
|
const raw = readFile7(full, "utf8");
|
|
@@ -9563,20 +9570,20 @@ function collectScratchSnapshot(repoRoot, deps = {}) {
|
|
|
9563
9570
|
}
|
|
9564
9571
|
let planMeta = {};
|
|
9565
9572
|
try {
|
|
9566
|
-
planMeta = parseMeta(readFile7((0,
|
|
9573
|
+
planMeta = parseMeta(readFile7((0, import_node_path11.join)(plansRoot, ".plan-meta.json"), "utf8"));
|
|
9567
9574
|
} catch {
|
|
9568
9575
|
planMeta = {};
|
|
9569
9576
|
}
|
|
9570
9577
|
let project2;
|
|
9571
9578
|
try {
|
|
9572
|
-
const cfg = JSON.parse(readFile7((0,
|
|
9579
|
+
const cfg = JSON.parse(readFile7((0, import_node_path11.join)(repoRoot, ".mmi", "config.json"), "utf8"));
|
|
9573
9580
|
if (typeof cfg.project === "string" && cfg.project.trim()) project2 = cfg.project.trim();
|
|
9574
9581
|
} catch {
|
|
9575
9582
|
}
|
|
9576
9583
|
const syncQueueSlugs = (() => {
|
|
9577
9584
|
let queueRaw;
|
|
9578
9585
|
try {
|
|
9579
|
-
queueRaw = readFile7((0,
|
|
9586
|
+
queueRaw = readFile7((0, import_node_path11.join)(plansRoot, ".sync-queue.json"), "utf8");
|
|
9580
9587
|
} catch (e) {
|
|
9581
9588
|
const code = typeof e === "object" && e && "code" in e ? String(e.code ?? "") : "";
|
|
9582
9589
|
return code === "ENOENT" || code === "ENOTDIR" ? /* @__PURE__ */ new Set() : null;
|
|
@@ -9649,23 +9656,23 @@ function spawnDetachedSelf(args, deps) {
|
|
|
9649
9656
|
}
|
|
9650
9657
|
}
|
|
9651
9658
|
function isInsideRepoSubdir(cwd, exists = import_node_fs13.existsSync) {
|
|
9652
|
-
if (exists((0,
|
|
9659
|
+
if (exists((0, import_node_path12.join)(cwd, ".git"))) return false;
|
|
9653
9660
|
let dir = cwd;
|
|
9654
9661
|
for (; ; ) {
|
|
9655
|
-
const parent = (0,
|
|
9662
|
+
const parent = (0, import_node_path12.dirname)(dir);
|
|
9656
9663
|
if (parent === dir) return false;
|
|
9657
|
-
if (exists((0,
|
|
9664
|
+
if (exists((0, import_node_path12.join)(parent, ".git"))) return true;
|
|
9658
9665
|
dir = parent;
|
|
9659
9666
|
}
|
|
9660
9667
|
}
|
|
9661
9668
|
function planStoreLines(cwd) {
|
|
9662
9669
|
const mdFiles = (dir, minSize = 0) => {
|
|
9663
|
-
const p = (0,
|
|
9670
|
+
const p = (0, import_node_path12.join)(cwd, dir);
|
|
9664
9671
|
if (!(0, import_node_fs13.existsSync)(p)) return [];
|
|
9665
9672
|
try {
|
|
9666
9673
|
return (0, import_node_fs13.readdirSync)(p).filter((f) => f.toLowerCase().endsWith(".md")).filter((f) => {
|
|
9667
9674
|
try {
|
|
9668
|
-
return (0, import_node_fs13.statSync)((0,
|
|
9675
|
+
return (0, import_node_fs13.statSync)((0, import_node_path12.join)(p, f)).size >= minSize;
|
|
9669
9676
|
} catch {
|
|
9670
9677
|
return false;
|
|
9671
9678
|
}
|
|
@@ -9686,7 +9693,7 @@ function planStoreLines(cwd) {
|
|
|
9686
9693
|
function scratchGcLines(cwd, env = process.env, now = Date.now()) {
|
|
9687
9694
|
if (env.MMI_NO_AUTO_GC) return [];
|
|
9688
9695
|
try {
|
|
9689
|
-
const stamp = scratchGcThrottlePath((0,
|
|
9696
|
+
const stamp = scratchGcThrottlePath((0, import_node_path12.join)(cwd, ".mmi"));
|
|
9690
9697
|
if (!scratchGcDue(stamp, now)) return [];
|
|
9691
9698
|
const run = executeScratchGc(cwd, { apply: true }, now);
|
|
9692
9699
|
markScratchGcRun(stamp, now);
|
|
@@ -9879,8 +9886,8 @@ function registerCoopCommands(program3) {
|
|
|
9879
9886
|
// src/throttle-commands.ts
|
|
9880
9887
|
var import_node_child_process8 = require("node:child_process");
|
|
9881
9888
|
var import_node_fs14 = require("node:fs");
|
|
9882
|
-
var
|
|
9883
|
-
var THROTTLE_TRACE_REL = (0,
|
|
9889
|
+
var import_node_path13 = require("node:path");
|
|
9890
|
+
var THROTTLE_TRACE_REL = (0, import_node_path13.join)(".mmi", "throttle", "trace.jsonl");
|
|
9884
9891
|
function resolveRepoGitRoot(cwd = process.cwd()) {
|
|
9885
9892
|
try {
|
|
9886
9893
|
const root = (0, import_node_child_process8.execFileSync)("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
|
|
@@ -9893,7 +9900,7 @@ function resolveRepoGitRoot(cwd = process.cwd()) {
|
|
|
9893
9900
|
}
|
|
9894
9901
|
}
|
|
9895
9902
|
function resolveThrottleTracePath(cwd = process.cwd()) {
|
|
9896
|
-
return (0,
|
|
9903
|
+
return (0, import_node_path13.join)(resolveRepoGitRoot(cwd), THROTTLE_TRACE_REL);
|
|
9897
9904
|
}
|
|
9898
9905
|
function resolveModeFromEnv() {
|
|
9899
9906
|
const v = String(process.env.MMI_THROTTLE_MODE ?? "block").trim().toLowerCase();
|
|
@@ -10950,11 +10957,11 @@ function ghError(e) {
|
|
|
10950
10957
|
|
|
10951
10958
|
// src/board-slice-cache.ts
|
|
10952
10959
|
var import_node_fs15 = require("node:fs");
|
|
10953
|
-
var
|
|
10954
|
-
var BOARD_SLICE_CACHE_FILE = (0,
|
|
10960
|
+
var import_node_path14 = require("node:path");
|
|
10961
|
+
var BOARD_SLICE_CACHE_FILE = (0, import_node_path14.join)(".mmi", "board-slice.json");
|
|
10955
10962
|
var BOARD_SLICE_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
10956
10963
|
function boardSliceCachePath(cwd) {
|
|
10957
|
-
return (0,
|
|
10964
|
+
return (0, import_node_path14.join)(cwd, BOARD_SLICE_CACHE_FILE);
|
|
10958
10965
|
}
|
|
10959
10966
|
function readCachedBoardSlice(cwd) {
|
|
10960
10967
|
try {
|
|
@@ -10969,7 +10976,7 @@ function writeCachedBoardSlice(cwd, slice) {
|
|
|
10969
10976
|
const path2 = boardSliceCachePath(cwd);
|
|
10970
10977
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
10971
10978
|
try {
|
|
10972
|
-
(0, import_node_fs15.mkdirSync)((0,
|
|
10979
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path14.dirname)(path2), { recursive: true });
|
|
10973
10980
|
(0, import_node_fs15.writeFileSync)(tmp, JSON.stringify(slice));
|
|
10974
10981
|
(0, import_node_fs15.renameSync)(tmp, path2);
|
|
10975
10982
|
} catch {
|
|
@@ -11103,7 +11110,7 @@ async function refreshBoardSliceCache(deps) {
|
|
|
11103
11110
|
|
|
11104
11111
|
// src/worktree.ts
|
|
11105
11112
|
var import_node_fs16 = require("node:fs");
|
|
11106
|
-
var
|
|
11113
|
+
var import_node_path15 = require("node:path");
|
|
11107
11114
|
var LOCAL_ONLY_FILES = [".claude/settings.local.json"];
|
|
11108
11115
|
var PKG = "package.json";
|
|
11109
11116
|
var LOCKFILE = "package-lock.json";
|
|
@@ -11133,12 +11140,12 @@ var realFsProbe = {
|
|
|
11133
11140
|
};
|
|
11134
11141
|
function scanInstallDirs(root, fs2 = realFsProbe) {
|
|
11135
11142
|
const factsFor = (dir) => {
|
|
11136
|
-
const abs = dir ? (0,
|
|
11143
|
+
const abs = dir ? (0, import_node_path15.join)(root, dir) : root;
|
|
11137
11144
|
return {
|
|
11138
11145
|
dir,
|
|
11139
|
-
hasPackageJson: fs2.isFile((0,
|
|
11140
|
-
hasLockfile: fs2.isFile((0,
|
|
11141
|
-
hasNodeModules: fs2.isDir((0,
|
|
11146
|
+
hasPackageJson: fs2.isFile((0, import_node_path15.join)(abs, PKG)),
|
|
11147
|
+
hasLockfile: fs2.isFile((0, import_node_path15.join)(abs, LOCKFILE)),
|
|
11148
|
+
hasNodeModules: fs2.isDir((0, import_node_path15.join)(abs, NODE_MODULES))
|
|
11142
11149
|
};
|
|
11143
11150
|
};
|
|
11144
11151
|
const children = fs2.listDirs(root).filter((name) => name !== NODE_MODULES && name !== ".git");
|
|
@@ -11148,7 +11155,7 @@ function npmInstallTargets(dirs) {
|
|
|
11148
11155
|
return dirs.filter((d) => d.hasPackageJson && !d.hasNodeModules).map((d) => ({ dir: d.dir, command: d.hasLockfile ? "npm ci" : "npm install" }));
|
|
11149
11156
|
}
|
|
11150
11157
|
function isLinkedWorktree(root, fs2 = realFsProbe) {
|
|
11151
|
-
return fs2.isFile((0,
|
|
11158
|
+
return fs2.isFile((0, import_node_path15.join)(root, ".git"));
|
|
11152
11159
|
}
|
|
11153
11160
|
function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
11154
11161
|
if (!isLinkedWorktree(root, fs2)) return null;
|
|
@@ -11158,7 +11165,7 @@ function worktreeAutoProvisionBanner(root, fs2 = realFsProbe) {
|
|
|
11158
11165
|
return `[worktree] provisioning tooling in the background (deps in ${where} + local config) \u2014 \`mmi-cli worktree setup\` to redo`;
|
|
11159
11166
|
}
|
|
11160
11167
|
function defaultCopyFile(from, to) {
|
|
11161
|
-
(0, import_node_fs16.mkdirSync)((0,
|
|
11168
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path15.dirname)(to), { recursive: true });
|
|
11162
11169
|
(0, import_node_fs16.copyFileSync)(from, to);
|
|
11163
11170
|
}
|
|
11164
11171
|
async function provisionWorktree(worktreeRoot, deps) {
|
|
@@ -11171,7 +11178,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
11171
11178
|
const skippedInstall = allDirs.filter((d) => d.hasPackageJson && d.hasNodeModules).map((d) => d.dir);
|
|
11172
11179
|
const installed = [];
|
|
11173
11180
|
for (const target of targets) {
|
|
11174
|
-
const cwd = target.dir ? (0,
|
|
11181
|
+
const cwd = target.dir ? (0, import_node_path15.join)(worktreeRoot, target.dir) : worktreeRoot;
|
|
11175
11182
|
log(`installing deps: ${target.command} in ${target.dir || "."}`);
|
|
11176
11183
|
await deps.runInstall(target.command, cwd);
|
|
11177
11184
|
installed.push(target);
|
|
@@ -11180,7 +11187,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
11180
11187
|
const copySkipped = [];
|
|
11181
11188
|
const primary = await deps.primaryCheckout();
|
|
11182
11189
|
for (const rel of LOCAL_ONLY_FILES) {
|
|
11183
|
-
const dest = (0,
|
|
11190
|
+
const dest = (0, import_node_path15.join)(worktreeRoot, rel);
|
|
11184
11191
|
if (fs2.isFile(dest)) {
|
|
11185
11192
|
copySkipped.push({ file: rel, reason: "already-present" });
|
|
11186
11193
|
continue;
|
|
@@ -11189,11 +11196,11 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
11189
11196
|
copySkipped.push({ file: rel, reason: "no-primary" });
|
|
11190
11197
|
continue;
|
|
11191
11198
|
}
|
|
11192
|
-
if (!fs2.isFile((0,
|
|
11199
|
+
if (!fs2.isFile((0, import_node_path15.join)(primary, rel))) {
|
|
11193
11200
|
copySkipped.push({ file: rel, reason: "absent-in-primary" });
|
|
11194
11201
|
continue;
|
|
11195
11202
|
}
|
|
11196
|
-
copyFile((0,
|
|
11203
|
+
copyFile((0, import_node_path15.join)(primary, rel), dest);
|
|
11197
11204
|
copied.push(rel);
|
|
11198
11205
|
log(`copied local config: ${rel}`);
|
|
11199
11206
|
}
|
|
@@ -11201,7 +11208,7 @@ async function provisionWorktree(worktreeRoot, deps) {
|
|
|
11201
11208
|
}
|
|
11202
11209
|
function defaultWorktreePath(repoRoot, branch) {
|
|
11203
11210
|
const safe = branch.replace(/[/\\]+/g, "-");
|
|
11204
|
-
return (0,
|
|
11211
|
+
return (0, import_node_path15.join)((0, import_node_path15.dirname)(repoRoot), "mmi-worktrees", safe);
|
|
11205
11212
|
}
|
|
11206
11213
|
|
|
11207
11214
|
// src/northstar-context.ts
|
|
@@ -11343,7 +11350,7 @@ function whoamiLine(report) {
|
|
|
11343
11350
|
}
|
|
11344
11351
|
|
|
11345
11352
|
// src/index.ts
|
|
11346
|
-
var
|
|
11353
|
+
var import_node_path24 = require("node:path");
|
|
11347
11354
|
|
|
11348
11355
|
// src/merge-ci-policy.ts
|
|
11349
11356
|
function resolveMergeCiPolicy(input) {
|
|
@@ -12526,7 +12533,7 @@ async function resolveAutoAddBoardAttach(client, cfg, selector, priority, warn =
|
|
|
12526
12533
|
// src/gh-create.ts
|
|
12527
12534
|
var import_promises5 = require("node:fs/promises");
|
|
12528
12535
|
var import_node_os3 = require("node:os");
|
|
12529
|
-
var
|
|
12536
|
+
var import_node_path16 = require("node:path");
|
|
12530
12537
|
var import_node_crypto5 = require("node:crypto");
|
|
12531
12538
|
var ISSUE_TYPES = ["bug", "feature", "task"];
|
|
12532
12539
|
var GH_MUTATION_TIMEOUT_MS = 12e4;
|
|
@@ -12567,7 +12574,7 @@ async function bodyArgsViaFile(args, deps = {}) {
|
|
|
12567
12574
|
} };
|
|
12568
12575
|
const write = deps.write ?? import_promises5.writeFile;
|
|
12569
12576
|
const remove = deps.remove ?? import_promises5.unlink;
|
|
12570
|
-
const file = (0,
|
|
12577
|
+
const file = (0, import_node_path16.join)(deps.dir ?? (0, import_node_os3.tmpdir)(), `mmi-gh-body-${process.pid}-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}.md`);
|
|
12571
12578
|
await write(file, args[i + 1], "utf8");
|
|
12572
12579
|
return {
|
|
12573
12580
|
args: [...args.slice(0, i), "--body-file", file, ...args.slice(i + 2)],
|
|
@@ -13679,7 +13686,7 @@ async function runStageLiveDown(deps, t) {
|
|
|
13679
13686
|
|
|
13680
13687
|
// src/design-system.ts
|
|
13681
13688
|
var import_node_fs17 = require("node:fs");
|
|
13682
|
-
var
|
|
13689
|
+
var import_node_path17 = require("node:path");
|
|
13683
13690
|
var UI_PACKAGE_CANDIDATES = ["@mutmutco/ui-dashboard", "@mutmutco/ui", "@mutmutco/theme"];
|
|
13684
13691
|
var DESIGN_SYSTEM_VERSION_LABEL = "@mutmutco design-system npm package (vs @latest)";
|
|
13685
13692
|
function dashboardConsumerRegistryFix(error) {
|
|
@@ -13734,11 +13741,11 @@ function readJsonFile(path2) {
|
|
|
13734
13741
|
}
|
|
13735
13742
|
}
|
|
13736
13743
|
function isUiFactoryCheckout(root) {
|
|
13737
|
-
const pkg = readJsonFile((0,
|
|
13744
|
+
const pkg = readJsonFile((0, import_node_path17.join)(root, "package.json"));
|
|
13738
13745
|
return pkg?.name === "mmd-ui" && pkg?.private === true;
|
|
13739
13746
|
}
|
|
13740
13747
|
function resolveDeclaredUiPackage(root) {
|
|
13741
|
-
const pkg = readJsonFile((0,
|
|
13748
|
+
const pkg = readJsonFile((0, import_node_path17.join)(root, "package.json"));
|
|
13742
13749
|
if (!pkg) return void 0;
|
|
13743
13750
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13744
13751
|
for (const name of UI_PACKAGE_CANDIDATES) {
|
|
@@ -13748,7 +13755,7 @@ function resolveDeclaredUiPackage(root) {
|
|
|
13748
13755
|
return void 0;
|
|
13749
13756
|
}
|
|
13750
13757
|
function readLockfileInstalledVersion(root, packageName) {
|
|
13751
|
-
const lockPath = (0,
|
|
13758
|
+
const lockPath = (0, import_node_path17.join)(root, "package-lock.json");
|
|
13752
13759
|
if (!(0, import_node_fs17.existsSync)(lockPath)) return void 0;
|
|
13753
13760
|
const lock = readJsonFile(lockPath);
|
|
13754
13761
|
const node = lock?.packages?.[`node_modules/${packageName}`];
|
|
@@ -13779,7 +13786,7 @@ function designSystemSnapshot(root) {
|
|
|
13779
13786
|
// src/design-system-registry.ts
|
|
13780
13787
|
var import_node_crypto6 = require("node:crypto");
|
|
13781
13788
|
var import_node_fs19 = require("node:fs");
|
|
13782
|
-
var
|
|
13789
|
+
var import_node_path18 = require("node:path");
|
|
13783
13790
|
|
|
13784
13791
|
// src/atomic-write.ts
|
|
13785
13792
|
var import_node_fs18 = require("node:fs");
|
|
@@ -13803,7 +13810,7 @@ function readJsonFile2(path2) {
|
|
|
13803
13810
|
}
|
|
13804
13811
|
}
|
|
13805
13812
|
function readComponentsJson(root) {
|
|
13806
|
-
return readJsonFile2((0,
|
|
13813
|
+
return readJsonFile2((0, import_node_path18.join)(root, "components.json"));
|
|
13807
13814
|
}
|
|
13808
13815
|
function hasMutmutcoRegistry(root) {
|
|
13809
13816
|
const url = readComponentsJson(root)?.registries?.["@mutmutco"];
|
|
@@ -13811,7 +13818,7 @@ function hasMutmutcoRegistry(root) {
|
|
|
13811
13818
|
}
|
|
13812
13819
|
function resolveCacheDir(root) {
|
|
13813
13820
|
const custom = readComponentsJson(root)?.mmi?.cacheDir;
|
|
13814
|
-
return (0,
|
|
13821
|
+
return (0, import_node_path18.join)(root, custom ?? DESIGN_SYSTEM_CACHE_DIR);
|
|
13815
13822
|
}
|
|
13816
13823
|
function resolveRegistryUrlTemplate(root) {
|
|
13817
13824
|
return readComponentsJson(root)?.registries?.["@mutmutco"];
|
|
@@ -13820,7 +13827,7 @@ function registryItemUrl(template, name) {
|
|
|
13820
13827
|
return template.replace("{name}", name);
|
|
13821
13828
|
}
|
|
13822
13829
|
function readDesignSystemManifest(root) {
|
|
13823
|
-
const raw = readJsonFile2((0,
|
|
13830
|
+
const raw = readJsonFile2((0, import_node_path18.join)(root, DESIGN_SYSTEM_MANIFEST_PATH));
|
|
13824
13831
|
if (!raw || !Array.isArray(raw.components)) return void 0;
|
|
13825
13832
|
return raw;
|
|
13826
13833
|
}
|
|
@@ -13836,7 +13843,7 @@ function scanCachedComponentNames(cacheDir) {
|
|
|
13836
13843
|
const names = /* @__PURE__ */ new Set();
|
|
13837
13844
|
const walk = (dir) => {
|
|
13838
13845
|
for (const ent of (0, import_node_fs19.readdirSync)(dir, { withFileTypes: true })) {
|
|
13839
|
-
const p = (0,
|
|
13846
|
+
const p = (0, import_node_path18.join)(dir, ent.name);
|
|
13840
13847
|
if (ent.isDirectory()) walk(p);
|
|
13841
13848
|
else if (ent.isFile() && /\.(tsx?|jsx?)$/.test(ent.name)) {
|
|
13842
13849
|
names.add(ent.name.replace(/\.(tsx|ts|jsx|js)$/, ""));
|
|
@@ -13925,7 +13932,7 @@ async function gatherRegistryComponentsState(root, targetVersion, deps) {
|
|
|
13925
13932
|
let componentStale = false;
|
|
13926
13933
|
for (const file of item.files) {
|
|
13927
13934
|
if (!file.target || file.content == null) continue;
|
|
13928
|
-
const cachePath = (0,
|
|
13935
|
+
const cachePath = (0, import_node_path18.join)(cacheDir, cacheRelativePath(file.target));
|
|
13929
13936
|
if (!(0, import_node_fs19.existsSync)(cachePath)) {
|
|
13930
13937
|
componentStale = true;
|
|
13931
13938
|
break;
|
|
@@ -13941,7 +13948,7 @@ async function gatherRegistryComponentsState(root, targetVersion, deps) {
|
|
|
13941
13948
|
}
|
|
13942
13949
|
}
|
|
13943
13950
|
if (componentStale) {
|
|
13944
|
-
if ((0, import_node_fs19.existsSync)((0,
|
|
13951
|
+
if ((0, import_node_fs19.existsSync)((0, import_node_path18.join)(cacheDir, "ui", `${name}.tsx`)) || (0, import_node_fs19.existsSync)((0, import_node_path18.join)(cacheDir, `${name}.tsx`))) {
|
|
13945
13952
|
stale.push(name);
|
|
13946
13953
|
} else {
|
|
13947
13954
|
missing.push(name);
|
|
@@ -13969,15 +13976,15 @@ async function applyRegistryComponentsSync(root, components, targetVersion, log,
|
|
|
13969
13976
|
if (!item) return { ok: false };
|
|
13970
13977
|
for (const file of item.files) {
|
|
13971
13978
|
if (!file.target || file.content == null) continue;
|
|
13972
|
-
const outPath = (0,
|
|
13973
|
-
deps.mkdir((0,
|
|
13979
|
+
const outPath = (0, import_node_path18.join)(cacheDir, cacheRelativePath(file.target));
|
|
13980
|
+
deps.mkdir((0, import_node_path18.dirname)(outPath));
|
|
13974
13981
|
const body = file.content.endsWith("\n") ? file.content : `${file.content}
|
|
13975
13982
|
`;
|
|
13976
13983
|
deps.writeFile(outPath, body);
|
|
13977
13984
|
}
|
|
13978
13985
|
}
|
|
13979
|
-
const manifestPath = (0,
|
|
13980
|
-
deps.mkdir((0,
|
|
13986
|
+
const manifestPath = (0, import_node_path18.join)(root, DESIGN_SYSTEM_MANIFEST_PATH);
|
|
13987
|
+
deps.mkdir((0, import_node_path18.dirname)(manifestPath));
|
|
13981
13988
|
const manifest = {
|
|
13982
13989
|
version: targetVersion,
|
|
13983
13990
|
syncedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -14746,7 +14753,7 @@ async function announceRelease(deps, args) {
|
|
|
14746
14753
|
|
|
14747
14754
|
// src/port-registry.ts
|
|
14748
14755
|
var import_node_fs20 = require("node:fs");
|
|
14749
|
-
var
|
|
14756
|
+
var import_node_path19 = require("node:path");
|
|
14750
14757
|
|
|
14751
14758
|
// ../infra/port-geometry.mjs
|
|
14752
14759
|
var PORT_BLOCK = 100;
|
|
@@ -14799,18 +14806,18 @@ function existingPortRange(repo, registry2) {
|
|
|
14799
14806
|
return registry2[repo] ?? null;
|
|
14800
14807
|
}
|
|
14801
14808
|
function portRangeInfraAt(root, source) {
|
|
14802
|
-
const registryPath = (0,
|
|
14803
|
-
const ddbScriptPath = (0,
|
|
14809
|
+
const registryPath = (0, import_node_path19.join)(root, "infra", "port-ranges.json");
|
|
14810
|
+
const ddbScriptPath = (0, import_node_path19.join)(root, "infra", "port-ddb.mjs");
|
|
14804
14811
|
if (!(0, import_node_fs20.existsSync)(registryPath) || !(0, import_node_fs20.existsSync)(ddbScriptPath)) return null;
|
|
14805
14812
|
return { root, source, registryPath, ddbScriptPath };
|
|
14806
14813
|
}
|
|
14807
14814
|
function resolvePortRangeInfra(cwd) {
|
|
14808
14815
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
14809
14816
|
if (direct) return direct;
|
|
14810
|
-
for (let dir = cwd; ; dir = (0,
|
|
14811
|
-
const sibling = portRangeInfraAt((0,
|
|
14817
|
+
for (let dir = cwd; ; dir = (0, import_node_path19.dirname)(dir)) {
|
|
14818
|
+
const sibling = portRangeInfraAt((0, import_node_path19.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
14812
14819
|
if (sibling) return sibling;
|
|
14813
|
-
const parent = (0,
|
|
14820
|
+
const parent = (0, import_node_path19.dirname)(dir);
|
|
14814
14821
|
if (parent === dir) return null;
|
|
14815
14822
|
}
|
|
14816
14823
|
}
|
|
@@ -16075,7 +16082,7 @@ ${section}`.trim();
|
|
|
16075
16082
|
}
|
|
16076
16083
|
|
|
16077
16084
|
// src/project-set.ts
|
|
16078
|
-
var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "dashboard", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "gate"];
|
|
16085
|
+
var UNSET_KEYS = ["oauth", "requiredRuntimeSecrets", "edgeDomains", "requiredGcpApis", "publishRequired", "publishDir", "dsManifestPath", "dashboard", "fofuEnabled", "consumesDesignSystem", "ci", "requiredChecks", "gate"];
|
|
16079
16086
|
var UNSET_KEY_SET = new Set(UNSET_KEYS);
|
|
16080
16087
|
var RUNTIME_SECRET_STAGES = ["dev", "rc", "main"];
|
|
16081
16088
|
function parseRuntimeSecretsVar(raw) {
|
|
@@ -16261,6 +16268,16 @@ function parsePublishDirVar(raw) {
|
|
|
16261
16268
|
}
|
|
16262
16269
|
return v;
|
|
16263
16270
|
}
|
|
16271
|
+
function parseDsManifestPathVar(raw) {
|
|
16272
|
+
const v = raw.trim();
|
|
16273
|
+
if (v === "" || !/^[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/.test(v) || /(^|\/)\.\.(\/|$)/.test(v)) {
|
|
16274
|
+
throw new Error('project set: dsManifestPath must be a safe relative path \u2014 no leading slash, no ".." segment');
|
|
16275
|
+
}
|
|
16276
|
+
if (v !== "package.json" && !v.endsWith("/package.json")) {
|
|
16277
|
+
throw new Error("project set: dsManifestPath must point to a package.json, e.g. web/package.json");
|
|
16278
|
+
}
|
|
16279
|
+
return v;
|
|
16280
|
+
}
|
|
16264
16281
|
function parseRequiredChecksVar(raw) {
|
|
16265
16282
|
let parsed;
|
|
16266
16283
|
try {
|
|
@@ -16312,6 +16329,7 @@ var SETTABLE_VAR_KEYS = [
|
|
|
16312
16329
|
"oauth",
|
|
16313
16330
|
"publishRequired",
|
|
16314
16331
|
"publishDir",
|
|
16332
|
+
"dsManifestPath",
|
|
16315
16333
|
"dashboard",
|
|
16316
16334
|
"fofuEnabled",
|
|
16317
16335
|
"consumesDesignSystem",
|
|
@@ -16332,6 +16350,7 @@ var SETTABLE_VAR_HINTS = {
|
|
|
16332
16350
|
projectNumber: "numeric",
|
|
16333
16351
|
publishRequired: "true|false",
|
|
16334
16352
|
publishDir: "relative subpath, e.g. packages/ui",
|
|
16353
|
+
dsManifestPath: "relative path to a package.json, e.g. web/package.json",
|
|
16335
16354
|
dashboard: "true|false",
|
|
16336
16355
|
fofuEnabled: "true|false",
|
|
16337
16356
|
consumesDesignSystem: '"fofu"',
|
|
@@ -16416,6 +16435,8 @@ function buildProjectSetPatch(input) {
|
|
|
16416
16435
|
patch[key] = parseConsumesDesignSystemVar(raw);
|
|
16417
16436
|
} else if (key === "publishDir") {
|
|
16418
16437
|
patch[key] = parsePublishDirVar(raw);
|
|
16438
|
+
} else if (key === "dsManifestPath") {
|
|
16439
|
+
patch[key] = parseDsManifestPathVar(raw);
|
|
16419
16440
|
} else if (key === "ci") {
|
|
16420
16441
|
if (raw !== "none") throw new Error('project set: ci must be "none" (or use --unset ci to require checks)');
|
|
16421
16442
|
patch[key] = raw;
|
|
@@ -17574,14 +17595,14 @@ function authorizeBodyHasMismatch(body) {
|
|
|
17574
17595
|
// src/doctor-run.ts
|
|
17575
17596
|
var import_node_fs26 = require("node:fs");
|
|
17576
17597
|
var import_promises7 = require("node:fs/promises");
|
|
17577
|
-
var
|
|
17598
|
+
var import_node_path23 = require("node:path");
|
|
17578
17599
|
var import_node_os5 = require("node:os");
|
|
17579
17600
|
|
|
17580
17601
|
// src/cursor-plugin-seed.ts
|
|
17581
17602
|
var import_node_child_process12 = require("node:child_process");
|
|
17582
17603
|
var import_node_fs22 = require("node:fs");
|
|
17583
17604
|
var import_node_os4 = require("node:os");
|
|
17584
|
-
var
|
|
17605
|
+
var import_node_path20 = require("node:path");
|
|
17585
17606
|
var import_node_util7 = require("node:util");
|
|
17586
17607
|
function isSemverVersion(v) {
|
|
17587
17608
|
return typeof v === "string" && /^v?\d+\.\d+\.\d+/.test(v.trim());
|
|
@@ -17598,13 +17619,13 @@ function ghReleaseTarballApiArgs(tag) {
|
|
|
17598
17619
|
}
|
|
17599
17620
|
function cursorUserGlobalStatePath() {
|
|
17600
17621
|
if (process.platform === "win32") {
|
|
17601
|
-
const base = process.env.APPDATA || (0,
|
|
17602
|
-
return (0,
|
|
17622
|
+
const base = process.env.APPDATA || (0, import_node_path20.join)((0, import_node_os4.homedir)(), "AppData", "Roaming");
|
|
17623
|
+
return (0, import_node_path20.join)(base, "Cursor", "User", "globalStorage", "state.vscdb");
|
|
17603
17624
|
}
|
|
17604
17625
|
if (process.platform === "darwin") {
|
|
17605
|
-
return (0,
|
|
17626
|
+
return (0, import_node_path20.join)((0, import_node_os4.homedir)(), "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
17606
17627
|
}
|
|
17607
|
-
return (0,
|
|
17628
|
+
return (0, import_node_path20.join)((0, import_node_os4.homedir)(), ".config", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
17608
17629
|
}
|
|
17609
17630
|
async function readCursorThirdPartyExtensibilityEnabled(execFileP5) {
|
|
17610
17631
|
const dbPath = cursorUserGlobalStatePath();
|
|
@@ -17624,7 +17645,7 @@ async function readCursorThirdPartyExtensibilityEnabled(execFileP5) {
|
|
|
17624
17645
|
function syncDirContents(src, dest) {
|
|
17625
17646
|
(0, import_node_fs22.mkdirSync)(dest, { recursive: true });
|
|
17626
17647
|
for (const name of (0, import_node_fs22.readdirSync)(dest)) {
|
|
17627
|
-
(0, import_node_fs22.rmSync)((0,
|
|
17648
|
+
(0, import_node_fs22.rmSync)((0, import_node_path20.join)(dest, name), { recursive: true, force: true });
|
|
17628
17649
|
}
|
|
17629
17650
|
(0, import_node_fs22.cpSync)(src, dest, { recursive: true });
|
|
17630
17651
|
}
|
|
@@ -17632,21 +17653,21 @@ function releaseTag(releasedVersion) {
|
|
|
17632
17653
|
return releasedVersion.startsWith("v") ? releasedVersion : `v${releasedVersion}`;
|
|
17633
17654
|
}
|
|
17634
17655
|
async function extractPluginMmiFromHubCheckout(hubCheckout, tag, tmpRoot, execFileP5) {
|
|
17635
|
-
const tarFile = (0,
|
|
17656
|
+
const tarFile = (0, import_node_path20.join)(tmpRoot, "archive.tar");
|
|
17636
17657
|
try {
|
|
17637
17658
|
await execFileP5("git", gitFetchReleaseTagArgs(hubCheckout, tag), { timeout: 6e4 });
|
|
17638
17659
|
await execFileP5("git", ["-C", hubCheckout, "archive", "--format=tar", `--output=${tarFile}`, tag, "plugins/mmi"], {
|
|
17639
17660
|
timeout: 6e4
|
|
17640
17661
|
});
|
|
17641
17662
|
await execFileP5("tar", ["-xf", tarFile, "-C", tmpRoot], { timeout: 6e4 });
|
|
17642
|
-
const pluginMmi = (0,
|
|
17643
|
-
return (0, import_node_fs22.existsSync)((0,
|
|
17663
|
+
const pluginMmi = (0, import_node_path20.join)(tmpRoot, "plugins", "mmi");
|
|
17664
|
+
return (0, import_node_fs22.existsSync)((0, import_node_path20.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
|
|
17644
17665
|
} catch {
|
|
17645
17666
|
return void 0;
|
|
17646
17667
|
}
|
|
17647
17668
|
}
|
|
17648
17669
|
async function downloadPluginMmiViaGh(tag, tmpRoot) {
|
|
17649
|
-
const tarPath = (0,
|
|
17670
|
+
const tarPath = (0, import_node_path20.join)(tmpRoot, "repo.tgz");
|
|
17650
17671
|
try {
|
|
17651
17672
|
(0, import_node_fs22.mkdirSync)(tmpRoot, { recursive: true });
|
|
17652
17673
|
const { stdout } = await execFileBuffer("gh", ghReleaseTarballApiArgs(tag), {
|
|
@@ -17659,8 +17680,8 @@ async function downloadPluginMmiViaGh(tag, tmpRoot) {
|
|
|
17659
17680
|
await execFileBuffer("tar", ["-xzf", tarPath, "-C", tmpRoot], { timeout: 12e4, windowsHide: true });
|
|
17660
17681
|
const top = (0, import_node_fs22.readdirSync)(tmpRoot).find((entry) => entry !== "repo.tgz");
|
|
17661
17682
|
if (!top) return void 0;
|
|
17662
|
-
const pluginMmi = (0,
|
|
17663
|
-
return (0, import_node_fs22.existsSync)((0,
|
|
17683
|
+
const pluginMmi = (0, import_node_path20.join)(tmpRoot, top, "plugins", "mmi");
|
|
17684
|
+
return (0, import_node_fs22.existsSync)((0, import_node_path20.join)(pluginMmi, PLUGIN_JSON_REL)) ? pluginMmi : void 0;
|
|
17664
17685
|
} catch {
|
|
17665
17686
|
return void 0;
|
|
17666
17687
|
}
|
|
@@ -17672,7 +17693,7 @@ async function resolvePluginMmiSource(releasedVersion, hubCheckout, tmpRoot, exe
|
|
|
17672
17693
|
const fromHub = await extractPluginMmiFromHubCheckout(hubCheckout, tag, tmpRoot, execFileP5);
|
|
17673
17694
|
if (fromHub) return fromHub;
|
|
17674
17695
|
}
|
|
17675
|
-
return downloadPluginMmiViaGh(tag, (0,
|
|
17696
|
+
return downloadPluginMmiViaGh(tag, (0, import_node_path20.join)(tmpRoot, "gh"));
|
|
17676
17697
|
}
|
|
17677
17698
|
function cursorPluginPinsNeedingSeed(pins, releasedVersion) {
|
|
17678
17699
|
if (!isSemverVersion(releasedVersion)) return pins.filter((pin) => !pin.hasPluginJson || !pin.hasHooksJson || pin.isEmpty);
|
|
@@ -18520,7 +18541,7 @@ function buildCursorPluginInstallCheck(input) {
|
|
|
18520
18541
|
};
|
|
18521
18542
|
}
|
|
18522
18543
|
}
|
|
18523
|
-
if (input.
|
|
18544
|
+
if (input.cacheRootExists && isSemverVersion2(input.releasedVersion) && input.pins.some((pin) => isSemverVersion2(pin.version) && compareVersions(pin.version, input.releasedVersion) < 0)) {
|
|
18524
18545
|
const stale = input.pins.filter((pin) => isSemverVersion2(pin.version) && compareVersions(pin.version, input.releasedVersion) < 0).map((pin) => `${pin.version} at ${pin.name}`).join(", ");
|
|
18525
18546
|
return {
|
|
18526
18547
|
...base,
|
|
@@ -18700,12 +18721,34 @@ function doctorHealPlan(input) {
|
|
|
18700
18721
|
const versionUpdate = versionAutoUpdateAction(input.versionReport, input.hasPluginRoot);
|
|
18701
18722
|
const pluginReinstall = input.isOrgRepo && !input.installedVersionCheck.ok && (input.surface === "claude-cli" || input.surface === "claude-vscode" || input.surface === "codex") && Boolean(input.installedVersionCheck.staleSurfaces?.length);
|
|
18702
18723
|
const legacyPluginMigration = input.isOrgRepo && !input.legacyPluginCheck.ok;
|
|
18703
|
-
const
|
|
18704
|
-
|
|
18724
|
+
const opencodeReinstall = input.isOrgRepo && Boolean(input.opencodeAdapterStale);
|
|
18725
|
+
const cursorReseed = input.isOrgRepo && Boolean(input.cursorCacheStale);
|
|
18726
|
+
const needsEagerHeal = versionUpdate !== "none" || pluginReinstall || legacyPluginMigration || opencodeReinstall || cursorReseed;
|
|
18727
|
+
return { needsEagerHeal, versionUpdate, pluginReinstall, legacyPluginMigration, opencodeReinstall, cursorReseed };
|
|
18705
18728
|
}
|
|
18706
18729
|
function doctorPreflightDoneLine(surface) {
|
|
18707
18730
|
return `\u21BB MMI tooling updated \u2014 ${reloadAction(surface)} to load changes`;
|
|
18708
18731
|
}
|
|
18732
|
+
function selfUpdateHaltLine(report) {
|
|
18733
|
+
const to = report.releasedVersion ?? "latest";
|
|
18734
|
+
return `\u21BB mmi-cli updated \u2192 ${to}. This process is still the previous version \u2014 rerun \`mmi-cli doctor --apply\` so the remaining surfaces reconcile under the new CLI.`;
|
|
18735
|
+
}
|
|
18736
|
+
function buildSelfUpdateHaltPayload(input) {
|
|
18737
|
+
return {
|
|
18738
|
+
ok: false,
|
|
18739
|
+
rerunRequired: true,
|
|
18740
|
+
reason: "mmi-cli self-updated; rerun doctor so the remaining surfaces reconcile under the new CLI",
|
|
18741
|
+
updatedTo: input.updatedTo ?? null,
|
|
18742
|
+
checks: input.checks
|
|
18743
|
+
};
|
|
18744
|
+
}
|
|
18745
|
+
function preflightOutcome(input) {
|
|
18746
|
+
if (input.gaps.length) {
|
|
18747
|
+
return { healed: false, line: `\u26A0 MMI preflight: ${input.gaps.length} item(s) still need attention \u2014 ${input.gaps.map((g) => g.fix).join(" \xB7 ")}` };
|
|
18748
|
+
}
|
|
18749
|
+
if (input.needsEagerHeal) return { healed: true, line: doctorPreflightDoneLine(input.surface) };
|
|
18750
|
+
return { healed: true };
|
|
18751
|
+
}
|
|
18709
18752
|
function pluginAutonomousHaltLine(reloadHint) {
|
|
18710
18753
|
return `\u26A0 PLUGIN RELOAD REQUIRED \u2014 mmi:* skills and agent types are unavailable until you ${reloadHint}. Halt autonomous /grind and /build until then.`;
|
|
18711
18754
|
}
|
|
@@ -18741,14 +18784,14 @@ function renderTerseDoctorReport(input) {
|
|
|
18741
18784
|
|
|
18742
18785
|
// src/kb-drift-report.ts
|
|
18743
18786
|
var import_node_fs23 = require("node:fs");
|
|
18744
|
-
var
|
|
18787
|
+
var import_node_path21 = require("node:path");
|
|
18745
18788
|
function yesterdayIso() {
|
|
18746
18789
|
const d = /* @__PURE__ */ new Date();
|
|
18747
18790
|
d.setUTCDate(d.getUTCDate() - 1);
|
|
18748
18791
|
return d.toISOString().slice(0, 10);
|
|
18749
18792
|
}
|
|
18750
18793
|
async function fetchLatestKbDriftReport(execFileP5, repoRoot) {
|
|
18751
|
-
const sagaIo = (0,
|
|
18794
|
+
const sagaIo = (0, import_node_path21.join)(repoRoot, "infra", "saga-io.mjs");
|
|
18752
18795
|
if (!(0, import_node_fs23.existsSync)(sagaIo)) return null;
|
|
18753
18796
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18754
18797
|
for (const date of [today, yesterdayIso()]) {
|
|
@@ -18766,7 +18809,7 @@ async function fetchLatestKbDriftReport(execFileP5, repoRoot) {
|
|
|
18766
18809
|
|
|
18767
18810
|
// src/cli-doctor-shared.ts
|
|
18768
18811
|
var import_node_fs24 = require("node:fs");
|
|
18769
|
-
var
|
|
18812
|
+
var import_node_path22 = require("node:path");
|
|
18770
18813
|
var import_node_fs25 = require("node:fs");
|
|
18771
18814
|
var GC_GH_TIMEOUT_MS = 2e4;
|
|
18772
18815
|
async function awsCallerArn() {
|
|
@@ -18813,7 +18856,7 @@ async function localBranchHeads() {
|
|
|
18813
18856
|
}
|
|
18814
18857
|
async function currentRepoWorktreeGitRoot(repoRoot) {
|
|
18815
18858
|
const gitCommonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
18816
|
-
return gitCommonDir ? (0,
|
|
18859
|
+
return gitCommonDir ? (0, import_node_path22.resolve)(repoRoot, gitCommonDir, "worktrees") : "";
|
|
18817
18860
|
}
|
|
18818
18861
|
async function worktreeBranches() {
|
|
18819
18862
|
const { stdout } = await execFileP2("git", ["worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS });
|
|
@@ -18833,7 +18876,7 @@ function resolveGitdirForWorktreeFile(worktreePath, content) {
|
|
|
18833
18876
|
const match = /^gitdir:\s*(.+)\s*$/im.exec(content);
|
|
18834
18877
|
if (!match?.[1]) return void 0;
|
|
18835
18878
|
const raw = match[1].trim();
|
|
18836
|
-
return (0,
|
|
18879
|
+
return (0, import_node_path22.isAbsolute)(raw) ? raw : (0, import_node_path22.resolve)(worktreePath, raw);
|
|
18837
18880
|
}
|
|
18838
18881
|
function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
18839
18882
|
if (!worktreeGitRoot) return false;
|
|
@@ -18842,9 +18885,9 @@ function metadataOwnsMissingWorktreeDir(worktreePath, worktreeGitRoot) {
|
|
|
18842
18885
|
for (const ent of entries) {
|
|
18843
18886
|
if (!ent.isDirectory()) continue;
|
|
18844
18887
|
try {
|
|
18845
|
-
const gitdirPath = (0, import_node_fs24.readFileSync)((0,
|
|
18846
|
-
const resolvedGitdir = (0,
|
|
18847
|
-
if (sameWorktreeMetadataPath((0,
|
|
18888
|
+
const gitdirPath = (0, import_node_fs24.readFileSync)((0, import_node_path22.join)(worktreeGitRoot, ent.name, "gitdir"), "utf8").trim();
|
|
18889
|
+
const resolvedGitdir = (0, import_node_path22.isAbsolute)(gitdirPath) ? gitdirPath : (0, import_node_path22.resolve)(worktreeGitRoot, ent.name, gitdirPath);
|
|
18890
|
+
if (sameWorktreeMetadataPath((0, import_node_path22.dirname)(resolvedGitdir), worktreePath)) return true;
|
|
18848
18891
|
} catch {
|
|
18849
18892
|
}
|
|
18850
18893
|
}
|
|
@@ -18863,7 +18906,7 @@ function pathExistsKnown(path2) {
|
|
|
18863
18906
|
}
|
|
18864
18907
|
}
|
|
18865
18908
|
function inspectSiblingWorktreeDir(path2, worktreeGitRoot) {
|
|
18866
|
-
const gitPath = (0,
|
|
18909
|
+
const gitPath = (0, import_node_path22.join)(path2, ".git");
|
|
18867
18910
|
let st;
|
|
18868
18911
|
try {
|
|
18869
18912
|
st = (0, import_node_fs25.lstatSync)(gitPath);
|
|
@@ -18920,7 +18963,7 @@ async function siblingWorktreeDirs() {
|
|
|
18920
18963
|
const siblingRoot = siblingMmiWorktreesRoot(repoRoot);
|
|
18921
18964
|
try {
|
|
18922
18965
|
const entries = (0, import_node_fs25.readdirSync)(siblingRoot, { withFileTypes: true });
|
|
18923
|
-
return entries.filter((ent) => ent.isDirectory()).map((ent) => inspectSiblingWorktreeDir((0,
|
|
18966
|
+
return entries.filter((ent) => ent.isDirectory()).map((ent) => inspectSiblingWorktreeDir((0, import_node_path22.join)(siblingRoot, ent.name), worktreeGitRoot)).filter((entry) => Boolean(entry));
|
|
18924
18967
|
} catch {
|
|
18925
18968
|
return [];
|
|
18926
18969
|
}
|
|
@@ -18970,7 +19013,7 @@ async function fetchHubVersionInfo(baseUrl) {
|
|
|
18970
19013
|
}
|
|
18971
19014
|
function readRepoVersion() {
|
|
18972
19015
|
try {
|
|
18973
|
-
return JSON.parse((0, import_node_fs26.readFileSync)((0,
|
|
19016
|
+
return JSON.parse((0, import_node_fs26.readFileSync)((0, import_node_path23.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
18974
19017
|
} catch {
|
|
18975
19018
|
return void 0;
|
|
18976
19019
|
}
|
|
@@ -18988,24 +19031,24 @@ var NPM_VIEW_TIMEOUT_MS = 15e3;
|
|
|
18988
19031
|
var PLUGIN_PULL_TIMEOUT_MS = 3e4;
|
|
18989
19032
|
async function applyVersionAutoUpdate(report, log) {
|
|
18990
19033
|
const action = versionAutoUpdateAction(report, Boolean(process.env.CLAUDE_PLUGIN_ROOT));
|
|
18991
|
-
if (action === "none") return report;
|
|
19034
|
+
if (action === "none") return { report, applied: "none" };
|
|
18992
19035
|
const target = report.releasedVersion ?? "latest";
|
|
18993
19036
|
if (action === "plugin-pull") {
|
|
18994
19037
|
try {
|
|
18995
19038
|
const root = (await execFileP2("git", ["-C", process.env.CLAUDE_PLUGIN_ROOT, "rev-parse", "--show-toplevel"], { timeout: PLUGIN_PULL_TIMEOUT_MS })).stdout.trim();
|
|
18996
19039
|
log(` \u21BB refreshing MMI plugin ${report.currentVersion} \u2192 ${target} (effective next session)\u2026`);
|
|
18997
19040
|
await execFileP2("git", ["-C", root, "pull", "--ff-only"], { timeout: PLUGIN_PULL_TIMEOUT_MS });
|
|
18998
|
-
return { ...report, ok: true };
|
|
19041
|
+
return { report: { ...report, ok: true }, applied: "plugin-pull" };
|
|
18999
19042
|
} catch {
|
|
19000
|
-
return report;
|
|
19043
|
+
return { report, applied: "none" };
|
|
19001
19044
|
}
|
|
19002
19045
|
}
|
|
19003
19046
|
try {
|
|
19004
19047
|
log(` \u21BB updating mmi-cli ${report.currentVersion} \u2192 ${target}\u2026`);
|
|
19005
19048
|
await runHostBin("npm", ["install", "-g", "@mutmutco/cli@latest"], { timeout: NPM_UPDATE_TIMEOUT_MS });
|
|
19006
|
-
return { ...report, ok: true };
|
|
19049
|
+
return { report: { ...report, ok: true }, applied: "npm" };
|
|
19007
19050
|
} catch {
|
|
19008
|
-
return report;
|
|
19051
|
+
return { report, applied: "none" };
|
|
19009
19052
|
}
|
|
19010
19053
|
}
|
|
19011
19054
|
async function fetchNpmReleasedVersion() {
|
|
@@ -19033,7 +19076,11 @@ async function applyDesignSystemUpdate(check, log) {
|
|
|
19033
19076
|
if (check.latestVersion && installedVersion && compareVersions(installedVersion, check.latestVersion) >= 0) {
|
|
19034
19077
|
return { ...check, ok: true, installedVersion };
|
|
19035
19078
|
}
|
|
19036
|
-
return {
|
|
19079
|
+
return {
|
|
19080
|
+
...check,
|
|
19081
|
+
installedVersion,
|
|
19082
|
+
fix: `${check.packageName} is held below ${check.latestVersion ?? "latest"} by this repo's package.json range \u2014 \`npm update\` cannot cross it. Bump the range or run \`npm install ${check.packageName}@latest\` to force the update.`
|
|
19083
|
+
};
|
|
19037
19084
|
} catch {
|
|
19038
19085
|
return check;
|
|
19039
19086
|
}
|
|
@@ -19067,6 +19114,9 @@ var CLAUDE_PLUGIN_TIMEOUT_MS = 12e4;
|
|
|
19067
19114
|
function runHostBin(bin, args, opts) {
|
|
19068
19115
|
return isWin ? execFileP2("cmd.exe", ["/c", bin, ...args], opts) : execFileP2(bin, args, opts);
|
|
19069
19116
|
}
|
|
19117
|
+
function hostBinAvailable(bin) {
|
|
19118
|
+
return execFileP2(isWin ? "where" : "which", [bin]).then(() => true).catch(() => false);
|
|
19119
|
+
}
|
|
19070
19120
|
async function runClaudePlugin(args) {
|
|
19071
19121
|
try {
|
|
19072
19122
|
await runHostBin("claude", args, { timeout: CLAUDE_PLUGIN_TIMEOUT_MS });
|
|
@@ -19099,7 +19149,7 @@ async function applyPluginHeal(token, surface, log, opts) {
|
|
|
19099
19149
|
}
|
|
19100
19150
|
var installedPluginsPath = (surface = detectSurface(process.env)) => {
|
|
19101
19151
|
const homeDir = surface === "codex" ? ".codex" : ".claude";
|
|
19102
|
-
return (0,
|
|
19152
|
+
return (0, import_node_path23.join)((0, import_node_os5.homedir)(), homeDir, "plugins", "installed_plugins.json");
|
|
19103
19153
|
};
|
|
19104
19154
|
function readInstalledPlugins() {
|
|
19105
19155
|
try {
|
|
@@ -19110,7 +19160,7 @@ function readInstalledPlugins() {
|
|
|
19110
19160
|
}
|
|
19111
19161
|
function installedPluginSources() {
|
|
19112
19162
|
return ["claude", "codex"].map((surface) => {
|
|
19113
|
-
const recordPath = (0,
|
|
19163
|
+
const recordPath = (0, import_node_path23.join)((0, import_node_os5.homedir)(), `.${surface}`, "plugins", "installed_plugins.json");
|
|
19114
19164
|
try {
|
|
19115
19165
|
return { surface, installed: JSON.parse((0, import_node_fs26.readFileSync)(recordPath, "utf8")), recordPath };
|
|
19116
19166
|
} catch {
|
|
@@ -19120,7 +19170,7 @@ function installedPluginSources() {
|
|
|
19120
19170
|
}
|
|
19121
19171
|
function readClaudeSettings() {
|
|
19122
19172
|
try {
|
|
19123
|
-
return JSON.parse((0, import_node_fs26.readFileSync)((0,
|
|
19173
|
+
return JSON.parse((0, import_node_fs26.readFileSync)((0, import_node_path23.join)(process.cwd(), ".claude", "settings.json"), "utf8"));
|
|
19124
19174
|
} catch {
|
|
19125
19175
|
return null;
|
|
19126
19176
|
}
|
|
@@ -19165,16 +19215,16 @@ function backupAndWriteInstalledPlugins(records, pluginId) {
|
|
|
19165
19215
|
}
|
|
19166
19216
|
}
|
|
19167
19217
|
function opencodeConfigDir() {
|
|
19168
|
-
return (0,
|
|
19218
|
+
return (0, import_node_path23.join)((0, import_node_os5.homedir)(), ".config", "opencode");
|
|
19169
19219
|
}
|
|
19170
19220
|
function opencodeConfigPath() {
|
|
19171
|
-
return (0,
|
|
19221
|
+
return (0, import_node_path23.join)(opencodeConfigDir(), "opencode.jsonc");
|
|
19172
19222
|
}
|
|
19173
19223
|
function opencodeCommandsDir() {
|
|
19174
|
-
return (0,
|
|
19224
|
+
return (0, import_node_path23.join)(opencodeConfigDir(), "commands");
|
|
19175
19225
|
}
|
|
19176
19226
|
function opencodeSkillsPath() {
|
|
19177
|
-
return (0,
|
|
19227
|
+
return (0, import_node_path23.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "skills");
|
|
19178
19228
|
}
|
|
19179
19229
|
function opencodeConfigSnapshot() {
|
|
19180
19230
|
const path2 = opencodeConfigPath();
|
|
@@ -19203,7 +19253,7 @@ function writeOpencodeConfigPlugin(snapshot) {
|
|
|
19203
19253
|
const plan2 = planOpencodeConfigWrite(snapshot.hasConfig ? snapshot.raw : void 0);
|
|
19204
19254
|
if (plan2.action === "already") return true;
|
|
19205
19255
|
if (!plan2.text || plan2.action === "unsafe") return false;
|
|
19206
|
-
(0, import_node_fs26.mkdirSync)((0,
|
|
19256
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path23.dirname)(path2), { recursive: true });
|
|
19207
19257
|
if (snapshot.hasConfig) (0, import_node_fs26.copyFileSync)(path2, `${path2}.bak`);
|
|
19208
19258
|
(0, import_node_fs26.writeFileSync)(path2, plan2.text, "utf8");
|
|
19209
19259
|
return true;
|
|
@@ -19220,7 +19270,7 @@ function writeOpencodeSkillsPath(snapshot, skillsPath) {
|
|
|
19220
19270
|
const normalized = skillsPath.replace(/\\/g, "/");
|
|
19221
19271
|
if (!paths.some((p) => p.replace(/\\/g, "/") === normalized)) paths.push(skillsPath.replace(/\\/g, "/"));
|
|
19222
19272
|
parsed.skills = { ...skills, paths };
|
|
19223
|
-
(0, import_node_fs26.mkdirSync)((0,
|
|
19273
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path23.dirname)(snapshot.path), { recursive: true });
|
|
19224
19274
|
if (snapshot.hasConfig && (0, import_node_fs26.existsSync)(snapshot.path)) (0, import_node_fs26.copyFileSync)(snapshot.path, `${snapshot.path}.bak`);
|
|
19225
19275
|
(0, import_node_fs26.writeFileSync)(snapshot.path, `${JSON.stringify(parsed, null, 2)}
|
|
19226
19276
|
`, "utf8");
|
|
@@ -19241,7 +19291,7 @@ function writeOpencodeCommandFiles() {
|
|
|
19241
19291
|
const dir = opencodeCommandsDir();
|
|
19242
19292
|
(0, import_node_fs26.mkdirSync)(dir, { recursive: true });
|
|
19243
19293
|
for (const command of OPENCODE_WORKFLOW_COMMANDS) {
|
|
19244
|
-
(0, import_node_fs26.writeFileSync)((0,
|
|
19294
|
+
(0, import_node_fs26.writeFileSync)((0, import_node_path23.join)(dir, `${command}.md`), opencodeCommandMarkdown(command), "utf8");
|
|
19245
19295
|
}
|
|
19246
19296
|
return true;
|
|
19247
19297
|
} catch {
|
|
@@ -19250,8 +19300,8 @@ function writeOpencodeCommandFiles() {
|
|
|
19250
19300
|
}
|
|
19251
19301
|
function readOpencodeAdapterDiskVersion() {
|
|
19252
19302
|
const candidates = [
|
|
19253
|
-
(0,
|
|
19254
|
-
(0,
|
|
19303
|
+
(0, import_node_path23.join)(opencodeConfigDir(), "node_modules", "@mutmutco", "opencode-mmi", "package.json"),
|
|
19304
|
+
(0, import_node_path23.join)((0, import_node_os5.homedir)(), ".cache", "opencode", "node_modules", "@mutmutco", "opencode-mmi", "package.json")
|
|
19255
19305
|
];
|
|
19256
19306
|
for (const path2 of candidates) {
|
|
19257
19307
|
try {
|
|
@@ -19286,21 +19336,21 @@ function opencodePluginVersionsForReport() {
|
|
|
19286
19336
|
}
|
|
19287
19337
|
function opencodeDesktopLogsRoot() {
|
|
19288
19338
|
if (process.platform === "win32") {
|
|
19289
|
-
const base = process.env.APPDATA || (0,
|
|
19290
|
-
return (0,
|
|
19339
|
+
const base = process.env.APPDATA || (0, import_node_path23.join)((0, import_node_os5.homedir)(), "AppData", "Roaming");
|
|
19340
|
+
return (0, import_node_path23.join)(base, "ai.opencode.desktop", "logs");
|
|
19291
19341
|
}
|
|
19292
19342
|
if (process.platform === "darwin") {
|
|
19293
|
-
return (0,
|
|
19343
|
+
return (0, import_node_path23.join)((0, import_node_os5.homedir)(), "Library", "Application Support", "ai.opencode.desktop", "logs");
|
|
19294
19344
|
}
|
|
19295
|
-
return (0,
|
|
19345
|
+
return (0, import_node_path23.join)((0, import_node_os5.homedir)(), ".config", "ai.opencode.desktop", "logs");
|
|
19296
19346
|
}
|
|
19297
19347
|
function opencodeDesktopBootstrapSnapshot() {
|
|
19298
19348
|
const root = opencodeDesktopLogsRoot();
|
|
19299
19349
|
try {
|
|
19300
|
-
const sessionDirs = (0, import_node_fs26.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => (0,
|
|
19350
|
+
const sessionDirs = (0, import_node_fs26.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => (0, import_node_path23.join)(root, entry.name)).sort((a, b) => (0, import_node_fs26.statSync)(b).mtimeMs - (0, import_node_fs26.statSync)(a).mtimeMs);
|
|
19301
19351
|
const newest = sessionDirs[0];
|
|
19302
19352
|
if (!newest) return [];
|
|
19303
|
-
const logPath = (0,
|
|
19353
|
+
const logPath = (0, import_node_path23.join)(newest, "renderer.log");
|
|
19304
19354
|
const text = (0, import_node_fs26.readFileSync)(logPath, "utf8");
|
|
19305
19355
|
return opencodeAgentDirectoriesFromLog(text).filter((directory) => !(0, import_node_fs26.existsSync)(directory)).map((directory) => ({ directory, logPath }));
|
|
19306
19356
|
} catch {
|
|
@@ -19308,7 +19358,7 @@ function opencodeDesktopBootstrapSnapshot() {
|
|
|
19308
19358
|
}
|
|
19309
19359
|
}
|
|
19310
19360
|
function opencodeLegacyConfigSnapshot() {
|
|
19311
|
-
const legacyPath = (0,
|
|
19361
|
+
const legacyPath = (0, import_node_path23.join)((0, import_node_os5.homedir)(), ".opencode", "opencode.json");
|
|
19312
19362
|
if (!(0, import_node_fs26.existsSync)(legacyPath)) return {};
|
|
19313
19363
|
const content = readTextFile(legacyPath);
|
|
19314
19364
|
if (content == null) return {};
|
|
@@ -19329,16 +19379,16 @@ function quarantineOpencodeLegacyConfig(legacyPath) {
|
|
|
19329
19379
|
}
|
|
19330
19380
|
}
|
|
19331
19381
|
function cursorPluginCacheRoot() {
|
|
19332
|
-
return (0,
|
|
19382
|
+
return (0, import_node_path23.join)((0, import_node_os5.homedir)(), ".cursor", "plugins", "cache", "mutmutco", "mmi");
|
|
19333
19383
|
}
|
|
19334
19384
|
function cursorPluginCachePinSnapshots() {
|
|
19335
19385
|
const root = cursorPluginCacheRoot();
|
|
19336
19386
|
try {
|
|
19337
19387
|
return (0, import_node_fs26.readdirSync)(root, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => {
|
|
19338
|
-
const path2 = (0,
|
|
19339
|
-
const pluginJson = (0,
|
|
19340
|
-
const hooksJson = (0,
|
|
19341
|
-
const cliBundle = (0,
|
|
19388
|
+
const path2 = (0, import_node_path23.join)(root, entry.name);
|
|
19389
|
+
const pluginJson = (0, import_node_path23.join)(path2, ".cursor-plugin", "plugin.json");
|
|
19390
|
+
const hooksJson = (0, import_node_path23.join)(path2, "hooks", "hooks.json");
|
|
19391
|
+
const cliBundle = (0, import_node_path23.join)(path2, "cli", "dist", "index.cjs");
|
|
19342
19392
|
let version;
|
|
19343
19393
|
try {
|
|
19344
19394
|
const raw = JSON.parse((0, import_node_fs26.readFileSync)(pluginJson, "utf8"));
|
|
@@ -19367,19 +19417,19 @@ function cursorPluginCachePinSnapshots() {
|
|
|
19367
19417
|
}
|
|
19368
19418
|
}
|
|
19369
19419
|
function hubCheckoutForCursorSeed() {
|
|
19370
|
-
const manifest = (0,
|
|
19420
|
+
const manifest = (0, import_node_path23.join)(process.cwd(), "plugins", "mmi", ".cursor-plugin", "plugin.json");
|
|
19371
19421
|
return (0, import_node_fs26.existsSync)(manifest) ? process.cwd() : void 0;
|
|
19372
19422
|
}
|
|
19373
19423
|
function mmiPluginCacheRootSnapshots() {
|
|
19374
19424
|
const roots = [
|
|
19375
|
-
{ surface: "claude", root: (0,
|
|
19376
|
-
{ surface: "codex", root: (0,
|
|
19425
|
+
{ surface: "claude", root: (0, import_node_path23.join)((0, import_node_os5.homedir)(), ".claude", "plugins", "cache", "mutmutco", "mmi") },
|
|
19426
|
+
{ surface: "codex", root: (0, import_node_path23.join)((0, import_node_os5.homedir)(), ".codex", "plugins", "cache", "mutmutco", "mmi") }
|
|
19377
19427
|
];
|
|
19378
19428
|
return roots.flatMap(({ surface, root }) => {
|
|
19379
19429
|
try {
|
|
19380
19430
|
const entries = (0, import_node_fs26.readdirSync)(root, { withFileTypes: true }).map((entry) => ({
|
|
19381
19431
|
name: entry.name,
|
|
19382
|
-
path: (0,
|
|
19432
|
+
path: (0, import_node_path23.join)(root, entry.name),
|
|
19383
19433
|
isDirectory: entry.isDirectory()
|
|
19384
19434
|
}));
|
|
19385
19435
|
return [{ surface, root, entries }];
|
|
@@ -19390,7 +19440,7 @@ function mmiPluginCacheRootSnapshots() {
|
|
|
19390
19440
|
}
|
|
19391
19441
|
function hasNestedMmiChild(versionDir) {
|
|
19392
19442
|
try {
|
|
19393
|
-
return (0, import_node_fs26.statSync)((0,
|
|
19443
|
+
return (0, import_node_fs26.statSync)((0, import_node_path23.join)(versionDir, "mmi")).isDirectory();
|
|
19394
19444
|
} catch {
|
|
19395
19445
|
return false;
|
|
19396
19446
|
}
|
|
@@ -19415,7 +19465,7 @@ function quarantinePluginCacheDirs(plan2) {
|
|
|
19415
19465
|
try {
|
|
19416
19466
|
if (!(0, import_node_fs26.existsSync)(move.from)) continue;
|
|
19417
19467
|
const target = uniqueQuarantineTarget(move.to);
|
|
19418
|
-
(0, import_node_fs26.mkdirSync)((0,
|
|
19468
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path23.dirname)(target), { recursive: true });
|
|
19419
19469
|
(0, import_node_fs26.renameSync)(move.from, target);
|
|
19420
19470
|
moved += 1;
|
|
19421
19471
|
} catch {
|
|
@@ -19437,7 +19487,7 @@ async function clearNestedPluginTreeDir(targetPath) {
|
|
|
19437
19487
|
try {
|
|
19438
19488
|
if (!(0, import_node_fs26.existsSync)(targetPath)) return true;
|
|
19439
19489
|
if (isWin) {
|
|
19440
|
-
const emptyDir = (0,
|
|
19490
|
+
const emptyDir = (0, import_node_path23.join)((0, import_node_os5.tmpdir)(), `mmi-empty-${Date.now()}`);
|
|
19441
19491
|
(0, import_node_fs26.mkdirSync)(emptyDir, { recursive: true });
|
|
19442
19492
|
try {
|
|
19443
19493
|
await robocopyMirrorEmpty(emptyDir, targetPath);
|
|
@@ -19464,7 +19514,7 @@ async function applyNestedPluginTreeCleanup(paths, log) {
|
|
|
19464
19514
|
}
|
|
19465
19515
|
return true;
|
|
19466
19516
|
}
|
|
19467
|
-
var gitignorePath = () => (0,
|
|
19517
|
+
var gitignorePath = () => (0, import_node_path23.join)(process.cwd(), ".gitignore");
|
|
19468
19518
|
function readTextFile(path2) {
|
|
19469
19519
|
try {
|
|
19470
19520
|
if (!(0, import_node_fs26.existsSync)(path2)) return null;
|
|
@@ -19477,10 +19527,10 @@ function playwrightMcpConfigSnapshots() {
|
|
|
19477
19527
|
const cwd = process.cwd();
|
|
19478
19528
|
const home = (0, import_node_os5.homedir)();
|
|
19479
19529
|
const candidates = [
|
|
19480
|
-
(0,
|
|
19481
|
-
(0,
|
|
19482
|
-
(0,
|
|
19483
|
-
(0,
|
|
19530
|
+
(0, import_node_path23.join)(cwd, ".mcp.json"),
|
|
19531
|
+
(0, import_node_path23.join)(cwd, ".cursor", "mcp.json"),
|
|
19532
|
+
(0, import_node_path23.join)(home, ".cursor", "mcp.json"),
|
|
19533
|
+
(0, import_node_path23.join)(home, ".codex", "config.toml")
|
|
19484
19534
|
];
|
|
19485
19535
|
const out = [];
|
|
19486
19536
|
for (const path2 of candidates) {
|
|
@@ -19493,7 +19543,7 @@ function strayBrowserArtifactPaths() {
|
|
|
19493
19543
|
const cwd = process.cwd();
|
|
19494
19544
|
return STRAY_BROWSER_ARTIFACT_DIRS.filter((rel) => {
|
|
19495
19545
|
try {
|
|
19496
|
-
return (0, import_node_fs26.existsSync)((0,
|
|
19546
|
+
return (0, import_node_fs26.existsSync)((0, import_node_path23.join)(cwd, rel));
|
|
19497
19547
|
} catch {
|
|
19498
19548
|
return false;
|
|
19499
19549
|
}
|
|
@@ -19512,8 +19562,8 @@ function latestIso(values) {
|
|
|
19512
19562
|
return best;
|
|
19513
19563
|
}
|
|
19514
19564
|
function latestNorthstarContinuityAt() {
|
|
19515
|
-
const meta = parseMeta(readTextFile((0,
|
|
19516
|
-
const queue = parseQueue(readTextFile((0,
|
|
19565
|
+
const meta = parseMeta(readTextFile((0, import_node_path23.join)(process.cwd(), META_FILE)));
|
|
19566
|
+
const queue = parseQueue(readTextFile((0, import_node_path23.join)(process.cwd(), QUEUE_FILE)));
|
|
19517
19567
|
return latestIso([
|
|
19518
19568
|
...Object.values(meta).map((entry) => entry.syncedAt),
|
|
19519
19569
|
...queue.map((entry) => entry.queuedAt)
|
|
@@ -19570,6 +19620,10 @@ async function runDoctor(opts, io = consoleIo) {
|
|
|
19570
19620
|
});
|
|
19571
19621
|
const installedForHealPlan = readInstalledPlugins();
|
|
19572
19622
|
const sourcesForHealPlan = installedPluginSources();
|
|
19623
|
+
const semverPrefix = /^\d+\.\d+\.\d+/;
|
|
19624
|
+
const isBehind = (installed2, released) => Boolean(installed2 && released && semverPrefix.test(installed2) && semverPrefix.test(released) && compareVersions(installed2, released) < 0);
|
|
19625
|
+
const opencodeAdapterStale = isBehind(opencodeInstalledVersionForDoctor(), releasedVersion);
|
|
19626
|
+
const cursorCacheStale = (0, import_node_fs26.existsSync)(cursorPluginCacheRoot()) && (cursorPluginCachePinSnapshots() ?? []).some((p) => isBehind(p.version, releasedVersion));
|
|
19573
19627
|
const healPlan = doctorHealPlan({
|
|
19574
19628
|
isOrgRepo: Boolean(cfg.sagaApiUrl),
|
|
19575
19629
|
surface,
|
|
@@ -19584,7 +19638,9 @@ async function runDoctor(opts, io = consoleIo) {
|
|
|
19584
19638
|
legacyPluginCheck: buildLegacyPluginInstallCheck({
|
|
19585
19639
|
isOrgRepo: Boolean(cfg.sagaApiUrl),
|
|
19586
19640
|
sources: sourcesForHealPlan
|
|
19587
|
-
})
|
|
19641
|
+
}),
|
|
19642
|
+
opencodeAdapterStale,
|
|
19643
|
+
cursorCacheStale
|
|
19588
19644
|
});
|
|
19589
19645
|
if (opts.preflight && !healPlan.needsEagerHeal) return;
|
|
19590
19646
|
const eagerHeal = Boolean(opts.preflight) || Boolean(opts.banner) && healPlan.needsEagerHeal;
|
|
@@ -19615,9 +19671,19 @@ async function runDoctor(opts, io = consoleIo) {
|
|
|
19615
19671
|
repoVersion: readRepoVersion(),
|
|
19616
19672
|
releasedVersion
|
|
19617
19673
|
});
|
|
19618
|
-
|
|
19674
|
+
let selfUpdatedCli = false;
|
|
19675
|
+
if (repairFull) {
|
|
19676
|
+
const updated = await applyVersionAutoUpdate(versionReport, (m) => io.err(m));
|
|
19677
|
+
versionReport = updated.report;
|
|
19678
|
+
selfUpdatedCli = updated.applied === "npm";
|
|
19679
|
+
}
|
|
19619
19680
|
if (!versionReport.ok) versionReport = { ...versionReport, fix: pluginRecoveryFix(surface) };
|
|
19620
19681
|
checks.push(versionReport);
|
|
19682
|
+
if (selfUpdatedCli) {
|
|
19683
|
+
if (opts.json) io.log(JSON.stringify(buildSelfUpdateHaltPayload({ checks, updatedTo: versionReport.releasedVersion }), null, 2));
|
|
19684
|
+
else io.err(selfUpdateHaltLine(versionReport));
|
|
19685
|
+
return;
|
|
19686
|
+
}
|
|
19621
19687
|
checks.push({ ok: Boolean(cfg.sagaApiUrl), label: "Hub API URL configured", fix: "set MMI_HUB_URL or use a current MMI CLI/plugin build" });
|
|
19622
19688
|
const hubVersionInfo = await fetchHubVersionInfo(cfg.sagaApiUrl);
|
|
19623
19689
|
const installedVersion = resolveClientVersion();
|
|
@@ -19732,14 +19798,12 @@ async function runDoctor(opts, io = consoleIo) {
|
|
|
19732
19798
|
surface
|
|
19733
19799
|
});
|
|
19734
19800
|
if (!installedVersionCheck.ok && (repairFull || repairLocal)) {
|
|
19801
|
+
const crossSurfaceRepair = Boolean(opts.apply) || !opts.json && !opts.banner && !opts.preflight;
|
|
19802
|
+
const canDriveSurface = async (token) => surfaceToken(surface) === token || crossSurfaceRepair && await hostBinAvailable(token);
|
|
19803
|
+
const rereadInstalled = () => buildInstalledPluginVersionCheck({ isOrgRepo: Boolean(cfg.sagaApiUrl), sources: installedPluginSources(), releasedVersion, surface });
|
|
19735
19804
|
const claudeStale = installedVersionCheck.staleSurfaces?.some((s) => s.surface === "claude") ?? false;
|
|
19736
|
-
if (claudeStale && await applyPluginHeal("claude", surface, (m) => io.err(m))) {
|
|
19737
|
-
const healed =
|
|
19738
|
-
isOrgRepo: Boolean(cfg.sagaApiUrl),
|
|
19739
|
-
sources: installedPluginSources(),
|
|
19740
|
-
releasedVersion,
|
|
19741
|
-
surface
|
|
19742
|
-
});
|
|
19805
|
+
if (claudeStale && await canDriveSurface("claude") && await applyPluginHeal("claude", surface, (m) => io.err(m), { force: true })) {
|
|
19806
|
+
const healed = rereadInstalled();
|
|
19743
19807
|
installedVersionCheck = healed;
|
|
19744
19808
|
if (healed.ok) {
|
|
19745
19809
|
markPluginReloadRequired();
|
|
@@ -19747,13 +19811,8 @@ async function runDoctor(opts, io = consoleIo) {
|
|
|
19747
19811
|
}
|
|
19748
19812
|
}
|
|
19749
19813
|
const codexStale = installedVersionCheck.staleSurfaces?.some((s) => s.surface === "codex") ?? false;
|
|
19750
|
-
if (!installedVersionCheck.ok && codexStale && await applyPluginHeal("codex", surface, (m) => io.err(m))) {
|
|
19751
|
-
const healed =
|
|
19752
|
-
isOrgRepo: Boolean(cfg.sagaApiUrl),
|
|
19753
|
-
sources: installedPluginSources(),
|
|
19754
|
-
releasedVersion,
|
|
19755
|
-
surface
|
|
19756
|
-
});
|
|
19814
|
+
if (!installedVersionCheck.ok && codexStale && await canDriveSurface("codex") && await applyPluginHeal("codex", surface, (m) => io.err(m), { force: true })) {
|
|
19815
|
+
const healed = rereadInstalled();
|
|
19757
19816
|
installedVersionCheck = healed;
|
|
19758
19817
|
if (healed.ok) {
|
|
19759
19818
|
markPluginReloadRequired();
|
|
@@ -19937,7 +19996,7 @@ async function runDoctor(opts, io = consoleIo) {
|
|
|
19937
19996
|
releasedVersion,
|
|
19938
19997
|
hubCheckout: hubCheckoutForCursorSeed(),
|
|
19939
19998
|
execFileP: execFileP2,
|
|
19940
|
-
mkdtemp: (prefix) => (0, import_promises7.mkdtemp)((0,
|
|
19999
|
+
mkdtemp: (prefix) => (0, import_promises7.mkdtemp)((0, import_node_path23.join)((0, import_node_os5.tmpdir)(), prefix)),
|
|
19941
20000
|
log: (m) => io.err(m)
|
|
19942
20001
|
});
|
|
19943
20002
|
if (seeded) {
|
|
@@ -20075,7 +20134,8 @@ async function runDoctor(opts, io = consoleIo) {
|
|
|
20075
20134
|
}
|
|
20076
20135
|
const gaps = checks.filter((c) => !c.ok);
|
|
20077
20136
|
if (opts.preflight) {
|
|
20078
|
-
|
|
20137
|
+
const outcome = preflightOutcome({ gaps, needsEagerHeal: healPlan.needsEagerHeal, surface });
|
|
20138
|
+
if (outcome.line) io.err(outcome.line);
|
|
20079
20139
|
if (pluginReloadRequired) io.err(pluginAutonomousHaltLine(reloadHint));
|
|
20080
20140
|
return;
|
|
20081
20141
|
}
|
|
@@ -20327,7 +20387,7 @@ rules.command("sync").option("--quiet", "stay silent unless something changed or
|
|
|
20327
20387
|
if (!await runRulesSync(opts)) process.exitCode = 1;
|
|
20328
20388
|
});
|
|
20329
20389
|
rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
|
|
20330
|
-
const path2 = (0,
|
|
20390
|
+
const path2 = (0, import_node_path24.join)(process.cwd(), ".gitignore");
|
|
20331
20391
|
const current = (0, import_node_fs27.existsSync)(path2) ? (0, import_node_fs27.readFileSync)(path2, "utf8") : null;
|
|
20332
20392
|
const plan2 = planManagedGitignore(current);
|
|
20333
20393
|
const drift = [...plan2.added.map((l) => `+${l}`), ...plan2.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
@@ -20534,7 +20594,7 @@ function runWorktreeInstall(command, cwd, quiet) {
|
|
|
20534
20594
|
async function primaryCheckoutRoot(worktreeRoot) {
|
|
20535
20595
|
try {
|
|
20536
20596
|
const out = (await execFileP2("git", ["-C", worktreeRoot, "rev-parse", "--path-format=absolute", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim();
|
|
20537
|
-
return out ? (0,
|
|
20597
|
+
return out ? (0, import_node_path24.dirname)(out) : void 0;
|
|
20538
20598
|
} catch {
|
|
20539
20599
|
return void 0;
|
|
20540
20600
|
}
|
|
@@ -20547,7 +20607,7 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
20547
20607
|
};
|
|
20548
20608
|
}
|
|
20549
20609
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
20550
|
-
const lockPath = (0,
|
|
20610
|
+
const lockPath = (0, import_node_path24.join)(worktreeRoot, ".mmi", "worktree-setup.lock");
|
|
20551
20611
|
const take = () => {
|
|
20552
20612
|
const fd = (0, import_node_fs27.openSync)(lockPath, "wx");
|
|
20553
20613
|
try {
|
|
@@ -20563,7 +20623,7 @@ function acquireWorktreeSetupLock(worktreeRoot) {
|
|
|
20563
20623
|
};
|
|
20564
20624
|
};
|
|
20565
20625
|
try {
|
|
20566
|
-
(0, import_node_fs27.mkdirSync)((0,
|
|
20626
|
+
(0, import_node_fs27.mkdirSync)((0, import_node_path24.dirname)(lockPath), { recursive: true });
|
|
20567
20627
|
return take();
|
|
20568
20628
|
} catch {
|
|
20569
20629
|
try {
|
|
@@ -21569,7 +21629,7 @@ pr.command("create").description("create a PR and print {number,url} JSON").opti
|
|
|
21569
21629
|
console.log(JSON.stringify(created));
|
|
21570
21630
|
});
|
|
21571
21631
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
21572
|
-
const wfDir = (0,
|
|
21632
|
+
const wfDir = (0, import_node_path24.join)(cwd, ".github", "workflows");
|
|
21573
21633
|
if (!(0, import_node_fs27.existsSync)(wfDir)) return [];
|
|
21574
21634
|
return (0, import_node_fs27.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).map((name) => `.github/workflows/${name}`);
|
|
21575
21635
|
}
|
|
@@ -21743,7 +21803,7 @@ async function createDeferredWorktreeStore() {
|
|
|
21743
21803
|
},
|
|
21744
21804
|
write: async (entries) => {
|
|
21745
21805
|
try {
|
|
21746
|
-
await (0, import_promises8.mkdir)((0,
|
|
21806
|
+
await (0, import_promises8.mkdir)((0, import_node_path24.dirname)(registryPath), { recursive: true });
|
|
21747
21807
|
await (0, import_promises8.writeFile)(registryPath, serializeDeferredWorktrees(entries), "utf8");
|
|
21748
21808
|
} catch {
|
|
21749
21809
|
}
|
|
@@ -22101,8 +22161,8 @@ async function resolveStage() {
|
|
|
22101
22161
|
local,
|
|
22102
22162
|
shell: shellFor(),
|
|
22103
22163
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
22104
|
-
hasCompose: (0, import_node_fs27.existsSync)((0,
|
|
22105
|
-
hasEnvExample: (0, import_node_fs27.existsSync)((0,
|
|
22164
|
+
hasCompose: (0, import_node_fs27.existsSync)((0, import_node_path24.join)(process.cwd(), "docker-compose.yml")),
|
|
22165
|
+
hasEnvExample: (0, import_node_fs27.existsSync)((0, import_node_path24.join)(process.cwd(), ".env.example"))
|
|
22106
22166
|
});
|
|
22107
22167
|
}
|
|
22108
22168
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -22957,6 +23017,7 @@ program2.command("session-start").description("run the SessionStart verbs (rules
|
|
|
22957
23017
|
console.error("[mmi-hook] session-start: cwd is a repository SUBDIRECTORY \u2014 skipping the SessionStart hook (spine/docs/plan/saga delivery); run it from the repo root.");
|
|
22958
23018
|
return;
|
|
22959
23019
|
}
|
|
23020
|
+
if (!isOrgRepoRoot(process.cwd())) return;
|
|
22960
23021
|
try {
|
|
22961
23022
|
const hook = parseHookInput(await readStdin());
|
|
22962
23023
|
if (hook.session_id) persistSession(hook.session_id);
|