@mutmutco/installer-launcher 0.1.15 → 0.1.18

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
@@ -799,15 +799,24 @@ function createFace({ product, color = false, columns, env = process.env, operat
799
799
  const record = { v: PROGRESS_PROTOCOL, step: stripColor(title), state: kind };
800
800
  if (typeof measure === "number") record.ms = Math.max(0, Math.round(measure * 1e3));
801
801
  if (kind === "running" && typeof measure === "string") record.measure = measure;
802
- try {
803
- if (progressFile) appendFileSync(progressFile, `${JSON.stringify(record)}
804
- `);
805
- else writeSync(progressFd, `${JSON.stringify(record)}
806
- `);
807
- return true;
808
- } catch {
809
- return false;
802
+ const line = `${JSON.stringify(record)}
803
+ `;
804
+ if (progressFd !== null) {
805
+ try {
806
+ writeSync(progressFd, line);
807
+ return true;
808
+ } catch {
809
+ }
810
810
  }
811
+ if (progressFile) {
812
+ try {
813
+ appendFileSync(progressFile, line);
814
+ return true;
815
+ } catch {
816
+ return false;
817
+ }
818
+ }
819
+ return false;
811
820
  };
812
821
  const welcome = () => continuesFace || nested ? [] : [
813
822
  `${paint(identity.accent, GLYPH.diamond)} ${paint(identity.accent, identity.name)} \u2014 Mutatis Mutandis`,
@@ -821,7 +830,7 @@ function createFace({ product, color = false, columns, env = process.env, operat
821
830
  };
822
831
  const step = (title, measure = null, kind = "ok") => {
823
832
  if (emitMilestone(title, measure, kind)) return "";
824
- const glyph = title === "Armed hourly updates" && kind === "ok" ? GLYPH.clock : kind === "fail" ? paint(identity.accent, GLYPH.cross) : kind === "note" ? paint(PALETTE.muted, GLYPH.dot) : paint(PALETTE.green, GLYPH.check);
833
+ const glyph = title === "Armed hourly updates" && kind === "ok" ? GLYPH.clock : kind === "fail" ? paint(identity.accent, GLYPH.cross) : kind === "note" ? paint(PALETTE.muted, GLYPH.dot) : paint(identity.accent, GLYPH.check);
825
834
  const measured = measure === null || measure === void 0 ? "" : paint(PALETTE.muted, typeof measure === "number" ? `${Math.max(0, Math.round(measure))}s` : String(measure).trim());
826
835
  const time = measured;
827
836
  const column = Math.min(44, Math.max(0, width - 8));
@@ -842,7 +851,7 @@ function createFace({ product, color = false, columns, env = process.env, operat
842
851
  const content = Math.min(width - 6, Math.max(...body.map(visibleWidth)));
843
852
  const rule = paint(identity.accent, GLYPH.rule.repeat(content + 4));
844
853
  const frame = (left, right) => `${paint(identity.accent, left)}${rule}${paint(identity.accent, right)}`;
845
- const bodyRow = (line) => line.startsWith(GLYPH.check) ? `${paint(PALETTE.green, GLYPH.check)}${line.slice(1)}` : line;
854
+ const bodyRow = (line) => line.startsWith(GLYPH.check) ? `${paint(identity.accent, GLYPH.check)}${line.slice(1)}` : line;
846
855
  return [
847
856
  frame(GLYPH.boxTop, GLYPH.boxTopEnd),
848
857
  ...body.map((line) => `${paint(identity.accent, GLYPH.bar)} ${bodyRow(line)}${" ".repeat(Math.max(0, content - visibleWidth(line)))} ${paint(identity.accent, GLYPH.bar)}`),
@@ -873,16 +882,31 @@ import { appendFileSync as appendFileSync2, writeSync as writeSync2 } from "node
873
882
  import { Worker } from "node:worker_threads";
874
883
 
875
884
  // ../face/src/encoding.ts
885
+ import { execFileSync } from "node:child_process";
876
886
  var UNICODE_SPINNER_FRAMES = Object.freeze(["\u25D2", "\u25D0", "\u25D3", "\u25D1"]);
877
887
  var ASCII_SPINNER_FRAMES = Object.freeze(["-", "\\", "|", "/"]);
878
- function consoleRendersUnicode(env = process.env, platform = process.platform) {
888
+ var cachedCodePage;
889
+ function consoleOutputCodePage() {
890
+ if (cachedCodePage !== void 0) return cachedCodePage;
891
+ cachedCodePage = null;
892
+ try {
893
+ const out = execFileSync("chcp.com", { windowsHide: true, encoding: "utf8", timeout: 5e3 });
894
+ const pages = [...String(out).matchAll(/(\d{3,5})/gu)].map((m) => Number(m[1]));
895
+ cachedCodePage = pages.length ? pages[pages.length - 1] : null;
896
+ } catch {
897
+ cachedCodePage = null;
898
+ }
899
+ return cachedCodePage;
900
+ }
901
+ function consoleRendersUnicode(env = process.env, platform = process.platform, codePage = platform === "win32" ? consoleOutputCodePage() : null) {
879
902
  if (env.MM_FACE_ASCII === "1" || env.NO_UNICODE === "1") return false;
880
903
  const locale = env.LC_ALL || env.LC_CTYPE || env.LANG || "";
881
904
  if (locale === "C" || locale === "POSIX" || /^C\./u.test(locale) || /^POSIX\./u.test(locale)) return false;
882
905
  if (/cp437|ibm437|\b437\b/iu.test(locale)) return false;
883
906
  if (/utf-?8/iu.test(locale)) return true;
884
907
  if (platform === "win32") {
885
- return Boolean(env.WT_SESSION) || env.TERM_PROGRAM === "vscode" || env.CHCP === "65001" || env.ConEmuANSI === "ON";
908
+ if (env.WT_SESSION || env.ConEmuANSI === "ON") return true;
909
+ return codePage === 65001;
886
910
  }
887
911
  return true;
888
912
  }
@@ -1172,6 +1196,7 @@ function createInstallerRun(value, options = {}) {
1172
1196
  let chunkColumn = 0;
1173
1197
  const trailingCR = /* @__PURE__ */ new Set();
1174
1198
  let deferredActivity;
1199
+ const drawnPhaseCompletions = /* @__PURE__ */ new Set();
1175
1200
  const closeChunk = () => {
1176
1201
  if (chunkOpen) emit("\n", chunkChannel);
1177
1202
  chunkOpen = false;
@@ -1218,11 +1243,15 @@ function createInstallerRun(value, options = {}) {
1218
1243
  const fold = operation === "update" && UPDATE_CHECK_PHASES.has(id) && state !== "fail";
1219
1244
  const title = PHASES[fold ? "check" : id][state === "ok" ? 1 : 0];
1220
1245
  if (state === "running") {
1221
- if (face.progress(title, facts.measure ?? null)) return;
1222
- if (activeTitle === title) spinner.say(title, facts.measure ?? null);
1246
+ if (facts.runningTitle !== void 0 && (typeof facts.runningTitle !== "string" || !facts.runningTitle.trim() || /[\r\n\x00-\x1f]/u.test(facts.runningTitle))) {
1247
+ throw new Error("installer run: invalid runningTitle");
1248
+ }
1249
+ const runningTitle = facts.runningTitle?.trim() ?? title;
1250
+ if (face.progress(runningTitle, facts.measure ?? null)) return;
1251
+ if (activeTitle === runningTitle) spinner.say(runningTitle, facts.measure ?? null);
1223
1252
  else {
1224
- activeTitle = title;
1225
- spinner.start(title, facts.measure ?? null);
1253
+ activeTitle = runningTitle;
1254
+ spinner.start(runningTitle, facts.measure ?? null);
1226
1255
  }
1227
1256
  return;
1228
1257
  }
@@ -1230,7 +1259,10 @@ function createInstallerRun(value, options = {}) {
1230
1259
  if (facts.detail) run2.relay(facts.detail);
1231
1260
  return;
1232
1261
  }
1233
- if (!face.continues(id, state)) durable(title, facts.seconds ?? facts.measure ?? null, state);
1262
+ if (!face.continues(id, state)) {
1263
+ durable(title, facts.seconds ?? facts.measure ?? null, state);
1264
+ if (state === "ok") drawnPhaseCompletions.add(title);
1265
+ }
1234
1266
  if (facts.detail) run2.relay(facts.detail);
1235
1267
  },
1236
1268
  surface(facts) {
@@ -1261,7 +1293,9 @@ function createInstallerRun(value, options = {}) {
1261
1293
  }
1262
1294
  return;
1263
1295
  }
1296
+ if (state !== "fail" && drawnPhaseCompletions.has(step)) return;
1264
1297
  durable(step, ms === void 0 ? null : ms / 1e3, state);
1298
+ if (state === "ok") drawnPhaseCompletions.add(step);
1265
1299
  },
1266
1300
  signIn({ url, code }) {
1267
1301
  start();
@@ -1776,7 +1810,7 @@ function page(title, body) {
1776
1810
  }
1777
1811
 
1778
1812
  // src/index.ts
1779
- var LAUNCHER_VERSION = true ? "0.1.15" : readVersionFromPackage();
1813
+ var LAUNCHER_VERSION = true ? "0.1.18" : readVersionFromPackage();
1780
1814
  function defaultPrint(message) {
1781
1815
  process.stdout.write(`${message}
1782
1816
  `);
@@ -2060,6 +2094,9 @@ function faceProduct(config) {
2060
2094
  const known = { mmi: "mmi-hub", jerv: "jerv-hub" };
2061
2095
  return known[config.product] ?? config.product;
2062
2096
  }
2097
+ function formatMb(bytes) {
2098
+ return (bytes / 1048576).toFixed(1).replace(/\.0$/, "");
2099
+ }
2063
2100
  async function installOrUpdate(config, dir, options, print, update) {
2064
2101
  const product = faceProduct(config);
2065
2102
  const installer = createInstallerRun({
@@ -2118,7 +2155,8 @@ async function installOrUpdate(config, dir, options, print, update) {
2118
2155
  const candidateDir = join6(dir, "candidates", candidate);
2119
2156
  const onProgress = ({ done, total }) => installer.phase("download", {
2120
2157
  state: "running",
2121
- measure: total ? `${Math.floor(done / total * 100)}% \xB7 ${done}/${total} B` : `${done} B`
2158
+ measure: total ? `${Math.floor(done / total * 100)}% \xB7 ${formatMb(done)} of ${formatMb(total)} MB` : `${formatMb(done)} MB`,
2159
+ ...total ? { runningTitle: `Downloading ${config.product} ${version} (${formatMb(total)} MB)` } : {}
2122
2160
  });
2123
2161
  if (!cached) await downloadAndUnpack(config, candidateDir, manifest, accessToken, { fetchImpl, onProgress, cacheDir: dir });
2124
2162
  const acquisition = existsSync7(join6(candidateDir, "payload", "payload.json")) ? readAcquisition(join6(candidateDir, "payload")) : null;
@@ -2472,6 +2510,7 @@ export {
2472
2510
  LAUNCHER_VERSION,
2473
2511
  defaultRunEntry,
2474
2512
  ensureFreshToken,
2513
+ formatMb,
2475
2514
  readPayloadEntry,
2476
2515
  readPayloadRun,
2477
2516
  readPayloadVerbs,
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  LAUNCHER_VERSION: () => LAUNCHER_VERSION,
24
24
  defaultRunEntry: () => defaultRunEntry,
25
25
  ensureFreshToken: () => ensureFreshToken,
26
+ formatMb: () => formatMb,
26
27
  readPayloadEntry: () => readPayloadEntry,
27
28
  readPayloadRun: () => readPayloadRun,
28
29
  readPayloadVerbs: () => readPayloadVerbs,
@@ -703,7 +704,7 @@ async function installAcquisition(dir, candidate, version, acquisition, options)
703
704
  }
704
705
 
705
706
  // src/index.ts
706
- var import_node_child_process4 = require("node:child_process");
707
+ var import_node_child_process5 = require("node:child_process");
707
708
  var import_node_fs11 = require("node:fs");
708
709
  var import_node_os4 = require("node:os");
709
710
  var import_node_path6 = require("node:path");
@@ -831,15 +832,24 @@ function createFace({ product, color = false, columns, env = process.env, operat
831
832
  const record = { v: PROGRESS_PROTOCOL, step: stripColor(title), state: kind };
832
833
  if (typeof measure === "number") record.ms = Math.max(0, Math.round(measure * 1e3));
833
834
  if (kind === "running" && typeof measure === "string") record.measure = measure;
834
- try {
835
- if (progressFile) (0, import_node_fs6.appendFileSync)(progressFile, `${JSON.stringify(record)}
836
- `);
837
- else (0, import_node_fs6.writeSync)(progressFd, `${JSON.stringify(record)}
838
- `);
839
- return true;
840
- } catch {
841
- return false;
835
+ const line = `${JSON.stringify(record)}
836
+ `;
837
+ if (progressFd !== null) {
838
+ try {
839
+ (0, import_node_fs6.writeSync)(progressFd, line);
840
+ return true;
841
+ } catch {
842
+ }
843
+ }
844
+ if (progressFile) {
845
+ try {
846
+ (0, import_node_fs6.appendFileSync)(progressFile, line);
847
+ return true;
848
+ } catch {
849
+ return false;
850
+ }
842
851
  }
852
+ return false;
843
853
  };
844
854
  const welcome = () => continuesFace || nested ? [] : [
845
855
  `${paint(identity.accent, GLYPH.diamond)} ${paint(identity.accent, identity.name)} \u2014 Mutatis Mutandis`,
@@ -853,7 +863,7 @@ function createFace({ product, color = false, columns, env = process.env, operat
853
863
  };
854
864
  const step = (title, measure = null, kind = "ok") => {
855
865
  if (emitMilestone(title, measure, kind)) return "";
856
- const glyph = title === "Armed hourly updates" && kind === "ok" ? GLYPH.clock : kind === "fail" ? paint(identity.accent, GLYPH.cross) : kind === "note" ? paint(PALETTE.muted, GLYPH.dot) : paint(PALETTE.green, GLYPH.check);
866
+ const glyph = title === "Armed hourly updates" && kind === "ok" ? GLYPH.clock : kind === "fail" ? paint(identity.accent, GLYPH.cross) : kind === "note" ? paint(PALETTE.muted, GLYPH.dot) : paint(identity.accent, GLYPH.check);
857
867
  const measured = measure === null || measure === void 0 ? "" : paint(PALETTE.muted, typeof measure === "number" ? `${Math.max(0, Math.round(measure))}s` : String(measure).trim());
858
868
  const time = measured;
859
869
  const column = Math.min(44, Math.max(0, width - 8));
@@ -874,7 +884,7 @@ function createFace({ product, color = false, columns, env = process.env, operat
874
884
  const content = Math.min(width - 6, Math.max(...body.map(visibleWidth)));
875
885
  const rule = paint(identity.accent, GLYPH.rule.repeat(content + 4));
876
886
  const frame = (left, right) => `${paint(identity.accent, left)}${rule}${paint(identity.accent, right)}`;
877
- const bodyRow = (line) => line.startsWith(GLYPH.check) ? `${paint(PALETTE.green, GLYPH.check)}${line.slice(1)}` : line;
887
+ const bodyRow = (line) => line.startsWith(GLYPH.check) ? `${paint(identity.accent, GLYPH.check)}${line.slice(1)}` : line;
878
888
  return [
879
889
  frame(GLYPH.boxTop, GLYPH.boxTopEnd),
880
890
  ...body.map((line) => `${paint(identity.accent, GLYPH.bar)} ${bodyRow(line)}${" ".repeat(Math.max(0, content - visibleWidth(line)))} ${paint(identity.accent, GLYPH.bar)}`),
@@ -905,16 +915,31 @@ var import_node_fs7 = require("node:fs");
905
915
  var import_node_worker_threads = require("node:worker_threads");
906
916
 
907
917
  // ../face/src/encoding.ts
918
+ var import_node_child_process2 = require("node:child_process");
908
919
  var UNICODE_SPINNER_FRAMES = Object.freeze(["\u25D2", "\u25D0", "\u25D3", "\u25D1"]);
909
920
  var ASCII_SPINNER_FRAMES = Object.freeze(["-", "\\", "|", "/"]);
910
- function consoleRendersUnicode(env = process.env, platform = process.platform) {
921
+ var cachedCodePage;
922
+ function consoleOutputCodePage() {
923
+ if (cachedCodePage !== void 0) return cachedCodePage;
924
+ cachedCodePage = null;
925
+ try {
926
+ const out = (0, import_node_child_process2.execFileSync)("chcp.com", { windowsHide: true, encoding: "utf8", timeout: 5e3 });
927
+ const pages = [...String(out).matchAll(/(\d{3,5})/gu)].map((m) => Number(m[1]));
928
+ cachedCodePage = pages.length ? pages[pages.length - 1] : null;
929
+ } catch {
930
+ cachedCodePage = null;
931
+ }
932
+ return cachedCodePage;
933
+ }
934
+ function consoleRendersUnicode(env = process.env, platform = process.platform, codePage = platform === "win32" ? consoleOutputCodePage() : null) {
911
935
  if (env.MM_FACE_ASCII === "1" || env.NO_UNICODE === "1") return false;
912
936
  const locale = env.LC_ALL || env.LC_CTYPE || env.LANG || "";
913
937
  if (locale === "C" || locale === "POSIX" || /^C\./u.test(locale) || /^POSIX\./u.test(locale)) return false;
914
938
  if (/cp437|ibm437|\b437\b/iu.test(locale)) return false;
915
939
  if (/utf-?8/iu.test(locale)) return true;
916
940
  if (platform === "win32") {
917
- return Boolean(env.WT_SESSION) || env.TERM_PROGRAM === "vscode" || env.CHCP === "65001" || env.ConEmuANSI === "ON";
941
+ if (env.WT_SESSION || env.ConEmuANSI === "ON") return true;
942
+ return codePage === 65001;
918
943
  }
919
944
  return true;
920
945
  }
@@ -1204,6 +1229,7 @@ function createInstallerRun(value, options = {}) {
1204
1229
  let chunkColumn = 0;
1205
1230
  const trailingCR = /* @__PURE__ */ new Set();
1206
1231
  let deferredActivity;
1232
+ const drawnPhaseCompletions = /* @__PURE__ */ new Set();
1207
1233
  const closeChunk = () => {
1208
1234
  if (chunkOpen) emit("\n", chunkChannel);
1209
1235
  chunkOpen = false;
@@ -1250,11 +1276,15 @@ function createInstallerRun(value, options = {}) {
1250
1276
  const fold = operation === "update" && UPDATE_CHECK_PHASES.has(id) && state !== "fail";
1251
1277
  const title = PHASES[fold ? "check" : id][state === "ok" ? 1 : 0];
1252
1278
  if (state === "running") {
1253
- if (face.progress(title, facts.measure ?? null)) return;
1254
- if (activeTitle === title) spinner.say(title, facts.measure ?? null);
1279
+ if (facts.runningTitle !== void 0 && (typeof facts.runningTitle !== "string" || !facts.runningTitle.trim() || /[\r\n\x00-\x1f]/u.test(facts.runningTitle))) {
1280
+ throw new Error("installer run: invalid runningTitle");
1281
+ }
1282
+ const runningTitle = facts.runningTitle?.trim() ?? title;
1283
+ if (face.progress(runningTitle, facts.measure ?? null)) return;
1284
+ if (activeTitle === runningTitle) spinner.say(runningTitle, facts.measure ?? null);
1255
1285
  else {
1256
- activeTitle = title;
1257
- spinner.start(title, facts.measure ?? null);
1286
+ activeTitle = runningTitle;
1287
+ spinner.start(runningTitle, facts.measure ?? null);
1258
1288
  }
1259
1289
  return;
1260
1290
  }
@@ -1262,7 +1292,10 @@ function createInstallerRun(value, options = {}) {
1262
1292
  if (facts.detail) run2.relay(facts.detail);
1263
1293
  return;
1264
1294
  }
1265
- if (!face.continues(id, state)) durable(title, facts.seconds ?? facts.measure ?? null, state);
1295
+ if (!face.continues(id, state)) {
1296
+ durable(title, facts.seconds ?? facts.measure ?? null, state);
1297
+ if (state === "ok") drawnPhaseCompletions.add(title);
1298
+ }
1266
1299
  if (facts.detail) run2.relay(facts.detail);
1267
1300
  },
1268
1301
  surface(facts) {
@@ -1293,7 +1326,9 @@ function createInstallerRun(value, options = {}) {
1293
1326
  }
1294
1327
  return;
1295
1328
  }
1329
+ if (state !== "fail" && drawnPhaseCompletions.has(step)) return;
1296
1330
  durable(step, ms === void 0 ? null : ms / 1e3, state);
1331
+ if (state === "ok") drawnPhaseCompletions.add(step);
1297
1332
  },
1298
1333
  signIn({ url, code }) {
1299
1334
  start();
@@ -1399,7 +1434,7 @@ function createInstallerRun(value, options = {}) {
1399
1434
  }
1400
1435
 
1401
1436
  // src/autoupdate.ts
1402
- var import_node_child_process2 = require("node:child_process");
1437
+ var import_node_child_process3 = require("node:child_process");
1403
1438
  var import_node_fs10 = require("node:fs");
1404
1439
  var import_node_os3 = require("node:os");
1405
1440
  var import_node_path5 = require("node:path");
@@ -1409,7 +1444,7 @@ function schedulePlatform(override) {
1409
1444
  return null;
1410
1445
  }
1411
1446
  function defaultExec(command2, args) {
1412
- const result = (0, import_node_child_process2.spawnSync)(command2, args, { encoding: "utf8", windowsHide: true });
1447
+ const result = (0, import_node_child_process3.spawnSync)(command2, args, { encoding: "utf8", windowsHide: true });
1413
1448
  if (result.error) return { code: 1, stdout: "", stderr: result.error.message };
1414
1449
  return {
1415
1450
  code: typeof result.status === "number" ? result.status : 1,
@@ -1574,14 +1609,14 @@ function firstLine(text) {
1574
1609
  }
1575
1610
 
1576
1611
  // src/login-github.ts
1577
- var import_node_child_process3 = require("node:child_process");
1612
+ var import_node_child_process4 = require("node:child_process");
1578
1613
  var realSleep = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
1579
1614
  function openBrowser(url) {
1580
1615
  if (process.env.LAUNCHER_NO_OPEN === "1") return;
1581
1616
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "rundll32" : "xdg-open";
1582
1617
  const args = process.platform === "win32" ? ["url.dll,FileProtocolHandler", url] : [url];
1583
1618
  try {
1584
- const child = (0, import_node_child_process3.spawn)(opener, args, { detached: true, stdio: "ignore", windowsHide: true });
1619
+ const child = (0, import_node_child_process4.spawn)(opener, args, { detached: true, stdio: "ignore", windowsHide: true });
1585
1620
  child.on("error", () => {
1586
1621
  });
1587
1622
  child.unref();
@@ -1808,7 +1843,7 @@ function page(title, body) {
1808
1843
  }
1809
1844
 
1810
1845
  // src/index.ts
1811
- var LAUNCHER_VERSION = true ? "0.1.15" : readVersionFromPackage();
1846
+ var LAUNCHER_VERSION = true ? "0.1.18" : readVersionFromPackage();
1812
1847
  function defaultPrint(message) {
1813
1848
  process.stdout.write(`${message}
1814
1849
  `);
@@ -2061,7 +2096,7 @@ function defaultRunEntry(entry2, cwd, env) {
2061
2096
  const [command2, ...args] = entry2;
2062
2097
  const shell = needsShell(command2);
2063
2098
  const commandLine = shell ? [command2, ...args].map(quoteForShell).join(" ") : command2;
2064
- const spawnEntry = (progress2) => (0, import_node_child_process4.spawnSync)(commandLine, shell ? [] : args, {
2099
+ const spawnEntry = (progress2) => (0, import_node_child_process5.spawnSync)(commandLine, shell ? [] : args, {
2065
2100
  cwd,
2066
2101
  stdio: progress2 ? ["inherit", "inherit", "inherit", "pipe"] : "inherit",
2067
2102
  shell,
@@ -2092,6 +2127,9 @@ function faceProduct(config) {
2092
2127
  const known = { mmi: "mmi-hub", jerv: "jerv-hub" };
2093
2128
  return known[config.product] ?? config.product;
2094
2129
  }
2130
+ function formatMb(bytes) {
2131
+ return (bytes / 1048576).toFixed(1).replace(/\.0$/, "");
2132
+ }
2095
2133
  async function installOrUpdate(config, dir, options, print, update) {
2096
2134
  const product = faceProduct(config);
2097
2135
  const installer = createInstallerRun({
@@ -2150,7 +2188,8 @@ async function installOrUpdate(config, dir, options, print, update) {
2150
2188
  const candidateDir = (0, import_node_path6.join)(dir, "candidates", candidate);
2151
2189
  const onProgress = ({ done, total }) => installer.phase("download", {
2152
2190
  state: "running",
2153
- measure: total ? `${Math.floor(done / total * 100)}% \xB7 ${done}/${total} B` : `${done} B`
2191
+ measure: total ? `${Math.floor(done / total * 100)}% \xB7 ${formatMb(done)} of ${formatMb(total)} MB` : `${formatMb(done)} MB`,
2192
+ ...total ? { runningTitle: `Downloading ${config.product} ${version} (${formatMb(total)} MB)` } : {}
2154
2193
  });
2155
2194
  if (!cached) await downloadAndUnpack(config, candidateDir, manifest, accessToken, { fetchImpl, onProgress, cacheDir: dir });
2156
2195
  const acquisition = (0, import_node_fs11.existsSync)((0, import_node_path6.join)(candidateDir, "payload", "payload.json")) ? readAcquisition((0, import_node_path6.join)(candidateDir, "payload")) : null;
@@ -2302,7 +2341,7 @@ async function runInstallEntry(entry2, cwd, env, installer, tokens = null) {
2302
2341
  const redact = (text) => secrets.reduce((safe, value) => safe.replaceAll(value, "[redacted]"), text);
2303
2342
  try {
2304
2343
  const result = await new Promise((resolve3) => {
2305
- const child = (0, import_node_child_process4.spawn)(shell ? [command2, ...args].map(quoteForShell).join(" ") : command2, shell ? [] : args, {
2344
+ const child = (0, import_node_child_process5.spawn)(shell ? [command2, ...args].map(quoteForShell).join(" ") : command2, shell ? [] : args, {
2306
2345
  cwd,
2307
2346
  shell,
2308
2347
  windowsHide: true,
@@ -2505,6 +2544,7 @@ if (invokedAsMain) {
2505
2544
  LAUNCHER_VERSION,
2506
2545
  defaultRunEntry,
2507
2546
  ensureFreshToken,
2547
+ formatMb,
2508
2548
  readPayloadEntry,
2509
2549
  readPayloadRun,
2510
2550
  readPayloadVerbs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/installer-launcher",
3
- "version": "0.1.15",
3
+ "version": "0.1.18",
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",