@mutmutco/cli 3.41.0 → 3.42.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 +369 -136
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -3410,8 +3410,8 @@ var program = new Command();
|
|
|
3410
3410
|
|
|
3411
3411
|
// src/index.ts
|
|
3412
3412
|
var import_promises7 = require("node:fs/promises");
|
|
3413
|
-
var
|
|
3414
|
-
var
|
|
3413
|
+
var import_node_fs29 = require("node:fs");
|
|
3414
|
+
var import_node_child_process13 = require("node:child_process");
|
|
3415
3415
|
|
|
3416
3416
|
// src/cli-shared.ts
|
|
3417
3417
|
var import_node_child_process3 = require("node:child_process");
|
|
@@ -8949,7 +8949,7 @@ function commandLadderHint() {
|
|
|
8949
8949
|
}
|
|
8950
8950
|
|
|
8951
8951
|
// src/index.ts
|
|
8952
|
-
var
|
|
8952
|
+
var import_node_path26 = require("node:path");
|
|
8953
8953
|
|
|
8954
8954
|
// src/merge-ci-policy.ts
|
|
8955
8955
|
function resolveMergeCiPolicy(input) {
|
|
@@ -15375,6 +15375,213 @@ function createDocsIndexDeps(repoRoot2) {
|
|
|
15375
15375
|
};
|
|
15376
15376
|
}
|
|
15377
15377
|
|
|
15378
|
+
// src/doc-refs-core.ts
|
|
15379
|
+
var import_node_child_process9 = require("node:child_process");
|
|
15380
|
+
var import_node_fs18 = require("node:fs");
|
|
15381
|
+
var import_node_path16 = require("node:path");
|
|
15382
|
+
var PIN_RE = /<!--\s*pinned by\s+([^:]+?)\s*:\s*"([^"]+)"[^"]*-->/;
|
|
15383
|
+
var PIN_MENTION_RE = /<!--\s*pinned by\b/;
|
|
15384
|
+
var REF_RE = /`([A-Za-z0-9_./-]+\.[A-Za-z0-9]+)(?::\d+)?`/g;
|
|
15385
|
+
var LINK_RE = /\]\(([^)#\s]+?\.md)(?:#[^)]*)?\)/g;
|
|
15386
|
+
var CMD_RE = /`mmi-cli ((?:[a-z][a-z-]*)(?: [a-z][a-z-]*){0,3})/g;
|
|
15387
|
+
var RETIRED_RE = /\b(retired|historical|removed|deleted|gone|no longer|superseded|legacy)\b/i;
|
|
15388
|
+
var ROOT_DOCS = ["README.md", "architecture.md"];
|
|
15389
|
+
var SKIP_WALK = ["docs/Archive/", "docs/incidents/"];
|
|
15390
|
+
var PINNED_DOCS = ["docs/Reference/runtime-contracts.md"];
|
|
15391
|
+
function stripFences(markdown) {
|
|
15392
|
+
let inFence = false;
|
|
15393
|
+
return markdown.split(/\r?\n/).map((line) => {
|
|
15394
|
+
if (/^\s*```/.test(line)) {
|
|
15395
|
+
inFence = !inFence;
|
|
15396
|
+
return "";
|
|
15397
|
+
}
|
|
15398
|
+
return inFence ? "" : line;
|
|
15399
|
+
});
|
|
15400
|
+
}
|
|
15401
|
+
function isRetiredLine(text) {
|
|
15402
|
+
return RETIRED_RE.test(text);
|
|
15403
|
+
}
|
|
15404
|
+
function extractPins(markdown) {
|
|
15405
|
+
const pins = [];
|
|
15406
|
+
markdown.split(/\r?\n/).forEach((text, index) => {
|
|
15407
|
+
const match = PIN_RE.exec(text);
|
|
15408
|
+
if (match) {
|
|
15409
|
+
pins.push({ file: match[1].trim(), phrase: match[2], line: index + 1 });
|
|
15410
|
+
} else if (PIN_MENTION_RE.test(text.replace(/`[^`]*`/g, ""))) {
|
|
15411
|
+
pins.push({ malformed: true, line: index + 1, text: text.trim() });
|
|
15412
|
+
}
|
|
15413
|
+
});
|
|
15414
|
+
return pins;
|
|
15415
|
+
}
|
|
15416
|
+
function checkPins(root, readFile6) {
|
|
15417
|
+
const findings = [];
|
|
15418
|
+
for (const doc of PINNED_DOCS) {
|
|
15419
|
+
const markdown = readFile6((0, import_node_path16.join)(root, doc));
|
|
15420
|
+
if (markdown == null) {
|
|
15421
|
+
findings.push({ kind: "missing-doc", doc, line: 0, detail: doc });
|
|
15422
|
+
continue;
|
|
15423
|
+
}
|
|
15424
|
+
for (const pin of extractPins(markdown)) {
|
|
15425
|
+
if ("malformed" in pin) {
|
|
15426
|
+
findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
|
|
15427
|
+
continue;
|
|
15428
|
+
}
|
|
15429
|
+
const source = readFile6((0, import_node_path16.join)(root, pin.file));
|
|
15430
|
+
if (source == null) {
|
|
15431
|
+
findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
|
|
15432
|
+
continue;
|
|
15433
|
+
}
|
|
15434
|
+
if (!source.includes(pin.phrase)) {
|
|
15435
|
+
findings.push({ kind: "unasserted-phrase", doc, line: pin.line, detail: pin.phrase });
|
|
15436
|
+
}
|
|
15437
|
+
}
|
|
15438
|
+
}
|
|
15439
|
+
return { ok: findings.length === 0, findings };
|
|
15440
|
+
}
|
|
15441
|
+
function isDomainLike(ref) {
|
|
15442
|
+
const first = ref.split("/")[0];
|
|
15443
|
+
return first.includes(".") && !first.startsWith(".");
|
|
15444
|
+
}
|
|
15445
|
+
function extractRefs(markdown) {
|
|
15446
|
+
const lines = stripFences(markdown);
|
|
15447
|
+
const refs = [];
|
|
15448
|
+
lines.forEach((text, index) => {
|
|
15449
|
+
if (isRetiredLine(text)) return;
|
|
15450
|
+
for (const match of text.matchAll(REF_RE)) {
|
|
15451
|
+
const ref = match[1];
|
|
15452
|
+
if (!ref.includes("/")) continue;
|
|
15453
|
+
if (ref.startsWith("/") || ref.startsWith(".git/")) continue;
|
|
15454
|
+
if (isDomainLike(ref)) continue;
|
|
15455
|
+
refs.push({ ref, line: index + 1 });
|
|
15456
|
+
}
|
|
15457
|
+
});
|
|
15458
|
+
return refs;
|
|
15459
|
+
}
|
|
15460
|
+
function extractLinks(markdown) {
|
|
15461
|
+
const lines = stripFences(markdown);
|
|
15462
|
+
const links = [];
|
|
15463
|
+
lines.forEach((text, index) => {
|
|
15464
|
+
if (isRetiredLine(text)) return;
|
|
15465
|
+
for (const match of text.matchAll(LINK_RE)) {
|
|
15466
|
+
const target = match[1];
|
|
15467
|
+
if (/^[a-z]+:/i.test(target)) continue;
|
|
15468
|
+
links.push({ target, line: index + 1 });
|
|
15469
|
+
}
|
|
15470
|
+
});
|
|
15471
|
+
return links;
|
|
15472
|
+
}
|
|
15473
|
+
function extractCommands(markdown) {
|
|
15474
|
+
const lines = stripFences(markdown);
|
|
15475
|
+
const commands = [];
|
|
15476
|
+
lines.forEach((text, index) => {
|
|
15477
|
+
if (isRetiredLine(text)) return;
|
|
15478
|
+
for (const match of text.matchAll(CMD_RE)) {
|
|
15479
|
+
commands.push({ command: match[1], line: index + 1 });
|
|
15480
|
+
}
|
|
15481
|
+
});
|
|
15482
|
+
return commands;
|
|
15483
|
+
}
|
|
15484
|
+
function checkRefs(root, deps, docs2) {
|
|
15485
|
+
const { exists, isIgnored = () => /* @__PURE__ */ new Set() } = deps;
|
|
15486
|
+
const candidates = [];
|
|
15487
|
+
for (const [doc, markdown] of Object.entries(docs2)) {
|
|
15488
|
+
for (const { ref, line } of extractRefs(markdown)) {
|
|
15489
|
+
const first = ref.split("/")[0];
|
|
15490
|
+
if (!exists((0, import_node_path16.join)(root, first))) continue;
|
|
15491
|
+
if (!exists((0, import_node_path16.join)(root, ref))) candidates.push({ kind: "missing-path", doc, line, detail: ref });
|
|
15492
|
+
}
|
|
15493
|
+
const docDir = import_node_path16.posix.dirname(doc);
|
|
15494
|
+
for (const { target, line } of extractLinks(markdown)) {
|
|
15495
|
+
const resolved = import_node_path16.posix.normalize(import_node_path16.posix.join(docDir === "." ? "" : docDir, target));
|
|
15496
|
+
if (!exists((0, import_node_path16.join)(root, resolved))) {
|
|
15497
|
+
candidates.push({ kind: "missing-link", doc, line, detail: target, resolved });
|
|
15498
|
+
}
|
|
15499
|
+
}
|
|
15500
|
+
}
|
|
15501
|
+
const ignored = candidates.length ? isIgnored(candidates.map((c) => c.kind === "missing-link" ? c.resolved : c.detail)) : /* @__PURE__ */ new Set();
|
|
15502
|
+
const findings = candidates.filter((c) => !ignored.has(c.kind === "missing-link" ? c.resolved : c.detail)).map(({ resolved, ...finding }) => finding);
|
|
15503
|
+
return { ok: findings.length === 0, findings };
|
|
15504
|
+
}
|
|
15505
|
+
function checkCommands(docs2, commandPaths) {
|
|
15506
|
+
const findings = [];
|
|
15507
|
+
const prefixesSome = (prefix) => {
|
|
15508
|
+
for (const path2 of commandPaths) {
|
|
15509
|
+
if (path2 === prefix || path2.startsWith(`${prefix} `)) return true;
|
|
15510
|
+
}
|
|
15511
|
+
return false;
|
|
15512
|
+
};
|
|
15513
|
+
for (const [doc, markdown] of Object.entries(docs2)) {
|
|
15514
|
+
for (const { command, line } of extractCommands(markdown)) {
|
|
15515
|
+
const tokens2 = command.split(" ");
|
|
15516
|
+
for (let i = 1; i <= tokens2.length; i += 1) {
|
|
15517
|
+
const prefix = tokens2.slice(0, i).join(" ");
|
|
15518
|
+
if (prefixesSome(prefix)) continue;
|
|
15519
|
+
const parent = tokens2.slice(0, i - 1).join(" ");
|
|
15520
|
+
if (i > 1 && commandPaths.has(parent)) break;
|
|
15521
|
+
findings.push({ kind: "unknown-command", doc, line, detail: `mmi-cli ${prefix}` });
|
|
15522
|
+
break;
|
|
15523
|
+
}
|
|
15524
|
+
}
|
|
15525
|
+
}
|
|
15526
|
+
return { ok: findings.length === 0, findings };
|
|
15527
|
+
}
|
|
15528
|
+
function readFileOrNull(path2) {
|
|
15529
|
+
return (0, import_node_fs18.existsSync)(path2) ? (0, import_node_fs18.readFileSync)(path2, "utf8") : null;
|
|
15530
|
+
}
|
|
15531
|
+
function walk(dir, root, out) {
|
|
15532
|
+
for (const entry of (0, import_node_fs18.readdirSync)(dir)) {
|
|
15533
|
+
const full = (0, import_node_path16.join)(dir, entry);
|
|
15534
|
+
if ((0, import_node_fs18.statSync)(full).isDirectory()) walk(full, root, out);
|
|
15535
|
+
else if (entry.endsWith(".md")) out.push(full.slice(root.length + 1).replaceAll("\\", "/"));
|
|
15536
|
+
}
|
|
15537
|
+
return out;
|
|
15538
|
+
}
|
|
15539
|
+
function defaultListDocs(root) {
|
|
15540
|
+
const docsDir = (0, import_node_path16.join)(root, "docs");
|
|
15541
|
+
const docs2 = ((0, import_node_fs18.existsSync)(docsDir) ? walk(docsDir, root, []) : []).filter(
|
|
15542
|
+
(rel) => !SKIP_WALK.some((skip) => rel.startsWith(skip))
|
|
15543
|
+
);
|
|
15544
|
+
return [...ROOT_DOCS.filter((rel) => (0, import_node_fs18.existsSync)((0, import_node_path16.join)(root, rel))), ...docs2];
|
|
15545
|
+
}
|
|
15546
|
+
function defaultIsIgnored(root, relPaths, exec = import_node_child_process9.execFileSync) {
|
|
15547
|
+
try {
|
|
15548
|
+
const out = exec("git", ["check-ignore", "--stdin"], {
|
|
15549
|
+
cwd: root,
|
|
15550
|
+
input: relPaths.join("\n"),
|
|
15551
|
+
encoding: "utf8"
|
|
15552
|
+
});
|
|
15553
|
+
return new Set(out.split(/\r?\n/).filter(Boolean));
|
|
15554
|
+
} catch (error) {
|
|
15555
|
+
if (error?.status === 1) return /* @__PURE__ */ new Set();
|
|
15556
|
+
throw error;
|
|
15557
|
+
}
|
|
15558
|
+
}
|
|
15559
|
+
function runDocRefs(root, deps = {}) {
|
|
15560
|
+
const readFile6 = deps.readFile ?? readFileOrNull;
|
|
15561
|
+
const exists = deps.exists ?? import_node_fs18.existsSync;
|
|
15562
|
+
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
15563
|
+
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
15564
|
+
const commandPaths = deps.commandPaths ?? null;
|
|
15565
|
+
const docs2 = Object.fromEntries(
|
|
15566
|
+
listDocs(root).map((rel) => [rel, readFile6((0, import_node_path16.join)(root, rel))]).filter(([, body]) => body != null)
|
|
15567
|
+
);
|
|
15568
|
+
const findings = [
|
|
15569
|
+
...checkPins(root, readFile6).findings,
|
|
15570
|
+
...checkRefs(root, { exists, isIgnored }, docs2).findings
|
|
15571
|
+
];
|
|
15572
|
+
if (commandPaths == null) {
|
|
15573
|
+
findings.push({
|
|
15574
|
+
kind: "command-manifest-unavailable",
|
|
15575
|
+
doc: "cli command manifest",
|
|
15576
|
+
line: 0,
|
|
15577
|
+
detail: "the CLI could not enumerate its own commands \u2014 command refs cannot be verified"
|
|
15578
|
+
});
|
|
15579
|
+
} else {
|
|
15580
|
+
findings.push(...checkCommands(docs2, commandPaths).findings);
|
|
15581
|
+
}
|
|
15582
|
+
return { ok: findings.length === 0, findings, docCount: Object.keys(docs2).length };
|
|
15583
|
+
}
|
|
15584
|
+
|
|
15378
15585
|
// src/docs-audit-command.ts
|
|
15379
15586
|
function serializeOutcome(outcome) {
|
|
15380
15587
|
switch (outcome.kind) {
|
|
@@ -16298,8 +16505,8 @@ function writeError(res) {
|
|
|
16298
16505
|
}
|
|
16299
16506
|
|
|
16300
16507
|
// src/secrets-commands.ts
|
|
16301
|
-
var
|
|
16302
|
-
var
|
|
16508
|
+
var import_node_fs19 = require("node:fs");
|
|
16509
|
+
var import_node_path17 = require("node:path");
|
|
16303
16510
|
var import_node_os5 = require("node:os");
|
|
16304
16511
|
|
|
16305
16512
|
// src/project-runtime.ts
|
|
@@ -16423,18 +16630,18 @@ function collectMap(value, previous = []) {
|
|
|
16423
16630
|
return [...previous, value];
|
|
16424
16631
|
}
|
|
16425
16632
|
async function decryptRailsCredentials(input) {
|
|
16426
|
-
const appDir = (0,
|
|
16633
|
+
const appDir = (0, import_node_path17.resolve)(input.appDir ?? process.cwd());
|
|
16427
16634
|
const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
|
|
16428
16635
|
const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
|
|
16429
|
-
const credentialsPath = (0,
|
|
16430
|
-
const masterKeyPath = (0,
|
|
16636
|
+
const credentialsPath = (0, import_node_path17.resolve)(appDir, credentialsFile);
|
|
16637
|
+
const masterKeyPath = (0, import_node_path17.resolve)(appDir, masterKeyFile);
|
|
16431
16638
|
const env = {
|
|
16432
16639
|
...process.env,
|
|
16433
16640
|
MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
|
|
16434
16641
|
MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
|
|
16435
16642
|
};
|
|
16436
|
-
if ((0,
|
|
16437
|
-
env.RAILS_MASTER_KEY = (0,
|
|
16643
|
+
if ((0, import_node_fs19.existsSync)(masterKeyPath)) {
|
|
16644
|
+
env.RAILS_MASTER_KEY = (0, import_node_fs19.readFileSync)(masterKeyPath, "utf8").trim();
|
|
16438
16645
|
}
|
|
16439
16646
|
const script = [
|
|
16440
16647
|
'require "json"',
|
|
@@ -16444,9 +16651,9 @@ async function decryptRailsCredentials(input) {
|
|
|
16444
16651
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
16445
16652
|
"puts JSON.generate(config.config)"
|
|
16446
16653
|
].join("\n");
|
|
16447
|
-
const scriptDir = (0,
|
|
16448
|
-
const scriptPath = (0,
|
|
16449
|
-
(0,
|
|
16654
|
+
const scriptDir = (0, import_node_fs19.mkdtempSync)((0, import_node_path17.join)((0, import_node_os5.tmpdir)(), "mmi-rails-decrypt-"));
|
|
16655
|
+
const scriptPath = (0, import_node_path17.join)(scriptDir, "decrypt.rb");
|
|
16656
|
+
(0, import_node_fs19.writeFileSync)(scriptPath, script, "utf8");
|
|
16450
16657
|
try {
|
|
16451
16658
|
const args = ["exec", "ruby", scriptPath];
|
|
16452
16659
|
const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
|
|
@@ -16458,7 +16665,7 @@ async function decryptRailsCredentials(input) {
|
|
|
16458
16665
|
});
|
|
16459
16666
|
return JSON.parse(stdout);
|
|
16460
16667
|
} finally {
|
|
16461
|
-
(0,
|
|
16668
|
+
(0, import_node_fs19.rmSync)(scriptDir, { recursive: true, force: true });
|
|
16462
16669
|
}
|
|
16463
16670
|
}
|
|
16464
16671
|
async function readSecretStdin() {
|
|
@@ -16548,7 +16755,7 @@ function registerSecretsCommands(program3) {
|
|
|
16548
16755
|
let body;
|
|
16549
16756
|
if (o.file) {
|
|
16550
16757
|
try {
|
|
16551
|
-
body = (0,
|
|
16758
|
+
body = (0, import_node_fs19.readFileSync)((0, import_node_path17.resolve)(o.file), "utf8");
|
|
16552
16759
|
} catch (e) {
|
|
16553
16760
|
return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
|
|
16554
16761
|
}
|
|
@@ -16653,7 +16860,7 @@ function registerSecretsCommands(program3) {
|
|
|
16653
16860
|
{
|
|
16654
16861
|
...d,
|
|
16655
16862
|
decryptRailsCredentials,
|
|
16656
|
-
removeFile: (path2) => (0,
|
|
16863
|
+
removeFile: (path2) => (0, import_node_fs19.unlinkSync)((0, import_node_path17.resolve)(o.appDir ?? process.cwd(), path2))
|
|
16657
16864
|
},
|
|
16658
16865
|
{
|
|
16659
16866
|
repo: o.repo,
|
|
@@ -17028,7 +17235,7 @@ function registerBoxCommands(program3) {
|
|
|
17028
17235
|
|
|
17029
17236
|
// src/schedules-commands.ts
|
|
17030
17237
|
var import_promises2 = require("node:fs/promises");
|
|
17031
|
-
var
|
|
17238
|
+
var import_node_child_process10 = require("node:child_process");
|
|
17032
17239
|
var import_node_util7 = require("node:util");
|
|
17033
17240
|
|
|
17034
17241
|
// src/schedules.ts
|
|
@@ -17334,7 +17541,7 @@ function assembleReconciliation(githubEntries2, readRepos, registry2, activeWork
|
|
|
17334
17541
|
}
|
|
17335
17542
|
|
|
17336
17543
|
// src/schedules-commands.ts
|
|
17337
|
-
var execFileP5 = (0, import_node_util7.promisify)(
|
|
17544
|
+
var execFileP5 = (0, import_node_util7.promisify)(import_node_child_process10.execFile);
|
|
17338
17545
|
var AWS_REGION = "eu-central-1";
|
|
17339
17546
|
var AWS_TIMEOUT_MS = 3e4;
|
|
17340
17547
|
var AWS_RETRY_DELAY_MS = 1500;
|
|
@@ -17570,14 +17777,14 @@ function registerSchedulesCommands(program3) {
|
|
|
17570
17777
|
|
|
17571
17778
|
// src/schedules-lift-command.ts
|
|
17572
17779
|
var import_promises3 = require("node:fs/promises");
|
|
17573
|
-
var
|
|
17780
|
+
var import_node_path18 = require("node:path");
|
|
17574
17781
|
|
|
17575
17782
|
// src/schedules-lift.ts
|
|
17576
17783
|
var SCHEDULE_HEADER_FIELDS = ["schedule", "what", "owner", "cadence", "executor", "llm", "output", "breaks", "kill"];
|
|
17577
17784
|
function parseScheduleHeader(yamlText) {
|
|
17578
17785
|
const out = {};
|
|
17579
17786
|
for (const rawLine of yamlText.split("\n")) {
|
|
17580
|
-
const m = /^#\s*(schedule|what|owner|cadence|executor|llm|output|breaks|kill|target):\s*(.+?)\s*$/.exec(rawLine);
|
|
17787
|
+
const m = /^#\s*(schedule|what|owner|cadence|executor|llm|output|breaks|kill|target|model):\s*(.+?)\s*$/.exec(rawLine);
|
|
17581
17788
|
if (m && out[m[1]] === void 0) out[m[1]] = m[2].trim();
|
|
17582
17789
|
}
|
|
17583
17790
|
return out;
|
|
@@ -17614,6 +17821,10 @@ function scheduleRecordFromWorkflow(repo, workflowPath, yamlText) {
|
|
|
17614
17821
|
if (target !== void 0 && !/^mmi-fleet-[A-Za-z0-9_-]{1,130}$/.test(target)) {
|
|
17615
17822
|
throw new Error(`schedules lift: ${expectedId} header \`target: ${target}\` must be a bare lambda function name in the reserved fleet namespace \`mmi-fleet-*\` (allowed after the prefix: A-Z a-z 0-9 _ -; total max 140). The dispatcher can only invoke mmi-fleet-* functions.`);
|
|
17616
17823
|
}
|
|
17824
|
+
const model = header.model;
|
|
17825
|
+
if (model !== void 0 && !/^[a-z][a-z0-9-]{0,30}$/.test(model)) {
|
|
17826
|
+
throw new Error(`schedules lift: ${expectedId} header \`model: ${model}\` must be a model ROLE KEY (lowercase kebab, max 31 chars \u2014 e.g. janitor, arbiter), never a model id \u2014 ids resolve from the vault at dispatch.`);
|
|
17827
|
+
}
|
|
17617
17828
|
return {
|
|
17618
17829
|
id: expectedId,
|
|
17619
17830
|
what: h.what,
|
|
@@ -17626,7 +17837,8 @@ function scheduleRecordFromWorkflow(repo, workflowPath, yamlText) {
|
|
|
17626
17837
|
kill: h.kill,
|
|
17627
17838
|
repo,
|
|
17628
17839
|
sourcePath: workflowPath,
|
|
17629
|
-
...target !== void 0 ? { target } : {}
|
|
17840
|
+
...target !== void 0 ? { target } : {},
|
|
17841
|
+
...model !== void 0 ? { model } : {}
|
|
17630
17842
|
};
|
|
17631
17843
|
}
|
|
17632
17844
|
function scheduleRecordsFromWorkflows(repo, files) {
|
|
@@ -17671,7 +17883,7 @@ async function readWorkflowFiles(dir) {
|
|
|
17671
17883
|
const files = [];
|
|
17672
17884
|
for (const name of names.sort()) {
|
|
17673
17885
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
17674
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises3.readFile)((0,
|
|
17886
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises3.readFile)((0, import_node_path18.join)(dir, name), "utf8") });
|
|
17675
17887
|
}
|
|
17676
17888
|
return files;
|
|
17677
17889
|
}
|
|
@@ -18211,7 +18423,7 @@ function registerQueryCommands(program3) {
|
|
|
18211
18423
|
}
|
|
18212
18424
|
|
|
18213
18425
|
// src/bootstrap-commands.ts
|
|
18214
|
-
var
|
|
18426
|
+
var import_node_fs20 = require("node:fs");
|
|
18215
18427
|
|
|
18216
18428
|
// src/bootstrap-verify.ts
|
|
18217
18429
|
var TRAIN_BRANCHES2 = ["development", "rc", "main"];
|
|
@@ -18759,7 +18971,7 @@ function registerBootstrapCommands(program3) {
|
|
|
18759
18971
|
client: defaultGitHubClient(),
|
|
18760
18972
|
projectMeta: meta,
|
|
18761
18973
|
deployModel: typeof meta?.deployModel === "string" ? meta.deployModel : void 0,
|
|
18762
|
-
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0,
|
|
18974
|
+
readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs20.existsSync)(path2) ? (0, import_node_fs20.readFileSync)(path2, "utf8") : null,
|
|
18763
18975
|
// requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
|
|
18764
18976
|
// comma-string — accept either so the seeded value verifies regardless of how it was written.
|
|
18765
18977
|
requiredGcpApis: (() => {
|
|
@@ -18810,12 +19022,12 @@ function registerBootstrapCommands(program3) {
|
|
|
18810
19022
|
return fail(`bootstrap apply: ${e.message}`);
|
|
18811
19023
|
}
|
|
18812
19024
|
const manifestPath = "skills/bootstrap/seeds/manifest.json";
|
|
18813
|
-
if (!(0,
|
|
18814
|
-
const manifest = loadBootstrapSeeds((0,
|
|
19025
|
+
if (!(0, import_node_fs20.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`);
|
|
19026
|
+
const manifest = loadBootstrapSeeds((0, import_node_fs20.readFileSync)(manifestPath, "utf8"));
|
|
18815
19027
|
const baseBranch = o.class === "content" ? "main" : "development";
|
|
18816
19028
|
const slug = parsedRepo.slug;
|
|
18817
19029
|
const gh = async (args) => execFileP2("gh", args, { timeout: 2e4 });
|
|
18818
|
-
const readFile6 = (p) => (0,
|
|
19030
|
+
const readFile6 = (p) => (0, import_node_fs20.existsSync)(p) ? (0, import_node_fs20.readFileSync)(p, "utf8") : null;
|
|
18819
19031
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
18820
19032
|
const rawVars = {};
|
|
18821
19033
|
for (const value of cmdOpts.var ?? []) {
|
|
@@ -19011,12 +19223,12 @@ LIVE apply to ${repo}:
|
|
|
19011
19223
|
}
|
|
19012
19224
|
|
|
19013
19225
|
// src/stage-commands.ts
|
|
19014
|
-
var
|
|
19015
|
-
var
|
|
19226
|
+
var import_node_fs22 = require("node:fs");
|
|
19227
|
+
var import_node_path20 = require("node:path");
|
|
19016
19228
|
|
|
19017
19229
|
// src/port-registry.ts
|
|
19018
|
-
var
|
|
19019
|
-
var
|
|
19230
|
+
var import_node_fs21 = require("node:fs");
|
|
19231
|
+
var import_node_path19 = require("node:path");
|
|
19020
19232
|
|
|
19021
19233
|
// ../infra/port-geometry.mjs
|
|
19022
19234
|
var PORT_BLOCK = 100;
|
|
@@ -19030,8 +19242,8 @@ function nextPortBlock(registry2) {
|
|
|
19030
19242
|
return [base, base + PORT_SPAN];
|
|
19031
19243
|
}
|
|
19032
19244
|
function loadPortRegistry(path2) {
|
|
19033
|
-
if (!(0,
|
|
19034
|
-
const raw = JSON.parse((0,
|
|
19245
|
+
if (!(0, import_node_fs21.existsSync)(path2)) return {};
|
|
19246
|
+
const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
|
|
19035
19247
|
const out = {};
|
|
19036
19248
|
for (const [key, value] of Object.entries(raw)) {
|
|
19037
19249
|
if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
|
|
@@ -19045,9 +19257,9 @@ function ensurePortRange(repo, path2) {
|
|
|
19045
19257
|
const existing = registry2[repo];
|
|
19046
19258
|
if (existing) return existing;
|
|
19047
19259
|
const range = nextPortBlock(registry2);
|
|
19048
|
-
const raw = (0,
|
|
19260
|
+
const raw = (0, import_node_fs21.existsSync)(path2) ? JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8")) : {};
|
|
19049
19261
|
raw[repo] = range;
|
|
19050
|
-
(0,
|
|
19262
|
+
(0, import_node_fs21.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
|
|
19051
19263
|
return range;
|
|
19052
19264
|
}
|
|
19053
19265
|
function portCursorSeed(registry2) {
|
|
@@ -19069,22 +19281,22 @@ function existingPortRange(repo, registry2) {
|
|
|
19069
19281
|
return registry2[repo] ?? null;
|
|
19070
19282
|
}
|
|
19071
19283
|
function portRangeInfraAt(root, source) {
|
|
19072
|
-
const registryPath = (0,
|
|
19073
|
-
const ddbScriptPath = (0,
|
|
19074
|
-
if (!(0,
|
|
19284
|
+
const registryPath = (0, import_node_path19.join)(root, "infra", "port-ranges.json");
|
|
19285
|
+
const ddbScriptPath = (0, import_node_path19.join)(root, "infra", "port-ddb.mjs");
|
|
19286
|
+
if (!(0, import_node_fs21.existsSync)(registryPath) || !(0, import_node_fs21.existsSync)(ddbScriptPath)) return null;
|
|
19075
19287
|
return { root, source, registryPath, ddbScriptPath };
|
|
19076
19288
|
}
|
|
19077
19289
|
function resolvePortRangeInfra(cwd, packageDir) {
|
|
19078
19290
|
const direct = portRangeInfraAt(cwd, "cwd");
|
|
19079
19291
|
if (direct) return direct;
|
|
19080
|
-
for (let dir = cwd; ; dir = (0,
|
|
19081
|
-
const sibling = portRangeInfraAt((0,
|
|
19292
|
+
for (let dir = cwd; ; dir = (0, import_node_path19.dirname)(dir)) {
|
|
19293
|
+
const sibling = portRangeInfraAt((0, import_node_path19.join)(dir, "MMI-Hub"), "sibling-hub");
|
|
19082
19294
|
if (sibling) return sibling;
|
|
19083
|
-
const parent = (0,
|
|
19295
|
+
const parent = (0, import_node_path19.dirname)(dir);
|
|
19084
19296
|
if (parent === dir) break;
|
|
19085
19297
|
}
|
|
19086
19298
|
if (packageDir) {
|
|
19087
|
-
const pkgRoot = (0,
|
|
19299
|
+
const pkgRoot = (0, import_node_path19.join)(packageDir, "..", "..");
|
|
19088
19300
|
const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
|
|
19089
19301
|
if (pkgFrom) return pkgFrom;
|
|
19090
19302
|
}
|
|
@@ -19260,8 +19472,8 @@ function registerStageCommands(program3) {
|
|
|
19260
19472
|
const portRange = portRangeMeta && typeof portRangeMeta.start === "number" && typeof portRangeMeta.end === "number" ? [portRangeMeta.start, portRangeMeta.end] : void 0;
|
|
19261
19473
|
return decideStage({
|
|
19262
19474
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
19263
|
-
hasCompose: (0,
|
|
19264
|
-
hasEnvExample: (0,
|
|
19475
|
+
hasCompose: (0, import_node_fs22.existsSync)((0, import_node_path20.join)(process.cwd(), "docker-compose.yml")),
|
|
19476
|
+
hasEnvExample: (0, import_node_fs22.existsSync)((0, import_node_path20.join)(process.cwd(), ".env.example"))
|
|
19265
19477
|
});
|
|
19266
19478
|
}
|
|
19267
19479
|
async function fetchStageVaultEnvMerge() {
|
|
@@ -19696,9 +19908,9 @@ function registerBoardCommands(program3) {
|
|
|
19696
19908
|
}
|
|
19697
19909
|
|
|
19698
19910
|
// src/merge-cleanup.ts
|
|
19699
|
-
var
|
|
19911
|
+
var import_node_fs23 = require("node:fs");
|
|
19700
19912
|
var import_promises5 = require("node:fs/promises");
|
|
19701
|
-
var
|
|
19913
|
+
var import_node_child_process11 = require("node:child_process");
|
|
19702
19914
|
|
|
19703
19915
|
// src/board-advance.ts
|
|
19704
19916
|
function repoOf2(ref) {
|
|
@@ -19784,7 +19996,7 @@ function boardAdvanceFailureMessage(result) {
|
|
|
19784
19996
|
|
|
19785
19997
|
// src/deferred-registry-store.ts
|
|
19786
19998
|
var import_promises4 = require("node:fs/promises");
|
|
19787
|
-
var
|
|
19999
|
+
var import_node_path21 = require("node:path");
|
|
19788
20000
|
var sleep = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
19789
20001
|
async function atomicWrite(target, contents) {
|
|
19790
20002
|
const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
@@ -19888,12 +20100,12 @@ function makeDeferredWorktreeStore(registryPath, lockOpts = {}) {
|
|
|
19888
20100
|
},
|
|
19889
20101
|
// Standalone atomic write — THROWS on failure (no best-effort swallow, #2846).
|
|
19890
20102
|
write: async (entries) => {
|
|
19891
|
-
await (0, import_promises4.mkdir)((0,
|
|
20103
|
+
await (0, import_promises4.mkdir)((0, import_node_path21.dirname)(registryPath), { recursive: true });
|
|
19892
20104
|
await atomicWrite(registryPath, serializeDeferredWorktrees(entries));
|
|
19893
20105
|
},
|
|
19894
20106
|
// Serialized read-modify-write under the repo-wide lock (#2846).
|
|
19895
20107
|
update: async (mutate) => {
|
|
19896
|
-
await (0, import_promises4.mkdir)((0,
|
|
20108
|
+
await (0, import_promises4.mkdir)((0, import_node_path21.dirname)(registryPath), { recursive: true });
|
|
19897
20109
|
const deadline = Date.now() + opts.maxWaitMs;
|
|
19898
20110
|
for (; ; ) {
|
|
19899
20111
|
const guard = await acquireLock(lockPath, opts, deadline);
|
|
@@ -20020,7 +20232,7 @@ async function applyGcPlan(plan, remote) {
|
|
|
20020
20232
|
return cleanupPrMergeLocalBranch(branch.branch, {
|
|
20021
20233
|
beforeWorktrees,
|
|
20022
20234
|
startingPath: branch.worktreePath,
|
|
20023
|
-
pathExists: (p) => (0,
|
|
20235
|
+
pathExists: (p) => (0, import_node_fs23.existsSync)(p),
|
|
20024
20236
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
20025
20237
|
teardownWorktreeStage,
|
|
20026
20238
|
deferredStore,
|
|
@@ -20046,7 +20258,7 @@ async function applyGcPlan(plan, remote) {
|
|
|
20046
20258
|
for (const wt of plan.worktreeDirs) {
|
|
20047
20259
|
try {
|
|
20048
20260
|
const cleanupTarget = resolveSafeSiblingWorktreeCleanupTarget(wt.path, siblingRoot, {
|
|
20049
|
-
realpath: (path2) => (0,
|
|
20261
|
+
realpath: (path2) => (0, import_node_fs23.realpathSync)(path2)
|
|
20050
20262
|
});
|
|
20051
20263
|
if (!cleanupTarget.ok) {
|
|
20052
20264
|
result.failed.push(`${wt.path}: ${cleanupTarget.reason}`);
|
|
@@ -20159,7 +20371,7 @@ async function remoteBranchExists2(branch, options = {}) {
|
|
|
20159
20371
|
}
|
|
20160
20372
|
var COMPOSE_TIMEOUT_MS = 12e4;
|
|
20161
20373
|
function spawnDeferredGcSweep() {
|
|
20162
|
-
spawnDetachedSelf(["worktree", "gc", "sweep-deferred", "--quiet"], { spawn:
|
|
20374
|
+
spawnDetachedSelf(["worktree", "gc", "sweep-deferred", "--quiet"], { spawn: import_node_child_process11.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
|
|
20163
20375
|
}
|
|
20164
20376
|
async function createDeferredWorktreeStore() {
|
|
20165
20377
|
try {
|
|
@@ -20173,13 +20385,13 @@ var realWorktreeDirRemover = {
|
|
|
20173
20385
|
probe: (p) => {
|
|
20174
20386
|
let st;
|
|
20175
20387
|
try {
|
|
20176
|
-
st = (0,
|
|
20388
|
+
st = (0, import_node_fs23.lstatSync)(p);
|
|
20177
20389
|
} catch {
|
|
20178
20390
|
return null;
|
|
20179
20391
|
}
|
|
20180
20392
|
if (st.isSymbolicLink()) return "link";
|
|
20181
20393
|
try {
|
|
20182
|
-
(0,
|
|
20394
|
+
(0, import_node_fs23.readlinkSync)(p);
|
|
20183
20395
|
return "link";
|
|
20184
20396
|
} catch {
|
|
20185
20397
|
}
|
|
@@ -20187,7 +20399,7 @@ var realWorktreeDirRemover = {
|
|
|
20187
20399
|
},
|
|
20188
20400
|
readdir: (p) => {
|
|
20189
20401
|
try {
|
|
20190
|
-
return (0,
|
|
20402
|
+
return (0, import_node_fs23.readdirSync)(p);
|
|
20191
20403
|
} catch {
|
|
20192
20404
|
return [];
|
|
20193
20405
|
}
|
|
@@ -20196,9 +20408,9 @@ var realWorktreeDirRemover = {
|
|
|
20196
20408
|
// leaving the target); a file symlink with unlink. rmdir first, fall back to unlink.
|
|
20197
20409
|
detachLink: (p) => {
|
|
20198
20410
|
try {
|
|
20199
|
-
(0,
|
|
20411
|
+
(0, import_node_fs23.rmdirSync)(p);
|
|
20200
20412
|
} catch {
|
|
20201
|
-
(0,
|
|
20413
|
+
(0, import_node_fs23.unlinkSync)(p);
|
|
20202
20414
|
}
|
|
20203
20415
|
},
|
|
20204
20416
|
removeTree: (p) => (0, import_promises5.rm)(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 })
|
|
@@ -20231,9 +20443,9 @@ async function worktreeHasStageState(worktreePath) {
|
|
|
20231
20443
|
}
|
|
20232
20444
|
}
|
|
20233
20445
|
function stageStateFileBelongsToWorktree(statePath, worktreePath) {
|
|
20234
|
-
if (!(0,
|
|
20446
|
+
if (!(0, import_node_fs23.existsSync)(statePath)) return false;
|
|
20235
20447
|
try {
|
|
20236
|
-
const state = JSON.parse((0,
|
|
20448
|
+
const state = JSON.parse((0, import_node_fs23.readFileSync)(statePath, "utf8"));
|
|
20237
20449
|
const recordedCwd = typeof state.identity?.cwd === "string" ? state.identity.cwd : typeof state.cwd === "string" ? state.cwd : "";
|
|
20238
20450
|
return Boolean(recordedCwd && isPathUnderDirectory(recordedCwd, worktreePath));
|
|
20239
20451
|
} catch {
|
|
@@ -20361,8 +20573,8 @@ async function fetchRestCorePool(gh = defaultGhApi) {
|
|
|
20361
20573
|
}
|
|
20362
20574
|
|
|
20363
20575
|
// src/worktree-lifecycle-commands.ts
|
|
20364
|
-
var
|
|
20365
|
-
var
|
|
20576
|
+
var import_node_fs24 = require("node:fs");
|
|
20577
|
+
var import_node_path22 = require("node:path");
|
|
20366
20578
|
var GH_TIMEOUT_MS = 2e4;
|
|
20367
20579
|
var DEFAULT_BASE = "origin/development";
|
|
20368
20580
|
var DEFAULT_REMOTE = "origin";
|
|
@@ -20499,13 +20711,13 @@ function registerWorktreeCommands(program3) {
|
|
|
20499
20711
|
if (PROTECTED_BRANCHES2.has(branch)) {
|
|
20500
20712
|
return fail(`worktree land: refusing to land protected branch '${branch}'`, { code: ERROR_CODES.ERR_BAD_ENUM });
|
|
20501
20713
|
}
|
|
20502
|
-
const gitFile = (0,
|
|
20503
|
-
const isLinked = (0,
|
|
20714
|
+
const gitFile = (0, import_node_path22.join)(wtPath, ".git");
|
|
20715
|
+
const isLinked = (0, import_node_fs24.existsSync)(gitFile) && (0, import_node_fs24.statSync)(gitFile).isFile();
|
|
20504
20716
|
if (apply && !isLinked) {
|
|
20505
20717
|
return fail("worktree land: run from inside the linked worktree you want to land (this is the primary checkout)");
|
|
20506
20718
|
}
|
|
20507
20719
|
const commonDir = (await execFileP2("git", ["rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS }).catch(() => ({ stdout: "" }))).stdout.trim();
|
|
20508
|
-
const primaryCheckout = commonDir ? (0,
|
|
20720
|
+
const primaryCheckout = commonDir ? (0, import_node_path22.dirname)(commonDir) : wtPath;
|
|
20509
20721
|
const stageSummary = readStageSummary(wtPath);
|
|
20510
20722
|
const hasStage = stageSummary != null;
|
|
20511
20723
|
const steps = landSteps(branch, true, hasStage);
|
|
@@ -20617,10 +20829,10 @@ async function gatherWorktreeContext() {
|
|
|
20617
20829
|
}
|
|
20618
20830
|
const orphanDirs = [];
|
|
20619
20831
|
const wtRoot = siblingMmiWorktreesRoot(repoRoot2);
|
|
20620
|
-
if ((0,
|
|
20832
|
+
if ((0, import_node_fs24.existsSync)(wtRoot)) {
|
|
20621
20833
|
let entries = [];
|
|
20622
20834
|
try {
|
|
20623
|
-
entries = (0,
|
|
20835
|
+
entries = (0, import_node_fs24.readdirSync)(wtRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => (0, import_node_path22.join)(wtRoot, e.name));
|
|
20624
20836
|
} catch {
|
|
20625
20837
|
}
|
|
20626
20838
|
const known = new Set(worktrees.map((w) => w.path));
|
|
@@ -20645,7 +20857,7 @@ async function bestEffortGit(args, cwd, step, timeoutMs = GIT_TIMEOUT_MS) {
|
|
|
20645
20857
|
}
|
|
20646
20858
|
|
|
20647
20859
|
// src/issue-commands.ts
|
|
20648
|
-
var
|
|
20860
|
+
var import_node_fs25 = require("node:fs");
|
|
20649
20861
|
var import_node_crypto5 = require("node:crypto");
|
|
20650
20862
|
var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
|
|
20651
20863
|
async function editIssue(client, options, deps = {}) {
|
|
@@ -20659,7 +20871,7 @@ async function editIssue(client, options, deps = {}) {
|
|
|
20659
20871
|
if (options.body !== void 0 || options.bodyFile !== void 0) {
|
|
20660
20872
|
let body;
|
|
20661
20873
|
if (options.bodyFile) {
|
|
20662
|
-
const td = deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0,
|
|
20874
|
+
const td = deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs25.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
|
|
20663
20875
|
body = await resolveIssueBody({ body: options.body, bodyFile: options.bodyFile }, td);
|
|
20664
20876
|
} else {
|
|
20665
20877
|
body = options.body ?? "";
|
|
@@ -21142,7 +21354,7 @@ function extendCreateCommand(issue2) {
|
|
|
21142
21354
|
if (opts.batch) {
|
|
21143
21355
|
let specs;
|
|
21144
21356
|
try {
|
|
21145
|
-
const raw = (0,
|
|
21357
|
+
const raw = (0, import_node_fs25.readFileSync)(opts.batch, "utf8");
|
|
21146
21358
|
specs = JSON.parse(raw);
|
|
21147
21359
|
if (!Array.isArray(specs)) throw new Error("batch file must contain a JSON array");
|
|
21148
21360
|
} catch (e) {
|
|
@@ -21186,12 +21398,12 @@ ${lines}`);
|
|
|
21186
21398
|
}
|
|
21187
21399
|
|
|
21188
21400
|
// src/train-commands.ts
|
|
21189
|
-
var
|
|
21190
|
-
var
|
|
21401
|
+
var import_node_fs27 = require("node:fs");
|
|
21402
|
+
var import_node_path24 = require("node:path");
|
|
21191
21403
|
|
|
21192
21404
|
// src/plugin-guard-io.ts
|
|
21193
|
-
var
|
|
21194
|
-
var
|
|
21405
|
+
var import_node_fs26 = require("node:fs");
|
|
21406
|
+
var import_node_path23 = require("node:path");
|
|
21195
21407
|
var import_node_os6 = require("node:os");
|
|
21196
21408
|
|
|
21197
21409
|
// src/plugin-guard.ts
|
|
@@ -21321,11 +21533,11 @@ function runHostBin(bin, args, opts) {
|
|
|
21321
21533
|
}
|
|
21322
21534
|
var installedPluginsPath2 = (surface = detectSurface(process.env)) => {
|
|
21323
21535
|
const homeDir = surface === "codex" ? ".codex" : ".claude";
|
|
21324
|
-
return (0,
|
|
21536
|
+
return (0, import_node_path23.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "installed_plugins.json");
|
|
21325
21537
|
};
|
|
21326
21538
|
function readInstalledPlugins(surface = detectSurface(process.env)) {
|
|
21327
21539
|
try {
|
|
21328
|
-
return JSON.parse((0,
|
|
21540
|
+
return JSON.parse((0, import_node_fs26.readFileSync)(installedPluginsPath2(surface), "utf8"));
|
|
21329
21541
|
} catch {
|
|
21330
21542
|
return null;
|
|
21331
21543
|
}
|
|
@@ -21333,13 +21545,13 @@ function readInstalledPlugins(surface = detectSurface(process.env)) {
|
|
|
21333
21545
|
function marketplaceCloneCandidates(surface, home) {
|
|
21334
21546
|
if (surface === "codex") {
|
|
21335
21547
|
return [
|
|
21336
|
-
(0,
|
|
21337
|
-
(0,
|
|
21548
|
+
(0, import_node_path23.join)(home, ".codex", ".tmp", "marketplaces", "mutmutco"),
|
|
21549
|
+
(0, import_node_path23.join)(home, ".codex", "plugins", "marketplaces", "mutmutco")
|
|
21338
21550
|
];
|
|
21339
21551
|
}
|
|
21340
|
-
return [(0,
|
|
21552
|
+
return [(0, import_node_path23.join)(home, ".claude", "plugins", "marketplaces", "mutmutco")];
|
|
21341
21553
|
}
|
|
21342
|
-
function marketplaceClonePresent(surface, home, exists =
|
|
21554
|
+
function marketplaceClonePresent(surface, home, exists = import_node_fs26.existsSync) {
|
|
21343
21555
|
return marketplaceCloneCandidates(surface, home).some(exists);
|
|
21344
21556
|
}
|
|
21345
21557
|
async function fetchNpmReleasedVersion() {
|
|
@@ -21366,7 +21578,7 @@ function snapshotPluginGuardInput(surface = detectSurface(process.env), isOrgRep
|
|
|
21366
21578
|
isOrgRepo,
|
|
21367
21579
|
installRecordPresent: hasUserInstallRecord(installed, MMI_PLUGIN_ID) || hasProjectInstallRecord(installed, MMI_PLUGIN_ID, process.cwd()),
|
|
21368
21580
|
marketplaceClonePresent: marketplaceClonePresent(surface, (0, import_node_os6.homedir)()),
|
|
21369
|
-
pluginCachePresent: (0,
|
|
21581
|
+
pluginCachePresent: (0, import_node_fs26.existsSync)((0, import_node_path23.join)((0, import_node_os6.homedir)(), homeDir, "plugins", "cache", "mutmutco", "mmi"))
|
|
21370
21582
|
};
|
|
21371
21583
|
}
|
|
21372
21584
|
function claudePluginGuardState(isOrgRepo) {
|
|
@@ -21501,7 +21713,7 @@ function formatTrainStatus(r) {
|
|
|
21501
21713
|
// src/train-commands.ts
|
|
21502
21714
|
function readRepoVersion() {
|
|
21503
21715
|
try {
|
|
21504
|
-
return JSON.parse((0,
|
|
21716
|
+
return JSON.parse((0, import_node_fs27.readFileSync)((0, import_node_path24.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
21505
21717
|
} catch {
|
|
21506
21718
|
return void 0;
|
|
21507
21719
|
}
|
|
@@ -22953,17 +23165,17 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
22953
23165
|
}
|
|
22954
23166
|
|
|
22955
23167
|
// src/doctor-io.ts
|
|
22956
|
-
var
|
|
23168
|
+
var import_node_fs28 = require("node:fs");
|
|
22957
23169
|
var import_node_os7 = require("node:os");
|
|
22958
|
-
var
|
|
22959
|
-
var
|
|
23170
|
+
var import_node_path25 = require("node:path");
|
|
23171
|
+
var import_node_child_process12 = require("node:child_process");
|
|
22960
23172
|
var import_node_util8 = require("node:util");
|
|
22961
|
-
var execFileP6 = (0, import_node_util8.promisify)(
|
|
23173
|
+
var execFileP6 = (0, import_node_util8.promisify)(import_node_child_process12.execFile);
|
|
22962
23174
|
var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
22963
23175
|
function installedClaudePluginVersion() {
|
|
22964
23176
|
try {
|
|
22965
23177
|
const file = JSON.parse(
|
|
22966
|
-
(0,
|
|
23178
|
+
(0, import_node_fs28.readFileSync)((0, import_node_path25.join)((0, import_node_os7.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
22967
23179
|
);
|
|
22968
23180
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
22969
23181
|
if (versions.length === 0) return void 0;
|
|
@@ -22974,7 +23186,7 @@ function installedClaudePluginVersion() {
|
|
|
22974
23186
|
}
|
|
22975
23187
|
function worktreeRootSync() {
|
|
22976
23188
|
try {
|
|
22977
|
-
const out = (0,
|
|
23189
|
+
const out = (0, import_node_child_process12.execFileSync)("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
22978
23190
|
let root = out.endsWith("\n") ? out.slice(0, -1) : out;
|
|
22979
23191
|
if (process.platform === "win32" && root.endsWith("\r")) root = root.slice(0, -1);
|
|
22980
23192
|
return root || null;
|
|
@@ -22984,13 +23196,13 @@ function worktreeRootSync() {
|
|
|
22984
23196
|
}
|
|
22985
23197
|
var gitignorePath = () => {
|
|
22986
23198
|
const root = worktreeRootSync();
|
|
22987
|
-
return root === null ? null : (0,
|
|
23199
|
+
return root === null ? null : (0, import_node_path25.join)(root, ".gitignore");
|
|
22988
23200
|
};
|
|
22989
23201
|
function readGitignore() {
|
|
22990
23202
|
const path2 = gitignorePath();
|
|
22991
23203
|
if (path2 === null) return null;
|
|
22992
23204
|
try {
|
|
22993
|
-
return (0,
|
|
23205
|
+
return (0, import_node_fs28.readFileSync)(path2, "utf8");
|
|
22994
23206
|
} catch {
|
|
22995
23207
|
return null;
|
|
22996
23208
|
}
|
|
@@ -22999,7 +23211,7 @@ function writeGitignore(content) {
|
|
|
22999
23211
|
const path2 = gitignorePath();
|
|
23000
23212
|
if (path2 === null) return false;
|
|
23001
23213
|
try {
|
|
23002
|
-
(0,
|
|
23214
|
+
(0, import_node_fs28.writeFileSync)(path2, content, "utf8");
|
|
23003
23215
|
return true;
|
|
23004
23216
|
} catch {
|
|
23005
23217
|
return false;
|
|
@@ -23023,7 +23235,7 @@ async function repoRoot() {
|
|
|
23023
23235
|
}
|
|
23024
23236
|
function hasRepoLocalWorktrees() {
|
|
23025
23237
|
const root = worktreeRootSync();
|
|
23026
|
-
return root !== null && (0,
|
|
23238
|
+
return root !== null && (0, import_node_fs28.existsSync)((0, import_node_path25.join)(root, ".worktrees"));
|
|
23027
23239
|
}
|
|
23028
23240
|
|
|
23029
23241
|
// src/index.ts
|
|
@@ -23141,16 +23353,16 @@ var cachedLongFlags;
|
|
|
23141
23353
|
function allLongFlags() {
|
|
23142
23354
|
if (cachedLongFlags) return cachedLongFlags;
|
|
23143
23355
|
const acc = /* @__PURE__ */ new Set();
|
|
23144
|
-
const
|
|
23356
|
+
const walk2 = (node) => {
|
|
23145
23357
|
if (!isCanonicalSuggestion(node)) return;
|
|
23146
23358
|
for (const opt of node.options) {
|
|
23147
23359
|
if (opt.discovery) continue;
|
|
23148
23360
|
const m = /--[\w-]+/.exec(opt.flags);
|
|
23149
23361
|
if (m) acc.add(m[0]);
|
|
23150
23362
|
}
|
|
23151
|
-
for (const child2 of node.subcommands)
|
|
23363
|
+
for (const child2 of node.subcommands) walk2(child2);
|
|
23152
23364
|
};
|
|
23153
|
-
|
|
23365
|
+
walk2(buildCommandManifest(program2).tree);
|
|
23154
23366
|
cachedLongFlags = [...acc];
|
|
23155
23367
|
return cachedLongFlags;
|
|
23156
23368
|
}
|
|
@@ -23250,19 +23462,19 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
23250
23462
|
});
|
|
23251
23463
|
var rules = program2.command("rules").description("org-managed .gitignore delivery");
|
|
23252
23464
|
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) => {
|
|
23253
|
-
const path2 = (0,
|
|
23254
|
-
const current = (0,
|
|
23465
|
+
const path2 = (0, import_node_path26.join)(process.cwd(), ".gitignore");
|
|
23466
|
+
const current = (0, import_node_fs29.existsSync)(path2) ? (0, import_node_fs29.readFileSync)(path2, "utf8") : null;
|
|
23255
23467
|
const plan = planManagedGitignore(current);
|
|
23256
23468
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
23257
23469
|
if (opts.json) {
|
|
23258
|
-
if (opts.write && plan.changed) (0,
|
|
23470
|
+
if (opts.write && plan.changed) (0, import_node_fs29.writeFileSync)(path2, plan.content, "utf8");
|
|
23259
23471
|
console.log(JSON.stringify(plan, null, 2));
|
|
23260
23472
|
if (!opts.write && plan.changed) process.exitCode = 1;
|
|
23261
23473
|
return;
|
|
23262
23474
|
}
|
|
23263
23475
|
if (opts.write) {
|
|
23264
23476
|
if (plan.changed) {
|
|
23265
|
-
(0,
|
|
23477
|
+
(0, import_node_fs29.writeFileSync)(path2, plan.content, "utf8");
|
|
23266
23478
|
console.log(`mmi-cli org rules gitignore: updated .gitignore (${drift})`);
|
|
23267
23479
|
} else {
|
|
23268
23480
|
console.log("mmi-cli org rules gitignore: up to date");
|
|
@@ -23420,7 +23632,7 @@ function runWorktreeInstall(command, cwd, quiet) {
|
|
|
23420
23632
|
const file = isWin2 ? "cmd.exe" : bin;
|
|
23421
23633
|
const spawnArgs = isWin2 ? ["/c", bin, ...args] : args;
|
|
23422
23634
|
return new Promise((resolve5, reject) => {
|
|
23423
|
-
const child2 = (0,
|
|
23635
|
+
const child2 = (0, import_node_child_process13.spawn)(file, spawnArgs, { cwd, stdio: quiet ? "ignore" : "inherit", windowsHide: true });
|
|
23424
23636
|
const timer = setTimeout(() => {
|
|
23425
23637
|
try {
|
|
23426
23638
|
child2.kill();
|
|
@@ -23452,26 +23664,26 @@ function makeProvisionDeps(worktreeRoot, quiet, log) {
|
|
|
23452
23664
|
function acquireWorktreeSetupLock(worktreeRoot) {
|
|
23453
23665
|
const lockPath = repoRuntimeStatePath(worktreeRoot, "worktree-setup.lock");
|
|
23454
23666
|
const take = () => {
|
|
23455
|
-
const fd = (0,
|
|
23667
|
+
const fd = (0, import_node_fs29.openSync)(lockPath, "wx");
|
|
23456
23668
|
try {
|
|
23457
|
-
(0,
|
|
23669
|
+
(0, import_node_fs29.writeSync)(fd, String(Date.now()));
|
|
23458
23670
|
} finally {
|
|
23459
|
-
(0,
|
|
23671
|
+
(0, import_node_fs29.closeSync)(fd);
|
|
23460
23672
|
}
|
|
23461
23673
|
return () => {
|
|
23462
23674
|
try {
|
|
23463
|
-
(0,
|
|
23675
|
+
(0, import_node_fs29.rmSync)(lockPath, { force: true });
|
|
23464
23676
|
} catch {
|
|
23465
23677
|
}
|
|
23466
23678
|
};
|
|
23467
23679
|
};
|
|
23468
23680
|
try {
|
|
23469
|
-
(0,
|
|
23681
|
+
(0, import_node_fs29.mkdirSync)((0, import_node_path26.dirname)(lockPath), { recursive: true });
|
|
23470
23682
|
return take();
|
|
23471
23683
|
} catch {
|
|
23472
23684
|
try {
|
|
23473
|
-
if (Date.now() - (0,
|
|
23474
|
-
(0,
|
|
23685
|
+
if (Date.now() - (0, import_node_fs29.statSync)(lockPath).mtimeMs > WORKTREE_SETUP_LOCK_TTL_MS) {
|
|
23686
|
+
(0, import_node_fs29.rmSync)(lockPath, { force: true });
|
|
23475
23687
|
return take();
|
|
23476
23688
|
}
|
|
23477
23689
|
} catch {
|
|
@@ -23651,7 +23863,7 @@ function scheduleRelatedDiscovery(o) {
|
|
|
23651
23863
|
try {
|
|
23652
23864
|
const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body, "--fail-soft"];
|
|
23653
23865
|
if (o.repo) args.push("--repo", o.repo);
|
|
23654
|
-
spawnDetachedSelf(args, { spawn:
|
|
23866
|
+
spawnDetachedSelf(args, { spawn: import_node_child_process13.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
|
|
23655
23867
|
} catch {
|
|
23656
23868
|
}
|
|
23657
23869
|
}
|
|
@@ -23677,6 +23889,27 @@ docs.command("index").description("regenerate docs/index.md from the docs/ tree
|
|
|
23677
23889
|
await failGraceful(e.message);
|
|
23678
23890
|
}
|
|
23679
23891
|
});
|
|
23892
|
+
docs.command("refs").description("deterministic doc reference gate: every backticked repo path, relative .md link, `mmi-cli` command ref, and `<!-- pinned by \u2026 -->` comment across docs/** + README.md + architecture.md must resolve, or exit 1 (fleet-portable port of the Hub gate scripts/check-doc-refs.mjs, #3339)").option("--json", "machine-readable findings list: { ok, docCount, findings[] }").action(async (o) => {
|
|
23893
|
+
try {
|
|
23894
|
+
const root = await repoRoot();
|
|
23895
|
+
const commandPaths = new Set(buildCommandManifest(program2).index.map((entry) => entry.path));
|
|
23896
|
+
const result = runDocRefs(root, { commandPaths });
|
|
23897
|
+
if (o.json) {
|
|
23898
|
+
consoleIo.log(JSON.stringify({ ok: result.ok, docCount: result.docCount, findings: result.findings }, null, 2));
|
|
23899
|
+
if (!result.ok) process.exitCode = 1;
|
|
23900
|
+
return;
|
|
23901
|
+
}
|
|
23902
|
+
if (result.ok) {
|
|
23903
|
+
console.log(`doc refs: ${result.docCount} docs, every reference resolves`);
|
|
23904
|
+
return;
|
|
23905
|
+
}
|
|
23906
|
+
console.error("doc refs: unresolved references");
|
|
23907
|
+
for (const f of result.findings) console.error(`- ${f.doc}:${f.line} [${f.kind}] ${f.detail}`);
|
|
23908
|
+
process.exitCode = 1;
|
|
23909
|
+
} catch (e) {
|
|
23910
|
+
await failGraceful(e.message);
|
|
23911
|
+
}
|
|
23912
|
+
});
|
|
23680
23913
|
var docsAudit = program2.command("docs-audit").description("the docs janitor verdict ledger \u2014 record a dated run verdict, or read the dead-man status back");
|
|
23681
23914
|
docsAudit.command("record").description("write a dated janitor verdict for one repo to the registry ledger (master-only server-side)").option("--repo <owner/name>", "the repo the verdict is for (default: the current repo)").option("--date <YYYY-MM-DD>", "the ISO day the run examined (default: today)").requiredOption("--sha-range <a..b>", "the git range the janitor read (e.g. <lastVerdictSha>..HEAD)").requiredOption("--outcome <kind>", "clean | refreshed | failed").option("--count <n>", "docs refreshed (required when --outcome refreshed)").option("--reason <text>", "why the run failed (required when --outcome failed)").requiredOption("--checker-vendor <vendor>", "which vendor's model actually ran the check").action(async (o) => {
|
|
23682
23915
|
try {
|
|
@@ -23892,7 +24125,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
|
|
|
23892
24125
|
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`);
|
|
23893
24126
|
if (o.secretsFile) {
|
|
23894
24127
|
try {
|
|
23895
|
-
vars.push(`secrets=${(0,
|
|
24128
|
+
vars.push(`secrets=${(0, import_node_fs29.readFileSync)(o.secretsFile, "utf8")}`);
|
|
23896
24129
|
} catch (e) {
|
|
23897
24130
|
return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
|
|
23898
24131
|
}
|
|
@@ -24527,11 +24760,11 @@ pr.command("view <number>").description("read a PR as structured JSON (merged st
|
|
|
24527
24760
|
}
|
|
24528
24761
|
});
|
|
24529
24762
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
24530
|
-
const wfDir = (0,
|
|
24531
|
-
if (!(0,
|
|
24532
|
-
return (0,
|
|
24763
|
+
const wfDir = (0, import_node_path26.join)(cwd, ".github", "workflows");
|
|
24764
|
+
if (!(0, import_node_fs29.existsSync)(wfDir)) return [];
|
|
24765
|
+
return (0, import_node_fs29.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
24533
24766
|
try {
|
|
24534
|
-
return workflowReportsPrChecks((0,
|
|
24767
|
+
return workflowReportsPrChecks((0, import_node_fs29.readFileSync)((0, import_node_path26.join)(wfDir, name), "utf8"));
|
|
24535
24768
|
} catch {
|
|
24536
24769
|
return true;
|
|
24537
24770
|
}
|
|
@@ -24558,16 +24791,16 @@ function ciAuditDeps() {
|
|
|
24558
24791
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
24559
24792
|
readSeedFile: (path2) => {
|
|
24560
24793
|
if (!root) return null;
|
|
24561
|
-
const fullPath = (0,
|
|
24562
|
-
return (0,
|
|
24794
|
+
const fullPath = (0, import_node_path26.join)(root, path2);
|
|
24795
|
+
return (0, import_node_fs29.existsSync)(fullPath) ? (0, import_node_fs29.readFileSync)(fullPath, "utf8") : null;
|
|
24563
24796
|
}
|
|
24564
24797
|
};
|
|
24565
24798
|
}
|
|
24566
24799
|
function hubRoot() {
|
|
24567
|
-
const fromPkg = (0,
|
|
24800
|
+
const fromPkg = (0, import_node_path26.join)(__dirname, "..", "..");
|
|
24568
24801
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
24569
|
-
if ((0,
|
|
24570
|
-
if ((0,
|
|
24802
|
+
if ((0, import_node_fs29.existsSync)((0, import_node_path26.join)(fromPkg, marker))) return fromPkg;
|
|
24803
|
+
if ((0, import_node_fs29.existsSync)((0, import_node_path26.join)(process.cwd(), marker))) return process.cwd();
|
|
24571
24804
|
return null;
|
|
24572
24805
|
}
|
|
24573
24806
|
pr.command("ci-policy").description("report merge CI policy: wait-for-checks vs no-ci (for grind/build agents)").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the current checkout)").action(async (o) => {
|
|
@@ -24806,7 +25039,7 @@ pr.command("merge <number>").description("merge a PR (squash by default) and cle
|
|
|
24806
25039
|
localCleanup = await cleanupPrMergeLocalBranch(headRef, {
|
|
24807
25040
|
beforeWorktrees,
|
|
24808
25041
|
startingPath,
|
|
24809
|
-
pathExists: (p) => (0,
|
|
25042
|
+
pathExists: (p) => (0, import_node_fs29.existsSync)(p),
|
|
24810
25043
|
execGit: async (args) => (await execFileP2("git", args, { timeout: GIT_TIMEOUT_MS })).stdout,
|
|
24811
25044
|
teardownWorktreeStage,
|
|
24812
25045
|
deferredStore,
|
|
@@ -25146,10 +25379,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
|
|
|
25146
25379
|
targets = resolution.targets;
|
|
25147
25380
|
}
|
|
25148
25381
|
const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
|
|
25149
|
-
const fileMatrix = (0,
|
|
25382
|
+
const fileMatrix = (0, import_node_fs29.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs29.readFileSync)("access-matrix.json", "utf8")) : {};
|
|
25150
25383
|
const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
|
|
25151
25384
|
const derivedContracts = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
|
|
25152
|
-
const fileContracts = (0,
|
|
25385
|
+
const fileContracts = (0, import_node_fs29.existsSync)("data-access-contracts.json") ? loadDataAccessContracts((0, import_node_fs29.readFileSync)("data-access-contracts.json", "utf8")) : { consumers: {} };
|
|
25153
25386
|
const dataAccess = mergeDataAccessContracts(fileContracts, derivedContracts);
|
|
25154
25387
|
const report = await auditOrgAccess(targets, deps, matrix, dataAccess);
|
|
25155
25388
|
console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
|
|
@@ -25182,16 +25415,16 @@ function directoryBytes(path2) {
|
|
|
25182
25415
|
let total = 0;
|
|
25183
25416
|
let entries;
|
|
25184
25417
|
try {
|
|
25185
|
-
entries = (0,
|
|
25418
|
+
entries = (0, import_node_fs29.readdirSync)(path2, { withFileTypes: true });
|
|
25186
25419
|
} catch {
|
|
25187
25420
|
return 0;
|
|
25188
25421
|
}
|
|
25189
25422
|
for (const entry of entries) {
|
|
25190
|
-
const child2 = (0,
|
|
25423
|
+
const child2 = (0, import_node_path26.join)(path2, entry.name);
|
|
25191
25424
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
25192
25425
|
else {
|
|
25193
25426
|
try {
|
|
25194
|
-
total += (0,
|
|
25427
|
+
total += (0, import_node_fs29.statSync)(child2).size;
|
|
25195
25428
|
} catch {
|
|
25196
25429
|
}
|
|
25197
25430
|
}
|
|
@@ -25199,25 +25432,25 @@ function directoryBytes(path2) {
|
|
|
25199
25432
|
return total;
|
|
25200
25433
|
}
|
|
25201
25434
|
function listDirEntries(dir) {
|
|
25202
|
-
return (0,
|
|
25435
|
+
return (0, import_node_fs29.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
|
|
25203
25436
|
}
|
|
25204
25437
|
function readInstalledPluginRefs(home) {
|
|
25205
25438
|
const p = installedPluginsPath(home);
|
|
25206
|
-
if (!(0,
|
|
25439
|
+
if (!(0, import_node_fs29.existsSync)(p)) return [];
|
|
25207
25440
|
try {
|
|
25208
|
-
return installedPluginPaths((0,
|
|
25441
|
+
return installedPluginPaths((0, import_node_fs29.readFileSync)(p, "utf8"));
|
|
25209
25442
|
} catch {
|
|
25210
25443
|
return null;
|
|
25211
25444
|
}
|
|
25212
25445
|
}
|
|
25213
25446
|
function pluginCacheFsDeps(home, dirBytes) {
|
|
25214
25447
|
return {
|
|
25215
|
-
exists: (p) => (0,
|
|
25216
|
-
listVersionDirs: (root) => (0,
|
|
25448
|
+
exists: (p) => (0, import_node_fs29.existsSync)(p),
|
|
25449
|
+
listVersionDirs: (root) => (0, import_node_fs29.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
|
|
25217
25450
|
dirBytes,
|
|
25218
|
-
listStagingDirs: (root) => (0,
|
|
25451
|
+
listStagingDirs: (root) => (0, import_node_fs29.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
25219
25452
|
try {
|
|
25220
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
25453
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path26.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs29.statSync)(p).mtimeMs) };
|
|
25221
25454
|
} catch {
|
|
25222
25455
|
return { name: d.name, mtimeMs: Date.now() };
|
|
25223
25456
|
}
|
|
@@ -25231,10 +25464,10 @@ function stagingApplyFsGuard(home) {
|
|
|
25231
25464
|
return {
|
|
25232
25465
|
referencedPaths: () => readInstalledPluginRefs(home),
|
|
25233
25466
|
mtimeMs: (name) => {
|
|
25234
|
-
const p = (0,
|
|
25235
|
-
if (!(0,
|
|
25467
|
+
const p = (0, import_node_path26.join)(stagingRoot, name);
|
|
25468
|
+
if (!(0, import_node_fs29.existsSync)(p)) return null;
|
|
25236
25469
|
try {
|
|
25237
|
-
return newestMtimeMs(p, listDirEntries, (q) => (0,
|
|
25470
|
+
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs29.statSync)(q).mtimeMs);
|
|
25238
25471
|
} catch {
|
|
25239
25472
|
return null;
|
|
25240
25473
|
}
|
|
@@ -25250,7 +25483,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
25250
25483
|
{ withBytes: true }
|
|
25251
25484
|
);
|
|
25252
25485
|
const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
|
|
25253
|
-
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0,
|
|
25486
|
+
const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs29.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard((0, import_node_os8.homedir)())) : void 0;
|
|
25254
25487
|
const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
|
|
25255
25488
|
if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
|
|
25256
25489
|
else console.log(renderPluginCachePlan(plan, result));
|
|
@@ -25283,7 +25516,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
|
|
|
25283
25516
|
readBoard,
|
|
25284
25517
|
// #1813: warm the slice cache out-of-band (detached) so the ~20s live read
|
|
25285
25518
|
// never costs banner time and next session's glance renders instantly within budget.
|
|
25286
|
-
scheduleRefresh: () => spawnDetachedSelf(["board", "slice-refresh", "--quiet"], { spawn:
|
|
25519
|
+
scheduleRefresh: () => spawnDetachedSelf(["board", "slice-refresh", "--quiet"], { spawn: import_node_child_process13.spawn, execPath: process.execPath, scriptPath: process.argv[1] })
|
|
25287
25520
|
}),
|
|
25288
25521
|
// command-ladder hint (#2609): compact gh→mmi-cli cheat sheet so agents reach for mmi-cli first,
|
|
25289
25522
|
// not after a denied gh call. <1KB, pure in-memory — no network, no fs, fail-soft.
|
|
@@ -25314,7 +25547,7 @@ program2.command("session-start").description("run the SessionStart verbs (whoam
|
|
|
25314
25547
|
for (const line of scratchGcLines(process.cwd())) consoleIo.log(line);
|
|
25315
25548
|
const worktreeBanner = worktreeAutoProvisionBanner(process.cwd());
|
|
25316
25549
|
if (worktreeBanner) {
|
|
25317
|
-
spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn:
|
|
25550
|
+
spawnDetachedSelf(["worktree", "setup", "--quiet"], { spawn: import_node_child_process13.spawn, execPath: process.execPath, scriptPath: process.argv[1] });
|
|
25318
25551
|
consoleIo.log(worktreeBanner);
|
|
25319
25552
|
}
|
|
25320
25553
|
appendHookActivity(process.cwd(), { event: "SessionStart", script: "session-start", outcome: "ran", action: "session-start hook completed" });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mutmutco/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.42.0",
|
|
4
4
|
"description": "MMI Future CLI — the org dev toolbox (board, registry, keyless secrets, release train, bootstrap, doctor) and the cross-IDE engine the plugin's session-start hook drives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|