@loontail/minecraft-kit 0.2.0 → 0.4.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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A stateless TypeScript Minecraft launcher library and interactive CLI for vanilla, Fabric, and modern Forge.
4
4
 
5
+ **Documentation:** https://loontail.github.io/minecraft-kit/
6
+
5
7
  ## Features
6
8
 
7
9
  - Resolve and install vanilla Minecraft, Fabric, and modern Forge.
@@ -14,7 +16,7 @@ A stateless TypeScript Minecraft launcher library and interactive CLI for vanill
14
16
  ## Install
15
17
 
16
18
  ```bash
17
- pnpm add @loontail/minecraft-kit
19
+ npm install @loontail/minecraft-kit
18
20
  ```
19
21
 
20
22
  ## Usage
package/dist/cli/index.js CHANGED
@@ -515,14 +515,16 @@ function planLibraryDownloads(input) {
515
515
  );
516
516
  if (!seenPaths.has(targetPath)) {
517
517
  seenPaths.add(targetPath);
518
- downloads.push({
519
- kind: InstallActionKinds.DOWNLOAD_FILE,
520
- url: artifact.url,
521
- target: targetPath,
522
- ...artifact.sha1 !== void 0 ? { expectedSha1: artifact.sha1 } : {},
523
- ...artifact.size !== void 0 ? { expectedSize: artifact.size } : {},
524
- category: input.category
525
- });
518
+ if (artifact.url) {
519
+ downloads.push({
520
+ kind: InstallActionKinds.DOWNLOAD_FILE,
521
+ url: artifact.url,
522
+ target: targetPath,
523
+ ...artifact.sha1 !== void 0 ? { expectedSha1: artifact.sha1 } : {},
524
+ ...artifact.size !== void 0 ? { expectedSize: artifact.size } : {},
525
+ category: input.category
526
+ });
527
+ }
526
528
  classpathFiles.push(targetPath);
527
529
  }
528
530
  }
