windows-development-sandbox 1.27.1 → 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 (78) 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/registry.d.ts +1 -1
  11. package/dist/app/registry.js +15 -2
  12. package/dist/bin/agent-sandbox.js +2 -2
  13. package/dist/bin/{chunk-QUHNXHVG.js → chunk-4M5SZZ5P.js} +46 -41
  14. package/dist/bin/{chunk-4TLSWPG7.js → chunk-FA5VWLP4.js} +1 -1
  15. package/dist/bin/{chunk-RSIX7C6D.js → chunk-RU7XRN62.js} +249 -101
  16. package/dist/bin/claude-host.js +2 -2
  17. package/dist/bin/claude-sbx.js +2 -2
  18. package/dist/bin/codex-sbx.js +2 -2
  19. package/dist/bin/gemini-sbx.js +2 -2
  20. package/dist/bin/sandbox.js +2 -2
  21. package/dist/bin/sbx-hide.js +2 -2
  22. package/dist/bin/sbx-show.js +2 -2
  23. package/dist/cli/menu/menu.js +6 -1
  24. package/dist/cli/menu/pages/accounts-page.js +9 -5
  25. package/dist/guest/apps/app-installer.js +7 -5
  26. package/dist/guest/apps/comet-unpack.js +2 -2
  27. package/dist/guest/runtime/pools.d.ts +4 -4
  28. package/dist/guest/runtime/pools.js +4 -15
  29. package/dist/guest/runtime/process.d.ts +5 -2
  30. package/dist/guest/runtime/process.js +23 -3
  31. package/dist/guest/toolchains/engines/epic-launcher.d.ts +6 -0
  32. package/dist/guest/toolchains/engines/epic-launcher.js +19 -1
  33. package/dist/guest/toolchains/engines/unreal-engines.js +2 -1
  34. package/dist/guest/toolchains/installers.d.ts +3 -3
  35. package/dist/guest/toolchains/installers.js +5 -5
  36. package/dist/guest/toolchains/native/vcruntime.js +2 -2
  37. package/dist/guest/toolchains/native/vs-persist.d.ts +2 -2
  38. package/dist/guest/toolchains/signature.d.ts +2 -0
  39. package/dist/guest/toolchains/signature.js +9 -2
  40. package/dist/guest/toolchains/step-scheduler.js +1 -1
  41. package/dist/host/accounts/deliver.js +15 -7
  42. package/dist/host/pc-installs/discover.js +5 -2
  43. package/dist/host/pc-installs/unreal.d.ts +3 -1
  44. package/dist/host/pc-installs/unreal.js +27 -1
  45. package/dist/runtime/agent.js +34 -22
  46. package/dist/runtime/daemon.js +96 -51
  47. package/dist/runtime/db.js +32 -16
  48. package/dist/runtime/main.js +98 -53
  49. package/dist/runtime/netproxy.js +26 -12
  50. package/dist/runtime/tool.js +32 -15
  51. package/dist/runtime/view.js +26 -12
  52. package/dist/selftest/app.test.js +20 -2
  53. package/dist/selftest/boot-runner.test.js +15 -1
  54. package/dist/selftest/engines.test.js +22 -1
  55. package/dist/selftest/menu-screens.js +52 -1
  56. package/dist/selftest/menu.test.js +29 -3
  57. package/dist/selftest/service-accounts.test.js +77 -2
  58. package/dist/selftest/ui-text.test.js +4 -0
  59. package/dist/shared/accounts/kinds.js +9 -9
  60. package/dist/shared/apps/catalogue-gamedev.js +1 -0
  61. package/dist/shared/apps/catalogue.d.ts +2 -0
  62. package/dist/shared/concurrency/pools.js +1 -1
  63. package/dist/shared/download/archive.js +4 -2
  64. package/dist/shared/download/index.d.ts +1 -1
  65. package/dist/shared/download/index.js +1 -1
  66. package/dist/shared/download/spawn.d.ts +7 -1
  67. package/dist/shared/download/spawn.js +16 -1
  68. package/dist/shared/paths/pc-installs.d.ts +8 -0
  69. package/dist/shared/unreal/launcher-files.d.ts +7 -0
  70. package/dist/shared/unreal/launcher-files.js +32 -1
  71. package/dist/web/index.html +1 -1
  72. package/dist/web/{main-VPMYTSUL.js → main-NKM7ECSB.js} +59 -59
  73. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  74. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  75. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  76. package/package.json +1 -1
  77. package/schemas/config.schema.json +9 -9
  78. package/schemas/sandbox-config.schema.json +9 -9
