@mutmutco/cli 4.3.57 → 4.3.58

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.
Files changed (2) hide show
  1. package/dist/main.cjs +87 -261
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -6046,6 +6046,15 @@ var REGISTRY_FETCH_TIMEOUT_MS = 8e3;
6046
6046
  init_fetch_retry();
6047
6047
  init_client_version();
6048
6048
 
6049
+ // ../shared/schedule-inventory.ts
6050
+ function classifyLlmValue(raw) {
6051
+ const value = raw.trim().toLowerCase();
6052
+ if (/^no\b|^none\b/.test(value)) return "no";
6053
+ if (/^yes\b/.test(value)) return "yes";
6054
+ if (/^embeddings\b/.test(value)) return "embeddings";
6055
+ return "unknown";
6056
+ }
6057
+
6049
6058
  // src/workflow-context.ts
6050
6059
  function parseWorkflowJobs(yaml) {
6051
6060
  const lines2 = yaml.split(/\r?\n/);
@@ -6324,25 +6333,10 @@ function resolvedLabel(entry, now) {
6324
6333
  var ORG = "mutmutco";
6325
6334
  var DOC_START_MARKER = "<!-- schedules:inventory:start -->";
6326
6335
  var DOC_END_MARKER = "<!-- schedules:inventory:end -->";
6327
- function isJervResource(name) {
6328
- return /^jerv-memory(?:-|$)/i.test(name);
6329
- }
6330
6336
  function llmFromHeader(yamlText) {
6331
6337
  const m = /^#\s*llm:\s*(.+)$/im.exec(yamlText);
6332
6338
  return m ? classifyLlmValue(m[1]) : "unknown";
6333
6339
  }
6334
- function classifyLlmValue(raw) {
6335
- const value = raw.trim().toLowerCase();
6336
- if (/^no\b|^none\b/.test(value)) return "no";
6337
- if (/^yes\b/.test(value)) return "yes";
6338
- if (/^embeddings\b/.test(value)) return "embeddings";
6339
- return "unknown";
6340
- }
6341
- function readLlmDeclaration(text) {
6342
- if (!text) return "unknown";
6343
- const m = /\bllm:\s*(.+)/i.exec(text);
6344
- return m ? classifyLlmValue(m[1]) : "unknown";
6345
- }
6346
6340
  function extractWorkflowCrons(yamlText) {
6347
6341
  const crons = [];
6348
6342
  for (const rawLine of yamlText.split("\n")) {
@@ -6366,126 +6360,6 @@ function workflowEntry(repo, workflowPath, yamlText) {
6366
6360
  harbourUnmanaged: isHarbourUnmanaged(yamlText)
6367
6361
  };
6368
6362
  }
6369
- function awsRuleEntries(payload) {
6370
- if (!payload || typeof payload !== "object") {
6371
- throw new Error("aws events list-rules answered a non-object payload \u2014 refusing to read it as zero rules");
6372
- }
6373
- const { Rules: rules } = payload;
6374
- if (!Array.isArray(rules)) {
6375
- throw new Error("aws events list-rules answered no Rules array \u2014 refusing to read it as zero rules");
6376
- }
6377
- const entries = [];
6378
- for (const node of rules) {
6379
- if (!node || typeof node !== "object") {
6380
- throw new Error("aws events list-rules returned a non-object rule \u2014 refusing to read it as no rule");
6381
- }
6382
- const { Name, ScheduleExpression, State, Description } = node;
6383
- if (typeof Name !== "string") {
6384
- throw new Error("aws events list-rules returned a rule with no Name string \u2014 refusing to read it as no rule");
6385
- }
6386
- if (typeof ScheduleExpression !== "string") continue;
6387
- if (State !== "ENABLED" || isJervResource(Name)) continue;
6388
- entries.push({
6389
- name: Name,
6390
- cadence: ScheduleExpression,
6391
- executor: "aws-eventbridge-rule",
6392
- // An AWS rule declares `llm:` in its own Description (the shared convention) — a rule with no
6393
- // Description reads `unknown`, and stack-internal plumbing like the Lambda warmer should say
6394
- // `llm: no` there to go green.
6395
- llm: readLlmDeclaration(typeof Description === "string" ? Description : void 0),
6396
- resolved: "live",
6397
- source: `aws events rule ${Name} (eu-central-1)`
6398
- });
6399
- }
6400
- return entries;
6401
- }
6402
- function lambdaTargetFromArn(arn) {
6403
- const marker = ":function:";
6404
- const i = arn.indexOf(marker);
6405
- if (i < 0) return { functionName: arn.split(":").pop() ?? "" };
6406
- const rest = arn.slice(i + marker.length);
6407
- const q = rest.indexOf(":");
6408
- if (q < 0) return { functionName: rest };
6409
- return { functionName: rest.slice(0, q), qualifier: rest.slice(q + 1) };
6410
- }
6411
- function awsScheduleEntry(payload) {
6412
- if (!payload || typeof payload !== "object") {
6413
- throw new Error("aws scheduler get-schedule answered a non-object payload \u2014 refusing to read it as no schedule");
6414
- }
6415
- const { Name, ScheduleExpression, State, Target, Description, CreationDate } = payload;
6416
- if (typeof Name !== "string" || typeof ScheduleExpression !== "string") {
6417
- throw new Error("aws scheduler get-schedule answered no Name/ScheduleExpression strings \u2014 refusing to read it as no schedule");
6418
- }
6419
- if (State !== "ENABLED" || isJervResource(Name)) return null;
6420
- let target = "";
6421
- let qualifier;
6422
- let scheduleId;
6423
- if (Target && typeof Target === "object") {
6424
- const { Arn, Input } = Target;
6425
- if (typeof Arn === "string") {
6426
- const parsed = lambdaTargetFromArn(Arn);
6427
- target = parsed.functionName;
6428
- qualifier = parsed.qualifier;
6429
- }
6430
- if (typeof Input === "string") {
6431
- try {
6432
- const parsed = JSON.parse(Input);
6433
- if (typeof parsed?.scheduleId === "string" && parsed.scheduleId) scheduleId = parsed.scheduleId;
6434
- } catch {
6435
- }
6436
- }
6437
- }
6438
- const sourceBase = `aws scheduler schedule ${Name} (eu-central-1)`;
6439
- const source = qualifier && target ? `${sourceBase} \u2192 ${target}:${qualifier}` : sourceBase;
6440
- const armedAt = armedAtFromCreationDate(CreationDate);
6441
- return {
6442
- name: Name,
6443
- cadence: ScheduleExpression,
6444
- executor: target ? `aws-scheduler \u2192 ${target}` : "aws-scheduler",
6445
- llm: readLlmDeclaration(typeof Description === "string" ? Description : void 0),
6446
- resolved: "live",
6447
- source,
6448
- ...scheduleId ? { scheduleId } : {},
6449
- ...armedAt ? { armedAt } : {}
6450
- };
6451
- }
6452
- function armedAtFromCreationDate(creationDate) {
6453
- if (creationDate instanceof Date) {
6454
- return Number.isNaN(creationDate.getTime()) ? void 0 : creationDate.toISOString().slice(0, 10);
6455
- }
6456
- if (typeof creationDate === "string" && creationDate.trim()) {
6457
- const parsed = Date.parse(creationDate);
6458
- return Number.isNaN(parsed) ? void 0 : new Date(parsed).toISOString().slice(0, 10);
6459
- }
6460
- if (typeof creationDate === "number" && Number.isFinite(creationDate)) {
6461
- const ms = creationDate > 1e12 ? creationDate : creationDate * 1e3;
6462
- const date = new Date(ms);
6463
- return Number.isNaN(date.getTime()) ? void 0 : date.toISOString().slice(0, 10);
6464
- }
6465
- return void 0;
6466
- }
6467
- function awsScheduleRefs(payload) {
6468
- if (!payload || typeof payload !== "object") {
6469
- throw new Error("aws scheduler list-schedules answered a non-object payload \u2014 refusing to read it as zero schedules");
6470
- }
6471
- const { Schedules: schedules } = payload;
6472
- if (!Array.isArray(schedules)) {
6473
- throw new Error("aws scheduler list-schedules answered no Schedules array \u2014 refusing to read it as zero schedules");
6474
- }
6475
- const refs = [];
6476
- for (const s of schedules) {
6477
- if (!s || typeof s !== "object") {
6478
- throw new Error("aws scheduler list-schedules returned a non-object schedule \u2014 refusing to read it as no schedule");
6479
- }
6480
- const { Name, GroupName } = s;
6481
- if (typeof Name !== "string") {
6482
- throw new Error("aws scheduler list-schedules returned a schedule with no Name string \u2014 refusing to read it as no schedule");
6483
- }
6484
- if (isJervResource(Name)) continue;
6485
- refs.push(typeof GroupName === "string" && GroupName !== "default" && GroupName !== "" ? { name: Name, group: GroupName } : { name: Name });
6486
- }
6487
- return refs;
6488
- }
6489
6363
  function decorateAwsModel(entries, registry2, verdicts) {
6490
6364
  if (!registry2 || registry2.length === 0) return [...entries];
6491
6365
  const rowById = new Map(registry2.map((r) => [r.id, r]));
@@ -6960,6 +6834,24 @@ async function fetchDeployFactsBySlug(slug, deps) {
6960
6834
  return null;
6961
6835
  }
6962
6836
  }
6837
+ async function fetchScheduleInventory(deps) {
6838
+ try {
6839
+ if (!deps.baseUrl) return null;
6840
+ const token = await deps.token();
6841
+ if (!token) return null;
6842
+ const res = await retriedFetch(deps, `${deps.baseUrl.replace(/\/$/, "")}/schedules/inventory`, {
6843
+ method: "GET",
6844
+ headers: { Authorization: `Bearer ${token}` }
6845
+ });
6846
+ if (!res.ok) return null;
6847
+ const body = await res.json();
6848
+ if (!body || !Array.isArray(body.entries) || !Array.isArray(body.incomplete) || !body.incomplete.every((v) => typeof v === "string") || typeof body.schedulerRead !== "boolean" || !body.schedulerRead && body.incomplete.length === 0) return null;
6849
+ if (!body.entries.every((e) => e && typeof e.name === "string" && typeof e.cadence === "string" && typeof e.executor === "string" && typeof e.source === "string" && e.resolved === "live" && ["yes", "no", "embeddings", "unknown"].includes(e.llm) && (e.scheduleId === void 0 || typeof e.scheduleId === "string") && (e.armedAt === void 0 || typeof e.armedAt === "string"))) return null;
6850
+ return body;
6851
+ } catch {
6852
+ return null;
6853
+ }
6854
+ }
6963
6855
  async function fetchSchedulesList(deps) {
6964
6856
  if (!deps.baseUrl) return null;
6965
6857
  const token = await deps.token();
@@ -7071,6 +6963,9 @@ async function tenantReconcile(payload, deps) {
7071
6963
  async function tenantDeploy(payload, deps) {
7072
6964
  return postJson("/tenant-deploy", payload, deps, "POST", { noRetry: true, timeoutMs: TENANT_DEPLOY_TIMEOUT_MS });
7073
6965
  }
6966
+ async function releaseAnnouncement(payload, deps) {
6967
+ return postJson("/release-announcement", payload, deps, "POST", { noRetry: true, timeoutMs: 3e4 });
6968
+ }
7074
6969
  async function actionsCanary(payload, deps) {
7075
6970
  return postJson("/actions-canary", payload, deps, "POST", { noRetry: true });
7076
6971
  }
@@ -15877,10 +15772,10 @@ var rollout_plan_default = {
15877
15772
  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)."
15878
15773
  },
15879
15774
  baseline: {
15880
- version: "4.3.57",
15881
- tag: "v4.3.57",
15882
- commit: "b988569fdfe3",
15883
- npm: "@mutmutco/cli@4.3.57"
15775
+ version: "4.3.58",
15776
+ tag: "v4.3.58",
15777
+ commit: "aa4958ac3926",
15778
+ npm: "@mutmutco/cli@4.3.58"
15884
15779
  },
15885
15780
  exitCriterion: "fleet-n-of-n",
15886
15781
  hubOnlyShortcut: "forbidden",
@@ -15897,14 +15792,14 @@ var rollout_plan_default = {
15897
15792
  repo: "mutmutco/mmi-hub",
15898
15793
  role: "canary",
15899
15794
  schedule: "train",
15900
- v3Target: "v4.3.57"
15795
+ v3Target: "v4.3.58"
15901
15796
  }
15902
15797
  ],
15903
15798
  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.",
15904
15799
  rollback: {
15905
15800
  independent: true,
15906
- mechanism: "npm dist-tag latest -> 4.3.57 and redeploy the Hub Lambda from tag v4.3.57 (b988569fdfe3); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15907
- v3Target: "v4.3.57 (@mutmutco/cli@4.3.57, tag commit b988569fdfe3 \u2014 last known-good release carrying the repo-index v4-only contract)"
15801
+ mechanism: "npm dist-tag latest -> 4.3.58 and redeploy the Hub Lambda from tag v4.3.58 (aa4958ac3926); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15802
+ v3Target: "v4.3.58 (@mutmutco/cli@4.3.58, tag commit aa4958ac3926 \u2014 last known-good release carrying the repo-index v4-only contract)"
15908
15803
  }
15909
15804
  },
15910
15805
  {
@@ -35594,15 +35489,9 @@ function writeError(res) {
35594
35489
 
35595
35490
  // src/schedules-commands.ts
35596
35491
  var import_promises5 = require("node:fs/promises");
35597
- var import_node_child_process11 = require("node:child_process");
35598
- var import_node_util6 = require("node:util");
35599
35492
  init_clean_exit();
35600
35493
  init_github_client();
35601
35494
  init_cli_shared();
35602
- var execFileP4 = (0, import_node_util6.promisify)(import_node_child_process11.execFile);
35603
- var AWS_REGION = "eu-central-1";
35604
- var AWS_TIMEOUT_MS = 3e4;
35605
- var AWS_RETRY_DELAY_MS = 1500;
35606
35495
  async function listWorkflows(client, repo) {
35607
35496
  const all = [];
35608
35497
  for (let page = 1; ; page += 1) {
@@ -35699,44 +35588,11 @@ async function githubEntries(client) {
35699
35588
  drift.push(...reconciliation.map(renderDrift));
35700
35589
  return { entries, incomplete, drift, reconciliation, readRepos, workflowNames: [...workflows.map((w) => w.name), ...unreadableNames], disabledWorkflowNames };
35701
35590
  }
35702
- async function awsJson(args) {
35703
- const run = async () => {
35704
- const { stdout } = await execFileP4("aws", [...args, "--region", AWS_REGION, "--output", "json"], {
35705
- encoding: "utf8",
35706
- windowsHide: true,
35707
- timeout: AWS_TIMEOUT_MS
35708
- });
35709
- return JSON.parse(stdout);
35710
- };
35711
- try {
35712
- return await run();
35713
- } catch {
35714
- await new Promise((resolve7) => setTimeout(resolve7, AWS_RETRY_DELAY_MS));
35715
- return run();
35716
- }
35717
- }
35718
35591
  async function awsEntries() {
35719
- const entries = [];
35720
- const incomplete = [];
35721
- try {
35722
- entries.push(...awsRuleEntries(await awsJson(["events", "list-rules"])));
35723
- } catch (e) {
35724
- incomplete.push(`aws: events list-rules failed \u2014 ${e.message}`);
35725
- }
35726
- let schedulerRead = false;
35727
- try {
35728
- const refs = awsScheduleRefs(await awsJson(["scheduler", "list-schedules"]));
35729
- for (const ref of refs) {
35730
- const args = ["scheduler", "get-schedule", "--name", ref.name, ...ref.group ? ["--group-name", ref.group] : []];
35731
- const entry = awsScheduleEntry(await awsJson(args));
35732
- if (entry) entries.push(entry);
35733
- }
35734
- schedulerRead = true;
35735
- } catch (e) {
35736
- incomplete.push(`aws: scheduler listing failed \u2014 ${e.message}`);
35737
- }
35738
- const reconciliation = unlauncheredLlmDrifts(entries);
35739
- return { entries, incomplete, drift: reconciliation.map(renderDrift), reconciliation, schedulerRead };
35592
+ const inventory = await fetchScheduleInventory(registryClientDeps(await loadConfig()));
35593
+ if (!inventory) return { entries: [], incomplete: ["aws: Hub schedule inventory unavailable or unauthenticated"], drift: [], reconciliation: [], schedulerRead: false };
35594
+ const reconciliation = unlauncheredLlmDrifts(inventory.entries);
35595
+ return { ...inventory, reconciliation, drift: reconciliation.map(renderDrift) };
35740
35596
  }
35741
35597
  async function readOrFail(read) {
35742
35598
  try {
@@ -36593,8 +36449,13 @@ async function resolveStageBuildSecrets(input) {
36593
36449
  out[envKey] = fromVault;
36594
36450
  continue;
36595
36451
  }
36452
+ const fromGitHub = await input.githubToken?.();
36453
+ if (fromGitHub) {
36454
+ out[envKey] = fromGitHub;
36455
+ continue;
36456
+ }
36596
36457
  missing.push(
36597
- `${envKey}=${GITHUB_PACKAGES_TOKEN_REF} (central deploy mints this; local /stage needs process env ${envKey} or a stageless project vault secret ${envKey} \u2014 a GitHub PAT with read:packages for npm.pkg.github.com; declare+set via vault secrets, never commit the value)`
36458
+ `${envKey}=${GITHUB_PACKAGES_TOKEN_REF} (sign in with gh auth login using a package-readable GitHub identity, or provide process env ${envKey} or stageless project vault secret ${envKey}; npm.pkg.github.com still requires package read permission)`
36598
36459
  );
36599
36460
  continue;
36600
36461
  }
@@ -36628,6 +36489,7 @@ async function fetchVaultRef(fetchVault, ref) {
36628
36489
  }
36629
36490
 
36630
36491
  // src/stage-commands.ts
36492
+ init_github_client();
36631
36493
  function registerStageCommands(program3) {
36632
36494
  function stagePortFromArgv() {
36633
36495
  const raw = rawValue("--port", "");
@@ -36687,7 +36549,8 @@ function registerStageCommands(program3) {
36687
36549
  const d = makeSecretsDeps(cfg);
36688
36550
  const merge = await resolveStageBuildSecrets({
36689
36551
  requiredBuildSecrets: required,
36690
- fetchVault: (key, opts) => fetchSecretValue(d, key, opts ?? {})
36552
+ fetchVault: (key, opts) => fetchSecretValue(d, key, opts ?? {}),
36553
+ githubToken
36691
36554
  });
36692
36555
  return Object.keys(merge).length ? merge : void 0;
36693
36556
  }
@@ -37089,7 +36952,7 @@ function renderVerifySecrets(body) {
37089
36952
  }
37090
36953
 
37091
36954
  // src/command-register-collaboration.ts
37092
- var import_node_child_process16 = require("node:child_process");
36955
+ var import_node_child_process15 = require("node:child_process");
37093
36956
  var import_node_fs41 = require("node:fs");
37094
36957
  var import_promises7 = require("node:fs/promises");
37095
36958
  init_clean_exit();
@@ -37475,12 +37338,12 @@ function boardAdvanceFailureMessage(result) {
37475
37338
  }
37476
37339
 
37477
37340
  // src/test-policy-core.ts
37478
- var import_node_child_process13 = require("node:child_process");
37341
+ var import_node_child_process12 = require("node:child_process");
37479
37342
  var import_node_fs35 = require("node:fs");
37480
37343
  var import_node_path33 = require("node:path");
37481
37344
 
37482
37345
  // src/test-command-policy-shared.mjs
37483
- var import_node_child_process12 = require("node:child_process");
37346
+ var import_node_child_process11 = require("node:child_process");
37484
37347
  var TEST_COMMAND_CLASS = "test";
37485
37348
  var TRAILER_KEY = "Test-Policy-Override";
37486
37349
  var OVERRIDE_RE = /^Test-Policy-Override:\s*(.+)$/im;
@@ -37597,7 +37460,7 @@ function evaluateTestCommandPolicy({ paths, mandatory, regulated = true, overrid
37597
37460
  };
37598
37461
  }
37599
37462
  function git(args, cwd) {
37600
- return (0, import_node_child_process12.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
37463
+ return (0, import_node_child_process11.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
37601
37464
  }
37602
37465
  function parseScope(value) {
37603
37466
  const scoped = /^\[([^\]]*)\]\s*([\s\S]*)$/.exec(value);
@@ -38096,14 +37959,14 @@ function evaluate(changed, policy, present = () => false) {
38096
37959
  return findings;
38097
37960
  }
38098
37961
  function git2(args, cwd) {
38099
- return (0, import_node_child_process13.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
37962
+ return (0, import_node_child_process12.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
38100
37963
  }
38101
37964
  var COAUTHOR_KEY = "Co-authored-by";
38102
37965
  var GH_MESSAGE_SEPARATOR = /^-{5,}$/;
38103
37966
  var LIFTED_KEYS = new RegExp(`^(?:${TRAILER_KEY}|${COAUTHOR_KEY}):`, "i");
38104
37967
  function parseTrailers(message2, cwd) {
38105
37968
  try {
38106
- return (0, import_node_child_process13.execFileSync)("git", ["interpret-trailers", "--parse", "--unfold"], {
37969
+ return (0, import_node_child_process12.execFileSync)("git", ["interpret-trailers", "--parse", "--unfold"], {
38107
37970
  windowsHide: true,
38108
37971
  cwd,
38109
37972
  input: message2,
@@ -38859,7 +38722,7 @@ function postMergeReconWarnings(input) {
38859
38722
  }
38860
38723
 
38861
38724
  // src/review-verdict.ts
38862
- var import_node_child_process14 = require("node:child_process");
38725
+ var import_node_child_process13 = require("node:child_process");
38863
38726
  var import_node_fs38 = require("node:fs");
38864
38727
  var import_node_os19 = require("node:os");
38865
38728
  var import_node_path36 = require("node:path");
@@ -38959,8 +38822,8 @@ async function checkPrReview(number, repo, head, deps = {
38959
38822
  }
38960
38823
  function computePrPatchId(number, repo) {
38961
38824
  return new Promise((resolve7, reject) => {
38962
- const gh = (0, import_node_child_process14.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
38963
- const git3 = (0, import_node_child_process14.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
38825
+ const gh = (0, import_node_child_process13.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
38826
+ const git3 = (0, import_node_child_process13.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
38964
38827
  let out = "";
38965
38828
  let ghErr = "";
38966
38829
  let gitErr = "";
@@ -39042,7 +38905,7 @@ async function postPrCommentFromFile(number, repo, body) {
39042
38905
  }
39043
38906
 
39044
38907
  // src/pr-create-docs-check.ts
39045
- var import_node_child_process15 = require("node:child_process");
38908
+ var import_node_child_process14 = require("node:child_process");
39046
38909
  init_cli_shared();
39047
38910
  var GIT_TIMEOUT_MS2 = 15e3;
39048
38911
  function catFileBatch(root, ref, paths) {
@@ -39050,7 +38913,7 @@ function catFileBatch(root, ref, paths) {
39050
38913
  return new Promise((resolve7) => {
39051
38914
  const chunks = [];
39052
38915
  let settled = false;
39053
- const child2 = (0, import_node_child_process15.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
38916
+ const child2 = (0, import_node_child_process14.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
39054
38917
  const finish = () => {
39055
38918
  if (settled) return;
39056
38919
  settled = true;
@@ -40197,7 +40060,7 @@ function scheduleRelatedDiscovery(o) {
40197
40060
  try {
40198
40061
  const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body, "--fail-soft"];
40199
40062
  if (o.repo) args.push("--repo", o.repo);
40200
- spawnDetachedSelf(args, { spawn: import_node_child_process16.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
40063
+ spawnDetachedSelf(args, { spawn: import_node_child_process15.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
40201
40064
  } catch {
40202
40065
  }
40203
40066
  }
@@ -41893,7 +41756,7 @@ ${SSH_RECIPE_AGENT_NOTE}`);
41893
41756
  }
41894
41757
 
41895
41758
  // src/dist-drift.ts
41896
- var import_node_child_process17 = require("node:child_process");
41759
+ var import_node_child_process16 = require("node:child_process");
41897
41760
  var import_node_crypto13 = require("node:crypto");
41898
41761
  var import_node_fs44 = require("node:fs");
41899
41762
  var import_node_os20 = require("node:os");
@@ -42038,7 +41901,7 @@ function bomPathFor(root) {
42038
41901
  }
42039
41902
  }
42040
41903
  function rebuildTo(packageRoot, outDir) {
42041
- (0, import_node_child_process17.execFileSync)(process.execPath, ["build.mjs"], {
41904
+ (0, import_node_child_process16.execFileSync)(process.execPath, ["build.mjs"], {
42042
41905
  cwd: packageRoot,
42043
41906
  env: { ...process.env, MMI_DIST_OUTDIR: outDir },
42044
41907
  windowsHide: true,
@@ -42265,7 +42128,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
42265
42128
  }
42266
42129
 
42267
42130
  // src/spawn-policy-core.ts
42268
- var import_node_child_process18 = require("node:child_process");
42131
+ var import_node_child_process17 = require("node:child_process");
42269
42132
  var import_node_fs45 = require("node:fs");
42270
42133
  var import_node_path43 = require("node:path");
42271
42134
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
@@ -42336,7 +42199,7 @@ function findViolationsInSource(raw) {
42336
42199
  return found;
42337
42200
  }
42338
42201
  function policedFiles(root) {
42339
- const r = (0, import_node_child_process18.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
42202
+ const r = (0, import_node_child_process17.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
42340
42203
  cwd: root,
42341
42204
  encoding: "utf8",
42342
42205
  windowsHide: true,
@@ -42642,50 +42505,6 @@ init_house_map();
42642
42505
  // src/hotfix-apply.ts
42643
42506
  var import_promises9 = require("node:fs/promises");
42644
42507
 
42645
- // src/slack-alert.ts
42646
- var SSM_REGION = "eu-central-1";
42647
- var SSM_TOKEN_PARAM = "/mmi-future/_org/slack/SLACK_BOT_TOKEN";
42648
- var SSM_CHANNEL_PARAM = "/mmi-future/_org/slack/SLACK_ALERTS_CHANNEL";
42649
- var SLACK_TIMEOUT_MS = 1e4;
42650
- async function readSsmParameter(deps, name, decrypt) {
42651
- const args = [
42652
- "ssm",
42653
- "get-parameter",
42654
- "--region",
42655
- SSM_REGION,
42656
- "--name",
42657
- name,
42658
- "--query",
42659
- "Parameter.Value",
42660
- "--output",
42661
- "text",
42662
- ...decrypt ? ["--with-decryption"] : []
42663
- ];
42664
- const value = (await deps.run("aws", args)).trim();
42665
- if (!value || value === "None") throw new Error(`SSM parameter ${name} is empty`);
42666
- return value;
42667
- }
42668
- async function postToChannel(deps, channel, text) {
42669
- const resolved = channel.trim();
42670
- if (!resolved || resolved === "None") throw new Error("no Slack channel resolved");
42671
- const token = await readSsmParameter(deps, SSM_TOKEN_PARAM, true);
42672
- const fetchImpl = deps.fetchImpl ?? fetch;
42673
- const res = await fetchImpl("https://slack.com/api/chat.postMessage", {
42674
- method: "POST",
42675
- headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json; charset=utf-8" },
42676
- body: JSON.stringify({ channel: resolved, text, unfurl_links: false }),
42677
- signal: AbortSignal.timeout(SLACK_TIMEOUT_MS)
42678
- });
42679
- const json = await res.json().catch(() => ({}));
42680
- if (!json.ok) throw new Error(`slack postMessage failed: ${json.error ?? `http ${res.status}`}`);
42681
- return { status: "posted", note: "posted" };
42682
- }
42683
- async function postToAlertsChannel(deps, text) {
42684
- const channel = await readSsmParameter(deps, SSM_CHANNEL_PARAM, false);
42685
- await postToChannel(deps, channel, text);
42686
- return { status: "posted", note: "posted to the alerts channel" };
42687
- }
42688
-
42689
42508
  // src/release-announce.ts
42690
42509
  var ANNOUNCE_REPO = "mutmutco/MMI-Hub";
42691
42510
  var MAX_BULLETS = 6;
@@ -42792,12 +42611,6 @@ async function announceRelease(deps, args) {
42792
42611
  if (args.summaryFile) {
42793
42612
  if (!deps.readFile) throw new Error("summary file given but deps.readFile is missing");
42794
42613
  lines2 = summaryFileLines(await deps.readFile(args.summaryFile), neutralize);
42795
- if (deps.removeFile) {
42796
- try {
42797
- await deps.removeFile(args.summaryFile);
42798
- } catch {
42799
- }
42800
- }
42801
42614
  }
42802
42615
  if (lines2.length === 0) {
42803
42616
  if (target.kind !== "alerts") {
@@ -42813,12 +42626,16 @@ async function announceRelease(deps, args) {
42813
42626
  releaseUrl,
42814
42627
  ...target.kind === "channel" ? { language: target.language } : {}
42815
42628
  });
42816
- if (target.kind === "alerts") {
42817
- await postToAlertsChannel(deps, text);
42818
- return { status: "announced", note: `announced ${args.tag} to the alerts channel` };
42629
+ const delivery = await deps.postAnnouncement({ repo: args.repo, tag: args.tag, text });
42630
+ if (delivery === "skipped") return { status: "skipped", note: missingChannelNote(args.repo) };
42631
+ if (args.summaryFile && deps.removeFile) {
42632
+ try {
42633
+ await deps.removeFile(args.summaryFile);
42634
+ } catch {
42635
+ }
42819
42636
  }
42820
- await postToChannel(deps, target.channel, text);
42821
- return { status: "announced", note: `announced ${args.tag} to the project release channel` };
42637
+ const destination = target.kind === "alerts" ? "alerts channel" : "project release channel";
42638
+ return { status: "announced", note: `${delivery === "already-posted" ? "already announced" : "announced"} ${args.tag} to the ${destination}` };
42822
42639
  } catch (e) {
42823
42640
  return { status: "failed", note: `announce failed (release unaffected): ${e.message}` };
42824
42641
  }
@@ -43945,12 +43762,12 @@ async function findInFlightHotfixVersion(deps, ctx, latestMainTag, workflows = H
43945
43762
  }
43946
43763
 
43947
43764
  // src/hotfix-coverage.ts
43948
- var import_node_child_process19 = require("node:child_process");
43765
+ var import_node_child_process18 = require("node:child_process");
43949
43766
  var CHERRY_TRAILER = /\(cherry picked from commit ([0-9a-f]{7,40})\)/g;
43950
43767
  function checkHotfixCoverage(options = {}) {
43951
43768
  const { cwd = process.cwd(), mainRef = "origin/main", rcRef = "origin/rc", manifestPaths = [] } = options;
43952
43769
  const ack = (options.ack ?? []).filter(Boolean);
43953
- const git3 = options.git ?? ((args, opts) => (0, import_node_child_process19.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
43770
+ const git3 = options.git ?? ((args, opts) => (0, import_node_child_process18.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
43954
43771
  const revList = (range) => {
43955
43772
  const out = git3(["rev-list", "--no-merges", range]).trim();
43956
43773
  return out ? out.split("\n") : [];
@@ -44018,7 +43835,7 @@ function checkHotfixCoverage(options = {}) {
44018
43835
  }
44019
43836
  function checkHotfixCarries(options) {
44020
43837
  const { cwd = process.cwd(), branch, baseRef, targets } = options;
44021
- const git3 = options.git ?? ((args, opts) => (0, import_node_child_process19.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
43838
+ const git3 = options.git ?? ((args, opts) => (0, import_node_child_process18.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
44022
43839
  const isAncestor = (sha, ref) => {
44023
43840
  try {
44024
43841
  git3(["merge-base", "--is-ancestor", sha, ref]);
@@ -44288,6 +44105,15 @@ function trainApplyDeps() {
44288
44105
  // registry releaseChannel META for a product repo — best-effort inside announceRelease itself.
44289
44106
  announce: (args) => announceRelease({
44290
44107
  run: async (file, cmdArgs) => (await execFileP(file, cmdArgs, { timeout: GH_TRAIN_TIMEOUT_MS })).stdout,
44108
+ postAnnouncement: async (payload) => {
44109
+ const res = await releaseAnnouncement(payload, registryClientDeps(await loadConfig()));
44110
+ const body = res.body;
44111
+ if (!res.ok) throw new Error(body?.error ?? `Hub announcement failed (HTTP ${res.status}); verify delivery before retrying`);
44112
+ if (body?.ok !== true || body.status !== "posted" && body?.status !== "already-posted" && body?.status !== "skipped") {
44113
+ throw new Error("Hub announcement returned an unverified delivery result; do not resend");
44114
+ }
44115
+ return body.status;
44116
+ },
44291
44117
  readFile: (path2) => (0, import_promises10.readFile)(path2, "utf8"),
44292
44118
  removeFile: (path2) => (0, import_promises10.unlink)(path2),
44293
44119
  // #6521/#6523: the project's own release channel AND releaseLanguage, read from registry META in ONE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/cli",
3
- "version": "4.3.57",
3
+ "version": "4.3.58",
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",