@mutmutco/codex-plugin 4.6.32 → 4.6.33

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,6 +1,6 @@
1
1
  {
2
2
  "name": "mmi",
3
- "version": "4.6.32",
3
+ "version": "4.6.33",
4
4
  "mmiCompat": "4.x",
5
5
  "description": "MMI workflow skills and org gates delivery.",
6
6
  "author": {
package/cli/dist/main.cjs CHANGED
@@ -27062,6 +27062,71 @@ function contentPutInputArgs(repo, path2, inputFile) {
27062
27062
  inputFile
27063
27063
  ];
27064
27064
  }
27065
+ var BANK_REQUEST_REPO = "mutmutco/Jerv-Hub";
27066
+ var BANK_REQUEST_LABEL = "bank-request";
27067
+ var BANK_REQUEST_SOURCE = "MMI-Hub#9958";
27068
+ function bankRequestTitle(repoName2) {
27069
+ return `bank-request: coding-agent::${repoName2}`;
27070
+ }
27071
+ function bankRequestBody(fullName) {
27072
+ return `Create the coding-agent memory bank for \`${fullName}\` (asked by \`mmi-cli devops bootstrap apply\`; see ${BANK_REQUEST_SOURCE}).`;
27073
+ }
27074
+ function planBankRequest(fullName, existing) {
27075
+ const parsed = parseOwnerRepo(fullName);
27076
+ const base = { title: bankRequestTitle(parsed.name), label: BANK_REQUEST_LABEL, body: bankRequestBody(parsed.fullName) };
27077
+ if (existing == null) return { ...base, action: "skip", reason: `could not read ${BANK_REQUEST_REPO} issues` };
27078
+ const found = existing.find((issue) => issue?.title === base.title);
27079
+ if (found) {
27080
+ return {
27081
+ ...base,
27082
+ action: "exists",
27083
+ number: found.number,
27084
+ state: found.state ?? "open",
27085
+ url: found.url ?? `https://github.com/${BANK_REQUEST_REPO}/issues/${found.number}`
27086
+ };
27087
+ }
27088
+ return { ...base, action: "create" };
27089
+ }
27090
+ var oneLine = (e) => String(e?.message ?? e).split("\n")[0].trim();
27091
+ function bankRequestManualStep(request, reason) {
27092
+ return `file it by hand at https://github.com/${BANK_REQUEST_REPO}/issues/new \u2014 title "${request.title}", label ${request.label}, body: ${request.body} (${reason})`;
27093
+ }
27094
+ function renderBankRequestPlan(result) {
27095
+ return [
27096
+ "bootstrap apply \u2014 coding-agent memory bank request (dry-run; no issue filed):",
27097
+ ` PLAN file issue "${result.title}" (label ${result.label}) in ${BANK_REQUEST_REPO}`,
27098
+ ` body: ${result.body}`
27099
+ ].join("\n");
27100
+ }
27101
+ function renderBankRequestLine(result) {
27102
+ if (result.status === "opened") {
27103
+ return `memory bank request: ${BANK_REQUEST_REPO}#${result.number} opened \u2014 "${result.title}" (label ${result.label})${result.url ? ` ${result.url}` : ""}`;
27104
+ }
27105
+ if (result.status === "exists") {
27106
+ return `memory bank request: already requested \u2014 ${BANK_REQUEST_REPO}#${result.number} (${result.state})${result.url ? ` ${result.url}` : ""}`;
27107
+ }
27108
+ return `memory bank request: SKIPPED (${result.reason ?? "not attempted"}) \u2014 ${bankRequestManualStep(result, result.reason ?? "not attempted")}`;
27109
+ }
27110
+ async function runBankRequest(fullName, options, deps) {
27111
+ const parsed = parseOwnerRepo(fullName);
27112
+ const request = { title: bankRequestTitle(parsed.name), label: BANK_REQUEST_LABEL, body: bankRequestBody(parsed.fullName) };
27113
+ if (options.dryRun) return { ...request, status: "planned" };
27114
+ let existing;
27115
+ try {
27116
+ existing = await deps.listIssues();
27117
+ } catch (e) {
27118
+ return { ...request, status: "skipped", reason: `could not read ${BANK_REQUEST_REPO} issues: ${oneLine(e)}` };
27119
+ }
27120
+ const plan = planBankRequest(fullName, existing);
27121
+ if (plan.action === "exists") return { ...request, status: "exists", number: plan.number, state: plan.state, url: plan.url };
27122
+ if (plan.action === "skip") return { ...request, status: "skipped", reason: plan.reason };
27123
+ try {
27124
+ const created = await deps.createIssue(request);
27125
+ return { ...request, status: "opened", number: created.number, url: created.url };
27126
+ } catch (e) {
27127
+ return { ...request, status: "skipped", reason: `App issue write failed: ${oneLine(e)}` };
27128
+ }
27129
+ }
27065
27130
 
27066
27131
  // src/train-apply-contracts.ts
27067
27132
  var import_node_fs21 = require("node:fs");
@@ -28301,10 +28366,10 @@ var rollout_plan_default = {
28301
28366
  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)."
28302
28367
  },
