@mutmutco/installer-launcher 0.1.4 → 0.1.7

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
@@ -863,7 +863,7 @@ function wipeProductDir(dir) {
863
863
  }
864
864
 
865
865
  // src/index.ts
866
- var LAUNCHER_VERSION = true ? "0.1.4" : readVersionFromPackage();
866
+ var LAUNCHER_VERSION = true ? "0.1.7" : readVersionFromPackage();
867
867
  function defaultPrint(message) {
868
868
  process.stdout.write(`${message}
869
869
  `);
@@ -1075,20 +1075,58 @@ function needsShell(command) {
1075
1075
  function quoteForShell(arg) {
1076
1076
  return /[\s"&|<>^%]/.test(arg) ? `"${arg.replace(/"/g, '\\"')}"` : arg;
1077
1077
  }
1078
+ var SUPPORTED_PROGRESS_PROTOCOLS = /* @__PURE__ */ new Set([1]);
1079
+ function parseProgress(raw) {
1080
+ if (raw === null || raw === void 0) return [];
1081
+ const progress = [];
1082
+ for (const line of raw.toString().split(/\r?\n/)) {
1083
+ if (!line) continue;
1084
+ try {
1085
+ const message = JSON.parse(line);
1086
+ if (!SUPPORTED_PROGRESS_PROTOCOLS.has(message.v) || typeof message.step !== "string") continue;
1087
+ const state = message.state ?? "ok";
1088
+ if (state !== "ok" && state !== "fail" && state !== "note") continue;
1089
+ if (message.ms !== void 0 && typeof message.ms !== "number") continue;
1090
+ progress.push({
1091
+ step: message.step,
1092
+ state,
1093
+ ...typeof message.ms === "number" ? { ms: message.ms } : {}
1094
+ });
1095
+ } catch {
1096
+ }
1097
+ }
1098
+ return progress;
1099
+ }
1078
1100
  function defaultRunEntry(entry, cwd, env) {
1079
1101
  const [command, ...args] = entry;
1080
1102
  const shell = needsShell(command);
1081
1103
  const commandLine = shell ? [command, ...args].map(quoteForShell).join(" ") : command;
1082
- const result = spawnSync2(commandLine, shell ? [] : args, {
1104
+ const spawn2 = (progress2) => spawnSync2(commandLine, shell ? [] : args, {
1083
1105
  cwd,
1084
- stdio: "inherit",
1106
+ stdio: progress2 ? ["inherit", "inherit", "inherit", "pipe"] : "inherit",
1085
1107
  shell,
1086
- env: env ?? process.env,
1108
+ env: progress2 ? { ...env ?? process.env, MM_PROGRESS_FD: "3", MM_PROGRESS_PROTOCOL: "1" } : env ?? process.env,
1087
1109
  windowsHide: true
1088
1110
  });
1111
+ let result;
1112
+ if (process.platform === "win32" && shell) {
1113
+ result = spawn2(false);
1114
+ } else {
1115
+ try {
1116
+ result = spawn2(true);
1117
+ } catch {
1118
+ result = spawn2(false);
1119
+ }
1120
+ }
1089
1121
  if (result.error) return { ok: false, error: result.error.message };
1090
1122
  const code = typeof result.status === "number" ? result.status : void 0;
1091
- return { ok: result.status === 0, error: result.status === 0 ? void 0 : `exit code ${result.status}`, code };
1123
+ const progress = parseProgress(result.output?.[3]);
1124
+ return {
1125
+ ok: result.status === 0,
1126
+ error: result.status === 0 ? void 0 : `exit code ${result.status}`,
1127
+ code,
1128
+ ...progress.length > 0 ? { progress } : {}
1129
+ };
1092
1130
  }
1093
1131
  function faceProduct(config) {
1094
1132
  const known = { mmi: "mmi-hub", jerv: "jerv-hub" };
@@ -1110,9 +1148,13 @@ function faceFor(config, options) {
1110
1148
  function since(start) {
1111
1149
  return (Date.now() - start) / 1e3;
1112
1150
  }
1151
+ function outerConsoleOwnsOutcome() {
1152
+ return process.env.MM_OUTER_CONSOLE === "1";
1153
+ }
1113
1154
  function printReceipt(face, config, print, ready, lines) {
1114
1155
  const name = face ? face.identity.name : config.product;
1115
1156
  const headline = ready ? `${name} is ready.` : `${name} is installed, but not ready yet.`;
1157
+ if (ready && outerConsoleOwnsOutcome()) return;
1116
1158
  if (!face) {
1117
1159
  print(headline);
1118
1160
  for (const line of lines) print(line.trim());
@@ -1125,6 +1167,11 @@ function printReceipt(face, config, print, ready, lines) {
1125
1167
  function printStep(face, print, title, seconds, kind = "ok") {
1126
1168
  print(face ? face.step(title, seconds, kind) : title);
1127
1169
  }
1170
+ function printProgress(face, print, progress) {
1171
+ for (const message of progress ?? []) {
1172
+ printStep(face, print, message.step, message.ms === void 0 ? null : message.ms / 1e3, message.state);
1173
+ }
1174
+ }
1128
1175
  async function doInstall(config, dir, options, print) {
1129
1176
  const fetchImpl = options.fetchImpl ?? fetch;
1130
1177
  const face = faceFor(config, options);
@@ -1139,7 +1186,7 @@ async function doInstall(config, dir, options, print) {
1139
1186
  async function doUpdate(config, dir, options, print) {
1140
1187
  const fetchImpl = options.fetchImpl ?? fetch;
1141
1188
  const face = faceFor(config, options);
1142
- if (face) for (const line of face.welcome()) print(line);
1189
+ if (face && !outerConsoleOwnsOutcome()) for (const line of face.welcome()) print(line);
1143
1190
  const accessToken = await fetchAccessTokenOrLogin(config, dir, options, print);
1144
1191
  const started = Date.now();
1145
1192
  const manifest = await fetchVerifiedManifest(config, accessToken, fetchImpl);
@@ -1178,8 +1225,8 @@ function finishLastMile(config, dir, options, print, face, version) {
1178
1225
  const payload = payloadDir(dir);
1179
1226
  if (!entry) {
1180
1227
  printReceipt(face, config, print, true, [
1181
- ` Installed ${version} into ${dir}`,
1182
- ` next step: run ${join4(payload, config.binName)} to start ${config.product}.`
1228
+ `Installed ${version} into ${dir}`,
1229
+ `next step: run ${join4(payload, config.binName)} to start ${config.product}.`
1183
1230
  ]);
1184
1231
  return 0;
1185
1232
  }
@@ -1188,19 +1235,20 @@ function finishLastMile(config, dir, options, print, face, version) {
1188
1235
  if (dataFile) {
1189
1236
  printStep(face, print, `The payload names ${dataFile} as its command, but that is a file, not a program`, null, "fail");
1190
1237
  printReceipt(face, config, print, false, [
1191
- ` Downloaded ${version} into ${dir}`,
1192
- ` This payload was built wrong: its entry must be a command, not one of its own files.`,
1193
- ` Nothing on this machine can finish it \u2014 report it to the ${config.product} maintainers.`
1238
+ `Downloaded ${version} into ${dir}`,
1239
+ `This payload was built wrong: its entry must be a command, not one of its own files.`,
1240
+ `Nothing on this machine can finish it \u2014 report it to the ${config.product} maintainers.`
1194
1241
  ]);
1195
1242
  return 2;
1196
1243
  }
1197
1244
  const started = Date.now();
1198
1245
  const result = (options.runEntry ?? defaultRunEntry)(command, payload, payloadEnv(dir));
1246
+ printProgress(face, print, result.progress);
1199
1247
  if (result.ok) {
1200
1248
  printStep(face, print, "Armed this machine", since(started));
1201
1249
  printReceipt(face, config, print, true, [
1202
- ` Installed ${version} into ${dir}`,
1203
- ` Check health any time: ${config.binName} doctor`
1250
+ `Installed ${version} into ${dir}`,
1251
+ `Check health any time: ${config.binName} doctor`
1204
1252
  ]);
1205
1253
  return 0;
1206
1254
  }
@@ -1213,8 +1261,8 @@ function finishLastMile(config, dir, options, print, face, version) {
1213
1261
  "fail"
1214
1262
  );
1215
1263
  printReceipt(face, config, print, false, [
1216
- ` Downloaded ${version} into ${dir}`,
1217
- ` Finish it with: (cd ${payload} && ${command.join(" ")})`
1264
+ `Downloaded ${version} into ${dir}`,
1265
+ `Finish it with: (cd ${payload} && ${command.join(" ")})`
1218
1266
  ]);
1219
1267
  return code;
1220
1268
  }
@@ -894,7 +894,7 @@ function wipeProductDir(dir) {
894
894
  }
895
895
 
896
896
  // src/index.ts
897
- var LAUNCHER_VERSION = true ? "0.1.4" : readVersionFromPackage();
897
+ var LAUNCHER_VERSION = true ? "0.1.7" : readVersionFromPackage();
898
898
  function defaultPrint(message) {
899
899
  process.stdout.write(`${message}
900
900
  `);
@@ -1106,20 +1106,58 @@ function needsShell(command) {
1106
1106
  function quoteForShell(arg) {
1107
1107
  return /[\s"&|<>^%]/.test(arg) ? `"${arg.replace(/"/g, '\\"')}"` : arg;
1108
1108
  }
1109
+ var SUPPORTED_PROGRESS_PROTOCOLS = /* @__PURE__ */ new Set([1]);
1110
+ function parseProgress(raw) {
1111
+ if (raw === null || raw === void 0) return [];
1112
+ const progress = [];
1113
+ for (const line of raw.toString().split(/\r?\n/)) {
1114
+ if (!line) continue;
1115
+ try {
1116
+ const message = JSON.parse(line);
1117
+ if (!SUPPORTED_PROGRESS_PROTOCOLS.has(message.v) || typeof message.step !== "string") continue;
1118
+ const state = message.state ?? "ok";
1119
+ if (state !== "ok" && state !== "fail" && state !== "note") continue;
1120
+ if (message.ms !== void 0 && typeof message.ms !== "number") continue;
1121
+ progress.push({
1122
+ step: message.step,
1123
+ state,
1124
+ ...typeof message.ms === "number" ? { ms: message.ms } : {}
1125
+ });
1126
+ } catch {
1127
+ }
1128
+ }
1129
+ return progress;
1130
+ }
1109
1131
  function defaultRunEntry(entry, cwd, env) {
1110
1132
  const [command, ...args] = entry;
1111
1133
  const shell = needsShell(command);
1112
1134
  const commandLine = shell ? [command, ...args].map(quoteForShell).join(" ") : command;
1113
- const result = (0, import_node_child_process3.spawnSync)(commandLine, shell ? [] : args, {
1135
+ const spawn2 = (progress2) => (0, import_node_child_process3.spawnSync)(commandLine, shell ? [] : args, {
1114
1136
  cwd,
1115
- stdio: "inherit",
1137
+ stdio: progress2 ? ["inherit", "inherit", "inherit", "pipe"] : "inherit",
1116
1138
  shell,
1117
- env: env ?? process.env,
1139
+ env: progress2 ? { ...env ?? process.env, MM_PROGRESS_FD: "3", MM_PROGRESS_PROTOCOL: "1" } : env ?? process.env,
1118
1140
  windowsHide: true
1119
1141
  });
1142
+ let result;
1143
+ if (process.platform === "win32" && shell) {
1144
+ result = spawn2(false);
1145
+ } else {
1146
+ try {
1147
+ result = spawn2(true);
1148
+ } catch {
1149
+ result = spawn2(false);
1150
+ }
1151
+ }
1120
1152
  if (result.error) return { ok: false, error: result.error.message };
1121
1153
  const code = typeof result.status === "number" ? result.status : void 0;
1122
- return { ok: result.status === 0, error: result.status === 0 ? void 0 : `exit code ${result.status}`, code };
1154
+ const progress = parseProgress(result.output?.[3]);
1155
+ return {
1156
+ ok: result.status === 0,
1157
+ error: result.status === 0 ? void 0 : `exit code ${result.status}`,
1158
+ code,
1159
+ ...progress.length > 0 ? { progress } : {}
1160
+ };
1123
1161
  }
1124
1162
  function faceProduct(config) {
1125
1163
  const known = { mmi: "mmi-hub", jerv: "jerv-hub" };
@@ -1141,9 +1179,13 @@ function faceFor(config, options) {
1141
1179
  function since(start) {
1142
1180
  return (Date.now() - start) / 1e3;
1143
1181
  }
1182
+ function outerConsoleOwnsOutcome() {
1183
+ return process.env.MM_OUTER_CONSOLE === "1";
1184
+ }
1144
1185
  function printReceipt(face, config, print, ready, lines) {
1145
1186
  const name = face ? face.identity.name : config.product;
1146
1187
  const headline = ready ? `${name} is ready.` : `${name} is installed, but not ready yet.`;
1188
+ if (ready && outerConsoleOwnsOutcome()) return;
1147
1189
  if (!face) {
1148
1190
  print(headline);
1149
1191
  for (const line of lines) print(line.trim());
@@ -1156,6 +1198,11 @@ function printReceipt(face, config, print, ready, lines) {
1156
1198
  function printStep(face, print, title, seconds, kind = "ok") {
1157
1199
  print(face ? face.step(title, seconds, kind) : title);
1158
1200
  }
1201
+ function printProgress(face, print, progress) {
1202
+ for (const message of progress ?? []) {
1203
+ printStep(face, print, message.step, message.ms === void 0 ? null : message.ms / 1e3, message.state);
1204
+ }
1205
+ }
1159
1206
  async function doInstall(config, dir, options, print) {
1160
1207
  const fetchImpl = options.fetchImpl ?? fetch;
1161
1208
  const face = faceFor(config, options);
@@ -1170,7 +1217,7 @@ async function doInstall(config, dir, options, print) {
1170
1217
  async function doUpdate(config, dir, options, print) {
1171
1218
  const fetchImpl = options.fetchImpl ?? fetch;
1172
1219
  const face = faceFor(config, options);
1173
- if (face) for (const line of face.welcome()) print(line);
1220
+ if (face && !outerConsoleOwnsOutcome()) for (const line of face.welcome()) print(line);
1174
1221
  const accessToken = await fetchAccessTokenOrLogin(config, dir, options, print);
1175
1222
  const started = Date.now();
1176
1223
  const manifest = await fetchVerifiedManifest(config, accessToken, fetchImpl);
@@ -1209,8 +1256,8 @@ function finishLastMile(config, dir, options, print, face, version) {
1209
1256
  const payload = payloadDir(dir);
1210
1257
  if (!entry) {
1211
1258
  printReceipt(face, config, print, true, [
1212
- ` Installed ${version} into ${dir}`,
1213
- ` next step: run ${(0, import_node_path4.join)(payload, config.binName)} to start ${config.product}.`
1259
+ `Installed ${version} into ${dir}`,
1260
+ `next step: run ${(0, import_node_path4.join)(payload, config.binName)} to start ${config.product}.`
1214
1261
  ]);
1215
1262
  return 0;
1216
1263
  }
@@ -1219,19 +1266,20 @@ function finishLastMile(config, dir, options, print, face, version) {
1219
1266
  if (dataFile) {
1220
1267
  printStep(face, print, `The payload names ${dataFile} as its command, but that is a file, not a program`, null, "fail");
1221
1268
  printReceipt(face, config, print, false, [
1222
- ` Downloaded ${version} into ${dir}`,
1223
- ` This payload was built wrong: its entry must be a command, not one of its own files.`,
1224
- ` Nothing on this machine can finish it \u2014 report it to the ${config.product} maintainers.`
1269
+ `Downloaded ${version} into ${dir}`,
1270
+ `This payload was built wrong: its entry must be a command, not one of its own files.`,
1271
+ `Nothing on this machine can finish it \u2014 report it to the ${config.product} maintainers.`
1225
1272
  ]);
1226
1273
  return 2;
1227
1274
  }
1228
1275
  const started = Date.now();
1229
1276
  const result = (options.runEntry ?? defaultRunEntry)(command, payload, payloadEnv(dir));
1277
+ printProgress(face, print, result.progress);
1230
1278
  if (result.ok) {
1231
1279
  printStep(face, print, "Armed this machine", since(started));
1232
1280
  printReceipt(face, config, print, true, [
1233
- ` Installed ${version} into ${dir}`,
1234
- ` Check health any time: ${config.binName} doctor`
1281
+ `Installed ${version} into ${dir}`,
1282
+ `Check health any time: ${config.binName} doctor`
1235
1283
  ]);
1236
1284
  return 0;
1237
1285
  }
@@ -1244,8 +1292,8 @@ function finishLastMile(config, dir, options, print, face, version) {
1244
1292
  "fail"
1245
1293
  );
1246
1294
  printReceipt(face, config, print, false, [
1247
- ` Downloaded ${version} into ${dir}`,
1248
- ` Finish it with: (cd ${payload} && ${command.join(" ")})`
1295
+ `Downloaded ${version} into ${dir}`,
1296
+ `Finish it with: (cd ${payload} && ${command.join(" ")})`
1249
1297
  ]);
1250
1298
  return code;
1251
1299
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/installer-launcher",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
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",