@mutmutco/installer-launcher 1.4.2 → 1.5.0

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.
package/dist/launcher.js CHANGED
@@ -1699,15 +1699,21 @@ function querySchedule(config, options = {}) {
1699
1699
  if (result.code !== 0) return { supported: true, enabled: false };
1700
1700
  const lastRun = valueOf(result.stdout, "Last Run Time:");
1701
1701
  const nextRun = valueOf(result.stdout, "Next Run Time:");
1702
+ const lastResult = valueOf(result.stdout, "Last Result:");
1702
1703
  const state2 = { supported: true, enabled: true, cadence: "hourly" };
1703
1704
  if (lastRun && !/disabled|never|not run/i.test(lastRun)) state2.lastRun = lastRun;
1704
1705
  else if (nextRun && !/disabled|never/i.test(nextRun)) state2.lastRun = `next run ${nextRun}`;
1706
+ if (lastResult) state2.lastResult = lastResult;
1705
1707
  return state2;
1706
1708
  }
1707
1709
  if (platform === "darwin") {
1708
1710
  const plist = join5(home, "Library", "LaunchAgents", `${scheduleLabel(config)}.plist`);
1709
1711
  if (!existsSync6(plist)) return { supported: true, enabled: false };
1710
- return { supported: true, enabled: true, cadence: "hourly" };
1712
+ const state2 = { supported: true, enabled: true, cadence: "hourly" };
1713
+ const printed = exec("launchctl", ["print", `gui/${process.getuid?.() ?? 501}/${scheduleLabel(config)}`]);
1714
+ const exitCode = /last exit code = (-?\d+)/.exec(`${printed.stdout ?? ""}${printed.stderr ?? ""}`)?.[1];
1715
+ if (printed.code === 0 && exitCode) state2.lastResult = exitCode;
1716
+ return state2;
1711
1717
  }
1712
1718
  const timer = join5(home, ".config", "systemd", "user", `${scheduleLabel(config)}.timer`);
1713
1719
  if (!existsSync6(timer)) return { supported: true, enabled: false };
@@ -1715,6 +1721,9 @@ function querySchedule(config, options = {}) {
1715
1721
  const shown = exec("systemctl", ["--user", "show", `${scheduleLabel(config)}.service`, "-p", "ExecMainStartTimestamp", "--value"]);
1716
1722
  const stamp = (shown.stdout ?? "").trim();
1717
1723
  if (shown.code === 0 && stamp && stamp !== "n/a") state.lastRun = stamp;
1724
+ const status = exec("systemctl", ["--user", "show", `${scheduleLabel(config)}.service`, "-p", "ExecMainStatus", "--value"]);
1725
+ const code = (status.stdout ?? "").trim();
1726
+ if (status.code === 0 && /^\d+$/.test(code)) state.lastResult = code;
1718
1727
  return state;
1719
1728
  }
