windows-development-sandbox 1.27.0 → 1.27.3

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.
Files changed (93) hide show
  1. package/dist/app/context.d.ts +5 -0
  2. package/dist/app/context.js +13 -0
  3. package/dist/app/features/accounts/accounts.def.d.ts +16 -0
  4. package/dist/app/features/accounts/accounts.run.d.ts +4 -0
  5. package/dist/app/features/accounts/services.def.d.ts +15 -1
  6. package/dist/app/features/accounts/services.def.js +67 -31
  7. package/dist/app/features/accounts/services.run.d.ts +7 -2
  8. package/dist/app/features/accounts/services.run.js +25 -6
  9. package/dist/app/features/defs.d.ts +17 -0
  10. package/dist/app/features/unreal/unreal.run.js +13 -3
  11. package/dist/app/registry.d.ts +1 -1
  12. package/dist/app/registry.js +15 -2
  13. package/dist/bin/agent-sandbox.js +2 -2
  14. package/dist/bin/{chunk-JXL6ZOO3.js → chunk-4M5SZZ5P.js} +46 -41
  15. package/dist/bin/{chunk-ZXCAVVS4.js → chunk-FA5VWLP4.js} +1 -1
  16. package/dist/bin/{chunk-6WWMBCT2.js → chunk-RU7XRN62.js} +303 -112
  17. package/dist/bin/claude-host.js +2 -2
  18. package/dist/bin/claude-sbx.js +2 -2
  19. package/dist/bin/codex-sbx.js +2 -2
  20. package/dist/bin/gemini-sbx.js +2 -2
  21. package/dist/bin/sandbox.js +2 -2
  22. package/dist/bin/sbx-hide.js +2 -2
  23. package/dist/bin/sbx-show.js +2 -2
  24. package/dist/cli/commands/launch/launch.js +2 -1
  25. package/dist/cli/menu/menu.js +6 -1
  26. package/dist/cli/menu/pages/accounts-page.js +9 -5
  27. package/dist/guest/apps/app-installer.js +7 -5
  28. package/dist/guest/apps/comet-unpack.js +2 -2
  29. package/dist/guest/runtime/pools.d.ts +4 -4
  30. package/dist/guest/runtime/pools.js +4 -15
  31. package/dist/guest/runtime/process.d.ts +5 -2
  32. package/dist/guest/runtime/process.js +23 -3
  33. package/dist/guest/setup/unity-agent.js +4 -1
  34. package/dist/guest/toolchains/engines/epic-launcher.d.ts +7 -1
  35. package/dist/guest/toolchains/engines/epic-launcher.js +30 -8
  36. package/dist/guest/toolchains/engines/unreal-engines.js +2 -1
  37. package/dist/guest/toolchains/engines/unreal-status.js +1 -1
  38. package/dist/guest/toolchains/installers.d.ts +3 -3
  39. package/dist/guest/toolchains/installers.js +5 -5
  40. package/dist/guest/toolchains/native/mesa.js +35 -11
  41. package/dist/guest/toolchains/native/unreal.js +1 -0
  42. package/dist/guest/toolchains/native/vcruntime.js +2 -2
  43. package/dist/guest/toolchains/native/vs-persist.d.ts +2 -2
  44. package/dist/guest/toolchains/signature.d.ts +2 -0
  45. package/dist/guest/toolchains/signature.js +9 -2
  46. package/dist/guest/toolchains/step-scheduler.js +1 -1
  47. package/dist/host/accounts/deliver.d.ts +3 -0
  48. package/dist/host/accounts/deliver.js +27 -0
  49. package/dist/host/accounts/source.d.ts +2 -0
  50. package/dist/host/accounts/source.js +2 -0
  51. package/dist/host/pc-installs/discover.js +8 -4
  52. package/dist/host/pc-installs/epic.js +3 -0
  53. package/dist/host/pc-installs/unity.d.ts +2 -0
  54. package/dist/host/pc-installs/unity.js +12 -3
  55. package/dist/host/pc-installs/unreal.d.ts +5 -1
  56. package/dist/host/pc-installs/unreal.js +51 -9
  57. package/dist/runtime/agent.js +34 -22
  58. package/dist/runtime/daemon.js +134 -65
  59. package/dist/runtime/db.js +32 -16
  60. package/dist/runtime/main.js +136 -67
  61. package/dist/runtime/netproxy.js +26 -12
  62. package/dist/runtime/tool.js +32 -15
  63. package/dist/runtime/view.js +26 -12
  64. package/dist/selftest/app.test.js +20 -2
  65. package/dist/selftest/boot-runner.test.js +15 -1
  66. package/dist/selftest/engines.test.js +52 -2
  67. package/dist/selftest/menu-screens.js +52 -1
  68. package/dist/selftest/menu.test.js +29 -3
  69. package/dist/selftest/mixamo.test.js +1 -1
  70. package/dist/selftest/service-accounts.test.js +88 -2
  71. package/dist/selftest/ui-text.test.js +4 -0
  72. package/dist/shared/accounts/kinds.js +9 -9
  73. package/dist/shared/apps/catalogue-gamedev.js +1 -0
  74. package/dist/shared/apps/catalogue.d.ts +2 -0
  75. package/dist/shared/concurrency/pools.js +1 -1
  76. package/dist/shared/download/archive.js +4 -2
  77. package/dist/shared/download/index.d.ts +1 -1
  78. package/dist/shared/download/index.js +1 -1
  79. package/dist/shared/download/spawn.d.ts +7 -1
  80. package/dist/shared/download/spawn.js +16 -1
  81. package/dist/shared/paths/pc-installs.d.ts +8 -0
  82. package/dist/shared/unreal/launcher-files.d.ts +7 -0
  83. package/dist/shared/unreal/launcher-files.js +32 -1
  84. package/dist/shared/unreal/status.d.ts +1 -0
  85. package/dist/shared/unreal/status.js +2 -0
  86. package/dist/web/index.html +1 -1
  87. package/dist/web/{main-VPMYTSUL.js → main-NKM7ECSB.js} +59 -59
  88. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  89. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  90. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  91. package/package.json +1 -1
  92. package/schemas/config.schema.json +9 -9
  93. package/schemas/sandbox-config.schema.json +9 -9