@@ -22806,10 +22806,10 @@ var esm_default2 = createPrompt((config3, done) => {
22806
22806
  const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
22807
22807
  return [prefix, message, answer].filter(Boolean).join(" ");
22808
22808
  }
22809
- let helpLine;
22809
+ let helpLine2;
22810
22810
  if (theme.helpMode !== "never" && instructions !== false) {
22811
22811
  if (typeof instructions === "string") {
22812
- helpLine = instructions;
22812
+ helpLine2 = instructions;
22813
22813
  } else {
22814
22814
  const keys = [
22815
22815
  ["\u2191\u2193", "navigate"],
@@ -22820,7 +22820,7 @@ var esm_default2 = createPrompt((config3, done) => {
22820
22820
  if (shortcuts.invert)
22821
22821
  keys.push([shortcuts.invert, "invert"]);
22822
22822
  keys.push(["\u23CE", "submit"]);
22823
- helpLine = theme.style.keysHelpTip(keys);
22823
+ helpLine2 = theme.style.keysHelpTip(keys);
22824
22824
  }
22825
22825
  }
22826
22826
  const lines = [
@@ -22829,7 +22829,7 @@ var esm_default2 = createPrompt((config3, done) => {
22829
22829
  " ",
22830
22830
  description ? theme.style.description(description) : "",
22831
22831
  errorMsg ? theme.style.error(errorMsg) : "",
22832
- helpLine
22832
+ helpLine2
22833
22833
  ].filter(Boolean).join("\n").trimEnd();
22834
22834
  return `${lines}${cursorHide}`;
22835
22835
  });
@@ -23687,13 +23687,13 @@ var esm_default10 = createPrompt((config3, done) => {
23687
23687
  }
23688
23688
  });
23689
23689
  const message = theme.style.message(config3.message, status);
23690
- let helpLine;
23690
+ let helpLine2;
23691
23691
  if (theme.helpMode !== "never") {
23692
23692
  if (config3.instructions) {
23693
23693
  const { pager, navigation } = config3.instructions;
23694
- helpLine = theme.style.help(searchResults.length > pageSize ? pager : navigation);
23694
+ helpLine2 = theme.style.help(searchResults.length > pageSize ? pager : navigation);
23695
23695
  } else {
23696
- helpLine = theme.style.keysHelpTip([
23696
+ helpLine2 = theme.style.keysHelpTip([
23697
23697
  ["\u2191\u2193", "navigate"],
23698
23698
  ["\u23CE", "select"]
23699
23699
  ]);
@@ -23735,7 +23735,7 @@ var esm_default10 = createPrompt((config3, done) => {
23735
23735
  error62 ?? page,
23736
23736
  " ",
23737
23737
  description ? theme.style.description(description) : "",
23738
- helpLine
23738
+ helpLine2
23739
23739
  ].filter(Boolean).join("\n").trimEnd();
23740
23740
  return [header, body];
23741
23741
  });
@@ -23857,13 +23857,13 @@ var esm_default11 = createPrompt((config3, done) => {
23857
23857
  clearTimeout(searchTimeoutRef.current);
23858
23858
  }, []);
23859
23859
  const message = theme.style.message(config3.message, status);
23860
- let helpLine;
23860
+ let helpLine2;
23861
23861
  if (theme.helpMode !== "never") {
23862
23862
  if (config3.instructions) {
23863
23863
  const { pager, navigation } = config3.instructions;
23864
- helpLine = theme.style.help(items.length > pageSize ? pager : navigation);
23864
+ helpLine2 = theme.style.help(items.length > pageSize ? pager : navigation);
23865
23865
  } else {
23866
- helpLine = theme.style.keysHelpTip([
23866
+ helpLine2 = theme.style.keysHelpTip([
23867
23867
  ["\u2191\u2193", "navigate"],
23868
23868
  ["\u23CE", "select"]
23869
23869
  ]);
@@ -23899,7 +23899,7 @@ var esm_default11 = createPrompt((config3, done) => {
23899
23899
  page,
23900
23900
  " ",
23901
23901
  description ? theme.style.description(description) : "",
23902
- helpLine
23902
+ helpLine2
23903
23903
  ].filter(Boolean).join("\n").trimEnd();
23904
23904
  return `${lines}${cursorHide}`;
23905
23905
  });
@@ -46814,6 +46814,7 @@ var GAMEDEV_APPS = [
46814
46814
  size: "100 MB",
46815
46815
  source: { github: "f3d-app/f3d", asset: "^F3D-[\\d.]+-Windows-x86_64\\.zip$" },
46816
46816
  exe: "f3d.exe",
46817
+ onPath: true,
46817
46818
  needs: ["mesa"]
46818
46819
  },
46819
46820
  {
@@ -47961,7 +47962,7 @@ var SERVICE_SPECS = {
47961
47962
  },
47962
47963
  steam: {
47963
47964
  kind: "steam",
47964
- label: "Steam (SteamCMD)",
47965
+ label: "Steam",
47965
47966
  usedBy: ["steam"],
47966
47967
  sources: ["file", "sandbox"],
47967
47968
  singleHolder: true,
@@ -47997,7 +47998,7 @@ var SERVICE_SPECS = {
47997
47998
  },
47998
47999
  cfx: {
47999
48000
  kind: "cfx",
48000
- label: "Cfx.re (FiveM / RedM server key)",
48001
+ label: "FiveM key",
48001
48002
  usedBy: ["fivem"],
48002
48003
  sources: ["typed", "file"],
48003
48004
  singleHolder: false,
@@ -48026,7 +48027,7 @@ var SERVICE_SPECS = {
48026
48027
  },
48027
48028
  keystore: {
48028
48029
  kind: "keystore",
48029
- label: "Android upload keystore",
48030
+ label: "Android keystore",
48030
48031
  usedBy: ["android"],
48031
48032
  sources: ["file"],
48032
48033
  singleHolder: false,
@@ -48041,7 +48042,7 @@ var SERVICE_SPECS = {
48041
48042
  },
48042
48043
  play: {
48043
48044
  kind: "play",
48044
- label: "Google Play (service account)",
48045
+ label: "Google Play",
48045
48046
  usedBy: ["android"],
48046
48047
  sources: ["file"],
48047
48048
  singleHolder: false,
@@ -48052,7 +48053,7 @@ var SERVICE_SPECS = {
48052
48053
  },
48053
48054
  expo: {
48054
48055
  kind: "expo",
48055
- label: "Expo (EAS)",
48056
+ label: "Expo",
48056
48057
  usedBy: ["reactNative"],
48057
48058
  sources: ["typed"],
48058
48059
  singleHolder: false,
@@ -48063,7 +48064,7 @@ var SERVICE_SPECS = {
48063
48064
  },
48064
48065
  appstore: {
48065
48066
  kind: "appstore",
48066
- label: "App Store Connect API key",
48067
+ label: "App Store Connect",
48067
48068
  usedBy: ["reactNative", "flutter"],
48068
48069
  sources: ["file", "typed"],
48069
48070
  singleHolder: false,
@@ -48077,7 +48078,7 @@ var SERVICE_SPECS = {
48077
48078
  },
48078
48079
  perplexity: {
48079
48080
  kind: "perplexity",
48080
- label: "Perplexity API key",
48081
+ label: "Perplexity API",
48081
48082
  usedBy: ["perplexity"],
48082
48083
  sources: ["pc", "file", "typed"],
48083
48084
  singleHolder: false,
@@ -48101,7 +48102,7 @@ var SERVICE_SPECS = {
48101
48102
  },
48102
48103
  comet: {
48103
48104
  kind: "comet",
48104
- label: "Comet (Perplexity browser)",
48105
+ label: "Comet",
48105
48106
  usedBy: ["comet"],
48106
48107
  sources: ["sandbox"],
48107
48108
  singleHolder: false,
@@ -48117,7 +48118,7 @@ var SERVICE_SPECS = {
48117
48118
  },
48118
48119
  perplexityapp: {
48119
48120
  kind: "perplexityapp",
48120
- label: "Perplexity desktop app",
48121
+ label: "Perplexity app",
48121
48122
  usedBy: ["perplexityapp"],
48122
48123
  sources: ["sandbox"],
48123
48124
  singleHolder: false,
@@ -56560,7 +56561,7 @@ function clearLiveRecord(storageRoot, dataPath) {
56560
56561
  import fs71 from "node:fs";
56561
56562
  import path94 from "node:path";
56562
56563
  import crypto14 from "node:crypto";
56563
- import os16 from "node:os";
56564
+ import os17 from "node:os";
56564
56565
 
56565
56566
  // src/shared/accounts/fingerprint.ts
56566
56567
  import crypto8 from "node:crypto";
@@ -58861,10 +58862,20 @@ function scriptArgs(name2, args = []) {
58861
58862
  }
58862
58863
 
58863
58864
  // src/shared/download/spawn.ts
58865
+ import os14 from "node:os";
58864
58866
  import { spawn as spawn9 } from "node:child_process";
58867
+ function lowerPriority(pid) {
58868
+ if (pid === void 0) return;
58869
+ try {
58870
+ os14.setPriority(pid, os14.constants.priority.PRIORITY_BELOW_NORMAL);
58871
+ } catch {
58872
+ }
58873
+ }
58865
58874
  function spawnAsync(file2, args, options = {}) {
58875
+ const { lowPriority, ...spawnOptions } = options;
58866
58876
  return new Promise((resolve, reject) => {
58867
- const child = spawn9(file2, args, { stdio: "ignore", windowsHide: true, ...options });
58877
+ const child = spawn9(file2, args, { stdio: "ignore", windowsHide: true, ...spawnOptions });
58878
+ if (lowPriority) lowerPriority(child.pid);
58868
58879
  child.once("error", reject);
58869
58880
  child.once("close", (code) => resolve(code ?? -1));
58870
58881
  });
@@ -58885,13 +58896,16 @@ function extractArchive(archive, destination, members2 = []) {
58885
58896
  }
58886
58897
  async function extract(archive, destination, members2) {
58887
58898
  fs57.mkdirSync(destination, { recursive: true });
58888
- let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2]);
58899
+ let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2], {
58900
+ lowPriority: true
58901
+ });
58889
58902
  if (status !== 0 && /\.(zip|nupkg)$/i.test(archive)) {
58890
58903
  const zip = archive.endsWith(".zip") ? archive : archive + ".zip";
58891
58904
  if (zip !== archive) fs57.copyFileSync(archive, zip);
58892
58905
  status = await spawnAsync(
58893
58906
  SYSTEM.powershell(),
58894
- scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination])
58907
+ scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination]),
58908
+ { lowPriority: true }
58895
58909
  );
58896
58910
  }
58897
58911
  if (status !== 0) throw new Error("Could not extract " + archive);
@@ -59789,10 +59803,10 @@ function pcHasPwsh(env = process.env, exists2 = fs60.existsSync) {
59789
59803
 
59790
59804
  // src/host/launch/pc-scan.ts
59791
59805
  import fs61 from "node:fs";
59792
- import os14 from "node:os";
59806
+ import os15 from "node:os";
59793
59807
  import path84 from "node:path";
59794
59808
  function msvcRust() {
59795
- const settings = path84.join(process.env.RUSTUP_HOME ?? path84.join(os14.homedir(), ".rustup"), "settings.toml");
59809
+ const settings = path84.join(process.env.RUSTUP_HOME ?? path84.join(os15.homedir(), ".rustup"), "settings.toml");
59796
59810
  try {
59797
59811
  return /default_host_triple\s*=\s*"[^"]*-msvc"/.test(fs61.readFileSync(settings, "utf8").slice(0, 64 * 1024));
59798
59812
  } catch {
@@ -59959,7 +59973,7 @@ function databasePlanner(config3, compose2) {
59959
59973
  import path89 from "node:path";
59960
59974
 
59961
59975
  // src/host/launch/wsb-file.ts
59962
- import os15 from "node:os";
59976
+ import os16 from "node:os";
59963
59977
  var GUEST = {
59964
59978
  launch: "C:\\AgentLaunch",
59965
59979
  data: "C:\\AgentData",
@@ -60002,7 +60016,7 @@ function memoryNote(decision) {
60002
60016
  if (decision.limitedBy !== "commit" || decision.withoutCommitMb - decision.mb < 2048) return null;
60003
60017
  return "The sandbox gets " + decision.mb / 1024 + " GB of memory instead of " + decision.withoutCommitMb / 1024 + " GB: this PC has only " + Math.floor((decision.commitAvailableMb ?? 0) / 1024) + " GB of memory (RAM plus paging file) left to hand out, and if it runs out Windows closes the sandbox. A bigger Windows paging file, or closing other programs, gives it more.";
60004
60018
  }
60005
- function resolveMemoryMb(sandbox, freeMemoryBytes = os15.freemem(), totalMemoryBytes = os15.totalmem(), commitAvailableMb = null) {
60019
+ function resolveMemoryMb(sandbox, freeMemoryBytes = os16.freemem(), totalMemoryBytes = os16.totalmem(), commitAvailableMb = null) {
60006
60020
  if (sandbox.memoryMb !== "auto") return sandbox.memoryMb;
60007
60021
  const decision = decideMemory(
60008
60022
  sandbox,
@@ -60915,7 +60929,7 @@ function generateSandbox(given, opened) {
60915
60929
  resolveMemoryMb(config3.sandbox, o.freeMemoryBytes, void 0, commitAvailableMb),
60916
60930
  ...others.map((p) => typeof p.config.sandbox.memoryMb === "number" ? p.config.sandbox.memoryMb : 0)
60917
60931
  );
60918
- const memoryMb = cappedMemoryMb(askedMb, config3.sandbox, Math.floor(os16.totalmem() / 1048576));
60932
+ const memoryMb = cappedMemoryMb(askedMb, config3.sandbox, Math.floor(os17.totalmem() / 1048576));
60919
60933
  const launchId = o.launchId ?? newLaunchId();
60920
60934
  const launchPath = path94.join(storageRoot, "launches", launchId);
60921
60935
  ensureDir(dataPath);
@@ -60988,8 +61002,8 @@ function generateSandbox(given, opened) {
60988
61002
  memoryNote: residentNote(askedMb, memoryMb) ?? (config3.sandbox.memoryMb === "auto" ? memoryNote(
60989
61003
  decideMemory(
60990
61004
  config3.sandbox,
60991
- Math.floor((o.freeMemoryBytes ?? os16.freemem()) / 1048576),
60992
- Math.floor(os16.totalmem() / 1048576),
61005
+ Math.floor((o.freeMemoryBytes ?? os17.freemem()) / 1048576),
61006
+ Math.floor(os17.totalmem() / 1048576),
60993
61007
  commitAvailableMb
60994
61008
  )
60995
61009
  ) : null),
@@ -62927,16 +62941,19 @@ function howToSave(spec) {
62927
62941
  if (spec.returns) return "sign in once in this sandbox, or: sandbox account import " + spec.kind;
62928
62942
  return spec.sources.includes("typed") ? "save one: sandbox account login " + spec.kind : "save one: sandbox account import " + spec.kind + " --from <file>";
62929
62943
  }
62930
- function takeFromPc(kind, pc, store) {
62944
+ function takeFromPc(kind, pc, store, saved) {
62931
62945
  const source = HOST_SOURCES[kind];
62932
- if (!pc || !source.fromPc) return null;
62946
+ if (!pc || !source.fromPc) return saved;
62947
+ if (saved && store.info(kind)?.source !== "pc") return saved;
62933
62948
  let payload = null;
62934
62949
  try {
62935
62950
  payload = source.fromPc(pc);
62936
62951
  } catch {
62937
- return null;
62952
+ return saved;
62938
62953
  }
62939
- if (payload) store.save(kind, payload, "pc", source.summary(payload));
62954
+ if (!payload) return saved;
62955
+ if (!saved || fingerprint(payload) !== fingerprint(saved))
62956
+ store.save(kind, payload, "pc", source.summary(payload));
62940
62957
  return payload;
62941
62958
  }
62942
62959
  function prepareServiceAccounts(i) {
@@ -62968,7 +62985,7 @@ function prepareServiceAccounts(i) {
62968
62985
  } catch {
62969
62986
  unreadable = true;
62970
62987
  }
62971
- if (!payload && !unreadable) payload = takeFromPc(kind, i.pc, store);
62988
+ if (!unreadable) payload = takeFromPc(kind, i.pc, store, payload);
62972
62989
  if (spec.singleHolder) {
62973
62990
  const claim2 = leases.claim(kind, dataSet, i.launchId, payload ? fingerprint(payload) : null, i.isRunning);
62974
62991
  if (!claim2.ok) {
@@ -63178,9 +63195,6 @@ async function prepareStorePackages(apps, o) {
63178
63195
  return { notes };
63179
63196
  }
63180
63197
 
63181
- // src/host/pc-installs/epic.ts
63182
- import path117 from "node:path";
63183
-
63184
63198
  // src/shared/unreal/engines.ts
63185
63199
  import path113 from "node:path";
63186
63200
  var win = path113.win32;
@@ -63226,6 +63240,9 @@ var stripBom2 = (text) => text.replace(/^\uFEFF/, "");
63226
63240
  function launcherInstalledFile(programData) {
63227
63241
  return win2.join(programData, "Epic", "UnrealEngineLauncher", "LauncherInstalled.dat");
63228
63242
  }
63243
+ function launcherManifestsDir(programData) {
63244
+ return win2.join(programData, "Epic", "EpicGamesLauncher", "Data", "Manifests");
63245
+ }
63229
63246
  var EntrySchema = external_exports.looseObject({
63230
63247
  InstallLocation: external_exports.string().max(1024),
63231
63248
  AppName: external_exports.string().max(200),
@@ -63261,6 +63278,41 @@ var ItemSchema = external_exports.looseObject({
63261
63278
  InstallSize: external_exports.number().int().min(0).optional(),
63262
63279
  bIsIncompleteInstall: external_exports.boolean().optional()
63263
63280
  });
63281
+ function itemInstallLocation(text) {
63282
+ return itemInfo(text)?.installLocation ?? null;
63283
+ }
63284
+ function itemInfo(text) {
63285
+ try {
63286
+ const item = ItemSchema.parse(JSON.parse(stripBom2(text)));
63287
+ const at = item.InstallLocation;
63288
+ return at && win2.isAbsolute(at) ? { installLocation: at, sizeBytes: item.InstallSize ?? null } : null;
63289
+ } catch {
63290
+ return null;
63291
+ }
63292
+ }
63293
+ var ITEM_NAME = /^[A-Za-z0-9_-]{1,80}\.item$/;
63294
+ function relocateItem(text, from, to) {
63295
+ let item;
63296
+ try {
63297
+ item = JSON.parse(stripBom2(text));
63298
+ } catch {
63299
+ return null;
63300
+ }
63301
+ if (!item || typeof item !== "object" || Array.isArray(item)) return null;
63302
+ const base = win2.resolve(from).toLowerCase();
63303
+ const out = {};
63304
+ for (const [key3, value] of Object.entries(item)) {
63305
+ if (typeof value !== "string" || !win2.isAbsolute(value)) {
63306
+ out[key3] = value;
63307
+ continue;
63308
+ }
63309
+ const full = win2.resolve(value);
63310
+ const low = full.toLowerCase();
63311
+ if (low === base || low.startsWith(base + "\\")) out[key3] = to + full.slice(base.length);
63312
+ }
63313
+ const at = typeof out.InstallLocation === "string" ? out.InstallLocation : "";
63314
+ return at.toLowerCase() === to.toLowerCase() ? JSON.stringify(out, null, " ") : null;
63315
+ }
63264
63316
 
63265
63317
  // src/shared/unreal/status.ts
63266
63318
  var UNREAL_STATUS_FILE = "status.json";
@@ -63404,6 +63456,7 @@ function vaultPacks(vault, fs141) {
63404
63456
  }
63405
63457
 
63406
63458
  // src/host/pc-installs/epic.ts
63459
+ import path117 from "node:path";
63407
63460
  var APP = /^[A-Za-z0-9._-]{1,100}$/;
63408
63461
  function findEpicGames(text, wanted) {
63409
63462
  const names = wanted === true ? null : new Set(wanted.map((w) => String(w).toLowerCase()));
@@ -63925,6 +63978,25 @@ var versionOf = (dir, files) => {
63925
63978
  const bytes = files.read(win9.join(dir, "Engine", "Build", "Build.version"), 64 * 1024);
63926
63979
  return bytes ? parseBuildVersion(bytes.toString("utf8")) : null;
63927
63980
  };
63981
+ var MAX_ITEM_BYTES2 = 64 * 1024;
63982
+ function launcherItemOf(dir, files) {
63983
+ if (!files.manifests) return {};
63984
+ const want = win9.resolve(dir).toLowerCase();
63985
+ for (const name2 of files.list(files.manifests).filter((n) => ITEM_NAME.test(n))) {
63986
+ const bytes = files.read(win9.join(files.manifests, name2), MAX_ITEM_BYTES2);
63987
+ const at = bytes ? itemInstallLocation(bytes.toString("utf8")) : null;
63988
+ if (bytes && at && win9.resolve(at).toLowerCase() === want)
63989
+ return { launcherItem: { name: name2, text: bytes.toString("utf8") } };
63990
+ }
63991
+ return {};
63992
+ }
63993
+ function launcherIdsOf(dir, files) {
63994
+ const want = win9.resolve(dir).toLowerCase();
63995
+ const entry = (files.launcherInstalled ? launcherInstallations(files.launcherInstalled) : []).find(
63996
+ (i) => APP_NAME.test(i.appName) && i.ids && win9.resolve(i.installLocation).toLowerCase() === want
63997
+ );
63998
+ return entry?.ids ? { launcher: entry.ids } : {};
63999
+ }
63928
64000
  var isWanted = (wanted, v) => wanted === true || wanted.map((w) => String(w).replace(/^UE_/i, "")).includes(v.major + "." + v.minor);
63929
64001
  function findUnrealInstalls(files, wanted) {
63930
64002
  const found = [];
@@ -63944,7 +64016,8 @@ function findUnrealInstalls(files, wanted) {
63944
64016
  version: versionText(v),
63945
64017
  host: win9.normalize(dir),
63946
64018
  guest: "",
63947
- ...ids ? { launcher: ids } : {}
64019
+ ...ids ? { launcher: ids } : {},
64020
+ ...launcherItemOf(dir, files)
63948
64021
  });
63949
64022
  };
63950
64023
  const listed = files.launcherInstalled ? launcherInstallations(files.launcherInstalled) : [];
@@ -63989,7 +64062,10 @@ function findEngineFolders(files, folders) {
63989
64062
  host: dir,
63990
64063
  guest: "",
63991
64064
  writable: true,
63992
- ...source ? { buildId: source.buildId } : {}
64065
+ ...source ? { buildId: source.buildId } : {},
64066
+ // An engine the launcher installed keeps its ids and manifest, so the sandbox's launcher lists it too.
64067
+ ...launcherIdsOf(dir, { launcherInstalled: files.launcherInstalled ?? null }),
64068
+ ...files.list ? launcherItemOf(dir, { manifests: files.manifests, list: files.list, read: files.read }) : {}
63993
64069
  });
63994
64070
  }
63995
64071
  return found;
@@ -64017,6 +64093,7 @@ function unrealPcFiles(pc) {
64017
64093
  win9.join(d, "Program Files", "Epic Games"),
64018
64094
  win9.join(d, "Epic Games")
64019
64095
  ]),
64096
+ manifests: launcherManifestsDir(pc.programData),
64020
64097
  list: listDir2,
64021
64098
  read: readBoundedFile
64022
64099
  };
@@ -64155,8 +64232,9 @@ function discoverPcInstalls(s3, o, pc = pcEnv()) {
64155
64232
  readOnly: !writable,
64156
64233
  label: writable ? "this PC, writable" : "this PC, read-only"
64157
64234
  });
64158
- const { host: _host, ...shown } = install;
64159
- items.push({ ...shown, guest });
64235
+ const { host: _host, launcherItem, ...shown } = install;
64236
+ const moved = launcherItem ? relocateItem(launcherItem.text, install.host, guest) : null;
64237
+ items.push({ ...shown, guest, ...moved ? { launcherItem: { name: launcherItem.name, text: moved } } : {} });
64160
64238
  } catch (e) {
64161
64239
  notes.push("pcInstalls: " + install.name + " is not mapped: " + errMsg(e));
64162
64240
  }
@@ -64866,7 +64944,7 @@ var SandboxChannel = class {
64866
64944
 
64867
64945
  // src/host/channel/attach.ts
64868
64946
  import net4 from "node:net";
64869
- import os17 from "node:os";
64947
+ import os18 from "node:os";
64870
64948
 
64871
64949
  // src/shared/pty/protocol.ts
64872
64950
  var FrameType = {
@@ -65512,7 +65590,7 @@ function runTerminalClient(socket, token, options = {}) {
65512
65590
 
65513
65591
  // src/host/channel/attach.ts
65514
65592
  var ipToInt = (ip) => ip.split(".").reduce((n, part) => n * 256 + Number(part), 0);
65515
- function isSandboxAddress(ip, interfaces = os17.networkInterfaces()) {
65593
+ function isSandboxAddress(ip, interfaces = os18.networkInterfaces()) {
65516
65594
  if (!net4.isIPv4(ip)) return false;
65517
65595
  return Object.entries(interfaces).some(
65518
65596
  ([name2, list2]) => /^vEthernet/i.test(name2) && !/WSL/i.test(name2) && (list2 ?? []).some((i) => {
@@ -66353,7 +66431,7 @@ var AuditCollector = class {
66353
66431
  };
66354
66432
 
66355
66433
  // src/sync/watcher.ts
66356
- import os18 from "node:os";
66434
+ import os19 from "node:os";
66357
66435
  var WATCH_INTERVAL_MS = 60 * 1e3;
66358
66436
  var FIRST_SYNC_MS = 3e4;
66359
66437
  var AUDIT_FLUSH_MS = 1e4;
@@ -66412,7 +66490,7 @@ var Watcher = class {
66412
66490
  memoryStream = null;
66413
66491
  watchdog = WATCHDOG_START;
66414
66492
  watchdogBusy = false;
66415
- lastCpu = os18.cpus();
66493
+ lastCpu = os19.cpus();
66416
66494
  lastHostLog = 0;
66417
66495
  /** Runs until the sandbox has closed and the final sync is done (or the end deadline passed). */
66418
66496
  async run() {
@@ -66532,7 +66610,7 @@ var Watcher = class {
66532
66610
  try {
66533
66611
  const settings = readLoadSettings(this.storageRoot, this.dataPath);
66534
66612
  const memory = this.memoryStream?.latest() ?? await readHostMemoryAsync(this.storageRoot);
66535
- const cpus = os18.cpus();
66613
+ const cpus = os19.cpus();
66536
66614
  const cpuPercent = cpuPercentBetween(this.lastCpu, cpus);
66537
66615
  this.lastCpu = cpus;
66538
66616
  const nowMs = Date.now();
@@ -69257,7 +69335,7 @@ function continuesAfterFailedMigration(command2) {
69257
69335
 
69258
69336
  // src/cli/services/update-service.ts
69259
69337
  import fs112 from "node:fs";
69260
- import os19 from "node:os";
69338
+ import os20 from "node:os";
69261
69339
  import path156 from "node:path";
69262
69340
 
69263
69341
  // src/host/update/release-source.ts
@@ -69692,7 +69770,7 @@ var Updater = class {
69692
69770
  var NPM_UPDATE_COMMAND = "npm install -g windows-development-sandbox";
69693
69771
  var AUTO_CHECK_HOURS = 24;
69694
69772
  var SeenSchema = external_exports.object({ seen: external_exports.string() });
69695
- function runsAsSystem(env = process.env, username = os19.userInfo().username) {
69773
+ function runsAsSystem(env = process.env, username = os20.userInfo().username) {
69696
69774
  return username.toUpperCase() === "SYSTEM" || (env.USERNAME ?? "").endsWith("$");
69697
69775
  }
69698
69776
  var UpdateService = class _UpdateService {
@@ -70315,7 +70393,7 @@ import { spawnSync as spawnSync29 } from "node:child_process";
70315
70393
 
70316
70394
  // src/cli/commands/setup/facts.ts
70317
70395
  var import_lodash27 = __toESM(require_lodash(), 1);
70318
- import os20 from "node:os";
70396
+ import os21 from "node:os";
70319
70397
  var FEATURE = "Containers-DisposableClientVM";
70320
70398
  var ENABLE_COMMAND = "Enable-WindowsOptionalFeature -Online -FeatureName " + FEATURE + " -All -NoRestart";
70321
70399
  function parseRegQuery(text) {
@@ -70363,7 +70441,7 @@ function gatherFacts(storageRoot) {
70363
70441
  sandboxExe: fileExists(system32("WindowsSandbox.exe")),
70364
70442
  virtualizationFirmware: probe.virtualizationFirmware ?? null,
70365
70443
  hypervisorPresent: probe.hypervisorPresent ?? null,
70366
- totalRamBytes: os20.totalmem(),
70444
+ totalRamBytes: os21.totalmem(),
70367
70445
  freeDiskBytes: freeBytesAt(storageRoot),
70368
70446
  storageRoot,
70369
70447
  nodeVersion: process.version
@@ -71381,6 +71459,12 @@ import path162 from "node:path";
71381
71459
 
71382
71460
  // src/app/context.ts
71383
71461
  var implement = implementer();
71462
+ function reloadSettings(ctx) {
71463
+ try {
71464
+ ctx.loaded = loadConfig(ctx.loaded.configPath ?? ctx.options.config);
71465
+ } catch {
71466
+ }
71467
+ }
71384
71468
  function typedConfirm(io) {
71385
71469
  return (prompt, expected) => io.confirm({
71386
71470
  title: prompt,
@@ -73088,13 +73172,13 @@ function fingerprintOf(der) {
73088
73172
  // src/host/remote/firewall.ts
73089
73173
  import crypto22 from "node:crypto";
73090
73174
  import fs119 from "node:fs";
73091
- import os22 from "node:os";
73175
+ import os23 from "node:os";
73092
73176
  import path168 from "node:path";
73093
73177
  import { spawn as spawn13 } from "node:child_process";
73094
73178
 
73095
73179
  // src/host/remote/lan.ts
73096
73180
  import net7 from "node:net";
73097
- import os21 from "node:os";
73181
+ import os22 from "node:os";
73098
73182
  var toInt = (ip) => ip.split(".").reduce((n, part) => n * 256 + Number(part), 0) >>> 0;
73099
73183
  function isPrivateIPv4(ip) {
73100
73184
  if (!net7.isIPv4(ip)) return false;
@@ -73111,7 +73195,7 @@ function plainIPv4(ip) {
73111
73195
  function virtualAdapter(name2) {
73112
73196
  return /^vEthernet/i.test(name2) || /Hyper-V|WSL/i.test(name2);
73113
73197
  }
73114
- function privateAddresses(interfaces = os21.networkInterfaces()) {
73198
+ function privateAddresses(interfaces = os22.networkInterfaces()) {
73115
73199
  const out = [];
73116
73200
  for (const [adapter, list2] of Object.entries(interfaces)) {
73117
73201
  if (virtualAdapter(adapter)) continue;
@@ -73121,7 +73205,7 @@ function privateAddresses(interfaces = os21.networkInterfaces()) {
73121
73205
  }
73122
73206
  return out;
73123
73207
  }
73124
- function chooseLanAddress(configured, interfaces = os21.networkInterfaces()) {
73208
+ function chooseLanAddress(configured, interfaces = os22.networkInterfaces()) {
73125
73209
  const own2 = privateAddresses(interfaces);
73126
73210
  if (configured) {
73127
73211
  if (!isPrivateIPv4(configured))
@@ -73149,7 +73233,7 @@ function sameSubnet(a, b, netmask) {
73149
73233
  const mask = toInt(netmask);
73150
73234
  return mask !== 0 && (toInt(a) & mask) === (toInt(b) & mask);
73151
73235
  }
73152
- function lanPeerProblem(peer, local, bound, interfaces = os21.networkInterfaces()) {
73236
+ function lanPeerProblem(peer, local, bound, interfaces = os22.networkInterfaces()) {
73153
73237
  const ip = plainIPv4(peer);
73154
73238
  if (plainIPv4(local) !== bound.address) return "reached another address of this PC";
73155
73239
  if (!isPrivateIPv4(ip)) return "not a private address";
@@ -73200,7 +73284,7 @@ var OutcomeSchema3 = external_exports.object({
73200
73284
  commands: external_exports.array(external_exports.string().max(1e3)).max(4).optional()
73201
73285
  });
73202
73286
  async function runScript2(request2, dryRun, run3) {
73203
- const dir = fs119.mkdtempSync(path168.join(os22.tmpdir(), "agent-sandbox-firewall-"));
73287
+ const dir = fs119.mkdtempSync(path168.join(os23.tmpdir(), "agent-sandbox-firewall-"));
73204
73288
  try {
73205
73289
  const file2 = path168.join(dir, "request.json");
73206
73290
  fs119.writeFileSync(file2, JSON.stringify(request2, null, 2), "utf8");
@@ -74793,7 +74877,7 @@ var RemoteGate = class {
74793
74877
  };
74794
74878
 
74795
74879
  // src/host/remote/tls-store.ts
74796
- import os23 from "node:os";
74880
+ import os24 from "node:os";
74797
74881
  import path171 from "node:path";
74798
74882
  var TlsFileSchema = external_exports.strictObject({
74799
74883
  cert: external_exports.string().max(8e3),
@@ -74835,7 +74919,7 @@ var TlsStore = class {
74835
74919
  }
74836
74920
  /** A new certificate (the old one is gone). */
74837
74921
  renew(addresses) {
74838
- const made = makeCertificate({ addresses, dnsNames: [os23.hostname()], now: this.now() });
74922
+ const made = makeCertificate({ addresses, dnsNames: [os24.hostname()], now: this.now() });
74839
74923
  this.file.write({
74840
74924
  cert: made.cert,
74841
74925
  key: this.secrets.seal(made.key),
@@ -76331,12 +76415,16 @@ var ServiceRowSchema = external_exports.object({
76331
76415
  canImport: external_exports.boolean().describe("It can be taken from this PC or a file (sandbox account import)"),
76332
76416
  canLogin: external_exports.boolean().describe("It can be typed (sandbox account login)"),
76333
76417
  needsFile: external_exports.boolean().describe("Importing it needs --from <file>"),
76418
+ fromPc: external_exports.boolean().describe("This PC's own program can give it (the next launch takes it when sharing is on)"),
76419
+ hasFileSource: external_exports.boolean().describe("It can be read from a file you name"),
76420
+ onPc: external_exports.boolean().nullable().describe("This PC has one to take (null: it cannot be taken from this PC). Only the presence, never the sign-in"),
76421
+ sandboxOnly: external_exports.boolean().describe("Only a sandbox can give it: sign in once inside one and it is kept"),
76334
76422
  ready: external_exports.boolean().describe("Its sign-in is written; false: the menu and the web leave it out (the CLI says coming)")
76335
76423
  });
76336
76424
  var ServicesListSchema = external_exports.object({ services: external_exports.array(ServiceRowSchema) });
76337
76425
  var STATE_TEXT = {
76338
76426
  none: "not saved",
76339
- saved: "saved (encrypted)",
76427
+ saved: "saved",
76340
76428
  unreadable: "cannot be read"
76341
76429
  };
76342
76430
  var STATE_TONE = {
@@ -76345,10 +76433,10 @@ var STATE_TONE = {
76345
76433
  unreadable: "danger"
76346
76434
  };
76347
76435
  var SOURCE_TEXT = {
76348
- pc: "taken from this PC",
76436
+ pc: "from this PC",
76349
76437
  file: "from a file",
76350
- typed: "typed in",
76351
- sandbox: "signed in (or renewed) in a sandbox"
76438
+ typed: "by typing it",
76439
+ sandbox: "from a sandbox"
76352
76440
  };
76353
76441
  var day = (iso) => iso ? iso.slice(0, 10) : "";
76354
76442
  function servicesText(o) {
@@ -76381,7 +76469,8 @@ var serviceImport = defineOperation({
76381
76469
  summary: "save a service sign-in from this PC's program or a file, for sandboxes",
76382
76470
  input: external_exports.object({
76383
76471
  name: KindSchema,
76384
- from: external_exports.string().max(1e3).optional().describe("(import) the file or folder to take the sign-in from")
76472
+ from: external_exports.string().max(1e3).optional().describe("(import) the file or folder to take the sign-in from"),
76473
+ file: external_exports.boolean().optional().describe("(import) ask for a file even when this PC has one to take")
76385
76474
  }),
76386
76475
  output: MessageSchema2,
76387
76476
  text: (o) => o.message,
@@ -76410,6 +76499,12 @@ var SERVICE_OPERATIONS = [serviceImport, serviceLogin, serviceLogout];
76410
76499
  function serviceCategory(kind) {
76411
76500
  return "service:" + kind;
76412
76501
  }
76502
+ var PC_HELP = {
76503
+ epic: "Sign in to the Epic launcher here, with Remember me on.",
76504
+ steam: "Log in once with SteamCMD in C:\\steamcmd.",
76505
+ unity: "Sign in to the Unity Hub here.",
76506
+ perplexity: "Set PERPLEXITY_API_KEY for your Windows user."
76507
+ };
76413
76508
  function serviceActions(s3) {
76414
76509
  return [
76415
76510
  action(
@@ -76422,51 +76517,75 @@ function serviceActions(s3) {
76422
76517
  importance: 1
76423
76518
  }
76424
76519
  ),
76425
- ...s3.canImport ? [action(serviceImport, { name: s3.kind }, { key: "i", verb: "import", importance: 1 })] : [],
76426
- ...s3.canLogin ? [action(serviceLogin, { name: s3.kind }, { key: "n", verb: "sign in", importance: 1 })] : [],
76520
+ ...s3.fromPc ? [
76521
+ action(
76522
+ serviceImport,
76523
+ { name: s3.kind },
76524
+ { key: "i", verb: "take from this PC", label: "Take this PC's sign-in", importance: 1 }
76525
+ )
76526
+ ] : [],
76527
+ ...s3.hasFileSource ? [
76528
+ action(
76529
+ serviceImport,
76530
+ { name: s3.kind, file: true },
76531
+ {
76532
+ key: s3.fromPc ? "f" : "i",
76533
+ verb: "import a file",
76534
+ label: "Import from a file\u2026",
76535
+ importance: s3.fromPc ? 2 : 1
76536
+ }
76537
+ )
76538
+ ] : [],
76539
+ ...s3.canLogin ? [
76540
+ action(
76541
+ serviceLogin,
76542
+ { name: s3.kind },
76543
+ { key: "n", verb: "type it in", label: "Type the sign-in\u2026", importance: 1 }
76544
+ )
76545
+ ] : [],
76427
76546
  ...s3.state !== "none" ? [action(serviceLogout, { name: s3.kind }, { key: "x", verb: "forget", importance: 2 })] : []
76428
76547
  ];
76429
76548
  }
76430
- function howTo(s3) {
76431
- const ways = [...s3.canImport ? ["import it"] : [], ...s3.canLogin ? ["type it in"] : []];
76432
- return ways.length ? ways.join(" or ") : "sign in once inside a sandbox (it can't be copied from this PC: Windows locks it to your PC account)";
76549
+ function helpLine(s3) {
76550
+ if (s3.state !== "none") return void 0;
76551
+ if (s3.sandboxOnly) return "Sign in once inside a sandbox; it is kept for the next ones.";
76552
+ if (s3.fromPc && s3.onPc)
76553
+ return s3.share ? "The next sandbox takes this PC's." : "Share it and the next sandbox takes this PC's.";
76554
+ if (s3.fromPc) return PC_HELP[s3.kind] ?? "Not found on this PC.";
76555
+ return s3.canLogin ? "Type it in, or import it from a file." : "Import it from a file.";
76433
76556
  }
76434
76557
  function serviceSection(s3) {
76435
76558
  const facts2 = [
76436
76559
  {
76437
76560
  id: s3.kind + ":share",
76438
- label: "Shared with sandboxes",
76561
+ label: "Shared",
76439
76562
  value: s3.share ? "on" : "off",
76440
76563
  tone: s3.share ? "ok" : "muted",
76441
- description: "For sandboxes that use " + s3.usedFor + ". " + s3.warnings.join(" ")
76564
+ description: "The agent can use it."
76442
76565
  },
76443
76566
  {
76444
76567
  id: s3.kind + ":state",
76445
76568
  label: "Sign-in",
76446
76569
  value: STATE_TEXT[s3.state] + (s3.savedAt ? " " + day(s3.savedAt) : ""),
76447
76570
  tone: STATE_TONE[s3.state],
76448
- description: s3.state === "none" ? "Save one: " + howTo(s3) + "." : void 0
76571
+ description: s3.state === "unreadable" ? "Only the Windows user that saved it can read it: save it again." : helpLine(s3) ?? (s3.source ? "Saved " + (SOURCE_TEXT[s3.source] ?? s3.source) + "." : void 0)
76449
76572
  },
76450
- ...s3.source ? [{ id: s3.kind + ":source", label: "From", value: SOURCE_TEXT[s3.source] ?? s3.source }] : [],
76573
+ ...s3.onPc === null ? [] : [
76574
+ {
76575
+ id: s3.kind + ":pc",
76576
+ label: "On this PC",
76577
+ value: s3.onPc ? "found" : "not found",
76578
+ tone: s3.onPc ? "ok" : "muted"
76579
+ }
76580
+ ],
76451
76581
  ...s3.summary ? [{ id: s3.kind + ":summary", label: "Account", value: s3.summary }] : [],
76452
76582
  ...s3.heldBy ? [{ id: s3.kind + ":held", label: "In use by", value: "sandbox " + s3.heldBy, tone: "accent" }] : []
76453
76583
  ];
76454
- const warnings = s3.warnings.map((w, i) => ({
76455
- id: s3.kind + ":warning:" + i,
76456
- label: w,
76457
- tone: "warn",
76458
- group: "Before you share it"
76459
- }));
76460
- const notes = [
76461
- ...s3.state === "unreadable" ? [{ text: "Only the Windows user that saved it can read it: save it again.", tone: "muted" }] : []
76462
- ];
76463
76584
  return {
76464
76585
  id: serviceCategory(s3.kind),
76465
76586
  title: s3.label,
76466
76587
  summary: (s3.share ? "shared" : "not shared") + " \xB7 " + STATE_TEXT[s3.state],
76467
76588
  facts: facts2,
76468
- items: warnings,
76469
- notes,
76470
76589
  actions: serviceActions(s3)
76471
76590
  };
76472
76591
  }
@@ -76781,7 +76900,17 @@ var accountsView = defineView({
76781
76900
  // src/app/features/accounts/services.run.ts
76782
76901
  import fs124 from "node:fs";
76783
76902
  import path174 from "node:path";
76784
- function serviceRow(kind, config3, store, leases) {
76903
+ function presentOnPc(kind, pc) {
76904
+ const source = HOST_SOURCES[kind];
76905
+ if (!source.fromPc) return null;
76906
+ if (!pc) return false;
76907
+ try {
76908
+ return source.fromPc(pc) !== null;
76909
+ } catch {
76910
+ return false;
76911
+ }
76912
+ }
76913
+ function serviceRow(kind, config3, store, leases, pc) {
76785
76914
  const spec = SERVICE_SPECS[kind];
76786
76915
  const source = HOST_SOURCES[kind];
76787
76916
  const state = store.state(kind);
@@ -76802,6 +76931,10 @@ function serviceRow(kind, config3, store, leases) {
76802
76931
  canImport: Boolean(source.fromPc || source.fromFile),
76803
76932
  canLogin: Boolean(source.fromAnswers),
76804
76933
  needsFile: Boolean(source.fromFile && !source.fromPc),
76934
+ fromPc: Boolean(source.fromPc),
76935
+ hasFileSource: Boolean(source.fromFile),
76936
+ onPc: presentOnPc(kind, pc),
76937
+ sandboxOnly: !source.fromPc && !source.fromFile && !source.fromAnswers,
76805
76938
  ready: isKindReady(kind)
76806
76939
  };
76807
76940
  }
@@ -76849,7 +76982,7 @@ function refuseSandboxOnly(spec) {
76849
76982
  function savedMessage(kind, share2) {
76850
76983
  return "Saved your " + SERVICE_SPECS[kind].label + " sign-in (encrypted for your Windows user)." + (share2 ? "" : " Sandboxes get it once you turn on Share with sandboxes.");
76851
76984
  }
76852
- async function importServiceFlow(io, kind, from, deps) {
76985
+ async function importServiceFlow(io, kind, from, deps, wantFile = false) {
76853
76986
  const spec = SERVICE_SPECS[kind];
76854
76987
  const source = HOST_SOURCES[kind];
76855
76988
  if (!source.fromPc && !source.fromFile) refuseSandboxOnly(spec);
@@ -76857,7 +76990,7 @@ async function importServiceFlow(io, kind, from, deps) {
76857
76990
  failWith(spec.label + " cannot be imported.", "Type it instead.", {
76858
76991
  op: "accounts.service.login",
76859
76992
  input: { name: kind },
76860
- label: "Sign in\u2026",
76993
+ label: "Type the sign-in\u2026",
76861
76994
  cli: "sandbox account login " + kind
76862
76995
  });
76863
76996
  let file2 = from === void 0 ? void 0 : path174.resolve(from);
@@ -76868,7 +77001,7 @@ async function importServiceFlow(io, kind, from, deps) {
76868
77001
  return false;
76869
77002
  }
76870
77003
  };
76871
- const useFile = Boolean(source.fromFile && (file2 ? isFile(file2) : !source.fromPc));
77004
+ const useFile = Boolean(source.fromFile && (file2 ? isFile(file2) : wantFile || !source.fromPc));
76872
77005
  if (useFile && !file2) {
76873
77006
  const asked = await io.path({ title: "The " + spec.label + " file:", pathKind: "file" });
76874
77007
  if (asked === void 0) cancelled();
@@ -76945,7 +77078,8 @@ var listServicesRun = implement(listServices, async (ctx, input2) => {
76945
77078
  if (name2 !== void 0 && name2 !== "" && !isServiceKind(name2))
76946
77079
  fail('There is no service called "' + safeText(input2.name ?? "") + '".', "Use one of: " + SERVICE_KINDS.join(", "));
76947
77080
  const kinds = name2 ? [name2] : [...SERVICE_KINDS];
76948
- return { services: kinds.map((k) => serviceRow(k, ctx.loaded.config, store, leases)) };
77081
+ const pc = pcEnv();
77082
+ return { services: kinds.map((k) => serviceRow(k, ctx.loaded.config, store, leases, pc)) };
76949
77083
  });
76950
77084
  var serviceImportRun = implement(serviceImport, async (ctx, input2, io) => {
76951
77085
  requireOnPc("account import");
@@ -76955,11 +77089,17 @@ var serviceImportRun = implement(serviceImport, async (ctx, input2, io) => {
76955
77089
  "import",
76956
77090
  (s3) => Boolean(HOST_SOURCES[s3.kind].fromPc || HOST_SOURCES[s3.kind].fromFile)
76957
77091
  );
76958
- return importServiceFlow(io, kind, input2.from, {
76959
- store: new ServiceAccountStore(ctx.storageRoot),
76960
- pc: pcEnv(),
76961
- share: ctx.loaded.config.accounts[kind].share
76962
- });
77092
+ return importServiceFlow(
77093
+ io,
77094
+ kind,
77095
+ input2.from,
77096
+ {
77097
+ store: new ServiceAccountStore(ctx.storageRoot),
77098
+ pc: pcEnv(),
77099
+ share: ctx.loaded.config.accounts[kind].share
77100
+ },
77101
+ input2.file ?? false
77102
+ );
76963
77103
  });
76964
77104
  var serviceLoginRun = implement(serviceLogin, async (ctx, input2, io) => {
76965
77105
  requireOnPc("account login");
@@ -83319,7 +83459,7 @@ var vpnLogoutRun = implement(vpnLogout, async (ctx, _input, io) => {
83319
83459
  });
83320
83460
 
83321
83461
  // src/app/features/github/github.run.ts
83322
- import os24 from "node:os";
83462
+ import os25 from "node:os";
83323
83463
  async function saveGithubTokenFlow(io, store, verify = verifyGithubToken) {
83324
83464
  io.log("Make a GitHub token only for sandboxes:");
83325
83465
  GITHUB_STEPS.forEach((s3, i) => io.log(" " + (i + 1) + ". " + s3));
@@ -83380,7 +83520,7 @@ var githubStatusRun = implement(githubStatus, async (ctx) => {
83380
83520
  expiresAt: token === "none" ? null : store.check()?.expiresAt ?? null,
83381
83521
  repoCount: token === "none" ? null : store.check()?.repoCount ?? null,
83382
83522
  checkedAt: token === "none" ? null : store.check()?.checkedAt ?? null,
83383
- tokenUrl: tokenUrlFor(os24.hostname())
83523
+ tokenUrl: tokenUrlFor(os25.hostname())
83384
83524
  };
83385
83525
  });
83386
83526
  var githubLoginRun = implement(githubLogin, async (ctx, _input, io) => {
@@ -84736,7 +84876,14 @@ function implementationOf(id) {
84736
84876
  function runDefinition(id, ctx, input2, io) {
84737
84877
  const impl = implementationOf(id);
84738
84878
  if (!impl) throw new Error("No implementation for " + id);
84739
- return invoke(impl, ctx, input2, io);
84879
+ return invokeAndRefresh(impl, ctx, input2, io);
84880
+ }
84881
+ async function invokeAndRefresh(impl, ctx, input2, io) {
84882
+ try {
84883
+ return await invoke(impl, ctx, input2, io);
84884
+ } finally {
84885
+ if (impl.def.kind === "operation") reloadSettings(ctx);
84886
+ }
84740
84887
  }
84741
84888
  async function readQuery(def, ctx, input2 = {}) {
84742
84889
  return await runDefinition(def.id, ctx, input2, NO_QUESTIONS);
@@ -84761,7 +84908,7 @@ function createRpcHost(ctx) {
84761
84908
  if (!impl) throw new Error("Not allowed on the web: " + id);
84762
84909
  const need = accessNeeded(impl.def, input2);
84763
84910
  if (!allows(caller, need)) fail(refusalText(caller, need));
84764
- return invoke(impl, ctx, input2, io);
84911
+ return invokeAndRefresh(impl, ctx, input2, io);
84765
84912
  }
84766
84913
  };
84767
84914
  }
@@ -85188,7 +85335,7 @@ async function attachOpened(ctx, session) {
85188
85335
  nextStep("sandbox attach " + session);
85189
85336
  return 0;
85190
85337
  }
85191
- const { attach: attach2 } = await import("./chunk-4TLSWPG7.js");
85338
+ const { attach: attach2 } = await import("./chunk-FA5VWLP4.js");
85192
85339
  return attach2({ ...ctx, options: { ...ctx.options, positionals: [session] } });
85193
85340
  }
85194
85341
  function definitionHandler(def) {
@@ -86148,6 +86295,7 @@ export {
86148
86295
  NAV,
86149
86296
  withOperationCommands,
86150
86297
  SandboxChannel,
86298
+ reloadSettings,
86151
86299
  esm_default4 as esm_default,
86152
86300
  esm_default11 as esm_default2,
86153
86301
  askChoice,