28303
28368
  baseline: {
28304
- version: "4.6.32",
28305
- tag: "v4.6.32",
28306
- commit: "0e477e5e2765",
28307
- npm: "@mutmutco/cli@4.6.32"
28369
+ version: "4.6.33",
28370
+ tag: "v4.6.33",
28371
+ commit: "80768b0b2052",
28372
+ npm: "@mutmutco/cli@4.6.33"
28308
28373
  },
28309
28374
  exitCriterion: "fleet-n-of-n",
28310
28375
  hubOnlyShortcut: "forbidden",
@@ -28321,14 +28386,14 @@ var rollout_plan_default = {
28321
28386
  repo: "mutmutco/mmi-hub",
28322
28387
  role: "canary",
28323
28388
  schedule: "train",
28324
- v3Target: "v4.6.32"
28389
+ v3Target: "v4.6.33"
28325
28390
  }
28326
28391
  ],
28327
28392
  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.",
28328
28393
  rollback: {
28329
28394
  independent: true,
28330
- mechanism: "npm dist-tag latest -> 4.6.32 and redeploy the Hub Lambda from tag v4.6.32 (0e477e5e2765); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28331
- v3Target: "v4.6.32 (@mutmutco/cli@4.6.32, tag commit 0e477e5e2765 \u2014 last known-good release carrying the repo-index v4-only contract)"
28395
+ mechanism: "npm dist-tag latest -> 4.6.33 and redeploy the Hub Lambda from tag v4.6.33 (80768b0b2052); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28396
+ v3Target: "v4.6.33 (@mutmutco/cli@4.6.33, tag commit 80768b0b2052 \u2014 last known-good release carrying the repo-index v4-only contract)"
28332
28397
  }
28333
28398
  },