@@ -26086,6 +26086,7 @@ var GAMEDEV_APPS = [
26086
26086
  size: "100 MB",
26087
26087
  source: { github: "f3d-app/f3d", asset: "^F3D-[\\d.]+-Windows-x86_64\\.zip$" },
26088
26088
  exe: "f3d.exe",
26089
+ onPath: true,
26089
26090
  needs: ["mesa"]
26090
26091
  },
26091
26092
  {
@@ -27426,7 +27427,7 @@ var SERVICE_SPECS = {
27426
27427
  },
27427
27428
  steam: {
27428
27429
  kind: "steam",
27429
- label: "Steam (SteamCMD)",
27430
+ label: "Steam",
27430
27431
  usedBy: ["steam"],
27431
27432
  sources: ["file", "sandbox"],
27432
27433
  singleHolder: true,
@@ -27462,7 +27463,7 @@ var SERVICE_SPECS = {
27462
27463
  },
27463
27464
  cfx: {
27464
27465
  kind: "cfx",
27465
- label: "Cfx.re (FiveM / RedM server key)",
27466
+ label: "FiveM key",
27466
27467
  usedBy: ["fivem"],
27467
27468
  sources: ["typed", "file"],
27468
27469
  singleHolder: false,
@@ -27491,7 +27492,7 @@ var SERVICE_SPECS = {
27491
27492
  },
27492
27493
  keystore: {
27493
27494
  kind: "keystore",
27494
- label: "Android upload keystore",
27495
+ label: "Android keystore",
27495
27496
  usedBy: ["android"],
27496
27497
  sources: ["file"],
27497
27498
  singleHolder: false,
@@ -27506,7 +27507,7 @@ var SERVICE_SPECS = {
27506
27507
  },
27507
27508
  play: {
27508
27509
  kind: "play",
27509
- label: "Google Play (service account)",
27510
+ label: "Google Play",
27510
27511
  usedBy: ["android"],
27511
27512
  sources: ["file"],
27512
27513
  singleHolder: false,
@@ -27517,7 +27518,7 @@ var SERVICE_SPECS = {
27517
27518
  },
27518
27519
  expo: {
27519
27520
  kind: "expo",
27520
- label: "Expo (EAS)",
27521
+ label: "Expo",
27521
27522
  usedBy: ["reactNative"],
27522
27523
  sources: ["typed"],
27523
27524
  singleHolder: false,
@@ -27528,7 +27529,7 @@ var SERVICE_SPECS = {
27528
27529
  },
27529
27530
  appstore: {
27530
27531
  kind: "appstore",
27531
- label: "App Store Connect API key",
27532
+ label: "App Store Connect",
27532
27533
  usedBy: ["reactNative", "flutter"],
27533
27534
  sources: ["file", "typed"],
27534
27535
  singleHolder: false,
@@ -27542,7 +27543,7 @@ var SERVICE_SPECS = {
27542
27543
  },
27543
27544
  perplexity: {
27544
27545
  kind: "perplexity",
27545
- label: "Perplexity API key",
27546
+ label: "Perplexity API",
27546
27547
  usedBy: ["perplexity"],
27547
27548
  sources: ["pc", "file", "typed"],
27548
27549
  singleHolder: false,
@@ -27566,7 +27567,7 @@ var SERVICE_SPECS = {
27566
27567
  },
27567
27568
  comet: {
27568
27569
  kind: "comet",
27569
- label: "Comet (Perplexity browser)",
27570
+ label: "Comet",
27570
27571
  usedBy: ["comet"],
27571
27572
  sources: ["sandbox"],
27572
27573
  singleHolder: false,
@@ -27582,7 +27583,7 @@ var SERVICE_SPECS = {
27582
27583
  },
27583
27584
  perplexityapp: {
27584
27585
  kind: "perplexityapp",
27585
- label: "Perplexity desktop app",
27586
+ label: "Perplexity app",
27586
27587
  usedBy: ["perplexityapp"],
27587
27588
  sources: ["sandbox"],
27588
27589
  singleHolder: false,
@@ -28363,7 +28364,7 @@ var logsDir = path9.join(dataDir, "logs");
28363
28364
  var run = new RunDir(dataDir);
28364
28365
 
28365
28366
  // src/guest/runtime/status.ts
28366
- import os3 from "node:os";
28367
+ import os4 from "node:os";
28367
28368
 
28368
28369
  // src/core/util/errors.ts
28369
28370
  function errMsg(e) {
@@ -28548,10 +28549,20 @@ function scriptArgs(name, args = []) {
28548
28549
  }
28549
28550
 
28550
28551
  // src/shared/download/spawn.ts
28552
+ import os3 from "node:os";
28551
28553
  import { spawn } from "node:child_process";
28554
+ function lowerPriority(pid) {
28555
+ if (pid === void 0) return;
28556
+ try {
28557
+ os3.setPriority(pid, os3.constants.priority.PRIORITY_BELOW_NORMAL);
28558
+ } catch {
28559
+ }
28560
+ }
28552
28561
  function spawnAsync(file3, args, options = {}) {
28562
+ const { lowPriority, ...spawnOptions } = options;
28553
28563
  return new Promise((resolve2, reject) => {
28554
- const child = spawn(file3, args, { stdio: "ignore", windowsHide: true, ...options });
28564
+ const child = spawn(file3, args, { stdio: "ignore", windowsHide: true, ...spawnOptions });
28565
+ if (lowPriority) lowerPriority(child.pid);
28555
28566
  child.once("error", reject);
28556
28567
  child.once("close", (code) => resolve2(code ?? -1));
28557
28568
  });
@@ -28575,13 +28586,16 @@ function extractArchive(archive, destination, members2 = []) {
28575
28586
  }
28576
28587
  async function extract(archive, destination, members2) {
28577
28588
  fs10.mkdirSync(destination, { recursive: true });
28578
- let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2]);
28589
+ let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2], {
28590
+ lowPriority: true
28591
+ });
28579
28592
  if (status !== 0 && /\.(zip|nupkg)$/i.test(archive)) {
28580
28593
  const zip = archive.endsWith(".zip") ? archive : archive + ".zip";
28581
28594
  if (zip !== archive) fs10.copyFileSync(archive, zip);
28582
28595
  status = await spawnAsync(
28583
28596
  SYSTEM.powershell(),
28584
- scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination])
28597
+ scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination]),
28598
+ { lowPriority: true }
28585
28599
  );
28586
28600
  }
28587
28601
  if (status !== 0) throw new Error("Could not extract " + archive);
@@ -28825,7 +28839,7 @@ function setBackgroundWork(work) {
28825
28839
  }
28826
28840
  }
28827
28841
  function ownAddresses() {
28828
- return Object.values(os3.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address).slice(0, 8);
28842
+ return Object.values(os4.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address).slice(0, 8);
28829
28843
  }
28830
28844
  function writeStatus(phase, message) {
28831
28845
  writeJsonAtomic(run.sandboxFile, {
@@ -28893,7 +28907,7 @@ import path18 from "node:path";
28893
28907
 
28894
28908
  // src/guest/runtime/process.ts
28895
28909
  import fs14 from "node:fs";
28896
- import os4 from "node:os";
28910
+ import os5 from "node:os";
28897
28911
  import path17 from "node:path";
28898
28912
  import { spawn as spawn2, spawnSync } from "node:child_process";
28899
28913
  var outputSink = null;
@@ -28931,13 +28945,15 @@ function exec(file3, args, options = {}) {
28931
28945
  throw new Error(path17.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + result.status);
28932
28946
  }
28933
28947
  async function execAsync(file3, args, options = {}) {
28948
+ const { lowPriority, ...spawnOptions } = options;
28934
28949
  const code = captureOutput() ? await new Promise((resolve2, reject) => {
28935
- const child = spawn2(file3, args, { stdio: ["inherit", "pipe", "pipe"], windowsHide: true, ...options });
28950
+ const child = spawn2(file3, args, { stdio: ["inherit", "pipe", "pipe"], windowsHide: true, ...spawnOptions });
28951
+ if (lowPriority) lowerPriority(child.pid);
28936
28952
  logLines(child.stdout);
28937
28953
  logLines(child.stderr);
28938
28954
  child.once("error", reject);
28939
28955
  child.once("close", (c) => resolve2(c ?? -1));
28940
- }) : await spawnAsync(file3, args, { stdio: "inherit", ...options });
28956
+ }) : await spawnAsync(file3, args, { stdio: "inherit", ...spawnOptions, ...lowPriority ? { lowPriority } : {} });
28941
28957
  if (code !== 0)
28942
28958
  throw new Error(path17.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + code);
28943
28959
  }
@@ -28991,8 +29007,23 @@ function runScriptAsync(name, args = []) {
28991
29007
  function scriptOutput(name, args = [], options = {}) {
28992
29008
  return execOutput(SYSTEM.powershell(), scriptArgs(name, args), options);
28993
29009
  }
29010
+ function scriptOutputAsync(name, args = []) {
29011
+ return new Promise((resolve2) => {
29012
+ const child = spawn2(SYSTEM.powershell(), scriptArgs(name, args), {
29013
+ stdio: ["ignore", "pipe", "ignore"],
29014
+ windowsHide: true
29015
+ });
29016
+ let out = "";
29017
+ child.stdout?.setEncoding("utf8");
29018
+ child.stdout?.on("data", (chunk) => {
29019
+ if (out.length < CAPTURE_BYTES) out += chunk;
29020
+ });
29021
+ child.once("error", () => resolve2(""));
29022
+ child.once("close", (code) => resolve2(code === 0 ? out.trim() : ""));
29023
+ });
29024
+ }
28994
29025
  function runScriptWithJson(name, param, data, args = []) {
28995
- const dir = fs14.mkdtempSync(path17.join(os4.tmpdir(), "sbx-"));
29026
+ const dir = fs14.mkdtempSync(path17.join(os5.tmpdir(), "sbx-"));
28996
29027
  const file3 = path17.join(dir, "input.json");
28997
29028
  try {
28998
29029
  fs14.writeFileSync(file3, JSON.stringify(data), "utf8");
@@ -29002,7 +29033,7 @@ function runScriptWithJson(name, param, data, args = []) {
29002
29033
  }
29003
29034
  }
29004
29035
  async function runScriptWithJsonAsync(name, param, data, args = []) {
29005
- const dir = fs14.mkdtempSync(path17.join(os4.tmpdir(), "sbx-"));
29036
+ const dir = fs14.mkdtempSync(path17.join(os5.tmpdir(), "sbx-"));
29006
29037
  const file3 = path17.join(dir, "input.json");
29007
29038
  try {
29008
29039
  fs14.writeFileSync(file3, JSON.stringify(data), "utf8");
@@ -29451,13 +29482,14 @@ function itemSizes(saved) {
29451
29482
  }
29452
29483
  return sizes;
29453
29484
  }
29485
+ var ITEM_NAME = /^[A-Za-z0-9_-]{1,80}\.item$/;
29454
29486
  function isItemUnder(text2, root) {
29455
29487
  const at = itemInstallLocation(text2);
29456
29488
  return at !== null && isWithin(root, at) && win2.resolve(at) !== win2.resolve(root);
29457
29489
  }
29458
29490
  function itemFiles(dir) {
29459
29491
  try {
29460
- return fs16.readdirSync(dir).filter((f) => /^[A-Za-z0-9_-]{1,80}\.item$/.test(f));
29492
+ return fs16.readdirSync(dir).filter((f) => ITEM_NAME.test(f));
29461
29493
  } catch {
29462
29494
  return [];
29463
29495
  }
@@ -29528,6 +29560,8 @@ var UnrealStatusSchema = external_exports.object({
29528
29560
  ).max(64),
29529
29561
  launcher: external_exports.object({
29530
29562
  installed: external_exports.boolean(),
29563
+ /** Its program (Program Files or Program Files (x86), by launcher version); null when there is none. */
29564
+ exe: Text2().nullable().default(null),
29531
29565
  /** Where the launcher installs engines; null when it could not be set. */
29532
29566
  installLocation: Text2().nullable(),
29533
29567
  /** Why engines would not go to the data disk (shown loudly), null when they do. */
@@ -30704,7 +30738,6 @@ import fs21 from "node:fs";
30704
30738
  import path34 from "node:path";
30705
30739
 
30706
30740
  // src/guest/runtime/pools.ts
30707
- import os5 from "node:os";
30708
30741
  import { spawn as spawn4 } from "node:child_process";
30709
30742
  import path31 from "node:path";
30710
30743
 
@@ -30778,7 +30811,7 @@ function installerRetry(code, attempt) {
30778
30811
  }
30779
30812
 
30780
30813
  // src/shared/concurrency/pools.ts
30781
- var net2 = new Limiter(4, "net");
30814
+ var net2 = new Limiter(3, "net");
30782
30815
  var heavy = new Limiter(2, "heavy");
30783
30816
  var installer = new Limiter(1, "installer");
30784
30817
 
@@ -30787,14 +30820,7 @@ function installPools() {
30787
30820
  downloader.limit = net2;
30788
30821
  limitExtraction(heavy);
30789
30822
  }
30790
- var BELOW_NORMAL = os5.constants.priority.PRIORITY_BELOW_NORMAL;
30791
- function belowNormal(pid) {
30792
- if (pid === void 0) return;
30793
- try {
30794
- os5.setPriority(pid, BELOW_NORMAL);
30795
- } catch {
30796
- }
30797
- }
30823
+ var belowNormal = lowerPriority;
30798
30824
  async function runInstaller(file3, args, o = {}) {
30799
30825
  for (let attempt = 1; ; attempt++) {
30800
30826
  const code = await installer.run(
@@ -30820,7 +30846,7 @@ async function runInstallerChecked(file3, args, o = {}) {
30820
30846
  throw new Error(path31.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + code);
30821
30847
  }
30822
30848
  function execHeavy(file3, args, options = {}) {
30823
- return heavy.run(() => execAsync(file3, args, options));
30849
+ return heavy.run(() => execAsync(file3, args, { ...options, lowPriority: true }));
30824
30850
  }
30825
30851
 
30826
30852
  // src/guest/toolchains/installers.ts
@@ -30830,7 +30856,10 @@ import path32 from "node:path";
30830
30856
  // src/guest/toolchains/signature.ts
30831
30857
  var SignatureSchema = external_exports.object({ subject: external_exports.string().max(4096), issuer: external_exports.string().max(4096) });
30832
30858
  function signatureOf(file3) {
30833
- const text2 = scriptOutput("get-signature.ps1", ["-Path", file3]).trim();
30859
+ return parseSignature(scriptOutput("get-signature.ps1", ["-Path", file3]));
30860
+ }
30861
+ function parseSignature(output3) {
30862
+ const text2 = output3.trim();
30834
30863
  if (!text2) return null;
30835
30864
  try {
30836
30865
  const parsed = SignatureSchema.safeParse(JSON.parse(text2));
@@ -30842,11 +30871,14 @@ function signatureOf(file3) {
30842
30871
  function signedBy(file3, signer) {
30843
30872
  return signerMatches(signatureOf(file3), signer);
30844
30873
  }
30874
+ async function signedByAsync(file3, signer) {
30875
+ return signerMatches(parseSignature(await scriptOutputAsync("get-signature.ps1", ["-Path", file3])), signer);
30876
+ }
30845
30877
 
30846
30878
  // src/guest/toolchains/installers.ts
30847
30879
  function signatureCheck(signer, what) {
30848
- return (file3) => {
30849
- if (!signedBy(file3, signer)) throw new Error(what + " is not signed by its vendor");
30880
+ return async (file3) => {
30881
+ if (!await signedByAsync(file3, signer)) throw new Error(what + " is not signed by its vendor");
30850
30882
  };
30851
30883
  }
30852
30884
  async function signedInstaller(url2, file3, what, signer, sha256 = null) {
@@ -30855,7 +30887,7 @@ async function signedInstaller(url2, file3, what, signer, sha256 = null) {
30855
30887
  mkdirp(path32.dirname(file3));
30856
30888
  await downloader.file(url2, file3, { sha256, verify: signatureCheck(signer, path32.basename(file3)) });
30857
30889
  }
30858
- if (!signedBy(file3, signer)) {
30890
+ if (!await signedByAsync(file3, signer)) {
30859
30891
  fs20.rmSync(file3, { force: true });
30860
30892
  throw new Error(
30861
30893
  path32.basename(file3) + " is not signed by its vendor; deleted it (it is downloaded again next boot)"
@@ -30875,7 +30907,7 @@ var EMPTY = {
30875
30907
  updatedAt: "",
30876
30908
  engines: [],
30877
30909
  projects: [],
30878
- launcher: { installed: false, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
30910
+ launcher: { installed: false, exe: null, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
30879
30911
  visualStudio: { version: "", path: "", how: "", check: "", ok: false },
30880
30912
  debugger: null,
30881
30913
  ddc: { mode: "local", dir: null },
@@ -30903,11 +30935,15 @@ var SAVED_ENTRIES = path34.join(SAVED_DIR, "LauncherInstalled.json");
30903
30935
  var programData = () => process.env.ProgramData ?? "C:\\ProgramData";
30904
30936
  var localAppData2 = () => process.env.LOCALAPPDATA ?? "";
30905
30937
  function launcherExe() {
30906
- const root = path34.join(process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "Epic Games", "Launcher");
30907
- for (const arch2 of ["Win64", "Win32"]) {
30908
- const exe = path34.join(root, "Portal", "Binaries", arch2, "EpicGamesLauncher.exe");
30909
- if (exists(exe)) return exe;
30910
- }
30938
+ const roots = [
30939
+ process.env.ProgramFiles ?? "C:\\Program Files",
30940
+ process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)"
30941
+ ];
30942
+ for (const root of roots)
30943
+ for (const arch2 of ["Win64", "Win32"]) {
30944
+ const exe = path34.join(root, "Epic Games", "Launcher", "Portal", "Binaries", arch2, "EpicGamesLauncher.exe");
30945
+ if (exists(exe)) return exe;
30946
+ }
30911
30947
  return null;
30912
30948
  }
30913
30949
  async function fetchLauncher() {
@@ -30959,6 +30995,18 @@ function savedEntries() {
30959
30995
  function restoreLauncherItems() {
30960
30996
  return restoreItems(SAVED_MANIFESTS, launcherManifestsDir(programData()), ENGINES_DIR, exists);
30961
30997
  }
30998
+ function writePcLauncherItems(items) {
30999
+ const dir = launcherManifestsDir(programData());
31000
+ let written = 0;
31001
+ for (const i of items) {
31002
+ if (i.kind !== "unreal" || !i.launcherItem || !ITEM_NAME.test(i.launcherItem.name)) continue;
31003
+ const at = itemInstallLocation(i.launcherItem.text);
31004
+ if (!at || path34.win32.resolve(at).toLowerCase() !== path34.win32.resolve(i.guest).toLowerCase()) continue;
31005
+ fs21.writeFileSync(path34.join(mkdirp(dir), i.launcherItem.name), i.launcherItem.text, "utf8");
31006
+ written++;
31007
+ }
31008
+ return written;
31009
+ }
30962
31010
  function writeLauncherEntries(entries3) {
30963
31011
  if (!entries3.length) return;
30964
31012
  const file3 = launcherInstalledFile(programData());
@@ -31023,6 +31071,7 @@ async function registerEngines(engines, selectorFrom, ctx, aliases = []) {
31023
31071
  ];
31024
31072
  if (values.length) await runScriptWithJsonAsync("set-registry-values.ps1", "PlanFile", { values });
31025
31073
  try {
31074
+ writePcLauncherItems(ctx.pcInstalls.items);
31026
31075
  writeLauncherEntries(launcherEntries(engines, ctx));
31027
31076
  } catch (e) {
31028
31077
  warn("Unreal: the Epic Games Launcher's LauncherInstalled.dat was left as it is (" + errMsg(e) + ")");
@@ -31906,7 +31955,7 @@ async function installFromKept(dest, signer, what) {
31906
31955
  if (!installer2) return null;
31907
31956
  const installed = installedCometExe();
31908
31957
  if (fs29.existsSync(installed)) return installed;
31909
- if (!signedBy(installer2, signer)) {
31958
+ if (!await signedByAsync(installer2, signer)) {
31910
31959
  fs29.rmSync(path44.join(dest, ".agent-sandbox-app"), { force: true });
31911
31960
  fs29.rmSync(installer2, { force: true });
31912
31961
  throw new Error(what + "'s installer is not signed by its vendor; deleted it (it is downloaded again next boot)");
@@ -32208,7 +32257,7 @@ var MARKER = ".agent-sandbox-app";
32208
32257
  function prefetchedFile(entry, fileName) {
32209
32258
  return path48.join(tool("apps", ...entry.id.split("/")) + ".download", fileName.replace(/[\\/:*?"<>|]/g, "_"));
32210
32259
  }
32211
- var PARALLEL = 3;
32260
+ var PARALLEL = 2;
32212
32261
  var AppInstaller = class {
32213
32262
  constructor(env, options, parallel = PARALLEL) {
32214
32263
  this.env = env;
@@ -32229,19 +32278,21 @@ var AppInstaller = class {
32229
32278
  const todo = entries3.filter(
32230
32279
  (e) => !("remote" in e.source) && !("locked" in e.source) && !("store" in e.source) && !("npm" in e.source) && e.id !== "7zip" && (this.options.refresh || !exists(path48.join(tool("apps", ...e.id.split("/")), MARKER)))
32231
32280
  );
32232
- await Promise.all(
32233
- todo.map(async (entry) => {
32234
- try {
32235
- const d = await resolve(entry);
32236
- const file3 = prefetchedFile(entry, d.fileName);
32237
- if (exists(file3)) return;
32238
- await downloader.file(d.url, file3, {
32239
- sha256: d.sha256 ?? null,
32240
- ...entry.signer ? { verify: signatureCheck(entry.signer, d.fileName) } : {}
32241
- });
32242
- } catch {
32243
- }
32244
- })
32281
+ await asBackground(
32282
+ () => Promise.all(
32283
+ todo.map(async (entry) => {
32284
+ try {
32285
+ const d = await resolve(entry);
32286
+ const file3 = prefetchedFile(entry, d.fileName);
32287
+ if (exists(file3)) return;
32288
+ await downloader.file(d.url, file3, {
32289
+ sha256: d.sha256 ?? null,
32290
+ ...entry.signer ? { verify: signatureCheck(entry.signer, d.fileName) } : {}
32291
+ });
32292
+ } catch {
32293
+ }
32294
+ })
32295
+ )
32245
32296
  );
32246
32297
  }
32247
32298
  /** Installs the entries (7-Zip first: the NSIS apps need it to unpack), then their shortcuts. */
@@ -32298,7 +32349,7 @@ var AppInstaller = class {
32298
32349
  const exe = findExe(dest, entry.exe) ?? (entry.unpack === "chromium" && entry.signer ? await installFromKept(dest, entry.signer, entry.name) : null);
32299
32350
  if (!exe) throw new Error(entry.exe + " not found in the download");
32300
32351
  await afterInstall(entry, exe);
32301
- if (!entry.service && (entry.cli || entry.id === "sysinternals")) {
32352
+ if (!entry.service && (entry.cli || entry.onPath || entry.id === "sysinternals")) {
32302
32353
  if (entry.id === "rust-analyzer") this.env.prepend.unshift(path48.dirname(exe));
32303
32354
  else this.env.prepend.push(path48.dirname(exe));
32304
32355
  }
@@ -33859,8 +33910,19 @@ async function setupMesa(env, config3) {
33859
33910
  );
33860
33911
  if (config3.vulkan) await setupLavapipe(env, dir);
33861
33912
  }
33862
- var VULKAN_RUNTIME = "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-runtime-components.zip";
33863
- var VULKAN_RUNTIME_PINNED = "https://sdk.lunarg.com/sdk/download/1.4.350.0/windows/vulkan-runtime-components.zip";
33913
+ var VULKAN_LATEST = "https://vulkan.lunarg.com/sdk/latest.json";
33914
+ var runtimeUrl = (version2) => "https://sdk.lunarg.com/sdk/download/" + version2 + "/windows/vulkan-runtime-components.zip";
33915
+ var VULKAN_PINNED = "1.4.363.0";
33916
+ async function runtimeVersions() {
33917
+ let latest = null;
33918
+ try {
33919
+ const value = (await fetchJson(VULKAN_LATEST)).windows;
33920
+ if (typeof value === "string" && /^\d{1,2}\.\d{1,2}\.\d{1,4}\.\d{1,3}$/.test(value)) latest = value;
33921
+ } catch {
33922
+ }
33923
+ const found = latest ? [latest, latest.replace(/\.\d+$/, ".0")] : [];
33924
+ return [.../* @__PURE__ */ new Set([...found, VULKAN_PINNED])];
33925
+ }
33864
33926
  var setupLavapipe = async (env, mesaDir) => {
33865
33927
  const icd = path64.join(mesaDir, arch === "arm64" ? "lvp_icd.aarch64.json" : "lvp_icd.x86_64.json");
33866
33928
  if (!exists(icd)) throw new Error("this Mesa build has no lavapipe (" + path64.basename(icd) + ")");
@@ -33868,11 +33930,15 @@ var setupLavapipe = async (env, mesaDir) => {
33868
33930
  if (!exists(path64.join(dir, "vulkan-1.dll")) || !exists(path64.join(dir, "vulkaninfo.exe"))) {
33869
33931
  log("Downloading the Vulkan loader (~20 MB once) ...");
33870
33932
  const fetchRuntime = (url2) => downloader.archive(url2, dir, { locate: "vulkan-1.dll", fileName: "vulkan-runtime.zip", members: ["*/x64/*"] });
33871
- try {
33872
- await fetchRuntime(VULKAN_RUNTIME);
33873
- } catch (e) {
33874
- warn("The latest Vulkan runtime could not be downloaded (" + errMsg(e) + "); using version 1.4.350.0.");
33875
- await fetchRuntime(VULKAN_RUNTIME_PINNED);
33933
+ const versions = await runtimeVersions();
33934
+ for (const [n, version2] of versions.entries()) {
33935
+ try {
33936
+ await fetchRuntime(runtimeUrl(version2));
33937
+ log("Vulkan loader " + version2 + " installed");
33938
+ break;
33939
+ } catch (e) {
33940
+ if (n === versions.length - 1) throw new Error("the Vulkan loader could not be downloaded (" + errMsg(e) + ")");
33941
+ }
33876
33942
  }
33877
33943
  }
33878
33944
  const register = (file3) => execAsync(
@@ -34940,6 +35006,7 @@ async function setupUnreal(env, config3, _ctx) {
34940
35006
  ...s,
34941
35007
  launcher: {
34942
35008
  installed: launcher !== null,
35009
+ exe: launcher,
34943
35010
  installLocation: place.installLocation,
34944
35011
  problem: place.problem,
34945
35012
  freeBytes: place.freeBytes,
@@ -35384,7 +35451,7 @@ async function setupVcRuntime(env, summary = true) {
35384
35451
  log("Downloading the Visual C++ runtime (~25 MB once) ...");
35385
35452
  await downloadFile(VC_REDIST, installer2);
35386
35453
  }
35387
- if (!signedBy(installer2, SIGNERS.microsoft)) {
35454
+ if (!await signedByAsync(installer2, SIGNERS.microsoft)) {
35388
35455
  fs56.rmSync(installer2, { force: true });
35389
35456
  throw new Error("vc_redist.x64.exe is not signed by Microsoft; deleted it (it is downloaded again next boot)");
35390
35457
  }
@@ -37670,7 +37737,9 @@ import path87 from "node:path";
37670
37737
  async function syncSkills(unityExe, agent) {
37671
37738
  const home = agent === "claude" ? { CLAUDE_CONFIG_DIR: claudeDir } : { CODEX_HOME: path87.join(stateDir, "codex") };
37672
37739
  try {
37673
- await execAsync(unityExe, ["skill", "sync", agent], { env: { ...process.env, ...UNITY_CLI_ENV, ...home } });
37740
+ await execAsync(unityExe, ["skill", "sync", agent === "claude" ? "claude-code" : "codex"], {
37741
+ env: { ...process.env, ...UNITY_CLI_ENV, ...home }
37742
+ });
37674
37743
  return true;
37675
37744
  } catch (e) {
37676
37745
  warn("Unity skills for " + agent + " were not synced: " + (e instanceof Error ? e.message : String(e)));
@@ -38621,7 +38690,7 @@ function plan(config3, versions, o) {
38621
38690
 
38622
38691
  // src/guest/toolchains/step-scheduler.ts
38623
38692
  import { AsyncLocalStorage as AsyncLocalStorage4 } from "node:async_hooks";
38624
- var PARALLEL2 = 4;
38693
+ var PARALLEL2 = 3;
38625
38694
  async function runReported(sink2, name, env, work) {
38626
38695
  try {
38627
38696
  await work();
@@ -26121,6 +26121,7 @@ var GAMEDEV_APPS = [
26121
26121
  size: "100 MB",
26122
26122
  source: { github: "f3d-app/f3d", asset: "^F3D-[\\d.]+-Windows-x86_64\\.zip$" },
26123
26123
  exe: "f3d.exe",
26124
+ onPath: true,
26124
26125
  needs: ["mesa"]
26125
26126
  },
26126
26127
  {
@@ -27220,7 +27221,7 @@ var SERVICE_SPECS = {
27220
27221
  },
27221
27222
  steam: {
27222
27223
  kind: "steam",
27223
- label: "Steam (SteamCMD)",
27224
+ label: "Steam",
27224
27225
  usedBy: ["steam"],
27225
27226
  sources: ["file", "sandbox"],
27226
27227
  singleHolder: true,
@@ -27256,7 +27257,7 @@ var SERVICE_SPECS = {
27256
27257
  },
27257
27258
  cfx: {
27258
27259
  kind: "cfx",
27259
- label: "Cfx.re (FiveM / RedM server key)",
27260
+ label: "FiveM key",
27260
27261
  usedBy: ["fivem"],
27261
27262
  sources: ["typed", "file"],
27262
27263
  singleHolder: false,
@@ -27285,7 +27286,7 @@ var SERVICE_SPECS = {
27285
27286
  },
27286
27287
  keystore: {
27287
27288
  kind: "keystore",
27288
- label: "Android upload keystore",
27289
+ label: "Android keystore",
27289
27290
  usedBy: ["android"],
27290
27291
  sources: ["file"],
27291
27292
  singleHolder: false,
@@ -27300,7 +27301,7 @@ var SERVICE_SPECS = {
27300
27301
  },
27301
27302
  play: {
27302
27303
  kind: "play",
27303
- label: "Google Play (service account)",
27304
+ label: "Google Play",
27304
27305
  usedBy: ["android"],
27305
27306
  sources: ["file"],
27306
27307
  singleHolder: false,
@@ -27311,7 +27312,7 @@ var SERVICE_SPECS = {
27311
27312
  },
27312
27313
  expo: {
27313
27314
  kind: "expo",
27314
- label: "Expo (EAS)",
27315
+ label: "Expo",
27315
27316
  usedBy: ["reactNative"],
27316
27317
  sources: ["typed"],
27317
27318
  singleHolder: false,
@@ -27322,7 +27323,7 @@ var SERVICE_SPECS = {
27322
27323
  },
27323
27324
  appstore: {
27324
27325
  kind: "appstore",
27325
- label: "App Store Connect API key",
27326
+ label: "App Store Connect",
27326
27327
  usedBy: ["reactNative", "flutter"],
27327
27328
  sources: ["file", "typed"],
27328
27329
  singleHolder: false,
@@ -27336,7 +27337,7 @@ var SERVICE_SPECS = {
27336
27337
  },
27337
27338
  perplexity: {
27338
27339
  kind: "perplexity",
27339
- label: "Perplexity API key",
27340
+ label: "Perplexity API",
27340
27341
  usedBy: ["perplexity"],
27341
27342
  sources: ["pc", "file", "typed"],
27342
27343
  singleHolder: false,
@@ -27360,7 +27361,7 @@ var SERVICE_SPECS = {
27360
27361
  },
27361
27362
  comet: {
27362
27363
  kind: "comet",
27363
- label: "Comet (Perplexity browser)",
27364
+ label: "Comet",
27364
27365
  usedBy: ["comet"],
27365
27366
  sources: ["sandbox"],
27366
27367
  singleHolder: false,
@@ -27376,7 +27377,7 @@ var SERVICE_SPECS = {
27376
27377
  },
27377
27378
  perplexityapp: {
27378
27379
  kind: "perplexityapp",
27379
- label: "Perplexity desktop app",
27380
+ label: "Perplexity app",
27380
27381
  usedBy: ["perplexityapp"],
27381
27382
  sources: ["sandbox"],
27382
27383
  singleHolder: false,
@@ -28124,10 +28125,20 @@ function scriptArgs(name, args = []) {
28124
28125
  }
28125
28126
 
28126
28127
  // src/shared/download/spawn.ts
28128
+ import os3 from "node:os";
28127
28129
  import { spawn } from "node:child_process";
28130
+ function lowerPriority(pid) {
28131
+ if (pid === void 0) return;
28132
+ try {
28133
+ os3.setPriority(pid, os3.constants.priority.PRIORITY_BELOW_NORMAL);
28134
+ } catch {
28135
+ }
28136
+ }
28128
28137
  function spawnAsync(file2, args, options = {}) {
28138
+ const { lowPriority, ...spawnOptions } = options;
28129
28139
  return new Promise((resolve, reject) => {
28130
- const child = spawn(file2, args, { stdio: "ignore", windowsHide: true, ...options });
28140
+ const child = spawn(file2, args, { stdio: "ignore", windowsHide: true, ...spawnOptions });
28141
+ if (lowPriority) lowerPriority(child.pid);
28131
28142
  child.once("error", reject);
28132
28143
  child.once("close", (code) => resolve(code ?? -1));
28133
28144
  });
@@ -28148,13 +28159,16 @@ function extractArchive(archive, destination, members2 = []) {
28148
28159
  }
28149
28160
  async function extract(archive, destination, members2) {
28150
28161
  fs6.mkdirSync(destination, { recursive: true });
28151
- let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2]);
28162
+ let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2], {
28163
+ lowPriority: true
28164
+ });
28152
28165
  if (status !== 0 && /\.(zip|nupkg)$/i.test(archive)) {
28153
28166
  const zip = archive.endsWith(".zip") ? archive : archive + ".zip";
28154
28167
  if (zip !== archive) fs6.copyFileSync(archive, zip);
28155
28168
  status = await spawnAsync(
28156
28169
  SYSTEM.powershell(),
28157
- scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination])
28170
+ scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination]),
28171
+ { lowPriority: true }
28158
28172
  );
28159
28173
  }
28160
28174
  if (status !== 0) throw new Error("Could not extract " + archive);