@gamecrate/cli 2.2.1 → 2.3.1

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/gamecrate.js CHANGED
@@ -2449,7 +2449,10 @@ function repeats(entries, key) {
2449
2449
  });
2450
2450
  return found;
2451
2451
  }
2452
- var TAG_COMPONENT = /^[A-Za-z0-9_][A-Za-z0-9._-]*$/;
2452
+ function describe(value) {
2453
+ return typeof value === "string" ? value : JSON.stringify(value);
2454
+ }
2455
+ var TAG_COMPONENT = /^\w[\w.-]*$/;
2453
2456
  function steamBuildRules(ctx) {
2454
2457
  const push = (message, path, suggestion) => {
2455
2458
  ctx.issues.push({
@@ -2504,7 +2507,7 @@ function steamBuildRules(ctx) {
2504
2507
  const wants = depot === "windows" ? "proton" : "xvfb";
2505
2508
  if (base === wants)
2506
2509
  return;
2507
- push(`a ${String(depot)} depot cannot run on the "${base}" base`, ["variants", index, "base"], depot === "windows" ? 'set base to "proton"; it is the only base with wine' : 'set base to "xvfb", or set depot to "windows" if the image should run under wine');
2510
+ push(`a ${describe(depot)} depot cannot run on the "${base}" base`, ["variants", index, "base"], depot === "windows" ? 'set base to "proton"; it is the only base with wine' : 'set base to "xvfb", or set depot to "windows" if the image should run under wine');
2508
2511
  });
2509
2512
  }
2510
2513
  var steamBuildSchema = obj({
@@ -4523,7 +4526,10 @@ function refsLink(game) {
4523
4526
  }
4524
4527
  var MARK2 = "@@gamecrate@@ ";
4525
4528
  function extractScript(candidates, container) {
4526
- const quoted = candidates.map((c) => `'${join11(container, c).replaceAll("'", String.raw`'\''`)}'`);
4529
+ const quoted = candidates.map((c) => {
4530
+ const escaped = join11(container, c).replaceAll("'", String.raw`'\''`);
4531
+ return `'${escaped}'`;
4532
+ });
4527
4533
  return [
4528
4534
  `for d in ${quoted.join(" ")}; do`,
4529
4535
  ' set -- "$d"/*.dll',
@@ -4875,7 +4881,7 @@ async function modsAdd(args, ctx) {
4875
4881
  const target = await resolveTarget(args, ctx, game);
4876
4882
  const pins = await discover(source, gameConfig, requirePlugin(ctx.plugins, game), ctx);
4877
4883
  if (pins.length === 0) {
4878
- throw new GamecrateError(`no mod manifest at ${describe(source)}`, Exit.Resolution, `looked for ${gameConfig.manifest.file}`);
4884
+ throw new GamecrateError(`no mod manifest at ${describe2(source)}`, Exit.Resolution, `looked for ${gameConfig.manifest.file}`);
4879
4885
  }
4880
4886
  const where = new Map;
4881
4887
  for (const pin of pins) {
@@ -4888,7 +4894,7 @@ async function modsAdd(args, ctx) {
4888
4894
  const lines = [...where.entries()].filter(([, at]) => at.length > 1);
4889
4895
  const rows = lines.map(([id, at]) => ` ${id}: ${at.join(", ")}`).join(`
4890
4896
  `);
4891
- throw new GamecrateError(`${twice.length} mod id(s) are declared by more than one directory in ${describe(source)}`, Exit.Config, `${rows}
4897
+ throw new GamecrateError(`${twice.length} mod id(s) are declared by more than one directory in ${describe2(source)}`, Exit.Config, `${rows}
4892
4898
  pin one of them with --subdir`);
4893
4899
  }
4894
4900
  const clashes = pins.filter((pin) => existingKey(target.existing, pin.id) !== undefined);
@@ -5018,7 +5024,7 @@ async function syncWorkshop(ctx, name, pins) {
5018
5024
  function gitPin(url, entry) {
5019
5025
  return { url, ...entry.subdir === undefined ? {} : { subdir: entry.subdir } };
5020
5026
  }
5021
- function describe(source) {
5027
+ function describe2(source) {
5022
5028
  if (source.kind === "path")
5023
5029
  return source.value;
5024
5030
  if (source.kind === "workshop")
@@ -5297,7 +5303,8 @@ function dockerRun(mounts, script) {
5297
5303
  ];
5298
5304
  }
5299
5305
  function shq(value) {
5300
- return `'${value.replaceAll("'", `'\\''`)}'`;
5306
+ const escaped = value.replaceAll("'", String.raw`'\''`);
5307
+ return `'${escaped}'`;
5301
5308
  }
5302
5309
  function craneArgv(mounts, ref, lines) {
5303
5310
  const creds = ref === null ? null : registryCreds();
@@ -5348,7 +5355,7 @@ async function runLive(argv, what) {
5348
5355
  }
5349
5356
  function lastLine(text) {
5350
5357
  return text.split(`
5351
- `).map((l) => l.trim()).filter((l) => l !== "").at(-1) ?? "no output";
5358
+ `).map((l) => l.trim()).findLast((l) => l !== "") ?? "no output";
5352
5359
  }
5353
5360
  async function craneAppend(opts) {
5354
5361
  for (const p of opts.include) {
@@ -5532,7 +5539,7 @@ function sanitizeVersion(raw, fallback) {
5532
5539
  }
5533
5540
  function versionPrefixes(version) {
5534
5541
  const parts = version.split(".");
5535
- if (parts.length < 2 || parts.some((p) => p === ""))
5542
+ if (parts.length < 2 || parts.includes(""))
5536
5543
  return [];
5537
5544
  return parts.slice(0, -1).map((_, i) => parts.slice(0, i + 1).join("."));
5538
5545
  }
@@ -5678,6 +5685,10 @@ async function download(input, opts, ctx, say) {
5678
5685
  }
5679
5686
  return (await pending).dir;
5680
5687
  }
5688
+ function loadOutput(stdout, stderr) {
5689
+ return `${stdout}
5690
+ ${stderr}`.trim() || "(no output)";
5691
+ }
5681
5692
  async function resolvedBase(base, platform) {
5682
5693
  if (base.includes("@sha256:"))
5683
5694
  return base;
@@ -5703,7 +5714,7 @@ async function readGate(ref, opts) {
5703
5714
  reads.push(await craneLabels(ref));
5704
5715
  if (opts.load)
5705
5716
  reads.push(await inspectLabels(ref));
5706
- if (reads.some((labels) => labels === null))
5717
+ if (reads.includes(null))
5707
5718
  return { present: false, buildid: null };
5708
5719
  const ids = reads.map((labels) => labels?.["steam.buildid"] ?? null);
5709
5720
  return { present: reads.length > 0, buildid: ids.every((id) => id === ids[0]) ? ids[0] ?? null : null };
@@ -5721,8 +5732,7 @@ async function inspectLabels(ref) {
5721
5732
  async function dockerLoad(tar, ref) {
5722
5733
  const { code, stdout, stderr } = await capture(["docker", "load", "-i", tar]);
5723
5734
  if (code !== 0 || !stdout.includes(`Loaded image: ${ref}`)) {
5724
- throw new GamecrateError(`docker load failed for ${tar}`, Exit.Environment, `expected "Loaded image: ${ref}", got: ${`${stdout}
5725
- ${stderr}`.trim() || "(no output)"}`);
5735
+ throw new GamecrateError(`docker load failed for ${tar}`, Exit.Environment, `expected "Loaded image: ${ref}", got: ${loadOutput(stdout, stderr)}`);
5726
5736
  }
5727
5737
  }
5728
5738
  async function dockerLabel(ref, labels) {
@@ -5997,7 +6007,10 @@ ${cases}
5997
6007
  complete -F ${fn} ${NAME}
5998
6008
  `;
5999
6009
  }
6000
- const zshVerbs = SUBCOMMANDS.map((s) => ` '${s.name}:${s.summary.replaceAll("'", String.raw`'\''`)}'`).join(`
6010
+ const zshVerbs = SUBCOMMANDS.map((s) => {
6011
+ const summary = s.summary.replaceAll("'", String.raw`'\''`);
6012
+ return ` '${s.name}:${summary}'`;
6013
+ }).join(`
6001
6014
  `);
6002
6015
  const zshFlags = options.map((f) => {
6003
6016
  const desc = f.description.replaceAll("'", String.raw`'\''`).replaceAll(/[[\]:]/g, "");
@@ -7585,7 +7598,7 @@ function published2(value) {
7585
7598
  }
7586
7599
 
7587
7600
  // src/index.ts
7588
- var VERSION = "2.2.1";
7601
+ var VERSION = "2.3.1";
7589
7602
  async function main(argv) {
7590
7603
  const supervised = supervisedDir(argv);
7591
7604
  try {
@@ -7866,8 +7879,10 @@ async function rebuiltForUpdate(plan, config, args) {
7866
7879
  cwd: process.cwd(),
7867
7880
  configFile: await globalConfigPath(),
7868
7881
  ask: async (question) => {
7869
- if (args.yes)
7870
- return rebuilt = true;
7882
+ if (args.yes) {
7883
+ rebuilt = true;
7884
+ return true;
7885
+ }
7871
7886
  if (process.stdin.isTTY !== true || args.json) {
7872
7887
  warn("no terminal to ask, so the launch keeps the current image");
7873
7888
  return false;
@@ -8011,7 +8026,7 @@ async function copyOutLogs(plan) {
8011
8026
  try {
8012
8027
  await cp(source, target, { recursive: true, force: true });
8013
8028
  } catch (error) {
8014
- warn(`could not copy ${source}: ${describe2(error)}`);
8029
+ warn(`could not copy ${source}: ${describe3(error)}`);
8015
8030
  }
8016
8031
  }
8017
8032
  async function mods(args, config, plugins, defaults) {
@@ -8486,7 +8501,7 @@ async function spawnStatus(argv, interactive = false) {
8486
8501
  const proc = spawnArgv(argv, [interactive ? "inherit" : "ignore", "inherit", "inherit"]);
8487
8502
  return exited(proc);
8488
8503
  }
8489
- function describe2(error) {
8504
+ function describe3(error) {
8490
8505
  return error instanceof Error ? error.message : String(error);
8491
8506
  }
8492
8507
  function reportFatal(error) {
@@ -8498,7 +8513,7 @@ function reportFatal(error) {
8498
8513
  `);
8499
8514
  return error.code;
8500
8515
  }
8501
- process.stderr.write(`gamecrate: ${describe2(error)}
8516
+ process.stderr.write(`gamecrate: ${describe3(error)}
8502
8517
  `);
8503
8518
  return Exit.GameFailed;
8504
8519
  }
package/dist/lib.js CHANGED
@@ -242,7 +242,10 @@ function repeats(entries, key) {
242
242
  });
243
243
  return found;
244
244
  }
245
- var TAG_COMPONENT = /^[A-Za-z0-9_][A-Za-z0-9._-]*$/;
245
+ function describe(value) {
246
+ return typeof value === "string" ? value : JSON.stringify(value);
247
+ }
248
+ var TAG_COMPONENT = /^\w[\w.-]*$/;
246
249
  function steamBuildRules(ctx) {
247
250
  const push = (message, path, suggestion) => {
248
251
  ctx.issues.push({
@@ -297,7 +300,7 @@ function steamBuildRules(ctx) {
297
300
  const wants = depot === "windows" ? "proton" : "xvfb";
298
301
  if (base === wants)
299
302
  return;
300
- push(`a ${String(depot)} depot cannot run on the "${base}" base`, ["variants", index, "base"], depot === "windows" ? 'set base to "proton"; it is the only base with wine' : 'set base to "xvfb", or set depot to "windows" if the image should run under wine');
303
+ push(`a ${describe(depot)} depot cannot run on the "${base}" base`, ["variants", index, "base"], depot === "windows" ? 'set base to "proton"; it is the only base with wine' : 'set base to "xvfb", or set depot to "windows" if the image should run under wine');
301
304
  });
302
305
  }
303
306
  var steamBuildSchema = obj({
@@ -1,6 +1,5 @@
1
1
  import type { ImageLaunch } from '../docker/spec';
2
- import type { ModeName, Problem } from '../types';
3
- import type { GameConfig } from '../types';
2
+ import type { GameConfig, ModeName, Problem } from '../types';
4
3
  /** What an image says about itself. Every field is null for an image gamecrate did not build. */
5
4
  export interface ImageFacts {
6
5
  present: boolean;
@@ -1,6 +1,5 @@
1
1
  import type { ImageFacts } from './image';
2
- import type { ParsedArgs, RootConfig } from '../types';
3
- import type { UpdateCheckSpec } from '../types';
2
+ import type { ParsedArgs, RootConfig, UpdateCheckSpec } from '../types';
4
3
  export interface CheckInput {
5
4
  facts: ImageFacts;
6
5
  spec: UpdateCheckSpec | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gamecrate/cli",
3
- "version": "2.2.1",
3
+ "version": "2.3.1",
4
4
  "description": "Run a modded game in a container, with mods resolved from your local checkouts.",
5
5
  "license": "MIT",
6
6
  "type": "module",