@mutmutco/hub 4.4.4 → 4.4.6

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/index.cjs +61 -42
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -80,6 +80,7 @@ __export(index_exports, {
80
80
  schedulerStatus: () => schedulerStatus,
81
81
  sharedDocLockPath: () => sharedDocLockPath,
82
82
  sharedDocLockTimeoutReceipt: () => sharedDocLockTimeoutReceipt,
83
+ shippedTargetFrom: () => shippedTargetFrom,
83
84
  shouldHandOff: () => shouldHandOff,
84
85
  signOff: () => signOff,
85
86
  startSpinner: () => startSpinner,
@@ -2073,6 +2074,7 @@ function shouldHandOff(self, options) {
2073
2074
  }
2074
2075
  function reconcile(options) {
2075
2076
  const env = options.env ?? process.env;
2077
+ const shipped = options.shippedTarget?.trim() || null;
2076
2078
  const say = (line) => {
2077
2079
  options.narrate?.(line);
2078
2080
  options.onPhase?.(line);
@@ -2108,47 +2110,55 @@ function reconcile(options) {
2108
2110
  summary.reap = reap({ paths, dryRun: options.dryRun, env });
2109
2111
  for (const row of summary.reap) journal({ kind: "reap", surface: row.category, verdict: row.verdict, count: row.reaped, detail: row.detail });
2110
2112
  for (const row of summary.reap.filter((entry) => entry.verdict !== "skip")) say(`reap ${row.category}: ${row.verdict}${row.detail ? " \u2014 " + row.detail : ""}`);
2111
- say("polling npm for @mutmutco/cli versions");
2112
- const versions = npmVersions("@mutmutco/cli", env).sort((a, b) => compareSemver(b, a));
2113
- if (!versions.length) {
2114
- journal({ kind: "poll", verdict: "fail", detail: "@mutmutco/cli has no npm versions \u2014 cannot discover a candidate" });
2115
- summary.exit = 1;
2116
- summary.detail = "npm poll returned no versions for @mutmutco/cli";
2117
- return summary;
2118
- }
2119
- say("fetching release BOM gate cache");
2120
- ensureBareCache(paths.gitCache, repoUrl);
2121
- fetchIntoCache(paths.gitCache, repoUrl, "refs/heads/main:refs/heads/main");
2122
- for (const candidate of versions.slice(0, bound)) {
2123
- say(`gating candidate v${candidate}`);
2124
- const gate = gateCandidate(paths.gitCache, repoUrl, candidate);
2125
- if (!gate.ok) {
2126
- say(`candidate v${candidate} rejected (${gate.reason ?? "gate"})`);
2127
- journal({ kind: "candidate-reject", to: candidate, verdict: "skip", detail: gate.reason ?? "gate rejected" });
2128
- continue;
2113
+ if (shipped) {
2114
+ say(`shipped target v${shipped} \u2014 the payload is the release; no npm poll, no gate`);
2115
+ summary.target = shipped;
2116
+ summary.gate = "shipped payload";
2117
+ summary.managedSurfaces = null;
2118
+ journal({ kind: "target", to: shipped, verdict: "ok", detail: "shipped payload" });
2119
+ } else {
2120
+ say("polling npm for @mutmutco/cli versions");
2121
+ const versions = npmVersions("@mutmutco/cli", env).sort((a, b) => compareSemver(b, a));
2122
+ if (!versions.length) {
2123
+ journal({ kind: "poll", verdict: "fail", detail: "@mutmutco/cli has no npm versions \u2014 cannot discover a candidate" });
2124
+ summary.exit = 1;
2125
+ summary.detail = "npm poll returned no versions for @mutmutco/cli";
2126
+ return summary;
2129
2127
  }
2130
- const atomicity = checkAtomicity(paths.gitCache, gate.tagCommit, gate.bom, candidate, {
2131
- distIntegrity: (spec) => npmDistIntegrity(spec, env)
2132
- });
2133
- if (!atomicity.ok) {
2134
- journal({ kind: "candidate-reject", to: candidate, verdict: "skip", detail: `atomicity: ${atomicity.rows.filter((row) => !row.ok).map((row) => row.detail).join("; ")}` });
2135
- continue;
2128
+ say("fetching release BOM gate cache");
2129
+ ensureBareCache(paths.gitCache, repoUrl);
2130
+ fetchIntoCache(paths.gitCache, repoUrl, "refs/heads/main:refs/heads/main");
2131
+ for (const candidate of versions.slice(0, bound)) {
2132
+ say(`gating candidate v${candidate}`);
2133
+ const gate = gateCandidate(paths.gitCache, repoUrl, candidate);
2134
+ if (!gate.ok) {
2135
+ say(`candidate v${candidate} rejected (${gate.reason ?? "gate"})`);
2136
+ journal({ kind: "candidate-reject", to: candidate, verdict: "skip", detail: gate.reason ?? "gate rejected" });
2137
+ continue;
2138
+ }
2139
+ const atomicity = checkAtomicity(paths.gitCache, gate.tagCommit, gate.bom, candidate, {
2140
+ distIntegrity: (spec) => npmDistIntegrity(spec, env)
2141
+ });
2142
+ if (!atomicity.ok) {
2143
+ journal({ kind: "candidate-reject", to: candidate, verdict: "skip", detail: `atomicity: ${atomicity.rows.filter((row) => !row.ok).map((row) => row.detail).join("; ")}` });
2144
+ continue;
2145
+ }
2146
+ summary.target = candidate;
2147
+ summary.managedSurfaces = Array.isArray(gate.bom?.managedSurfaces) ? gate.bom.managedSurfaces.map(String) : null;
2148
+ summary.gate = `tag v${candidate} reachable from main, BOM stamp coherent`;
2149
+ summary.atomicity = atomicity;
2150
+ journal({ kind: "target", to: candidate, verdict: "ok", detail: summary.gate });
2151
+ break;
2136
2152
  }
2137
- summary.target = candidate;
2138
- summary.managedSurfaces = Array.isArray(gate.bom?.managedSurfaces) ? gate.bom.managedSurfaces.map(String) : null;
2139
- summary.gate = `tag v${candidate} reachable from main, BOM stamp coherent`;
2140
- summary.atomicity = atomicity;
2141
- journal({ kind: "target", to: candidate, verdict: "ok", detail: summary.gate });
2142
- break;
2143
- }
2144
- if (!summary.target) {
2145
- say("no green target \u2014 deferred");
2146
- journal({ kind: "target", verdict: "defer", detail: `no green candidate in the newest ${Math.min(bound, versions.length)} versions \u2014 registry not ready for this fleet stamp yet` });
2147
- for (const probe of enumerateSurfaces(env)) {
2148
- summary.surfaces.push({ id: probe.id, present: probe.present, action: probe.present ? "deferred-no-target" : "absent-skip" });
2149
- journal({ kind: "surface", surface: probe.id, present: probe.present, verdict: "skip", detail: probe.present ? "present; no green target yet" : `absent (${probe.marker}) \u2014 skipped` });
2153
+ if (!summary.target) {
2154
+ say("no green target \u2014 deferred");
2155
+ journal({ kind: "target", verdict: "defer", detail: `no green candidate in the newest ${Math.min(bound, versions.length)} versions \u2014 registry not ready for this fleet stamp yet` });
2156
+ for (const probe of enumerateSurfaces(env)) {
2157
+ summary.surfaces.push({ id: probe.id, present: probe.present, action: probe.present ? "deferred-no-target" : "absent-skip" });
2158
+ journal({ kind: "surface", surface: probe.id, present: probe.present, verdict: "skip", detail: probe.present ? "present; no green target yet" : `absent (${probe.marker}) \u2014 skipped` });
2159
+ }
2160
+ return summary;
2150
2161
  }
2151
- return summary;
2152
2162
  }
2153
2163
  say(`target v${summary.target} (${summary.gate})`);
2154
2164
  options.onTargetResolved?.(summary.target, summary.gate);
@@ -3337,7 +3347,13 @@ function heldOutput(write) {
3337
3347
  }
3338
3348
  };
3339
3349
  }
3340
- function runUpdate(args, json, face = false) {
3350
+ function shippedTargetFrom(args) {
3351
+ const index = args.indexOf("--shipped");
3352
+ if (index < 0) return void 0;
3353
+ const value = (args[index + 1] ?? "").trim();
3354
+ return value && !value.startsWith("--") ? value : void 0;
3355
+ }
3356
+ function runUpdate(args, json, face = false, shippedTarget) {
3341
3357
  const dryRun = args.includes("--dry-run");
3342
3358
  const verbose = args.includes("--verbose");
3343
3359
  const narrate = (line) => {
@@ -3346,7 +3362,7 @@ function runUpdate(args, json, face = false) {
3346
3362
  };
3347
3363
  const progressive = !json && !verbose && Boolean(process.stderr.isTTY);
3348
3364
  if (!progressive) {
3349
- return { summary: reconcile({ dryRun, narrate: verbose ? narrate : void 0 }), rendered: false };
3365
+ return { summary: reconcile({ dryRun, narrate: verbose ? narrate : void 0, shippedTarget }), rendered: false };
3350
3366
  }
3351
3367
  const reportOptions = humanOptions(dryRun);
3352
3368
  const spinner = startSpinner(true);
@@ -3358,6 +3374,7 @@ function runUpdate(args, json, face = false) {
3358
3374
  try {
3359
3375
  summary = reconcile({
3360
3376
  dryRun,
3377
+ shippedTarget,
3361
3378
  onPhase: (line) => spinner.label(line),
3362
3379
  onTargetResolved: face ? void 0 : (target) => {
3363
3380
  emit(updateHeader(target, dryRun, reportOptions));
@@ -3408,9 +3425,10 @@ function main(args = process.argv.slice(2)) {
3408
3425
  if (command === "install") {
3409
3426
  const face = openFace(args, json);
3410
3427
  const dryRun = args.includes("--dry-run");
3411
- const { summary, rendered } = runUpdate(args, json, face);
3428
+ const shippedTarget = shippedTargetFrom(args);
3429
+ const { summary, rendered } = runUpdate(args, json, face, shippedTarget);
3412
3430
  if (summary.reexec) {
3413
- const handedOff = handOff(summary.reexec, ["update", ...args.filter((arg) => arg !== "install")]);
3431
+ const handedOff = handOff(summary.reexec, ["update", ...args.filter((arg) => arg !== "install" && arg !== "--shipped" && arg !== shippedTarget)]);
3414
3432
  const scheduled = installTask();
3415
3433
  if (!json) {
3416
3434
  process.stdout.write(scheduled.ok ? ` Auto-update on \u2014 hourly task "MMI Fleet Updater".
@@ -3513,6 +3531,7 @@ if (typeof require !== "undefined" && require.main === module) {
3513
3531
  schedulerStatus,
3514
3532
  sharedDocLockPath,
3515
3533
  sharedDocLockTimeoutReceipt,
3534
+ shippedTargetFrom,
3516
3535
  shouldHandOff,
3517
3536
  signOff,
3518
3537
  startSpinner,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/hub",
3
- "version": "4.4.4",
3
+ "version": "4.4.6",
4
4
  "description": "Install and maintain the MMI CLI and every present host surface from one release-gated Hub command.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",