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
@@ -26113,6 +26113,7 @@ var GAMEDEV_APPS = [
26113
26113
  size: "100 MB",
26114
26114
  source: { github: "f3d-app/f3d", asset: "^F3D-[\\d.]+-Windows-x86_64\\.zip$" },
26115
26115
  exe: "f3d.exe",
26116
+ onPath: true,
26116
26117
  needs: ["mesa"]
26117
26118
  },
26118
26119
  {
@@ -27413,7 +27414,7 @@ var SERVICE_SPECS = {
27413
27414
  },
27414
27415
  steam: {
27415
27416
  kind: "steam",
27416
- label: "Steam (SteamCMD)",
27417
+ label: "Steam",
27417
27418
  usedBy: ["steam"],
27418
27419
  sources: ["file", "sandbox"],
27419
27420
  singleHolder: true,
@@ -27449,7 +27450,7 @@ var SERVICE_SPECS = {
27449
27450
  },
27450
27451
  cfx: {
27451
27452
  kind: "cfx",
27452
- label: "Cfx.re (FiveM / RedM server key)",
27453
+ label: "FiveM key",
27453
27454
  usedBy: ["fivem"],
27454
27455
  sources: ["typed", "file"],
27455
27456
  singleHolder: false,
@@ -27478,7 +27479,7 @@ var SERVICE_SPECS = {
27478
27479
  },
27479
27480
  keystore: {
27480
27481
  kind: "keystore",
27481
- label: "Android upload keystore",
27482
+ label: "Android keystore",
27482
27483
  usedBy: ["android"],
27483
27484
  sources: ["file"],
27484
27485
  singleHolder: false,
@@ -27493,7 +27494,7 @@ var SERVICE_SPECS = {
27493
27494
  },
27494
27495
  play: {
27495
27496
  kind: "play",
27496
- label: "Google Play (service account)",
27497
+ label: "Google Play",
27497
27498
  usedBy: ["android"],
27498
27499
  sources: ["file"],
27499
27500
  singleHolder: false,
@@ -27504,7 +27505,7 @@ var SERVICE_SPECS = {
27504
27505
  },
27505
27506
  expo: {
27506
27507
  kind: "expo",
27507
- label: "Expo (EAS)",
27508
+ label: "Expo",
27508
27509
  usedBy: ["reactNative"],
27509
27510
  sources: ["typed"],
27510
27511
  singleHolder: false,
@@ -27515,7 +27516,7 @@ var SERVICE_SPECS = {
27515
27516
  },
27516
27517
  appstore: {
27517
27518
  kind: "appstore",
27518
- label: "App Store Connect API key",
27519
+ label: "App Store Connect",
27519
27520
  usedBy: ["reactNative", "flutter"],
27520
27521
  sources: ["file", "typed"],
27521
27522
  singleHolder: false,
@@ -27529,7 +27530,7 @@ var SERVICE_SPECS = {
27529
27530
  },
27530
27531
  perplexity: {
27531
27532
  kind: "perplexity",
27532
- label: "Perplexity API key",
27533
+ label: "Perplexity API",
27533
27534
  usedBy: ["perplexity"],
27534
27535
  sources: ["pc", "file", "typed"],
27535
27536
  singleHolder: false,
@@ -27553,7 +27554,7 @@ var SERVICE_SPECS = {
27553
27554
  },
27554
27555
  comet: {
27555
27556
  kind: "comet",
27556
- label: "Comet (Perplexity browser)",
27557
+ label: "Comet",
27557
27558
  usedBy: ["comet"],
27558
27559
  sources: ["sandbox"],
27559
27560
  singleHolder: false,
@@ -27569,7 +27570,7 @@ var SERVICE_SPECS = {
27569
27570
  },
27570
27571
  perplexityapp: {
27571
27572
  kind: "perplexityapp",
27572
- label: "Perplexity desktop app",
27573
+ label: "Perplexity app",
27573
27574
  usedBy: ["perplexityapp"],
27574
27575
  sources: ["sandbox"],
27575
27576
  singleHolder: false,
@@ -28531,10 +28532,20 @@ function scriptArgs(name, args = []) {
28531
28532
  }
28532
28533
 
28533
28534
  // src/shared/download/spawn.ts
28535
+ import os3 from "node:os";
28534
28536
  import { spawn } from "node:child_process";
28537
+ function lowerPriority(pid) {
28538
+ if (pid === void 0) return;
28539
+ try {
28540
+ os3.setPriority(pid, os3.constants.priority.PRIORITY_BELOW_NORMAL);
28541
+ } catch {
28542
+ }
28543
+ }
28535
28544
  function spawnAsync(file3, args, options = {}) {
28545
+ const { lowPriority, ...spawnOptions } = options;
28536
28546
  return new Promise((resolve2, reject) => {
28537
- const child = spawn(file3, args, { stdio: "ignore", windowsHide: true, ...options });
28547
+ const child = spawn(file3, args, { stdio: "ignore", windowsHide: true, ...spawnOptions });
28548
+ if (lowPriority) lowerPriority(child.pid);
28538
28549
  child.once("error", reject);
28539
28550
  child.once("close", (code) => resolve2(code ?? -1));
28540
28551
  });
@@ -28558,13 +28569,16 @@ function extractArchive(archive, destination, members2 = []) {
28558
28569
  }
28559
28570
  async function extract(archive, destination, members2) {
28560
28571
  fs10.mkdirSync(destination, { recursive: true });
28561
- let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2]);
28572
+ let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2], {
28573
+ lowPriority: true
28574
+ });
28562
28575
  if (status !== 0 && /\.(zip|nupkg)$/i.test(archive)) {
28563
28576
  const zip = archive.endsWith(".zip") ? archive : archive + ".zip";
28564
28577
  if (zip !== archive) fs10.copyFileSync(archive, zip);
28565
28578
  status = await spawnAsync(
28566
28579
  SYSTEM.powershell(),
28567
- scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination])
28580
+ scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination]),
28581
+ { lowPriority: true }
28568
28582
  );
28569
28583
  }
28570
28584
  if (status !== 0) throw new Error("Could not extract " + archive);
@@ -29160,7 +29174,6 @@ function withRequestSecrets(req) {
29160
29174
  }
29161
29175
 
29162
29176
  // src/guest/runtime/pools.ts
29163
- import os4 from "node:os";
29164
29177
  import { spawn as spawn3 } from "node:child_process";
29165
29178
  import path21 from "node:path";
29166
29179
 
@@ -29234,13 +29247,13 @@ function installerRetry(code, attempt) {
29234
29247
  }
29235
29248
 
29236
29249
  // src/shared/concurrency/pools.ts
29237
- var net2 = new Limiter(4, "net");
29250
+ var net2 = new Limiter(3, "net");
29238
29251
  var heavy = new Limiter(2, "heavy");
29239
29252
  var installer = new Limiter(1, "installer");
29240
29253
 
29241
29254
  // src/guest/runtime/process.ts
29242
29255
  import fs16 from "node:fs";
29243
- import os3 from "node:os";
29256
+ import os4 from "node:os";
29244
29257
  import path20 from "node:path";
29245
29258
  import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
29246
29259
  var outputSink = null;
@@ -29262,13 +29275,15 @@ function logLines(stream) {
29262
29275
  stream.on("end", () => logOutput(partial2));
29263
29276
  }
29264
29277
  async function execAsync(file3, args, options = {}) {
29278
+ const { lowPriority, ...spawnOptions } = options;
29265
29279
  const code = captureOutput() ? await new Promise((resolve2, reject) => {
29266
- const child = spawn2(file3, args, { stdio: ["inherit", "pipe", "pipe"], windowsHide: true, ...options });
29280
+ const child = spawn2(file3, args, { stdio: ["inherit", "pipe", "pipe"], windowsHide: true, ...spawnOptions });
29281
+ if (lowPriority) lowerPriority(child.pid);
29267
29282
  logLines(child.stdout);
29268
29283
  logLines(child.stderr);
29269
29284
  child.once("error", reject);
29270
29285
  child.once("close", (c) => resolve2(c ?? -1));
29271
- }) : await spawnAsync(file3, args, { stdio: "inherit", ...options });
29286
+ }) : await spawnAsync(file3, args, { stdio: "inherit", ...spawnOptions, ...lowPriority ? { lowPriority } : {} });
29272
29287
  if (code !== 0)
29273
29288
  throw new Error(path20.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + code);
29274
29289
  }
@@ -29322,8 +29337,23 @@ function runScriptAsync(name, args = []) {
29322
29337
  function scriptOutput(name, args = [], options = {}) {
29323
29338
  return execOutput(SYSTEM.powershell(), scriptArgs(name, args), options);
29324
29339
  }
29340
+ function scriptOutputAsync(name, args = []) {
29341
+ return new Promise((resolve2) => {
29342
+ const child = spawn2(SYSTEM.powershell(), scriptArgs(name, args), {
29343
+ stdio: ["ignore", "pipe", "ignore"],
29344
+ windowsHide: true
29345
+ });
29346
+ let out = "";
29347
+ child.stdout?.setEncoding("utf8");
29348
+ child.stdout?.on("data", (chunk) => {
29349
+ if (out.length < CAPTURE_BYTES) out += chunk;
29350
+ });
29351
+ child.once("error", () => resolve2(""));
29352
+ child.once("close", (code) => resolve2(code === 0 ? out.trim() : ""));
29353
+ });
29354
+ }
29325
29355
  function runScriptWithJson(name, param, data, args = []) {
29326
- const dir = fs16.mkdtempSync(path20.join(os3.tmpdir(), "sbx-"));
29356
+ const dir = fs16.mkdtempSync(path20.join(os4.tmpdir(), "sbx-"));
29327
29357
  const file3 = path20.join(dir, "input.json");
29328
29358
  try {
29329
29359
  fs16.writeFileSync(file3, JSON.stringify(data), "utf8");
@@ -29333,7 +29363,7 @@ function runScriptWithJson(name, param, data, args = []) {
29333
29363
  }
29334
29364
  }
29335
29365
  async function runScriptWithJsonAsync(name, param, data, args = []) {
29336
- const dir = fs16.mkdtempSync(path20.join(os3.tmpdir(), "sbx-"));
29366
+ const dir = fs16.mkdtempSync(path20.join(os4.tmpdir(), "sbx-"));
29337
29367
  const file3 = path20.join(dir, "input.json");
29338
29368
  try {
29339
29369
  fs16.writeFileSync(file3, JSON.stringify(data), "utf8");
@@ -29404,14 +29434,7 @@ function installPools() {
29404
29434
  downloader.limit = net2;
29405
29435
  limitExtraction(heavy);
29406
29436
  }
29407
- var BELOW_NORMAL = os4.constants.priority.PRIORITY_BELOW_NORMAL;
29408
- function belowNormal(pid) {
29409
- if (pid === void 0) return;
29410
- try {
29411
- os4.setPriority(pid, BELOW_NORMAL);
29412
- } catch {
29413
- }
29414
- }
29437
+ var belowNormal = lowerPriority;
29415
29438
  async function runInstaller(file3, args, o = {}) {
29416
29439
  for (let attempt = 1; ; attempt++) {
29417
29440
  const code = await installer.run(
@@ -29437,7 +29460,7 @@ async function runInstallerChecked(file3, args, o = {}) {
29437
29460
  throw new Error(path21.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + code);
29438
29461
  }
29439
29462
  function execHeavy(file3, args, options = {}) {
29440
- return heavy.run(() => execAsync(file3, args, options));
29463
+ return heavy.run(() => execAsync(file3, args, { ...options, lowPriority: true }));
29441
29464
  }
29442
29465
 
29443
29466
  // src/guest/daemon/daemon.ts
@@ -30361,13 +30384,14 @@ function itemSizes(saved2) {
30361
30384
  }
30362
30385
  return sizes;
30363
30386
  }
30387
+ var ITEM_NAME = /^[A-Za-z0-9_-]{1,80}\.item$/;
30364
30388
  function isItemUnder(text2, root) {
30365
30389
  const at = itemInstallLocation(text2);
30366
30390
  return at !== null && isWithin2(root, at) && win2.resolve(at) !== win2.resolve(root);
30367
30391
  }
30368
30392
  function itemFiles(dir) {
30369
30393
  try {
30370
- return fs22.readdirSync(dir).filter((f) => /^[A-Za-z0-9_-]{1,80}\.item$/.test(f));
30394
+ return fs22.readdirSync(dir).filter((f) => ITEM_NAME.test(f));
30371
30395
  } catch {
30372
30396
  return [];
30373
30397
  }
@@ -30451,6 +30475,8 @@ var UnrealStatusSchema = external_exports.object({
30451
30475
  ).max(64),
30452
30476
  launcher: external_exports.object({
30453
30477
  installed: external_exports.boolean(),
30478
+ /** Its program (Program Files or Program Files (x86), by launcher version); null when there is none. */
30479
+ exe: Text2().nullable().default(null),
30454
30480
  /** Where the launcher installs engines; null when it could not be set. */
30455
30481
  installLocation: Text2().nullable(),
30456
30482
  /** Why engines would not go to the data disk (shown loudly), null when they do. */
@@ -31523,7 +31549,10 @@ import path42 from "node:path";
31523
31549
  // src/guest/toolchains/signature.ts
31524
31550
  var SignatureSchema = external_exports.object({ subject: external_exports.string().max(4096), issuer: external_exports.string().max(4096) });
31525
31551
  function signatureOf(file3) {
31526
- const text2 = scriptOutput("get-signature.ps1", ["-Path", file3]).trim();
31552
+ return parseSignature(scriptOutput("get-signature.ps1", ["-Path", file3]));
31553
+ }
31554
+ function parseSignature(output2) {
31555
+ const text2 = output2.trim();
31527
31556
  if (!text2) return null;
31528
31557
  try {
31529
31558
  const parsed = SignatureSchema.safeParse(JSON.parse(text2));
@@ -31535,11 +31564,14 @@ function signatureOf(file3) {
31535
31564
  function signedBy(file3, signer) {
31536
31565
  return signerMatches(signatureOf(file3), signer);
31537
31566
  }
31567
+ async function signedByAsync(file3, signer) {
31568
+ return signerMatches(parseSignature(await scriptOutputAsync("get-signature.ps1", ["-Path", file3])), signer);
31569
+ }
31538
31570
 
31539
31571
  // src/guest/toolchains/installers.ts
31540
31572
  function signatureCheck(signer, what) {
31541
- return (file3) => {
31542
- if (!signedBy(file3, signer)) throw new Error(what + " is not signed by its vendor");
31573
+ return async (file3) => {
31574
+ if (!await signedByAsync(file3, signer)) throw new Error(what + " is not signed by its vendor");
31543
31575
  };
31544
31576
  }
31545
31577
  async function signedInstaller(url2, file3, what, signer, sha256 = null) {
@@ -31548,7 +31580,7 @@ async function signedInstaller(url2, file3, what, signer, sha256 = null) {
31548
31580
  mkdirp(path42.dirname(file3));
31549
31581
  await downloader.file(url2, file3, { sha256, verify: signatureCheck(signer, path42.basename(file3)) });
31550
31582
  }
31551
- if (!signedBy(file3, signer)) {
31583
+ if (!await signedByAsync(file3, signer)) {
31552
31584
  fs25.rmSync(file3, { force: true });
31553
31585
  throw new Error(
31554
31586
  path42.basename(file3) + " is not signed by its vendor; deleted it (it is downloaded again next boot)"
@@ -31568,7 +31600,7 @@ var EMPTY = {
31568
31600
  updatedAt: "",
31569
31601
  engines: [],
31570
31602
  projects: [],
31571
- launcher: { installed: false, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
31603
+ launcher: { installed: false, exe: null, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
31572
31604
  visualStudio: { version: "", path: "", how: "", check: "", ok: false },
31573
31605
  debugger: null,
31574
31606
  ddc: { mode: "local", dir: null },
@@ -31596,11 +31628,15 @@ var SAVED_ENTRIES = path44.join(SAVED_DIR, "LauncherInstalled.json");
31596
31628
  var programData = () => process.env.ProgramData ?? "C:\\ProgramData";
31597
31629
  var localAppData2 = () => process.env.LOCALAPPDATA ?? "";
31598
31630
  function launcherExe() {
31599
- const root = path44.join(process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "Epic Games", "Launcher");
31600
- for (const arch2 of ["Win64", "Win32"]) {
31601
- const exe = path44.join(root, "Portal", "Binaries", arch2, "EpicGamesLauncher.exe");
31602
- if (exists(exe)) return exe;
31603
- }
31631
+ const roots = [
31632
+ process.env.ProgramFiles ?? "C:\\Program Files",
31633
+ process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)"
31634
+ ];
31635
+ for (const root of roots)
31636
+ for (const arch2 of ["Win64", "Win32"]) {
31637
+ const exe = path44.join(root, "Epic Games", "Launcher", "Portal", "Binaries", arch2, "EpicGamesLauncher.exe");
31638
+ if (exists(exe)) return exe;
31639
+ }
31604
31640
  return null;
31605
31641
  }
31606
31642
  async function fetchLauncher() {
@@ -31652,6 +31688,18 @@ function savedEntries() {
31652
31688
  function restoreLauncherItems() {
31653
31689
  return restoreItems(SAVED_MANIFESTS, launcherManifestsDir(programData()), ENGINES_DIR, exists);
31654
31690
  }
31691
+ function writePcLauncherItems(items) {
31692
+ const dir = launcherManifestsDir(programData());
31693
+ let written = 0;
31694
+ for (const i of items) {
31695
+ if (i.kind !== "unreal" || !i.launcherItem || !ITEM_NAME.test(i.launcherItem.name)) continue;
31696
+ const at = itemInstallLocation(i.launcherItem.text);
31697
+ if (!at || path44.win32.resolve(at).toLowerCase() !== path44.win32.resolve(i.guest).toLowerCase()) continue;
31698
+ fs26.writeFileSync(path44.join(mkdirp(dir), i.launcherItem.name), i.launcherItem.text, "utf8");
31699
+ written++;
31700
+ }
31701
+ return written;
31702
+ }
31655
31703
  function writeLauncherEntries(entries2) {
31656
31704
  if (!entries2.length) return;
31657
31705
  const file3 = launcherInstalledFile(programData());
@@ -31735,6 +31783,7 @@ async function registerEngines(engines, selectorFrom, ctx, aliases = []) {
31735
31783
  ];
31736
31784
  if (values.length) await runScriptWithJsonAsync("set-registry-values.ps1", "PlanFile", { values });
31737
31785
  try {
31786
+ writePcLauncherItems(ctx.pcInstalls.items);
31738
31787
  writeLauncherEntries(launcherEntries(engines, ctx));
31739
31788
  } catch (e) {
31740
31789
  warn("Unreal: the Epic Games Launcher's LauncherInstalled.dat was left as it is (" + errMsg(e) + ")");
@@ -32615,7 +32664,7 @@ async function installFromKept(dest, signer, what) {
32615
32664
  if (!installer2) return null;
32616
32665
  const installed = installedCometExe();
32617
32666
  if (fs35.existsSync(installed)) return installed;
32618
- if (!signedBy(installer2, signer)) {
32667
+ if (!await signedByAsync(installer2, signer)) {
32619
32668
  fs35.rmSync(path54.join(dest, ".agent-sandbox-app"), { force: true });
32620
32669
  fs35.rmSync(installer2, { force: true });
32621
32670
  throw new Error(what + "'s installer is not signed by its vendor; deleted it (it is downloaded again next boot)");
@@ -32917,7 +32966,7 @@ var MARKER = ".agent-sandbox-app";
32917
32966
  function prefetchedFile(entry, fileName) {
32918
32967
  return path58.join(tool("apps", ...entry.id.split("/")) + ".download", fileName.replace(/[\\/:*?"<>|]/g, "_"));
32919
32968
  }
32920
- var PARALLEL = 3;
32969
+ var PARALLEL = 2;
32921
32970
  var AppInstaller = class {
32922
32971
  constructor(env, options, parallel = PARALLEL) {
32923
32972
  this.env = env;
@@ -32938,19 +32987,21 @@ var AppInstaller = class {
32938
32987
  const todo = entries2.filter(
32939
32988
  (e) => !("remote" in e.source) && !("locked" in e.source) && !("store" in e.source) && !("npm" in e.source) && e.id !== "7zip" && (this.options.refresh || !exists(path58.join(tool("apps", ...e.id.split("/")), MARKER)))
32940
32989
  );
32941
- await Promise.all(
32942
- todo.map(async (entry) => {
32943
- try {
32944
- const d = await resolve(entry);
32945
- const file3 = prefetchedFile(entry, d.fileName);
32946
- if (exists(file3)) return;
32947
- await downloader.file(d.url, file3, {
32948
- sha256: d.sha256 ?? null,
32949
- ...entry.signer ? { verify: signatureCheck(entry.signer, d.fileName) } : {}
32950
- });
32951
- } catch {
32952
- }
32953
- })
32990
+ await asBackground(
32991
+ () => Promise.all(
32992
+ todo.map(async (entry) => {
32993
+ try {
32994
+ const d = await resolve(entry);
32995
+ const file3 = prefetchedFile(entry, d.fileName);
32996
+ if (exists(file3)) return;
32997
+ await downloader.file(d.url, file3, {
32998
+ sha256: d.sha256 ?? null,
32999
+ ...entry.signer ? { verify: signatureCheck(entry.signer, d.fileName) } : {}
33000
+ });
33001
+ } catch {
33002
+ }
33003
+ })
33004
+ )
32954
33005
  );
32955
33006
  }
32956
33007
  /** Installs the entries (7-Zip first: the NSIS apps need it to unpack), then their shortcuts. */
@@ -33007,7 +33058,7 @@ var AppInstaller = class {
33007
33058
  const exe = findExe(dest, entry.exe) ?? (entry.unpack === "chromium" && entry.signer ? await installFromKept(dest, entry.signer, entry.name) : null);
33008
33059
  if (!exe) throw new Error(entry.exe + " not found in the download");
33009
33060
  await afterInstall(entry, exe);
33010
- if (!entry.service && (entry.cli || entry.id === "sysinternals")) {
33061
+ if (!entry.service && (entry.cli || entry.onPath || entry.id === "sysinternals")) {
33011
33062
  if (entry.id === "rust-analyzer") this.env.prepend.unshift(path58.dirname(exe));
33012
33063
  else this.env.prepend.push(path58.dirname(exe));
33013
33064
  }
@@ -34573,8 +34624,19 @@ async function setupMesa(env, config2) {
34573
34624
  );
34574
34625
  if (config2.vulkan) await setupLavapipe(env, dir);
34575
34626
  }
34576
- var VULKAN_RUNTIME = "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-runtime-components.zip";
34577
- var VULKAN_RUNTIME_PINNED = "https://sdk.lunarg.com/sdk/download/1.4.350.0/windows/vulkan-runtime-components.zip";
34627
+ var VULKAN_LATEST = "https://vulkan.lunarg.com/sdk/latest.json";
34628
+ var runtimeUrl = (version2) => "https://sdk.lunarg.com/sdk/download/" + version2 + "/windows/vulkan-runtime-components.zip";
34629
+ var VULKAN_PINNED = "1.4.363.0";
34630
+ async function runtimeVersions() {
34631
+ let latest = null;
34632
+ try {
34633
+ const value = (await fetchJson(VULKAN_LATEST)).windows;
34634
+ if (typeof value === "string" && /^\d{1,2}\.\d{1,2}\.\d{1,4}\.\d{1,3}$/.test(value)) latest = value;
34635
+ } catch {
34636
+ }
34637
+ const found = latest ? [latest, latest.replace(/\.\d+$/, ".0")] : [];
34638
+ return [.../* @__PURE__ */ new Set([...found, VULKAN_PINNED])];
34639
+ }
34578
34640
  var setupLavapipe = async (env, mesaDir) => {
34579
34641
  const icd = path74.join(mesaDir, arch === "arm64" ? "lvp_icd.aarch64.json" : "lvp_icd.x86_64.json");
34580
34642
  if (!exists(icd)) throw new Error("this Mesa build has no lavapipe (" + path74.basename(icd) + ")");
@@ -34582,11 +34644,15 @@ var setupLavapipe = async (env, mesaDir) => {
34582
34644
  if (!exists(path74.join(dir, "vulkan-1.dll")) || !exists(path74.join(dir, "vulkaninfo.exe"))) {
34583
34645
  log("Downloading the Vulkan loader (~20 MB once) ...");
34584
34646
  const fetchRuntime = (url2) => downloader.archive(url2, dir, { locate: "vulkan-1.dll", fileName: "vulkan-runtime.zip", members: ["*/x64/*"] });
34585
- try {
34586
- await fetchRuntime(VULKAN_RUNTIME);
34587
- } catch (e) {
34588
- warn("The latest Vulkan runtime could not be downloaded (" + errMsg(e) + "); using version 1.4.350.0.");
34589
- await fetchRuntime(VULKAN_RUNTIME_PINNED);
34647
+ const versions = await runtimeVersions();
34648
+ for (const [n, version2] of versions.entries()) {
34649
+ try {
34650
+ await fetchRuntime(runtimeUrl(version2));
34651
+ log("Vulkan loader " + version2 + " installed");
34652
+ break;
34653
+ } catch (e) {
34654
+ if (n === versions.length - 1) throw new Error("the Vulkan loader could not be downloaded (" + errMsg(e) + ")");
34655
+ }
34590
34656
  }
34591
34657
  }
34592
34658
  const register = (file3) => execAsync(
@@ -35702,6 +35768,7 @@ async function setupUnreal(env, config2, _ctx) {
35702
35768
  ...s,
35703
35769
  launcher: {
35704
35770
  installed: launcher !== null,
35771
+ exe: launcher,
35705
35772
  installLocation: place.installLocation,
35706
35773
  problem: place.problem,
35707
35774
  freeBytes: place.freeBytes,
@@ -36146,7 +36213,7 @@ async function setupVcRuntime(env, summary = true) {
36146
36213
  log("Downloading the Visual C++ runtime (~25 MB once) ...");
36147
36214
  await downloadFile(VC_REDIST, installer2);
36148
36215
  }
36149
- if (!signedBy(installer2, SIGNERS.microsoft)) {
36216
+ if (!await signedByAsync(installer2, SIGNERS.microsoft)) {
36150
36217
  fs62.rmSync(installer2, { force: true });
36151
36218
  throw new Error("vc_redist.x64.exe is not signed by Microsoft; deleted it (it is downloaded again next boot)");
36152
36219
  }
@@ -36960,7 +37027,9 @@ import path97 from "node:path";
36960
37027
  async function syncSkills(unityExe, agent) {
36961
37028
  const home = agent === "claude" ? { CLAUDE_CONFIG_DIR: claudeDir } : { CODEX_HOME: path97.join(stateDir, "codex") };
36962
37029
  try {
36963
- await execAsync(unityExe, ["skill", "sync", agent], { env: { ...process.env, ...UNITY_CLI_ENV, ...home } });
37030
+ await execAsync(unityExe, ["skill", "sync", agent === "claude" ? "claude-code" : "codex"], {
37031
+ env: { ...process.env, ...UNITY_CLI_ENV, ...home }
37032
+ });
36964
37033
  return true;
36965
37034
  } catch (e) {
36966
37035
  warn("Unity skills for " + agent + " were not synced: " + (e instanceof Error ? e.message : String(e)));
@@ -38180,7 +38249,7 @@ function plan(config2, versions, o) {
38180
38249
 
38181
38250
  // src/guest/toolchains/step-scheduler.ts
38182
38251
  import { AsyncLocalStorage as AsyncLocalStorage4 } from "node:async_hooks";
38183
- var PARALLEL2 = 4;
38252
+ var PARALLEL2 = 3;
38184
38253
  async function runReported(sink2, name, env, work) {
38185
38254
  try {
38186
38255
  await work();
@@ -26069,6 +26069,7 @@ var GAMEDEV_APPS = [
26069
26069
  size: "100 MB",
26070
26070
  source: { github: "f3d-app/f3d", asset: "^F3D-[\\d.]+-Windows-x86_64\\.zip$" },
26071
26071
  exe: "f3d.exe",
26072
+ onPath: true,
26072
26073
  needs: ["mesa"]
26073
26074
  },
26074
26075
  {
@@ -27168,7 +27169,7 @@ var SERVICE_SPECS = {
27168
27169
  },
27169
27170
  steam: {
27170
27171
  kind: "steam",
27171
- label: "Steam (SteamCMD)",
27172
+ label: "Steam",
27172
27173
  usedBy: ["steam"],
27173
27174
  sources: ["file", "sandbox"],
27174
27175
  singleHolder: true,
@@ -27204,7 +27205,7 @@ var SERVICE_SPECS = {
27204
27205
  },
27205
27206
  cfx: {
27206
27207
  kind: "cfx",
27207
- label: "Cfx.re (FiveM / RedM server key)",
27208
+ label: "FiveM key",
27208
27209
  usedBy: ["fivem"],
27209
27210
  sources: ["typed", "file"],
27210
27211
  singleHolder: false,
@@ -27233,7 +27234,7 @@ var SERVICE_SPECS = {
27233
27234
  },
27234
27235
  keystore: {
27235
27236
  kind: "keystore",
27236
- label: "Android upload keystore",
27237
+ label: "Android keystore",
27237
27238
  usedBy: ["android"],
27238
27239
  sources: ["file"],
27239
27240
  singleHolder: false,
@@ -27248,7 +27249,7 @@ var SERVICE_SPECS = {
27248
27249
  },
27249
27250
  play: {
27250
27251
  kind: "play",
27251
- label: "Google Play (service account)",
27252
+ label: "Google Play",
27252
27253
  usedBy: ["android"],
27253
27254
  sources: ["file"],
27254
27255
  singleHolder: false,
@@ -27259,7 +27260,7 @@ var SERVICE_SPECS = {
27259
27260
  },
27260
27261
  expo: {
27261
27262
  kind: "expo",
27262
- label: "Expo (EAS)",
27263
+ label: "Expo",
27263
27264
  usedBy: ["reactNative"],
27264
27265
  sources: ["typed"],
27265
27266
  singleHolder: false,
@@ -27270,7 +27271,7 @@ var SERVICE_SPECS = {
27270
27271
  },
27271
27272
  appstore: {
27272
27273
  kind: "appstore",
27273
- label: "App Store Connect API key",
27274
+ label: "App Store Connect",
27274
27275
  usedBy: ["reactNative", "flutter"],
27275
27276
  sources: ["file", "typed"],
27276
27277
  singleHolder: false,
@@ -27284,7 +27285,7 @@ var SERVICE_SPECS = {
27284
27285
  },
27285
27286
  perplexity: {
27286
27287
  kind: "perplexity",
27287
- label: "Perplexity API key",
27288
+ label: "Perplexity API",
27288
27289
  usedBy: ["perplexity"],
27289
27290
  sources: ["pc", "file", "typed"],
27290
27291
  singleHolder: false,
@@ -27308,7 +27309,7 @@ var SERVICE_SPECS = {
27308
27309
  },
27309
27310
  comet: {
27310
27311
  kind: "comet",
27311
- label: "Comet (Perplexity browser)",
27312
+ label: "Comet",
27312
27313
  usedBy: ["comet"],
27313
27314
  sources: ["sandbox"],
27314
27315
  singleHolder: false,
@@ -27324,7 +27325,7 @@ var SERVICE_SPECS = {
27324
27325
  },
27325
27326
  perplexityapp: {
27326
27327
  kind: "perplexityapp",
27327
- label: "Perplexity desktop app",
27328
+ label: "Perplexity app",
27328
27329
  usedBy: ["perplexityapp"],
27329
27330
  sources: ["sandbox"],
27330
27331
  singleHolder: false,
@@ -28160,10 +28161,20 @@ function scriptArgs(name, args = []) {
28160
28161
  }
28161
28162
 
28162
28163
  // src/shared/download/spawn.ts
28164
+ import os3 from "node:os";
28163
28165
  import { spawn } from "node:child_process";
28166
+ function lowerPriority(pid) {
28167
+ if (pid === void 0) return;
28168
+ try {
28169
+ os3.setPriority(pid, os3.constants.priority.PRIORITY_BELOW_NORMAL);
28170
+ } catch {
28171
+ }
28172
+ }
28164
28173
  function spawnAsync(file2, args, options = {}) {
28174
+ const { lowPriority, ...spawnOptions } = options;
28165
28175
  return new Promise((resolve, reject) => {
28166
- const child = spawn(file2, args, { stdio: "ignore", windowsHide: true, ...options });
28176
+ const child = spawn(file2, args, { stdio: "ignore", windowsHide: true, ...spawnOptions });
28177
+ if (lowPriority) lowerPriority(child.pid);
28167
28178
  child.once("error", reject);
28168
28179
  child.once("close", (code) => resolve(code ?? -1));
28169
28180
  });
@@ -28184,13 +28195,16 @@ function extractArchive(archive, destination, members2 = []) {
28184
28195
  }
28185
28196
  async function extract(archive, destination, members2) {
28186
28197
  fs7.mkdirSync(destination, { recursive: true });
28187
- let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2]);
28198
+ let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2], {
28199
+ lowPriority: true
28200
+ });
28188
28201
  if (status !== 0 && /\.(zip|nupkg)$/i.test(archive)) {
28189
28202
  const zip = archive.endsWith(".zip") ? archive : archive + ".zip";
28190
28203
  if (zip !== archive) fs7.copyFileSync(archive, zip);
28191
28204
  status = await spawnAsync(
28192
28205
  SYSTEM.powershell(),
28193
- scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination])
28206
+ scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination]),
28207
+ { lowPriority: true }
28194
28208
  );
28195
28209
  }
28196
28210
  if (status !== 0) throw new Error("Could not extract " + archive);
@@ -28439,7 +28453,7 @@ import { spawn as spawn4 } from "node:child_process";
28439
28453
 
28440
28454
  // src/guest/runtime/process.ts
28441
28455
  import fs10 from "node:fs";
28442
- import os3 from "node:os";
28456
+ import os4 from "node:os";
28443
28457
  import path12 from "node:path";
28444
28458
  import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
28445
28459
  var outputSink = null;
@@ -28461,13 +28475,15 @@ function logLines(stream) {
28461
28475
  stream.on("end", () => logOutput(partial2));
28462
28476
  }
28463
28477
  async function execAsync(file2, args, options = {}) {
28478
+ const { lowPriority, ...spawnOptions } = options;
28464
28479
  const code = captureOutput() ? await new Promise((resolve, reject) => {
28465
- const child = spawn2(file2, args, { stdio: ["inherit", "pipe", "pipe"], windowsHide: true, ...options });
28480
+ const child = spawn2(file2, args, { stdio: ["inherit", "pipe", "pipe"], windowsHide: true, ...spawnOptions });
28481
+ if (lowPriority) lowerPriority(child.pid);
28466
28482
  logLines(child.stdout);
28467
28483
  logLines(child.stderr);
28468
28484
  child.once("error", reject);
28469
28485
  child.once("close", (c) => resolve(c ?? -1));
28470
- }) : await spawnAsync(file2, args, { stdio: "inherit", ...options });
28486
+ }) : await spawnAsync(file2, args, { stdio: "inherit", ...spawnOptions, ...lowPriority ? { lowPriority } : {} });
28471
28487
  if (code !== 0)
28472
28488
  throw new Error(path12.basename(file2) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + code);
28473
28489
  }
@@ -28492,7 +28508,7 @@ function runScript(name, args = []) {
28492
28508
  throw new Error(name + " failed with exit code " + result.status + (errors ? ": " + errors.slice(0, 400) : ""));
28493
28509
  }
28494
28510
  function runScriptWithJson(name, param, data, args = []) {
28495
- const dir = fs10.mkdtempSync(path12.join(os3.tmpdir(), "sbx-"));
28511
+ const dir = fs10.mkdtempSync(path12.join(os4.tmpdir(), "sbx-"));
28496
28512
  const file2 = path12.join(dir, "input.json");
28497
28513
  try {
28498
28514
  fs10.writeFileSync(file2, JSON.stringify(data), "utf8");