@@ -531,14 +533,16 @@ function planLibraryDownloads(input) {
531
533
  const targetPath = path.join(targetPaths.librariesDir(input.directory), native.relativePath);
532
534
  if (!seenPaths.has(targetPath)) {
533
535
  seenPaths.add(targetPath);
534
- downloads.push({
535
- kind: InstallActionKinds.DOWNLOAD_FILE,
536
- url: native.url,
537
- target: targetPath,
538
- ...native.sha1 !== void 0 ? { expectedSha1: native.sha1 } : {},
539
- ...native.size !== void 0 ? { expectedSize: native.size } : {},
540
- category: input.category
541
- });
536
+ if (native.url) {
537
+ downloads.push({
538
+ kind: InstallActionKinds.DOWNLOAD_FILE,
539
+ url: native.url,
540
+ target: targetPath,
541
+ ...native.sha1 !== void 0 ? { expectedSha1: native.sha1 } : {},
542
+ ...native.size !== void 0 ? { expectedSize: native.size } : {},
543
+ category: input.category
544
+ });
545
+ }
542
546
  }
543
547
  nativeExtractions.push({
544
548
  kind: InstallActionKinds.EXTRACT_NATIVE,
@@ -1342,7 +1346,7 @@ async function buildProcessorActions(input) {
1342
1346
  continue;
1343
1347
  }
1344
1348
  if (!evaluateRules([], { system: input.system })) ;
1345
- const action = await buildProcessorAction({
1349
+ const action = buildProcessorAction({
1346
1350
  processor,
1347
1351
  directory: input.directory,
1348
1352
  tokens,
@@ -1357,19 +1361,11 @@ function processorAppliesToClient(processor) {
1357
1361
  if (!processor.sides || processor.sides.length === 0) return true;
1358
1362
  return processor.sides.includes("client");
1359
1363
  }
1360
- async function buildProcessorAction(input) {
1364
+ function buildProcessorAction(input) {
1361
1365
  const jarPath = path.join(
1362
1366
  targetPaths.librariesDir(input.directory),
1363
1367
  mavenRelativePathFor(input.processor.jar)
1364
1368
  );
1365
- const mainClass = await readJarMainClass(jarPath);
1366
- if (!mainClass) {
1367
- throw new MinecraftKitError(
1368
- "FORGE_INSTALLER_INVALID",
1369
- `Processor jar has no Main-Class: ${input.processor.jar}`,
1370
- { context: { filePath: jarPath } }
1371
- );
1372
- }
1373
1369
  const classpath = [
1374
1370
  jarPath,
1375
1371
  ...input.processor.classpath.map(
@@ -1388,7 +1384,6 @@ async function buildProcessorAction(input) {
1388
1384
  return {
1389
1385
  kind: InstallActionKinds.RUN_FORGE_PROCESSOR,
1390
1386
  index: input.index,
1391
- mainClass,
1392
1387
  classpath,
1393
1388
  args,
1394
1389
  outputs
@@ -1730,16 +1725,32 @@ function isWrite(action) {
1730
1725
  }
1731
1726
  async function runProcessor(input) {
1732
1727
  const startedAt = Date.now();
1728
+ const processorJar = input.action.classpath[0];
1729
+ if (processorJar === void 0) {
1730
+ throw new MinecraftKitError(
1731
+ "FORGE_INSTALLER_INVALID",
1732
+ "Forge processor has an empty classpath",
1733
+ { context: { processorIndex: input.action.index } }
1734
+ );
1735
+ }
1736
+ const mainClass = await readJarMainClass(processorJar);
1737
+ if (!mainClass) {
1738
+ throw new MinecraftKitError(
1739
+ "FORGE_INSTALLER_INVALID",
1740
+ `Forge processor jar has no Main-Class: ${processorJar}`,
1741
+ { context: { filePath: processorJar } }
1742
+ );
1743
+ }
1733
1744
  const classpathSeparator = process.platform === "win32" ? ";" : ":";
1734
1745
  const args = [
1735
1746
  "-cp",
1736
1747
  input.action.classpath.join(classpathSeparator),
1737
- input.action.mainClass,
1748
+ mainClass,
1738
1749
  ...input.action.args
1739
1750
  ];
1740
1751
  input.onEvent?.({
1741
1752
  type: "forge:processor-started",
1742
- processor: { index: input.action.index, mainClass: input.action.mainClass },
1753
+ processor: { index: input.action.index, mainClass },
1743
1754
  total: input.total
1744
1755
  });
1745
1756
  const stderrTail = [];
@@ -1754,11 +1765,11 @@ async function runProcessor(input) {
1754
1765
  if (exit.code !== 0) {
1755
1766
  throw new MinecraftKitError(
1756
1767
  "FORGE_PROCESSOR_FAILED",
1757
- `Forge processor exited with code ${exit.code ?? "(signal)"}: ${input.action.mainClass}`,
1768
+ `Forge processor exited with code ${exit.code ?? "(signal)"}: ${mainClass}`,
1758
1769
  {
1759
1770
  context: {
1760
1771
  exitCode: exit.code ?? void 0,
1761
- mainClass: input.action.mainClass,
1772
+ mainClass,
1762
1773
  stderr: stderrTail.join("\n")
1763
1774
  }
1764
1775
  }
@@ -1766,7 +1777,7 @@ async function runProcessor(input) {
1766
1777
  }
1767
1778
  input.onEvent?.({
1768
1779
  type: "forge:processor-completed",
1769
- processor: { index: input.action.index, mainClass: input.action.mainClass },
1780
+ processor: { index: input.action.index, mainClass },
1770
1781
  exitCode: exit.code ?? 0,
1771
1782
  durationMs: Date.now() - startedAt
1772
1783
  });
@@ -1781,7 +1792,7 @@ async function runProcessor(input) {
1781
1792
  }
1782
1793
  input.onEvent?.({
1783
1794
  type: "forge:processor-output-verified",
1784
- processor: { index: input.action.index, mainClass: input.action.mainClass },
1795
+ processor: { index: input.action.index, mainClass },
1785
1796
  path: outputPath
1786
1797
  });
1787
1798
  }
@@ -3861,6 +3872,7 @@ async function runInstallWithProgress(ctx, target, label) {
3861
3872
  planSpinner.stop(`Plan ready: ${plan.totalActions} actions, ${formatBytes(plan.totalBytes)}.`);
3862
3873
  } catch (error) {
3863
3874
  planSpinner.stop("Planning failed.");
3875
+ ctx.ui.log("error", formatUserError(error));
3864
3876
  throw error;
3865
3877
  }
3866
3878
  const renderer = new ProgressRenderer({
@@ -3901,7 +3913,7 @@ async function runInstallFromSelection(ctx, sel) {
3901
3913
  await runInstallWithProgress(ctx, target, describeLoader(sel));
3902
3914
  return "ok";
3903
3915
  } catch {
3904
- return "directory";
3916
+ return "cancelled";
3905
3917
  }
3906
3918
  }
3907
3919
  async function runStandaloneRuntimeInstallWithProgress(ctx, input) {
@@ -3918,6 +3930,7 @@ async function runStandaloneRuntimeInstallWithProgress(ctx, input) {
3918
3930
  planSpinner.stop(`Plan ready: ${plan.totalActions} files, ${formatBytes(plan.totalBytes)}.`);
3919
3931
  } catch (error) {
3920
3932
  planSpinner.stop("Planning failed.");
3933
+ ctx.ui.log("error", formatUserError(error));
3921
3934
  throw error;
3922
3935
  }
3923
3936
  const renderer = new ProgressRenderer({
@@ -4530,6 +4543,7 @@ async function scenarioInstallMinecraft(ctx) {
4530
4543
  if (!ok.value) return "cancelled";
4531
4544
  const result = await runInstallFromSelection(ctx, sel);
4532
4545
  if (result === "ok") return "completed";
4546
+ if (result === "cancelled") return "cancelled";
4533
4547
  step = result;
4534
4548
  }
4535
4549
  }