@mutmutco/cli 4.0.12 → 4.0.14
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 +246 -309
- package/dist/repo-index-v4.cjs +24 -7
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -4510,6 +4510,11 @@ function formatPositionalTarget(commandPath3, argName, opts = {}) {
|
|
|
4510
4510
|
if (concrete) return `mmi-cli ${commandPath3} ${concrete}`;
|
|
4511
4511
|
return `mmi-cli ${commandPath3} <${argName}>`;
|
|
4512
4512
|
}
|
|
4513
|
+
var FLAG_SYNONYMS = /* @__PURE__ */ new Map([["--outcome", "--reason"]]);
|
|
4514
|
+
function synonymFlagFor(flag, ownFlags) {
|
|
4515
|
+
const syn = FLAG_SYNONYMS.get(flag);
|
|
4516
|
+
return syn !== void 0 && ownFlags.includes(syn) ? syn : void 0;
|
|
4517
|
+
}
|
|
4513
4518
|
function unknownTargetFlagMessage(flag, positional) {
|
|
4514
4519
|
return `unknown option '${flag}' \u2014 this command takes its target as a positional: ${positional}`;
|
|
4515
4520
|
}
|
|
@@ -10827,10 +10832,10 @@ var rollout_plan_default = {
|
|
|
10827
10832
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
10828
10833
|
},
|
|
10829
10834
|
baseline: {
|
|
10830
|
-
version: "4.0.
|
|
10831
|
-
tag: "v4.0.
|
|
10832
|
-
commit: "
|
|
10833
|
-
npm: "@mutmutco/cli@4.0.
|
|
10835
|
+
version: "4.0.14",
|
|
10836
|
+
tag: "v4.0.14",
|
|
10837
|
+
commit: "386f339f67c6",
|
|
10838
|
+
npm: "@mutmutco/cli@4.0.14"
|
|
10834
10839
|
},
|
|
10835
10840
|
exitCriterion: "fleet-n-of-n",
|
|
10836
10841
|
hubOnlyShortcut: "forbidden",
|
|
@@ -10847,14 +10852,14 @@ var rollout_plan_default = {
|
|
|
10847
10852
|
repo: "mutmutco/mmi-hub",
|
|
10848
10853
|
role: "canary",
|
|
10849
10854
|
schedule: "train",
|
|
10850
|
-
v3Target: "v4.0.
|
|
10855
|
+
v3Target: "v4.0.14"
|
|
10851
10856
|
}
|
|
10852
10857
|
],
|
|
10853
10858
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
10854
10859
|
rollback: {
|
|
10855
10860
|
independent: true,
|
|
10856
|
-
mechanism: "npm dist-tag latest -> 4.0.
|
|
10857
|
-
v3Target: "v4.0.
|
|
10861
|
+
mechanism: "npm dist-tag latest -> 4.0.14 and redeploy the Hub Lambda from tag v4.0.14 (386f339f67c6); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
10862
|
+
v3Target: "v4.0.14 (@mutmutco/cli@4.0.14, tag commit 386f339f67c6 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
10858
10863
|
}
|
|
10859
10864
|
},
|
|
10860
10865
|
{
|
|
@@ -17301,7 +17306,7 @@ async function executeWaveLand(plan, deps) {
|
|
|
17301
17306
|
}
|
|
17302
17307
|
|
|
17303
17308
|
// src/index.ts
|
|
17304
|
-
var
|
|
17309
|
+
var import_node_os19 = require("node:os");
|
|
17305
17310
|
|
|
17306
17311
|
// src/board.ts
|
|
17307
17312
|
var import_node_child_process9 = require("node:child_process");
|
|
@@ -17412,14 +17417,16 @@ async function filterDependencyBlockedClaimables(items, client, opts = {}) {
|
|
|
17412
17417
|
}
|
|
17413
17418
|
|
|
17414
17419
|
// src/closing-keyword-guard.ts
|
|
17415
|
-
var CLOSING_MENTION_RE = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s
|
|
17420
|
+
var CLOSING_MENTION_RE = /\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+(?:#(\d+)|\[#(\d+)\]\([^)\s]+\))/gi;
|
|
17416
17421
|
var NEGATION_RE = /\b(?:not|never|cannot|can't|don't|doesn't|didn't|won't|wouldn't|shouldn't|mustn't|without)\b/i;
|
|
17417
17422
|
var CLAUSE_WINDOW = 120;
|
|
17418
|
-
var NEGATED_CLOSING_PHRASE_RE = /\b(?:(?:does|do|did|will|would|should|must|can)\s+not|(?:is|was|are|were)\s+not|doesn't|don't|didn't|won't|wouldn't|shouldn't|mustn't|can't|cannot|never|without|not)\s+(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s
|
|
17423
|
+
var NEGATED_CLOSING_PHRASE_RE = /\b(?:(?:does|do|did|will|would|should|must|can)\s+not|(?:is|was|are|were)\s+not|doesn't|don't|didn't|won't|wouldn't|shouldn't|mustn't|can't|cannot|never|without|not)\s+(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+(?:#(\d+)|\[#(\d+)\]\([^)\s]+\))/gi;
|
|
17419
17424
|
function rewriteNegatedClosingPhrases(text) {
|
|
17420
17425
|
if (!text.includes("#")) return text;
|
|
17421
17426
|
const segments = text.split(/(```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`)/g);
|
|
17422
|
-
return segments.map(
|
|
17427
|
+
return segments.map(
|
|
17428
|
+
(seg, i) => i % 2 === 1 ? seg : seg.replace(NEGATED_CLOSING_PHRASE_RE, (_m, plain, linked) => `leaves #${plain ?? linked} open`)
|
|
17429
|
+
).join("");
|
|
17423
17430
|
}
|
|
17424
17431
|
function findClosingMentions(text) {
|
|
17425
17432
|
const mentions = [];
|
|
@@ -17436,7 +17443,8 @@ function findClosingMentions(text) {
|
|
|
17436
17443
|
const clause = boundary === -1 ? windowText : windowText.slice(boundary + 1);
|
|
17437
17444
|
mentions.push({
|
|
17438
17445
|
keyword: (match[1] ?? "").toLowerCase(),
|
|
17439
|
-
issue: Number(match[2]),
|
|
17446
|
+
issue: Number(match[2] ?? match[3]),
|
|
17447
|
+
// plain `#N` vs Markdown-linked `[#N](URL)` (#5338)
|
|
17440
17448
|
negated: NEGATION_RE.test(clause)
|
|
17441
17449
|
});
|
|
17442
17450
|
}
|
|
@@ -23221,6 +23229,7 @@ var import_node_crypto9 = require("node:crypto");
|
|
|
23221
23229
|
var import_node_crypto8 = require("node:crypto");
|
|
23222
23230
|
var import_node_child_process13 = require("node:child_process");
|
|
23223
23231
|
var import_node_fs25 = require("node:fs");
|
|
23232
|
+
var import_node_os12 = require("node:os");
|
|
23224
23233
|
var import_node_path23 = require("node:path");
|
|
23225
23234
|
|
|
23226
23235
|
// src/repo-index-v4/chunks.ts
|
|
@@ -23475,22 +23484,37 @@ function runEmbedderOnce(cwd, chunks, modelDirectory, createdAt) {
|
|
|
23475
23484
|
if (!(0, import_node_fs25.existsSync)(file)) return { ok: false, reason: "embeddings-unavailable" };
|
|
23476
23485
|
const request = { texts: chunks.map((chunk) => ({ id: chunk.id, text: embeddingInput(cwd, chunk) })), maxBatch: V4_EMBED_BATCH };
|
|
23477
23486
|
const env = { ...process.env, ...modelDirectory ? { MMI_REPO_INDEXER_MODEL_DIR: modelDirectory } : {} };
|
|
23478
|
-
const
|
|
23487
|
+
const requestDir = (0, import_node_fs25.mkdtempSync)((0, import_node_path23.join)((0, import_node_os12.tmpdir)(), "mmi-repo-index-req-"));
|
|
23488
|
+
const requestFile = (0, import_node_path23.join)(requestDir, "request.json");
|
|
23489
|
+
(0, import_node_fs25.writeFileSync)(requestFile, JSON.stringify(request));
|
|
23490
|
+
let result;
|
|
23491
|
+
try {
|
|
23492
|
+
result = (0, import_node_child_process13.spawnSync)(process.execPath, [file, requestFile], { encoding: "utf8", windowsHide: true, timeout: V4_EMBED_TIMEOUT_MS, maxBuffer: V4_MAX_ARTIFACT_BYTES, env });
|
|
23493
|
+
} finally {
|
|
23494
|
+
(0, import_node_fs25.rmSync)(requestDir, { recursive: true, force: true });
|
|
23495
|
+
}
|
|
23479
23496
|
if (result.error || result.status !== 0) {
|
|
23480
23497
|
const cleanExit2 = result.error === void 0 && result.signal === void 0 && typeof result.status === "number" && result.status !== 0;
|
|
23498
|
+
const stdout = String(result.stdout).trim();
|
|
23499
|
+
const stderrTail = String(result.stderr).trim().slice(-400) || void 0;
|
|
23481
23500
|
let code;
|
|
23482
|
-
let stderrTail;
|
|
23483
23501
|
if (cleanExit2) {
|
|
23484
23502
|
try {
|
|
23485
|
-
code = JSON.parse(
|
|
23503
|
+
code = JSON.parse(stdout)?.code;
|
|
23486
23504
|
} catch {
|
|
23487
23505
|
}
|
|
23488
|
-
stderrTail = String(result.stderr).trim().slice(-400) || void 0;
|
|
23489
23506
|
}
|
|
23490
|
-
return {
|
|
23507
|
+
return {
|
|
23508
|
+
ok: false,
|
|
23509
|
+
code,
|
|
23510
|
+
stdoutTail: code ? void 0 : stdout.slice(-400) || void 0,
|
|
23511
|
+
stderrTail,
|
|
23512
|
+
cleanExit: cleanExit2,
|
|
23513
|
+
detail: result.error?.message ?? result.signal ?? `exit status ${result.status ?? "unknown"}`
|
|
23514
|
+
};
|
|
23491
23515
|
}
|
|
23492
23516
|
try {
|
|
23493
|
-
const response = JSON.parse(result.stdout);
|
|
23517
|
+
const response = JSON.parse(String(result.stdout));
|
|
23494
23518
|
if (!response.ok || !response.provenance || !Array.isArray(response.embeddings)) return { ok: false, reason: "embeddings-unavailable" };
|
|
23495
23519
|
const provenance = {
|
|
23496
23520
|
provider: response.provenance.provider,
|
|
@@ -23517,8 +23541,9 @@ function runEmbedder(cwd, chunks, modelDirectory, createdAt) {
|
|
|
23517
23541
|
}
|
|
23518
23542
|
const runner = last;
|
|
23519
23543
|
const code = runner.code ? ` code=${runner.code}` : "";
|
|
23544
|
+
const stdout = runner.stdoutTail ? ` stdout=${runner.stdoutTail}` : "";
|
|
23520
23545
|
const stderr = runner.stderrTail ? ` stderr=${runner.stderrTail}` : "";
|
|
23521
|
-
throw new Error(`repo-index v4 embedding runner failed: ${runner.detail ?? "unknown"}${code}${stderr}`);
|
|
23546
|
+
throw new Error(`repo-index v4 embedding runner failed: ${runner.detail ?? "unknown"}${code}${stdout}${stderr}`);
|
|
23522
23547
|
}
|
|
23523
23548
|
async function buildRepoIndexV4(cwd, repo, opts = {}) {
|
|
23524
23549
|
const { commit, defaultBranch, createdAt } = gitInfo(cwd);
|
|
@@ -23861,7 +23886,7 @@ async function gcRepoIndexCloud(deps) {
|
|
|
23861
23886
|
|
|
23862
23887
|
// src/repo-index-sync.ts
|
|
23863
23888
|
var import_node_fs27 = require("node:fs");
|
|
23864
|
-
var
|
|
23889
|
+
var import_node_os13 = require("node:os");
|
|
23865
23890
|
var import_node_path25 = require("node:path");
|
|
23866
23891
|
var import_node_child_process14 = require("node:child_process");
|
|
23867
23892
|
|
|
@@ -24073,7 +24098,7 @@ async function syncEstateRepoIndex(opts) {
|
|
|
24073
24098
|
}
|
|
24074
24099
|
} catch {
|
|
24075
24100
|
}
|
|
24076
|
-
const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path25.join)((0,
|
|
24101
|
+
const dir = (0, import_node_fs27.mkdtempSync)((0, import_node_path25.join)((0, import_node_os13.tmpdir)(), "mmi-repo-index-"));
|
|
24077
24102
|
try {
|
|
24078
24103
|
const reconciled = await reconcileRepoIndexCloud(repo, opts.deps);
|
|
24079
24104
|
if (!reconciled.ok) {
|
|
@@ -25737,7 +25762,7 @@ function writeError(res) {
|
|
|
25737
25762
|
// src/secrets-commands.ts
|
|
25738
25763
|
var import_node_fs32 = require("node:fs");
|
|
25739
25764
|
var import_node_path29 = require("node:path");
|
|
25740
|
-
var
|
|
25765
|
+
var import_node_os14 = require("node:os");
|
|
25741
25766
|
|
|
25742
25767
|
// src/secrets-diff.ts
|
|
25743
25768
|
var TIMEOUT_MS2 = 8e3;
|
|
@@ -25860,7 +25885,7 @@ async function decryptRailsCredentials(input) {
|
|
|
25860
25885
|
'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
|
|
25861
25886
|
"puts JSON.generate(config.config)"
|
|
25862
25887
|
].join("\n");
|
|
25863
|
-
const scriptDir = (0, import_node_fs32.mkdtempSync)((0, import_node_path29.join)((0,
|
|
25888
|
+
const scriptDir = (0, import_node_fs32.mkdtempSync)((0, import_node_path29.join)((0, import_node_os14.tmpdir)(), "mmi-rails-decrypt-"));
|
|
25864
25889
|
const scriptPath = (0, import_node_path29.join)(scriptDir, "decrypt.rb");
|
|
25865
25890
|
(0, import_node_fs32.writeFileSync)(scriptPath, script, "utf8");
|
|
25866
25891
|
try {
|
|
@@ -27082,7 +27107,7 @@ function registerEdgeCommands(program3) {
|
|
|
27082
27107
|
|
|
27083
27108
|
// src/bootstrap-commands.ts
|
|
27084
27109
|
var import_node_fs34 = require("node:fs");
|
|
27085
|
-
var
|
|
27110
|
+
var import_node_os15 = require("node:os");
|
|
27086
27111
|
var import_node_path32 = require("node:path");
|
|
27087
27112
|
|
|
27088
27113
|
// src/bootstrap-drift.ts
|
|
@@ -28286,7 +28311,7 @@ function registerBootstrapCommands(program3) {
|
|
|
28286
28311
|
const readFile6 = (p) => (0, import_node_fs34.existsSync)(p) ? (0, import_node_fs34.readFileSync)(p, "utf8") : null;
|
|
28287
28312
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
28288
28313
|
const putSeed = async (target, content, ref, sha) => {
|
|
28289
|
-
const tmp = (0, import_node_path32.join)((0,
|
|
28314
|
+
const tmp = (0, import_node_path32.join)((0, import_node_os15.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
28290
28315
|
(0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
|
|
28291
28316
|
try {
|
|
28292
28317
|
await gh(contentPutInputArgs(repo, target, tmp));
|
|
@@ -28757,7 +28782,7 @@ LIVE apply to ${repo}:
|
|
|
28757
28782
|
} catch {
|
|
28758
28783
|
existingSha = void 0;
|
|
28759
28784
|
}
|
|
28760
|
-
const tmp = (0, import_node_path32.join)((0,
|
|
28785
|
+
const tmp = (0, import_node_path32.join)((0, import_node_os15.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
28761
28786
|
const desiredContent = desiredByRepo.get(rec.repo);
|
|
28762
28787
|
if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
|
|
28763
28788
|
(0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha)), "utf8");
|
|
@@ -28930,7 +28955,7 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
|
|
|
28930
28955
|
} catch {
|
|
28931
28956
|
existingSha = void 0;
|
|
28932
28957
|
}
|
|
28933
|
-
const tmp = (0, import_node_path32.join)((0,
|
|
28958
|
+
const tmp = (0, import_node_path32.join)((0, import_node_os15.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
28934
28959
|
(0, import_node_fs34.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
|
|
28935
28960
|
try {
|
|
28936
28961
|
await gh(contentPutInputArgs(repo, seed.target, tmp));
|
|
@@ -29441,7 +29466,7 @@ function registerStageCommands(program3) {
|
|
|
29441
29466
|
// src/merge-cleanup.ts
|
|
29442
29467
|
var import_node_fs37 = require("node:fs");
|
|
29443
29468
|
var import_node_path35 = require("node:path");
|
|
29444
|
-
var
|
|
29469
|
+
var import_node_os16 = require("node:os");
|
|
29445
29470
|
|
|
29446
29471
|
// src/config-load.ts
|
|
29447
29472
|
var discoveredConfig = null;
|
|
@@ -29705,7 +29730,7 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh) {
|
|
|
29705
29730
|
const commits = JSON.parse(raw).commits ?? [];
|
|
29706
29731
|
const body = squashBodyWithOverride(commits.map((c) => ({ headline: c.messageHeadline ?? "", body: c.messageBody ?? "" })), process.cwd());
|
|
29707
29732
|
if (!body) return void 0;
|
|
29708
|
-
const dir = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0,
|
|
29733
|
+
const dir = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os16.tmpdir)(), "mmi-squash-body-"));
|
|
29709
29734
|
const path2 = (0, import_node_path35.join)(dir, "body.txt");
|
|
29710
29735
|
(0, import_node_fs37.writeFileSync)(path2, `${body}
|
|
29711
29736
|
`, "utf8");
|
|
@@ -30474,6 +30499,175 @@ async function checkDocsIndexAtHead(opts, deps) {
|
|
|
30474
30499
|
// src/issue-commands.ts
|
|
30475
30500
|
var import_node_fs38 = require("node:fs");
|
|
30476
30501
|
var import_node_crypto13 = require("node:crypto");
|
|
30502
|
+
|
|
30503
|
+
// src/learning-closure-rate.ts
|
|
30504
|
+
var CLOSURE_RATE_TIMEOUT_MS = 2e4;
|
|
30505
|
+
var LOOP_ITEM_CAP = 100;
|
|
30506
|
+
var EVIDENCE_CONCURRENCY = 4;
|
|
30507
|
+
var RED_TEAM_FINDING_LABEL2 = "red-team";
|
|
30508
|
+
var RULING_LOOP_STATE_LABELS = ["loop-state:closed-deferred", "loop-state:closed-invalid"];
|
|
30509
|
+
var CLOSED_MERGED_LOOP_STATE_LABEL = "loop-state:closed-merged";
|
|
30510
|
+
var LOOP_KINDS2 = [
|
|
30511
|
+
{ kind: "friction", label: REPORT_LABEL },
|
|
30512
|
+
{ kind: "lesson", label: SKILL_LESSON_LABEL },
|
|
30513
|
+
{ kind: "red-team", label: RED_TEAM_FINDING_LABEL2 }
|
|
30514
|
+
];
|
|
30515
|
+
function prIsMerged(pr2) {
|
|
30516
|
+
return String(pr2.state ?? "").toUpperCase() === "MERGED";
|
|
30517
|
+
}
|
|
30518
|
+
function mergedPrsOf(linkedPrs) {
|
|
30519
|
+
return linkedPrs.filter(prIsMerged);
|
|
30520
|
+
}
|
|
30521
|
+
function hasRecordedRuling(labels) {
|
|
30522
|
+
return labels.some((label) => RULING_LOOP_STATE_LABELS.includes(label));
|
|
30523
|
+
}
|
|
30524
|
+
function classifyLoopClosure(item, evidence) {
|
|
30525
|
+
if (String(item.state ?? "").toUpperCase() !== "CLOSED") return "open";
|
|
30526
|
+
if (mergedPrsOf(evidence.linkedPrs).length > 0) return "closed";
|
|
30527
|
+
if (item.labels.includes(CLOSED_MERGED_LOOP_STATE_LABEL)) return "closed";
|
|
30528
|
+
if (hasRecordedRuling(item.labels)) return "closed";
|
|
30529
|
+
return "closed-no-evidence";
|
|
30530
|
+
}
|
|
30531
|
+
var round3 = (x) => Math.round(x * 1e3) / 1e3;
|
|
30532
|
+
function computeLoopKindRate(spec, verdicts) {
|
|
30533
|
+
const numerator = verdicts.filter((v) => v === "closed").length;
|
|
30534
|
+
const unknownEvidence = verdicts.filter((v) => v === "closed-no-evidence").length;
|
|
30535
|
+
const denominator = verdicts.length;
|
|
30536
|
+
return {
|
|
30537
|
+
kind: spec.kind,
|
|
30538
|
+
label: spec.label,
|
|
30539
|
+
numerator,
|
|
30540
|
+
denominator,
|
|
30541
|
+
unknownEvidence,
|
|
30542
|
+
rate: denominator > 0 ? round3(numerator / denominator) : null
|
|
30543
|
+
};
|
|
30544
|
+
}
|
|
30545
|
+
function fmtRate(rate) {
|
|
30546
|
+
return rate === null ? "\u2014" : rate.toFixed(3);
|
|
30547
|
+
}
|
|
30548
|
+
function formatClosureSummary(report) {
|
|
30549
|
+
const kindWidth = Math.max(...report.kinds.map((k) => k.kind.length));
|
|
30550
|
+
const labelWidth = Math.max(...report.kinds.map((k) => k.label.length));
|
|
30551
|
+
const lines = [`learning closure rate \u2014 ${report.repo} (computed at read; #4440)`];
|
|
30552
|
+
for (const k of report.kinds) {
|
|
30553
|
+
const head = `${k.kind.padEnd(kindWidth)} (label ${k.label.padEnd(labelWidth)})`;
|
|
30554
|
+
const body = k.denominator === 0 ? "no loop items" : `${k.numerator}/${k.denominator} closed \xB7 ${k.unknownEvidence} unknown evidence \xB7 rate ${fmtRate(k.rate)}`;
|
|
30555
|
+
lines.push(` ${head}: ${body}`);
|
|
30556
|
+
}
|
|
30557
|
+
const t = report.totals;
|
|
30558
|
+
lines.push(
|
|
30559
|
+
` ${"total".padEnd(kindWidth)}: ${t.numerator}/${t.denominator} closed \xB7 ${t.unknownEvidence} unknown evidence \xB7 rate ${fmtRate(t.rate)}`,
|
|
30560
|
+
"A closed loop without a merged PR or a recorded ruling reads as open."
|
|
30561
|
+
);
|
|
30562
|
+
if (report.evidencePartial) {
|
|
30563
|
+
lines.push("note: at least one closed item had an unreadable linked-PR read \u2014 counted open (unknown evidence).");
|
|
30564
|
+
}
|
|
30565
|
+
return lines.join("\n");
|
|
30566
|
+
}
|
|
30567
|
+
function buildClosureReport(repo, perKind, evidencePartial) {
|
|
30568
|
+
const kinds = perKind.map(({ spec, verdicts }) => computeLoopKindRate(spec, verdicts));
|
|
30569
|
+
const numerator = kinds.reduce((acc, k) => acc + k.numerator, 0);
|
|
30570
|
+
const denominator = kinds.reduce((acc, k) => acc + k.denominator, 0);
|
|
30571
|
+
const unknownEvidence = kinds.reduce((acc, k) => acc + k.unknownEvidence, 0);
|
|
30572
|
+
const report = {
|
|
30573
|
+
repo,
|
|
30574
|
+
kinds,
|
|
30575
|
+
totals: {
|
|
30576
|
+
numerator,
|
|
30577
|
+
denominator,
|
|
30578
|
+
unknownEvidence,
|
|
30579
|
+
rate: denominator > 0 ? round3(numerator / denominator) : null
|
|
30580
|
+
},
|
|
30581
|
+
evidencePartial,
|
|
30582
|
+
summary: ""
|
|
30583
|
+
};
|
|
30584
|
+
report.summary = formatClosureSummary(report);
|
|
30585
|
+
return report;
|
|
30586
|
+
}
|
|
30587
|
+
function splitRepo2(repo) {
|
|
30588
|
+
const parts = repo.split("/");
|
|
30589
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
30590
|
+
throw new QueryReadError("BAD_INPUT", `invalid repo "${repo}" (expected owner/repo)`);
|
|
30591
|
+
}
|
|
30592
|
+
return { owner: parts[0], name: parts[1] };
|
|
30593
|
+
}
|
|
30594
|
+
async function mapPooled(items, limit, worker) {
|
|
30595
|
+
const out = new Array(items.length);
|
|
30596
|
+
let next = 0;
|
|
30597
|
+
const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
30598
|
+
while (next < items.length) {
|
|
30599
|
+
const index = next;
|
|
30600
|
+
next += 1;
|
|
30601
|
+
out[index] = await worker(items[index]);
|
|
30602
|
+
}
|
|
30603
|
+
});
|
|
30604
|
+
await Promise.all(runners);
|
|
30605
|
+
return out;
|
|
30606
|
+
}
|
|
30607
|
+
async function readEvidence(deps, owner, name, item) {
|
|
30608
|
+
try {
|
|
30609
|
+
const resp = await deps.ghJson(prForIssueGraphqlArgs(owner, name, item.number), CLOSURE_RATE_TIMEOUT_MS);
|
|
30610
|
+
return { linkedPrs: extractPrForIssueResponse(resp), readFailed: false };
|
|
30611
|
+
} catch (e) {
|
|
30612
|
+
if (e instanceof QueryReadError && e.code === "NOT_FOUND") {
|
|
30613
|
+
return { linkedPrs: [], readFailed: false };
|
|
30614
|
+
}
|
|
30615
|
+
return { linkedPrs: [], readFailed: true };
|
|
30616
|
+
}
|
|
30617
|
+
}
|
|
30618
|
+
async function runLearningClosureRate(deps, opts = {}) {
|
|
30619
|
+
const repo = opts.repo ?? HUB_REPO;
|
|
30620
|
+
const { owner, name } = splitRepo2(repo);
|
|
30621
|
+
let evidencePartial = false;
|
|
30622
|
+
const perKind = [];
|
|
30623
|
+
for (const spec of LOOP_KINDS2) {
|
|
30624
|
+
const rows = await deps.ghJson(
|
|
30625
|
+
buildIssueListArgs({ label: spec.label, state: "all", limit: LOOP_ITEM_CAP }, repo),
|
|
30626
|
+
CLOSURE_RATE_TIMEOUT_MS
|
|
30627
|
+
);
|
|
30628
|
+
const items = shapeIssueList(rows);
|
|
30629
|
+
const closed = items.filter((item) => String(item.state ?? "").toUpperCase() === "CLOSED");
|
|
30630
|
+
const evidence = await mapPooled(closed, EVIDENCE_CONCURRENCY, (item) => readEvidence(deps, owner, name, item));
|
|
30631
|
+
if (evidence.some((ev) => ev.readFailed)) evidencePartial = true;
|
|
30632
|
+
const evidenceByNumber = new Map(closed.map((item, i) => [item.number, evidence[i]]));
|
|
30633
|
+
const verdicts = items.map(
|
|
30634
|
+
(item) => classifyLoopClosure(item, evidenceByNumber.get(item.number) ?? { linkedPrs: [], readFailed: false })
|
|
30635
|
+
);
|
|
30636
|
+
perKind.push({ spec, verdicts });
|
|
30637
|
+
}
|
|
30638
|
+
return buildClosureReport(repo, perKind, evidencePartial);
|
|
30639
|
+
}
|
|
30640
|
+
function closureRateFail(e) {
|
|
30641
|
+
if (e instanceof QueryReadError) {
|
|
30642
|
+
const code = e.code === "NOT_FOUND" ? ERROR_CODES.ERR_NOT_FOUND : e.code === "NO_AUTH" ? ERROR_CODES.ERR_NO_AUTH : ERROR_CODES.ERR_BAD_ENUM;
|
|
30643
|
+
return fail(`closure-rate: ${e.message}`, code === ERROR_CODES.ERR_BAD_ENUM ? void 0 : { code });
|
|
30644
|
+
}
|
|
30645
|
+
const err = e;
|
|
30646
|
+
return fail(`closure-rate: ${(err.stderr || err.message || String(e)).trim()}`);
|
|
30647
|
+
}
|
|
30648
|
+
function registerLearningClosureRateCommand(program3) {
|
|
30649
|
+
const deps = queryDeps();
|
|
30650
|
+
withExamples(
|
|
30651
|
+
program3.command("closure-rate").description(
|
|
30652
|
+
"learning closure rate per loop kind (friction, lesson, red-team) computed at read from board + linked-PR/ruling evidence \u2014 a closed loop without a merged PR or a recorded ruling reads as open (#4440)"
|
|
30653
|
+
).option("--repo <owner/repo>", `repo holding the loop items (defaults to ${HUB_REPO}, the central Hub board)`).option("--json", "print the structured LearningClosureReport JSON (default is the human summary)").action(async (o) => {
|
|
30654
|
+
try {
|
|
30655
|
+
const report = await runLearningClosureRate(deps, { repo: o.repo });
|
|
30656
|
+
if (o.json) console.log(JSON.stringify(report, null, 2));
|
|
30657
|
+
else console.log(report.summary);
|
|
30658
|
+
} catch (e) {
|
|
30659
|
+
closureRateFail(e);
|
|
30660
|
+
}
|
|
30661
|
+
}),
|
|
30662
|
+
[
|
|
30663
|
+
"mmi-cli learning closure-rate",
|
|
30664
|
+
"mmi-cli learning closure-rate --repo mutmutco/MMI-Hub --json"
|
|
30665
|
+
],
|
|
30666
|
+
"loop items are read newest-first with a bounded cap of 100 per kind \u2014 a rate over a longer history needs the cap raised, never an unbounded scan"
|
|
30667
|
+
);
|
|
30668
|
+
}
|
|
30669
|
+
|
|
30670
|
+
// src/issue-commands.ts
|
|
30477
30671
|
var ghRunner = async (args, timeoutMs) => (await execFileP2("gh", args, { timeout: timeoutMs })).stdout;
|
|
30478
30672
|
var ReparentConflictError = class extends Error {
|
|
30479
30673
|
constructor(message, payload) {
|
|
@@ -30597,6 +30791,13 @@ async function closeIssue(client, options, deps = {}) {
|
|
|
30597
30791
|
if (options.evidence !== void 0) {
|
|
30598
30792
|
await verifyCloseEvidence(client, options.evidence, repo, parsed.number, reason === "duplicate-of" ? options.duplicateOf : void 0);
|
|
30599
30793
|
}
|
|
30794
|
+
if (reason === "completed" && options.evidence !== void 0) {
|
|
30795
|
+
const ensureLabels = deps.ensureLabels ?? ensureLabelsExist;
|
|
30796
|
+
await ensureLabels([CLOSED_MERGED_LOOP_STATE_LABEL], repo);
|
|
30797
|
+
await client.rest("POST", `repos/${repo}/issues/${parsed.number}/labels`, {
|
|
30798
|
+
body: { labels: [CLOSED_MERGED_LOOP_STATE_LABEL] }
|
|
30799
|
+
});
|
|
30800
|
+
}
|
|
30600
30801
|
await client.rest("PATCH", `repos/${repo}/issues/${parsed.number}`, {
|
|
30601
30802
|
body: { state: "closed", state_reason: stateReason }
|
|
30602
30803
|
});
|
|
@@ -31340,7 +31541,7 @@ function registerDeployCommands(program3) {
|
|
|
31340
31541
|
|
|
31341
31542
|
// src/discovery-commands.ts
|
|
31342
31543
|
var import_node_fs40 = require("node:fs");
|
|
31343
|
-
var
|
|
31544
|
+
var import_node_os17 = require("node:os");
|
|
31344
31545
|
var import_node_path37 = require("node:path");
|
|
31345
31546
|
var GC_GH_TIMEOUT_MS2 = 2e4;
|
|
31346
31547
|
async function collectStatus() {
|
|
@@ -31541,7 +31742,7 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
31541
31742
|
else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
|
|
31542
31743
|
else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
|
|
31543
31744
|
}
|
|
31544
|
-
const home = (0,
|
|
31745
|
+
const home = (0, import_node_os17.homedir)();
|
|
31545
31746
|
const plugin = onboardPluginGate({
|
|
31546
31747
|
readKnown: () => readFileSyncSafe((0, import_node_path37.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs40.readFileSync),
|
|
31547
31748
|
readSettings: () => readFileSyncSafe((0, import_node_path37.join)(home, ".claude", "settings.json"), import_node_fs40.readFileSync)
|
|
@@ -32306,173 +32507,6 @@ function registerSessionReport(program3) {
|
|
|
32306
32507
|
});
|
|
32307
32508
|
}
|
|
32308
32509
|
|
|
32309
|
-
// src/learning-closure-rate.ts
|
|
32310
|
-
var CLOSURE_RATE_TIMEOUT_MS = 2e4;
|
|
32311
|
-
var LOOP_ITEM_CAP = 100;
|
|
32312
|
-
var EVIDENCE_CONCURRENCY = 4;
|
|
32313
|
-
var RED_TEAM_FINDING_LABEL2 = "red-team";
|
|
32314
|
-
var RULING_LOOP_STATE_LABELS = ["loop-state:closed-deferred", "loop-state:closed-invalid"];
|
|
32315
|
-
var CLOSED_MERGED_LOOP_STATE_LABEL = "loop-state:closed-merged";
|
|
32316
|
-
var LOOP_KINDS2 = [
|
|
32317
|
-
{ kind: "friction", label: REPORT_LABEL },
|
|
32318
|
-
{ kind: "lesson", label: SKILL_LESSON_LABEL },
|
|
32319
|
-
{ kind: "red-team", label: RED_TEAM_FINDING_LABEL2 }
|
|
32320
|
-
];
|
|
32321
|
-
function prIsMerged(pr2) {
|
|
32322
|
-
return String(pr2.state ?? "").toUpperCase() === "MERGED";
|
|
32323
|
-
}
|
|
32324
|
-
function mergedPrsOf(linkedPrs) {
|
|
32325
|
-
return linkedPrs.filter(prIsMerged);
|
|
32326
|
-
}
|
|
32327
|
-
function hasRecordedRuling(labels) {
|
|
32328
|
-
return labels.some((label) => RULING_LOOP_STATE_LABELS.includes(label));
|
|
32329
|
-
}
|
|
32330
|
-
function classifyLoopClosure(item, evidence) {
|
|
32331
|
-
if (String(item.state ?? "").toUpperCase() !== "CLOSED") return "open";
|
|
32332
|
-
if (mergedPrsOf(evidence.linkedPrs).length > 0) return "closed";
|
|
32333
|
-
if (item.labels.includes(CLOSED_MERGED_LOOP_STATE_LABEL)) return "closed";
|
|
32334
|
-
if (hasRecordedRuling(item.labels)) return "closed";
|
|
32335
|
-
return "closed-no-evidence";
|
|
32336
|
-
}
|
|
32337
|
-
var round3 = (x) => Math.round(x * 1e3) / 1e3;
|
|
32338
|
-
function computeLoopKindRate(spec, verdicts) {
|
|
32339
|
-
const numerator = verdicts.filter((v) => v === "closed").length;
|
|
32340
|
-
const unknownEvidence = verdicts.filter((v) => v === "closed-no-evidence").length;
|
|
32341
|
-
const denominator = verdicts.length;
|
|
32342
|
-
return {
|
|
32343
|
-
kind: spec.kind,
|
|
32344
|
-
label: spec.label,
|
|
32345
|
-
numerator,
|
|
32346
|
-
denominator,
|
|
32347
|
-
unknownEvidence,
|
|
32348
|
-
rate: denominator > 0 ? round3(numerator / denominator) : null
|
|
32349
|
-
};
|
|
32350
|
-
}
|
|
32351
|
-
function fmtRate(rate) {
|
|
32352
|
-
return rate === null ? "\u2014" : rate.toFixed(3);
|
|
32353
|
-
}
|
|
32354
|
-
function formatClosureSummary(report) {
|
|
32355
|
-
const kindWidth = Math.max(...report.kinds.map((k) => k.kind.length));
|
|
32356
|
-
const labelWidth = Math.max(...report.kinds.map((k) => k.label.length));
|
|
32357
|
-
const lines = [`learning closure rate \u2014 ${report.repo} (computed at read; #4440)`];
|
|
32358
|
-
for (const k of report.kinds) {
|
|
32359
|
-
const head = `${k.kind.padEnd(kindWidth)} (label ${k.label.padEnd(labelWidth)})`;
|
|
32360
|
-
const body = k.denominator === 0 ? "no loop items" : `${k.numerator}/${k.denominator} closed \xB7 ${k.unknownEvidence} unknown evidence \xB7 rate ${fmtRate(k.rate)}`;
|
|
32361
|
-
lines.push(` ${head}: ${body}`);
|
|
32362
|
-
}
|
|
32363
|
-
const t = report.totals;
|
|
32364
|
-
lines.push(
|
|
32365
|
-
` ${"total".padEnd(kindWidth)}: ${t.numerator}/${t.denominator} closed \xB7 ${t.unknownEvidence} unknown evidence \xB7 rate ${fmtRate(t.rate)}`,
|
|
32366
|
-
"A closed loop without a merged PR or a recorded ruling reads as open."
|
|
32367
|
-
);
|
|
32368
|
-
if (report.evidencePartial) {
|
|
32369
|
-
lines.push("note: at least one closed item had an unreadable linked-PR read \u2014 counted open (unknown evidence).");
|
|
32370
|
-
}
|
|
32371
|
-
return lines.join("\n");
|
|
32372
|
-
}
|
|
32373
|
-
function buildClosureReport(repo, perKind, evidencePartial) {
|
|
32374
|
-
const kinds = perKind.map(({ spec, verdicts }) => computeLoopKindRate(spec, verdicts));
|
|
32375
|
-
const numerator = kinds.reduce((acc, k) => acc + k.numerator, 0);
|
|
32376
|
-
const denominator = kinds.reduce((acc, k) => acc + k.denominator, 0);
|
|
32377
|
-
const unknownEvidence = kinds.reduce((acc, k) => acc + k.unknownEvidence, 0);
|
|
32378
|
-
const report = {
|
|
32379
|
-
repo,
|
|
32380
|
-
kinds,
|
|
32381
|
-
totals: {
|
|
32382
|
-
numerator,
|
|
32383
|
-
denominator,
|
|
32384
|
-
unknownEvidence,
|
|
32385
|
-
rate: denominator > 0 ? round3(numerator / denominator) : null
|
|
32386
|
-
},
|
|
32387
|
-
evidencePartial,
|
|
32388
|
-
summary: ""
|
|
32389
|
-
};
|
|
32390
|
-
report.summary = formatClosureSummary(report);
|
|
32391
|
-
return report;
|
|
32392
|
-
}
|
|
32393
|
-
function splitRepo2(repo) {
|
|
32394
|
-
const parts = repo.split("/");
|
|
32395
|
-
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
32396
|
-
throw new QueryReadError("BAD_INPUT", `invalid repo "${repo}" (expected owner/repo)`);
|
|
32397
|
-
}
|
|
32398
|
-
return { owner: parts[0], name: parts[1] };
|
|
32399
|
-
}
|
|
32400
|
-
async function mapPooled(items, limit, worker) {
|
|
32401
|
-
const out = new Array(items.length);
|
|
32402
|
-
let next = 0;
|
|
32403
|
-
const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
32404
|
-
while (next < items.length) {
|
|
32405
|
-
const index = next;
|
|
32406
|
-
next += 1;
|
|
32407
|
-
out[index] = await worker(items[index]);
|
|
32408
|
-
}
|
|
32409
|
-
});
|
|
32410
|
-
await Promise.all(runners);
|
|
32411
|
-
return out;
|
|
32412
|
-
}
|
|
32413
|
-
async function readEvidence(deps, owner, name, item) {
|
|
32414
|
-
try {
|
|
32415
|
-
const resp = await deps.ghJson(prForIssueGraphqlArgs(owner, name, item.number), CLOSURE_RATE_TIMEOUT_MS);
|
|
32416
|
-
return { linkedPrs: extractPrForIssueResponse(resp), readFailed: false };
|
|
32417
|
-
} catch (e) {
|
|
32418
|
-
if (e instanceof QueryReadError && e.code === "NOT_FOUND") {
|
|
32419
|
-
return { linkedPrs: [], readFailed: false };
|
|
32420
|
-
}
|
|
32421
|
-
return { linkedPrs: [], readFailed: true };
|
|
32422
|
-
}
|
|
32423
|
-
}
|
|
32424
|
-
async function runLearningClosureRate(deps, opts = {}) {
|
|
32425
|
-
const repo = opts.repo ?? HUB_REPO;
|
|
32426
|
-
const { owner, name } = splitRepo2(repo);
|
|
32427
|
-
let evidencePartial = false;
|
|
32428
|
-
const perKind = [];
|
|
32429
|
-
for (const spec of LOOP_KINDS2) {
|
|
32430
|
-
const rows = await deps.ghJson(
|
|
32431
|
-
buildIssueListArgs({ label: spec.label, state: "all", limit: LOOP_ITEM_CAP }, repo),
|
|
32432
|
-
CLOSURE_RATE_TIMEOUT_MS
|
|
32433
|
-
);
|
|
32434
|
-
const items = shapeIssueList(rows);
|
|
32435
|
-
const closed = items.filter((item) => String(item.state ?? "").toUpperCase() === "CLOSED");
|
|
32436
|
-
const evidence = await mapPooled(closed, EVIDENCE_CONCURRENCY, (item) => readEvidence(deps, owner, name, item));
|
|
32437
|
-
if (evidence.some((ev) => ev.readFailed)) evidencePartial = true;
|
|
32438
|
-
const evidenceByNumber = new Map(closed.map((item, i) => [item.number, evidence[i]]));
|
|
32439
|
-
const verdicts = items.map(
|
|
32440
|
-
(item) => classifyLoopClosure(item, evidenceByNumber.get(item.number) ?? { linkedPrs: [], readFailed: false })
|
|
32441
|
-
);
|
|
32442
|
-
perKind.push({ spec, verdicts });
|
|
32443
|
-
}
|
|
32444
|
-
return buildClosureReport(repo, perKind, evidencePartial);
|
|
32445
|
-
}
|
|
32446
|
-
function closureRateFail(e) {
|
|
32447
|
-
if (e instanceof QueryReadError) {
|
|
32448
|
-
const code = e.code === "NOT_FOUND" ? ERROR_CODES.ERR_NOT_FOUND : e.code === "NO_AUTH" ? ERROR_CODES.ERR_NO_AUTH : ERROR_CODES.ERR_BAD_ENUM;
|
|
32449
|
-
return fail(`closure-rate: ${e.message}`, code === ERROR_CODES.ERR_BAD_ENUM ? void 0 : { code });
|
|
32450
|
-
}
|
|
32451
|
-
const err = e;
|
|
32452
|
-
return fail(`closure-rate: ${(err.stderr || err.message || String(e)).trim()}`);
|
|
32453
|
-
}
|
|
32454
|
-
function registerLearningClosureRateCommand(program3) {
|
|
32455
|
-
const deps = queryDeps();
|
|
32456
|
-
withExamples(
|
|
32457
|
-
program3.command("closure-rate").description(
|
|
32458
|
-
"learning closure rate per loop kind (friction, lesson, red-team) computed at read from board + linked-PR/ruling evidence \u2014 a closed loop without a merged PR or a recorded ruling reads as open (#4440)"
|
|
32459
|
-
).option("--repo <owner/repo>", `repo holding the loop items (defaults to ${HUB_REPO}, the central Hub board)`).option("--json", "print the structured LearningClosureReport JSON (default is the human summary)").action(async (o) => {
|
|
32460
|
-
try {
|
|
32461
|
-
const report = await runLearningClosureRate(deps, { repo: o.repo });
|
|
32462
|
-
if (o.json) console.log(JSON.stringify(report, null, 2));
|
|
32463
|
-
else console.log(report.summary);
|
|
32464
|
-
} catch (e) {
|
|
32465
|
-
closureRateFail(e);
|
|
32466
|
-
}
|
|
32467
|
-
}),
|
|
32468
|
-
[
|
|
32469
|
-
"mmi-cli learning closure-rate",
|
|
32470
|
-
"mmi-cli learning closure-rate --repo mutmutco/MMI-Hub --json"
|
|
32471
|
-
],
|
|
32472
|
-
"loop items are read newest-first with a bounded cap of 100 per kind \u2014 a rate over a longer history needs the cap raised, never an unbounded scan"
|
|
32473
|
-
);
|
|
32474
|
-
}
|
|
32475
|
-
|
|
32476
32510
|
// ../infra/src/fleet-health.ts
|
|
32477
32511
|
function uniqueRepos(repos) {
|
|
32478
32512
|
const unique = /* @__PURE__ */ new Map();
|
|
@@ -32703,10 +32737,6 @@ var surfaces_default = {
|
|
|
32703
32737
|
releaseMetadata: {
|
|
32704
32738
|
ownerPath: "surfaces.json",
|
|
32705
32739
|
bomPath: "distribution-bom.json"
|
|
32706
|
-
},
|
|
32707
|
-
soul: {
|
|
32708
|
-
ownerPath: "prompts/soul.md",
|
|
32709
|
-
sourceSurfaceId: "mmi-soul"
|
|
32710
32740
|
}
|
|
32711
32741
|
},
|
|
32712
32742
|
agentSurfaces: [
|
|
@@ -32718,7 +32748,6 @@ var surfaces_default = {
|
|
|
32718
32748
|
"mmi-claude-plugin",
|
|
32719
32749
|
"mmi-claude-marketplace",
|
|
32720
32750
|
"mmi-skills",
|
|
32721
|
-
"mmi-soul",
|
|
32722
32751
|
"mmi-hook-policy",
|
|
32723
32752
|
"mmi-hooks",
|
|
32724
32753
|
"mmi-cli"
|
|
@@ -32733,14 +32762,6 @@ var surfaces_default = {
|
|
|
32733
32762
|
sourcePath: "skills",
|
|
32734
32763
|
targetPath: "packages/claude-plugin/skills"
|
|
32735
32764
|
},
|
|
32736
|
-
{
|
|
32737
|
-
mode: "files",
|
|
32738
|
-
sourcePath: "prompts",
|
|
32739
|
-
targetPath: "packages/claude-plugin/prompts",
|
|
32740
|
-
include: [
|
|
32741
|
-
"soul.md"
|
|
32742
|
-
]
|
|
32743
|
-
},
|
|
32744
32765
|
{
|
|
32745
32766
|
mode: "files",
|
|
32746
32767
|
sourcePath: "hooks",
|
|
@@ -32854,7 +32875,6 @@ var surfaces_default = {
|
|
|
32854
32875
|
artifactIds: [
|
|
32855
32876
|
"mmi-codex-plugin",
|
|
32856
32877
|
"mmi-skills",
|
|
32857
|
-
"mmi-soul",
|
|
32858
32878
|
"mmi-hook-policy",
|
|
32859
32879
|
"mmi-cli"
|
|
32860
32880
|
],
|
|
@@ -32868,14 +32888,6 @@ var surfaces_default = {
|
|
|
32868
32888
|
sourcePath: "skills",
|
|
32869
32889
|
targetPath: "packages/codex-plugin/skills"
|
|
32870
32890
|
},
|
|
32871
|
-
{
|
|
32872
|
-
mode: "files",
|
|
32873
|
-
sourcePath: "prompts",
|
|
32874
|
-
targetPath: "packages/codex-plugin/prompts",
|
|
32875
|
-
include: [
|
|
32876
|
-
"soul.md"
|
|
32877
|
-
]
|
|
32878
|
-
},
|
|
32879
32891
|
{
|
|
32880
32892
|
mode: "files",
|
|
32881
32893
|
sourcePath: "hooks",
|
|
@@ -32989,7 +33001,6 @@ var surfaces_default = {
|
|
|
32989
33001
|
artifactIds: [
|
|
32990
33002
|
"mmi-kimi-plugin",
|
|
32991
33003
|
"mmi-skills",
|
|
32992
|
-
"mmi-soul",
|
|
32993
33004
|
"mmi-hook-policy",
|
|
32994
33005
|
"mmi-cli"
|
|
32995
33006
|
],
|
|
@@ -33003,14 +33014,6 @@ var surfaces_default = {
|
|
|
33003
33014
|
sourcePath: "skills",
|
|
33004
33015
|
targetPath: "packages/kimi-plugin/skills"
|
|
33005
33016
|
},
|
|
33006
|
-
{
|
|
33007
|
-
mode: "files",
|
|
33008
|
-
sourcePath: "prompts",
|
|
33009
|
-
targetPath: "packages/kimi-plugin/prompts",
|
|
33010
|
-
include: [
|
|
33011
|
-
"soul.md"
|
|
33012
|
-
]
|
|
33013
|
-
},
|
|
33014
33017
|
{
|
|
33015
33018
|
mode: "files",
|
|
33016
33019
|
sourcePath: "scripts",
|
|
@@ -33116,7 +33119,6 @@ var surfaces_default = {
|
|
|
33116
33119
|
artifactIds: [
|
|
33117
33120
|
"mmi-cursor-plugin",
|
|
33118
33121
|
"mmi-skills",
|
|
33119
|
-
"mmi-soul",
|
|
33120
33122
|
"mmi-hook-policy",
|
|
33121
33123
|
"mmi-cli"
|
|
33122
33124
|
],
|
|
@@ -33130,14 +33132,6 @@ var surfaces_default = {
|
|
|
33130
33132
|
sourcePath: "skills",
|
|
33131
33133
|
targetPath: "packages/cursor-plugin/skills"
|
|
33132
33134
|
},
|
|
33133
|
-
{
|
|
33134
|
-
mode: "files",
|
|
33135
|
-
sourcePath: "prompts",
|
|
33136
|
-
targetPath: "packages/cursor-plugin/prompts",
|
|
33137
|
-
include: [
|
|
33138
|
-
"soul.md"
|
|
33139
|
-
]
|
|
33140
|
-
},
|
|
33141
33135
|
{
|
|
33142
33136
|
mode: "files",
|
|
33143
33137
|
sourcePath: "hooks",
|
|
@@ -33250,7 +33244,6 @@ var surfaces_default = {
|
|
|
33250
33244
|
displayName: "Kilo Code",
|
|
33251
33245
|
lifecycle: "active",
|
|
33252
33246
|
artifactIds: [
|
|
33253
|
-
"mmi-soul",
|
|
33254
33247
|
"mmi-kilo-plugin",
|
|
33255
33248
|
"mmi-kilo-skills",
|
|
33256
33249
|
"mmi-hook-policy",
|
|
@@ -33269,14 +33262,6 @@ var surfaces_default = {
|
|
|
33269
33262
|
"_"
|
|
33270
33263
|
]
|
|
33271
33264
|
},
|
|
33272
|
-
{
|
|
33273
|
-
mode: "files",
|
|
33274
|
-
sourcePath: "prompts",
|
|
33275
|
-
targetPath: ".kilo-plugin/prompts",
|
|
33276
|
-
include: [
|
|
33277
|
-
"soul.md"
|
|
33278
|
-
]
|
|
33279
|
-
},
|
|
33280
33265
|
{
|
|
33281
33266
|
mode: "files",
|
|
33282
33267
|
sourcePath: "scripts",
|
|
@@ -33362,7 +33347,6 @@ var surfaces_default = {
|
|
|
33362
33347
|
artifactIds: [
|
|
33363
33348
|
"mmi-pi-plugin",
|
|
33364
33349
|
"mmi-skills",
|
|
33365
|
-
"mmi-soul",
|
|
33366
33350
|
"mmi-cli",
|
|
33367
33351
|
"mmi-hook-policy"
|
|
33368
33352
|
],
|
|
@@ -33379,14 +33363,6 @@ var surfaces_default = {
|
|
|
33379
33363
|
"_"
|
|
33380
33364
|
]
|
|
33381
33365
|
},
|
|
33382
|
-
{
|
|
33383
|
-
mode: "files",
|
|
33384
|
-
sourcePath: "prompts",
|
|
33385
|
-
targetPath: ".pi-plugin/prompts",
|
|
33386
|
-
include: [
|
|
33387
|
-
"soul.md"
|
|
33388
|
-
]
|
|
33389
|
-
},
|
|
33390
33366
|
{
|
|
33391
33367
|
mode: "files",
|
|
33392
33368
|
sourcePath: "pi-plugin/extensions",
|
|
@@ -33481,7 +33457,6 @@ var surfaces_default = {
|
|
|
33481
33457
|
artifactIds: [
|
|
33482
33458
|
"mmi-hermes-plugin",
|
|
33483
33459
|
"mmi-skills",
|
|
33484
|
-
"mmi-soul",
|
|
33485
33460
|
"mmi-cli",
|
|
33486
33461
|
"mmi-hook-policy"
|
|
33487
33462
|
],
|
|
@@ -33495,14 +33470,6 @@ var surfaces_default = {
|
|
|
33495
33470
|
sourcePath: "skills",
|
|
33496
33471
|
targetPath: "packages/hermes-plugin/skills"
|
|
33497
33472
|
},
|
|
33498
|
-
{
|
|
33499
|
-
mode: "files",
|
|
33500
|
-
sourcePath: "prompts",
|
|
33501
|
-
targetPath: "packages/hermes-plugin/prompts",
|
|
33502
|
-
include: [
|
|
33503
|
-
"soul.md"
|
|
33504
|
-
]
|
|
33505
|
-
},
|
|
33506
33473
|
{
|
|
33507
33474
|
mode: "files",
|
|
33508
33475
|
sourcePath: "scripts",
|
|
@@ -33622,39 +33589,6 @@ var surfaces_default = {
|
|
|
33622
33589
|
],
|
|
33623
33590
|
publishVisibility: "public"
|
|
33624
33591
|
},
|
|
33625
|
-
{
|
|
33626
|
-
id: "mmi-soul",
|
|
33627
|
-
classification: "capability",
|
|
33628
|
-
kind: "spine",
|
|
33629
|
-
ownerPath: "prompts/soul.md",
|
|
33630
|
-
deliveryPath: "prompts/soul.md",
|
|
33631
|
-
delivery: "plugin-install",
|
|
33632
|
-
applicability: "plugin-enabled agent surfaces; opaque JervCode soul mirror, not a host-invocable prompt.",
|
|
33633
|
-
versionCoordinated: true,
|
|
33634
|
-
versionPaths: [
|
|
33635
|
-
{
|
|
33636
|
-
path: "cli/package.json",
|
|
33637
|
-
pointer: "version"
|
|
33638
|
-
}
|
|
33639
|
-
],
|
|
33640
|
-
artifactIdentity: {
|
|
33641
|
-
kind: "sha256-tree",
|
|
33642
|
-
paths: [
|
|
33643
|
-
"prompts/soul.md"
|
|
33644
|
-
]
|
|
33645
|
-
},
|
|
33646
|
-
verify: [
|
|
33647
|
-
{
|
|
33648
|
-
command: "node",
|
|
33649
|
-
args: [
|
|
33650
|
-
"scripts/check-soul-payload.mjs",
|
|
33651
|
-
"--contract"
|
|
33652
|
-
],
|
|
33653
|
-
expected: "soul payload check: ok"
|
|
33654
|
-
}
|
|
33655
|
-
],
|
|
33656
|
-
publishVisibility: "public"
|
|
33657
|
-
},
|
|
33658
33592
|
{
|
|
33659
33593
|
id: "mmi-claude-plugin",
|
|
33660
33594
|
classification: "packaging",
|
|
@@ -35472,7 +35406,7 @@ function ghAccountCaveat(announcedLogin, accounts) {
|
|
|
35472
35406
|
|
|
35473
35407
|
// src/doctor-io.ts
|
|
35474
35408
|
var import_node_fs41 = require("node:fs");
|
|
35475
|
-
var
|
|
35409
|
+
var import_node_os18 = require("node:os");
|
|
35476
35410
|
var import_node_path38 = require("node:path");
|
|
35477
35411
|
var import_node_child_process18 = require("node:child_process");
|
|
35478
35412
|
var import_node_util8 = require("node:util");
|
|
@@ -35481,7 +35415,7 @@ var MMI_PLUGIN_ID2 = "mmi@mutmutco";
|
|
|
35481
35415
|
function installedClaudePluginVersion() {
|
|
35482
35416
|
try {
|
|
35483
35417
|
const file = JSON.parse(
|
|
35484
|
-
(0, import_node_fs41.readFileSync)((0, import_node_path38.join)((0,
|
|
35418
|
+
(0, import_node_fs41.readFileSync)((0, import_node_path38.join)((0, import_node_os18.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
|
|
35485
35419
|
);
|
|
35486
35420
|
const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
|
|
35487
35421
|
if (versions.length === 0) return void 0;
|
|
@@ -35541,7 +35475,7 @@ function installedSurfacePluginVersion(surface) {
|
|
|
35541
35475
|
const token = surfaceToken(surface);
|
|
35542
35476
|
if (token === "kilo") {
|
|
35543
35477
|
try {
|
|
35544
|
-
const stamp = (0, import_node_fs41.readFileSync)((0, import_node_path38.join)((0,
|
|
35478
|
+
const stamp = (0, import_node_fs41.readFileSync)((0, import_node_path38.join)((0, import_node_os18.homedir)(), ".kilo", ".mmi-kilo-version"), "utf8").trim();
|
|
35545
35479
|
return stamp || void 0;
|
|
35546
35480
|
} catch {
|
|
35547
35481
|
return void 0;
|
|
@@ -35785,7 +35719,7 @@ function envHealLockPath(home) {
|
|
|
35785
35719
|
async function withEnvHealLock(what, run) {
|
|
35786
35720
|
try {
|
|
35787
35721
|
return await withFileLock(
|
|
35788
|
-
envHealLockPath((0,
|
|
35722
|
+
envHealLockPath((0, import_node_os19.homedir)()),
|
|
35789
35723
|
{ staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
|
|
35790
35724
|
run
|
|
35791
35725
|
);
|
|
@@ -35880,7 +35814,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
35880
35814
|
const configRoot = surfaceConfigRoot(surface);
|
|
35881
35815
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
35882
35816
|
const plan = buildPluginCachePlan(
|
|
35883
|
-
(0,
|
|
35817
|
+
(0, import_node_os19.homedir)(),
|
|
35884
35818
|
running,
|
|
35885
35819
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
35886
35820
|
{ configRoot, includeStaging: surface !== "codex" }
|
|
@@ -35908,7 +35842,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
35908
35842
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
35909
35843
|
const installed = installedActivePluginVersion(surface);
|
|
35910
35844
|
const plan = buildPluginCachePlan(
|
|
35911
|
-
(0,
|
|
35845
|
+
(0, import_node_os19.homedir)(),
|
|
35912
35846
|
running,
|
|
35913
35847
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
35914
35848
|
{ configRoot, includeStaging: surface !== "codex", installedVersion: installed }
|
|
@@ -36249,7 +36183,8 @@ function envelopeAwareWriteErr(str) {
|
|
|
36249
36183
|
const invoked = resolveCommandFromArgv(program2, argv);
|
|
36250
36184
|
const positional = TARGET_SELECTOR_FLAGS.has(flag) ? positionalTargetForm(invoked, { flag, argv }) : void 0;
|
|
36251
36185
|
if (argvWantsJson2()) {
|
|
36252
|
-
const
|
|
36186
|
+
const ownFlags = commandOwnLongFlags(invoked);
|
|
36187
|
+
const suggestion = positional ? void 0 : didYouMean(flag, ownFlags) ?? synonymFlagFor(flag, ownFlags);
|
|
36253
36188
|
const corrected = suggestion ? `mmi-cli ${canonicalArgvFor(argv.map((a) => a === flag ? suggestion : a)).join(" ")}` : void 0;
|
|
36254
36189
|
const message = positional ? unknownTargetFlagMessage(flag, positional) : `unknown option '${flag}'`;
|
|
36255
36190
|
process.stderr.write(
|
|
@@ -37961,7 +37896,7 @@ pr.command("ci-policy").description("report merge CI policy: wait-for-checks vs
|
|
|
37961
37896
|
if (o.json) return printLine(JSON.stringify(result));
|
|
37962
37897
|
printLine(`merge CI policy: ${result.policy} (${result.reason})`);
|
|
37963
37898
|
});
|
|
37964
|
-
pr.command("checks-wait <number>").description(`bounded wait for PR
|
|
37899
|
+
pr.command("checks-wait <number>").description(`bounded wait for ALL checks on the PR head, required or not (#5336); skips immediately on no-ci repos (#1432), fails immediately on a CONFLICTING PR \u2014 GitHub never queues checks for one (#2970). REST-only polling with a pool floor (#3024). Default budget ${PR_CHECKS_TIMEOUT_MS / 6e4}m; --timeout raises it. Exit 1 = a check FAILED or the PR is CONFLICTING, exit ${PR_CHECKS_TIMEOUT_EXIT_CODE} = the wait window expired or the API pool ran dry (re-arm)`).option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--timeout <minutes>", `wait budget in minutes (default ${PR_CHECKS_TIMEOUT_MS / 6e4}) \u2014 raise it for serial self-hosted e2e queues`).action(async (number, o) => {
|
|
37965
37900
|
let timeoutMs;
|
|
37966
37901
|
if (o.timeout !== void 0) {
|
|
37967
37902
|
const minutes = Number(o.timeout);
|
|
@@ -37976,10 +37911,12 @@ pr.command("checks-wait <number>").description(`bounded wait for PR checks; skip
|
|
|
37976
37911
|
const snapshot = snapshotRead.snapshot;
|
|
37977
37912
|
const baseBranch = snapshot.baseRef;
|
|
37978
37913
|
const ciHeadRef = !snapshot.headIsFork && snapshot.headRef ? snapshot.headRef : void 0;
|
|
37979
|
-
const requiredContexts = await fetchRequiredCheckContexts(repo, baseBranch).catch(() => null);
|
|
37980
37914
|
const result = await waitForPrChecks({
|
|
37981
37915
|
resolvePolicy: () => resolveMergeCiPolicyForCheckout(o.repo, ciHeadRef),
|
|
37982
|
-
|
|
37916
|
+
// #5336: ALL checks on the PR head — no required-status scoping here. A non-required check still
|
|
37917
|
+
// pending must hold the wait open, and a non-required red must fail it; #4396's scoping is the
|
|
37918
|
+
// merge paths' contract (`pr land`, `pr merge --wait`), which mirror the GitHub merge button.
|
|
37919
|
+
pollChecks: () => pollRestPrChecks(number, repo),
|
|
37983
37920
|
pollMergeable: () => pollRestPrMergeable(number, repo),
|
|
37984
37921
|
pollRateLimit: () => waitLoopCorePool("pr checks-wait"),
|
|
37985
37922
|
// #3388: on a confirmed red, read the failing runs' annotations so a wall-clock budget kill stops
|
|
@@ -39003,7 +38940,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
39003
38940
|
return;
|
|
39004
38941
|
}
|
|
39005
38942
|
const plan = buildPluginCachePlan(
|
|
39006
|
-
(0,
|
|
38943
|
+
(0, import_node_os19.homedir)(),
|
|
39007
38944
|
running,
|
|
39008
38945
|
pluginCacheFsDeps(configRoot, directoryBytes),
|
|
39009
38946
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
package/dist/repo-index-v4.cjs
CHANGED
|
@@ -371,6 +371,7 @@ var REPO_INDEX_V4_SCHEMA = 4;
|
|
|
371
371
|
var import_node_crypto3 = require("node:crypto");
|
|
372
372
|
var import_node_child_process3 = require("node:child_process");
|
|
373
373
|
var import_node_fs3 = require("node:fs");
|
|
374
|
+
var import_node_os2 = require("node:os");
|
|
374
375
|
var import_node_path4 = require("node:path");
|
|
375
376
|
var V4_MAX_CHUNKS = 1e4;
|
|
376
377
|
var V4_MAX_ARTIFACT_BYTES = 64 * 1024 * 1024;
|
|
@@ -448,22 +449,37 @@ function runEmbedderOnce(cwd, chunks, modelDirectory, createdAt) {
|
|
|
448
449
|
if (!(0, import_node_fs3.existsSync)(file)) return { ok: false, reason: "embeddings-unavailable" };
|
|
449
450
|
const request = { texts: chunks.map((chunk) => ({ id: chunk.id, text: embeddingInput(cwd, chunk) })), maxBatch: V4_EMBED_BATCH };
|
|
450
451
|
const env = { ...process.env, ...modelDirectory ? { MMI_REPO_INDEXER_MODEL_DIR: modelDirectory } : {} };
|
|
451
|
-
const
|
|
452
|
+
const requestDir = (0, import_node_fs3.mkdtempSync)((0, import_node_path4.join)((0, import_node_os2.tmpdir)(), "mmi-repo-index-req-"));
|
|
453
|
+
const requestFile = (0, import_node_path4.join)(requestDir, "request.json");
|
|
454
|
+
(0, import_node_fs3.writeFileSync)(requestFile, JSON.stringify(request));
|
|
455
|
+
let result;
|
|
456
|
+
try {
|
|
457
|
+
result = (0, import_node_child_process3.spawnSync)(process.execPath, [file, requestFile], { encoding: "utf8", windowsHide: true, timeout: V4_EMBED_TIMEOUT_MS, maxBuffer: V4_MAX_ARTIFACT_BYTES, env });
|
|
458
|
+
} finally {
|
|
459
|
+
(0, import_node_fs3.rmSync)(requestDir, { recursive: true, force: true });
|
|
460
|
+
}
|
|
452
461
|
if (result.error || result.status !== 0) {
|
|
453
462
|
const cleanExit = result.error === void 0 && result.signal === void 0 && typeof result.status === "number" && result.status !== 0;
|
|
463
|
+
const stdout = String(result.stdout).trim();
|
|
464
|
+
const stderrTail = String(result.stderr).trim().slice(-400) || void 0;
|
|
454
465
|
let code;
|
|
455
|
-
let stderrTail;
|
|
456
466
|
if (cleanExit) {
|
|
457
467
|
try {
|
|
458
|
-
code = JSON.parse(
|
|
468
|
+
code = JSON.parse(stdout)?.code;
|
|
459
469
|
} catch {
|
|
460
470
|
}
|
|
461
|
-
stderrTail = String(result.stderr).trim().slice(-400) || void 0;
|
|
462
471
|
}
|
|
463
|
-
return {
|
|
472
|
+
return {
|
|
473
|
+
ok: false,
|
|
474
|
+
code,
|
|
475
|
+
stdoutTail: code ? void 0 : stdout.slice(-400) || void 0,
|
|
476
|
+
stderrTail,
|
|
477
|
+
cleanExit,
|
|
478
|
+
detail: result.error?.message ?? result.signal ?? `exit status ${result.status ?? "unknown"}`
|
|
479
|
+
};
|
|
464
480
|
}
|
|
465
481
|
try {
|
|
466
|
-
const response = JSON.parse(result.stdout);
|
|
482
|
+
const response = JSON.parse(String(result.stdout));
|
|
467
483
|
if (!response.ok || !response.provenance || !Array.isArray(response.embeddings)) return { ok: false, reason: "embeddings-unavailable" };
|
|
468
484
|
const provenance = {
|
|
469
485
|
provider: response.provenance.provider,
|
|
@@ -490,8 +506,9 @@ function runEmbedder(cwd, chunks, modelDirectory, createdAt) {
|
|
|
490
506
|
}
|
|
491
507
|
const runner = last;
|
|
492
508
|
const code = runner.code ? ` code=${runner.code}` : "";
|
|
509
|
+
const stdout = runner.stdoutTail ? ` stdout=${runner.stdoutTail}` : "";
|
|
493
510
|
const stderr = runner.stderrTail ? ` stderr=${runner.stderrTail}` : "";
|
|
494
|
-
throw new Error(`repo-index v4 embedding runner failed: ${runner.detail ?? "unknown"}${code}${stderr}`);
|
|
511
|
+
throw new Error(`repo-index v4 embedding runner failed: ${runner.detail ?? "unknown"}${code}${stdout}${stderr}`);
|
|
495
512
|
}
|
|
496
513
|
async function buildRepoIndexV4(cwd, repo, opts = {}) {
|
|
497
514
|
const { commit, defaultBranch, createdAt } = gitInfo(cwd);
|
package/package.json
CHANGED