@mutmutco/claude-plugin 4.6.44 → 4.6.46

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.6.44",
4
+ "version": "4.6.46",
5
5
  "mmiCompat": "4.x",
6
6
  "description": "MMI workflow skills and org gates delivery.",
7
7
  "author": {
package/cli/dist/main.cjs CHANGED
@@ -28556,10 +28556,10 @@ var rollout_plan_default = {
28556
28556
  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)."
28557
28557
  },
28558
28558
  baseline: {
28559
- version: "4.6.44",
28560
- tag: "v4.6.44",
28561
- commit: "2ce6b7e5afc3",
28562
- npm: "@mutmutco/cli@4.6.44"
28559
+ version: "4.6.46",
28560
+ tag: "v4.6.46",
28561
+ commit: "4623316e6c45",
28562
+ npm: "@mutmutco/cli@4.6.46"
28563
28563
  },
28564
28564
  exitCriterion: "fleet-n-of-n",
28565
28565
  hubOnlyShortcut: "forbidden",
@@ -28576,14 +28576,14 @@ var rollout_plan_default = {
28576
28576
  repo: "mutmutco/mmi-hub",
28577
28577
  role: "canary",
28578
28578
  schedule: "train",
28579
- v3Target: "v4.6.44"
28579
+ v3Target: "v4.6.46"
28580
28580
  }
28581
28581
  ],
28582
28582
  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.",
28583
28583
  rollback: {
28584
28584
  independent: true,
28585
- mechanism: "npm dist-tag latest -> 4.6.44 and redeploy the Hub Lambda from tag v4.6.44 (2ce6b7e5afc3); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28586
- v3Target: "v4.6.44 (@mutmutco/cli@4.6.44, tag commit 2ce6b7e5afc3 \u2014 last known-good release carrying the repo-index v4-only contract)"
28585
+ mechanism: "npm dist-tag latest -> 4.6.46 and redeploy the Hub Lambda from tag v4.6.46 (4623316e6c45); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
28586
+ v3Target: "v4.6.46 (@mutmutco/cli@4.6.46, tag commit 4623316e6c45 \u2014 last known-good release carrying the repo-index v4-only contract)"
28587
28587
  }
28588
28588
  },
28589
28589
  {
@@ -48479,6 +48479,7 @@ var DEPLOY_BUCKET_RE = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;
48479
48479
  var DEPLOY_DISTRIBUTION_ID_RE = /^[A-Z0-9]{5,32}$/;
48480
48480
  var COMPOSE_PROFILE_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;
48481
48481
  var MAX_COMPOSE_PROFILES = 8;
48482
+ var READINESS_PATH_RE = /^\/[A-Za-z0-9/._~-]*$/;
48482
48483
  function buildSetDeployPatch(_slug, input) {
48483
48484
  const clean4 = (v) => typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
48484
48485
  const stage = clean4(input.stage);
@@ -48547,6 +48548,29 @@ function buildSetDeployPatch(_slug, input) {
48547
48548
  }
48548
48549
  composeProfiles = [...seen];
48549
48550
  }
48551
+ const healthUrl = clean4(input.healthUrl);
48552
+ if (input.clearHealthUrl && healthUrl !== void 0) {
48553
+ throw new Error("org project set-deploy: --clear-health-url cannot be combined with --health-url (they contradict)");
48554
+ }
48555
+ if (healthUrl !== void 0) {
48556
+ let u;
48557
+ try {
48558
+ u = new URL(healthUrl);
48559
+ } catch {
48560
+ u = void 0;
48561
+ }
48562
+ const loopback = u?.hostname === "127.0.0.1" || u?.hostname === "localhost";
48563
+ if (!DEPLOY_SHELL_SAFE_RE.test(healthUrl) || !u || u.protocol !== "https:" && !(u.protocol === "http:" && loopback)) {
48564
+ throw new Error(`org project set-deploy: --health-url must be a shell-safe https URL (or loopback http), got ${JSON.stringify(input.healthUrl)}`);
48565
+ }
48566
+ }
48567
+ const readinessPath = clean4(input.readinessPath);
48568
+ if (input.clearReadinessPath && readinessPath !== void 0) {
48569
+ throw new Error("org project set-deploy: --clear-readiness-path cannot be combined with --readiness-path (they contradict)");
48570
+ }
48571
+ if (readinessPath !== void 0 && !READINESS_PATH_RE.test(readinessPath)) {
48572
+ throw new Error(`org project set-deploy: --readiness-path must be an absolute path of [A-Za-z0-9/._~-], got ${JSON.stringify(input.readinessPath)}`);
48573
+ }
48550
48574
  return {
48551
48575
  stage,
48552
48576
  ...substrate !== void 0 ? { substrate } : {},
@@ -48567,7 +48591,10 @@ function buildSetDeployPatch(_slug, input) {
48567
48591
  ...input.noEnvFile !== void 0 ? { noEnvFile: input.noEnvFile } : {},
48568
48592
  // #7353: an explicit `[]` is what the route reads as "clear them"; omitting the key is what it reads as
48569
48593
  // "keep them" — same patch contract as aliases (#2986/#2984).
48570
- ...composeProfiles !== void 0 ? { composeProfiles } : {}
48594
+ ...composeProfiles !== void 0 ? { composeProfiles } : {},
48595
+ // #10096: an explicit null is what the route reads as "remove it"; omitting the key keeps it.
48596
+ ...input.clearHealthUrl ? { healthUrl: null } : healthUrl !== void 0 ? { healthUrl } : {},
48597
+ ...input.clearReadinessPath ? { readinessPath: null } : readinessPath !== void 0 ? { readinessPath } : {}
48571
48598
  };
48572
48599
  }
48573
48600
  var DEPLOY_STAGE_BRANCH = { dev: "development", rc: "rc", main: "main" };
@@ -75246,7 +75273,7 @@ fullTrack.command("readiness <owner/repo>").description("aggregate branch topolo
75246
75273
  console.log(JSON.stringify(report, null, 2));
75247
75274
  if (!report.rcand.canApply) process.exitCode = 1;
75248
75275
  });