1720
1729
  function darwinPlist(label, command2) {
@@ -1766,6 +1775,36 @@ function valueOf(output, key) {
1766
1775
  function firstLine(text) {
1767
1776
  return String(text).split(/\r?\n/).map((line) => line.trim()).filter(Boolean)[0] ?? "";
1768
1777
  }
1778
+ var SCHEDULE_SIGNAL = "MM_LAUNCHER_SCHEDULE";
1779
+ var OPT_OUT_FILE = "auto-update-off";
1780
+ function autoUpdateOptOut(dir) {
1781
+ return existsSync6(join5(dir, OPT_OUT_FILE));
1782
+ }
1783
+ function persistAutoUpdateOptOut(dir, off) {
1784
+ try {
1785
+ if (off) {
1786
+ mkdirSync5(dir, { recursive: true });
1787
+ writeFileSync6(join5(dir, OPT_OUT_FILE), "");
1788
+ } else rmSync5(join5(dir, OPT_OUT_FILE), { force: true });
1789
+ } catch {
1790
+ }
1791
+ }
1792
+ function armVerifiedSchedule(config, options) {
1793
+ try {
1794
+ enableSchedule(config, options.command, options);
1795
+ const verified = querySchedule(config, options);
1796
+ if (verified.enabled) return { signal: scheduleName(config), note: null };
1797
+ return { signal: null, note: `The launcher's hourly update task (${scheduleName(config)}) could not be verified \u2014 the product's own auto-update task stays.` };
1798
+ } catch (error) {
1799
+ return { signal: null, note: `The launcher could not arm its hourly update task: ${error.message} The product's own auto-update task stays.` };
1800
+ }
1801
+ }
1802
+ function lastResultFailed(value) {
1803
+ const text = value?.trim() ?? "";
1804
+ if (!text) return false;
1805
+ if (!/^-?(?:0x[0-9a-f]+|\d+)$/i.test(text)) return true;
1806
+ return ![0, 267011, 267009].includes(Number(text));
1807
+ }
1769
1808
 
1770
1809
  // src/login-github.ts
1771
1810
  import { spawn, spawnSync as spawnSync3 } from "node:child_process";
@@ -2265,7 +2304,7 @@ async function refreshLauncher(target, options = {}) {
2265
2304
  }
2266
2305
 
2267
2306
  // src/index.ts
2268
- var LAUNCHER_VERSION = true ? "1.4.2" : readVersionFromPackage();
2307
+ var LAUNCHER_VERSION = true ? "1.5.0" : readVersionFromPackage();
2269
2308
  function defaultPrint(message) {
2270
2309
  process.stdout.write(`${message}
2271
2310
  `);
@@ -2722,6 +2761,8 @@ async function installOrUpdateRun(config, dir, options, print, update, flags2, m
2722
2761
  installer.finish({ ...pointer ? { version: pointer } : {}, total: 1, updated: pointer && installed !== pointer ? 1 : 0, failed: 0, dryRun: true });
2723
2762
  return 0;
2724
2763
  }
2764
+ const armNote = armScheduleForInstall(config, dir, options);
2765
+ if (armNote) installer.phase("arm", { state: "note", detail: armNote });
2725
2766
  if (pointer && current?.version === pointer && payloadPresent) {
2726
2767
  version = pointer;
2727
2768
  installer.phase("resolve", { seconds: (Date.now() - started) / 1e3 });
@@ -2814,6 +2855,18 @@ async function installOrUpdateRun(config, dir, options, print, update, flags2, m
2814
2855
  installer.stop();
2815
2856
  }
2816
2857
  }
2858
+ function armScheduleForInstall(config, dir, options) {
2859
+ if (autoUpdateOptOut(dir)) return null;
2860
+ if (!isSea() && !options.autoupdate) return null;
2861
+ const result = armVerifiedSchedule(config, {
2862
+ command: options.autoupdate?.command ?? [process.execPath, "update"],
2863
+ stateDir: dir,
2864
+ ...options.autoupdate
2865
+ });
2866
+ if (!result.signal) return result.note;
2867
+ process.env[SCHEDULE_SIGNAL] = result.signal;
2868
+ return null;
2869
+ }
2817
2870
  function doInstall(config, dir, options, print, flags2) {
2818
2871
  return installOrUpdate(config, dir, options, print, false, flags2);
2819
2872
  }
@@ -3023,8 +3076,13 @@ function doAutoupdate(config, dir, options, args, ui) {
3023
3076
  const name = identityFor(ui.product).name;
3024
3077
  if (mode === "on" || mode === "off") {
3025
3078
  try {
3026
- if (mode === "on") enableSchedule(config, command2, scheduleOptions);
3027
- else disableSchedule(config, scheduleOptions);
3079
+ if (mode === "on") {
3080
+ enableSchedule(config, command2, scheduleOptions);
3081
+ persistAutoUpdateOptOut(dir, false);
3082
+ } else {
3083
+ disableSchedule(config, scheduleOptions);
3084
+ persistAutoUpdateOptOut(dir, true);
3085
+ }
3028
3086
  } catch (error) {
3029
3087
  return ui.refuse(sentence(error.message), `${ui.bin} doctor`);
3030
3088
  }
@@ -3035,8 +3093,16 @@ function doAutoupdate(config, dir, options, args, ui) {
3035
3093
  if (mode !== "status") return ui.refuse(`Unknown autoupdate mode: ${mode}.`, `${ui.bin} autoupdate status`, 2);
3036
3094
  const state = querySchedule(config, scheduleOptions);
3037
3095
  if (!state.supported) return ui.refuse("Auto-update is not supported on this platform.", `${ui.bin} update`);
3038
- if (state.enabled) ui.notice("ok", `Auto-update is on and runs every hour.${state.lastRun ? ` Last run: ${state.lastRun}.` : ""}`);
3039
- else ui.notice("note", "Auto-update is off.", `${ui.bin} autoupdate on`);
3096
+ if (state.enabled) {
3097
+ const failed = lastResultFailed(state.lastResult);
3098
+ ui.notice(
3099
+ failed ? "note" : "ok",
3100
+ `Auto-update is on and runs every hour.${state.lastRun ? ` Last run: ${state.lastRun}.` : ""}${failed ? ` Last result: ${state.lastResult}.` : ""}`,
3101
+ ...failed ? [`${ui.bin} doctor`] : []
3102
+ );
3103
+ return 0;
3104
+ }
3105
+ ui.notice("note", "Auto-update is off.", `${ui.bin} autoupdate on`);
3040
3106
  return 0;
3041
3107
  }
3042
3108
  function localFacts(config, dir, options) {
@@ -3055,10 +3121,12 @@ function signInRow(local) {
3055
3121
  if (local.signedIn) return { surface: "sign-in", state: local.expired ? "signed in \xB7 renews on next use" : "signed in", mark: "ok" };
3056
3122
  return { surface: "sign-in", state: local.expired ? "expired" : "signed out", mark: "fail" };
3057
3123
  }
3058
- function autoUpdateRow({ supported, enabled, cadence, lastRun }) {
3124
+ function autoUpdateRow({ supported, enabled, cadence, lastRun, lastResult }) {
3059
3125
  if (!supported) return { surface: AUTO_UPDATE, state: "unsupported on this platform", mark: "note" };
3060
3126
  if (!enabled) return { surface: AUTO_UPDATE, state: "off", mark: "note" };
3061
- return { surface: AUTO_UPDATE, state: `on \xB7 ${cadence ?? "hourly"}`, mark: "ok", ...lastRun ? { note: `Last run: ${lastRun}` } : {} };
3127
+ const updateFailed = lastResultFailed(lastResult);
3128
+ const note = updateFailed ? lastRun ? `Last run: ${lastRun}. Last run failed (exit ${lastResult})` : `Last run failed (exit ${lastResult})` : lastRun ? `Last run: ${lastRun}` : void 0;
3129
+ return { surface: AUTO_UPDATE, state: `on \xB7 ${cadence ?? "hourly"}`, mark: updateFailed ? "fail" : "ok", ...note ? { note } : {} };
3062
3130
  }
3063
3131
  function verdictFor(ui, local, updateAvailable, ready) {
3064
3132
  if (!local.installed) return { state: "fail", headline: "is not installed.", next: `${ui.bin} install` };
@@ -3113,7 +3181,12 @@ async function doStatus(config, dir, options, ui, print, json) {
3113
3181
  installed: local.installed,
3114
3182
  release,
3115
3183
  signIn: local.signedIn ? local.expired ? "renews" : "signed-in" : local.expired ? "expired" : "signed-out",
3116
- autoupdate: { supported: local.schedule.supported, enabled: local.schedule.enabled, lastRun: local.schedule.lastRun ?? null },
3184
+ autoupdate: {
3185
+ supported: local.schedule.supported,
3186
+ enabled: local.schedule.enabled,
3187
+ lastRun: local.schedule.lastRun ?? null,
3188
+ lastResult: local.schedule.lastResult ?? null
3189
+ },
3117
3190
  verdict: verdict.state,
3118
3191
  next: verdict.next
3119
3192
  }, null, 2));
@@ -3127,7 +3200,7 @@ async function doStatus(config, dir, options, ui, print, json) {
3127
3200
  productRow,
3128
3201
  signInRow(local),
3129
3202
  autoUpdateRow(local.schedule),
3130
- ...hub ? [{ surface: "github", state: budget?.line ?? "unknown", mark: budget && !budget.line.includes("unknown") ? "ok" : "note" }] : []
3203
+ ...hub ? (budget?.line ?? "unknown").split("\n").map((state) => ({ surface: "github", state, mark: state.includes("unknown") ? "note" : "ok" })) : []
3131
3204
  ],
3132
3205
  verdict: { ...verdict, facts: [release ? `The release is ${release}.` : "The release version could not be read."] }
3133
3206
  }, ui.render));
@@ -1732,15 +1732,21 @@ function querySchedule(config, options = {}) {
1732
1732
  if (result.code !== 0) return { supported: true, enabled: false };
1733
1733
  const lastRun = valueOf(result.stdout, "Last Run Time:");
1734
1734
  const nextRun = valueOf(result.stdout, "Next Run Time:");
1735
+ const lastResult = valueOf(result.stdout, "Last Result:");
1735
1736
  const state2 = { supported: true, enabled: true, cadence: "hourly" };
1736
1737
  if (lastRun && !/disabled|never|not run/i.test(lastRun)) state2.lastRun = lastRun;
1737
1738
  else if (nextRun && !/disabled|never/i.test(nextRun)) state2.lastRun = `next run ${nextRun}`;
1739
+ if (lastResult) state2.lastResult = lastResult;
1738
1740
  return state2;
1739
1741
  }
1740
1742
  if (platform === "darwin") {
1741
1743
  const plist = (0, import_node_path5.join)(home, "Library", "LaunchAgents", `${scheduleLabel(config)}.plist`);
1742
1744
  if (!(0, import_node_fs10.existsSync)(plist)) return { supported: true, enabled: false };
1743
- return { supported: true, enabled: true, cadence: "hourly" };
1745
+ const state2 = { supported: true, enabled: true, cadence: "hourly" };
1746
+ const printed = exec("launchctl", ["print", `gui/${process.getuid?.() ?? 501}/${scheduleLabel(config)}`]);
1747
+ const exitCode = /last exit code = (-?\d+)/.exec(`${printed.stdout ?? ""}${printed.stderr ?? ""}`)?.[1];
1748
+ if (printed.code === 0 && exitCode) state2.lastResult = exitCode;
1749
+ return state2;
1744
1750
  }
1745
1751
  const timer = (0, import_node_path5.join)(home, ".config", "systemd", "user", `${scheduleLabel(config)}.timer`);
1746
1752
  if (!(0, import_node_fs10.existsSync)(timer)) return { supported: true, enabled: false };
@@ -1748,6 +1754,9 @@ function querySchedule(config, options = {}) {
1748
1754
  const shown = exec("systemctl", ["--user", "show", `${scheduleLabel(config)}.service`, "-p", "ExecMainStartTimestamp", "--value"]);
1749
1755
  const stamp = (shown.stdout ?? "").trim();
1750
1756
  if (shown.code === 0 && stamp && stamp !== "n/a") state.lastRun = stamp;
1757
+ const status = exec("systemctl", ["--user", "show", `${scheduleLabel(config)}.service`, "-p", "ExecMainStatus", "--value"]);
1758
+ const code = (status.stdout ?? "").trim();
1759
+ if (status.code === 0 && /^\d+$/.test(code)) state.lastResult = code;
1751
1760
  return state;
1752
1761
  }
1753
1762
  function darwinPlist(label, command2) {
@@ -1799,6 +1808,36 @@ function valueOf(output, key) {
1799
1808
  function firstLine(text) {
1800
1809
  return String(text).split(/\r?\n/).map((line) => line.trim()).filter(Boolean)[0] ?? "";
1801
1810
  }
1811
+ var SCHEDULE_SIGNAL = "MM_LAUNCHER_SCHEDULE";
1812
+ var OPT_OUT_FILE = "auto-update-off";
1813
+ function autoUpdateOptOut(dir) {
1814
+ return (0, import_node_fs10.existsSync)((0, import_node_path5.join)(dir, OPT_OUT_FILE));
1815
+ }
1816
+ function persistAutoUpdateOptOut(dir, off) {
1817
+ try {
1818
+ if (off) {
1819
+ (0, import_node_fs10.mkdirSync)(dir, { recursive: true });
1820
+ (0, import_node_fs10.writeFileSync)((0, import_node_path5.join)(dir, OPT_OUT_FILE), "");
1821
+ } else (0, import_node_fs10.rmSync)((0, import_node_path5.join)(dir, OPT_OUT_FILE), { force: true });
1822
+ } catch {
1823
+ }
1824
+ }
1825
+ function armVerifiedSchedule(config, options) {
1826
+ try {
1827
+ enableSchedule(config, options.command, options);
1828
+ const verified = querySchedule(config, options);
1829
+ if (verified.enabled) return { signal: scheduleName(config), note: null };
1830
+ return { signal: null, note: `The launcher's hourly update task (${scheduleName(config)}) could not be verified \u2014 the product's own auto-update task stays.` };
1831
+ } catch (error) {
1832
+ return { signal: null, note: `The launcher could not arm its hourly update task: ${error.message} The product's own auto-update task stays.` };
1833
+ }
1834
+ }
1835
+ function lastResultFailed(value) {
1836
+ const text = value?.trim() ?? "";
1837
+ if (!text) return false;
1838
+ if (!/^-?(?:0x[0-9a-f]+|\d+)$/i.test(text)) return true;
1839
+ return ![0, 267011, 267009].includes(Number(text));
1840
+ }
1802
1841
 
1803
1842
  // src/login-github.ts
1804
1843
  var import_node_child_process3 = require("node:child_process");
@@ -2298,7 +2337,7 @@ async function refreshLauncher(target, options = {}) {
2298
2337
  }
2299
2338
 
2300
2339
  // src/index.ts
2301
- var LAUNCHER_VERSION = true ? "1.4.2" : readVersionFromPackage();
2340
+ var LAUNCHER_VERSION = true ? "1.5.0" : readVersionFromPackage();
2302
2341
  function defaultPrint(message) {
2303
2342
  process.stdout.write(`${message}
2304
2343
  `);
@@ -2755,6 +2794,8 @@ async function installOrUpdateRun(config, dir, options, print, update, flags2, m
2755
2794
  installer.finish({ ...pointer ? { version: pointer } : {}, total: 1, updated: pointer && installed !== pointer ? 1 : 0, failed: 0, dryRun: true });
2756
2795
  return 0;
2757
2796
  }
2797
+ const armNote = armScheduleForInstall(config, dir, options);
2798
+ if (armNote) installer.phase("arm", { state: "note", detail: armNote });
2758
2799
  if (pointer && current?.version === pointer && payloadPresent) {
2759
2800
  version = pointer;
2760
2801
  installer.phase("resolve", { seconds: (Date.now() - started) / 1e3 });
@@ -2847,6 +2888,18 @@ async function installOrUpdateRun(config, dir, options, print, update, flags2, m
2847
2888
  installer.stop();
2848
2889
  }
2849
2890
  }
2891
+ function armScheduleForInstall(config, dir, options) {
2892
+ if (autoUpdateOptOut(dir)) return null;
2893
+ if (!(0, import_node_sea2.isSea)() && !options.autoupdate) return null;
2894
+ const result = armVerifiedSchedule(config, {
2895
+ command: options.autoupdate?.command ?? [process.execPath, "update"],
2896
+ stateDir: dir,
2897
+ ...options.autoupdate
2898
+ });
2899
+ if (!result.signal) return result.note;
2900
+ process.env[SCHEDULE_SIGNAL] = result.signal;
2901
+ return null;
2902
+ }
2850
2903
  function doInstall(config, dir, options, print, flags2) {
2851
2904
  return installOrUpdate(config, dir, options, print, false, flags2);
2852
2905
  }
@@ -3056,8 +3109,13 @@ function doAutoupdate(config, dir, options, args, ui) {
3056
3109
  const name = identityFor(ui.product).name;
3057
3110
  if (mode === "on" || mode === "off") {
3058
3111
  try {
3059
- if (mode === "on") enableSchedule(config, command2, scheduleOptions);
3060
- else disableSchedule(config, scheduleOptions);
3112
+ if (mode === "on") {
3113
+ enableSchedule(config, command2, scheduleOptions);
3114
+ persistAutoUpdateOptOut(dir, false);
3115
+ } else {
3116
+ disableSchedule(config, scheduleOptions);
3117
+ persistAutoUpdateOptOut(dir, true);
3118
+ }
3061
3119
  } catch (error) {
3062
3120
  return ui.refuse(sentence(error.message), `${ui.bin} doctor`);
3063
3121
  }
@@ -3068,8 +3126,16 @@ function doAutoupdate(config, dir, options, args, ui) {
3068
3126
  if (mode !== "status") return ui.refuse(`Unknown autoupdate mode: ${mode}.`, `${ui.bin} autoupdate status`, 2);
3069
3127
  const state = querySchedule(config, scheduleOptions);
3070
3128
  if (!state.supported) return ui.refuse("Auto-update is not supported on this platform.", `${ui.bin} update`);
3071
- if (state.enabled) ui.notice("ok", `Auto-update is on and runs every hour.${state.lastRun ? ` Last run: ${state.lastRun}.` : ""}`);
3072
- else ui.notice("note", "Auto-update is off.", `${ui.bin} autoupdate on`);
3129
+ if (state.enabled) {
3130
+ const failed = lastResultFailed(state.lastResult);
3131
+ ui.notice(
3132
+ failed ? "note" : "ok",
3133
+ `Auto-update is on and runs every hour.${state.lastRun ? ` Last run: ${state.lastRun}.` : ""}${failed ? ` Last result: ${state.lastResult}.` : ""}`,
3134
+ ...failed ? [`${ui.bin} doctor`] : []
3135
+ );
3136
+ return 0;
3137
+ }
3138
+ ui.notice("note", "Auto-update is off.", `${ui.bin} autoupdate on`);
3073
3139
  return 0;
3074
3140
  }
3075
3141
  function localFacts(config, dir, options) {
@@ -3088,10 +3154,12 @@ function signInRow(local) {
3088
3154
  if (local.signedIn) return { surface: "sign-in", state: local.expired ? "signed in \xB7 renews on next use" : "signed in", mark: "ok" };
3089
3155
  return { surface: "sign-in", state: local.expired ? "expired" : "signed out", mark: "fail" };
3090
3156
  }
3091
- function autoUpdateRow({ supported, enabled, cadence, lastRun }) {
3157
+ function autoUpdateRow({ supported, enabled, cadence, lastRun, lastResult }) {
3092
3158
  if (!supported) return { surface: AUTO_UPDATE, state: "unsupported on this platform", mark: "note" };
3093
3159
  if (!enabled) return { surface: AUTO_UPDATE, state: "off", mark: "note" };
3094
- return { surface: AUTO_UPDATE, state: `on \xB7 ${cadence ?? "hourly"}`, mark: "ok", ...lastRun ? { note: `Last run: ${lastRun}` } : {} };
3160
+ const updateFailed = lastResultFailed(lastResult);
3161
+ const note = updateFailed ? lastRun ? `Last run: ${lastRun}. Last run failed (exit ${lastResult})` : `Last run failed (exit ${lastResult})` : lastRun ? `Last run: ${lastRun}` : void 0;
3162
+ return { surface: AUTO_UPDATE, state: `on \xB7 ${cadence ?? "hourly"}`, mark: updateFailed ? "fail" : "ok", ...note ? { note } : {} };
3095
3163
  }
3096
3164
  function verdictFor(ui, local, updateAvailable, ready) {
3097
3165
  if (!local.installed) return { state: "fail", headline: "is not installed.", next: `${ui.bin} install` };
@@ -3146,7 +3214,12 @@ async function doStatus(config, dir, options, ui, print, json) {
3146
3214
  installed: local.installed,
3147
3215
  release,
3148
3216
  signIn: local.signedIn ? local.expired ? "renews" : "signed-in" : local.expired ? "expired" : "signed-out",
3149
- autoupdate: { supported: local.schedule.supported, enabled: local.schedule.enabled, lastRun: local.schedule.lastRun ?? null },
3217
+ autoupdate: {
3218
+ supported: local.schedule.supported,
3219
+ enabled: local.schedule.enabled,
3220
+ lastRun: local.schedule.lastRun ?? null,
3221
+ lastResult: local.schedule.lastResult ?? null
3222
+ },
3150
3223
  verdict: verdict.state,
3151
3224
  next: verdict.next
3152
3225
  }, null, 2));
@@ -3160,7 +3233,7 @@ async function doStatus(config, dir, options, ui, print, json) {
3160
3233
  productRow,
3161
3234
  signInRow(local),
3162
3235
  autoUpdateRow(local.schedule),
3163
- ...hub ? [{ surface: "github", state: budget?.line ?? "unknown", mark: budget && !budget.line.includes("unknown") ? "ok" : "note" }] : []
3236
+ ...hub ? (budget?.line ?? "unknown").split("\n").map((state) => ({ surface: "github", state, mark: state.includes("unknown") ? "note" : "ok" })) : []
3164
3237
  ],
3165
3238
  verdict: { ...verdict, facts: [release ? `The release is ${release}.` : "The release version could not be read."] }
3166
3239
  }, ui.render));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/installer-launcher",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "Single-executable (SEA) launcher: sign-in, gated payload fetch, self-update. One copy ships per product.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",