28334
28399
  {
@@ -51508,6 +51573,7 @@ function registerBootstrapCommands(program3) {
51508
51573
  }
51509
51574
  const actions = [];
51510
51575
  const applied = [];
51576
+ let bankRequest = null;
51511
51577
  let applyDeployModel;
51512
51578
  let applyProjectType;
51513
51579
  try {
@@ -51986,6 +52052,48 @@ ${onlyManagedBlock ? `Only the marker-bounded Hub-managed block inside repo-owne
51986
52052
  applied.push(`ddb register ${registerPayload.slug} (failed: ${why})`);
51987
52053
  }
51988
52054
  }
52055
+ if (!onlyTarget) {
52056
+ bankRequest = await runBankRequest(repo, { dryRun: !o.execute }, {
52057
+ listIssues: async () => {
52058
+ const listed = await gh2([
52059
+ "issue",
52060
+ "list",
52061
+ "--repo",
52062
+ BANK_REQUEST_REPO,
52063
+ "--state",
52064
+ "all",
52065
+ "--search",
52066
+ `in:title "${bankRequestTitle(parsedRepo.name)}"`,
52067
+ "--json",
52068
+ "number,title,state,url",
52069
+ "--limit",
52070
+ "50"
52071
+ ]);
52072
+ const rows = JSON.parse(listed.stdout || "[]");
52073
+ if (!Array.isArray(rows)) throw new Error("issue list is not an array");
52074
+ return rows;
52075
+ },
52076
+ createIssue: async (request) => {
52077
+ const out = await gh2([
52078
+ "issue",
52079
+ "create",
52080
+ "--repo",
52081
+ BANK_REQUEST_REPO,
52082
+ "--title",
52083
+ request.title,
52084
+ "--body",
52085
+ request.body,
52086
+ "--label",
52087
+ request.label
52088
+ ]);
52089
+ const url = out.stdout.trim().split("\n").pop()?.trim() ?? "";
52090
+ const number = Number(/(\d+)$/.exec(url)?.[1]);
52091
+ if (!url || !Number.isFinite(number)) throw new Error(`issue create returned no issue URL: ${out.stdout.trim().slice(0, 200)}`);
52092
+ return { number, url };
52093
+ }
52094
+ });
52095
+ if (o.execute) applied.push(renderBankRequestLine(bankRequest));
52096
+ }
51989
52097
  if (o.execute && !onlyTarget) {
51990
52098
  const github = await readBootstrapGitHubFacts(repo, effectiveTrack, controlClient);
51991
52099
  controlDeployFacts = await fetchDeployFactsBySlug(slug, registryClientDeps(await loadConfig()));
@@ -52081,13 +52189,15 @@ ${onlyManagedBlock ? `Only the marker-bounded Hub-managed block inside repo-owne
52081
52189
  return failGraceful(`bootstrap apply: cannot plan labels/environments; no writes made: ${e.message}`);
52082
52190
  }
52083
52191
  }
52084
- if (o.json) console.log(JSON.stringify({ repo, class: o.class, sourceSha: seedSource.sha, only: onlyTarget || null, execute: o.execute, seedDelivery: seedPlan.mode, seedBranch: seedPlan.branch, seedBaseSha: scopedPlan?.baseSha, seedPrUrl, actions, controlPlane: controlRows, labels: ancillaryPlan, environments: environmentPlan, applied, ddbWrites }, null, 2));
52192
+ if (o.json) console.log(JSON.stringify({ repo, class: o.class, sourceSha: seedSource.sha, only: onlyTarget || null, execute: o.execute, seedDelivery: seedPlan.mode, seedBranch: seedPlan.branch, seedBaseSha: scopedPlan?.baseSha, seedPrUrl, actions, controlPlane: controlRows, labels: ancillaryPlan, environments: environmentPlan, bankRequest, applied, ddbWrites }, null, 2));
52085
52193
  else {
52086
52194
  console.log(renderSeedPlan(actions));
52087
52195
  if (controlRows.length) console.log(`
52088
52196
  ${renderBootstrapControlPlan(controlRows)}`);
52089
52197
  if (ancillaryPlan && environmentPlan) console.log(`
52090
52198
  ${renderBootstrapAncillaryPlan(ancillaryPlan, environmentPlan, repoEnvironmentSpecs(repo, effectiveTrack, suiteSlug).filter((spec) => spec.exception).map((spec) => ({ name: spec.name, detail: spec.exception })))}`);
52199
+ if (bankRequest?.status === "planned") console.log(`
52200
+ ${renderBankRequestPlan(bankRequest)}`);
52091
52201
  if (o.execute) console.log(`
52092
52202
  LIVE apply to ${repo}:
52093
52203
  ${applied.join("\n ")}`);
@@ -56455,6 +56565,7 @@ async function verifyCustodyBootstrap(value, api, controller, requiredContexts,
56455
56565
  // src/release-custody.ts
56456
56566
  var RELEASE_CUSTODY_BRANCH = "mmi-release-state";
56457
56567
  var RELEASE_CUSTODY_PATH = "release-custody.json";
56568
+ var HUB_RELEASE_CUSTODY_JOB = "release";
56458
56569
  var ReleaseCustodyError = class extends Error {
56459
56570
  constructor(message2) {
56460
56571
  super("Release custody: " + message2);
@@ -56528,6 +56639,14 @@ function githubCustodyStore(repo, baseSha, api = defaultGitHubClient()) {
56528
56639
  `repos/${repo}/actions/runs/${controller.runId}/attempts/${controller.runAttempt}`
56529
56640
  );
56530
56641
  return run.id === controller.runId && run.run_attempt === controller.runAttempt && run.path === HUB_RELEASE_WORKFLOW && run.status === "completed";
56642
+ },
56643
+ async jobCompleted(controller) {
56644
+ const jobs = await api.rest(
56645
+ "GET",
56646
+ `repos/${repo}/actions/runs/${controller.runId}/attempts/${controller.runAttempt}/jobs?per_page=100`
56647
+ );
56648
+ const job = (jobs?.jobs ?? []).find((row) => row.name === (controller.job ?? HUB_RELEASE_CUSTODY_JOB));
56649
+ return job?.status === "completed" && job.conclusion === "success";
56531
56650
  }
56532
56651
  };
56533
56652
  }
@@ -56546,8 +56665,12 @@ var ReleaseCustodySession = class _ReleaseCustodySession {
56546
56665
  poison;
56547
56666
  static async acquire(store, controller, repo, initialize, prepare) {
56548
56667
  const found = await store.read();
56549
- if (found.state && !await store.terminal(found.state.controller)) {
56550
- throw new ReleaseCustodyError(`previous controller run ${found.state.controller.runId} attempt ${found.state.controller.runAttempt} is not proven terminal`);
56668
+ const prior = found.state?.controller;
56669
+ if (prior) {
56670
+ const handoff = prior.runId === controller.runId && prior.runAttempt === controller.runAttempt;
56671
+ if (!(handoff ? await store.jobCompleted(prior) : await store.terminal(prior))) {
56672
+ throw new ReleaseCustodyError(handoff ? `previous controller ${prior.job ?? HUB_RELEASE_CUSTODY_JOB} job of run ${prior.runId} attempt ${prior.runAttempt} is not proven completed` : `previous controller run ${prior.runId} attempt ${prior.runAttempt} is not proven terminal`);
56673
+ }
56551
56674
  }
56552
56675
  let state = {
56553
56676
  ...found.state ?? { schema: "mmi-release-custody/v1", repo, precutId: (0, import_node_crypto21.randomUUID)(), effects: {}, ...await initialize() },
@@ -56845,7 +56968,7 @@ function withHubReleaseCustody(deps) {
56845
56968
  if (!authority.ok || !authority.train || authority.authenticatedDelegation !== true) {
56846
56969
  throw new ReleaseCustodyError("repository custody requires the server-verified owner-triggered train session");
56847
56970
  }
56848
- const controller = { ...runIdentity, token: (0, import_node_crypto21.randomUUID)() };
56971
+ const controller = { ...runIdentity, token: (0, import_node_crypto21.randomUUID)(), ...process.env.GITHUB_JOB ? { job: process.env.GITHUB_JOB } : {} };
56849
56972
  const raw = localRaw(path2);
56850
56973
  const requiredContexts = () => discoverRequiredCheckContexts(
56851
56974
  deps,
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.6.32",
3
+ "version": "4.6.33",
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/codex-plugin",
3
- "version": "4.6.32",
3
+ "version": "4.6.33",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",
@@ -55,6 +55,8 @@ mmi-cli devops bootstrap apply "$OWNER/$REPO" --class deployable \
55
55
 
56
56
  `tenant-container` repos need a `docker-compose.yml` and Dockerfile building from the shipped source archive (no prebuilt `dist/`); bootstrap seeds both from `skills/bootstrap/seeds/`. The seeded compose is fileless: label `mmi.runtime-env: "true"`, no `env_file`, loopback-only port; deploy injects the stage's vault values (`DEPLOY#<stage>.noEnvFile: true`), so the app reads plain env vars, never self-loads SSM, never ships a `.env`. For an MM-Work module or non-suite web-app with OAuth META, read [reference.md](reference.md) before the first CI/deploy or OAuth provisioning.
57
57
 
58
+ `bootstrap apply --execute` also asks Jerv-Hub for this repo's coding-agent memory bank, by filing one `bank-request: coding-agent::<RepoName>` issue (label `bank-request`) there; if it reports that step SKIPPED with a manual next step, the MMI App could not file it — file that issue by hand at https://github.com/mutmutco/Jerv-Hub/issues/new and carry on.
59
+
58
60
  **Stage port block:** `tenant-container` and `solo-container` need Hub registry `portRange` (`bootstrap verify` fails without it). `bootstrap apply --execute` assigns it; for older META run `mmi-cli stage port-range <Repo>` (idempotent).
59
61
 
60
62
  ## Step 7 — org-managed .gitignore block