75249
- project.command("set-deploy [owner/repo]").description("patch a tenant DEPLOY row \u2014 project-admin may set only --no-env-file/--compose-profiles on their own existing dev/rc row; master may seed/change all coords and main; defaults to the current repo").addOption(new Option("--stage <stage>", "dev | rc | main").makeOptionMandatory().choices(["dev", "rc", "main"])).option("--ssh-host <host>", "the box address the deploy ssh-es into; omit to keep the stored value (required only for a NEW hetzner-ssh row \u2014 `mmi-cli devops runtime box list` finds it)").option("--ssh-user <user>", "ssh user; omit to leave the row unchanged (default root on a new row)").option("--port <port>", "loopback port the container binds / Caddy upstream (1..65535); omit to leave the row unchanged").addOption(new Option("--substrate <substrate>", "hetzner-ssh | s3-cloudfront; omit to leave the row unchanged").choices([...DEPLOY_SUBSTRATES])).option("--deploy-role-arn <arn>", "s3-cloudfront: the scoped OIDC deployer role tenant-deploy.yml assumes for this stage").option("--app-bucket <bucket>", "s3-cloudfront: the S3 bucket the built dist/ is synced into").option("--distribution-id <id>", "s3-cloudfront: the CloudFront distribution invalidated after the sync").option("--distribution-domain <domain>", "s3-cloudfront: the host the post-deploy security-header proof is measured against").option("--deploy-path <path>", "on-box per-stage release root; omit to leave the row unchanged (default /opt/mmi/<slug>/<stage> on a new row)").option("--service <name>", "systemd/compose service name; omit to leave the row unchanged (default the slug on a new row)").option("--domain <domain>", "canonical serving host; omit to leave the row unchanged").option("--alias <domain...>", "extra serving hostname the box Caddy answers (repeatable); omit to leave the stored aliases unchanged").option("--redirect-from <host>", "permanent redirect host or host=target (primary or alias); repeatable", (host, hosts) => [...hosts, host], []).option("--clear-aliases", "remove EVERY serving alias from the row (#2986) \u2014 omitting --alias preserves them, so clearing needs saying out loud").option("--no-env-file <bool>", "set the DEPLOY# fileless flag (true|false) \u2014 own-repo project-admin dev/rc; master main; true = env passthrough with no .env symlink").option("--compose-profiles <profiles>", "comma-separated compose profiles to enable for this stage (e.g. huddles,slack-bridge); omit to leave unchanged").option("--clear-compose-profiles", "remove EVERY compose profile from the row \u2014 omitting --compose-profiles preserves them, so clearing needs saying out loud").option("--force", "explicit recovery override: skip fileless-compose verification only after independent proof").option("--json", "machine-readable output").action(async (repoOrSlug, o) => {
75276
+ project.command("set-deploy [owner/repo]").description("patch a tenant DEPLOY row \u2014 project-admin may set only --no-env-file/--compose-profiles on their own existing dev/rc row; master may seed/change all coords and main; defaults to the current repo").addOption(new Option("--stage <stage>", "dev | rc | main").makeOptionMandatory().choices(["dev", "rc", "main"])).option("--ssh-host <host>", "the box address the deploy ssh-es into; omit to keep the stored value (required only for a NEW hetzner-ssh row \u2014 `mmi-cli devops runtime box list` finds it)").option("--ssh-user <user>", "ssh user; omit to leave the row unchanged (default root on a new row)").option("--port <port>", "loopback port the container binds / Caddy upstream (1..65535); omit to leave the row unchanged").addOption(new Option("--substrate <substrate>", "hetzner-ssh | s3-cloudfront; omit to leave the row unchanged").choices([...DEPLOY_SUBSTRATES])).option("--deploy-role-arn <arn>", "s3-cloudfront: the scoped OIDC deployer role tenant-deploy.yml assumes for this stage").option("--app-bucket <bucket>", "s3-cloudfront: the S3 bucket the built dist/ is synced into").option("--distribution-id <id>", "s3-cloudfront: the CloudFront distribution invalidated after the sync").option("--distribution-domain <domain>", "s3-cloudfront: the host the post-deploy security-header proof is measured against").option("--deploy-path <path>", "on-box per-stage release root; omit to leave the row unchanged (default /opt/mmi/<slug>/<stage> on a new row)").option("--service <name>", "systemd/compose service name; omit to leave the row unchanged (default the slug on a new row)").option("--domain <domain>", "canonical serving host; omit to leave the row unchanged").option("--alias <domain...>", "extra serving hostname the box Caddy answers (repeatable); omit to leave the stored aliases unchanged").option("--redirect-from <host>", "permanent redirect host or host=target (primary or alias); repeatable", (host, hosts) => [...hosts, host], []).option("--clear-aliases", "remove EVERY serving alias from the row (#2986) \u2014 omitting --alias preserves them, so clearing needs saying out loud").option("--no-env-file <bool>", "set the DEPLOY# fileless flag (true|false) \u2014 own-repo project-admin dev/rc; master main; true = env passthrough with no .env symlink").option("--compose-profiles <profiles>", "comma-separated compose profiles to enable for this stage (e.g. huddles,slack-bridge); omit to leave unchanged").option("--clear-compose-profiles", "remove EVERY compose profile from the row \u2014 omitting --compose-profiles preserves them, so clearing needs saying out loud").option("--health-url <url>", "master-only: stage health URL (https, or loopback http) the box health gate probes; omit to leave unchanged").option("--clear-health-url", "master-only: remove the stored health URL from the row").option("--readiness-path <path>", "master-only: readiness path Caddy actively probes (health_uri, e.g. /healthz); omit to leave unchanged").option("--clear-readiness-path", "master-only: remove the stored readiness path from the row").option("--force", "explicit recovery override: skip fileless-compose verification only after independent proof").option("--json", "machine-readable output").action(async (repoOrSlug, o) => {
75250
75277
  const cfg = await loadConfig();
75251
75278
  let target;
75252
75279
  try {
@@ -75305,7 +75332,11 @@ ${filelessTransitionGuide(target, o.stage)}`
75305
75332
  clearAliases: o.clearAliases,
75306
75333
  noEnvFile,
75307
75334
  composeProfiles,
75308
- clearComposeProfiles: o.clearComposeProfiles
75335
+ clearComposeProfiles: o.clearComposeProfiles,
75336
+ healthUrl: o.healthUrl,
75337
+ clearHealthUrl: o.clearHealthUrl,
75338
+ readinessPath: o.readinessPath,
75339
+ clearReadinessPath: o.clearReadinessPath
75309
75340
  });
75310
75341
  if (target.includes("/")) body.repo = target;
75311
75342
  } catch (e) {
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.6.44",
3
+ "version": "4.6.46",
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.6.44",
3
+ "version": "4.6.46",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",
@@ -309,7 +309,10 @@ requests like this should follow this structure, not prose guide."
309
309
  Option C, each its own full-resolution `1440x900` live HTML board in one MM Artifact A/B canvas
310
310
  (Part 3 rules: content-only `Ctrl + Mousewheel` zoom, 1:1 or side-by-side live comparison). Serve
311
311
  the verified canvas on the live loopback HTTP review server without opening a browser from the
312
- seat, so the owner's `Send answers` posts straight back to `POST /answers`. Once review passes,
312
+ seat, so the owner's `Send answers` posts straight back to `POST /answers`. Set `artifact.json`
313
+ `review: { issue, requester }` first: without it the page still opens, but shows the owner a red
314
+ routing alert and answers reach only the serving session. Confirm no routing warning renders
315
+ before sending the URL. Once review passes,
313
316
  send the orchestrator only the review URL and issue number, and keep the server running through
314
317
  Stage 2; the orchestrator opens it on the owner's screen (#8987, relay wording). Never open a
315
318
  `--standalone` `file://` export (`Download answers.json`) for an