@mutmutco/claude-plugin 4.5.235 → 4.5.236

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mmi",
3
3
  "displayName": "MMI",
4
- "version": "4.5.235",
4
+ "version": "4.5.236",
5
5
  "mmiCompat": "4.x",
6
6
  "description": "MMI workflow skills and org gates delivery.",
7
7
  "author": {
package/cli/dist/main.cjs CHANGED
@@ -1216,6 +1216,8 @@ var init_house_map = __esm({
1216
1216
  // allowlisted GitHub REST GET reads for automation (pull files, compare, contents)
1217
1217
  ci: "devops",
1218
1218
  // the CI/gate audit
1219
+ jev: "devops",
1220
+ // #9295: read-only status of the Hub-maintained Jev test-ordering learner
1219
1221
  rcand: "devops",
1220
1222
  release: "devops",
1221
1223
  hotfix: "devops",
@@ -25116,7 +25118,7 @@ function createDocsIndexDeps(repoRoot2) {
25116
25118
  var BLESSED_RUN_WITH_BUDGET_SHA = "5ce541add569e54e7ca96de67a768577d3d604e4";
25117
25119
  var BLESSED_RUNNER_GATE_SHA = "a19e9392e5ad9b0675f02e4304d68dd933fad60f";
25118
25120
  var BLESSED_KIT_AGENT_FILES_SHA = "a8b273ed418e703c0aa501a53ea87228ba28b1f0";
25119
- var BLESSED_JEV_FAILURES_SHA = "0e5b55b9fd45bdf55f791c1f56dafeb42c9fb88c";
25121
+ var BLESSED_JEV_FAILURES_SHA = "d5278c6133318b33727483ddfdfddc8f841e3ef6";
25120
25122
  var BLESSED_RUNBOOK_GUARD_SHA = "e661e0aedc0e58b73c738bf6cdfeac65e5914584";
25121
25123
  var REMOTE_USE = /^mutmutco\/MMI-Hub\/\.github\/actions\/run-with-budget@(\S+)$/;
25122
25124
  var LOCAL_USE = "./.github/actions/run-with-budget";
@@ -25652,6 +25654,15 @@ function gateServicesYaml(services) {
25652
25654
  }
25653
25655
  function gateJevStepsYaml(sha, runtime = "node") {
25654
25656
  if (!/^[0-9a-f]{40}$/.test(sha)) return { GATE_JEV_FETCH_YAML: "", GATE_JEV_REPORT_YAML: "" };
25657
+ const listFiles = runtime === "python" ? `git ls-files -z -- 'test_*.py' '*_test.py' | python3 -c "import sys,json;print(json.dumps([p for p in sys.stdin.read().split(chr(0)) if p]))" > .jerv/jev-test-files.json` : `git ls-files -z -- '*.test.*' '*.spec.*' | node -e "process.stdout.write(JSON.stringify(require('fs').readFileSync(0,'utf8').split('\\0').filter(Boolean)))" > .jerv/jev-test-files.json`;
25658
+ const listStep = [
25659
+ "\n - name: List test files for the Jev plan",
25660
+ "\n if: ${{ steps.development-gate.outputs.reuse != 'true' }}",
25661
+ "\n continue-on-error: true",
25662
+ "\n timeout-minutes: 1",
25663
+ `
25664
+ run: mkdir -p .jerv && ${listFiles}`
25665
+ ].join("");
25655
25666
  const step = (name, cond, mode) => [
25656
25667
  `
25657
25668
  - name: ${name}`,
@@ -25664,13 +25675,14 @@ function gateJevStepsYaml(sha, runtime = "node") {
25664
25675
  "\n with:",
25665
25676
  `
25666
25677
  mode: ${mode}`,
25667
- mode === "report" ? `
25678
+ mode === "outcomes" ? `
25668
25679
  report-format: ${runtime === "python" ? "junit-xml" : "vitest-json"}` : "",
25680
+ mode === "plan" ? "\n plan-files: .jerv/jev-test-files.json" : "",
25669
25681
  "\n token: ${{ github.token }}"
25670
25682
  ].join("");
25671
25683
  return {
25672
- GATE_JEV_FETCH_YAML: step("Fetch Jev recent failures (empty on any fault)", "", "fetch"),
25673
- GATE_JEV_REPORT_YAML: step("Report failing test files to Jev", "failure() && ", "report")
25684
+ GATE_JEV_FETCH_YAML: step("Fetch Jev recent failures (empty on any fault)", "", "fetch") + listStep + step("Plan Jev test order and PR-only skips (full order on any fault)", "", "plan"),
25685
+ GATE_JEV_REPORT_YAML: step("Report test outcomes to Jev", "always() && ", "outcomes")
25674
25686
  };
25675
25687
  }
25676
25688
  function gateExtraStepsYaml(steps) {
@@ -27268,10 +27280,10 @@ var rollout_plan_default = {
27268
27280
  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)."
27269
27281
  },
27270
27282
  baseline: {
27271
- version: "4.5.235",
27272
- tag: "v4.5.235",
27273
- commit: "c92194a19184",
27274
- npm: "@mutmutco/cli@4.5.235"
27283
+ version: "4.5.236",
27284
+ tag: "v4.5.236",
27285
+ commit: "b28d6f0940ce",
27286
+ npm: "@mutmutco/cli@4.5.236"
27275
27287
  },
27276
27288
  exitCriterion: "fleet-n-of-n",
27277
27289
  hubOnlyShortcut: "forbidden",
@@ -27288,14 +27300,14 @@ var rollout_plan_default = {
27288
27300
  repo: "mutmutco/mmi-hub",
27289
27301
  role: "canary",
27290
27302
  schedule: "train",
27291
- v3Target: "v4.5.235"
27303
+ v3Target: "v4.5.236"
27292
27304
  }
27293
27305
  ],
27294
27306
  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.",
27295
27307
  rollback: {
27296
27308
  independent: true,
27297
- mechanism: "npm dist-tag latest -> 4.5.235 and redeploy the Hub Lambda from tag v4.5.235 (c92194a19184); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27298
- v3Target: "v4.5.235 (@mutmutco/cli@4.5.235, tag commit c92194a19184 \u2014 last known-good release carrying the repo-index v4-only contract)"
27309
+ mechanism: "npm dist-tag latest -> 4.5.236 and redeploy the Hub Lambda from tag v4.5.236 (b28d6f0940ce); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
27310
+ v3Target: "v4.5.236 (@mutmutco/cli@4.5.236, tag commit b28d6f0940ce \u2014 last known-good release carrying the repo-index v4-only contract)"
27299
27311
  }
27300
27312
  },
27301
27313
  {
@@ -38463,6 +38475,48 @@ function auditSelfHostedRunnerHygiene(files) {
38463
38475
  }
38464
38476
  return checks;
38465
38477
  }
38478
+ var RUNS_TESTS = /(?:^|[\s;&|(`])(?:vitest|jest|pytest|npm\s+(?:run\s+)?test|npm\s+t|npx\s+(?:vitest|jest)|node\s+--test|mmi-cli\s+tests\b|ci-jev-tests)(?=\s|$)/m;
38479
+ var JEV_ACTION = /(?:^|\/)\.github\/actions\/jev-failures@?([0-9a-fA-F]*)/;
38480
+ function auditJevOutcomes(files) {
38481
+ const checks = [];
38482
+ for (const { path: path2, body } of files) {
38483
+ let doc;
38484
+ try {
38485
+ doc = (0, import_yaml2.parse)(body);
38486
+ } catch {
38487
+ continue;
38488
+ }
38489
+ const jobs = plainRecord(doc) && plainRecord(doc.jobs) ? doc.jobs : {};
38490
+ for (const [id, job] of Object.entries(jobs)) {
38491
+ if (!plainRecord(job) || !Array.isArray(job.steps)) continue;
38492
+ const steps = job.steps.filter(plainRecord);
38493
+ const stepCommand = (s) => typeof s.run === "string" ? s.run : typeof s.uses === "string" && s.uses.includes("run-with-budget") && plainRecord(s.with) && typeof s.with.command === "string" ? s.with.command : "";
38494
+ const jev = steps.filter((s) => typeof s.uses === "string" && JEV_ACTION.test(s.uses));
38495
+ const reports = jev.some((s) => plainRecord(s.with) && s.with.mode === "outcomes" && /\balways\(\)/.test(String(s.if ?? "")));
38496
+ if (!reports && steps.some((s) => RUNS_TESTS.test(stepCommand(s)))) {
38497
+ checks.push({
38498
+ ok: true,
38499
+ severity: "warn",
38500
+ label: `test job reports outcomes to the Jev learner (#9295): ${path2}:${id}`,
38501
+ detail: "this job runs tests but has no jev-failures step with mode: outcomes and if: always(), so the Hub learns nothing from it and cannot order or skip its tests",
38502
+ remediation: `Add after the test step: uses: mutmutco/MMI-Hub/.github/actions/jev-failures@${BLESSED_JEV_FAILURES_SHA} with mode: outcomes and if: always() - see skills/bootstrap/seeds/gate.template.yml`
38503
+ });
38504
+ }
38505
+ for (const s of jev) {
38506
+ const sha = JEV_ACTION.exec(String(s.uses))?.[1]?.toLowerCase();
38507
+ if (!sha || sha === BLESSED_JEV_FAILURES_SHA) continue;
38508
+ checks.push({
38509
+ ok: true,
38510
+ severity: "warn",
38511
+ label: `jev-failures pin is the blessed SHA (#9295): ${path2}:${id}`,
38512
+ detail: `pins ${sha.slice(0, 7)}, blessed is ${BLESSED_JEV_FAILURES_SHA.slice(0, 7)}`,
38513
+ remediation: `Re-pin to mutmutco/MMI-Hub/.github/actions/jev-failures@${BLESSED_JEV_FAILURES_SHA}`
38514
+ });
38515
+ }
38516
+ }
38517
+ }
38518
+ return checks;
38519
+ }
38466
38520
  var PENDING_LANDING_LABEL = "pending PRs landing (#8783)";
38467
38521
  var PENDING_LANDING_LIST_CAP = 50;
38468
38522
  var PENDING_LANDING_STALL_MS = 15 * 60 * 1e3;
@@ -39257,6 +39311,7 @@ async function auditRepoCi(repo, callerDeps) {
39257
39311
  checks.push({ ok: false, label: "runner workflow source is readable (#8958)", detail: e instanceof WorkflowSourceError ? e.message : "workflow source: read-failed" });
39258
39312
  }
39259
39313
  checks.push(...auditSelfHostedRunnerHygiene(workflows));
39314
+ checks.push(...auditJevOutcomes(workflows));
39260
39315
  if (repoClass !== "hub") checks.push(...await auditSharedActionPins(workflows, deps));
39261
39316
  } else {
39262
39317
  checks.push({ ok: false, label: "runner workflow source is readable (#8958)", detail: "workflow source inventory unreadable" });
@@ -39952,7 +40007,7 @@ var PRIMARY_GROUPS = [
39952
40007
  ["Setup and support", ["bootstrap", "secrets", "docs", "tests", "spawn", "dist"]],
39953
40008
  ["Coordinate and improve", ["wave", "report", "skill-lesson", "closure-rate"]]
39954
40009
  ];
39955
- var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["oauth", "org", "runtime", "plugin", "packages", "github", "archive-prune", "intercom"]);
40010
+ var OPERATIONAL_TOP_LEVEL = /* @__PURE__ */ new Set(["oauth", "org", "runtime", "plugin", "packages", "github", "archive-prune", "intercom", "jev"]);
39956
40011
  var CAMPAIGN_ORCHESTRATOR_TOP_LEVEL = /* @__PURE__ */ new Set(["pickup", "read"]);
39957
40012
  var SUPPORT_PRIMARY = /* @__PURE__ */ new Set(["doctor", "whoami", "commands", "explain", "docs", "tests", "spawn", "dist", "wave", "report", "skill-lesson", "closure-rate"]);
39958
40013
  var TOP_LEVEL_ORDER = /* @__PURE__ */ new Map();
@@ -40006,6 +40061,8 @@ var COMMAND_OWNERSHIP = {
40006
40061
  train: { module_owner: "cli/src/train-commands.ts", consumer: "release-operator" },
40007
40062
  suite: { module_owner: "cli/src/suite-commands.ts", consumer: "release-operator" },
40008
40063
  // #7264
40064
+ jev: { module_owner: "cli/src/jev-status.ts", consumer: "release-operator" },
40065
+ // #9295
40009
40066
  packages: { module_owner: "cli/src/packages-adopt-export.ts", consumer: "agent-workflow" },
40010
40067
  // #7833
40011
40068
  bootstrap: { module_owner: "cli/src/bootstrap-commands.ts", consumer: "repo-bootstrap" },
@@ -61134,6 +61191,52 @@ function suiteStatusDeps(github, registry2) {
61134
61191
  };
61135
61192
  }
61136
61193
 
61194
+ // src/jev-status.ts
61195
+ init_cli_shared();
61196
+ init_fetch_retry();
61197
+ init_client_version();
61198
+ var JEV_NOT_DEPLOYED = "learner status not deployed yet (the Hub has no /ci/jev/status route)";
61199
+ async function readJevStatus(deps, repo) {
61200
+ if (!deps.baseUrl) return { ok: false, reason: "unavailable", detail: "no Hub API URL" };
61201
+ const token = await deps.token().catch(() => void 0);
61202
+ if (!token) return { ok: false, reason: "unavailable", detail: "no Hub session token (run `gh auth login`)" };
61203
+ try {
61204
+ const res = await fetchWithRetry(deps.fetch ?? fetch, `${deps.baseUrl.replace(/\/$/, "")}/ci/jev/status`, {
61205
+ method: "GET",
61206
+ headers: { ...clientVersionHeaders(), Authorization: `Bearer ${token}` }
61207
+ }, { attempts: 2, timeoutMs: deps.timeoutMs ?? 8e3, sleep: deps.retrySleep });
61208
+ if (res.status === 404) return { ok: false, reason: "not-deployed", detail: JEV_NOT_DEPLOYED };
61209
+ if (!res.ok) return { ok: false, reason: "unavailable", detail: `Hub answered HTTP ${res.status}` };
61210
+ const body = await res.json().catch(() => null);
61211
+ const repos = body?.repositories;
61212
+ if (!Array.isArray(repos)) return { ok: false, reason: "unavailable", detail: "Hub answer was not a repo list" };
61213
+ return { ok: true, repos: repo ? repos.filter((r) => r.repository.toLowerCase() === repo.toLowerCase()) : repos };
61214
+ } catch (e) {
61215
+ return { ok: false, reason: "unavailable", detail: e.message };
61216
+ }
61217
+ }
61218
+ var pct = (n) => `${Math.round(n * 1e3) / 10}%`;
61219
+ function formatJevStatus(read) {
61220
+ if (!read.ok) return read.reason === "not-deployed" ? `Jev: ${read.detail}.` : `Jev: learner status unavailable - ${read.detail}.`;
61221
+ if (!read.repos.length) return "Jev: the learner has not learned from any repo yet.";
61222
+ return read.repos.map((r) => {
61223
+ const gain = r.medianFirstFailureGain == null ? "first-failure gain not measured yet" : `first failure ${pct(r.medianFirstFailureGain)} earlier (median)`;
61224
+ const shadow = r.shadow.active ? `skipping on PRs is ON (miss rate ${pct(r.shadow.missRate)} over ${r.shadow.runs} shadow runs)` : `skipping on PRs is OFF (${r.shadow.runs} shadow runs, miss rate ${pct(r.shadow.missRate)}; needs 30 runs at 1% or less)`;
61225
+ return `${r.repository}: learned from ${r.runsLearned} runs, ${r.filesTracked} test files; ${shadow}; ${r.prSkipShare30d == null ? "no PR runs in 30 days" : `${pct(r.prSkipShare30d)} of PR tests skipped in 30 days`}; ${gain}; updated ${r.updatedAt ? new Date(r.updatedAt).toISOString() : "never"}`;
61226
+ }).join("\n");
61227
+ }
61228
+ function registerJevCommands(program3) {
61229
+ const jev = program3.command("jev").description("the Hub-maintained Jev test-ordering learner, read-only (#9295)");
61230
+ jev.command("status").description("per repo: runs learned, whether PR skipping is on, miss rate, skip share, first-failure gain, last update").option("--repo <owner/repo>", "one repo only").option("--json", "structured output").action(async (o) => {
61231
+ try {
61232
+ const read = await readJevStatus(registryClientDeps(await loadConfig()), o.repo);
61233
+ console.log(o.json ? JSON.stringify(read, null, 2) : formatJevStatus(read));
61234
+ } catch (e) {
61235
+ fail(`jev status: ${e.message}`);
61236
+ }
61237
+ });
61238
+ }
61239
+
61137
61240
  // src/packages-adopt-export.ts
61138
61241
  var import_node_child_process19 = require("node:child_process");
61139
61242
  var import_node_fs53 = require("node:fs");
@@ -69559,6 +69662,7 @@ registerDeployCommands(program2);
69559
69662
  registerSuiteCommands(program2);
69560
69663
  registerIntercomGuestCommands(program2);
69561
69664
  registerPackagesCommands(program2);
69665
+ registerJevCommands(program2);
69562
69666
  registerDiscoveryCommands(program2);
69563
69667
  registerExplainCommand(program2);
69564
69668
  registerPrLifecycleCommands(program2);
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.5.235",
3
+ "version": "4.5.236",
4
4
  "description": "MMI Future CLI — the org dev toolbox and shared cross-IDE engine for every registry-declared MMI coding surface.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/claude-plugin",
3
- "version": "4.5.235",
3
+ "version": "4.5.236",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",
@@ -212,13 +212,18 @@ jobs:
212
212
  # of squatting a runner lane for GitHub's 6h default. ci-audit + the release train enforce this step.
213
213
  # #9293: PRs fail fast, merge_group and tags run everything. pytest reads PYTEST_ADDOPTS natively; a
214
214
  # Node check script opts in with MMI_FAIL_FAST (`vitest run ${MMI_FAIL_FAST:+--bail=1}`, or
215
- # `--fail-fast` on the org node runner). The Jev fetch/report steps around this one (#9295) render
216
- # only once bootstrap carries a blessed jev-failures pin; they are continue-on-error and never fail it.
215
+ # `--fail-fast` on the org node runner). #9295: on PRs the Jev plan step exports JEV_PYTEST_ARGS
216
+ # (`--ignore=<path>` per skipped file, folded into PYTEST_ADDOPTS) and JEV_VITEST_ARGS; a Node check script
217
+ # opts in to the skips with `vitest run ${MMI_FAIL_FAST:+--bail=1} $MMI_JEV_SKIP_ARGS`. The merge queue
218
+ # never skips. The Jev fetch/plan/outcomes steps around this one (#9295) render
219
+ # only once bootstrap carries a blessed jev-failures pin; they are continue-on-error and never fail it. The
220
+ # outcomes step runs under always() (pass or fail).
217
221
  - uses: mutmutco/MMI-Hub/.github/actions/run-with-budget@{{GATE_BUDGET_SHA}}
218
222
  if: ${{ steps.development-gate.outputs.reuse != 'true' }}
219
223
  env:
220
224
  MMI_FAIL_FAST: ${{ github.event_name == 'pull_request' && '1' || '' }}
221
- PYTEST_ADDOPTS: ${{ github.event_name == 'pull_request' && '--maxfail=1' || '' }}
225
+ PYTEST_ADDOPTS: ${{ github.event_name == 'pull_request' && format('--maxfail=1 {0}', env.JEV_PYTEST_ARGS) || '' }}
226
+ MMI_JEV_SKIP_ARGS: ${{ github.event_name == 'pull_request' && env.JEV_VITEST_ARGS || '' }}
222
227
  with:
223
228
  command: {{GATE_CMD}}
224
229
  max-seconds: {{GATE_MAX_SECONDS}}
@@ -80,10 +80,12 @@ jobs:
80
80
  if: ${{ steps.development-gate.outputs.reuse != 'true' }}
81
81
  uses: mutmutco/MMI-Hub/.github/actions/check-kit-agent-files@{{KIT_AGENT_FILES_SHA}} # #9161: own pin — this action postdates the shared runner pin{{GATE_JEV_FETCH_YAML}}
82
82
  # #9293: PRs fail fast (the module check reads MMI_FAIL_FAST); merge_group and tags run everything.
83
+ # #9295: a module check opts in to Jev PR-only skips with `vitest run $MMI_JEV_SKIP_ARGS` (set on PRs only).
83
84
  - uses: mutmutco/MMI-Hub/.github/actions/run-with-budget@{{GATE_BUDGET_SHA}}
84
85
  if: ${{ steps.development-gate.outputs.reuse != 'true' }}
85
86
  env:
86
87
  MMI_FAIL_FAST: ${{ github.event_name == 'pull_request' && '1' || '' }}
88
+ MMI_JEV_SKIP_ARGS: ${{ github.event_name == 'pull_request' && env.JEV_VITEST_ARGS || '' }}
87
89
  with:
88
90
  command: npm run typecheck && npm run build && npm --prefix module run check
89
91
  max-seconds: {{GATE_MAX_SECONDS}}