windows-development-sandbox 1.17.3 → 1.18.2

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 (315) hide show
  1. package/README.md +1 -1
  2. package/config.example.json +97 -4
  3. package/dist/app/features/accounts/accounts.def.d.ts +116 -2
  4. package/dist/app/features/accounts/accounts.def.js +80 -12
  5. package/dist/app/features/accounts/accounts.run.d.ts +29 -0
  6. package/dist/app/features/accounts/accounts.run.js +36 -6
  7. package/dist/app/features/accounts/index.d.ts +2 -0
  8. package/dist/app/features/accounts/index.js +4 -1
  9. package/dist/app/features/accounts/services.def.d.ts +111 -0
  10. package/dist/app/features/accounts/services.def.js +187 -0
  11. package/dist/app/features/accounts/services.run.d.ts +65 -0
  12. package/dist/app/features/accounts/services.run.js +212 -0
  13. package/dist/app/features/defs.d.ts +112 -1
  14. package/dist/app/features/defs.js +5 -0
  15. package/dist/app/features/settings/categories.def.js +21 -4
  16. package/dist/app/registry.js +5 -1
  17. package/dist/bin/agent-sandbox.js +2 -2
  18. package/dist/bin/{chunk-QLGGAG3D.js → chunk-IIHL7W6B.js} +51 -16
  19. package/dist/bin/{chunk-XYUVIVJT.js → chunk-M4OM632I.js} +1 -1
  20. package/dist/bin/{chunk-REE3EMHD.js → chunk-MQIA7GNB.js} +3813 -1702
  21. package/dist/bin/claude-host.js +2 -2
  22. package/dist/bin/claude-sbx.js +2 -2
  23. package/dist/bin/codex-sbx.js +2 -2
  24. package/dist/bin/gemini-sbx.js +2 -2
  25. package/dist/bin/sandbox.js +2 -2
  26. package/dist/bin/sbx-hide.js +2 -2
  27. package/dist/bin/sbx-show.js +2 -2
  28. package/dist/cli/commands/launch/launch.js +30 -1
  29. package/dist/cli/manifest.d.ts +93 -65
  30. package/dist/cli/manifest.js +23 -5
  31. package/dist/cli/menu/pages/accounts-page.js +31 -16
  32. package/dist/cli/services/accounts-service.d.ts +14 -4
  33. package/dist/cli/services/accounts-service.js +19 -6
  34. package/dist/cli/services/data-collect.js +26 -1
  35. package/dist/core/config/defaults.js +47 -4
  36. package/dist/core/detect/toolchains.d.ts +15 -1
  37. package/dist/core/detect/toolchains.js +45 -12
  38. package/dist/core/local-config/overrides.js +6 -0
  39. package/dist/core/schema/accounts.d.ts +27 -0
  40. package/dist/core/schema/accounts.js +32 -0
  41. package/dist/core/schema/config.d.ts +239 -0
  42. package/dist/core/schema/config.js +6 -0
  43. package/dist/core/schema/pc-installs.d.ts +7 -0
  44. package/dist/core/schema/pc-installs.js +17 -0
  45. package/dist/core/schema/toolchains.d.ts +61 -0
  46. package/dist/core/schema/toolchains.js +106 -0
  47. package/dist/core/types.d.ts +18 -0
  48. package/dist/guest/accounts/adapter.d.ts +25 -0
  49. package/dist/guest/accounts/adapter.js +21 -0
  50. package/dist/guest/accounts/adapters.d.ts +5 -0
  51. package/dist/guest/accounts/adapters.js +18 -0
  52. package/dist/guest/accounts/apply.d.ts +41 -0
  53. package/dist/guest/accounts/apply.js +47 -0
  54. package/dist/guest/accounts/kinds/appstore.d.ts +2 -0
  55. package/dist/guest/accounts/kinds/appstore.js +7 -0
  56. package/dist/guest/accounts/kinds/cfx.d.ts +2 -0
  57. package/dist/guest/accounts/kinds/cfx.js +7 -0
  58. package/dist/guest/accounts/kinds/epic.d.ts +2 -0
  59. package/dist/guest/accounts/kinds/epic.js +26 -0
  60. package/dist/guest/accounts/kinds/expo.d.ts +2 -0
  61. package/dist/guest/accounts/kinds/expo.js +7 -0
  62. package/dist/guest/accounts/kinds/keystore.d.ts +2 -0
  63. package/dist/guest/accounts/kinds/keystore.js +7 -0
  64. package/dist/guest/accounts/kinds/play.d.ts +2 -0
  65. package/dist/guest/accounts/kinds/play.js +7 -0
  66. package/dist/guest/accounts/kinds/steam.d.ts +4 -0
  67. package/dist/guest/accounts/kinds/steam.js +17 -0
  68. package/dist/guest/accounts/kinds/unity.d.ts +2 -0
  69. package/dist/guest/accounts/kinds/unity.js +7 -0
  70. package/dist/guest/accounts/watch.d.ts +28 -0
  71. package/dist/guest/accounts/watch.js +78 -0
  72. package/dist/guest/apps/resolvers-gamedev.d.ts +2 -0
  73. package/dist/guest/apps/resolvers-gamedev.js +1 -0
  74. package/dist/guest/apps/resolvers-mobile.d.ts +2 -0
  75. package/dist/guest/apps/resolvers-mobile.js +1 -0
  76. package/dist/guest/apps/resolvers.js +4 -0
  77. package/dist/guest/boot/boot.d.ts +5 -0
  78. package/dist/guest/boot/boot.js +35 -1
  79. package/dist/guest/daemon/accounts.d.ts +3 -0
  80. package/dist/guest/daemon/accounts.js +25 -0
  81. package/dist/guest/daemon/daemon.js +2 -0
  82. package/dist/guest/daemon/idle-shutdown.js +3 -1
  83. package/dist/guest/daemon/sessions.js +2 -0
  84. package/dist/guest/devtools/android.d.ts +2 -0
  85. package/dist/guest/devtools/android.js +7 -0
  86. package/dist/guest/devtools/devtool.d.ts +9 -0
  87. package/dist/guest/devtools/devtool.js +5 -0
  88. package/dist/guest/devtools/fivem.d.ts +2 -0
  89. package/dist/guest/devtools/fivem.js +7 -0
  90. package/dist/guest/devtools/registry.d.ts +6 -0
  91. package/dist/guest/devtools/registry.js +12 -0
  92. package/dist/guest/devtools/steam.d.ts +2 -0
  93. package/dist/guest/devtools/steam.js +228 -0
  94. package/dist/guest/devtools/unity.d.ts +2 -0
  95. package/dist/guest/devtools/unity.js +7 -0
  96. package/dist/guest/entries/daemon.js +2 -0
  97. package/dist/guest/entries/tool.d.ts +1 -0
  98. package/dist/guest/entries/tool.js +17 -0
  99. package/dist/guest/toolchains/engines/godot.d.ts +4 -0
  100. package/dist/guest/toolchains/engines/godot.js +4 -0
  101. package/dist/guest/toolchains/engines/unity-release.d.ts +15 -0
  102. package/dist/guest/toolchains/engines/unity-release.js +6 -0
  103. package/dist/guest/toolchains/engines/unity.d.ts +4 -0
  104. package/dist/guest/toolchains/engines/unity.js +4 -0
  105. package/dist/guest/toolchains/engines/unreal-engines.d.ts +4 -0
  106. package/dist/guest/toolchains/engines/unreal-engines.js +4 -0
  107. package/dist/guest/toolchains/fivem/artifacts.d.ts +6 -0
  108. package/dist/guest/toolchains/fivem/artifacts.js +7 -0
  109. package/dist/guest/toolchains/fivem/fivem.d.ts +4 -0
  110. package/dist/guest/toolchains/fivem/fivem.js +4 -0
  111. package/dist/guest/toolchains/installers.d.ts +12 -0
  112. package/dist/guest/toolchains/installers.js +39 -0
  113. package/dist/guest/toolchains/languages/java.js +1 -1
  114. package/dist/guest/toolchains/languages/kotlin.d.ts +3 -0
  115. package/dist/guest/toolchains/languages/kotlin.js +6 -0
  116. package/dist/guest/toolchains/mobile/android-repo.d.ts +11 -0
  117. package/dist/guest/toolchains/mobile/android-repo.js +10 -0
  118. package/dist/guest/toolchains/mobile/android.d.ts +17 -0
  119. package/dist/guest/toolchains/mobile/android.js +16 -0
  120. package/dist/guest/toolchains/mobile/dart.d.ts +4 -0
  121. package/dist/guest/toolchains/mobile/dart.js +4 -0
  122. package/dist/guest/toolchains/mobile/flutter.d.ts +4 -0
  123. package/dist/guest/toolchains/mobile/flutter.js +4 -0
  124. package/dist/guest/toolchains/mobile/react-native.d.ts +4 -0
  125. package/dist/guest/toolchains/mobile/react-native.js +4 -0
  126. package/dist/guest/toolchains/native/unreal.d.ts +3 -7
  127. package/dist/guest/toolchains/native/unreal.js +16 -167
  128. package/dist/guest/toolchains/native/visual-studio.d.ts +15 -0
  129. package/dist/guest/toolchains/native/visual-studio.js +159 -0
  130. package/dist/guest/toolchains/native/vs-request.d.ts +19 -0
  131. package/dist/guest/toolchains/native/vs-request.js +46 -0
  132. package/dist/guest/toolchains/not-yet.d.ts +2 -0
  133. package/dist/guest/toolchains/not-yet.js +6 -0
  134. package/dist/guest/toolchains/persisted.d.ts +48 -0
  135. package/dist/guest/toolchains/persisted.js +159 -0
  136. package/dist/guest/toolchains/plan.js +80 -4
  137. package/dist/guest/toolchains/steam/apps.d.ts +27 -0
  138. package/dist/guest/toolchains/steam/apps.js +112 -0
  139. package/dist/guest/toolchains/steam/client.d.ts +5 -0
  140. package/dist/guest/toolchains/steam/client.js +67 -0
  141. package/dist/guest/toolchains/steam/commands.d.ts +58 -0
  142. package/dist/guest/toolchains/steam/commands.js +155 -0
  143. package/dist/guest/toolchains/steam/steam.d.ts +4 -0
  144. package/dist/guest/toolchains/steam/steam.js +61 -0
  145. package/dist/guest/toolchains/steam/steamcmd-install.d.ts +29 -0
  146. package/dist/guest/toolchains/steam/steamcmd-install.js +177 -0
  147. package/dist/guest/toolchains/steam/steamcmd.d.ts +6 -0
  148. package/dist/guest/toolchains/steam/steamcmd.js +23 -0
  149. package/dist/guest/toolchains/step.d.ts +10 -0
  150. package/dist/host/accounts/deliver.d.ts +26 -0
  151. package/dist/host/accounts/deliver.js +80 -0
  152. package/dist/host/accounts/handoff.d.ts +17 -0
  153. package/dist/host/accounts/handoff.js +110 -0
  154. package/dist/host/accounts/index.d.ts +6 -0
  155. package/dist/host/accounts/index.js +8 -0
  156. package/dist/host/accounts/kinds/appstore.d.ts +2 -0
  157. package/dist/host/accounts/kinds/appstore.js +10 -0
  158. package/dist/host/accounts/kinds/cfx.d.ts +2 -0
  159. package/dist/host/accounts/kinds/cfx.js +7 -0
  160. package/dist/host/accounts/kinds/epic.d.ts +2 -0
  161. package/dist/host/accounts/kinds/epic.js +15 -0
  162. package/dist/host/accounts/kinds/expo.d.ts +2 -0
  163. package/dist/host/accounts/kinds/expo.js +7 -0
  164. package/dist/host/accounts/kinds/keystore.d.ts +2 -0
  165. package/dist/host/accounts/kinds/keystore.js +7 -0
  166. package/dist/host/accounts/kinds/play.d.ts +2 -0
  167. package/dist/host/accounts/kinds/play.js +7 -0
  168. package/dist/host/accounts/kinds/steam.d.ts +6 -0
  169. package/dist/host/accounts/kinds/steam.js +31 -0
  170. package/dist/host/accounts/kinds/unity.d.ts +2 -0
  171. package/dist/host/accounts/kinds/unity.js +13 -0
  172. package/dist/host/accounts/leases.d.ts +40 -0
  173. package/dist/host/accounts/leases.js +62 -0
  174. package/dist/host/accounts/source.d.ts +21 -0
  175. package/dist/host/accounts/source.js +15 -0
  176. package/dist/host/accounts/sources.d.ts +5 -0
  177. package/dist/host/accounts/sources.js +18 -0
  178. package/dist/host/accounts/store.d.ts +23 -0
  179. package/dist/host/accounts/store.js +74 -0
  180. package/dist/host/audit/log.d.ts +1 -1
  181. package/dist/host/launch/generate.d.ts +2 -0
  182. package/dist/host/launch/generate.js +16 -1
  183. package/dist/host/launch/hints/android.d.ts +3 -0
  184. package/dist/host/launch/hints/android.js +3 -0
  185. package/dist/host/launch/hints/engines.d.ts +3 -0
  186. package/dist/host/launch/hints/engines.js +3 -0
  187. package/dist/host/launch/hints/fivem.d.ts +3 -0
  188. package/dist/host/launch/hints/fivem.js +3 -0
  189. package/dist/host/launch/hints/hint.d.ts +2 -0
  190. package/dist/host/launch/hints/hint.js +1 -0
  191. package/dist/host/launch/hints/index.d.ts +5 -0
  192. package/dist/host/launch/hints/index.js +29 -0
  193. package/dist/host/launch/hints/mobile.d.ts +3 -0
  194. package/dist/host/launch/hints/mobile.js +3 -0
  195. package/dist/host/launch/hints/steam.d.ts +7 -0
  196. package/dist/host/launch/hints/steam.js +59 -0
  197. package/dist/host/launch/index.d.ts +2 -2
  198. package/dist/host/launch/index.js +2 -2
  199. package/dist/host/launch/mappings.js +2 -0
  200. package/dist/host/launch/session-file.js +2 -0
  201. package/dist/host/launch/stage.js +10 -1
  202. package/dist/host/launch/toolchains.d.ts +7 -0
  203. package/dist/host/launch/toolchains.js +11 -0
  204. package/dist/host/pc-installs/discover.d.ts +19 -0
  205. package/dist/host/pc-installs/discover.js +59 -0
  206. package/dist/host/pc-installs/epic.d.ts +2 -0
  207. package/dist/host/pc-installs/epic.js +7 -0
  208. package/dist/host/pc-installs/index.d.ts +3 -0
  209. package/dist/host/pc-installs/index.js +2 -0
  210. package/dist/host/pc-installs/source.d.ts +9 -0
  211. package/dist/host/pc-installs/source.js +1 -0
  212. package/dist/host/pc-installs/steam.d.ts +16 -0
  213. package/dist/host/pc-installs/steam.js +143 -0
  214. package/dist/host/pc-installs/unity.d.ts +2 -0
  215. package/dist/host/pc-installs/unity.js +7 -0
  216. package/dist/host/pc-installs/unreal.d.ts +2 -0
  217. package/dist/host/pc-installs/unreal.js +7 -0
  218. package/dist/host/profile/accounts.d.ts +21 -6
  219. package/dist/host/profile/accounts.js +108 -28
  220. package/dist/host/profile/claude-login.d.ts +32 -2
  221. package/dist/host/profile/claude-login.js +101 -8
  222. package/dist/host/profile/index.d.ts +1 -1
  223. package/dist/host/profile/index.js +1 -1
  224. package/dist/host/secrets/launch-secrets.js +1 -0
  225. package/dist/runtime/agent.js +321 -9
  226. package/dist/runtime/daemon.js +1987 -604
  227. package/dist/runtime/db.js +334 -11
  228. package/dist/runtime/main.js +2519 -723
  229. package/dist/runtime/netproxy.js +321 -9
  230. package/dist/runtime/tool.js +28549 -0
  231. package/dist/runtime/view.js +321 -9
  232. package/dist/selftest/accounts.test.js +172 -1
  233. package/dist/selftest/agent-paths.test.js +1 -0
  234. package/dist/selftest/android.test.d.ts +2 -0
  235. package/dist/selftest/android.test.js +7 -0
  236. package/dist/selftest/app.test.js +1 -1
  237. package/dist/selftest/engines.test.d.ts +2 -0
  238. package/dist/selftest/engines.test.js +7 -0
  239. package/dist/selftest/fivem.test.d.ts +2 -0
  240. package/dist/selftest/fivem.test.js +7 -0
  241. package/dist/selftest/generate.test.js +1 -1
  242. package/dist/selftest/index.js +18 -0
  243. package/dist/selftest/menu-screens.js +1 -0
  244. package/dist/selftest/menu.test.js +2 -1
  245. package/dist/selftest/mobile.test.d.ts +2 -0
  246. package/dist/selftest/mobile.test.js +7 -0
  247. package/dist/selftest/pc-installs.test.d.ts +2 -0
  248. package/dist/selftest/pc-installs.test.js +111 -0
  249. package/dist/selftest/persisted-installs.test.d.ts +2 -0
  250. package/dist/selftest/persisted-installs.test.js +107 -0
  251. package/dist/selftest/projects.test.js +6 -4
  252. package/dist/selftest/service-accounts.test.d.ts +2 -0
  253. package/dist/selftest/service-accounts.test.js +320 -0
  254. package/dist/selftest/steam.test.d.ts +2 -0
  255. package/dist/selftest/steam.test.js +316 -0
  256. package/dist/selftest/storage-helper.test.js +31 -8
  257. package/dist/selftest/support/engine-golden.js +3 -0
  258. package/dist/selftest/support/fixtures.d.ts +87 -0
  259. package/dist/selftest/support/fixtures.js +4 -3
  260. package/dist/selftest/support/pc-memory.d.ts +2 -0
  261. package/dist/selftest/support/pc-memory.js +17 -0
  262. package/dist/selftest/support/web-preview.js +20 -1
  263. package/dist/selftest/unity.test.d.ts +2 -0
  264. package/dist/selftest/unity.test.js +7 -0
  265. package/dist/shared/accounts/fingerprint.d.ts +1 -0
  266. package/dist/shared/accounts/fingerprint.js +20 -0
  267. package/dist/shared/accounts/index.d.ts +5 -0
  268. package/dist/shared/accounts/index.js +7 -0
  269. package/dist/shared/accounts/kinds/epic.d.ts +10 -0
  270. package/dist/shared/accounts/kinds/epic.js +56 -0
  271. package/dist/shared/accounts/kinds/steam.d.ts +28 -0
  272. package/dist/shared/accounts/kinds/steam.js +99 -0
  273. package/dist/shared/accounts/kinds.d.ts +41 -0
  274. package/dist/shared/accounts/kinds.js +154 -0
  275. package/dist/shared/accounts/payloads.d.ts +151 -0
  276. package/dist/shared/accounts/payloads.js +128 -0
  277. package/dist/shared/apps/catalogue-gamedev.d.ts +2 -0
  278. package/dist/shared/apps/catalogue-gamedev.js +1 -0
  279. package/dist/shared/apps/catalogue-mobile.d.ts +2 -0
  280. package/dist/shared/apps/catalogue-mobile.js +1 -0
  281. package/dist/shared/apps/catalogue-modding.d.ts +2 -0
  282. package/dist/shared/apps/catalogue-modding.js +1 -0
  283. package/dist/shared/apps/catalogue.d.ts +1 -0
  284. package/dist/shared/apps/catalogue.js +6 -1
  285. package/dist/shared/channel/schema.d.ts +183 -0
  286. package/dist/shared/channel/secrets.d.ts +42 -0
  287. package/dist/shared/channel/secrets.js +3 -0
  288. package/dist/shared/download/downloader.d.ts +7 -0
  289. package/dist/shared/download/downloader.js +10 -3
  290. package/dist/shared/installs.d.ts +19 -0
  291. package/dist/shared/installs.js +13 -0
  292. package/dist/shared/io/bounded.d.ts +6 -0
  293. package/dist/shared/io/bounded.js +38 -0
  294. package/dist/shared/io/index.d.ts +2 -0
  295. package/dist/shared/io/index.js +2 -0
  296. package/dist/shared/io/text.d.ts +9 -0
  297. package/dist/shared/io/text.js +18 -0
  298. package/dist/shared/paths/guest-paths.js +1 -1
  299. package/dist/shared/paths/index.d.ts +1 -0
  300. package/dist/shared/paths/index.js +1 -0
  301. package/dist/shared/paths/pc-installs.d.ts +20 -0
  302. package/dist/shared/paths/pc-installs.js +19 -0
  303. package/dist/shared/vdf.d.ts +25 -0
  304. package/dist/shared/vdf.js +151 -0
  305. package/dist/sync/sync-cycle.js +9 -0
  306. package/dist/web/index.html +1 -1
  307. package/dist/web/{main-JTH3FT4O.js → main-CWIF4VQI.js} +63 -61
  308. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  309. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  310. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  311. package/package.json +1 -1
  312. package/sandbox/scripts/add-firewall-port.ps1 +13 -0
  313. package/sandbox/templates/fivem/README.txt +2 -0
  314. package/schemas/config.schema.json +485 -0
  315. package/schemas/sandbox-config.schema.json +416 -0
@@ -1363,11 +1363,11 @@ var require_lodash = __commonJS({
1363
1363
  return isFunction(object2[key2]);
1364
1364
  });
1365
1365
  }
1366
- function baseGet(object2, path73) {
1367
- path73 = castPath(path73, object2);
1368
- var index = 0, length = path73.length;
1366
+ function baseGet(object2, path84) {
1367
+ path84 = castPath(path84, object2);
1368
+ var index = 0, length = path84.length;
1369
1369
  while (object2 != null && index < length) {
1370
- object2 = object2[toKey(path73[index++])];
1370
+ object2 = object2[toKey(path84[index++])];
1371
1371
  }
1372
1372
  return index && index == length ? object2 : undefined2;
1373
1373
  }
@@ -1431,10 +1431,10 @@ var require_lodash = __commonJS({
1431
1431
  });
1432
1432
  return accumulator;
1433
1433
  }
1434
- function baseInvoke(object2, path73, args) {
1435
- path73 = castPath(path73, object2);
1436
- object2 = parent(object2, path73);
1437
- var func = object2 == null ? object2 : object2[toKey(last(path73))];
1434
+ function baseInvoke(object2, path84, args) {
1435
+ path84 = castPath(path84, object2);
1436
+ object2 = parent(object2, path84);
1437
+ var func = object2 == null ? object2 : object2[toKey(last(path84))];
1438
1438
  return func == null ? undefined2 : apply(func, object2, args);
1439
1439
  }
1440
1440
  function baseIsArguments(value) {
@@ -1590,13 +1590,13 @@ var require_lodash = __commonJS({
1590
1590
  return object2 === source || baseIsMatch(object2, source, matchData);
1591
1591
  };
1592
1592
  }
1593
- function baseMatchesProperty(path73, srcValue) {
1594
- if (isKey(path73) && isStrictComparable(srcValue)) {
1595
- return matchesStrictComparable(toKey(path73), srcValue);
1593
+ function baseMatchesProperty(path84, srcValue) {
1594
+ if (isKey(path84) && isStrictComparable(srcValue)) {
1595
+ return matchesStrictComparable(toKey(path84), srcValue);
1596
1596
  }
1597
1597
  return function(object2) {
1598
- var objValue = get(object2, path73);
1599
- return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path73) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1598
+ var objValue = get(object2, path84);
1599
+ return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path84) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1600
1600
  };
1601
1601
  }
1602
1602
  function baseMerge(object2, source, srcIndex, customizer, stack) {
@@ -1693,23 +1693,23 @@ var require_lodash = __commonJS({
1693
1693
  });
1694
1694
  }
1695
1695
  function basePick(object2, paths) {
1696
- return basePickBy(object2, paths, function(value, path73) {
1697
- return hasIn(object2, path73);
1696
+ return basePickBy(object2, paths, function(value, path84) {
1697
+ return hasIn(object2, path84);
1698
1698
  });
1699
1699
  }
1700
1700
  function basePickBy(object2, paths, predicate) {
1701
1701
  var index = -1, length = paths.length, result2 = {};
1702
1702
  while (++index < length) {
1703
- var path73 = paths[index], value = baseGet(object2, path73);
1704
- if (predicate(value, path73)) {
1705
- baseSet(result2, castPath(path73, object2), value);
1703
+ var path84 = paths[index], value = baseGet(object2, path84);
1704
+ if (predicate(value, path84)) {
1705
+ baseSet(result2, castPath(path84, object2), value);
1706
1706
  }
1707
1707
  }
1708
1708
  return result2;
1709
1709
  }
1710
- function basePropertyDeep(path73) {
1710
+ function basePropertyDeep(path84) {
1711
1711
  return function(object2) {
1712
- return baseGet(object2, path73);
1712
+ return baseGet(object2, path84);
1713
1713
  };
1714
1714
  }
1715
1715
  function basePullAll(array2, values2, iteratee2, comparator) {
@@ -1783,14 +1783,14 @@ var require_lodash = __commonJS({
1783
1783
  var array2 = values(collection);
1784
1784
  return shuffleSelf(array2, baseClamp(n, 0, array2.length));
1785
1785
  }
1786
- function baseSet(object2, path73, value, customizer) {
1786
+ function baseSet(object2, path84, value, customizer) {
1787
1787
  if (!isObject2(object2)) {
1788
1788
  return object2;
1789
1789
  }
1790
- path73 = castPath(path73, object2);
1791
- var index = -1, length = path73.length, lastIndex = length - 1, nested = object2;
1790
+ path84 = castPath(path84, object2);
1791
+ var index = -1, length = path84.length, lastIndex = length - 1, nested = object2;
1792
1792
  while (nested != null && ++index < length) {
1793
- var key2 = toKey(path73[index]), newValue = value;
1793
+ var key2 = toKey(path84[index]), newValue = value;
1794
1794
  if (key2 === "__proto__" || key2 === "constructor" || key2 === "prototype") {
1795
1795
  return object2;
1796
1796
  }
@@ -1798,7 +1798,7 @@ var require_lodash = __commonJS({
1798
1798
  var objValue = nested[key2];
1799
1799
  newValue = customizer ? customizer(objValue, key2, nested) : undefined2;
1800
1800
  if (newValue === undefined2) {
1801
- newValue = isObject2(objValue) ? objValue : isIndex(path73[index + 1]) ? [] : {};
1801
+ newValue = isObject2(objValue) ? objValue : isIndex(path84[index + 1]) ? [] : {};
1802
1802
  }
1803
1803
  }
1804
1804
  assignValue(nested, key2, newValue);
@@ -1964,14 +1964,14 @@ var require_lodash = __commonJS({
1964
1964
  }
1965
1965
  return result2;
1966
1966
  }
1967
- function baseUnset(object2, path73) {
1968
- path73 = castPath(path73, object2);
1969
- var index = -1, length = path73.length;
1967
+ function baseUnset(object2, path84) {
1968
+ path84 = castPath(path84, object2);
1969
+ var index = -1, length = path84.length;
1970
1970
  if (!length) {
1971
1971
  return true;
1972
1972
  }
1973
1973
  while (++index < length) {
1974
- var key2 = toKey(path73[index]);
1974
+ var key2 = toKey(path84[index]);
1975
1975
  if (key2 === "__proto__" && !hasOwnProperty.call(object2, "__proto__")) {
1976
1976
  return false;
1977
1977
  }
@@ -1979,11 +1979,11 @@ var require_lodash = __commonJS({
1979
1979
  return false;
1980
1980
  }
1981
1981
  }
1982
- var obj = parent(object2, path73);
1983
- return obj == null || delete obj[toKey(last(path73))];
1982
+ var obj = parent(object2, path84);
1983
+ return obj == null || delete obj[toKey(last(path84))];
1984
1984
  }
1985
- function baseUpdate(object2, path73, updater, customizer) {
1986
- return baseSet(object2, path73, updater(baseGet(object2, path73)), customizer);
1985
+ function baseUpdate(object2, path84, updater, customizer) {
1986
+ return baseSet(object2, path84, updater(baseGet(object2, path84)), customizer);
1987
1987
  }
1988
1988
  function baseWhile(array2, predicate, isDrop, fromRight) {
1989
1989
  var length = array2.length, index = fromRight ? length : -1;
@@ -2866,11 +2866,11 @@ var require_lodash = __commonJS({
2866
2866
  var match = source.match(reWrapDetails);
2867
2867
  return match ? match[1].split(reSplitDetails) : [];
2868
2868
  }
2869
- function hasPath(object2, path73, hasFunc) {
2870
- path73 = castPath(path73, object2);
2871
- var index = -1, length = path73.length, result2 = false;
2869
+ function hasPath(object2, path84, hasFunc) {
2870
+ path84 = castPath(path84, object2);
2871
+ var index = -1, length = path84.length, result2 = false;
2872
2872
  while (++index < length) {
2873
- var key2 = toKey(path73[index]);
2873
+ var key2 = toKey(path84[index]);
2874
2874
  if (!(result2 = object2 != null && hasFunc(object2, key2))) {
2875
2875
  break;
2876
2876
  }
@@ -3072,8 +3072,8 @@ var require_lodash = __commonJS({
3072
3072
  return apply(func, this, otherArgs);
3073
3073
  };
3074
3074
  }
3075
- function parent(object2, path73) {
3076
- return path73.length < 2 ? object2 : baseGet(object2, baseSlice(path73, 0, -1));
3075
+ function parent(object2, path84) {
3076
+ return path84.length < 2 ? object2 : baseGet(object2, baseSlice(path84, 0, -1));
3077
3077
  }
3078
3078
  function reorder(array2, indexes) {
3079
3079
  var arrLength = array2.length, length = nativeMin(indexes.length, arrLength), oldArray = copyArray(array2);
@@ -3708,10 +3708,10 @@ var require_lodash = __commonJS({
3708
3708
  }
3709
3709
  return isString(collection) ? fromIndex <= length && collection.indexOf(value, fromIndex) > -1 : !!length && baseIndexOf(collection, value, fromIndex) > -1;
3710
3710
  }
3711
- var invokeMap = baseRest(function(collection, path73, args) {
3712
- var index = -1, isFunc = typeof path73 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3711
+ var invokeMap = baseRest(function(collection, path84, args) {
3712
+ var index = -1, isFunc = typeof path84 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3713
3713
  baseEach(collection, function(value) {
3714
- result2[++index] = isFunc ? apply(path73, value, args) : baseInvoke(value, path73, args);
3714
+ result2[++index] = isFunc ? apply(path84, value, args) : baseInvoke(value, path84, args);
3715
3715
  });
3716
3716
  return result2;
3717
3717
  });
@@ -4363,15 +4363,15 @@ var require_lodash = __commonJS({
4363
4363
  function functionsIn(object2) {
4364
4364
  return object2 == null ? [] : baseFunctions(object2, keysIn(object2));
4365
4365
  }
4366
- function get(object2, path73, defaultValue) {
4367
- var result2 = object2 == null ? undefined2 : baseGet(object2, path73);
4366
+ function get(object2, path84, defaultValue) {
4367
+ var result2 = object2 == null ? undefined2 : baseGet(object2, path84);
4368
4368
  return result2 === undefined2 ? defaultValue : result2;
4369
4369
  }
4370
- function has(object2, path73) {
4371
- return object2 != null && hasPath(object2, path73, baseHas);
4370
+ function has(object2, path84) {
4371
+ return object2 != null && hasPath(object2, path84, baseHas);
4372
4372
  }
4373
- function hasIn(object2, path73) {
4374
- return object2 != null && hasPath(object2, path73, baseHasIn);
4373
+ function hasIn(object2, path84) {
4374
+ return object2 != null && hasPath(object2, path84, baseHasIn);
4375
4375
  }
4376
4376
  var invert = createInverter(function(result2, value, key2) {
4377
4377
  if (value != null && typeof value.toString != "function") {
@@ -4424,10 +4424,10 @@ var require_lodash = __commonJS({
4424
4424
  return result2;
4425
4425
  }
4426
4426
  var isDeep = false;
4427
- paths = arrayMap(paths, function(path73) {
4428
- path73 = castPath(path73, object2);
4429
- isDeep || (isDeep = path73.length > 1);
4430
- return path73;
4427
+ paths = arrayMap(paths, function(path84) {
4428
+ path84 = castPath(path84, object2);
4429
+ isDeep || (isDeep = path84.length > 1);
4430
+ return path84;
4431
4431
  });
4432
4432
  copyObject(object2, getAllKeysIn(object2), result2);
4433
4433
  if (isDeep) {
@@ -4442,7 +4442,7 @@ var require_lodash = __commonJS({
4442
4442
  function omitBy(object2, predicate) {
4443
4443
  return pickBy(object2, negate(getIteratee(predicate)));
4444
4444
  }
4445
- var pick2 = flatRest(function(object2, paths) {
4445
+ var pick3 = flatRest(function(object2, paths) {
4446
4446
  return object2 == null ? {} : basePick(object2, paths);
4447
4447
  });
4448
4448
  function pickBy(object2, predicate) {
@@ -4453,19 +4453,19 @@ var require_lodash = __commonJS({
4453
4453
  return [prop];
4454
4454
  });
4455
4455
  predicate = getIteratee(predicate);
4456
- return basePickBy(object2, props, function(value, path73) {
4457
- return predicate(value, path73[0]);
4456
+ return basePickBy(object2, props, function(value, path84) {
4457
+ return predicate(value, path84[0]);
4458
4458
  });
4459
4459
  }
4460
- function result(object2, path73, defaultValue) {
4461
- path73 = castPath(path73, object2);
4462
- var index = -1, length = path73.length;
4460
+ function result(object2, path84, defaultValue) {
4461
+ path84 = castPath(path84, object2);
4462
+ var index = -1, length = path84.length;
4463
4463
  if (!length) {
4464
4464
  length = 1;
4465
4465
  object2 = undefined2;
4466
4466
  }
4467
4467
  while (++index < length) {
4468
- var value = object2 == null ? undefined2 : object2[toKey(path73[index])];
4468
+ var value = object2 == null ? undefined2 : object2[toKey(path84[index])];
4469
4469
  if (value === undefined2) {
4470
4470
  index = length;
4471
4471
  value = defaultValue;
@@ -4474,12 +4474,12 @@ var require_lodash = __commonJS({
4474
4474
  }
4475
4475
  return object2;
4476
4476
  }
4477
- function set2(object2, path73, value) {
4478
- return object2 == null ? object2 : baseSet(object2, path73, value);
4477
+ function set2(object2, path84, value) {
4478
+ return object2 == null ? object2 : baseSet(object2, path84, value);
4479
4479
  }
4480
- function setWith(object2, path73, value, customizer) {
4480
+ function setWith(object2, path84, value, customizer) {
4481
4481
  customizer = typeof customizer == "function" ? customizer : undefined2;
4482
- return object2 == null ? object2 : baseSet(object2, path73, value, customizer);
4482
+ return object2 == null ? object2 : baseSet(object2, path84, value, customizer);
4483
4483
  }
4484
4484
  var toPairs = createToPairs(keys);
4485
4485
  var toPairsIn = createToPairs(keysIn);
@@ -4501,15 +4501,15 @@ var require_lodash = __commonJS({
4501
4501
  });
4502
4502
  return accumulator;
4503
4503
  }
4504
- function unset(object2, path73) {
4505
- return object2 == null ? true : baseUnset(object2, path73);
4504
+ function unset(object2, path84) {
4505
+ return object2 == null ? true : baseUnset(object2, path84);
4506
4506
  }
4507
- function update(object2, path73, updater) {
4508
- return object2 == null ? object2 : baseUpdate(object2, path73, castFunction(updater));
4507
+ function update(object2, path84, updater) {
4508
+ return object2 == null ? object2 : baseUpdate(object2, path84, castFunction(updater));
4509
4509
  }
4510
- function updateWith(object2, path73, updater, customizer) {
4510
+ function updateWith(object2, path84, updater, customizer) {
4511
4511
  customizer = typeof customizer == "function" ? customizer : undefined2;
4512
- return object2 == null ? object2 : baseUpdate(object2, path73, castFunction(updater), customizer);
4512
+ return object2 == null ? object2 : baseUpdate(object2, path84, castFunction(updater), customizer);
4513
4513
  }
4514
4514
  function values(object2) {
4515
4515
  return object2 == null ? [] : baseValues(object2, keys(object2));
@@ -4895,17 +4895,17 @@ var require_lodash = __commonJS({
4895
4895
  function matches(source) {
4896
4896
  return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
4897
4897
  }
4898
- function matchesProperty(path73, srcValue) {
4899
- return baseMatchesProperty(path73, baseClone(srcValue, CLONE_DEEP_FLAG));
4898
+ function matchesProperty(path84, srcValue) {
4899
+ return baseMatchesProperty(path84, baseClone(srcValue, CLONE_DEEP_FLAG));
4900
4900
  }
4901
- var method = baseRest(function(path73, args) {
4901
+ var method = baseRest(function(path84, args) {
4902
4902
  return function(object2) {
4903
- return baseInvoke(object2, path73, args);
4903
+ return baseInvoke(object2, path84, args);
4904
4904
  };
4905
4905
  });
4906
4906
  var methodOf = baseRest(function(object2, args) {
4907
- return function(path73) {
4908
- return baseInvoke(object2, path73, args);
4907
+ return function(path84) {
4908
+ return baseInvoke(object2, path84, args);
4909
4909
  };
4910
4910
  });
4911
4911
  function mixin(object2, source, options) {
@@ -4952,12 +4952,12 @@ var require_lodash = __commonJS({
4952
4952
  var over = createOver(arrayMap);
4953
4953
  var overEvery = createOver(arrayEvery);
4954
4954
  var overSome = createOver(arraySome);
4955
- function property(path73) {
4956
- return isKey(path73) ? baseProperty(toKey(path73)) : basePropertyDeep(path73);
4955
+ function property(path84) {
4956
+ return isKey(path84) ? baseProperty(toKey(path84)) : basePropertyDeep(path84);
4957
4957
  }
4958
4958
  function propertyOf(object2) {
4959
- return function(path73) {
4960
- return object2 == null ? undefined2 : baseGet(object2, path73);
4959
+ return function(path84) {
4960
+ return object2 == null ? undefined2 : baseGet(object2, path84);
4961
4961
  };
4962
4962
  }
4963
4963
  var range = createRange();
@@ -5125,7 +5125,7 @@ var require_lodash = __commonJS({
5125
5125
  lodash.partial = partial2;
5126
5126
  lodash.partialRight = partialRight;
5127
5127
  lodash.partition = partition;
5128
- lodash.pick = pick2;
5128
+ lodash.pick = pick3;
5129
5129
  lodash.pickBy = pickBy;
5130
5130
  lodash.property = property;
5131
5131
  lodash.propertyOf = propertyOf;
@@ -5410,12 +5410,12 @@ var require_lodash = __commonJS({
5410
5410
  LazyWrapper.prototype.findLast = function(predicate) {
5411
5411
  return this.reverse().find(predicate);
5412
5412
  };
5413
- LazyWrapper.prototype.invokeMap = baseRest(function(path73, args) {
5414
- if (typeof path73 == "function") {
5413
+ LazyWrapper.prototype.invokeMap = baseRest(function(path84, args) {
5414
+ if (typeof path84 == "function") {
5415
5415
  return new LazyWrapper(this);
5416
5416
  }
5417
5417
  return this.map(function(value) {
5418
- return baseInvoke(value, path73, args);
5418
+ return baseInvoke(value, path84, args);
5419
5419
  });
5420
5420
  });
5421
5421
  LazyWrapper.prototype.reject = function(predicate) {
@@ -5540,14 +5540,14 @@ function relayPort(index) {
5540
5540
  }
5541
5541
 
5542
5542
  // src/guest/runtime/log.ts
5543
- import fs6 from "node:fs";
5543
+ import fs7 from "node:fs";
5544
5544
  import path9 from "node:path";
5545
5545
 
5546
5546
  // src/guest/runtime/paths.ts
5547
5547
  import path8 from "node:path";
5548
5548
 
5549
5549
  // src/shared/channel/run-dir.ts
5550
- import fs5 from "node:fs";
5550
+ import fs6 from "node:fs";
5551
5551
  import path7 from "node:path";
5552
5552
 
5553
5553
  // node_modules/zod/v4/classic/external.js
@@ -6366,10 +6366,10 @@ function mergeDefs(...defs) {
6366
6366
  function cloneDef(schema) {
6367
6367
  return mergeDefs(schema._zod.def);
6368
6368
  }
6369
- function getElementAtPath(obj, path73) {
6370
- if (!path73)
6369
+ function getElementAtPath(obj, path84) {
6370
+ if (!path84)
6371
6371
  return obj;
6372
- return path73.reduce((acc, key2) => acc?.[key2], obj);
6372
+ return path84.reduce((acc, key2) => acc?.[key2], obj);
6373
6373
  }
6374
6374
  function promiseAllObject(promisesObj) {
6375
6375
  const keys = Object.keys(promisesObj);
@@ -6709,11 +6709,11 @@ function explicitlyAborted(x, startIndex = 0) {
6709
6709
  }
6710
6710
  return false;
6711
6711
  }
6712
- function prefixIssues(path73, issues) {
6712
+ function prefixIssues(path84, issues) {
6713
6713
  return issues.map((iss) => {
6714
6714
  var _a3;
6715
6715
  (_a3 = iss).path ?? (_a3.path = []);
6716
- iss.path.unshift(path73);
6716
+ iss.path.unshift(path84);
6717
6717
  return iss;
6718
6718
  });
6719
6719
  }
@@ -6818,8 +6818,8 @@ function cleanEnum(obj) {
6818
6818
  return Number.isNaN(Number.parseInt(k, 10));
6819
6819
  }).map((el) => el[1]);
6820
6820
  }
6821
- function base64ToUint8Array(base643) {
6822
- const binaryString = atob(base643);
6821
+ function base64ToUint8Array(base644) {
6822
+ const binaryString = atob(base644);
6823
6823
  const bytes = new Uint8Array(binaryString.length);
6824
6824
  for (let i = 0; i < binaryString.length; i++) {
6825
6825
  bytes[i] = binaryString.charCodeAt(i);
@@ -6834,9 +6834,9 @@ function uint8ArrayToBase64(bytes) {
6834
6834
  return btoa(binaryString);
6835
6835
  }
6836
6836
  function base64urlToUint8Array(base64url3) {
6837
- const base643 = base64url3.replace(/-/g, "+").replace(/_/g, "/");
6838
- const padding = "=".repeat((4 - base643.length % 4) % 4);
6839
- return base64ToUint8Array(base643 + padding);
6837
+ const base644 = base64url3.replace(/-/g, "+").replace(/_/g, "/");
6838
+ const padding = "=".repeat((4 - base644.length % 4) % 4);
6839
+ return base64ToUint8Array(base644 + padding);
6840
6840
  }
6841
6841
  function uint8ArrayToBase64url(bytes) {
6842
6842
  return uint8ArrayToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
@@ -7163,16 +7163,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
7163
7163
  }
7164
7164
  function formatError(error62, mapper = (issue2) => issue2.message) {
7165
7165
  const fieldErrors = { _errors: [] };
7166
- const processError = (error63, path73 = []) => {
7166
+ const processError = (error63, path84 = []) => {
7167
7167
  for (const issue2 of error63.issues) {
7168
7168
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7169
- issue2.errors.map((issues) => processError({ issues }, [...path73, ...issue2.path]));
7169
+ issue2.errors.map((issues) => processError({ issues }, [...path84, ...issue2.path]));
7170
7170
  } else if (issue2.code === "invalid_key") {
7171
- processError({ issues: issue2.issues }, [...path73, ...issue2.path]);
7171
+ processError({ issues: issue2.issues }, [...path84, ...issue2.path]);
7172
7172
  } else if (issue2.code === "invalid_element") {
7173
- processError({ issues: issue2.issues }, [...path73, ...issue2.path]);
7173
+ processError({ issues: issue2.issues }, [...path84, ...issue2.path]);
7174
7174
  } else {
7175
- const fullpath = [...path73, ...issue2.path];
7175
+ const fullpath = [...path84, ...issue2.path];
7176
7176
  if (fullpath.length === 0) {
7177
7177
  fieldErrors._errors.push(mapper(issue2));
7178
7178
  } else {
@@ -7211,17 +7211,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
7211
7211
  }
7212
7212
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
7213
7213
  const result = { errors: [] };
7214
- const processError = (error63, path73 = []) => {
7214
+ const processError = (error63, path84 = []) => {
7215
7215
  var _a3;
7216
7216
  for (const issue2 of error63.issues) {
7217
7217
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7218
- issue2.errors.map((issues) => processError({ issues }, [...path73, ...issue2.path]));
7218
+ issue2.errors.map((issues) => processError({ issues }, [...path84, ...issue2.path]));
7219
7219
  } else if (issue2.code === "invalid_key") {
7220
- processError({ issues: issue2.issues }, [...path73, ...issue2.path]);
7220
+ processError({ issues: issue2.issues }, [...path84, ...issue2.path]);
7221
7221
  } else if (issue2.code === "invalid_element") {
7222
- processError({ issues: issue2.issues }, [...path73, ...issue2.path]);
7222
+ processError({ issues: issue2.issues }, [...path84, ...issue2.path]);
7223
7223
  } else {
7224
- const fullpath = [...path73, ...issue2.path];
7224
+ const fullpath = [...path84, ...issue2.path];
7225
7225
  if (fullpath.length === 0) {
7226
7226
  result.errors.push(mapper(issue2));
7227
7227
  continue;
@@ -7260,8 +7260,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
7260
7260
  }
7261
7261
  function toDotPath(_path) {
7262
7262
  const segs = [];
7263
- const path73 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7264
- for (const seg of path73) {
7263
+ const path84 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7264
+ for (const seg of path84) {
7265
7265
  if (typeof seg === "number")
7266
7266
  segs.push(`[${seg}]`);
7267
7267
  else if (typeof seg === "symbol")
@@ -8579,8 +8579,8 @@ var base64urlCharset = /^[A-Za-z0-9_-]*$/;
8579
8579
  function isValidBase64URL(data) {
8580
8580
  if (!base64urlCharset.test(data))
8581
8581
  return false;
8582
- const base643 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/");
8583
- const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
8582
+ const base644 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/");
8583
+ const padded = base644.padEnd(Math.ceil(base644.length / 4) * 4, "=");
8584
8584
  return isValidBase64(padded);
8585
8585
  }
8586
8586
  var $ZodBase64URL = /* @__PURE__ */ $constructor("$ZodBase64URL", (inst, def) => {
@@ -24363,13 +24363,13 @@ function resolveRef(ref, ctx) {
24363
24363
  if (!ref.startsWith("#")) {
24364
24364
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24365
24365
  }
24366
- const path73 = ref.slice(1).split("/").filter(Boolean);
24367
- if (path73.length === 0) {
24366
+ const path84 = ref.slice(1).split("/").filter(Boolean);
24367
+ if (path84.length === 0) {
24368
24368
  return ctx.rootSchema;
24369
24369
  }
24370
24370
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
24371
- if (path73[0] === defsKey) {
24372
- const key2 = path73[1] === void 0 ? void 0 : decodeJSONPointerSegment(path73[1]);
24371
+ if (path84[0] === defsKey) {
24372
+ const key2 = path84[1] === void 0 ? void 0 : decodeJSONPointerSegment(path84[1]);
24373
24373
  if (!key2 || !ctx.defs[key2]) {
24374
24374
  throw new Error(`Reference not found: ${ref}`);
24375
24375
  }
@@ -25219,7 +25219,7 @@ function date4(params) {
25219
25219
  }
25220
25220
 
25221
25221
  // src/shared/paths/guest-paths.ts
25222
- var RESERVED_GUEST = /^C:\\(?:Windows|Program Files|Program Files \(x86\)|ProgramData|Users|AgentLaunch|AgentData|HostTools|nvm|Mirror)(?:\\|$)/i;
25222
+ var RESERVED_GUEST = /^C:\\(?:Windows|Program Files|Program Files \(x86\)|ProgramData|Users|AgentLaunch|AgentData|HostTools|nvm|Mirror|PcInstalls)(?:\\|$)/i;
25223
25223
  var MIRROR_ROOT = "C:\\Mirror";
25224
25224
  var MIRROR_LETTER = /^[D-Z]$/;
25225
25225
  var DRIVE_PATH = /^([A-Za-z]):\\(.*)$/;
@@ -25680,8 +25680,119 @@ var ToolchainsSchema = external_exports.strictObject({
25680
25680
  ),
25681
25681
  keepInstallFiles: external_exports.boolean().describe(
25682
25682
  "Keep an offline copy of the Visual Studio install files in tools\\visualstudio (~10 GB, made once), so later boots install without downloading them again. Skipped while that disk has too little room."
25683
+ ),
25684
+ persistEngines: external_exports.boolean().describe(
25685
+ "Engines the Epic Games Launcher installs go to tools\\unreal\\engines (kept between sandboxes, 40-60 GB each) and are registered with the launcher again every boot. Off: they go on the sandbox disk and are lost when it closes. Engines installed on this PC can be mapped instead (pcInstalls.unrealEngines)."
25686
+ ),
25687
+ derivedDataCache: external_exports.enum(["persisted", "local"]).describe(
25688
+ `"persisted": the engine's local derived data cache (compiled shaders, 10-50 GB) in tools\\unreal\\ddc, kept between sandboxes. "local": Unreal's own place on the sandbox disk (rebuilt every boot).`
25689
+ )
25690
+ }),
25691
+ unity: external_exports.strictObject({
25692
+ enabled: enabled(
25693
+ "Unity: the editor version a project asks for, from Unity's release API (checked against its published hash), installed into tools\\unity\\<version> (6-7 GB each), with the modules you list.",
25694
+ "ProjectSettings/ProjectVersion.txt"
25695
+ ),
25696
+ acceptLicense: external_exports.boolean().describe(
25697
+ "Required to install: you accept the Unity terms of service (https://unity.com/legal/terms-of-service), and the editor needs a Unity licence (Personal is free). A project file cannot accept it for you."
25698
+ ),
25699
+ version: external_exports.string().min(1).describe(
25700
+ '"project" = the version in ProjectSettings/ProjectVersion.txt, or an editor version such as "6000.0.32f1".'
25701
+ ),
25702
+ modules: external_exports.array(external_exports.string().regex(/^[a-z0-9-]+$/)).describe(
25703
+ `Editor modules to add: "android" (4-5 GB, also the Android SDK), "webgl" (1.5 GB), "windows-il2cpp" (adds Visual Studio's C++ parts), "ios" (Xcode project export only: iOS builds need a Mac).`
25704
+ ),
25705
+ hub: external_exports.boolean().describe("Also Unity Hub, with the installed editors listed in it."),
25706
+ keepVersions: external_exports.number().int().min(1).max(20).describe(
25707
+ "How many editor versions to keep in tools\\unity; older ones are removed (the least recently used first)."
25708
+ )
25709
+ }),
25710
+ godot: external_exports.strictObject({
25711
+ enabled: enabled(
25712
+ "Godot from its official builds (checked against the published SHA-512 sums), self-contained in tools\\godot\\<version> with `godot` (the console build) on PATH.",
25713
+ "project.godot"
25714
+ ),
25715
+ version: external_exports.string().min(1).describe(
25716
+ '"project" = the version project.godot was saved with (else the newest stable), or a version such as "4.3".'
25717
+ ),
25718
+ dotnet: EnabledSchema.describe(
25719
+ 'The .NET (C#) build of Godot and the .NET SDK: true, false, or "auto" = when the project has a .csproj.'
25720
+ ),
25721
+ exportTemplates: external_exports.boolean().describe("Also the export templates for that version (~1.2 GB), for exporting games."),
25722
+ keepVersions: external_exports.number().int().min(1).max(20).describe("How many Godot versions to keep; older ones are removed (the least recently used first).")
25723
+ }),
25724
+ steam: external_exports.strictObject({
25725
+ enabled: enabled(
25726
+ "SteamCMD (`steamcmd` on PATH, Valve-signed, ~0.3 GB) and `sbx-steam` for logging in, downloading apps and workshop items, and uploading builds (ContentBuilder) and workshop items.",
25727
+ "steam_appid.txt, steam_api64.dll, steam_api.dll, or an app_build / workshop_item .vdf"
25728
+ ),
25729
+ client: external_exports.boolean().describe(
25730
+ "Also the Steam client (1-1.5 GB, in tools\\steam), for testing the Steamworks API, the overlay or in-game uploads. You sign in to it in each sandbox."
25731
+ ),
25732
+ sdkFolder: external_exports.string().describe(
25733
+ "Where the Steamworks SDK is in the sandbox (relative paths are inside the project); it sets STEAMWORKS_SDK. Empty = not set. The SDK is never downloaded (it needs a Steamworks partner login)."
25734
+ )
25735
+ }),
25736
+ fivem: external_exports.strictObject({
25737
+ enabled: enabled(
25738
+ "A FiveM / RedM server (FXServer with txAdmin) for resource development, from the Cfx.re artifacts (the game client is not supported). `sbx-fivem serve` starts it.",
25739
+ "fxmanifest.lua or __resource.lua (up to 3 folders down)"
25740
+ ),
25741
+ acceptLicense: external_exports.boolean().describe(
25742
+ "Required to install: you accept the Cfx.re platform terms (https://fivem.net/terms) and the FXServer licence. A project file cannot accept it for you."
25743
+ ),
25744
+ game: external_exports.enum(["gta5", "rdr3"]).describe('"gta5" = FiveM, "rdr3" = RedM.'),
25745
+ artifact: external_exports.string().regex(/^(recommended|optional|latest|\d+)$/).describe('The server build: "recommended", "optional", "latest", or a build number.'),
25746
+ txAdmin: external_exports.boolean().describe("Start the server with txAdmin (its web panel on port 40120)."),
25747
+ keepVersions: external_exports.number().int().min(1).max(20).describe("How many server builds to keep in tools\\fivem\\artifacts.")
25748
+ }),
25749
+ android: external_exports.strictObject({
25750
+ enabled: enabled(
25751
+ "The Android SDK (command-line tools, platform-tools, build-tools, platforms, NDK and CMake as needed) in tools\\android-sdk, with a JDK. No emulator (Windows Sandbox cannot run one): use a device over the network, or build only.",
25752
+ "a Gradle build using com.android, an AndroidManifest.xml (up to 3 folders down), a .NET MAUI project, or a Flutter / React Native / Godot Android project"
25753
+ ),
25754
+ acceptLicense: external_exports.boolean().describe(
25755
+ "Required to install: you accept the Android SDK licence (https://developer.android.com/studio/terms) and the licences sdkmanager shows. A project file cannot accept them for you."
25756
+ ),
25757
+ platforms: StringsSchema.describe(
25758
+ `Platforms to install, e.g. ["android-35"]; "project" = the compileSdk the project's Gradle files ask for.`
25759
+ ),
25760
+ buildTools: external_exports.string().min(1).describe('"latest" or a build-tools version such as "35.0.0".'),
25761
+ ndk: external_exports.union([external_exports.literal(false), external_exports.string().min(1)]).describe(
25762
+ '"auto" = when the project uses native code (ndkVersion, CMake or ndk-build), false = never, or a version.'
25763
+ ),
25764
+ cmake: external_exports.union([external_exports.literal(false), external_exports.string().min(1)]).describe('"auto" = when the project builds native code with CMake, false = never, or a version.'),
25765
+ packages: Packages("More sdkmanager packages (not the emulator or system images)", '["extras;google;usb_driver"]')
25766
+ }),
25767
+ flutter: external_exports.strictObject({
25768
+ enabled: enabled(
25769
+ "Flutter (with its Dart) from the official releases (checked against their SHA-256), with the Android SDK for Android builds.",
25770
+ "a pubspec.yaml with a flutter: section"
25771
+ ),
25772
+ version: external_exports.string().min(1).describe(
25773
+ '"project" = the version in .fvmrc (else the newest stable), "stable", "beta", or a version such as "3.24.5".'
25774
+ ),
25775
+ windowsDesktop: external_exports.boolean().describe(
25776
+ "Windows desktop builds: needs Visual Studio Build Tools' C++ parts (a real installer: it runs every boot, ~5 GB on the sandbox disk)."
25777
+ ),
25778
+ precache: StringsSchema.describe(
25779
+ 'Platforms whose engine files are downloaded ahead (flutter precache), e.g. ["android", "web"].'
25683
25780
  )
25684
25781
  }),
25782
+ dart: external_exports.strictObject({
25783
+ enabled: enabled(
25784
+ "The Dart SDK (without Flutter), checked against its published SHA-256.",
25785
+ "a pubspec.yaml without a flutter: section"
25786
+ ),
25787
+ version: external_exports.string().min(1).describe('"stable", "beta" or a version such as "3.5.4".')
25788
+ }),
25789
+ reactNative: external_exports.strictObject({
25790
+ enabled: enabled(
25791
+ "React Native / Expo: the Android SDK and JDK for Android builds (Node is always there). iOS builds run in EAS Build (the cloud).",
25792
+ "a package.json depending on react-native or expo"
25793
+ ),
25794
+ easCli: external_exports.boolean().describe("Also eas-cli (Expo Application Services) as a global npm package.")
25795
+ }),
25685
25796
  cpp: external_exports.strictObject({
25686
25797
  enabled: enabled(
25687
25798
  "MinGW-w64 GCC with CMake, Ninja, premake5 and mingw32-make (also Rust's linker).",
@@ -25701,7 +25812,8 @@ var ToolchainsSchema = external_exports.strictObject({
25701
25812
  ),
25702
25813
  netfx35: external_exports.boolean().describe(
25703
25814
  ".NET Framework 3.5 runtime (a Windows feature, enabled from Windows Update on every boot; a few minutes)."
25704
- )
25815
+ ),
25816
+ templates: Packages("Project templates (`dotnet new install`)", '["MonoGame.Templates.CSharp"]')
25705
25817
  }),
25706
25818
  go: external_exports.strictObject({
25707
25819
  enabled: enabled("Go.", "go.mod or go.work"),
@@ -25717,7 +25829,8 @@ var ToolchainsSchema = external_exports.strictObject({
25717
25829
  ),
25718
25830
  version: external_exports.string().min(1).describe(`"lts" (newest LTS) or a major version such as "21". A project's .java-version or .sdkmanrc wins.`),
25719
25831
  maven: external_exports.boolean().describe("Apache Maven (mvn). A project's mvnw works either way."),
25720
- gradle: external_exports.boolean().describe("Gradle (gradle). A project's gradlew works either way.")
25832
+ gradle: external_exports.boolean().describe("Gradle (gradle). A project's gradlew works either way."),
25833
+ kotlin: external_exports.boolean().describe("Also the Kotlin compiler (kotlinc) from JetBrains' releases. Gradle builds fetch their own.")
25721
25834
  }),
25722
25835
  ruby: external_exports.strictObject({
25723
25836
  enabled: enabled(
@@ -25788,6 +25901,15 @@ var ToolchainsSchema = external_exports.strictObject({
25788
25901
  )
25789
25902
  });
25790
25903
 
25904
+ // src/shared/apps/catalogue-gamedev.ts
25905
+ var GAMEDEV_APPS = [];
25906
+
25907
+ // src/shared/apps/catalogue-mobile.ts
25908
+ var MOBILE_APPS = [];
25909
+
25910
+ // src/shared/apps/catalogue-modding.ts
25911
+ var MODDING_APPS = [];
25912
+
25791
25913
  // src/shared/apps/catalogue.ts
25792
25914
  var gh = (github, asset) => ({ github, asset });
25793
25915
  var RTK_VERSION = "1.0.1";
@@ -25797,7 +25919,7 @@ var HEADROOM_VERSION = "0.41.0";
25797
25919
  var CCUSAGE_VERSION = "20.0.36";
25798
25920
  var PLAYWRIGHT_MCP_VERSION = "0.0.83";
25799
25921
  var CONTEXT7_MCP_VERSION = "4.4.2";
25800
- var APPS = [
25922
+ var CORE_APPS = [
25801
25923
  // ---- agent add-ons
25802
25924
  {
25803
25925
  id: "rtk",
@@ -26620,6 +26742,7 @@ var APPS = [
26620
26742
  cli: true
26621
26743
  }
26622
26744
  ];
26745
+ var APPS = [...CORE_APPS, ...GAMEDEV_APPS, ...MODDING_APPS, ...MOBILE_APPS];
26623
26746
  function appById(id) {
26624
26747
  return APPS.find((a) => a.id === id);
26625
26748
  }
@@ -26822,6 +26945,187 @@ var GithubSchema = external_exports.strictObject({
26822
26945
  )
26823
26946
  });
26824
26947
 
26948
+ // src/shared/accounts/kinds.ts
26949
+ var SERVICE_KINDS = ["epic", "steam", "unity", "cfx", "keystore", "play", "expo", "appstore"];
26950
+ var AGENT_CAN_USE = "The agent in the sandbox can use this sign-in while it is there.";
26951
+ var ONE_PLACE = "It works in one sandbox at a time: a second sandbox starts without it while the first one runs.";
26952
+ var SERVICE_SPECS = {
26953
+ epic: {
26954
+ kind: "epic",
26955
+ label: "Epic Games",
26956
+ usedBy: ["unreal"],
26957
+ sources: ["pc", "sandbox"],
26958
+ singleHolder: true,
26959
+ returns: true,
26960
+ maxBytes: 64 * 1024,
26961
+ warnings: [
26962
+ AGENT_CAN_USE,
26963
+ "A sign-in works in one place at a time: taking this PC's signs the launcher on this PC out the first time a sandbox uses it."
26964
+ ],
26965
+ fields: []
26966
+ },
26967
+ steam: {
26968
+ kind: "steam",
26969
+ label: "Steam (SteamCMD)",
26970
+ usedBy: ["steam"],
26971
+ sources: ["file", "sandbox"],
26972
+ singleHolder: true,
26973
+ returns: true,
26974
+ maxBytes: 768 * 1024,
26975
+ warnings: [
26976
+ AGENT_CAN_USE + " It can upload builds and workshop items to your Steam apps.",
26977
+ ONE_PLACE,
26978
+ "No password is kept: sign in once with sbx-steam login in a sandbox (Steam Guard asks there)."
26979
+ ],
26980
+ fields: []
26981
+ },
26982
+ unity: {
26983
+ kind: "unity",
26984
+ label: "Unity",
26985
+ usedBy: ["unity"],
26986
+ sources: ["pc", "file", "typed", "sandbox"],
26987
+ singleHolder: true,
26988
+ returns: true,
26989
+ maxBytes: 256 * 1024,
26990
+ warnings: [
26991
+ AGENT_CAN_USE,
26992
+ ONE_PLACE,
26993
+ "A Pro seat is handed back when the sandbox stops cleanly; a sandbox closed abruptly may keep it until you return it."
26994
+ ],
26995
+ fields: [
26996
+ { name: "email", label: "Unity ID email", secret: false, optional: true },
26997
+ { name: "password", label: "Unity ID password", secret: true, optional: true },
26998
+ { name: "serial", label: "Serial (Plus or Pro; empty for Personal)", secret: true, optional: true }
26999
+ ]
27000
+ },
27001
+ cfx: {
27002
+ kind: "cfx",
27003
+ label: "Cfx.re (FiveM / RedM server key)",
27004
+ usedBy: ["fivem"],
27005
+ sources: ["typed"],
27006
+ singleHolder: false,
27007
+ returns: false,
27008
+ maxBytes: 4 * 1024,
27009
+ warnings: [AGENT_CAN_USE + " Anyone with the key can run a server under your Cfx.re account."],
27010
+ fields: [
27011
+ { name: "licenseKey", label: "Server licence key (cfxk_...)", secret: true, pattern: /^cfxk_[A-Za-z0-9_]+$/ },
27012
+ {
27013
+ name: "steamWebApiKey",
27014
+ label: "Steam Web API key (optional)",
27015
+ secret: true,
27016
+ optional: true,
27017
+ pattern: /^[A-F0-9]{32}$/
27018
+ }
27019
+ ]
27020
+ },
27021
+ keystore: {
27022
+ kind: "keystore",
27023
+ label: "Android upload keystore",
27024
+ usedBy: ["android"],
27025
+ sources: ["file"],
27026
+ singleHolder: false,
27027
+ returns: false,
27028
+ maxBytes: 512 * 1024,
27029
+ warnings: [AGENT_CAN_USE + " It can sign app updates as you; keep a backup of the keystore elsewhere."],
27030
+ fields: [
27031
+ { name: "storePassword", label: "Keystore password", secret: true },
27032
+ { name: "keyAlias", label: "Key alias", secret: false },
27033
+ { name: "keyPassword", label: "Key password", secret: true }
27034
+ ]
27035
+ },
27036
+ play: {
27037
+ kind: "play",
27038
+ label: "Google Play (service account)",
27039
+ usedBy: ["android"],
27040
+ sources: ["file"],
27041
+ singleHolder: false,
27042
+ returns: false,
27043
+ maxBytes: 128 * 1024,
27044
+ warnings: [AGENT_CAN_USE + " It can publish to Google Play with what the service account is allowed."],
27045
+ fields: []
27046
+ },
27047
+ expo: {
27048
+ kind: "expo",
27049
+ label: "Expo (EAS)",
27050
+ usedBy: ["reactNative"],
27051
+ sources: ["typed"],
27052
+ singleHolder: false,
27053
+ returns: false,
27054
+ maxBytes: 4 * 1024,
27055
+ warnings: [AGENT_CAN_USE + " It can start EAS builds and submissions on your Expo account."],
27056
+ fields: [{ name: "token", label: "Expo access token", secret: true }]
27057
+ },
27058
+ appstore: {
27059
+ kind: "appstore",
27060
+ label: "App Store Connect API key",
27061
+ usedBy: ["reactNative", "flutter"],
27062
+ sources: ["file", "typed"],
27063
+ singleHolder: false,
27064
+ returns: false,
27065
+ maxBytes: 16 * 1024,
27066
+ warnings: [AGENT_CAN_USE + " It can upload and submit apps with what the key is allowed."],
27067
+ fields: [
27068
+ { name: "issuerId", label: "Issuer ID", secret: false },
27069
+ { name: "keyId", label: "Key ID", secret: false, pattern: /^[A-Z0-9]{10}$/ }
27070
+ ]
27071
+ }
27072
+ };
27073
+ var HANDOFF_PARTS = ["state", "accounts"];
27074
+
27075
+ // src/core/schema/accounts.ts
27076
+ function share(kind, how) {
27077
+ const spec = SERVICE_SPECS[kind];
27078
+ return external_exports.strictObject({
27079
+ share: external_exports.boolean().describe(
27080
+ "Hand your saved " + spec.label + " sign-in to sandboxes that use " + spec.usedBy.join(" or ") + " (" + how + "). Kept encrypted on this PC; " + spec.warnings.join(" ") + " Yours only: a project file can only turn it off."
27081
+ )
27082
+ });
27083
+ }
27084
+ var AccountsSchema = external_exports.strictObject({
27085
+ epic: share("epic", "sign in to the launcher once in a sandbox, or take this PC's: sandbox account import epic"),
27086
+ steam: share(
27087
+ "steam",
27088
+ "sign in once with sbx-steam login, or: sandbox account import steam --from <steamcmd folder>"
27089
+ ),
27090
+ unity: share("unity", "sign in once in a sandbox, or take this PC's licence: sandbox account import unity"),
27091
+ cfx: share("cfx", "sandbox account login cfx"),
27092
+ keystore: share("keystore", "sandbox account import keystore --from <upload.jks>"),
27093
+ play: share("play", "sandbox account import play --from <service-account.json>"),
27094
+ expo: share("expo", "sandbox account login expo"),
27095
+ appstore: share("appstore", "sandbox account import appstore --from <AuthKey.p8>")
27096
+ }).describe(
27097
+ "Service sign-ins for sandboxes (game stores, engines, app signing). Manage them in Accounts: sandbox account status."
27098
+ );
27099
+
27100
+ // src/core/schema/pc-installs.ts
27101
+ var pick2 = (item, what, example) => external_exports.union([external_exports.boolean(), external_exports.array(item)]).describe(
27102
+ what + " of this PC, read-only in the sandbox under C:\\PcInstalls: true = all of them, false = none, or a list (e.g. " + example + "). The agent can read their files."
27103
+ );
27104
+ var PcInstallsSchema = external_exports.strictObject({
27105
+ steamGames: pick2(
27106
+ external_exports.number().int().positive(),
27107
+ "Steam games (true maps each library; a list of app IDs maps only those games)",
27108
+ "[480, 730]"
27109
+ ),
27110
+ epicGames: pick2(
27111
+ external_exports.string().regex(/^[A-Za-z0-9._-]{1,100}$/),
27112
+ "Epic Games Launcher games (by their app name)",
27113
+ '["Fortnite"]'
27114
+ ),
27115
+ unrealEngines: pick2(
27116
+ external_exports.string().regex(/^(UE_)?\d+\.\d+$/),
27117
+ "Unreal Engine versions installed with the Epic Games Launcher",
27118
+ '["5.4"]'
27119
+ ),
27120
+ unityEditors: pick2(
27121
+ external_exports.string().regex(/^\d+\.\d+\.\d+[abfp]\d+$/),
27122
+ "Unity editors installed with Unity Hub",
27123
+ '["6000.0.32f1"]'
27124
+ )
27125
+ }).describe(
27126
+ "Games, engines and editors installed on this PC, mapped read-only into sandboxes (no copy, no room on the sandbox's disk)."
27127
+ );
27128
+
26825
27129
  // src/core/schema/config.ts
26826
27130
  var RESERVED_ENV_PREFIX = /^(AGENT_|GIT_|GH_|GITHUB_|NODE_|NPM_CONFIG_(USERCONFIG|GLOBALCONFIG|PREFIX|SCRIPT_SHELL)|SSL_|CLAUDE|ANTHROPIC_|OPENAI_|CODEX_|GEMINI_|GOOGLE_|COPILOT_|AWS_|AZURE_)/i;
26827
27131
  var RESERVED_ENV_SUFFIX = /(_PROXY|_BASE_URL|_ENDPOINT|_CA_BUNDLE|_CA_CERTS)$/i;
@@ -26883,6 +27187,8 @@ var ConfigSchema = external_exports.strictObject({
26883
27187
  network: NetworkSchema,
26884
27188
  vpn: VpnSchema,
26885
27189
  github: GithubSchema,
27190
+ accounts: AccountsSchema,
27191
+ pcInstalls: PcInstallsSchema,
26886
27192
  provisioning: ProvisioningSchema,
26887
27193
  downloads: DownloadsSchema,
26888
27194
  toolchains: ToolchainsSchema,
@@ -26935,6 +27241,8 @@ var LocalOverridesSchema = external_exports.strictObject({
26935
27241
  network: NetworkSchema.pick({ blockPrivateRanges: true, blockHosts: true }).partial(),
26936
27242
  // A project may turn the kill switch on, never off, and never choose a VPN, a server, a file or a login.
26937
27243
  vpn: VpnSchema.pick({ killSwitch: true }).partial(),
27244
+ // A project may only turn a sign-in off (policy: OFF_IS_SAFER); pcInstalls is never here (folders of this PC).
27245
+ accounts: external_exports.strictObject(import_lodash.default.mapValues(AccountsSchema.shape, (shape) => shape.partial())).partial(),
26938
27246
  provisioning: ProvisioningSchema.pick({ copyFromHost: true, fallbackToInstall: true, refresh: true }).extend({ git: GitSchema.partial(), terminal: toggle("Windows Terminal as the sandbox window.").partial() }).partial(),
26939
27247
  downloads: DownloadsSchema.partial(),
26940
27248
  // Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
@@ -27323,6 +27631,49 @@ function copyTreeTolerant(from, to, skip = () => false) {
27323
27631
  return { copied, vanished };
27324
27632
  }
27325
27633
 
27634
+ // src/shared/io/bounded.ts
27635
+ import fs5 from "node:fs";
27636
+ function readBoundedFile(file3, max, hooks = {}) {
27637
+ try {
27638
+ if (!fs5.lstatSync(file3).isFile()) return null;
27639
+ } catch {
27640
+ return null;
27641
+ }
27642
+ let fd = null;
27643
+ try {
27644
+ fd = fs5.openSync(file3, "r");
27645
+ const stat = fs5.fstatSync(fd);
27646
+ if (!stat.isFile() || stat.size > max) return null;
27647
+ hooks.afterStat?.();
27648
+ const buffer = Buffer.alloc(max + 1);
27649
+ let total = 0;
27650
+ while (total < buffer.length) {
27651
+ const read = fs5.readSync(fd, buffer, total, buffer.length - total, total);
27652
+ if (read === 0) break;
27653
+ total += read;
27654
+ }
27655
+ return total > max ? null : buffer.subarray(0, total);
27656
+ } catch {
27657
+ return null;
27658
+ } finally {
27659
+ if (fd !== null) fs5.closeSync(fd);
27660
+ }
27661
+ }
27662
+
27663
+ // src/shared/io/text.ts
27664
+ function decodeText(bytes) {
27665
+ if (bytes.length >= 2 && bytes[0] === 255 && bytes[1] === 254)
27666
+ return { text: bytes.subarray(2).toString("utf16le"), encoding: "utf16le" };
27667
+ if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191)
27668
+ return { text: bytes.subarray(3).toString("utf8"), encoding: "utf8bom" };
27669
+ return { text: bytes.toString("utf8"), encoding: "utf8" };
27670
+ }
27671
+ function encodeText(text, encoding) {
27672
+ if (encoding === "utf16le") return Buffer.concat([Buffer.from([255, 254]), Buffer.from(text, "utf16le")]);
27673
+ if (encoding === "utf8bom") return Buffer.concat([Buffer.from([239, 187, 191]), Buffer.from(text, "utf8")]);
27674
+ return Buffer.from(text, "utf8");
27675
+ }
27676
+
27326
27677
  // src/shared/channel/run-dir.ts
27327
27678
  function safeId(id) {
27328
27679
  return IdSchema.parse(id);
@@ -27331,10 +27682,10 @@ function now() {
27331
27682
  return (/* @__PURE__ */ new Date()).toISOString();
27332
27683
  }
27333
27684
  var scan = (schema, dir) => {
27334
- if (!fs5.existsSync(dir)) return { valid: [], invalid: [] };
27685
+ if (!fs6.existsSync(dir)) return { valid: [], invalid: [] };
27335
27686
  const valid = [];
27336
27687
  const invalid = [];
27337
- for (const name of fs5.readdirSync(dir)) {
27688
+ for (const name of fs6.readdirSync(dir)) {
27338
27689
  if (name.endsWith(".tmp")) continue;
27339
27690
  const message = /^[A-Za-z0-9_-]{1,64}\.json$/.test(name) ? readValid(schema, path7.join(dir, name)) : null;
27340
27691
  if (message) valid.push(message);
@@ -27448,14 +27799,14 @@ var logsDir = path8.join(dataDir, "logs");
27448
27799
  var run = new RunDir(dataDir);
27449
27800
 
27450
27801
  // src/guest/runtime/log.ts
27451
- fs6.mkdirSync(logsDir, { recursive: true });
27802
+ fs7.mkdirSync(logsDir, { recursive: true });
27452
27803
  var logFile = path9.join(
27453
27804
  logsDir,
27454
27805
  (process.env.AGENT_LOG_PREFIX ?? "guest") + "-" + (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-") + ".log"
27455
27806
  );
27456
27807
  var append = (line) => {
27457
27808
  try {
27458
- fs6.appendFileSync(logFile, line + "\n");
27809
+ fs7.appendFileSync(logFile, line + "\n");
27459
27810
  } catch {
27460
27811
  }
27461
27812
  };
@@ -27469,7 +27820,7 @@ function warn(message) {
27469
27820
  }
27470
27821
 
27471
27822
  // src/guest/runtime/session.ts
27472
- import fs10 from "node:fs";
27823
+ import fs11 from "node:fs";
27473
27824
  import path14 from "node:path";
27474
27825
 
27475
27826
  // src/shared/download/http.ts
@@ -27501,7 +27852,7 @@ async function fetchText(url2) {
27501
27852
  }
27502
27853
 
27503
27854
  // src/shared/download/archive.ts
27504
- import fs8 from "node:fs";
27855
+ import fs9 from "node:fs";
27505
27856
  import path12 from "node:path";
27506
27857
  import crypto from "node:crypto";
27507
27858
 
@@ -27533,13 +27884,13 @@ var SYSTEM = {
27533
27884
  };
27534
27885
 
27535
27886
  // src/shared/scripts.ts
27536
- import fs7 from "node:fs";
27887
+ import fs8 from "node:fs";
27537
27888
  import path11 from "node:path";
27538
27889
  import { fileURLToPath } from "node:url";
27539
27890
  var HERE = path11.dirname(fileURLToPath(import.meta.url));
27540
27891
  function sandboxScriptsDir() {
27541
27892
  const candidates = [path11.resolve(HERE, "..", "sandbox"), path11.resolve(HERE, "..", "..", "sandbox")];
27542
- return candidates.find((dir) => fs7.existsSync(path11.join(dir, "boot", "bootstrap.ps1"))) ?? candidates[candidates.length - 1];
27893
+ return candidates.find((dir) => fs8.existsSync(path11.join(dir, "boot", "bootstrap.ps1"))) ?? candidates[candidates.length - 1];
27543
27894
  }
27544
27895
  function scriptArgs(name, args = []) {
27545
27896
  return [
@@ -27570,15 +27921,15 @@ function stagingFolder(destination) {
27570
27921
  }
27571
27922
  function moveIntoPlace(work, destination) {
27572
27923
  safeRemove(destination, path12.dirname(destination));
27573
- fs8.mkdirSync(path12.dirname(destination), { recursive: true });
27574
- fs8.renameSync(work, destination);
27924
+ fs9.mkdirSync(path12.dirname(destination), { recursive: true });
27925
+ fs9.renameSync(work, destination);
27575
27926
  }
27576
27927
  async function extractArchive(archive, destination, members2 = []) {
27577
- fs8.mkdirSync(destination, { recursive: true });
27928
+ fs9.mkdirSync(destination, { recursive: true });
27578
27929
  let status = await spawnAsync(SYSTEM.tar(), ["-xf", archive, "-C", destination, ...members2]);
27579
27930
  if (status !== 0 && /\.(zip|nupkg)$/i.test(archive)) {
27580
27931
  const zip = archive.endsWith(".zip") ? archive : archive + ".zip";
27581
- if (zip !== archive) fs8.copyFileSync(archive, zip);
27932
+ if (zip !== archive) fs9.copyFileSync(archive, zip);
27582
27933
  status = await spawnAsync(
27583
27934
  SYSTEM.powershell(),
27584
27935
  scriptArgs("expand-archive.ps1", ["-Archive", zip, "-Destination", destination])
@@ -27587,8 +27938,8 @@ async function extractArchive(archive, destination, members2 = []) {
27587
27938
  if (status !== 0) throw new Error("Could not extract " + archive);
27588
27939
  }
27589
27940
  function findFile(root, name, maxDepth = 4) {
27590
- if (maxDepth < 0 || !fs8.existsSync(root)) return null;
27591
- const entries2 = fs8.readdirSync(root, { withFileTypes: true });
27941
+ if (maxDepth < 0 || !fs9.existsSync(root)) return null;
27942
+ const entries2 = fs9.readdirSync(root, { withFileTypes: true });
27592
27943
  for (const entry of entries2)
27593
27944
  if (entry.isFile() && entry.name.toLowerCase() === name.toLowerCase()) return path12.join(root, entry.name);
27594
27945
  for (const entry of entries2)
@@ -27600,7 +27951,7 @@ function findFile(root, name, maxDepth = 4) {
27600
27951
  }
27601
27952
 
27602
27953
  // src/shared/download/downloader.ts
27603
- import fs9 from "node:fs";
27954
+ import fs10 from "node:fs";
27604
27955
  import path13 from "node:path";
27605
27956
  import crypto2 from "node:crypto";
27606
27957
  import { Readable, Transform } from "node:stream";
@@ -27620,15 +27971,15 @@ var Downloader = class {
27620
27971
  */
27621
27972
  async file(url2, destination, expected = null) {
27622
27973
  const sums = typeof expected === "string" || expected === null ? { sha256: expected } : expected;
27623
- if (this.requireChecksum && !sums.sha256?.trim() && !sums.sha512?.trim()) {
27974
+ if (this.requireChecksum && !sums.sha256?.trim() && !sums.sha512?.trim() && !sums.sha1?.trim() && !sums.verify) {
27624
27975
  throw new Error(
27625
27976
  "Refusing to download " + path13.basename(destination) + " (" + url2 + "): no checksum is published for it, and downloads.requireChecksum is on. Turn that setting off to allow downloads that cannot be verified."
27626
27977
  );
27627
27978
  }
27628
27979
  const response = await fetchRetry(url2, {}, 3, 20 * 60 * 1e3);
27629
27980
  if (!response.body) throw new Error("Empty response for " + url2);
27630
- fs9.mkdirSync(path13.dirname(destination), { recursive: true });
27631
- const checks = ["sha256", "sha512"].flatMap((kind) => {
27981
+ fs10.mkdirSync(path13.dirname(destination), { recursive: true });
27982
+ const checks = ["sha256", "sha512", "sha1"].flatMap((kind) => {
27632
27983
  const want = sums[kind]?.trim().toLowerCase();
27633
27984
  return want ? [{ want, hash: crypto2.createHash(kind) }] : [];
27634
27985
  });
@@ -27657,12 +28008,13 @@ var Downloader = class {
27657
28008
  });
27658
28009
  const partial2 = destination + ".part";
27659
28010
  try {
27660
- await pipeline(Readable.fromWeb(response.body), tap, fs9.createWriteStream(partial2));
28011
+ await pipeline(Readable.fromWeb(response.body), tap, fs10.createWriteStream(partial2));
27661
28012
  if (checks.some((c) => c.hash.digest("hex") !== c.want)) throw new Error("Checksum mismatch for " + url2);
27662
- fs9.rmSync(destination, { force: true });
27663
- fs9.renameSync(partial2, destination);
28013
+ if (sums.verify) await sums.verify(partial2);
28014
+ fs10.rmSync(destination, { force: true });
28015
+ fs10.renameSync(partial2, destination);
27664
28016
  } finally {
27665
- fs9.rmSync(partial2, { force: true });
28017
+ fs10.rmSync(partial2, { force: true });
27666
28018
  }
27667
28019
  }
27668
28020
  /**
@@ -27673,7 +28025,12 @@ var Downloader = class {
27673
28025
  const work = stagingFolder(destination);
27674
28026
  try {
27675
28027
  const archive = path13.join(work, options.fileName ?? path13.basename(new URL(url2).pathname));
27676
- await this.file(url2, archive, { sha256: options.sha256, sha512: options.sha512 });
28028
+ await this.file(url2, archive, {
28029
+ sha256: options.sha256,
28030
+ sha512: options.sha512,
28031
+ sha1: options.sha1,
28032
+ ...options.verify ? { verify: options.verify } : {}
28033
+ });
27677
28034
  const extracted = path13.join(work, "x");
27678
28035
  await extractArchive(archive, extracted, options.members);
27679
28036
  let root = extracted;
@@ -27764,7 +28121,7 @@ var githubAssetFromPage = async (repo, pattern, searchOlder) => {
27764
28121
 
27765
28122
  // src/guest/runtime/session.ts
27766
28123
  var session = JSON.parse(
27767
- fs10.readFileSync(path14.join(launchDir, "session.json"), "utf8").replace(/^\uFEFF/, "")
28124
+ fs11.readFileSync(path14.join(launchDir, "session.json"), "utf8").replace(/^\uFEFF/, "")
27768
28125
  );
27769
28126
  downloader.requireChecksum = session.downloads?.requireChecksum === true;
27770
28127
  var workspace = process.env.AGENT_WORKSPACE ?? session.workspace;
@@ -27795,7 +28152,7 @@ function startRelays() {
27795
28152
  }
27796
28153
 
27797
28154
  // src/guest/audit/process-audit.ts
27798
- import fs12 from "node:fs";
28155
+ import fs13 from "node:fs";
27799
28156
  import path16 from "node:path";
27800
28157
  import { spawnSync } from "node:child_process";
27801
28158
 
@@ -27877,12 +28234,12 @@ function parseProcessEvents(xml, attribution) {
27877
28234
  }
27878
28235
 
27879
28236
  // src/guest/runtime/fs.ts
27880
- import fs11 from "node:fs";
28237
+ import fs12 from "node:fs";
27881
28238
  function exists(p) {
27882
- return fs11.existsSync(p);
28239
+ return fs12.existsSync(p);
27883
28240
  }
27884
28241
  function mkdirp(p) {
27885
- fs11.mkdirSync(p, { recursive: true });
28242
+ fs12.mkdirSync(p, { recursive: true });
27886
28243
  return p;
27887
28244
  }
27888
28245
 
@@ -27917,7 +28274,7 @@ function startProcessCollector(roots = () => []) {
27917
28274
  const { lines, last: newest } = parseProcessEvents(r.stdout ?? "", { attributor, roots: roots() });
27918
28275
  if (newest) last = newest;
27919
28276
  if (lines.length)
27920
- fs12.writeFileSync(
28277
+ fs13.writeFileSync(
27921
28278
  path16.join(mkdirp(run.auditDir), Date.now() + "-" + process.pid + ".jsonl"),
27922
28279
  lines.join("\n") + "\n"
27923
28280
  );
@@ -27960,7 +28317,68 @@ function safely(what, work) {
27960
28317
  }
27961
28318
 
27962
28319
  // src/guest/runtime/secrets.ts
27963
- import fs13 from "node:fs";
28320
+ import fs14 from "node:fs";
28321
+
28322
+ // src/shared/accounts/payloads.ts
28323
+ var KB = 1024;
28324
+ var base643 = (maxBytes) => external_exports.string().min(4).max(maxBytes).regex(/^[A-Za-z0-9+/]+={0,2}$/);
28325
+ var secretText = (max) => external_exports.string().min(1).max(max).regex(/^[^\r\n]+$/);
28326
+ var EpicPayloadSchema = external_exports.strictObject({
28327
+ data: external_exports.string().min(16).max(16384).regex(/^[A-Za-z0-9+/=_-]+$/)
28328
+ });
28329
+ var SteamPayloadSchema = external_exports.strictObject({
28330
+ account: external_exports.string().regex(/^[A-Za-z0-9_]{1,64}$/),
28331
+ configVdf: external_exports.string().min(1).max(256 * KB),
28332
+ sentries: external_exports.array(external_exports.strictObject({ name: external_exports.string().regex(/^ssfn\d{1,40}$/), base64: base643(64 * KB) })).max(4),
28333
+ /** Reserved for the Steam client's own login (very likely not portable between Windows users). */
28334
+ client: base643(256 * KB).optional()
28335
+ });
28336
+ var UnityPayloadSchema = external_exports.strictObject({
28337
+ ulf: external_exports.string().min(1).max(128 * KB).optional(),
28338
+ email: external_exports.string().email().max(256).optional(),
28339
+ password: secretText(1024).optional(),
28340
+ serial: secretText(64).optional()
28341
+ });
28342
+ var CfxPayloadSchema = external_exports.strictObject({
28343
+ licenseKey: external_exports.string().max(256).regex(/^cfxk_[A-Za-z0-9_]+$/),
28344
+ steamWebApiKey: external_exports.string().regex(/^[A-F0-9]{32}$/).optional()
28345
+ });
28346
+ var KeystorePayloadSchema = external_exports.strictObject({
28347
+ fileName: external_exports.string().regex(/^[A-Za-z0-9._-]{1,100}\.(jks|keystore|p12)$/i),
28348
+ jksBase64: base643(256 * KB),
28349
+ storePassword: secretText(1024),
28350
+ keyAlias: secretText(256),
28351
+ keyPassword: secretText(1024)
28352
+ });
28353
+ var PlayPayloadSchema = external_exports.strictObject({
28354
+ serviceAccountJson: external_exports.string().min(2).max(64 * KB).refine((text) => {
28355
+ try {
28356
+ const parsed = JSON.parse(text);
28357
+ return typeof parsed === "object" && parsed !== null && parsed.type === "service_account";
28358
+ } catch {
28359
+ return false;
28360
+ }
28361
+ }, 'not a Google service account key (its "type" is not "service_account")')
28362
+ });
28363
+ var ExpoPayloadSchema = external_exports.strictObject({
28364
+ token: external_exports.string().regex(/^[A-Za-z0-9_-]{8,512}$/)
28365
+ });
28366
+ var AppstorePayloadSchema = external_exports.strictObject({
28367
+ issuerId: external_exports.string().uuid(),
28368
+ keyId: external_exports.string().regex(/^[A-Z0-9]{10}$/),
28369
+ p8: external_exports.string().max(8 * KB).regex(/^-----BEGIN PRIVATE KEY-----\r?\n[A-Za-z0-9+/=\r\n]+-----END PRIVATE KEY-----\s*$/)
28370
+ });
28371
+ var ServiceAccountsSchema = external_exports.strictObject({
28372
+ epic: EpicPayloadSchema.optional(),
28373
+ steam: SteamPayloadSchema.optional(),
28374
+ unity: UnityPayloadSchema.optional(),
28375
+ cfx: CfxPayloadSchema.optional(),
28376
+ keystore: KeystorePayloadSchema.optional(),
28377
+ play: PlayPayloadSchema.optional(),
28378
+ expo: ExpoPayloadSchema.optional(),
28379
+ appstore: AppstorePayloadSchema.optional()
28380
+ });
28381
+ var LaunchIdSchema = external_exports.string().regex(/^[A-Za-z0-9-]{1,64}$/);
27964
28382
 
27965
28383
  // src/shared/github/token.ts
27966
28384
  var MIN_LENGTH = 20;
@@ -27985,6 +28403,8 @@ var SecretsFileSchema = external_exports.strictObject({
27985
28403
  wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional(),
27986
28404
  /** The GitHub token you saved for sandboxes (github.shareToken), only with git access "full". */
27987
28405
  githubToken: GithubTokenSchema.optional(),
28406
+ /** Your saved service sign-ins (accounts.<kind>.share): each goes to its tool's own files at boot. */
28407
+ serviceAccounts: ServiceAccountsSchema.optional(),
27988
28408
  /** projects.liveFolders "hcs": this launch's key for signed live-folder requests (live.ts). */
27989
28409
  liveFoldersKey: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
27990
28410
  });
@@ -28015,12 +28435,12 @@ function takeSecrets(id) {
28015
28435
  const file3 = run.secretFile(id);
28016
28436
  let text;
28017
28437
  try {
28018
- if (fs13.statSync(file3).size > MAX_BYTES) throw new Error("too big");
28019
- text = fs13.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
28438
+ if (fs14.statSync(file3).size > MAX_BYTES) throw new Error("too big");
28439
+ text = fs14.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
28020
28440
  } catch {
28021
28441
  return {};
28022
28442
  } finally {
28023
- fs13.rmSync(file3, { force: true });
28443
+ fs14.rmSync(file3, { force: true });
28024
28444
  }
28025
28445
  try {
28026
28446
  const parsed = SecretsFileSchema.safeParse(JSON.parse(text));
@@ -28056,15 +28476,15 @@ function withRequestSecrets(req) {
28056
28476
  }
28057
28477
 
28058
28478
  // src/guest/daemon/daemon.ts
28059
- import fs58 from "node:fs";
28479
+ import fs67 from "node:fs";
28060
28480
 
28061
28481
  // src/guest/setup/claude-mem.ts
28062
- import fs15 from "node:fs";
28482
+ import fs16 from "node:fs";
28063
28483
  import os4 from "node:os";
28064
28484
  import path19 from "node:path";
28065
28485
 
28066
28486
  // src/guest/runtime/process.ts
28067
- import fs14 from "node:fs";
28487
+ import fs15 from "node:fs";
28068
28488
  import os3 from "node:os";
28069
28489
  import path18 from "node:path";
28070
28490
  import { spawnSync as spawnSync2 } from "node:child_process";
@@ -28093,24 +28513,24 @@ function scriptOutput(name, args = [], options = {}) {
28093
28513
  return execOutput(SYSTEM.powershell(), scriptArgs(name, args), options);
28094
28514
  }
28095
28515
  function runScriptWithJson(name, param, data, args = []) {
28096
- const dir = fs14.mkdtempSync(path18.join(os3.tmpdir(), "sbx-"));
28516
+ const dir = fs15.mkdtempSync(path18.join(os3.tmpdir(), "sbx-"));
28097
28517
  const file3 = path18.join(dir, "input.json");
28098
28518
  try {
28099
- fs14.writeFileSync(file3, JSON.stringify(data), "utf8");
28519
+ fs15.writeFileSync(file3, JSON.stringify(data), "utf8");
28100
28520
  runScript(name, ["-" + param, file3, ...args]);
28101
28521
  } finally {
28102
- fs14.rmSync(dir, { recursive: true, force: true });
28522
+ fs15.rmSync(dir, { recursive: true, force: true });
28103
28523
  }
28104
28524
  }
28105
28525
  function robocopy(from, to, files = []) {
28106
28526
  if (!isWin) {
28107
28527
  if (!files.length) {
28108
- fs14.cpSync(from, to, { recursive: true });
28528
+ fs15.cpSync(from, to, { recursive: true });
28109
28529
  return;
28110
28530
  }
28111
- fs14.mkdirSync(to, { recursive: true });
28112
- for (const f of files.filter((f2) => fs14.existsSync(path18.join(from, f2))))
28113
- fs14.copyFileSync(path18.join(from, f), path18.join(to, f));
28531
+ fs15.mkdirSync(to, { recursive: true });
28532
+ for (const f of files.filter((f2) => fs15.existsSync(path18.join(from, f2))))
28533
+ fs15.copyFileSync(path18.join(from, f), path18.join(to, f));
28114
28534
  return;
28115
28535
  }
28116
28536
  const what = files.length ? files : ["/E"];
@@ -28168,12 +28588,12 @@ var claudeMemEnabled = () => session.claudeProfile.syncClaudeMem && !dryRun;
28168
28588
  var databaseFingerprint = (dir) => {
28169
28589
  const parts2 = [];
28170
28590
  const walk = (folder) => {
28171
- for (const entry of fs15.readdirSync(folder, { withFileTypes: true })) {
28591
+ for (const entry of fs16.readdirSync(folder, { withFileTypes: true })) {
28172
28592
  const full = path19.join(folder, entry.name);
28173
28593
  if (entry.isDirectory()) walk(full);
28174
28594
  else if (entry.isFile() && /\.(db|sqlite3?)(-wal)?$/i.test(entry.name)) {
28175
28595
  try {
28176
- const s = fs15.statSync(full);
28596
+ const s = fs16.statSync(full);
28177
28597
  parts2.push(full + ":" + s.size + ":" + s.mtimeMs);
28178
28598
  } catch {
28179
28599
  }
@@ -28187,33 +28607,33 @@ var lastSaved = null;
28187
28607
  var SQLITE_HEADER = "SQLite format 3\0";
28188
28608
  var looksLikeSqlite = (file3) => {
28189
28609
  if (!exists(file3)) return true;
28190
- const fd = fs15.openSync(file3, "r");
28610
+ const fd = fs16.openSync(file3, "r");
28191
28611
  try {
28192
28612
  const head = Buffer.alloc(16);
28193
- return fs15.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER;
28613
+ return fs16.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER;
28194
28614
  } finally {
28195
- fs15.closeSync(fd);
28615
+ fs16.closeSync(fd);
28196
28616
  }
28197
28617
  };
28198
28618
  var MAX_BACKUPS = 3;
28199
28619
  var BACKUP_EVERY_MS = 6 * 3600 * 1e3;
28200
28620
  var keepBackup = (previous, dir) => {
28201
28621
  if (!exists(previous)) return;
28202
- const backups = exists(dir) ? fs15.readdirSync(dir).filter((n) => /^\d{13}$/.test(n)).sort() : [];
28622
+ const backups = exists(dir) ? fs16.readdirSync(dir).filter((n) => /^\d{13}$/.test(n)).sort() : [];
28203
28623
  const newest = Number(backups[backups.length - 1] ?? 0);
28204
28624
  if (Date.now() - newest < BACKUP_EVERY_MS) {
28205
- fs15.rmSync(previous, { recursive: true, force: true });
28625
+ fs16.rmSync(previous, { recursive: true, force: true });
28206
28626
  return;
28207
28627
  }
28208
- fs15.renameSync(previous, path19.join(mkdirp(dir), String(Date.now())));
28628
+ fs16.renameSync(previous, path19.join(mkdirp(dir), String(Date.now())));
28209
28629
  for (const old of [...backups, String(Date.now())].slice(0, -MAX_BACKUPS))
28210
- fs15.rmSync(path19.join(dir, old), { recursive: true, force: true });
28630
+ fs16.rmSync(path19.join(dir, old), { recursive: true, force: true });
28211
28631
  };
28212
28632
  function saveClaudeMem() {
28213
28633
  if (!claudeMemEnabled() || !exists(claudeMemPaths.local)) return;
28214
28634
  const { store: store2, local } = claudeMemPaths;
28215
- const fingerprint2 = databaseFingerprint(local);
28216
- if (fingerprint2 === lastSaved && exists(store2)) return;
28635
+ const fingerprint3 = databaseFingerprint(local);
28636
+ if (fingerprint3 === lastSaved && exists(store2)) return;
28217
28637
  if (!looksLikeSqlite(path19.join(local, "claude-mem.db"))) {
28218
28638
  warn(
28219
28639
  "claude-mem: the local database does not look valid, so it was not saved over the stored copy (" + local + ")."
@@ -28222,22 +28642,22 @@ function saveClaudeMem() {
28222
28642
  }
28223
28643
  const incoming = store2 + ".incoming";
28224
28644
  const previous = store2 + ".previous";
28225
- fs15.rmSync(incoming, { recursive: true, force: true });
28645
+ fs16.rmSync(incoming, { recursive: true, force: true });
28226
28646
  copyTreeTolerant(local, incoming, (name) => /\.(pid|lock)$|-journal$|-shm$/i.test(name));
28227
- fs15.rmSync(previous, { recursive: true, force: true });
28228
- if (exists(store2)) fs15.renameSync(store2, previous);
28647
+ fs16.rmSync(previous, { recursive: true, force: true });
28648
+ if (exists(store2)) fs16.renameSync(store2, previous);
28229
28649
  try {
28230
- fs15.renameSync(incoming, store2);
28650
+ fs16.renameSync(incoming, store2);
28231
28651
  } catch (e) {
28232
- if (exists(previous)) fs15.renameSync(previous, store2);
28652
+ if (exists(previous)) fs16.renameSync(previous, store2);
28233
28653
  throw e;
28234
28654
  }
28235
28655
  keepBackup(previous, store2 + ".backups");
28236
- lastSaved = fingerprint2;
28656
+ lastSaved = fingerprint3;
28237
28657
  }
28238
28658
 
28239
28659
  // src/guest/agents/local-state.ts
28240
- import fs16 from "node:fs";
28660
+ import fs17 from "node:fs";
28241
28661
  import path21 from "node:path";
28242
28662
 
28243
28663
  // src/guest/agents/agent-files.ts
@@ -28278,32 +28698,32 @@ function agentLocalStates() {
28278
28698
  function localStateVars() {
28279
28699
  return Object.fromEntries(agentLocalStates().map((s) => [s.env, s.local]));
28280
28700
  }
28281
- var databaseFiles = (dir, keep) => exists(dir) ? fs16.readdirSync(dir, { withFileTypes: true }).flatMap((e) => e.isFile() && keep(e.name) ? [e.name] : []) : [];
28701
+ var databaseFiles = (dir, keep) => exists(dir) ? fs17.readdirSync(dir, { withFileTypes: true }).flatMap((e) => e.isFile() && keep(e.name) ? [e.name] : []) : [];
28282
28702
  var looksLikeSqlite2 = (file3) => {
28283
- const fd = fs16.openSync(file3, "r");
28703
+ const fd = fs17.openSync(file3, "r");
28284
28704
  try {
28285
28705
  const head = Buffer.alloc(16);
28286
- return fs16.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER2;
28706
+ return fs17.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER2;
28287
28707
  } finally {
28288
- fs16.closeSync(fd);
28708
+ fs17.closeSync(fd);
28289
28709
  }
28290
28710
  };
28291
28711
  var copyFiles = (from, to, names) => {
28292
- fs16.rmSync(to, { recursive: true, force: true });
28712
+ fs17.rmSync(to, { recursive: true, force: true });
28293
28713
  mkdirp(to);
28294
- for (const name of names) fs16.copyFileSync(path21.join(from, name), path21.join(to, name));
28714
+ for (const name of names) fs17.copyFileSync(path21.join(from, name), path21.join(to, name));
28295
28715
  };
28296
28716
  var swapIn = (incoming, store2) => {
28297
28717
  const previous = store2 + ".previous";
28298
- fs16.rmSync(previous, { recursive: true, force: true });
28299
- if (exists(store2)) fs16.renameSync(store2, previous);
28718
+ fs17.rmSync(previous, { recursive: true, force: true });
28719
+ if (exists(store2)) fs17.renameSync(store2, previous);
28300
28720
  try {
28301
- fs16.renameSync(incoming, store2);
28721
+ fs17.renameSync(incoming, store2);
28302
28722
  } catch (e) {
28303
- if (exists(previous)) fs16.renameSync(previous, store2);
28723
+ if (exists(previous)) fs17.renameSync(previous, store2);
28304
28724
  throw e;
28305
28725
  }
28306
- fs16.rmSync(previous, { recursive: true, force: true });
28726
+ fs17.rmSync(previous, { recursive: true, force: true });
28307
28727
  };
28308
28728
  function held(s) {
28309
28729
  if (!isWin) return false;
@@ -28312,7 +28732,7 @@ function held(s) {
28312
28732
  );
28313
28733
  }
28314
28734
  var fingerprint = (dir) => databaseFiles(dir, isCopyableDatabaseFile).sort().map((n) => {
28315
- const st = fs16.statSync(path21.join(dir, n));
28735
+ const st = fs17.statSync(path21.join(dir, n));
28316
28736
  return n + ":" + st.size + ":" + st.mtimeMs;
28317
28737
  }).join("|");
28318
28738
  var saved = /* @__PURE__ */ new Map();
@@ -28331,7 +28751,7 @@ function snapshotWhileRunning(s, print) {
28331
28751
  return;
28332
28752
  }
28333
28753
  const incoming = s.store + ".incoming";
28334
- fs16.rmSync(incoming, { recursive: true, force: true });
28754
+ fs17.rmSync(incoming, { recursive: true, force: true });
28335
28755
  mkdirp(incoming);
28336
28756
  for (const name of databaseFiles(s.local, (n) => isCopyableDatabaseFile(n) && !/-wal$/i.test(n))) {
28337
28757
  const db = new sqlite.DatabaseSync(path21.join(s.local, name), { readOnly: true });
@@ -28378,7 +28798,7 @@ function saveLocalState() {
28378
28798
  }
28379
28799
 
28380
28800
  // src/guest/daemon/exec.ts
28381
- import { spawn as spawn5 } from "node:child_process";
28801
+ import { spawn as spawn6 } from "node:child_process";
28382
28802
 
28383
28803
  // src/guest/setup/environment.ts
28384
28804
  import path23 from "node:path";
@@ -28497,11 +28917,11 @@ function withRegistryPath(env) {
28497
28917
  }
28498
28918
 
28499
28919
  // src/guest/daemon/project-provisioner.ts
28500
- import fs50 from "node:fs";
28501
- import path64 from "node:path";
28920
+ import fs57 from "node:fs";
28921
+ import path71 from "node:path";
28502
28922
 
28503
28923
  // src/guest/boot/boot-env.ts
28504
- import fs17 from "node:fs";
28924
+ import fs18 from "node:fs";
28505
28925
  import path24 from "node:path";
28506
28926
 
28507
28927
  // src/guest/boot/project-env.ts
@@ -28535,18 +28955,18 @@ function baseEnvFor(boot, current = process.env) {
28535
28955
  var file2 = () => path24.join(localDir, "boot-env.json");
28536
28956
  function readBootEnv() {
28537
28957
  try {
28538
- return BootEnvSchema.safeParse(JSON.parse(fs17.readFileSync(file2(), "utf8"))).data ?? null;
28958
+ return BootEnvSchema.safeParse(JSON.parse(fs18.readFileSync(file2(), "utf8"))).data ?? null;
28539
28959
  } catch {
28540
28960
  return null;
28541
28961
  }
28542
28962
  }
28543
28963
 
28544
28964
  // src/guest/boot/guide.ts
28545
- import fs19 from "node:fs";
28965
+ import fs20 from "node:fs";
28546
28966
  import path27 from "node:path";
28547
28967
 
28548
28968
  // src/guest/apps/find-exe.ts
28549
- import fs18 from "node:fs";
28969
+ import fs19 from "node:fs";
28550
28970
  import path25 from "node:path";
28551
28971
  var MAX_DEPTH = 7;
28552
28972
  var MAX_ENTRIES = 5e4;
@@ -28562,7 +28982,7 @@ function findExe(root, exe) {
28562
28982
  for (const dir of queue) {
28563
28983
  let entries2;
28564
28984
  try {
28565
- entries2 = fs18.readdirSync(dir, { withFileTypes: true });
28985
+ entries2 = fs19.readdirSync(dir, { withFileTypes: true });
28566
28986
  } catch {
28567
28987
  continue;
28568
28988
  }
@@ -28605,7 +29025,7 @@ function installedRtk() {
28605
29025
  var BEGIN = "<!-- agent-sandbox:begin (generated every boot, do not edit) -->";
28606
29026
  var END = "<!-- agent-sandbox:end -->";
28607
29027
  var mirrorLine = () => {
28608
- const drives = (session.substDrives ?? []).filter((d) => fs19.existsSync(d.letter + ":\\"));
29028
+ const drives = (session.substDrives ?? []).filter((d) => fs20.existsSync(d.letter + ":\\"));
28609
29029
  if (!drives.length) return [];
28610
29030
  return [
28611
29031
  "- " + drives.map((d) => d.letter + ":").join(", ") + " = mapped folders at their PC paths (subst onto `" + drives.map((d) => d.target).join("`, `") + "`; real-path tools may print that form)."
@@ -28635,12 +29055,12 @@ function sandboxGuide(toolSummary, lan = "blocked", projects = [], addons = [])
28635
29055
  ].join("\n");
28636
29056
  }
28637
29057
  function upsertGuide(file3, guide) {
28638
- fs19.mkdirSync(path27.dirname(file3), { recursive: true });
28639
- const current = fs19.existsSync(file3) ? fs19.readFileSync(file3, "utf8") : "";
29058
+ fs20.mkdirSync(path27.dirname(file3), { recursive: true });
29059
+ const current = fs20.existsSync(file3) ? fs20.readFileSync(file3, "utf8") : "";
28640
29060
  const start = current.indexOf(BEGIN);
28641
29061
  const end = current.indexOf(END);
28642
29062
  const without = start >= 0 && end > start ? current.slice(0, start) + current.slice(end + END.length) : current;
28643
- fs19.writeFileSync(file3, without.trimEnd() + (without.trim() ? "\n\n" : "") + guide + "\n", "utf8");
29063
+ fs20.writeFileSync(file3, without.trimEnd() + (without.trim() ? "\n\n" : "") + guide + "\n", "utf8");
28644
29064
  }
28645
29065
  function managedClaudeMd() {
28646
29066
  return path27.join(
@@ -28651,7 +29071,7 @@ function managedClaudeMd() {
28651
29071
  var headroomRuns = () => {
28652
29072
  try {
28653
29073
  const file3 = path27.join(path27.dirname(managedClaudeMd()), "managed-settings.json");
28654
- const settings = JSON.parse(fs19.readFileSync(file3, "utf8"));
29074
+ const settings = JSON.parse(fs20.readFileSync(file3, "utf8"));
28655
29075
  return typeof settings.env?.ANTHROPIC_BASE_URL === "string";
28656
29076
  } catch {
28657
29077
  return false;
@@ -28668,21 +29088,21 @@ function addonLines() {
28668
29088
  function writeGuides(toolSummary, lan, projects = []) {
28669
29089
  const guide = sandboxGuide(toolSummary, lan, projects, addonLines());
28670
29090
  const managed = managedClaudeMd();
28671
- fs19.mkdirSync(path27.dirname(managed), { recursive: true });
28672
- fs19.writeFileSync(managed, guide + "\n", "utf8");
28673
- fs19.writeFileSync(path27.join(dataDir, "SANDBOX.md"), guide + "\n", "utf8");
29091
+ fs20.mkdirSync(path27.dirname(managed), { recursive: true });
29092
+ fs20.writeFileSync(managed, guide + "\n", "utf8");
29093
+ fs20.writeFileSync(path27.join(dataDir, "SANDBOX.md"), guide + "\n", "utf8");
28674
29094
  upsertGuide(path27.join(stateDir, "codex", "AGENTS.md"), guide);
28675
29095
  upsertGuide(path27.join(stateDir, "gemini", ".gemini", "GEMINI.md"), guide);
28676
29096
  removeGuide(path27.join(claudeDir, "CLAUDE.md"));
28677
29097
  return managed;
28678
29098
  }
28679
29099
  var removeGuide = (file3) => {
28680
- if (!fs19.existsSync(file3)) return;
28681
- const current = fs19.readFileSync(file3, "utf8");
29100
+ if (!fs20.existsSync(file3)) return;
29101
+ const current = fs20.readFileSync(file3, "utf8");
28682
29102
  const start = current.indexOf(BEGIN);
28683
29103
  const end = current.indexOf(END);
28684
29104
  if (start >= 0 && end > start)
28685
- fs19.writeFileSync(file3, (current.slice(0, start) + current.slice(end + END.length)).trim() + "\n", "utf8");
29105
+ fs20.writeFileSync(file3, (current.slice(0, start) + current.slice(end + END.length)).trim() + "\n", "utf8");
28686
29106
  };
28687
29107
 
28688
29108
  // src/guest/runtime/project-context.ts
@@ -28719,7 +29139,7 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
28719
29139
  }
28720
29140
 
28721
29141
  // src/guest/setup/hooks.ts
28722
- import fs20 from "node:fs";
29142
+ import fs21 from "node:fs";
28723
29143
  import path28 from "node:path";
28724
29144
  import { spawnSync as spawnSync3 } from "node:child_process";
28725
29145
  var commandFor = (file3) => {
@@ -28741,7 +29161,7 @@ function projectHooks(name, cwd) {
28741
29161
  var hooksOf = (stage, target) => {
28742
29162
  const dir = path28.join(target.root, stage);
28743
29163
  if (!exists(dir)) return [];
28744
- return fs20.readdirSync(dir).sort().flatMap((name) => {
29164
+ return fs21.readdirSync(dir).sort().flatMap((name) => {
28745
29165
  const command = commandFor(path28.join(dir, name));
28746
29166
  return command ? [{ name, command }] : [];
28747
29167
  });
@@ -28772,22 +29192,22 @@ async function runHooksAsync(stage, env, target) {
28772
29192
  }
28773
29193
 
28774
29194
  // src/guest/apps/app-installer.ts
28775
- import fs24 from "node:fs";
29195
+ import fs25 from "node:fs";
28776
29196
  import path33 from "node:path";
28777
29197
 
28778
29198
  // src/guest/toolchains/runtimes.ts
28779
29199
  import path29 from "node:path";
28780
29200
 
28781
29201
  // src/guest/toolchains/install.ts
28782
- import fs21 from "node:fs";
29202
+ import fs22 from "node:fs";
28783
29203
  async function downloadFile(url2, file3, sha256 = null) {
28784
29204
  const part = file3 + ".part";
28785
29205
  try {
28786
29206
  await downloader.file(url2, part, sha256);
28787
- fs21.rmSync(file3, { force: true });
28788
- fs21.renameSync(part, file3);
29207
+ fs22.rmSync(file3, { force: true });
29208
+ fs22.renameSync(part, file3);
28789
29209
  } finally {
28790
- fs21.rmSync(part, { force: true });
29210
+ fs22.rmSync(part, { force: true });
28791
29211
  }
28792
29212
  }
28793
29213
  async function installFromGithub(repo, pattern, o) {
@@ -28872,7 +29292,7 @@ async function setupUv(env) {
28872
29292
  }
28873
29293
 
28874
29294
  // src/guest/apps/after-install.ts
28875
- import fs22 from "node:fs";
29295
+ import fs23 from "node:fs";
28876
29296
  import path30 from "node:path";
28877
29297
  var SYSINTERNALS_TOOLS = [
28878
29298
  "Process Explorer",
@@ -28899,10 +29319,10 @@ async function afterInstall(entry, exe) {
28899
29319
  const mesa = tool("mesa", arch === "arm64" ? "arm64" : "x64");
28900
29320
  for (const dll of ["opengl32.dll", "libgallium_wgl.dll", "dxil.dll"]) {
28901
29321
  if (exists(path30.join(mesa, dll)) && !exists(path30.join(dir, dll)))
28902
- fs22.copyFileSync(path30.join(mesa, dll), path30.join(dir, dll));
29322
+ fs23.copyFileSync(path30.join(mesa, dll), path30.join(dir, dll));
28903
29323
  }
28904
29324
  }
28905
- if (entry.id === "godot" && !exists(path30.join(dir, "._sc_"))) fs22.writeFileSync(path30.join(dir, "._sc_"), "");
29325
+ if (entry.id === "godot" && !exists(path30.join(dir, "._sc_"))) fs23.writeFileSync(path30.join(dir, "._sc_"), "");
28906
29326
  if (entry.id === "sublime") mkdirp(path30.join(dir, "Data"));
28907
29327
  if (entry.id === "sysinternals") {
28908
29328
  for (const name of SYSINTERNALS_TOOLS) {
@@ -28940,11 +29360,19 @@ function shortcuts(apps) {
28940
29360
  runScriptWithJson("new-shortcuts.ps1", "ListFile", links);
28941
29361
  }
28942
29362
 
29363
+ // src/guest/apps/resolvers-gamedev.ts
29364
+ var GAMEDEV_RESOLVERS = {};
29365
+
29366
+ // src/guest/apps/resolvers-mobile.ts
29367
+ var MOBILE_RESOLVERS = {};
29368
+
28943
29369
  // src/guest/apps/resolvers.ts
28944
29370
  var sumFor = (sums, file3) => sums.split(/\r?\n/).map((l) => /^([0-9a-f]{64})\s+\*?(.+)$/i.exec(l.trim())).find((m) => m && m[2].trim().endsWith(file3))?.[1].toLowerCase() ?? null;
28945
29371
  var firstHash = (text) => /\b([0-9a-f]{64})\b/i.exec(text)?.[1].toLowerCase() ?? null;
28946
29372
  var stripV = (tag) => tag.replace(/^v/, "");
28947
29373
  var RESOLVERS = {
29374
+ ...GAMEDEV_RESOLVERS,
29375
+ ...MOBILE_RESOLVERS,
28948
29376
  sublime: async () => {
28949
29377
  const { latest_version: build } = await fetchJson(
28950
29378
  "https://www.sublimetext.com/updates/4/stable_update_check"
@@ -29066,7 +29494,7 @@ async function resolve(entry) {
29066
29494
  }
29067
29495
 
29068
29496
  // src/guest/apps/unpack.ts
29069
- import fs23 from "node:fs";
29497
+ import fs24 from "node:fs";
29070
29498
  import path32 from "node:path";
29071
29499
  var sevenZip = () => tool("apps", "7zip", "7z.exe");
29072
29500
  async function unpack(entry, file3, out, d) {
@@ -29080,7 +29508,7 @@ async function unpack(entry, file3, out, d) {
29080
29508
  switch (entry.unpack ?? "archive") {
29081
29509
  case "file": {
29082
29510
  mkdirp(out);
29083
- fs23.renameSync(file3, path32.join(out, /^\//.test(entry.exe) ? path32.basename(file3) : entry.exe));
29511
+ fs24.renameSync(file3, path32.join(out, /^\//.test(entry.exe) ? path32.basename(file3) : entry.exe));
29084
29512
  return;
29085
29513
  }
29086
29514
  case "nsis": {
@@ -29090,7 +29518,7 @@ async function unpack(entry, file3, out, d) {
29090
29518
  await execAsync(sevenZip(), ["x", "-y", "-o" + raw, file3], { stdio: "ignore" });
29091
29519
  const inner = findExe(raw, "/^app-64\\.7z$/");
29092
29520
  if (inner) await execAsync(sevenZip(), ["x", "-y", "-o" + out, inner], { stdio: "ignore" });
29093
- else fs23.renameSync(raw, out);
29521
+ else fs24.renameSync(raw, out);
29094
29522
  return;
29095
29523
  }
29096
29524
  case "msi": {
@@ -29182,7 +29610,7 @@ var AppInstaller = class {
29182
29610
  await downloader.file(d.url, file3, { sha256: d.sha256 ?? null });
29183
29611
  await unpack(entry, file3, out, d);
29184
29612
  }
29185
- fs24.writeFileSync(path33.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
29613
+ fs25.writeFileSync(path33.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
29186
29614
  moveIntoPlace(out, dest);
29187
29615
  } finally {
29188
29616
  safeRemove(work, path33.dirname(work));
@@ -29193,7 +29621,7 @@ var LOCKED_PYTHON = "3.13";
29193
29621
  async function installLocked(id, kind, out) {
29194
29622
  const lock = path33.join(launchDir, "sandbox", "addons", id);
29195
29623
  if (kind === "npm") {
29196
- for (const f of ["package.json", "package-lock.json"]) fs24.copyFileSync(path33.join(lock, f), path33.join(out, f));
29624
+ for (const f of ["package.json", "package-lock.json"]) fs25.copyFileSync(path33.join(lock, f), path33.join(out, f));
29197
29625
  const npmCli = path33.join(path33.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
29198
29626
  await execAsync(
29199
29627
  process.execPath,
@@ -29243,7 +29671,7 @@ async function setupApps(env, apps, o) {
29243
29671
  }
29244
29672
 
29245
29673
  // src/guest/toolchains/detect.ts
29246
- import fs25 from "node:fs";
29674
+ import fs26 from "node:fs";
29247
29675
  import path34 from "node:path";
29248
29676
 
29249
29677
  // src/core/detect/versions.ts
@@ -29328,6 +29756,16 @@ var MARKERS = {
29328
29756
  rust: ["Cargo.toml", "rust-toolchain", "rust-toolchain.toml"],
29329
29757
  msvc: ["*.vcxproj", "CMakePresets.json", "CMakeUserPresets.json"],
29330
29758
  unreal: ["*.uproject", "*.uplugin"],
29759
+ unity: ["ProjectVersion.txt"],
29760
+ godot: ["project.godot"],
29761
+ steam: ["steam_appid.txt", "steam_api64.dll", "steam_api.dll"],
29762
+ fivem: ["fxmanifest.lua", "__resource.lua"],
29763
+ // Decided from file contents (host/launch/hints): Gradle's com.android plugin, an AndroidManifest.xml deeper down,
29764
+ // <UseMaui>, a pubspec's flutter: section, react-native / expo in package.json.
29765
+ android: [],
29766
+ flutter: [],
29767
+ dart: [],
29768
+ reactNative: [],
29331
29769
  cpp: [
29332
29770
  "CMakeLists.txt",
29333
29771
  "Makefile",
@@ -29353,7 +29791,8 @@ var MARKERS = {
29353
29791
  "gradlew",
29354
29792
  ".java-version",
29355
29793
  ".sdkmanrc",
29356
- "*.java"
29794
+ "*.java",
29795
+ "*.kt"
29357
29796
  ],
29358
29797
  ruby: ["Gemfile", "*.gemspec", ".ruby-version", "*.rb"],
29359
29798
  php: ["composer.json", "artisan", ".php-version", "*.php"],
@@ -29377,7 +29816,7 @@ function workspaceEntries() {
29377
29816
  if (known) return known;
29378
29817
  const list = (dir) => {
29379
29818
  try {
29380
- return fs25.readdirSync(dir, { withFileTypes: true });
29819
+ return fs26.readdirSync(dir, { withFileTypes: true });
29381
29820
  } catch {
29382
29821
  return [];
29383
29822
  }
@@ -29397,7 +29836,7 @@ function versionFromFiles(files, parse5 = (t) => specFromVersionFile(t)) {
29397
29836
  for (const name of files) {
29398
29837
  const file3 = path34.join(projectWorkspace(), name);
29399
29838
  if (!exists(file3)) continue;
29400
- const spec = parse5(fs25.readFileSync(file3, "utf8"), name);
29839
+ const spec = parse5(fs26.readFileSync(file3, "utf8"), name);
29401
29840
  if (spec) return { spec, source: name };
29402
29841
  }
29403
29842
  return null;
@@ -29470,22 +29909,22 @@ var DatabaseServer = class {
29470
29909
  };
29471
29910
 
29472
29911
  // src/guest/databases/dynamodb.ts
29473
- import fs30 from "node:fs";
29912
+ import fs31 from "node:fs";
29474
29913
  import path37 from "node:path";
29475
29914
  import { spawn as spawn3 } from "node:child_process";
29476
29915
 
29477
29916
  // src/guest/toolchains/languages/java.ts
29478
- import fs28 from "node:fs";
29917
+ import fs29 from "node:fs";
29479
29918
  import path35 from "node:path";
29480
29919
 
29481
29920
  // src/guest/toolchains/version-cache.ts
29482
- import fs27 from "node:fs";
29921
+ import fs28 from "node:fs";
29483
29922
 
29484
29923
  // src/guest/toolchains/state-file.ts
29485
- import fs26 from "node:fs";
29924
+ import fs27 from "node:fs";
29486
29925
  function readState(file3, schema, empty) {
29487
29926
  try {
29488
- return schema.safeParse(JSON.parse(fs26.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""))).data ?? empty;
29927
+ return schema.safeParse(JSON.parse(fs27.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""))).data ?? empty;
29489
29928
  } catch {
29490
29929
  return empty;
29491
29930
  }
@@ -29520,7 +29959,7 @@ var VersionCache = class {
29520
29959
  return cached2.value;
29521
29960
  try {
29522
29961
  const value = await resolve2();
29523
- fs27.mkdirSync(toolsDir, { recursive: true });
29962
+ fs28.mkdirSync(toolsDir, { recursive: true });
29524
29963
  writeJsonAtomic(this.file(), { ...this.remembered(), [key2]: { value, at: Date.now() } });
29525
29964
  return value;
29526
29965
  } catch (e) {
@@ -29588,10 +30027,10 @@ var setupJdk = async (env, config2) => {
29588
30027
  };
29589
30028
  async function ensureJdk() {
29590
30029
  const root = tool("java");
29591
- const installed = exists(root) ? fs28.readdirSync(root).filter((d) => exists(path35.join(root, d, "bin", "java.exe"))).sort((a, b) => b.localeCompare(a, void 0, { numeric: true })) : [];
30030
+ const installed = exists(root) ? fs29.readdirSync(root).filter((d) => exists(path35.join(root, d, "bin", "java.exe"))).sort((a, b) => b.localeCompare(a, void 0, { numeric: true })) : [];
29592
30031
  if (installed.length) return path35.join(root, installed[0]);
29593
30032
  const scratch = emptyEnv();
29594
- await setupJdk(scratch, { enabled: true, version: "lts", maven: false, gradle: false });
30033
+ await setupJdk(scratch, { enabled: true, version: "lts", maven: false, gradle: false, kotlin: false });
29595
30034
  return scratch.vars.JAVA_HOME;
29596
30035
  }
29597
30036
  var setupMaven = async (env) => {
@@ -29635,7 +30074,7 @@ var setupGradle = async (env) => {
29635
30074
  });
29636
30075
  }
29637
30076
  const userHome = tool("gradle-home");
29638
- fs28.mkdirSync(userHome, { recursive: true });
30077
+ fs29.mkdirSync(userHome, { recursive: true });
29639
30078
  Object.assign(env.vars, {
29640
30079
  GRADLE_HOME: home,
29641
30080
  GRADLE_USER_HOME: userHome,
@@ -29665,7 +30104,7 @@ async function setupJava(env, config2) {
29665
30104
  }
29666
30105
 
29667
30106
  // src/guest/databases/server.ts
29668
- import fs29 from "node:fs";
30107
+ import fs30 from "node:fs";
29669
30108
  import path36 from "node:path";
29670
30109
  import { spawn as spawn2 } from "node:child_process";
29671
30110
  function dataFor(name) {
@@ -29674,15 +30113,15 @@ function dataFor(name) {
29674
30113
  async function startServer(name, exe, args, port) {
29675
30114
  if (await portOpen(port)) throw new Error("port " + port + " is already in use (change databases." + name + ".port)");
29676
30115
  const logFile2 = path36.join(logsDir, name + ".log");
29677
- const out = fs29.openSync(logFile2, "a");
30116
+ const out = fs30.openSync(logFile2, "a");
29678
30117
  spawn2(exe, args, { detached: true, stdio: ["ignore", out, out], windowsHide: true }).unref();
29679
- fs29.closeSync(out);
30118
+ fs30.closeSync(out);
29680
30119
  if (!await waitForPort(port, 60))
29681
30120
  throw new Error(name + " did not start listening on port " + port + "; see " + logFile2);
29682
30121
  }
29683
30122
  async function clearStaleLocks(dir, files, port) {
29684
30123
  if (await portOpen(port)) return;
29685
- for (const f of files) fs29.rmSync(path36.join(dir, f), { force: true });
30124
+ for (const f of files) fs30.rmSync(path36.join(dir, f), { force: true });
29686
30125
  }
29687
30126
  async function createOnce(data, marker, create) {
29688
30127
  if (exists(path36.join(data, marker))) return;
@@ -29769,13 +30208,13 @@ var DynamoServer = class extends DatabaseServer {
29769
30208
  );
29770
30209
  return;
29771
30210
  }
29772
- const out = fs30.openSync(path37.join(logsDir, "dynamodb-admin.log"), "a");
30211
+ const out = fs31.openSync(path37.join(logsDir, "dynamodb-admin.log"), "a");
29773
30212
  spawn3(
29774
30213
  process.execPath,
29775
30214
  [script, "--port", String(plan2.adminPort), "--dynamo-endpoint", endpoint, "--skip-default-credentials"],
29776
30215
  { detached: true, stdio: ["ignore", out, out], windowsHide: true, env: { ...process.env, ...aws } }
29777
30216
  ).unref();
29778
- fs30.closeSync(out);
30217
+ fs31.closeSync(out);
29779
30218
  if (!await waitForPort(plan2.adminPort, 30))
29780
30219
  throw new Error("dynamodb-admin did not start; see " + path37.join(logsDir, "dynamodb-admin.log"));
29781
30220
  env.summary.push(
@@ -29878,7 +30317,7 @@ var MysqlServer = class extends DatabaseServer {
29878
30317
  };
29879
30318
 
29880
30319
  // src/guest/databases/postgres.ts
29881
- import fs31 from "node:fs";
30320
+ import fs32 from "node:fs";
29882
30321
  import path40 from "node:path";
29883
30322
  function postgresData(version2) {
29884
30323
  return dataFor("postgres-" + version2.split(".")[0]);
@@ -29945,7 +30384,7 @@ var PostgresServer = class extends DatabaseServer {
29945
30384
  /** Every installed version's cluster shuts down cleanly through pg_ctl first. */
29946
30385
  async stop(plan2) {
29947
30386
  if (exists(tool("postgres"))) {
29948
- for (const version2 of fs31.readdirSync(tool("postgres"))) {
30387
+ for (const version2 of fs32.readdirSync(tool("postgres"))) {
29949
30388
  const data = postgresData(version2);
29950
30389
  const pgCtl = path40.join(tool("postgres", version2), "bin", "pg_ctl.exe");
29951
30390
  if (exists(path40.join(data, "postmaster.pid")) && exists(pgCtl))
@@ -30010,11 +30449,11 @@ async function setupDatabase(env, plan2) {
30010
30449
  }
30011
30450
 
30012
30451
  // src/guest/toolchains/tools/git.ts
30013
- import fs33 from "node:fs";
30452
+ import fs34 from "node:fs";
30014
30453
  import path43 from "node:path";
30015
30454
 
30016
30455
  // src/guest/runtime/csc.ts
30017
- import fs32 from "node:fs";
30456
+ import fs33 from "node:fs";
30018
30457
  import os6 from "node:os";
30019
30458
  import path42 from "node:path";
30020
30459
  import crypto3 from "node:crypto";
@@ -30035,7 +30474,7 @@ function sourceOf(name) {
30035
30474
  return path42.join(launchDir, "sandbox", "csharp", SOURCES[name]);
30036
30475
  }
30037
30476
  function sourceHash(name) {
30038
- return crypto3.createHash("sha256").update(fs32.readFileSync(sourceOf(name))).digest("hex").slice(0, 12);
30477
+ return crypto3.createHash("sha256").update(fs33.readFileSync(sourceOf(name))).digest("hex").slice(0, 12);
30039
30478
  }
30040
30479
  function ensureCompiled(name) {
30041
30480
  const exe = path42.join(os6.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
@@ -30076,7 +30515,7 @@ var installPortableGit = async (root) => {
30076
30515
  await downloader.file(asset.url, sfx, asset.sha256);
30077
30516
  await execAsync(sfx, ["-o" + root, "-y"], { stdio: "ignore" });
30078
30517
  } finally {
30079
- fs33.rmSync(sfx, { force: true });
30518
+ fs34.rmSync(sfx, { force: true });
30080
30519
  }
30081
30520
  };
30082
30521
  var installGuard = (env, access, realGit) => {
@@ -30085,13 +30524,13 @@ var installGuard = (env, access, realGit) => {
30085
30524
  if (duringSession() && (exists(path43.join(dir, "git.exe")) || exists(path43.join(dir, "git.cmd")))) {
30086
30525
  } else
30087
30526
  try {
30088
- fs33.copyFileSync(ensureCompiled("gitshim"), path43.join(dir, "git.exe"));
30089
- fs33.rmSync(path43.join(dir, "git.cmd"), { force: true });
30527
+ fs34.copyFileSync(ensureCompiled("gitshim"), path43.join(dir, "git.exe"));
30528
+ fs34.rmSync(path43.join(dir, "git.cmd"), { force: true });
30090
30529
  } catch (e) {
30091
30530
  warn("git guard: falling back to git.cmd (" + errMsg(e) + ")");
30092
- fs33.writeFileSync(path43.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
30531
+ fs34.writeFileSync(path43.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
30093
30532
  }
30094
- fs33.writeFileSync(
30533
+ fs34.writeFileSync(
30095
30534
  path43.join(dir, "bashenv.sh"),
30096
30535
  'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n'
30097
30536
  );
@@ -30106,7 +30545,7 @@ var installGuard = (env, access, realGit) => {
30106
30545
  if (access === "readonly") {
30107
30546
  const hooks = mkdirp(path43.join(dir, "hooks"));
30108
30547
  for (const hook of BLOCKED_HOOKS)
30109
- fs33.writeFileSync(
30548
+ fs34.writeFileSync(
30110
30549
  path43.join(hooks, hook),
30111
30550
  '#!/bin/sh\necho "git is read-only in this sandbox: ' + hook + ' refused." >&2\nexit 1\n'
30112
30551
  );
@@ -30123,9 +30562,9 @@ var pointAtOwnCertificates = (root) => {
30123
30562
  const config2 = path43.join(root, "etc", "gitconfig");
30124
30563
  const bundle = path43.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
30125
30564
  if (!exists(config2) || !exists(bundle)) return;
30126
- const text = fs33.readFileSync(config2, "utf8");
30565
+ const text = fs34.readFileSync(config2, "utf8");
30127
30566
  const fixed = text.replace(/^(\s*sslCAInfo\s*=\s*).*$/gim, (_m, key2) => key2 + posix(bundle));
30128
- if (fixed !== text) fs33.writeFileSync(config2, fixed);
30567
+ if (fixed !== text) fs34.writeFileSync(config2, fixed);
30129
30568
  };
30130
30569
  async function setupGit(env, hostCopy, refresh, access) {
30131
30570
  const root = tool("git");
@@ -30172,7 +30611,7 @@ async function setupGit(env, hostCopy, refresh, access) {
30172
30611
  }
30173
30612
 
30174
30613
  // src/guest/toolchains/languages/go.ts
30175
- import fs34 from "node:fs";
30614
+ import fs35 from "node:fs";
30176
30615
  import path44 from "node:path";
30177
30616
 
30178
30617
  // src/guest/toolchains/package-ledger.ts
@@ -30193,12 +30632,12 @@ var PackageLedger = class {
30193
30632
  * Installs each package that is not installed yet (group e.g. "npm@22.11.0"). One failing package is reported and
30194
30633
  * skipped; it is tried again next boot.
30195
30634
  */
30196
- async installOnce(env, group, packages, install) {
30635
+ async installOnce(env, group, packages, install2) {
30197
30636
  const todo = packages.filter((p) => !this.has(group, p));
30198
30637
  for (const pkg of todo) {
30199
30638
  try {
30200
30639
  log("Installing " + pkg + " (" + group + ") ...");
30201
- await install(pkg);
30640
+ await install2(pkg);
30202
30641
  this.mark(group, pkg);
30203
30642
  } catch (e) {
30204
30643
  warn(
@@ -30214,8 +30653,8 @@ var PackageLedger = class {
30214
30653
  }
30215
30654
  };
30216
30655
  var packageLedger = new PackageLedger();
30217
- function installOnce(env, group, packages, install) {
30218
- return packageLedger.installOnce(env, group, packages, install);
30656
+ function installOnce(env, group, packages, install2) {
30657
+ return packageLedger.installOnce(env, group, packages, install2);
30219
30658
  }
30220
30659
 
30221
30660
  // src/guest/toolchains/languages/go.ts
@@ -30250,7 +30689,7 @@ async function setupGo(env, config2) {
30250
30689
  GOTOOLCHAIN: "auto",
30251
30690
  GOTELEMETRY: "off"
30252
30691
  };
30253
- fs34.mkdirSync(vars.GOBIN, { recursive: true });
30692
+ fs35.mkdirSync(vars.GOBIN, { recursive: true });
30254
30693
  Object.assign(env.vars, vars);
30255
30694
  env.prepend.push(path44.join(root, "bin"), vars.GOBIN);
30256
30695
  const go = path44.join(root, "bin", "go.exe");
@@ -30264,7 +30703,7 @@ async function setupGo(env, config2) {
30264
30703
  }
30265
30704
 
30266
30705
  // src/guest/toolchains/tools/cli.ts
30267
- import fs35 from "node:fs";
30706
+ import fs36 from "node:fs";
30268
30707
  import path45 from "node:path";
30269
30708
 
30270
30709
  // src/guest/toolchains/catalogue.ts
@@ -30321,7 +30760,7 @@ function deliveredGhConfigDir() {
30321
30760
  var GH_NOTE = " (log in once with: gh auth login --web --insecure-storage; it is kept between sandboxes)";
30322
30761
  function warnKeyringLogin() {
30323
30762
  try {
30324
- const hosts = fs35.readFileSync(path45.join(ghConfigDir(), "hosts.yml"), "utf8");
30763
+ const hosts = fs36.readFileSync(path45.join(ghConfigDir(), "hosts.yml"), "utf8");
30325
30764
  if (/^\s*user:/m.test(hosts) && !/oauth_token:/.test(hosts))
30326
30765
  warn(
30327
30766
  "gh: the GitHub login from an earlier sandbox was kept in Windows Credential Manager, which is wiped with each sandbox. Log in again with: gh auth login --web --insecure-storage (then it lasts)."
@@ -30342,8 +30781,8 @@ var shimOpenssl = (env) => {
30342
30781
  return;
30343
30782
  }
30344
30783
  const shims = mkdirp(tool("shims"));
30345
- fs35.copyFileSync(ensureCompiled("openssl"), path45.join(shims, "openssl.exe"));
30346
- fs35.rmSync(path45.join(shims, "openssl.cmd"), { force: true });
30784
+ fs36.copyFileSync(ensureCompiled("openssl"), path45.join(shims, "openssl.exe"));
30785
+ fs36.rmSync(path45.join(shims, "openssl.cmd"), { force: true });
30347
30786
  env.prepend.push(shims);
30348
30787
  env.summary.push("openssl: Git for Windows' copy");
30349
30788
  };
@@ -30390,12 +30829,12 @@ async function setupCli(env, settings, gitAccess, refresh = false) {
30390
30829
  }
30391
30830
 
30392
30831
  // src/guest/toolchains/managers.ts
30393
- import fs36 from "node:fs";
30832
+ import fs37 from "node:fs";
30394
30833
  import path46 from "node:path";
30395
30834
  function voltaPins() {
30396
30835
  try {
30397
30836
  const pkg = JSON.parse(
30398
- fs36.readFileSync(path46.join(projectWorkspace(), "package.json"), "utf8").replace(/^\uFEFF/, "")
30837
+ fs37.readFileSync(path46.join(projectWorkspace(), "package.json"), "utf8").replace(/^\uFEFF/, "")
30399
30838
  );
30400
30839
  return Object.fromEntries(
30401
30840
  Object.entries(pkg.volta ?? {}).filter(
@@ -30428,7 +30867,7 @@ async function setupVolta(env) {
30428
30867
  }
30429
30868
  for (const shim3 of ["node", "npm", "npx", "pnpm", "pnpx", "yarn", "yarnpkg"]) {
30430
30869
  const target = path46.join(dir, shim3 + ".exe");
30431
- if (!exists(target)) fs36.copyFileSync(path46.join(dir, "volta-shim.exe"), target);
30870
+ if (!exists(target)) fs37.copyFileSync(path46.join(dir, "volta-shim.exe"), target);
30432
30871
  }
30433
30872
  const home = mkdirp(tool("volta-home"));
30434
30873
  const shims = mkdirp(path46.join(home, "bin"));
@@ -30516,7 +30955,7 @@ var setupFlexBison = async (env) => {
30516
30955
  };
30517
30956
 
30518
30957
  // src/guest/toolchains/native/dotnet.ts
30519
- import fs37 from "node:fs";
30958
+ import fs38 from "node:fs";
30520
30959
  import path48 from "node:path";
30521
30960
  var DotnetMarkerSchema = external_exports.record(external_exports.string(), external_exports.boolean());
30522
30961
  async function setupDotnet(env, config2, refresh) {
@@ -30533,7 +30972,7 @@ async function setupDotnet(env, config2, refresh) {
30533
30972
  const installs = [
30534
30973
  ...config2.channels.map((c) => ["channel:" + c, ["-Channel", c]]),
30535
30974
  ...exists(globalJson) ? [
30536
- ["global.json:" + fs37.readFileSync(globalJson, "utf8").replace(/\s+/g, ""), ["-JSonFile", globalJson]]
30975
+ ["global.json:" + fs38.readFileSync(globalJson, "utf8").replace(/\s+/g, ""), ["-JSonFile", globalJson]]
30537
30976
  ] : []
30538
30977
  ];
30539
30978
  for (const [key2, args] of installs.filter(([k]) => !done[k])) {
@@ -30606,8 +31045,8 @@ var setupFrameworkReferences = async (env, targets) => {
30606
31045
  staging,
30607
31046
  { fileName: id + ".zip" }
30608
31047
  );
30609
- fs37.cpSync(path48.join(staging, "build", ".NETFramework"), path48.join(root, ".NETFramework"), { recursive: true });
30610
- fs37.writeFileSync(marker, version2);
31048
+ fs38.cpSync(path48.join(staging, "build", ".NETFramework"), path48.join(root, ".NETFramework"), { recursive: true });
31049
+ fs38.writeFileSync(marker, version2);
30611
31050
  } catch (e) {
30612
31051
  warn(
30613
31052
  ".NET Framework " + target + " reference assemblies could not be installed (projects targeting it will not build): " + errMsg(e)
@@ -30618,7 +31057,7 @@ var setupFrameworkReferences = async (env, targets) => {
30618
31057
  }
30619
31058
  if (!exists(path48.join(root, ".NETFramework"))) return;
30620
31059
  env.vars.TargetFrameworkRootPath = root + path48.sep;
30621
- env.summary.push(".NET Framework targeting: " + fs37.readdirSync(path48.join(root, ".NETFramework")).join(", "));
31060
+ env.summary.push(".NET Framework targeting: " + fs38.readdirSync(path48.join(root, ".NETFramework")).join(", "));
30622
31061
  };
30623
31062
  var setupNetFx35 = async (env) => {
30624
31063
  if (execOutput(SYSTEM.reg(), [
@@ -30697,15 +31136,15 @@ var setupLavapipe = async (env, mesaDir) => {
30697
31136
  var hasGpu = () => scriptOutput("get-gpu-names.ps1", [], { timeout: 3e4 }).split(/\r?\n/).map((n) => n.trim()).some((n) => n && !/^Microsoft (Remote Display|Basic (Render|Display))/i.test(n));
30698
31137
 
30699
31138
  // src/guest/toolchains/native/msvc/index.ts
30700
- import fs41 from "node:fs";
31139
+ import fs42 from "node:fs";
30701
31140
  import path53 from "node:path";
30702
31141
 
30703
31142
  // src/guest/toolchains/native/msvc/environment.ts
30704
- import fs39 from "node:fs";
31143
+ import fs40 from "node:fs";
30705
31144
  import path51 from "node:path";
30706
31145
 
30707
31146
  // src/guest/toolchains/native/msvc/tree.ts
30708
- import fs38 from "node:fs";
31147
+ import fs39 from "node:fs";
30709
31148
  import path50 from "node:path";
30710
31149
  var ROOT = tool("msvc");
30711
31150
  var MARKER2 = path50.join(ROOT, ".installed.json");
@@ -30721,7 +31160,7 @@ function hasCompiler(msvc) {
30721
31160
  var InstalledSchema = external_exports.object({ msvc: external_exports.string().min(1), sdk: external_exports.string().min(1), want: external_exports.string() });
30722
31161
  function readInstalled() {
30723
31162
  try {
30724
- return InstalledSchema.safeParse(JSON.parse(fs38.readFileSync(MARKER2, "utf8"))).data ?? null;
31163
+ return InstalledSchema.safeParse(JSON.parse(fs39.readFileSync(MARKER2, "utf8"))).data ?? null;
30725
31164
  } catch {
30726
31165
  return null;
30727
31166
  }
@@ -30771,8 +31210,8 @@ function writeVcvars(env) {
30771
31210
  'set "PATH=' + env.path.join(";") + ';%PATH%"',
30772
31211
  "exit /b 0"
30773
31212
  ];
30774
- fs39.writeFileSync(path51.join(dir, "vcvars64.bat"), lines.join("\r\n") + "\r\n");
30775
- fs39.writeFileSync(
31213
+ fs40.writeFileSync(path51.join(dir, "vcvars64.bat"), lines.join("\r\n") + "\r\n");
31214
+ fs40.writeFileSync(
30776
31215
  path51.join(dir, "vcvarsall.bat"),
30777
31216
  ["@echo off", "rem Only x64 (amd64) is installed.", 'call "%~dp0vcvars64.bat"', "exit /b %errorlevel%"].join(
30778
31217
  "\r\n"
@@ -30781,23 +31220,23 @@ function writeVcvars(env) {
30781
31220
  }
30782
31221
  function installVswhere(msvc) {
30783
31222
  mkdirp(VSWHERE_DIR);
30784
- fs39.copyFileSync(ensureCompiled("vswhere"), path51.join(VSWHERE_DIR, "vswhere.exe"));
31223
+ fs40.copyFileSync(ensureCompiled("vswhere"), path51.join(VSWHERE_DIR, "vswhere.exe"));
30785
31224
  const [major, minor] = msvc.split(".").slice(2);
30786
- fs39.writeFileSync(
31225
+ fs40.writeFileSync(
30787
31226
  path51.join(VSWHERE_DIR, "vswhere.json"),
30788
31227
  JSON.stringify({ installationPath: ROOT, installationVersion: "17." + (minor ?? "0") + ".0." + (major ?? "0") })
30789
31228
  );
30790
31229
  }
30791
31230
  function removeTelemetry(msvc) {
30792
31231
  try {
30793
- fs39.rmSync(hostBin(msvc, "vctip.exe"), { force: true });
31232
+ fs40.rmSync(hostBin(msvc, "vctip.exe"), { force: true });
30794
31233
  } catch (e) {
30795
31234
  warn("Could not remove MSVC's telemetry helper (vctip.exe); it may keep tools\\msvc locked: " + errMsg(e));
30796
31235
  }
30797
31236
  }
30798
31237
 
30799
31238
  // src/guest/toolchains/native/msvc/packages.ts
30800
- import fs40 from "node:fs";
31239
+ import fs41 from "node:fs";
30801
31240
  import path52 from "node:path";
30802
31241
  var CHANNEL = "https://aka.ms/vs/17/release/channel";
30803
31242
  var MANIFEST_DAY_MS = 24 * 60 * 60 * 1e3;
@@ -30825,9 +31264,9 @@ var SDK_MSIS = [
30825
31264
  ];
30826
31265
  var manifest = async () => {
30827
31266
  const cached2 = path52.join(ROOT, ".manifest.json");
30828
- if (exists(cached2) && Date.now() - fs40.statSync(cached2).mtimeMs < MANIFEST_DAY_MS) {
31267
+ if (exists(cached2) && Date.now() - fs41.statSync(cached2).mtimeMs < MANIFEST_DAY_MS) {
30829
31268
  try {
30830
- return JSON.parse(fs40.readFileSync(cached2, "utf8"));
31269
+ return JSON.parse(fs41.readFileSync(cached2, "utf8"));
30831
31270
  } catch {
30832
31271
  }
30833
31272
  }
@@ -30836,13 +31275,13 @@ var manifest = async () => {
30836
31275
  if (!item) throw new Error("the Visual Studio channel has no package manifest");
30837
31276
  mkdirp(ROOT);
30838
31277
  await downloader.file(item.url, cached2);
30839
- return JSON.parse(fs40.readFileSync(cached2, "utf8"));
31278
+ return JSON.parse(fs41.readFileSync(cached2, "utf8"));
30840
31279
  };
30841
31280
  var unpackVsix = async (vsix, work) => {
30842
31281
  const out = mkdirp(path52.join(work, "vsix-" + path52.basename(vsix)));
30843
31282
  await extractArchive(vsix, out, ["Contents"]);
30844
31283
  const decode4 = (dir) => {
30845
- for (const entry of fs40.readdirSync(dir, { withFileTypes: true })) {
31284
+ for (const entry of fs41.readdirSync(dir, { withFileTypes: true })) {
30846
31285
  const from = path52.join(dir, entry.name);
30847
31286
  let name = entry.name;
30848
31287
  try {
@@ -30850,12 +31289,12 @@ var unpackVsix = async (vsix, work) => {
30850
31289
  } catch {
30851
31290
  }
30852
31291
  const to = path52.join(dir, name);
30853
- if (to !== from) fs40.renameSync(from, to);
31292
+ if (to !== from) fs41.renameSync(from, to);
30854
31293
  if (entry.isDirectory()) decode4(to);
30855
31294
  }
30856
31295
  };
30857
31296
  decode4(out);
30858
- fs40.cpSync(path52.join(out, "Contents"), ROOT, { recursive: true, force: true });
31297
+ fs41.cpSync(path52.join(out, "Contents"), ROOT, { recursive: true, force: true });
30859
31298
  safeRemove(out, work);
30860
31299
  };
30861
31300
  var unpackMsi = async (msi) => {
@@ -30865,7 +31304,7 @@ var unpackMsi = async (msi) => {
30865
31304
  stdio: "ignore"
30866
31305
  });
30867
31306
  } catch (e) {
30868
- const lines = exists(logFile2) ? fs40.readFileSync(logFile2, "utf16le").split(/\r?\n/).filter((l) => /error|return value 3|failed/i.test(l)).slice(-4).join(" | ") : "";
31307
+ const lines = exists(logFile2) ? fs41.readFileSync(logFile2, "utf16le").split(/\r?\n/).filter((l) => /error|return value 3|failed/i.test(l)).slice(-4).join(" | ") : "";
30869
31308
  throw new Error(
30870
31309
  path52.basename(msi) + " did not unpack: " + (e instanceof Error ? e.message : String(e)) + (lines ? " (" + lines.slice(0, 600) + ")" : "")
30871
31310
  );
@@ -30886,10 +31325,10 @@ var payloadFetcher = (work) => async (p) => {
30886
31325
  };
30887
31326
  var unpackedToolset = () => {
30888
31327
  const toolsRoot = path52.join(ROOT, "VC", "Tools", "MSVC");
30889
- return fs40.readdirSync(toolsRoot).filter((d) => exists(hostBin(d, "cl.exe"))).sort((a, b) => a.localeCompare(b, void 0, { numeric: true })).pop();
31328
+ return fs41.readdirSync(toolsRoot).filter((d) => exists(hostBin(d, "cl.exe"))).sort((a, b) => a.localeCompare(b, void 0, { numeric: true })).pop();
30890
31329
  };
30891
31330
  async function installPackages(config2) {
30892
- const { ids, pick: pick2 } = catalogue(await manifest());
31331
+ const { ids, pick: pick3 } = catalogue(await manifest());
30893
31332
  const version2 = pickMsvcVersion(ids, config2.msvcVersion);
30894
31333
  if (!version2) throw new Error("no MSVC " + config2.msvcVersion + " in the Visual Studio manifest");
30895
31334
  const sdk = pickWindowsSdk(ids, config2.sdkVersion);
@@ -30898,13 +31337,13 @@ async function installPackages(config2) {
30898
31337
  const fetchPayload = payloadFetcher(work);
30899
31338
  log("Downloading the MSVC " + version2 + " compiler and C/C++ libraries ...");
30900
31339
  for (const part of MSVC_PARTS) {
30901
- const p = pick2("microsoft.vc." + version2 + "." + part);
31340
+ const p = pick3("microsoft.vc." + version2 + "." + part);
30902
31341
  if (!p && REQUIRED_PARTS.some((r) => part.startsWith(r))) throw new Error("MSVC " + version2 + " has no " + part);
30903
31342
  for (const payload2 of p?.payloads ?? []) await unpackVsix(await fetchPayload(payload2), work);
30904
31343
  }
30905
- for (const payload2 of pick2("microsoft.visualcpp.dia.sdk")?.payloads ?? [])
31344
+ for (const payload2 of pick3("microsoft.visualcpp.dia.sdk")?.payloads ?? [])
30906
31345
  await unpackVsix(await fetchPayload(payload2), work);
30907
- const sdkPackage = pick2(Object.keys(pick2(sdk.componentId)?.dependencies ?? {})[0] ?? "");
31346
+ const sdkPackage = pick3(Object.keys(pick3(sdk.componentId)?.dependencies ?? {})[0] ?? "");
30908
31347
  if (!sdkPackage?.payloads) throw new Error("the Windows SDK " + sdk.build + " package has no payloads");
30909
31348
  log("Downloading the Windows SDK " + sdk.build + " (headers, libraries; the biggest part) ...");
30910
31349
  const payload = (name) => sdkPackage.payloads.find((p) => p.fileName.toLowerCase() === ("installers\\" + name).toLowerCase());
@@ -30914,17 +31353,17 @@ async function installPackages(config2) {
30914
31353
  if (!p) throw new Error("the Windows SDK package has no " + name);
30915
31354
  const file3 = await fetchPayload(p);
30916
31355
  msis.push(file3);
30917
- for (const cab of msiCabs(fs40.readFileSync(file3))) {
31356
+ for (const cab of msiCabs(fs41.readFileSync(file3))) {
30918
31357
  const c = payload(cab);
30919
31358
  if (c) await fetchPayload(c);
30920
31359
  }
30921
31360
  }
30922
31361
  log("Unpacking the Windows SDK (a few minutes) ...");
30923
31362
  for (const msi of msis) await unpackMsi(msi);
30924
- for (const name of fs40.readdirSync(ROOT).filter((n) => n.toLowerCase().endsWith(".msi")))
30925
- fs40.rmSync(path52.join(ROOT, name), { force: true });
31363
+ for (const name of fs41.readdirSync(ROOT).filter((n) => n.toLowerCase().endsWith(".msi")))
31364
+ fs41.rmSync(path52.join(ROOT, name), { force: true });
30926
31365
  safeRemove(work, ROOT);
30927
- const sdkVersion = fs40.readdirSync(path52.join(ROOT, "Windows Kits", "10", "Include")).filter((d) => d.startsWith("10.0." + sdk.build)).sort().pop();
31366
+ const sdkVersion = fs41.readdirSync(path52.join(ROOT, "Windows Kits", "10", "Include")).filter((d) => d.startsWith("10.0." + sdk.build)).sort().pop();
30928
31367
  if (!sdkVersion) throw new Error("the Windows SDK did not unpack (no Include\\10.0." + sdk.build + ".*)");
30929
31368
  const toolset = unpackedToolset();
30930
31369
  if (!toolset) throw new Error("MSVC " + version2 + " did not unpack (no cl.exe under VC\\Tools\\MSVC)");
@@ -30938,7 +31377,7 @@ function installedMsvcEnv() {
30938
31377
  }
30939
31378
  var clearTree = () => {
30940
31379
  if (!exists(ROOT)) return;
30941
- for (const name of fs41.readdirSync(ROOT).filter((n) => n !== ".manifest.json" && n !== ".download"))
31380
+ for (const name of fs42.readdirSync(ROOT).filter((n) => n !== ".manifest.json" && n !== ".download"))
30942
31381
  safeRemove(path53.join(ROOT, name), ROOT);
30943
31382
  };
30944
31383
  async function setupMsvc(env, config2) {
@@ -30969,12 +31408,26 @@ async function setupMsvc(env, config2) {
30969
31408
  }
30970
31409
 
30971
31410
  // src/guest/toolchains/native/unreal.ts
30972
- import fs43 from "node:fs";
30973
- import os7 from "node:os";
31411
+ import os8 from "node:os";
31412
+ import path57 from "node:path";
31413
+
31414
+ // src/guest/toolchains/not-yet.ts
31415
+ function notAvailableYet(env, what) {
31416
+ log(what + ": not available yet (nothing installed)");
31417
+ env.summary.push(what + ": not available yet");
31418
+ }
31419
+
31420
+ // src/guest/toolchains/engines/unreal-engines.ts
31421
+ async function setupUnrealEngines(env, _config, _ctx) {
31422
+ notAvailableYet(env, "Unreal engines");
31423
+ }
31424
+
31425
+ // src/guest/toolchains/installers.ts
31426
+ import fs44 from "node:fs";
30974
31427
  import path55 from "node:path";
30975
31428
 
30976
31429
  // src/guest/toolchains/native/vcruntime.ts
30977
- import fs42 from "node:fs";
31430
+ import fs43 from "node:fs";
30978
31431
  import path54 from "node:path";
30979
31432
  var VC_REDIST = "https://aka.ms/vs/17/release/vc_redist.x64.exe";
30980
31433
  var MICROSOFT_SIGNER = "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US";
@@ -30994,7 +31447,7 @@ async function setupVcRuntime(env, summary = true) {
30994
31447
  await downloadFile(VC_REDIST, installer);
30995
31448
  }
30996
31449
  if (signerOf(installer) !== MICROSOFT_SIGNER) {
30997
- fs42.rmSync(installer, { force: true });
31450
+ fs43.rmSync(installer, { force: true });
30998
31451
  throw new Error("vc_redist.x64.exe is not signed by Microsoft; deleted it (it is downloaded again next boot)");
30999
31452
  }
31000
31453
  log("Installing the Visual C++ runtime ...");
@@ -31006,9 +31459,85 @@ async function setupVcRuntime(env, summary = true) {
31006
31459
  return missing;
31007
31460
  }
31008
31461
 
31009
- // src/guest/toolchains/native/unreal.ts
31010
- var BOOTSTRAPPER_URL = "https://aka.ms/vs/17/release/vs_community.exe";
31011
- var DIRECTX_URL = "https://download.microsoft.com/download/8/4/A/84A35BF1-DAFE-4AE8-82AF-AD2AE20B6B14/directx_Jun2010_redist.exe";
31462
+ // src/guest/toolchains/installers.ts
31463
+ var SIGNERS = {
31464
+ microsoft: MICROSOFT_SIGNER,
31465
+ valve: /^CN="?Valve(,| Corp)/,
31466
+ unity: /^CN="?Unity Technologies/
31467
+ };
31468
+ function signedBy(file3, signer) {
31469
+ const subject = signerOf(file3);
31470
+ return typeof signer === "string" ? subject === signer : signer.test(subject);
31471
+ }
31472
+ function signatureCheck(signer, what) {
31473
+ return (file3) => {
31474
+ if (!signedBy(file3, signer)) throw new Error(what + " is not signed by its vendor");
31475
+ };
31476
+ }
31477
+ async function signedInstaller(url2, file3, what, signer, sha256 = null) {
31478
+ if (!exists(file3)) {
31479
+ log("Downloading " + what + " ...");
31480
+ mkdirp(path55.dirname(file3));
31481
+ await downloader.file(url2, file3, { sha256, verify: signatureCheck(signer, path55.basename(file3)) });
31482
+ }
31483
+ if (!signedBy(file3, signer)) {
31484
+ fs44.rmSync(file3, { force: true });
31485
+ throw new Error(
31486
+ path55.basename(file3) + " is not signed by its vendor; deleted it (it is downloaded again next boot)"
31487
+ );
31488
+ }
31489
+ return file3;
31490
+ }
31491
+
31492
+ // src/guest/toolchains/native/visual-studio.ts
31493
+ import fs46 from "node:fs";
31494
+ import os7 from "node:os";
31495
+ import path56 from "node:path";
31496
+
31497
+ // src/guest/toolchains/persisted.ts
31498
+ import fs45 from "node:fs";
31499
+
31500
+ // src/shared/installs.ts
31501
+ var InstallRecordSchema = external_exports.object({
31502
+ name: external_exports.string().max(100),
31503
+ version: external_exports.string().max(100),
31504
+ sizeBytes: external_exports.number().nonnegative().nullable(),
31505
+ installedAt: external_exports.string().max(64),
31506
+ usedAt: external_exports.string().max(64)
31507
+ });
31508
+ var InstallRecordsSchema = external_exports.object({ installs: external_exports.array(InstallRecordSchema).max(1e3) });
31509
+
31510
+ // src/guest/toolchains/persisted.ts
31511
+ var GB = 1024 ** 3;
31512
+ var LOCAL_RESERVE_BYTES = 13 * GB;
31513
+ function freeBytes(dir, deps = {}) {
31514
+ try {
31515
+ const s = (deps.statfs ?? fs45.statfsSync)(dir);
31516
+ return s.bavail * s.bsize;
31517
+ } catch {
31518
+ return 0;
31519
+ }
31520
+ }
31521
+ var gb = (bytes) => (bytes / GB).toFixed(1) + " GB";
31522
+ function assertRoom(dir, needBytes, what, fix, deps = {}) {
31523
+ const free = freeBytes(dir, deps);
31524
+ if (free < needBytes)
31525
+ throw new Error(
31526
+ "not installing " + what + ": " + gb(free) + " free where it goes, it needs " + gb(needBytes) + ". " + fix
31527
+ );
31528
+ }
31529
+ function assertLocalRoom(needBytes, what, deps = {}) {
31530
+ const drive = deps.localDir ?? (process.env.SystemDrive ?? "C:") + "\\";
31531
+ assertRoom(
31532
+ drive,
31533
+ needBytes + LOCAL_RESERVE_BYTES,
31534
+ what,
31535
+ "The sandbox's own disk also holds the paging file and every build: give the sandbox less to install, or a smaller sandbox.pageFileMb.",
31536
+ deps
31537
+ );
31538
+ }
31539
+
31540
+ // src/guest/toolchains/native/vs-request.ts
31012
31541
  var UNREAL_COMPONENTS = [
31013
31542
  "Microsoft.VisualStudio.Workload.NativeGame",
31014
31543
  "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
@@ -31019,17 +31548,59 @@ var UNREAL_COMPONENTS = [
31019
31548
  "Component.Unreal.Ide",
31020
31549
  "Component.Unreal"
31021
31550
  ];
31022
- var OK_EXIT_CODES2 = [0, 3010];
31023
- var LAYOUT_ROOM_BYTES = 15 * 1024 ** 3;
31024
- var INSTALL_ROOM_BYTES = 20 * 1024 ** 3;
31025
- var ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;
31026
- var VS_DIR = tool("visualstudio");
31027
- var BOOTSTRAPPER = path55.join(VS_DIR, "vs_community.exe");
31028
- var LAYOUT = path55.join(VS_DIR, "layout");
31029
- var LAYOUT_MARKER = path55.join(LAYOUT, ".complete.json");
31030
- var LayoutSchema = external_exports.object({ components: external_exports.array(external_exports.string()) });
31031
- var VSWHERE = path55.join(
31032
- process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)",
31551
+ var BUILD_TOOLS_COMPONENTS = [
31552
+ "Microsoft.VisualStudio.Workload.VCTools",
31553
+ "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
31554
+ "Microsoft.VisualStudio.Component.Windows11SDK.22621"
31555
+ ];
31556
+ var isOn = (setting) => setting === true;
31557
+ function visualStudioWanted(t, on = isOn) {
31558
+ const unreal = on(t.unreal.enabled, "unreal");
31559
+ const flutter = on(t.flutter.enabled, "flutter") && t.flutter.windowsDesktop;
31560
+ const unity = on(t.unity.enabled, "unity") && t.unity.modules.includes("windows-il2cpp");
31561
+ const users = [...unreal ? ["unreal"] : [], ...flutter ? ["flutter"] : [], ...unity ? ["unity"] : []];
31562
+ if (!users.length) return null;
31563
+ if (unreal)
31564
+ return {
31565
+ product: "community",
31566
+ components: [.../* @__PURE__ */ new Set([...UNREAL_COMPONENTS, ...t.unreal.components])],
31567
+ for: users,
31568
+ licence: "toolchains.unreal.acceptLicense",
31569
+ accepted: t.unreal.acceptLicense
31570
+ };
31571
+ return {
31572
+ product: "buildtools",
31573
+ components: [...BUILD_TOOLS_COMPONENTS],
31574
+ for: users,
31575
+ licence: "toolchains.msvc.acceptLicense",
31576
+ accepted: t.msvc.acceptLicense
31577
+ };
31578
+ }
31579
+
31580
+ // src/guest/toolchains/native/visual-studio.ts
31581
+ var BOOTSTRAPPERS = {
31582
+ community: {
31583
+ url: "https://aka.ms/vs/17/release/vs_community.exe",
31584
+ file: "vs_community.exe",
31585
+ name: "Visual Studio Community 2022"
31586
+ },
31587
+ buildtools: {
31588
+ url: "https://aka.ms/vs/17/release/vs_buildtools.exe",
31589
+ file: "vs_buildtools.exe",
31590
+ name: "Visual Studio Build Tools 2022"
31591
+ }
31592
+ };
31593
+ var INSTALL_BYTES = {
31594
+ community: 7 * 1024 ** 3,
31595
+ buildtools: 5 * 1024 ** 3
31596
+ };
31597
+ var OK_EXIT_CODES2 = [0, 3010];
31598
+ var LAYOUT_ROOM_BYTES = 15 * 1024 ** 3;
31599
+ var ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;
31600
+ var VS_DIR = tool("visualstudio");
31601
+ var LayoutSchema = external_exports.object({ components: external_exports.array(external_exports.string()) });
31602
+ var VSWHERE = path56.join(
31603
+ process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)",
31033
31604
  "Microsoft Visual Studio",
31034
31605
  "Installer",
31035
31606
  "vswhere.exe"
@@ -31048,150 +31619,153 @@ function installedVs() {
31048
31619
  const at = ask("installationPath");
31049
31620
  return at ? { path: at, version: ask("installationVersion") || "installed" } : null;
31050
31621
  }
31051
- async function signedInstaller(url2, file3, what) {
31052
- if (!exists(file3)) {
31053
- log("Downloading " + what + " ...");
31054
- mkdirp(path55.dirname(file3));
31055
- await downloadFile(url2, file3);
31056
- }
31057
- if (signerOf(file3) !== MICROSOFT_SIGNER) {
31058
- fs43.rmSync(file3, { force: true });
31059
- throw new Error(path55.basename(file3) + " is not signed by Microsoft; deleted it (it is downloaded again next boot)");
31060
- }
31061
- return file3;
31622
+ function layoutDir(product) {
31623
+ return path56.join(VS_DIR, product === "community" ? "layout" : "layout-buildtools");
31062
31624
  }
31063
- function freeBytes(dir) {
31064
- try {
31065
- const s = fs43.statfsSync(dir);
31066
- return s.bavail * s.bsize;
31067
- } catch {
31068
- return 0;
31069
- }
31070
- }
31071
- async function layoutInstaller(bootstrapper, ids) {
31072
- const installer = path55.join(LAYOUT, "vs_community.exe");
31625
+ async function layoutInstaller(req, bootstrapper) {
31626
+ const layout = layoutDir(req.product);
31627
+ const marker = path56.join(layout, ".complete.json");
31628
+ const installer = path56.join(layout, BOOTSTRAPPERS[req.product].file);
31073
31629
  const has = () => {
31074
- if (!exists(LAYOUT_MARKER) || !exists(installer)) return false;
31630
+ if (!exists(marker) || !exists(installer)) return false;
31075
31631
  try {
31076
- const done = LayoutSchema.parse(JSON.parse(fs43.readFileSync(LAYOUT_MARKER, "utf8")));
31077
- return ids.every((id) => done.components.includes(id));
31632
+ const done = LayoutSchema.parse(JSON.parse(fs46.readFileSync(marker, "utf8")));
31633
+ return req.components.every((id) => done.components.includes(id));
31078
31634
  } catch {
31079
31635
  return false;
31080
31636
  }
31081
31637
  };
31082
31638
  if (has()) return installer;
31083
31639
  if (freeBytes(mkdirp(VS_DIR)) < LAYOUT_ROOM_BYTES) {
31084
- warn("unreal: not keeping the install files (less than 15 GB free in " + VS_DIR + "); downloading this boot");
31640
+ warn(
31641
+ "Visual Studio: not keeping the install files (less than 15 GB free in " + VS_DIR + "); downloading this boot"
31642
+ );
31085
31643
  return null;
31086
31644
  }
31087
31645
  log("Saving the Visual Studio install files for later boots (~10 GB, once) ...");
31088
- fs43.rmSync(LAYOUT_MARKER, { force: true });
31646
+ fs46.rmSync(marker, { force: true });
31089
31647
  const code = await spawnAsync(bootstrapper, [
31090
31648
  "--layout",
31091
- LAYOUT,
31649
+ layout,
31092
31650
  "--lang",
31093
31651
  "en-US",
31094
31652
  "--quiet",
31095
31653
  "--wait",
31096
- ...ids.flatMap((id) => ["--add", id])
31654
+ ...req.components.flatMap((id) => ["--add", id])
31097
31655
  ]);
31098
31656
  if (!OK_EXIT_CODES2.includes(code) || !exists(installer)) {
31099
- warn("unreal: saving the install files failed (exit " + code + "); downloading this boot");
31657
+ warn("Visual Studio: saving the install files failed (exit " + code + "); downloading this boot");
31100
31658
  return null;
31101
31659
  }
31102
- writeJsonAtomic(LAYOUT_MARKER, { components: [...ids] });
31660
+ writeJsonAtomic(marker, { components: [...req.components] });
31103
31661
  return installer;
31104
31662
  }
31105
- async function installVisualStudio(config2, ids) {
31106
- const bootstrapper = await signedInstaller(BOOTSTRAPPER_URL, BOOTSTRAPPER, "the Visual Studio installer");
31663
+ async function install(req, keepInstallFiles) {
31664
+ const boot = BOOTSTRAPPERS[req.product];
31665
+ const bootstrapper = await signedInstaller(
31666
+ boot.url,
31667
+ path56.join(VS_DIR, boot.file),
31668
+ "the " + boot.name + " installer",
31669
+ SIGNERS.microsoft
31670
+ );
31107
31671
  let installer = null;
31108
- if (config2.keepInstallFiles) {
31672
+ if (keepInstallFiles) {
31109
31673
  try {
31110
- installer = await layoutInstaller(bootstrapper, ids);
31674
+ installer = await layoutInstaller(req, bootstrapper);
31111
31675
  } catch (e) {
31112
- warn("unreal: the offline copy failed (" + errMsg(e) + "); downloading this boot");
31676
+ warn("Visual Studio: the offline copy failed (" + errMsg(e) + "); downloading this boot");
31113
31677
  }
31114
31678
  }
31115
- log(
31116
- "Installing Visual Studio Community 2022 with the C++ game workload" + (installer ? " from the saved install files" : " (downloads ~5-8 GB)") + " ..."
31117
- );
31679
+ log("Installing " + boot.name + (installer ? " from the saved install files" : " (downloads ~5-8 GB)") + " ...");
31118
31680
  const code = await spawnAsync(installer ?? bootstrapper, [
31119
31681
  "--quiet",
31120
31682
  "--wait",
31121
31683
  "--norestart",
31122
31684
  "--nocache",
31123
31685
  ...installer ? ["--noWeb"] : [],
31124
- ...ids.flatMap((id) => ["--add", id])
31686
+ ...req.components.flatMap((id) => ["--add", id])
31125
31687
  ]);
31126
31688
  if (!OK_EXIT_CODES2.includes(code) || !installedVs())
31127
31689
  throw new Error(
31128
31690
  "the Visual Studio installer failed (exit " + code + "); its logs are the dd_*.log files in " + os7.tmpdir()
31129
31691
  );
31130
31692
  }
31693
+ async function ensureVisualStudio(env, req, o) {
31694
+ if (!req.accepted)
31695
+ throw new Error(
31696
+ "Visual Studio (for " + req.for.join(", ") + ") is installed only with " + req.licence + " = true: it comes under Microsoft licence terms (https://visualstudio.microsoft.com/license-terms/)"
31697
+ );
31698
+ const bad = req.components.find((id) => !ID.test(id));
31699
+ if (bad) throw new Error('"' + bad + '" is not a Visual Studio component ID');
31700
+ const have = installedVs();
31701
+ if (have) return have;
31702
+ if (duringSession())
31703
+ throw new Error("Visual Studio is installed when the sandbox starts: restart it (sandbox restart) to get it");
31704
+ assertLocalRoom(INSTALL_BYTES[req.product], BOOTSTRAPPERS[req.product].name);
31705
+ await install(req, o.keepInstallFiles);
31706
+ const vs = installedVs();
31707
+ env.summary.push(
31708
+ "visual studio: " + BOOTSTRAPPERS[req.product].name + " " + vs.version + " at " + vs.path + " (for " + req.for.join(", ") + ")"
31709
+ );
31710
+ return vs;
31711
+ }
31712
+
31713
+ // src/guest/toolchains/native/unreal.ts
31714
+ var DIRECTX_URL = "https://download.microsoft.com/download/8/4/A/84A35BF1-DAFE-4AE8-82AF-AD2AE20B6B14/directx_Jun2010_redist.exe";
31131
31715
  async function installDirectX() {
31132
- const system322 = path55.join(process.env.WINDIR ?? "C:\\Windows", "System32");
31133
- if (exists(path55.join(system322, "d3dx9_43.dll")) && exists(path55.join(system322, "XAudio2_7.dll"))) return;
31716
+ const system322 = path57.join(process.env.WINDIR ?? "C:\\Windows", "System32");
31717
+ if (exists(path57.join(system322, "d3dx9_43.dll")) && exists(path57.join(system322, "XAudio2_7.dll"))) return;
31134
31718
  const redist = await signedInstaller(
31135
31719
  DIRECTX_URL,
31136
- path55.join(VS_DIR, "directx_Jun2010_redist.exe"),
31137
- "the DirectX End-User Runtime (~95 MB once)"
31720
+ path57.join(tool("visualstudio"), "directx_Jun2010_redist.exe"),
31721
+ "the DirectX End-User Runtime (~95 MB once)",
31722
+ SIGNERS.microsoft
31138
31723
  );
31139
- const unpacked = path55.join(os7.tmpdir(), "directx-redist");
31140
- safeRemove(unpacked, os7.tmpdir());
31724
+ const unpacked = path57.join(os8.tmpdir(), "directx-redist");
31725
+ safeRemove(unpacked, os8.tmpdir());
31141
31726
  mkdirp(unpacked);
31142
- if (await spawnAsync(redist, ["/Q", "/T:" + unpacked]) !== 0 || !exists(path55.join(unpacked, "DXSETUP.exe")))
31727
+ if (await spawnAsync(redist, ["/Q", "/T:" + unpacked]) !== 0 || !exists(path57.join(unpacked, "DXSETUP.exe")))
31143
31728
  throw new Error("could not unpack the DirectX End-User Runtime");
31144
- const code = await spawnAsync(path55.join(unpacked, "DXSETUP.exe"), ["/silent"]);
31145
- safeRemove(unpacked, os7.tmpdir());
31729
+ const code = await spawnAsync(path57.join(unpacked, "DXSETUP.exe"), ["/silent"]);
31730
+ safeRemove(unpacked, os8.tmpdir());
31146
31731
  if (code !== 0) throw new Error("the DirectX End-User Runtime installer failed (exit " + code + ")");
31147
31732
  }
31148
- async function setupUnreal(env, config2) {
31733
+ async function setupUnreal(env, config2, ctx) {
31149
31734
  if (!config2.acceptLicense)
31150
31735
  throw new Error(
31151
31736
  "Unreal tools are installed only with toolchains.unreal.acceptLicense = true: Visual Studio Community and the DirectX End-User Runtime come under Microsoft licence terms (https://visualstudio.microsoft.com/license-terms/)"
31152
31737
  );
31153
- const bad = config2.components.find((id) => !ID.test(id));
31154
- if (bad) throw new Error('toolchains.unreal.components: "' + bad + '" is not a Visual Studio component ID');
31155
- const ids = [.../* @__PURE__ */ new Set([...UNREAL_COMPONENTS, ...config2.components])];
31156
31738
  if (dryRun) {
31157
- log("(dry run) would install Visual Studio Community 2022 with " + ids.join(", ") + " and DirectX");
31739
+ log("(dry run) would install the DirectX End-User Runtime and set up the Unreal engines");
31158
31740
  return;
31159
31741
  }
31160
- if (!installedVs()) {
31161
- const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
31162
- const free = freeBytes(programFiles);
31163
- if (free < INSTALL_ROOM_BYTES)
31164
- throw new Error(
31165
- "not installing Visual Studio: the sandbox disk has " + (free / 1024 ** 3).toFixed(1) + " GB free and it needs 20 GB (7 GB for Visual Studio, the rest for builds and the paging file)"
31166
- );
31167
- await installVisualStudio(config2, ids);
31168
- }
31169
31742
  await installDirectX();
31743
+ await setupUnrealEngines(env, config2, ctx);
31170
31744
  const vs = installedVs();
31171
31745
  env.summary.push(
31172
- "unreal: Visual Studio Community " + vs.version + " (C++ game workload, Windows 11 SDK, Unreal support) at " + vs.path + "; DirectX End-User Runtime; get the engine from the Epic Games Launcher (Start menu)"
31746
+ "unreal: " + (vs ? "Visual Studio " + vs.version + " (C++ game workload, Windows 11 SDK, Unreal support); " : "") + "DirectX End-User Runtime; get the engine from the Epic Games Launcher (Start menu)"
31173
31747
  );
31174
31748
  }
31175
31749
 
31176
31750
  // src/guest/toolchains/native/rust.ts
31177
- import path57 from "node:path";
31751
+ import path59 from "node:path";
31178
31752
 
31179
31753
  // src/guest/toolchains/native/binstall.ts
31180
- import fs44 from "node:fs";
31181
- import path56 from "node:path";
31754
+ import fs47 from "node:fs";
31755
+ import path58 from "node:path";
31182
31756
  var ensureBinstall = async (cargoBin) => {
31183
- const target = path56.join(cargoBin, "cargo-binstall.exe");
31757
+ const target = path58.join(cargoBin, "cargo-binstall.exe");
31184
31758
  if (exists(target)) return true;
31185
31759
  try {
31186
31760
  const dir = tool("cargo-binstall");
31187
- if (!exists(path56.join(dir, "cargo-binstall.exe"))) {
31761
+ if (!exists(path58.join(dir, "cargo-binstall.exe"))) {
31188
31762
  await installFromGithub("cargo-bins/cargo-binstall", binstallAsset(arch), {
31189
31763
  dest: dir,
31190
31764
  what: "cargo-binstall for prebuilt Rust tools (~10 MB once)",
31191
31765
  locate: "cargo-binstall.exe"
31192
31766
  });
31193
31767
  }
31194
- fs44.copyFileSync(path56.join(dir, "cargo-binstall.exe"), target);
31768
+ fs47.copyFileSync(path58.join(dir, "cargo-binstall.exe"), target);
31195
31769
  return true;
31196
31770
  } catch (e) {
31197
31771
  warn("cargo-binstall unavailable, compiling crates with cargo install instead: " + errMsg(e));
@@ -31199,14 +31773,14 @@ var ensureBinstall = async (cargoBin) => {
31199
31773
  }
31200
31774
  };
31201
31775
  function crateInstaller(cargoHome, cargoEnv) {
31202
- const cargo = path56.join(cargoHome, "bin", "cargo.exe");
31776
+ const cargo = path58.join(cargoHome, "bin", "cargo.exe");
31203
31777
  let binstall = null;
31204
31778
  const binstallEnv = {
31205
31779
  ...cargoEnv,
31206
31780
  env: { ...cargoEnv.env ?? process.env, BINSTALL_DISABLE_TELEMETRY: "true" }
31207
31781
  };
31208
31782
  return async (crate) => {
31209
- binstall ??= ensureBinstall(path56.join(cargoHome, "bin"));
31783
+ binstall ??= ensureBinstall(path58.join(cargoHome, "bin"));
31210
31784
  if (await binstall) {
31211
31785
  try {
31212
31786
  await execAsync(
@@ -31228,7 +31802,7 @@ async function setupRust(env, config2, refresh) {
31228
31802
  const RUSTUP_HOME = tool("rust", "rustup");
31229
31803
  const CARGO_HOME = tool("rust", "cargo");
31230
31804
  const rustEnv = { env: { ...process.env, RUSTUP_HOME, CARGO_HOME } };
31231
- const rustup = path57.join(CARGO_HOME, "bin", "rustup.exe");
31805
+ const rustup = path59.join(CARGO_HOME, "bin", "rustup.exe");
31232
31806
  if (dryRun) {
31233
31807
  log("(dry run) would provision Rust " + config2.toolchain + " (" + config2.host + ")");
31234
31808
  return;
@@ -31264,9 +31838,9 @@ async function setupRust(env, config2, refresh) {
31264
31838
  if (refresh) await execAsync(rustup, ["update"], rustEnv);
31265
31839
  }
31266
31840
  Object.assign(env.vars, { RUSTUP_HOME, CARGO_HOME });
31267
- env.prepend.push(path57.join(CARGO_HOME, "bin"));
31841
+ env.prepend.push(path59.join(CARGO_HOME, "bin"));
31268
31842
  env.summary.push(
31269
- "rust: " + versionOf(path57.join(CARGO_HOME, "bin", "rustc.exe"), ["--version"], rustEnv) + " [" + config2.host + "]"
31843
+ "rust: " + versionOf(path59.join(CARGO_HOME, "bin", "rustc.exe"), ["--version"], rustEnv) + " [" + config2.host + "]"
31270
31844
  );
31271
31845
  const toolchainKey = "rustup@" + config2.toolchain;
31272
31846
  await installOnce(
@@ -31287,36 +31861,36 @@ async function setupRust(env, config2, refresh) {
31287
31861
  env: {
31288
31862
  ...rustEnv.env,
31289
31863
  ...msvc.vars,
31290
- PATH: [path57.join(CARGO_HOME, "bin"), ...msvc.path, process.env.PATH ?? ""].join(path57.delimiter)
31864
+ PATH: [path59.join(CARGO_HOME, "bin"), ...msvc.path, process.env.PATH ?? ""].join(path59.delimiter)
31291
31865
  }
31292
31866
  } : {
31293
31867
  env: {
31294
31868
  ...rustEnv.env,
31295
- CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: path57.join(mingw, "gcc.exe"),
31296
- PATH: [path57.join(CARGO_HOME, "bin"), mingw, process.env.PATH ?? ""].join(path57.delimiter)
31869
+ CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: path59.join(mingw, "gcc.exe"),
31870
+ PATH: [path59.join(CARGO_HOME, "bin"), mingw, process.env.PATH ?? ""].join(path59.delimiter)
31297
31871
  }
31298
31872
  };
31299
31873
  await installOnce(env, "cargo", config2.crates, crateInstaller(CARGO_HOME, cargoEnv));
31300
31874
  }
31301
31875
 
31302
31876
  // src/guest/toolchains/languages/node.ts
31303
- import fs45 from "node:fs";
31304
- import path58 from "node:path";
31877
+ import fs48 from "node:fs";
31878
+ import path60 from "node:path";
31305
31879
  import { spawn as spawn4 } from "node:child_process";
31306
31880
  var NVM_HOME = tool("nvm");
31307
- var NVM_SYMLINK = path58.join(localDir, "nodejs");
31308
- var HOST_NVM = path58.join(hostToolsDir, "nvm");
31881
+ var NVM_SYMLINK = path60.join(localDir, "nodejs");
31882
+ var HOST_NVM = path60.join(hostToolsDir, "nvm");
31309
31883
  var HOST_VERSIONS_MAX = 3;
31310
- var hostNvmVersions = () => exists(HOST_NVM) ? fs45.readdirSync(HOST_NVM).filter((d) => /^v\d+\.\d+\.\d+$/.test(d) && exists(path58.join(HOST_NVM, d, "node.exe"))).map((d) => d.slice(1)) : [];
31884
+ var hostNvmVersions = () => exists(HOST_NVM) ? fs48.readdirSync(HOST_NVM).filter((d) => /^v\d+\.\d+\.\d+$/.test(d) && exists(path60.join(HOST_NVM, d, "node.exe"))).map((d) => d.slice(1)) : [];
31311
31885
  var resolveNode = (spec) => resolveCached("node:" + spec, async () => {
31312
31886
  const exact = spec.replace(/^v/, "");
31313
31887
  if (/^\d+\.\d+\.\d+$/.test(exact)) return exact;
31314
31888
  const releases = await fetchJson("https://nodejs.org/dist/index.json");
31315
31889
  return pickNodeVersion(releases, spec) ?? Promise.reject(new Error('No Node.js release matches "' + spec + '"'));
31316
31890
  });
31317
- var NVM_TEMP = path58.join(NVM_HOME, ".tmp");
31891
+ var NVM_TEMP = path60.join(NVM_HOME, ".tmp");
31318
31892
  var nvm = (args) => new Promise((resolve2) => {
31319
- const child = spawn4(path58.join(NVM_HOME, "nvm.exe"), args, {
31893
+ const child = spawn4(path60.join(NVM_HOME, "nvm.exe"), args, {
31320
31894
  windowsHide: true,
31321
31895
  env: { ...process.env, NVM_HOME, NVM_SYMLINK, TEMP: NVM_TEMP, TMP: NVM_TEMP }
31322
31896
  });
@@ -31331,12 +31905,12 @@ var nvm = (args) => new Promise((resolve2) => {
31331
31905
  child.once("close", () => resolve2(out));
31332
31906
  });
31333
31907
  var ensureNvm = async () => {
31334
- if (exists(path58.join(NVM_HOME, "nvm.exe"))) return;
31335
- if (exists(path58.join(HOST_NVM, "nvm.exe"))) {
31908
+ if (exists(path60.join(NVM_HOME, "nvm.exe"))) return;
31909
+ if (exists(path60.join(HOST_NVM, "nvm.exe"))) {
31336
31910
  log("Copying nvm from this PC ...");
31337
31911
  mkdirp(NVM_HOME);
31338
- const files = fs45.readdirSync(HOST_NVM).filter((f) => /\.(exe|cmd|vbs)$/i.test(f)).sort((a, b) => Number(a.toLowerCase() === "nvm.exe") - Number(b.toLowerCase() === "nvm.exe"));
31339
- for (const file3 of files) fs45.copyFileSync(path58.join(HOST_NVM, file3), path58.join(NVM_HOME, file3));
31912
+ const files = fs48.readdirSync(HOST_NVM).filter((f) => /\.(exe|cmd|vbs)$/i.test(f)).sort((a, b) => Number(a.toLowerCase() === "nvm.exe") - Number(b.toLowerCase() === "nvm.exe"));
31913
+ for (const file3 of files) fs48.copyFileSync(path60.join(HOST_NVM, file3), path60.join(NVM_HOME, file3));
31340
31914
  return;
31341
31915
  }
31342
31916
  const asset = await githubAsset("coreybutler/nvm-windows", /^nvm-noinstall\.zip$/, true);
@@ -31344,14 +31918,14 @@ var ensureNvm = async () => {
31344
31918
  await downloader.archive(asset.url, NVM_HOME, { sha256: asset.sha256, locate: "nvm.exe", fileName: asset.name });
31345
31919
  };
31346
31920
  var hostNodeFolder = (version2) => {
31347
- const dir = path58.join(hostToolsDir, "node");
31348
- return session.hostTools.nodeVersion?.replace(/^v/, "") === version2 && exists(path58.join(dir, "node.exe")) ? dir : null;
31921
+ const dir = path60.join(hostToolsDir, "node");
31922
+ return session.hostTools.nodeVersion?.replace(/^v/, "") === version2 && exists(path60.join(dir, "node.exe")) ? dir : null;
31349
31923
  };
31350
31924
  var installNodeVersion = async (version2) => {
31351
- const dir = path58.join(NVM_HOME, "v" + version2);
31352
- const fromHost = path58.join(HOST_NVM, "v" + version2);
31353
- if (exists(path58.join(dir, "node.exe"))) return;
31354
- if (exists(path58.join(fromHost, "node.exe"))) {
31925
+ const dir = path60.join(NVM_HOME, "v" + version2);
31926
+ const fromHost = path60.join(HOST_NVM, "v" + version2);
31927
+ if (exists(path60.join(dir, "node.exe"))) return;
31928
+ if (exists(path60.join(fromHost, "node.exe"))) {
31355
31929
  log("Copying Node " + version2 + " from this PC's nvm (without global packages) ...");
31356
31930
  copyNode(fromHost, dir);
31357
31931
  return;
@@ -31370,19 +31944,19 @@ var installNodeVersion = async (version2) => {
31370
31944
  } finally {
31371
31945
  safeRemove(NVM_TEMP, NVM_HOME);
31372
31946
  }
31373
- if (!exists(path58.join(dir, "node.exe"))) {
31947
+ if (!exists(path60.join(dir, "node.exe"))) {
31374
31948
  const tail = out.trim().split(/\r?\n/).filter(Boolean).slice(-3).join(" ");
31375
31949
  const why = /complete/i.test(out) ? "nvm said it finished, but its move into the data folder did not happen" : "nvm could not download or unpack it: check the internet connection and the free disk space";
31376
31950
  throw new Error(
31377
- "nvm install " + version2 + " did not leave " + path58.join(dir, "node.exe") + " (" + why + ")" + (tail ? ". nvm printed: " + tail : "")
31951
+ "nvm install " + version2 + " did not leave " + path60.join(dir, "node.exe") + " (" + why + ")" + (tail ? ". nvm printed: " + tail : "")
31378
31952
  );
31379
31953
  }
31380
31954
  };
31381
31955
  var activate = async (version2) => {
31382
31956
  await nvm(["use", version2]);
31383
- if (exists(path58.join(NVM_SYMLINK, "node.exe"))) return;
31384
- fs45.rmSync(NVM_SYMLINK, { recursive: true, force: true });
31385
- fs45.symlinkSync(path58.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
31957
+ if (exists(path60.join(NVM_SYMLINK, "node.exe"))) return;
31958
+ fs48.rmSync(NVM_SYMLINK, { recursive: true, force: true });
31959
+ fs48.symlinkSync(path60.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
31386
31960
  };
31387
31961
  var PLAYWRIGHT_VARS = () => ({
31388
31962
  PLAYWRIGHT_BROWSERS_PATH: tool("ms-playwright"),
@@ -31394,8 +31968,8 @@ async function setupNode(env, versions, config2) {
31394
31968
  return;
31395
31969
  }
31396
31970
  await ensureNvm();
31397
- fs45.writeFileSync(
31398
- path58.join(NVM_HOME, "settings.txt"),
31971
+ fs48.writeFileSync(
31972
+ path60.join(NVM_HOME, "settings.txt"),
31399
31973
  [
31400
31974
  "root: " + NVM_HOME,
31401
31975
  "path: " + NVM_SYMLINK,
@@ -31422,7 +31996,7 @@ async function setupNode(env, versions, config2) {
31422
31996
  }
31423
31997
  }
31424
31998
  Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK, ...PLAYWRIGHT_VARS() });
31425
- if (duringSession()) env.prepend.push(path58.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
31999
+ if (duringSession()) env.prepend.push(path60.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
31426
32000
  else {
31427
32001
  await activate(main);
31428
32002
  env.prepend.push(NVM_HOME, NVM_SYMLINK);
@@ -31432,13 +32006,13 @@ async function setupNode(env, versions, config2) {
31432
32006
  await packageManagers(env, config2, main);
31433
32007
  }
31434
32008
  var packageManagers = async (env, config2, version2) => {
31435
- const dir = path58.join(NVM_HOME, "v" + version2);
31436
- const nodeEnv = { ...process.env, PATH: dir + path58.delimiter + (process.env.PATH ?? "") };
31437
- const npm = (args) => execAsync(path58.join(dir, "node.exe"), [path58.join(dir, "node_modules", "npm", "bin", "npm-cli.js"), ...args], {
32009
+ const dir = path60.join(NVM_HOME, "v" + version2);
32010
+ const nodeEnv = { ...process.env, PATH: dir + path60.delimiter + (process.env.PATH ?? "") };
32011
+ const npm = (args) => execAsync(path60.join(dir, "node.exe"), [path60.join(dir, "node_modules", "npm", "bin", "npm-cli.js"), ...args], {
31438
32012
  env: nodeEnv,
31439
32013
  stdio: "ignore"
31440
32014
  });
31441
- const corepackJs = path58.join(dir, "node_modules", "corepack", "dist", "corepack.js");
32015
+ const corepackJs = path60.join(dir, "node_modules", "corepack", "dist", "corepack.js");
31442
32016
  const extra = config2.corepack && !exists(corepackJs) ? ["corepack"] : [];
31443
32017
  await installOnce(
31444
32018
  env,
@@ -31459,7 +32033,7 @@ var packageManagers = async (env, config2, version2) => {
31459
32033
  }
31460
32034
  try {
31461
32035
  await execAsync(
31462
- path58.join(dir, "node.exe"),
32036
+ path60.join(dir, "node.exe"),
31463
32037
  [corepackJs, "enable", "--install-directory", mkdirp(tool("bin")), "pnpm", "yarn"],
31464
32038
  { env: nodeEnv, stdio: "ignore" }
31465
32039
  );
@@ -31484,8 +32058,8 @@ async function setupPwsh(env, refresh = false) {
31484
32058
  }
31485
32059
 
31486
32060
  // src/guest/toolchains/languages/python.ts
31487
- import fs46 from "node:fs";
31488
- import path59 from "node:path";
32061
+ import fs49 from "node:fs";
32062
+ import path61 from "node:path";
31489
32063
  var installPython = async (pkg, spec) => {
31490
32064
  const version2 = await resolveCached(pkg + ":" + spec, async () => {
31491
32065
  const { versions } = await fetchJson(
@@ -31494,7 +32068,7 @@ var installPython = async (pkg, spec) => {
31494
32068
  return pickPackageVersion(versions, spec) ?? Promise.reject(new Error("No " + pkg + ' release matches "' + spec + '"'));
31495
32069
  });
31496
32070
  const dir = tool("python", pkg + "-" + version2);
31497
- const exe = path59.join(dir, "python.exe");
32071
+ const exe = path61.join(dir, "python.exe");
31498
32072
  if (!exists(exe)) {
31499
32073
  log("Downloading Python " + version2 + (pkg === "python2" ? " (Python 2, " : " (") + "~30 MB once) ...");
31500
32074
  await downloader.archive(
@@ -31503,32 +32077,32 @@ var installPython = async (pkg, spec) => {
31503
32077
  { locate: "python.exe", fileName: pkg + "." + version2 + ".zip" }
31504
32078
  );
31505
32079
  }
31506
- if (!exists(path59.join(dir, "Scripts", "pip.exe")) && !exists(path59.join(dir, "Scripts", "pip2.exe")))
32080
+ if (!exists(path61.join(dir, "Scripts", "pip.exe")) && !exists(path61.join(dir, "Scripts", "pip2.exe")))
31507
32081
  await execAsync(exe, ["-m", "ensurepip", "--default-pip"], { stdio: "ignore" });
31508
32082
  return dir;
31509
32083
  };
31510
- var shimDir = (dir) => duringSession() ? tool("shims", path59.basename(dir)) : tool("shims");
32084
+ var shimDir = (dir) => duringSession() ? tool("shims", path61.basename(dir)) : tool("shims");
31511
32085
  var shim = (folder, name, program, args = []) => {
31512
32086
  const fixed = [program, ...args];
31513
- fs46.writeFileSync(
31514
- path59.join(mkdirp(folder), name + ".cmd"),
32087
+ fs49.writeFileSync(
32088
+ path61.join(mkdirp(folder), name + ".cmd"),
31515
32089
  "@echo off\r\n" + fixed.map((a) => '"' + a + '"').join(" ") + " %*\r\n"
31516
32090
  );
31517
32091
  const sh = fixed.map((a) => "'" + a.replace(/\\/g, "/").replace(/'/g, "'\\''") + "'").join(" ");
31518
- fs46.writeFileSync(path59.join(folder, name), "#!/bin/sh\nexec " + sh + ' "$@"\n');
32092
+ fs49.writeFileSync(path61.join(folder, name), "#!/bin/sh\nexec " + sh + ' "$@"\n');
31519
32093
  };
31520
32094
  var shimPair = (folder, version2, dir) => {
31521
- const python = path59.join(dir, "python.exe");
32095
+ const python = path61.join(dir, "python.exe");
31522
32096
  shim(folder, "python" + version2, python);
31523
32097
  shim(folder, "pip" + version2, python, ["-m", "pip"]);
31524
32098
  };
31525
32099
  var pyLauncher = (folder, py3, py2) => {
31526
- const script = path59.join(mkdirp(folder), "py-launcher.py");
31527
- fs46.writeFileSync(
32100
+ const script = path61.join(mkdirp(folder), "py-launcher.py");
32101
+ fs49.writeFileSync(
31528
32102
  script,
31529
32103
  [
31530
32104
  "import subprocess, sys",
31531
- "PY3, PY2 = " + JSON.stringify(path59.join(py3, "python.exe")) + ", " + JSON.stringify(py2 ? path59.join(py2, "python.exe") : null),
32105
+ "PY3, PY2 = " + JSON.stringify(path61.join(py3, "python.exe")) + ", " + JSON.stringify(py2 ? path61.join(py2, "python.exe") : null),
31532
32106
  "args = sys.argv[1:]",
31533
32107
  "exe = PY3",
31534
32108
  "if args and args[0].startswith('-2'):",
@@ -31540,7 +32114,7 @@ var pyLauncher = (folder, py3, py2) => {
31540
32114
  ""
31541
32115
  ].join("\n")
31542
32116
  );
31543
- shim(folder, "py", path59.join(py3, "python.exe"), [script]);
32117
+ shim(folder, "py", path61.join(py3, "python.exe"), [script]);
31544
32118
  };
31545
32119
  async function setupPython(env, config2, versions) {
31546
32120
  if (dryRun) {
@@ -31550,10 +32124,10 @@ async function setupPython(env, config2, versions) {
31550
32124
  const py3 = await installPython("python", versions.python.spec);
31551
32125
  const shims = shimDir(py3);
31552
32126
  shimPair(shims, "3", py3);
31553
- env.prepend.push(py3, mkdirp(path59.join(py3, "Scripts")), shims);
32127
+ env.prepend.push(py3, mkdirp(path61.join(py3, "Scripts")), shims);
31554
32128
  env.vars.PYTHONIOENCODING = "utf-8";
31555
32129
  env.summary.push(
31556
- "python: " + path59.basename(py3).replace("python-", "") + " (from " + versions.python.source + "; py works too)"
32130
+ "python: " + path61.basename(py3).replace("python-", "") + " (from " + versions.python.source + "; py works too)"
31557
32131
  );
31558
32132
  if (!config2.python2) {
31559
32133
  pyLauncher(shims, py3, null);
@@ -31562,12 +32136,12 @@ async function setupPython(env, config2, versions) {
31562
32136
  const py2 = await installPython("python2", "2.7");
31563
32137
  shimPair(shims, "2", py2);
31564
32138
  pyLauncher(shims, py3, py2);
31565
- env.summary.push("python2: " + path59.basename(py2).replace("python2-", ""));
32139
+ env.summary.push("python2: " + path61.basename(py2).replace("python2-", ""));
31566
32140
  }
31567
32141
 
31568
32142
  // src/guest/toolchains/languages/php.ts
31569
- import fs47 from "node:fs";
31570
- import path60 from "node:path";
32143
+ import fs50 from "node:fs";
32144
+ import path62 from "node:path";
31571
32145
  var PHP_EXTENSIONS = [
31572
32146
  "curl",
31573
32147
  "fileinfo",
@@ -31585,11 +32159,11 @@ var PHP_EXTENSIONS = [
31585
32159
  var COMPOSER = "https://getcomposer.org/download/latest-stable/composer.phar";
31586
32160
  var phpBuild = async (spec) => {
31587
32161
  const releases = await fetchJson("https://windows.php.net/downloads/releases/releases.json");
31588
- const pick2 = pickPackageVersion(
32162
+ const pick3 = pickPackageVersion(
31589
32163
  Object.values(releases).map((r) => r.version),
31590
32164
  spec
31591
32165
  );
31592
- const release = Object.values(releases).find((r) => r.version === pick2);
32166
+ const release = Object.values(releases).find((r) => r.version === pick3);
31593
32167
  const build = release && Object.entries(release).find(
31594
32168
  ([key2, value]) => /^nts-vs\d+-x64$/.test(key2) && typeof value === "object" && value.zip
31595
32169
  )?.[1];
@@ -31598,16 +32172,16 @@ var phpBuild = async (spec) => {
31598
32172
  return { version: release.version, ...build.zip };
31599
32173
  };
31600
32174
  var writePhpIni = (home) => {
31601
- const ini = path60.join(home, "php.ini");
31602
- if (exists(ini) || !exists(path60.join(home, "php.ini-development"))) return;
31603
- let text = fs47.readFileSync(path60.join(home, "php.ini-development"), "utf8").replace(/^;\s*extension_dir\s*=\s*"ext"/m, 'extension_dir = "' + path60.join(home, "ext") + '"');
31604
- for (const ext of PHP_EXTENSIONS.filter((e) => exists(path60.join(home, "ext", "php_" + e + ".dll"))))
32175
+ const ini = path62.join(home, "php.ini");
32176
+ if (exists(ini) || !exists(path62.join(home, "php.ini-development"))) return;
32177
+ let text = fs50.readFileSync(path62.join(home, "php.ini-development"), "utf8").replace(/^;\s*extension_dir\s*=\s*"ext"/m, 'extension_dir = "' + path62.join(home, "ext") + '"');
32178
+ for (const ext of PHP_EXTENSIONS.filter((e) => exists(path62.join(home, "ext", "php_" + e + ".dll"))))
31605
32179
  text = text.replace(new RegExp("^;(extension=" + ext + ")\\s*$", "m"), "$1");
31606
- fs47.writeFileSync(ini + ".tmp", text);
31607
- fs47.renameSync(ini + ".tmp", ini);
32180
+ fs50.writeFileSync(ini + ".tmp", text);
32181
+ fs50.renameSync(ini + ".tmp", ini);
31608
32182
  };
31609
32183
  var shim2 = (env, name, command) => {
31610
- fs47.writeFileSync(path60.join(mkdirp(tool("shims")), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
32184
+ fs50.writeFileSync(path62.join(mkdirp(tool("shims")), name + ".cmd"), "@echo off\r\n" + command + " %*\r\n");
31611
32185
  env.prepend.push(tool("shims"));
31612
32186
  };
31613
32187
  var setupComposer = async (env, php) => {
@@ -31619,7 +32193,7 @@ var setupComposer = async (env, php) => {
31619
32193
  }
31620
32194
  const composerHome = tool("composer-home");
31621
32195
  env.vars.COMPOSER_HOME = composerHome;
31622
- env.prepend.push(path60.join(composerHome, "vendor", "bin"));
32196
+ env.prepend.push(path62.join(composerHome, "vendor", "bin"));
31623
32197
  shim2(env, "composer", '"' + php + '" "' + phar + '"');
31624
32198
  env.summary.push(
31625
32199
  "composer: " + (/\d+\.\d+\.\d+/.exec(execOutput(php, [phar, "--version", "--no-ansi"]))?.[0] ?? "installed")
@@ -31634,7 +32208,7 @@ async function setupPhp(env, config2) {
31634
32208
  await setupVcRuntime(env, false);
31635
32209
  const version2 = await resolveCached("php:" + wantedSpec.spec, async () => (await phpBuild(wantedSpec.spec)).version);
31636
32210
  const home = tool("php", version2);
31637
- if (!exists(path60.join(home, "php.exe"))) {
32211
+ if (!exists(path62.join(home, "php.exe"))) {
31638
32212
  const build = await phpBuild(version2);
31639
32213
  log("Downloading PHP " + version2 + " (~30 MB once) ...");
31640
32214
  await downloader.archive("https://windows.php.net/downloads/releases/" + build.path, home, {
@@ -31646,11 +32220,11 @@ async function setupPhp(env, config2) {
31646
32220
  writePhpIni(home);
31647
32221
  env.prepend.push(home);
31648
32222
  env.summary.push("php: " + version2 + " (from " + wantedSpec.source + ")");
31649
- if (config2.composer) await setupComposer(env, path60.join(home, "php.exe"));
32223
+ if (config2.composer) await setupComposer(env, path62.join(home, "php.exe"));
31650
32224
  }
31651
32225
 
31652
32226
  // src/guest/toolchains/languages/ruby.ts
31653
- import path61 from "node:path";
32227
+ import path63 from "node:path";
31654
32228
  var RUBY_ASSET = /^rubyinstaller-(\d+\.\d+\.\d+)-(\d+)-x64\.7z$/;
31655
32229
  var buildNumber = (asset) => Number(RUBY_ASSET.exec(asset.name)?.[2] ?? 0);
31656
32230
  var rubyBuilds = async () => {
@@ -31678,7 +32252,7 @@ async function setupRuby(env, config2) {
31678
32252
  async () => pickPackageVersion([...(await rubyBuilds()).keys()], wantedSpec.spec) ?? Promise.reject(new Error('No RubyInstaller build matches "' + wantedSpec.spec + '"'))
31679
32253
  );
31680
32254
  const home = tool("ruby", version2);
31681
- if (!exists(path61.join(home, "bin", "ruby.exe"))) {
32255
+ if (!exists(path63.join(home, "bin", "ruby.exe"))) {
31682
32256
  const asset = (await rubyBuilds()).get(version2);
31683
32257
  if (!asset) throw new Error("RubyInstaller " + version2 + " is no longer published");
31684
32258
  log("Downloading Ruby " + version2 + " (~100 MB once) ...");
@@ -31691,11 +32265,11 @@ async function setupRuby(env, config2) {
31691
32265
  }
31692
32266
  const gems = tool("ruby-gems", version2.split(".").slice(0, 2).join("."));
31693
32267
  Object.assign(env.vars, { GEM_HOME: gems, BUNDLE_USER_HOME: tool("bundle-home") });
31694
- env.prepend.push(path61.join(home, "bin"), path61.join(gems, "bin"));
32268
+ env.prepend.push(path63.join(home, "bin"), path63.join(gems, "bin"));
31695
32269
  env.summary.push(
31696
- "ruby: " + versionOf(path61.join(home, "bin", "ruby.exe")) + " (from " + wantedSpec.source + "; gems with C extensions need MSYS2, not included)"
32270
+ "ruby: " + versionOf(path63.join(home, "bin", "ruby.exe")) + " (from " + wantedSpec.source + "; gems with C extensions need MSYS2, not included)"
31697
32271
  );
31698
- const gem = path61.join(home, "bin", "gem.cmd");
32272
+ const gem = path63.join(home, "bin", "gem.cmd");
31699
32273
  await installOnce(
31700
32274
  env,
31701
32275
  "gem@" + version2,
@@ -31707,9 +32281,9 @@ async function setupRuby(env, config2) {
31707
32281
  }
31708
32282
 
31709
32283
  // src/guest/toolchains/tools/vscode.ts
31710
- import fs48 from "node:fs";
31711
- import os8 from "node:os";
31712
- import path62 from "node:path";
32284
+ import fs51 from "node:fs";
32285
+ import os9 from "node:os";
32286
+ import path64 from "node:path";
31713
32287
 
31714
32288
  // node_modules/jsonc-parser/lib/esm/impl/scanner.js
31715
32289
  var CharacterCodes;
@@ -31889,14 +32463,14 @@ var ParseErrorCode;
31889
32463
  var VERSION_MARKER = ".agent-sandbox-version";
31890
32464
  var desktopShortcut = (exe) => {
31891
32465
  if (!isWin) return;
31892
- const link = path62.join(os8.homedir(), "Desktop", "Visual Studio Code.lnk");
32466
+ const link = path64.join(os9.homedir(), "Desktop", "Visual Studio Code.lnk");
31893
32467
  runScriptWithJson("new-shortcuts.ps1", "ListFile", [
31894
32468
  { link, target: exe, arguments: '"' + (process.env.AGENT_WORKSPACE ?? "") + '"' }
31895
32469
  ]);
31896
32470
  };
31897
32471
  async function setupVscode(env, refresh) {
31898
32472
  const root = tool("vscode");
31899
- const exe = path62.join(root, "Code.exe");
32473
+ const exe = path64.join(root, "Code.exe");
31900
32474
  if (dryRun) {
31901
32475
  log("(dry run) would provision VS Code");
31902
32476
  return;
@@ -31906,11 +32480,11 @@ async function setupVscode(env, refresh) {
31906
32480
  "https://update.code.visualstudio.com/api/update/win32-" + (arch === "arm64" ? "arm64" : "x64") + "-archive/stable/latest"
31907
32481
  );
31908
32482
  log("Downloading VS Code " + release.productVersion + " (~150 MB once) ...");
31909
- const keep = path62.join(root, "data");
32483
+ const keep = path64.join(root, "data");
31910
32484
  const parked = root + "-data";
31911
32485
  if (exists(keep)) {
31912
- fs48.rmSync(parked, { recursive: true, force: true });
31913
- fs48.renameSync(keep, parked);
32486
+ fs51.rmSync(parked, { recursive: true, force: true });
32487
+ fs51.renameSync(keep, parked);
31914
32488
  }
31915
32489
  try {
31916
32490
  await downloader.archive(release.url, root, {
@@ -31918,26 +32492,511 @@ async function setupVscode(env, refresh) {
31918
32492
  locate: "Code.exe",
31919
32493
  fileName: "vscode.zip"
31920
32494
  });
31921
- fs48.writeFileSync(path62.join(root, VERSION_MARKER), release.productVersion);
32495
+ fs51.writeFileSync(path64.join(root, VERSION_MARKER), release.productVersion);
31922
32496
  } finally {
31923
32497
  if (exists(parked)) {
31924
32498
  mkdirp(root);
31925
- fs48.rmSync(keep, { recursive: true, force: true });
31926
- fs48.renameSync(parked, keep);
32499
+ fs51.rmSync(keep, { recursive: true, force: true });
32500
+ fs51.renameSync(parked, keep);
31927
32501
  }
31928
32502
  }
31929
32503
  }
31930
- mkdirp(path62.join(root, "data"));
31931
- env.prepend.push(path62.join(root, "bin"));
32504
+ mkdirp(path64.join(root, "data"));
32505
+ env.prepend.push(path64.join(root, "bin"));
31932
32506
  desktopShortcut(exe);
31933
- const version2 = exists(path62.join(root, VERSION_MARKER)) ? fs48.readFileSync(path62.join(root, VERSION_MARKER), "utf8").trim() : "installed";
32507
+ const version2 = exists(path64.join(root, VERSION_MARKER)) ? fs51.readFileSync(path64.join(root, VERSION_MARKER), "utf8").trim() : "installed";
31934
32508
  env.summary.push("vscode: " + version2 + " (portable; run code . or use the desktop shortcut)");
31935
32509
  }
31936
32510
 
32511
+ // src/guest/toolchains/steam/steam.ts
32512
+ import fs55 from "node:fs";
32513
+ import path69 from "node:path";
32514
+
32515
+ // src/shared/accounts/kinds/steam.ts
32516
+ import fs52 from "node:fs";
32517
+ import path65 from "node:path";
32518
+
32519
+ // src/shared/vdf.ts
32520
+ var DEFAULT_MAX_BYTES = 1024 * 1024;
32521
+ var DEFAULT_MAX_DEPTH = 32;
32522
+ var DEFAULT_MAX_KEYS = 1e5;
32523
+ var isSpace = (c) => c === " " || c === " " || c === "\r" || c === "\n" || c === "\f";
32524
+ var ESCAPED = { "\\": "\\", '"': '"', n: "\n", t: " " };
32525
+ function tokenize(text, escapes) {
32526
+ const tokens = [];
32527
+ let i = 0;
32528
+ const n = text.length;
32529
+ while (i < n) {
32530
+ const c = text[i];
32531
+ if (isSpace(c)) {
32532
+ i++;
32533
+ } else if (c === "/" && text[i + 1] === "/") {
32534
+ while (i < n && text[i] !== "\n") i++;
32535
+ } else if (c === "{") {
32536
+ tokens.push({ kind: "open" });
32537
+ i++;
32538
+ } else if (c === "}") {
32539
+ tokens.push({ kind: "close" });
32540
+ i++;
32541
+ } else if (c === "[") {
32542
+ const end = text.indexOf("]", i);
32543
+ if (end < 0) return null;
32544
+ i = end + 1;
32545
+ } else if (c === '"') {
32546
+ let out = "";
32547
+ let start = ++i;
32548
+ for (; ; ) {
32549
+ if (i >= n) return null;
32550
+ const d = text[i];
32551
+ if (d === '"') break;
32552
+ if (escapes && d === "\\" && i + 1 < n && ESCAPED[text[i + 1]] !== void 0) {
32553
+ out += text.slice(start, i) + ESCAPED[text[i + 1]];
32554
+ i += 2;
32555
+ start = i;
32556
+ continue;
32557
+ }
32558
+ i++;
32559
+ }
32560
+ tokens.push({ kind: "text", text: out + text.slice(start, i) });
32561
+ i++;
32562
+ } else {
32563
+ const start = i;
32564
+ while (i < n && !isSpace(text[i]) && text[i] !== "{" && text[i] !== "}" && text[i] !== '"') i++;
32565
+ tokens.push({ kind: "text", text: text.slice(start, i) });
32566
+ }
32567
+ }
32568
+ return tokens;
32569
+ }
32570
+ function open2() {
32571
+ return { target: /* @__PURE__ */ Object.create(null), seen: /* @__PURE__ */ new Set() };
32572
+ }
32573
+ function setFirst(o, key2, value) {
32574
+ const lower = key2.toLowerCase();
32575
+ if (o.seen.has(lower)) return false;
32576
+ o.seen.add(lower);
32577
+ o.target[key2] = value;
32578
+ return true;
32579
+ }
32580
+ function parseVdf(text, limits = {}) {
32581
+ const maxBytes = limits.maxBytes ?? DEFAULT_MAX_BYTES;
32582
+ const maxDepth = limits.maxDepth ?? DEFAULT_MAX_DEPTH;
32583
+ const maxKeys = limits.maxKeys ?? DEFAULT_MAX_KEYS;
32584
+ if (typeof text !== "string" || text.length > maxBytes) return null;
32585
+ const tokens = tokenize(text.charCodeAt(0) === 65279 ? text.slice(1) : text, limits.escapes ?? true);
32586
+ if (!tokens) return null;
32587
+ const root = open2();
32588
+ const stack = [root];
32589
+ let keys = 0;
32590
+ let i = 0;
32591
+ while (i < tokens.length) {
32592
+ const token = tokens[i];
32593
+ const current = stack[stack.length - 1];
32594
+ if (token.kind === "close") {
32595
+ if (stack.length === 1) return null;
32596
+ stack.pop();
32597
+ i++;
32598
+ continue;
32599
+ }
32600
+ if (token.kind === "open") return null;
32601
+ if (++keys > maxKeys) return null;
32602
+ const next = tokens[i + 1];
32603
+ if (!next || next.kind === "close") return null;
32604
+ if (next.kind === "open") {
32605
+ if (stack.length > maxDepth) return null;
32606
+ const child = open2();
32607
+ setFirst(current, token.text, child.target);
32608
+ stack.push(child);
32609
+ } else {
32610
+ setFirst(current, token.text, next.text);
32611
+ }
32612
+ i += 2;
32613
+ }
32614
+ return stack.length === 1 ? root.target : null;
32615
+ }
32616
+ function vdfGet(root, ...keys) {
32617
+ let at = root ?? void 0;
32618
+ for (const key2 of keys) {
32619
+ if (at === void 0 || typeof at === "string") return void 0;
32620
+ const lower = key2.toLowerCase();
32621
+ let found;
32622
+ for (const k in at)
32623
+ if (k.toLowerCase() === lower) {
32624
+ found = at[k];
32625
+ break;
32626
+ }
32627
+ at = found;
32628
+ }
32629
+ return at;
32630
+ }
32631
+ function vdfObject(root, ...keys) {
32632
+ const value = vdfGet(root, ...keys);
32633
+ return value !== void 0 && typeof value !== "string" ? value : void 0;
32634
+ }
32635
+
32636
+ // src/shared/accounts/kinds/steam.ts
32637
+ var MAX_STEAM_CONFIG_BYTES = 256 * 1024;
32638
+ var MAX_SENTRY_BYTES = 48 * 1024;
32639
+ var MAX_SENTRIES = 4;
32640
+ var MAX_ENTRIES2 = 5e3;
32641
+ var SENTRY = /^ssfn\d{1,40}$/;
32642
+ var STEAM_ACCOUNT = /^[A-Za-z0-9_]{1,64}$/;
32643
+ var STEAM_ACCOUNT_FILE = "sbx-account.txt";
32644
+ function steamConfigFile(steamcmdDir) {
32645
+ return path65.join(steamcmdDir, "config", "config.vdf");
32646
+ }
32647
+ function steamKey(root) {
32648
+ return vdfObject(root, "InstallConfigStore", "Software", "Valve", "Steam");
32649
+ }
32650
+ function hasCachedLogin(configVdf) {
32651
+ const cache = vdfObject(steamKey(parseVdf(configVdf, { maxBytes: MAX_STEAM_CONFIG_BYTES })), "ConnectCache");
32652
+ return cache !== void 0 && Object.keys(cache).length > 0;
32653
+ }
32654
+ function steamAccounts(configVdf) {
32655
+ const accounts = vdfObject(steamKey(parseVdf(configVdf, { maxBytes: MAX_STEAM_CONFIG_BYTES })), "Accounts");
32656
+ return accounts ? Object.keys(accounts).filter((a) => STEAM_ACCOUNT.test(a)) : [];
32657
+ }
32658
+ function readSteamAccountFile(steamcmdDir) {
32659
+ const bytes = readBoundedFile(path65.join(steamcmdDir, "config", STEAM_ACCOUNT_FILE), 256);
32660
+ const name = bytes ? decodeText(bytes).text.trim() : "";
32661
+ return STEAM_ACCOUNT.test(name) ? name : null;
32662
+ }
32663
+ function readSentries(steamcmdDir) {
32664
+ let names;
32665
+ try {
32666
+ names = fs52.readdirSync(steamcmdDir).slice(0, MAX_ENTRIES2).filter((n) => SENTRY.test(n));
32667
+ } catch {
32668
+ return [];
32669
+ }
32670
+ const mtime = (name) => {
32671
+ try {
32672
+ return fs52.lstatSync(path65.join(steamcmdDir, name)).mtimeMs;
32673
+ } catch {
32674
+ return 0;
32675
+ }
32676
+ };
32677
+ const found = [];
32678
+ for (const name of names.sort((a, b) => mtime(b) - mtime(a))) {
32679
+ if (found.length >= MAX_SENTRIES) break;
32680
+ const bytes = readBoundedFile(path65.join(steamcmdDir, name), MAX_SENTRY_BYTES);
32681
+ if (bytes && bytes.length) found.push({ name, base64: bytes.toString("base64") });
32682
+ }
32683
+ return found.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
32684
+ }
32685
+ function readSteamCmdLogin(steamcmdDir, account) {
32686
+ const bytes = readBoundedFile(steamConfigFile(steamcmdDir), MAX_STEAM_CONFIG_BYTES);
32687
+ if (!bytes) return null;
32688
+ const configVdf = decodeText(bytes).text;
32689
+ if (!hasCachedLogin(configVdf)) return null;
32690
+ const name = readSteamAccountFile(steamcmdDir) ?? steamAccounts(configVdf)[0] ?? account;
32691
+ if (!name) return null;
32692
+ const parsed = SteamPayloadSchema.safeParse({ account: name, configVdf, sentries: readSentries(steamcmdDir) });
32693
+ return parsed.success ? parsed.data : null;
32694
+ }
32695
+ function writeSteamCmdLogin(steamcmdDir, p) {
32696
+ const login = SteamPayloadSchema.parse(p);
32697
+ const config2 = path65.dirname(steamConfigFile(steamcmdDir));
32698
+ fs52.mkdirSync(config2, { recursive: true });
32699
+ fs52.writeFileSync(steamConfigFile(steamcmdDir), login.configVdf, "utf8");
32700
+ fs52.writeFileSync(path65.join(config2, STEAM_ACCOUNT_FILE), login.account, "utf8");
32701
+ for (const s of login.sentries) fs52.writeFileSync(path65.join(steamcmdDir, s.name), Buffer.from(s.base64, "base64"));
32702
+ }
32703
+
32704
+ // src/guest/toolchains/steam/client.ts
32705
+ import fs53 from "node:fs";
32706
+ import path67 from "node:path";
32707
+
32708
+ // src/guest/toolchains/steam/commands.ts
32709
+ import path66 from "node:path";
32710
+ var STEAMCMD_DIR = "C:\\SteamCMD";
32711
+ var STEAMCMD_URL = "https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip";
32712
+ var STEAM_CLIENT_URL = "https://steamcdn-a.akamaihd.net/client/installer/SteamSetup.exe";
32713
+ function steamCmdStore(tools = toolsDir) {
32714
+ return path66.join(tools, "steamcmd");
32715
+ }
32716
+ function steamClientDir(tools = toolsDir) {
32717
+ return path66.join(tools, "steam");
32718
+ }
32719
+ var MAX_SCRIPT_BYTES = 256 * 1024;
32720
+
32721
+ // src/guest/toolchains/steam/client.ts
32722
+ var GB2 = 1024 ** 3;
32723
+ var CLIENT_NEED_BYTES = 2 * GB2;
32724
+ var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
32725
+ function installedSteamClient() {
32726
+ const exe = path67.join(steamClientDir(), "steam.exe");
32727
+ return exists(exe) && signedBy(exe, SIGNERS.valve) ? exe : null;
32728
+ }
32729
+ async function installSteamClient() {
32730
+ const dir = steamClientDir();
32731
+ const exe = path67.join(dir, "steam.exe");
32732
+ if (exists(exe)) {
32733
+ if (!signedBy(exe, SIGNERS.valve)) throw new Error("tools\\steam\\steam.exe is not signed by Valve");
32734
+ return exe;
32735
+ }
32736
+ fs53.mkdirSync(toolsDir, { recursive: true });
32737
+ assertRoom(toolsDir, CLIENT_NEED_BYTES, "the Steam client", "Free room on the data disk.");
32738
+ const setup = await signedInstaller(
32739
+ STEAM_CLIENT_URL,
32740
+ path67.join(tool("steam-setup"), "SteamSetup.exe"),
32741
+ "the Steam client installer (~2 MB once)",
32742
+ SIGNERS.valve
32743
+ );
32744
+ const work = stagingFolder(dir);
32745
+ fs53.mkdirSync(work, { recursive: true });
32746
+ try {
32747
+ log("Unpacking the Steam client into tools\\steam ...");
32748
+ const code = await spawnAsync(setup, ["/S", "/D=" + work], { timeout: SETUP_TIMEOUT_MS });
32749
+ const unpacked = path67.join(work, "steam.exe");
32750
+ if (!exists(unpacked)) throw new Error("SteamSetup.exe did not unpack steam.exe (exit code " + code + ")");
32751
+ if (!signedBy(unpacked, SIGNERS.valve)) throw new Error("the unpacked steam.exe is not signed by Valve");
32752
+ moveIntoPlace(work, dir);
32753
+ } finally {
32754
+ if (fs53.existsSync(work)) safeRemove(work, path67.dirname(work));
32755
+ }
32756
+ return exe;
32757
+ }
32758
+ async function ensureSteamClient(env) {
32759
+ try {
32760
+ const exe = await installSteamClient();
32761
+ env.summary.push("steam client: tools\\steam (start it with sbx-steam client; sign in there in each sandbox)");
32762
+ return exe;
32763
+ } catch (e) {
32764
+ log("Steam client: not set up: " + errMsg(e));
32765
+ env.summary.push("steam client: not set up (" + errMsg(e) + ")");
32766
+ return null;
32767
+ }
32768
+ }
32769
+
32770
+ // src/guest/toolchains/steam/steamcmd-install.ts
32771
+ import { spawn as spawn5 } from "node:child_process";
32772
+ import fs54 from "node:fs";
32773
+ import path68 from "node:path";
32774
+ var MB = 1024 ** 2;
32775
+ var STEAMCMD_NEED_BYTES = 600 * MB;
32776
+ var STEAMCMD_UPDATE_TIMEOUT_MS = 15 * 60 * 1e3;
32777
+ var PRIVATE_DIRS = /* @__PURE__ */ new Set(["config", "logs", "dumps", "userdata", "steamapps", "appcache", "depotcache"]);
32778
+ var isPrivate = (name) => PRIVATE_DIRS.has(name.toLowerCase()) || /^ssfn/i.test(name);
32779
+ var BOOTSTRAPPED = ["steamclient.dll", "steamclient64.dll"];
32780
+ function runWithTimeout(exe, args, cwd, timeoutMs) {
32781
+ return new Promise((resolve2, reject) => {
32782
+ const child = spawn5(exe, args, { cwd, stdio: "ignore", windowsHide: true });
32783
+ let timedOut = false;
32784
+ const timer = setTimeout(() => {
32785
+ timedOut = true;
32786
+ child.kill();
32787
+ }, timeoutMs);
32788
+ child.once("error", (e) => {
32789
+ clearTimeout(timer);
32790
+ reject(e);
32791
+ });
32792
+ child.once("close", (code) => {
32793
+ clearTimeout(timer);
32794
+ resolve2({ code: code ?? -1, timedOut });
32795
+ });
32796
+ });
32797
+ }
32798
+ var notSigned = (file3) => new Error(path68.basename(file3) + " is not signed by Valve: not running it (it is downloaded again next boot)");
32799
+ async function fetchSteamCmd(store2, deps) {
32800
+ fs54.mkdirSync(path68.dirname(store2), { recursive: true });
32801
+ assertRoom(path68.dirname(store2), STEAMCMD_NEED_BYTES, "SteamCMD", "Free room on the data disk.", deps);
32802
+ const work = stagingFolder(store2);
32803
+ const unpacked = path68.join(work, "x");
32804
+ const extract = deps.extract ?? extractArchive;
32805
+ try {
32806
+ fs54.mkdirSync(work, { recursive: true });
32807
+ const verify = async (part) => {
32808
+ await extract(part, unpacked);
32809
+ const exe = path68.join(unpacked, "steamcmd.exe");
32810
+ if (!fs54.existsSync(exe)) throw new Error("steamcmd.zip has no steamcmd.exe");
32811
+ if (!deps.signed(exe)) throw notSigned(exe);
32812
+ };
32813
+ const zip = path68.join(work, "steamcmd.zip");
32814
+ if (deps.download) await deps.download(STEAMCMD_URL, zip, verify);
32815
+ else await downloader.file(STEAMCMD_URL, zip, { verify });
32816
+ moveIntoPlace(unpacked, store2);
32817
+ } finally {
32818
+ if (fs54.existsSync(work)) safeRemove(work, path68.dirname(work));
32819
+ }
32820
+ }
32821
+ async function copyBinaries(from, to) {
32822
+ fs54.mkdirSync(to, { recursive: true });
32823
+ for (const entry of fs54.readdirSync(from, { withFileTypes: true })) {
32824
+ if (isPrivate(entry.name) || entry.isSymbolicLink()) continue;
32825
+ if (!entry.isFile() && !entry.isDirectory()) continue;
32826
+ await fs54.promises.cp(path68.join(from, entry.name), path68.join(to, entry.name), {
32827
+ recursive: true,
32828
+ force: true,
32829
+ verbatimSymlinks: true,
32830
+ filter: (source) => {
32831
+ try {
32832
+ return !fs54.lstatSync(source).isSymbolicLink();
32833
+ } catch {
32834
+ return false;
32835
+ }
32836
+ }
32837
+ });
32838
+ }
32839
+ }
32840
+ function snapshot(dir) {
32841
+ try {
32842
+ return fs54.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && !isPrivate(e.name) && /\.(exe|dll)$/i.test(e.name)).map((e) => {
32843
+ const s = fs54.statSync(path68.join(dir, e.name));
32844
+ return e.name.toLowerCase() + ":" + s.size + ":" + Math.floor(s.mtimeMs / 1e3);
32845
+ }).sort().join("|");
32846
+ } catch {
32847
+ return "";
32848
+ }
32849
+ }
32850
+ var bootstrapped = (dir) => BOOTSTRAPPED.some((f) => fs54.existsSync(path68.join(dir, f)));
32851
+ function scrubStore(store2) {
32852
+ let names = [];
32853
+ try {
32854
+ names = fs54.readdirSync(store2);
32855
+ } catch {
32856
+ return;
32857
+ }
32858
+ for (const name of names.filter(isPrivate)) safeRemove(path68.join(store2, name), store2);
32859
+ }
32860
+ async function prepareSteamCmd(deps) {
32861
+ const store2 = deps.storeDir ?? steamCmdStore(deps.toolsDir);
32862
+ const work = deps.workDir ?? STEAMCMD_DIR;
32863
+ const log2 = deps.log ?? (() => void 0);
32864
+ const exe = path68.join(work, "steamcmd.exe");
32865
+ if (fs54.existsSync(exe) && bootstrapped(work)) {
32866
+ if (!deps.signed(exe)) throw notSigned(exe);
32867
+ return exe;
32868
+ }
32869
+ if (!fs54.existsSync(path68.join(store2, "steamcmd.exe"))) {
32870
+ log2("Downloading SteamCMD (~3 MB once; it fetches ~300 MB on its first run) ...");
32871
+ await fetchSteamCmd(store2, deps);
32872
+ }
32873
+ scrubStore(store2);
32874
+ await copyBinaries(store2, work);
32875
+ if (!deps.signed(exe)) {
32876
+ safeRemove(store2, path68.dirname(store2));
32877
+ throw notSigned(exe);
32878
+ }
32879
+ const before = snapshot(work);
32880
+ const run2 = deps.run ?? runWithTimeout;
32881
+ const limit = deps.updateTimeoutMs ?? STEAMCMD_UPDATE_TIMEOUT_MS;
32882
+ for (let attempt = 1; attempt <= 2; attempt++) {
32883
+ log2(attempt === 1 ? "SteamCMD: checking for updates ..." : "SteamCMD: trying its update once more ...");
32884
+ const result = await run2(exe, ["+quit"], work, limit);
32885
+ if (result.timedOut)
32886
+ throw new Error("SteamCMD did not finish updating itself in " + Math.round(limit / 6e4) + " minutes");
32887
+ if (bootstrapped(work)) break;
32888
+ if (attempt === 2) throw new Error("SteamCMD did not finish its first run (exit code " + result.code + ")");
32889
+ }
32890
+ if (!deps.signed(exe)) throw notSigned(exe);
32891
+ if (snapshot(work) !== before || !bootstrapped(store2)) {
32892
+ const staging = stagingFolder(store2);
32893
+ try {
32894
+ await copyBinaries(work, staging);
32895
+ moveIntoPlace(staging, store2);
32896
+ } finally {
32897
+ if (fs54.existsSync(staging)) safeRemove(staging, path68.dirname(staging));
32898
+ }
32899
+ }
32900
+ return exe;
32901
+ }
32902
+
32903
+ // src/guest/toolchains/steam/steamcmd.ts
32904
+ function installSteamCmd() {
32905
+ return prepareSteamCmd({ signed: (file3) => signedBy(file3, SIGNERS.valve), log });
32906
+ }
32907
+
32908
+ // src/guest/toolchains/steam/steam.ts
32909
+ function signedInAs() {
32910
+ const bytes = readBoundedFile(steamConfigFile(STEAMCMD_DIR), 256 * 1024);
32911
+ if (!bytes || !hasCachedLogin(bytes.toString("utf8"))) return null;
32912
+ return readSteamAccountFile(STEAMCMD_DIR) ?? "your account";
32913
+ }
32914
+ function sdkFolder(env, setting) {
32915
+ if (!setting.trim()) return;
32916
+ const dir = path69.resolve(projectWorkspace(), setting.trim());
32917
+ let ok = false;
32918
+ try {
32919
+ ok = fs55.statSync(dir).isDirectory();
32920
+ } catch {
32921
+ }
32922
+ if (!ok) {
32923
+ log("Steamworks SDK: " + dir + " is not there (toolchains.steam.sdkFolder); STEAMWORKS_SDK is not set");
32924
+ env.summary.push("steamworks sdk: " + dir + " not found");
32925
+ return;
32926
+ }
32927
+ env.vars.STEAMWORKS_SDK = dir;
32928
+ env.summary.push("steamworks sdk: STEAMWORKS_SDK=" + dir);
32929
+ }
32930
+ async function setupSteam(env, config2, ctx) {
32931
+ if (dryRun) {
32932
+ log("(dry run) would set up SteamCMD" + (config2.client ? " and the Steam client" : ""));
32933
+ return;
32934
+ }
32935
+ const exe = await installSteamCmd();
32936
+ env.append.push(STEAMCMD_DIR);
32937
+ env.vars.STEAMCMD = exe;
32938
+ const user = signedInAs();
32939
+ env.summary.push(
32940
+ "steamcmd: C:\\SteamCMD, " + (user ? "signed in as " + user : "not signed in (sbx-steam login <account>)")
32941
+ );
32942
+ sdkFolder(env, config2.sdkFolder);
32943
+ const fromPc = ctx.pcInstalls.items.filter((i) => i.kind === "steam-game" || i.kind === "steam-library");
32944
+ if (fromPc.length)
32945
+ env.summary.push(
32946
+ "steam: " + fromPc.length + " of this PC's games or libraries, read-only in C:\\PcInstalls\\steam"
32947
+ );
32948
+ if (!config2.client) return;
32949
+ if (ctx.duringSession && !installedSteamClient()) {
32950
+ env.summary.push("steam client: restart the sandbox to install it");
32951
+ return;
32952
+ }
32953
+ await ensureSteamClient(env);
32954
+ }
32955
+
32956
+ // src/guest/toolchains/engines/godot.ts
32957
+ async function setupGodot(env, _config, _ctx) {
32958
+ notAvailableYet(env, "Godot");
32959
+ }
32960
+
32961
+ // src/guest/toolchains/engines/unity.ts
32962
+ async function setupUnity(env, _config, _ctx) {
32963
+ notAvailableYet(env, "Unity");
32964
+ }
32965
+
32966
+ // src/guest/toolchains/fivem/fivem.ts
32967
+ async function setupFivem(env, _config, _ctx) {
32968
+ notAvailableYet(env, "FiveM server");
32969
+ }
32970
+
32971
+ // src/guest/toolchains/mobile/android.ts
32972
+ async function setupAndroid(env, _config, _ctx) {
32973
+ notAvailableYet(env, "Android SDK");
32974
+ }
32975
+
32976
+ // src/guest/toolchains/mobile/flutter.ts
32977
+ async function setupFlutter(env, _config, _ctx) {
32978
+ notAvailableYet(env, "Flutter");
32979
+ }
32980
+
32981
+ // src/guest/toolchains/mobile/dart.ts
32982
+ async function setupDart(env, _config, _ctx) {
32983
+ notAvailableYet(env, "Dart");
32984
+ }
32985
+
32986
+ // src/guest/toolchains/mobile/react-native.ts
32987
+ async function setupReactNative(env, _config, _ctx) {
32988
+ notAvailableYet(env, "React Native");
32989
+ }
32990
+
32991
+ // src/guest/toolchains/languages/kotlin.ts
32992
+ async function setupKotlin(env, _ctx) {
32993
+ notAvailableYet(env, "Kotlin");
32994
+ }
32995
+
31937
32996
  // src/guest/toolchains/native/rust-extras.ts
31938
- import fs49 from "node:fs";
31939
- import os9 from "node:os";
31940
- import path63 from "node:path";
32997
+ import fs56 from "node:fs";
32998
+ import os10 from "node:os";
32999
+ import path70 from "node:path";
31941
33000
 
31942
33001
  // src/shared/memory/policy.ts
31943
33002
  var DIAL_STEPS = {
@@ -31986,41 +33045,41 @@ function maxCompilers(cpus, profile) {
31986
33045
  // src/guest/toolchains/native/rust-extras.ts
31987
33046
  var cargoTarget = (targetDir) => {
31988
33047
  if (targetDir === "shared" || targetDir === "separate") return null;
31989
- if (targetDir === "local") return path63.join(localDir, "cargo-target");
33048
+ if (targetDir === "local") return path70.join(localDir, "cargo-target");
31990
33049
  return targetDir;
31991
33050
  };
31992
33051
  function cargoShim(env, rust) {
31993
- const real = path63.join(tool("rust", "cargo", "bin"), "cargo.exe");
33052
+ const real = path70.join(tool("rust", "cargo", "bin"), "cargo.exe");
31994
33053
  if (rust.targetDir !== "separate" || !exists(real)) return;
31995
33054
  const dir = mkdirp(tool("shims", "cargo"));
31996
- fs49.copyFileSync(ensureCompiled("cargoshim"), path63.join(dir, "cargo.exe"));
33055
+ fs56.copyFileSync(ensureCompiled("cargoshim"), path70.join(dir, "cargo.exe"));
31997
33056
  env.prepend.unshift(dir);
31998
33057
  env.vars.AGENT_REAL_CARGO = real;
31999
33058
  }
32000
33059
  function linkGate(env, rust, host) {
32001
33060
  const gcc = tool("mingw", "mingw64", "bin", "gcc.exe");
32002
33061
  if (!host.endsWith("-pc-windows-gnu") || !exists(gcc)) return;
32003
- const gate = path63.join(mkdirp(tool("shims")), "linkgate.exe");
32004
- fs49.copyFileSync(ensureCompiled("linkgate"), gate);
32005
- const memoryGb = os9.totalmem() / 1024 ** 3;
33062
+ const gate = path70.join(mkdirp(tool("shims")), "linkgate.exe");
33063
+ fs56.copyFileSync(ensureCompiled("linkgate"), gate);
33064
+ const memoryGb = os10.totalmem() / 1024 ** 3;
32006
33065
  const slots = rust.linkSlots === "auto" ? linkSlotsFor(memoryGb) : rust.linkSlots;
32007
33066
  env.vars.AGENT_LINK_SLOTS = String(slots);
32008
33067
  env.vars.AGENT_REAL_LINKER = gcc;
32009
33068
  env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gate;
32010
33069
  const rustEnv = { ...process.env, RUSTUP_HOME: tool("rust", "rustup"), CARGO_HOME: tool("rust", "cargo") };
32011
33070
  const sysroot = rust.linker === "lld" ? execOutput(tool("rust", "cargo", "bin", "rustc.exe"), ["--print", "sysroot"], { env: rustEnv }) : "";
32012
- const lld = sysroot ? path63.join(sysroot, "lib", "rustlib", host, "bin", "gcc-ld") : "";
32013
- if (lld && exists(path63.join(lld, "ld.lld.exe"))) env.vars.AGENT_LLD_DIR = lld;
33071
+ const lld = sysroot ? path70.join(sysroot, "lib", "rustlib", host, "bin", "gcc-ld") : "";
33072
+ if (lld && exists(path70.join(lld, "ld.lld.exe"))) env.vars.AGENT_LLD_DIR = lld;
32014
33073
  env.summary.push(
32015
33074
  "rust linking: " + (env.vars.AGENT_LLD_DIR ? "lld" : "GNU ld") + ", at most " + env.vars.AGENT_LINK_SLOTS + " at once"
32016
33075
  );
32017
33076
  }
32018
33077
  function cargoDefaults(host) {
32019
33078
  const file3 = tool("rust", "cargo", "config.toml");
32020
- if (exists(file3) || !exists(path63.dirname(file3))) return;
32021
- const jobs = cargoJobs(os9.cpus().length, os9.totalmem() / 1024 ** 3, 1);
33079
+ if (exists(file3) || !exists(path70.dirname(file3))) return;
33080
+ const jobs = cargoJobs(os10.cpus().length, os10.totalmem() / 1024 ** 3, 1);
32022
33081
  const gnu = host.endsWith("-gnu");
32023
- fs49.writeFileSync(
33082
+ fs56.writeFileSync(
32024
33083
  file3,
32025
33084
  [
32026
33085
  "# Written by windows-development-sandbox once; edit freely, it is never overwritten.",
@@ -32035,7 +33094,7 @@ function rustCaches(rust) {
32035
33094
  const target = cargoTarget(rust.targetDir);
32036
33095
  return {
32037
33096
  ...target ? { CARGO_TARGET_DIR: target } : {},
32038
- ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path63.join(dataDir, "cache", "sccache") }
33097
+ ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path70.join(dataDir, "cache", "sccache") }
32039
33098
  };
32040
33099
  }
32041
33100
  function rustHost(config2) {
@@ -32063,6 +33122,13 @@ function plan(config2, versions, o) {
32063
33122
  const java = wanted(config2.java.enabled, "java");
32064
33123
  const python = wanted(config2.python.enabled, "python");
32065
33124
  const unreal = wanted(config2.unreal.enabled, "unreal");
33125
+ const android = wanted(config2.android.enabled, "android");
33126
+ const vs = visualStudioWanted(config2, (setting, name) => wanted(setting, name));
33127
+ const ctx = {
33128
+ refresh: o.refresh,
33129
+ pcInstalls: o.pcInstalls ?? { items: [] },
33130
+ duringSession: duringSession()
33131
+ };
32066
33132
  return [
32067
33133
  {
32068
33134
  name: "Git",
@@ -32080,18 +33146,32 @@ function plan(config2, versions, o) {
32080
33146
  enabled: wanted(config2.cpp.enabled, "cpp") || wanted(config2.rust.enabled, "rust"),
32081
33147
  install: (env) => setupCpp(env, config2.cpp)
32082
33148
  },
32083
- // Unreal's Visual Studio brings MSVC and the real vswhere: the portable MSVC (and its stand-in vswhere) stays out.
32084
- { name: "Unreal", enabled: unreal, shared: true, install: (env) => setupUnreal(env, config2.unreal) },
33149
+ // Visual Studio brings MSVC and the real vswhere: the portable MSVC (and its stand-in vswhere) stays out.
33150
+ {
33151
+ name: "Visual Studio",
33152
+ enabled: vs !== null,
33153
+ shared: true,
33154
+ install: async (env) => {
33155
+ await ensureVisualStudio(env, vs, { keepInstallFiles: config2.unreal.keepInstallFiles });
33156
+ }
33157
+ },
33158
+ {
33159
+ name: "Unreal",
33160
+ enabled: unreal,
33161
+ shared: true,
33162
+ after: ["Visual Studio"],
33163
+ install: (env) => setupUnreal(env, config2.unreal, ctx)
33164
+ },
32085
33165
  {
32086
33166
  name: "MSVC",
32087
- enabled: wanted(config2.msvc.enabled, "msvc") && !unreal,
33167
+ enabled: wanted(config2.msvc.enabled, "msvc") && vs === null,
32088
33168
  install: (env) => setupMsvc(env, config2.msvc)
32089
33169
  },
32090
33170
  // Rust links with MSVC (msvc host) or MinGW's gcc (GNU host): whichever it uses goes first.
32091
33171
  {
32092
33172
  name: "Rust",
32093
33173
  enabled: wanted(config2.rust.enabled, "rust"),
32094
- after: ["C/C++", "MSVC", "Unreal"],
33174
+ after: ["C/C++", "MSVC", "Visual Studio", "Unreal"],
32095
33175
  install: async (env) => {
32096
33176
  await setupRust(env, { ...config2.rust, host: rustHost(config2) }, o.refresh);
32097
33177
  Object.assign(env.vars, rustCaches(config2.rust));
@@ -32109,6 +33189,49 @@ function plan(config2, versions, o) {
32109
33189
  },
32110
33190
  { name: "Go", enabled: wanted(config2.go.enabled, "go"), install: (env) => setupGo(env, config2.go) },
32111
33191
  { name: "Java", enabled: java, install: (env) => setupJava(env, config2.java) },
33192
+ { name: "Kotlin", enabled: java && config2.java.kotlin, after: ["Java"], install: (env) => setupKotlin(env, ctx) },
33193
+ // Game engines, stores and mobile: each module keeps its big installs in tools (persisted.ts).
33194
+ {
33195
+ name: "Android SDK",
33196
+ enabled: android,
33197
+ after: ["Java"],
33198
+ install: (env) => setupAndroid(env, config2.android, ctx)
33199
+ },
33200
+ {
33201
+ name: "Steam",
33202
+ enabled: wanted(config2.steam.enabled, "steam"),
33203
+ install: (env) => setupSteam(env, config2.steam, ctx)
33204
+ },
33205
+ {
33206
+ name: "Unity",
33207
+ enabled: wanted(config2.unity.enabled, "unity"),
33208
+ after: ["Visual Studio", "Android SDK"],
33209
+ install: (env) => setupUnity(env, config2.unity, ctx)
33210
+ },
33211
+ {
33212
+ name: "Godot",
33213
+ enabled: wanted(config2.godot.enabled, "godot"),
33214
+ after: [".NET", "Android SDK"],
33215
+ install: (env) => setupGodot(env, config2.godot, ctx)
33216
+ },
33217
+ {
33218
+ name: "FiveM server",
33219
+ enabled: wanted(config2.fivem.enabled, "fivem"),
33220
+ install: (env) => setupFivem(env, config2.fivem, ctx)
33221
+ },
33222
+ {
33223
+ name: "Flutter",
33224
+ enabled: wanted(config2.flutter.enabled, "flutter"),
33225
+ after: ["Visual Studio", "Android SDK"],
33226
+ install: (env) => setupFlutter(env, config2.flutter, ctx)
33227
+ },
33228
+ { name: "Dart", enabled: wanted(config2.dart.enabled, "dart"), install: (env) => setupDart(env, config2.dart, ctx) },
33229
+ {
33230
+ name: "React Native",
33231
+ enabled: wanted(config2.reactNative.enabled, "reactNative"),
33232
+ after: ["Android SDK"],
33233
+ install: (env) => setupReactNative(env, config2.reactNative, ctx)
33234
+ },
32112
33235
  { name: "Ruby", enabled: wanted(config2.ruby.enabled, "ruby"), install: (env) => setupRuby(env, config2.ruby) },
32113
33236
  // PHP installs the Visual C++ runtime itself: one installer at a time.
32114
33237
  // Many apps (bat, delta, Neovim, most GUIs, your own programs) are built against it too.
@@ -32184,7 +33307,7 @@ function plan(config2, versions, o) {
32184
33307
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
32185
33308
 
32186
33309
  // src/guest/runtime/status.ts
32187
- import os10 from "node:os";
33310
+ import os11 from "node:os";
32188
33311
  var progress;
32189
33312
  function setSandboxStatus(phase, message, update) {
32190
33313
  try {
@@ -32208,7 +33331,7 @@ function fitProgress(p) {
32208
33331
  };
32209
33332
  }
32210
33333
  function ownAddresses() {
32211
- return Object.values(os10.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address).slice(0, 8);
33334
+ return Object.values(os11.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address).slice(0, 8);
32212
33335
  }
32213
33336
  function writeStatus(phase, message) {
32214
33337
  writeJsonAtomic(run.sandboxFile, {
@@ -32353,21 +33476,21 @@ function cmdSet(env, names) {
32353
33476
  return names.filter((n) => env[n] !== void 0 && !/[\r\n]/.test(String(env[n]))).map((n) => '@set "' + n + "=" + String(env[n]).replace(/%/g, "%%") + '"');
32354
33477
  }
32355
33478
  function writeShell(spec, env, names) {
32356
- const dir = mkdirp(path64.join(localDir, "projects", spec.name));
32357
- fs50.writeFileSync(path64.join(dir, "env.cmd"), [...cmdSet(env, [...names, "PATH"]), ""].join("\r\n"));
32358
- fs50.writeFileSync(
32359
- path64.join(dir, "shell.cmd"),
32360
- ['@call "' + path64.join(dir, "env.cmd") + '"', '@cd /d "' + spec.workspace + '"', "@title " + spec.name, ""].join(
33479
+ const dir = mkdirp(path71.join(localDir, "projects", spec.name));
33480
+ fs57.writeFileSync(path71.join(dir, "env.cmd"), [...cmdSet(env, [...names, "PATH"]), ""].join("\r\n"));
33481
+ fs57.writeFileSync(
33482
+ path71.join(dir, "shell.cmd"),
33483
+ ['@call "' + path71.join(dir, "env.cmd") + '"', '@cd /d "' + spec.workspace + '"', "@title " + spec.name, ""].join(
32361
33484
  "\r\n"
32362
33485
  )
32363
33486
  );
32364
- const bin = mkdirp(path64.join(localDir, "bin"));
32365
- fs50.writeFileSync(
32366
- path64.join(bin, "sbx-shell.cmd"),
33487
+ const bin = mkdirp(path71.join(localDir, "bin"));
33488
+ fs57.writeFileSync(
33489
+ path71.join(bin, "sbx-shell.cmd"),
32367
33490
  [
32368
- '@if "%~1"=="" (echo Usage: sbx-shell ^<project^> ^(a terminal in that project with its tools^) & dir /b "' + path64.join(localDir, "projects") + '" & exit /b 2)',
32369
- '@if not exist "' + path64.join(localDir, "projects") + '\\%~1\\shell.cmd" (echo No project %~1 in this sandbox. & exit /b 2)',
32370
- '@cmd /k ""' + path64.join(localDir, "projects") + '\\%~1\\shell.cmd""',
33491
+ '@if "%~1"=="" (echo Usage: sbx-shell ^<project^> ^(a terminal in that project with its tools^) & dir /b "' + path71.join(localDir, "projects") + '" & exit /b 2)',
33492
+ '@if not exist "' + path71.join(localDir, "projects") + '\\%~1\\shell.cmd" (echo No project %~1 in this sandbox. & exit /b 2)',
33493
+ '@cmd /k ""' + path71.join(localDir, "projects") + '\\%~1\\shell.cmd""',
32371
33494
  ""
32372
33495
  ].join("\r\n")
32373
33496
  );
@@ -32420,10 +33543,10 @@ async function setUp(spec, say) {
32420
33543
  }
32421
33544
  )
32422
33545
  );
32423
- tools.prepend.push(path64.join(localDir, "bin"));
33546
+ tools.prepend.push(path71.join(localDir, "bin"));
32424
33547
  const env = agentEnv(tools, { workspace: spec.workspace, project: spec.name, base });
32425
- const specFile = path64.join(mkdirp(path64.join(localDir, "projects", spec.name)), "project.json");
32426
- fs50.writeFileSync(specFile, JSON.stringify(spec));
33548
+ const specFile = path71.join(mkdirp(path71.join(localDir, "projects", spec.name)), "project.json");
33549
+ fs57.writeFileSync(specFile, JSON.stringify(spec));
32427
33550
  env.AGENT_PROJECT_FILE = specFile;
32428
33551
  addMachineEnvironment(tools.vars, [...tools.prepend, ...tools.append], true);
32429
33552
  try {
@@ -32511,7 +33634,7 @@ function execCommand(req) {
32511
33634
  return;
32512
33635
  }
32513
33636
  const env = withRegistryPath(provisioner.provisionedFor(req.cwd)?.env ?? process.env);
32514
- const child = spawn5(
33637
+ const child = spawn6(
32515
33638
  SYSTEM.cmd(),
32516
33639
  ["/d", "/s", "/c", '"chcp 65001>nul & ' + req.command.map(quoteForCmd).join(" ") + '"'],
32517
33640
  { cwd: req.cwd, env, windowsHide: true, windowsVerbatimArguments: true }
@@ -32540,11 +33663,11 @@ function execCommand(req) {
32540
33663
  }
32541
33664
 
32542
33665
  // src/guest/daemon/sessions.ts
32543
- import fs54 from "node:fs";
32544
- import path69 from "node:path";
32545
- import crypto4 from "node:crypto";
32546
- import os12 from "node:os";
32547
- import { spawn as spawn7 } from "node:child_process";
33666
+ import fs63 from "node:fs";
33667
+ import path80 from "node:path";
33668
+ import crypto5 from "node:crypto";
33669
+ import os13 from "node:os";
33670
+ import { spawn as spawn8 } from "node:child_process";
32548
33671
 
32549
33672
  // src/shared/pty/protocol.ts
32550
33673
  var FrameType = {
@@ -32622,7 +33745,7 @@ async function sendControl(endpoint, type) {
32622
33745
  var MAX_CLIPBOARD_STRING = 1024 * 1024;
32623
33746
 
32624
33747
  // src/guest/sessions/cmdline.ts
32625
- import path65 from "node:path";
33748
+ import path72 from "node:path";
32626
33749
  var quoted = (arg) => '"' + arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
32627
33750
  function quoteArg(arg) {
32628
33751
  return arg !== "" && !/[\s"]/.test(arg) ? arg : quoted(arg);
@@ -32636,7 +33759,7 @@ function cmdArgs(args) {
32636
33759
  }).join("");
32637
33760
  }
32638
33761
  function commandLine(file3, args) {
32639
- return path65.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
33762
+ return path72.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
32640
33763
  }
32641
33764
  function shellLaunch(asked, paths) {
32642
33765
  if (asked === "cmd") return { name: "cmd", file: paths.cmd, args: [] };
@@ -32650,9 +33773,9 @@ function shellLaunch(asked, paths) {
32650
33773
  }
32651
33774
 
32652
33775
  // src/guest/sessions/pty-host.ts
32653
- import fs51 from "node:fs";
32654
- import path66 from "node:path";
32655
- import { execFile, spawn as spawn6 } from "node:child_process";
33776
+ import fs58 from "node:fs";
33777
+ import path73 from "node:path";
33778
+ import { execFile, spawn as spawn7 } from "node:child_process";
32656
33779
  function ensurePtyHost() {
32657
33780
  return ensureCompiled("ptyhost");
32658
33781
  }
@@ -32670,21 +33793,21 @@ async function waitForPtyHost(child, port, timeoutMs) {
32670
33793
  throw new Error("the session host did not start listening on port " + port);
32671
33794
  }
32672
33795
  function ptyHostLog(id) {
32673
- return path66.join(logsDir, "ptyhost-" + id + ".log");
33796
+ return path73.join(logsDir, "ptyhost-" + id + ".log");
32674
33797
  }
32675
33798
  function ptyHostLogTail(id, lines = 12) {
32676
33799
  try {
32677
- return fs51.readFileSync(ptyHostLog(id), "utf8").trim().split(/\r?\n/).slice(-lines).join("\n");
33800
+ return fs58.readFileSync(ptyHostLog(id), "utf8").trim().split(/\r?\n/).slice(-lines).join("\n");
32678
33801
  } catch {
32679
33802
  return "";
32680
33803
  }
32681
33804
  }
32682
33805
  var conptyDll = () => {
32683
- const dll = path66.join(toolsDir, "conpty", "conpty.dll");
32684
- return session.provisioning.conpty?.enabled !== false && fs51.existsSync(dll) && fs51.existsSync(path66.join(toolsDir, "conpty", "OpenConsole.exe")) ? dll : null;
33806
+ const dll = path73.join(toolsDir, "conpty", "conpty.dll");
33807
+ return session.provisioning.conpty?.enabled !== false && fs58.existsSync(dll) && fs58.existsSync(path73.join(toolsDir, "conpty", "OpenConsole.exe")) ? dll : null;
32685
33808
  };
32686
33809
  function startPtyHost(o) {
32687
- fs51.mkdirSync(run.treesDir, { recursive: true });
33810
+ fs58.mkdirSync(run.treesDir, { recursive: true });
32688
33811
  const env = {
32689
33812
  ...o.env,
32690
33813
  PTYHOST_BIND: o.remote ? "any" : "loopback",
@@ -32693,7 +33816,7 @@ function startPtyHost(o) {
32693
33816
  delete env.PTYHOST_CONPTY;
32694
33817
  const dll = conptyDll();
32695
33818
  if (dll) env.PTYHOST_CONPTY = dll;
32696
- return spawn6(
33819
+ return spawn7(
32697
33820
  o.exe,
32698
33821
  [String(o.port), o.token, String(o.cols), String(o.rows), ptyHostLog(o.id), o.command, o.restartCommand],
32699
33822
  { cwd: o.cwd, env, detached: true, stdio: "ignore", windowsHide: true }
@@ -32702,13 +33825,13 @@ function startPtyHost(o) {
32702
33825
  var END_TREE_MS = 3e4;
32703
33826
  function endLeftoverTree(id, exe = ensurePtyHost()) {
32704
33827
  const file3 = run.treeFile(id);
32705
- if (!fs51.existsSync(file3)) return Promise.resolve(null);
33828
+ if (!fs58.existsSync(file3)) return Promise.resolve(null);
32706
33829
  return new Promise((resolve2) => {
32707
33830
  execFile(exe, ["--end-tree", file3], { timeout: END_TREE_MS, windowsHide: true }, (error62, stdout) => {
32708
33831
  const code = error62 ? typeof error62.code === "number" ? error62.code : -1 : 0;
32709
33832
  if (code !== 3)
32710
33833
  try {
32711
- fs51.rmSync(file3, { force: true });
33834
+ fs58.rmSync(file3, { force: true });
32712
33835
  } catch {
32713
33836
  }
32714
33837
  resolve2(code === 0 ? stdout.trim().slice(0, 200) : code === 3 ? null : "could not end them (code " + code + ")");
@@ -32717,15 +33840,15 @@ function endLeftoverTree(id, exe = ensurePtyHost()) {
32717
33840
  }
32718
33841
  function recordedTrees() {
32719
33842
  try {
32720
- return fs51.readdirSync(run.treesDir).filter((n) => /^[A-Za-z0-9_-]{1,64}\.json$/.test(n)).map((n) => n.slice(0, -".json".length));
33843
+ return fs58.readdirSync(run.treesDir).filter((n) => /^[A-Za-z0-9_-]{1,64}\.json$/.test(n)).map((n) => n.slice(0, -".json".length));
32721
33844
  } catch {
32722
33845
  return [];
32723
33846
  }
32724
33847
  }
32725
33848
 
32726
33849
  // src/guest/agents/agent-installer.ts
32727
- import fs52 from "node:fs";
32728
- import path67 from "node:path";
33850
+ import fs59 from "node:fs";
33851
+ import path74 from "node:path";
32729
33852
 
32730
33853
  // src/guest/agents/profile-links.ts
32731
33854
  var profileRoot = () => process.env.USERPROFILE ?? "";
@@ -32751,7 +33874,7 @@ var agentPaths2 = (name, harness) => agentPaths(toolsDir, name, harness);
32751
33874
  async function installViaNpm(name, harness, dir, env) {
32752
33875
  if (!harness.npmPackage)
32753
33876
  throw new Error("No npmPackage configured for " + name + " and no host executable was available.");
32754
- const npmCli = path67.join(path67.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
33877
+ const npmCli = path74.join(path74.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
32755
33878
  const args = [npmCli, "install", "--global", "--prefix", dir, harness.npmPackage, "--no-fund", "--no-audit"];
32756
33879
  log("Installing " + harness.npmPackage + " (this can take a minute)...");
32757
33880
  if (dryRun) {
@@ -32762,7 +33885,7 @@ async function installViaNpm(name, harness, dir, env) {
32762
33885
  await execAsync(process.execPath, args, { env });
32763
33886
  }
32764
33887
  async function installViaUv(name, harness, dir, env) {
32765
- const uv = path67.join(toolsDir, "uv", "uv.exe");
33888
+ const uv = path74.join(toolsDir, "uv", "uv.exe");
32766
33889
  log("Installing " + harness.uvPackage + " with uv (this can take a minute)...");
32767
33890
  if (dryRun) {
32768
33891
  log("(dry run) uv tool install " + harness.uvPackage);
@@ -32777,8 +33900,8 @@ async function installViaUv(name, harness, dir, env) {
32777
33900
  });
32778
33901
  }
32779
33902
  function putOnPath(dir, env) {
32780
- const parts2 = (env.PATH ?? "").split(path67.delimiter);
32781
- if (!parts2.some((p) => p.toLowerCase() === dir.toLowerCase())) env.PATH = [...parts2, dir].join(path67.delimiter);
33903
+ const parts2 = (env.PATH ?? "").split(path74.delimiter);
33904
+ if (!parts2.some((p) => p.toLowerCase() === dir.toLowerCase())) env.PATH = [...parts2, dir].join(path74.delimiter);
32782
33905
  addMachineEnvironment({}, [dir], true);
32783
33906
  }
32784
33907
  var AgentInstaller = class {
@@ -32819,9 +33942,9 @@ var AgentInstaller = class {
32819
33942
  }
32820
33943
  mkdirp(p.dir);
32821
33944
  if (this.sourceOf(name, harness) === "host") {
32822
- const source = path67.join(hostToolsDir, "agents", name, harness.hostExecutable);
33945
+ const source = path74.join(hostToolsDir, "agents", name, harness.hostExecutable);
32823
33946
  if (exists(source) && p.exe) {
32824
- fs52.copyFileSync(source, p.exe);
33947
+ fs59.copyFileSync(source, p.exe);
32825
33948
  log("Copied " + name + " from this PC: " + source);
32826
33949
  return;
32827
33950
  }
@@ -32836,28 +33959,28 @@ var AgentInstaller = class {
32836
33959
  var agents = new AgentInstaller();
32837
33960
 
32838
33961
  // src/guest/network/addresses.ts
32839
- import os11 from "node:os";
33962
+ import os12 from "node:os";
32840
33963
  function guestAddresses() {
32841
- return Object.values(os11.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address);
33964
+ return Object.values(os12.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === "IPv4" && !i.internal).map((i) => i.address);
32842
33965
  }
32843
33966
 
32844
33967
  // src/guest/sessions/conversation.ts
32845
- import fs53 from "node:fs";
32846
- import path68 from "node:path";
33968
+ import fs60 from "node:fs";
33969
+ import path75 from "node:path";
32847
33970
  var MAX_FILES = 2e3;
32848
33971
  function conversationFiles(claudeDir2, cwd) {
32849
33972
  const names = /* @__PURE__ */ new Set([projectFolderName(cwd), projectFolderName(sandboxFolder(cwd))]);
32850
33973
  return [...names].flatMap((name) => {
32851
- const dir = path68.join(claudeDir2, "projects", name);
33974
+ const dir = path75.join(claudeDir2, "projects", name);
32852
33975
  let entries2;
32853
33976
  try {
32854
- entries2 = fs53.readdirSync(dir);
33977
+ entries2 = fs60.readdirSync(dir);
32855
33978
  } catch {
32856
33979
  return [];
32857
33980
  }
32858
33981
  return entries2.filter((e) => e.endsWith(".jsonl") && isConversationId(e.slice(0, -".jsonl".length))).slice(0, MAX_FILES).flatMap((e) => {
32859
33982
  try {
32860
- return [{ id: e.slice(0, -".jsonl".length), createdMs: fs53.statSync(path68.join(dir, e)).birthtimeMs }];
33983
+ return [{ id: e.slice(0, -".jsonl".length), createdMs: fs60.statSync(path75.join(dir, e)).birthtimeMs }];
32861
33984
  } catch {
32862
33985
  return [];
32863
33986
  }
@@ -32870,6 +33993,263 @@ function findConversation(claudeDir2, cwd, sessionStartMs, claimed) {
32870
33993
 
32871
33994
  // src/guest/daemon/idle-shutdown.ts
32872
33995
  import { spawnSync as spawnSync6 } from "node:child_process";
33996
+
33997
+ // src/guest/accounts/watch.ts
33998
+ import fs62 from "node:fs";
33999
+ import path79 from "node:path";
34000
+
34001
+ // src/shared/accounts/fingerprint.ts
34002
+ import crypto4 from "node:crypto";
34003
+ function canonical2(value) {
34004
+ if (Array.isArray(value)) return "[" + value.map(canonical2).join(",") + "]";
34005
+ if (value && typeof value === "object")
34006
+ return "{" + Object.keys(value).filter((k) => value[k] !== void 0).sort().map((k) => JSON.stringify(k) + ":" + canonical2(value[k])).join(",") + "}";
34007
+ return JSON.stringify(value) ?? "null";
34008
+ }
34009
+ function fingerprint2(payload) {
34010
+ return crypto4.createHash("sha256").update(canonical2(payload)).digest("hex");
34011
+ }
34012
+
34013
+ // src/guest/accounts/adapter.ts
34014
+ import path76 from "node:path";
34015
+ function localAppData() {
34016
+ return process.env.LOCALAPPDATA ?? "C:\\Users\\WDAGUtilityAccount\\AppData\\Local";
34017
+ }
34018
+ function accountsRoot() {
34019
+ return path76.join(localAppData(), "AgentSandbox", "accounts");
34020
+ }
34021
+ function notAvailableYet2(kind) {
34022
+ return { summary: kind + ": using a saved sign-in is not available yet (it is not used)" };
34023
+ }
34024
+
34025
+ // src/guest/accounts/kinds/appstore.ts
34026
+ var appstoreAdapter = {
34027
+ kind: "appstore",
34028
+ apply(_p) {
34029
+ return notAvailableYet2("appstore");
34030
+ }
34031
+ };
34032
+
34033
+ // src/guest/accounts/kinds/cfx.ts
34034
+ var cfxAdapter = {
34035
+ kind: "cfx",
34036
+ apply(_p) {
34037
+ return notAvailableYet2("cfx");
34038
+ }
34039
+ };
34040
+
34041
+ // src/guest/accounts/kinds/epic.ts
34042
+ import fs61 from "node:fs";
34043
+ import path77 from "node:path";
34044
+
34045
+ // src/shared/accounts/kinds/epic.ts
34046
+ var MAX_EPIC_INI_BYTES = 1024 * 1024;
34047
+ var SECTION = "[rememberme]";
34048
+ function epicSettingsFile(localAppData2) {
34049
+ return localAppData2 + "\\EpicGamesLauncher\\Saved\\Config\\Windows\\GameUserSettings.ini";
34050
+ }
34051
+ var isHeader = (line) => line.trimStart().startsWith("[");
34052
+ function readEpicLogin(ini) {
34053
+ let inSection = false;
34054
+ let enabled2 = true;
34055
+ let data = null;
34056
+ for (const raw of ini.split(/\r?\n/)) {
34057
+ const line = raw.trim();
34058
+ if (isHeader(line)) {
34059
+ inSection = line.toLowerCase() === SECTION;
34060
+ continue;
34061
+ }
34062
+ if (!inSection) continue;
34063
+ const at = line.indexOf("=");
34064
+ if (at < 0) continue;
34065
+ const key2 = line.slice(0, at).trim().toLowerCase();
34066
+ const value = line.slice(at + 1).trim();
34067
+ if (key2 === "enable") enabled2 = value.toLowerCase() === "true";
34068
+ else if (key2 === "data") data = value;
34069
+ }
34070
+ if (!enabled2 || !data) return null;
34071
+ const parsed = EpicPayloadSchema.safeParse({ data });
34072
+ return parsed.success ? parsed.data : null;
34073
+ }
34074
+ function withEpicLogin(ini, login) {
34075
+ const kept = [];
34076
+ let inSection = false;
34077
+ for (const line of ini.split(/\r?\n/)) {
34078
+ if (isHeader(line)) inSection = line.trim().toLowerCase() === SECTION;
34079
+ if (!inSection) kept.push(line);
34080
+ }
34081
+ while (kept.length && kept[kept.length - 1].trim() === "") kept.pop();
34082
+ const section = ["[RememberMe]", "Enable=True", "Data=" + EpicPayloadSchema.parse(login).data];
34083
+ return [...kept, ...kept.length ? [""] : [], ...section, ""].join("\r\n");
34084
+ }
34085
+
34086
+ // src/guest/accounts/kinds/epic.ts
34087
+ function settingsFile() {
34088
+ return epicSettingsFile(localAppData());
34089
+ }
34090
+ var epicAdapter = {
34091
+ kind: "epic",
34092
+ apply(p) {
34093
+ const file3 = settingsFile();
34094
+ const bytes = readBoundedFile(file3, MAX_EPIC_INI_BYTES);
34095
+ const read = bytes ? decodeText(bytes) : { text: "", encoding: "utf8" };
34096
+ fs61.mkdirSync(path77.dirname(file3), { recursive: true });
34097
+ fs61.writeFileSync(file3, encodeText(withEpicLogin(read.text, p), read.encoding));
34098
+ return { summary: "Epic Games Launcher: signed in with your saved sign-in" };
34099
+ },
34100
+ current() {
34101
+ const bytes = readBoundedFile(settingsFile(), MAX_EPIC_INI_BYTES);
34102
+ return bytes ? readEpicLogin(decodeText(bytes).text) : null;
34103
+ }
34104
+ };
34105
+
34106
+ // src/guest/accounts/kinds/expo.ts
34107
+ var expoAdapter = {
34108
+ kind: "expo",
34109
+ apply(_p) {
34110
+ return notAvailableYet2("expo");
34111
+ }
34112
+ };
34113
+
34114
+ // src/guest/accounts/kinds/keystore.ts
34115
+ var keystoreAdapter = {
34116
+ kind: "keystore",
34117
+ apply(_p) {
34118
+ return notAvailableYet2("keystore");
34119
+ }
34120
+ };
34121
+
34122
+ // src/guest/accounts/kinds/play.ts
34123
+ var playAdapter = {
34124
+ kind: "play",
34125
+ apply(_p) {
34126
+ return notAvailableYet2("play");
34127
+ }
34128
+ };
34129
+
34130
+ // src/guest/accounts/kinds/steam.ts
34131
+ function steamAdapterFor(steamcmdDir) {
34132
+ return {
34133
+ kind: "steam",
34134
+ apply(p) {
34135
+ writeSteamCmdLogin(steamcmdDir, p);
34136
+ return { summary: "SteamCMD: signed in as " + p.account + " with your saved sign-in" };
34137
+ },
34138
+ current: () => readSteamCmdLogin(steamcmdDir)
34139
+ };
34140
+ }
34141
+ var steamAdapter = steamAdapterFor(STEAMCMD_DIR);
34142
+
34143
+ // src/guest/accounts/kinds/unity.ts
34144
+ var unityAdapter = {
34145
+ kind: "unity",
34146
+ apply(_p) {
34147
+ return notAvailableYet2("unity");
34148
+ }
34149
+ };
34150
+
34151
+ // src/guest/accounts/adapters.ts
34152
+ var ADAPTERS = {
34153
+ epic: epicAdapter,
34154
+ steam: steamAdapter,
34155
+ unity: unityAdapter,
34156
+ cfx: cfxAdapter,
34157
+ keystore: keystoreAdapter,
34158
+ play: playAdapter,
34159
+ expo: expoAdapter,
34160
+ appstore: appstoreAdapter
34161
+ };
34162
+
34163
+ // src/guest/accounts/apply.ts
34164
+ import path78 from "node:path";
34165
+ var DeliveredSchema = external_exports.object({
34166
+ fingerprints: external_exports.partialRecord(external_exports.enum(SERVICE_KINDS), external_exports.string().max(128)),
34167
+ leased: external_exports.array(external_exports.enum(SERVICE_KINDS))
34168
+ });
34169
+ function deliveredFile(root = accountsRoot()) {
34170
+ return path78.join(root, "delivered.json");
34171
+ }
34172
+ function readDelivered(root = accountsRoot()) {
34173
+ return readValid(DeliveredSchema, deliveredFile(root)) ?? { fingerprints: {}, leased: [] };
34174
+ }
34175
+
34176
+ // src/guest/accounts/watch.ts
34177
+ var DEFAULT_CHECK_MS = 6e4;
34178
+ var AccountWatch = class {
34179
+ constructor(kinds, o) {
34180
+ this.o = o;
34181
+ this.kinds = kinds.filter((k) => SERVICE_SPECS[k].returns && this.adapter(k).current);
34182
+ const delivered = readDelivered(o.root);
34183
+ for (const kind of this.kinds) this.last.set(kind, delivered.fingerprints[kind] ?? null);
34184
+ }
34185
+ o;
34186
+ last = /* @__PURE__ */ new Map();
34187
+ timers = [];
34188
+ kinds;
34189
+ adapter(kind) {
34190
+ return this.o.adapters?.[kind] ?? ADAPTERS[kind];
34191
+ }
34192
+ /** The kinds being watched. */
34193
+ watched() {
34194
+ return this.kinds;
34195
+ }
34196
+ start() {
34197
+ for (const kind of this.kinds) {
34198
+ const timer = setInterval(() => this.check(kind), this.adapter(kind).checkMs ?? DEFAULT_CHECK_MS);
34199
+ timer.unref();
34200
+ this.timers.push(timer);
34201
+ }
34202
+ }
34203
+ /** One look at one kind; true when a handoff was written. */
34204
+ check(kind) {
34205
+ try {
34206
+ const now2 = this.adapter(kind).current?.() ?? null;
34207
+ if (!now2) return false;
34208
+ const print = fingerprint2(now2);
34209
+ if (print === this.last.get(kind)) return false;
34210
+ const file3 = path79.join(this.o.dataDir, ...HANDOFF_PARTS, kind + ".json");
34211
+ fs62.mkdirSync(path79.dirname(file3), { recursive: true });
34212
+ writeJsonAtomic(file3, { kind, launchId: this.o.launchId, payload: now2 });
34213
+ this.last.set(kind, print);
34214
+ return true;
34215
+ } catch (e) {
34216
+ this.o.warn?.(SERVICE_SPECS[kind].label + " sign-in: could not keep it for the next sandbox: " + errMsg(e));
34217
+ return false;
34218
+ }
34219
+ }
34220
+ /** Looks at every kind now; with `final` (the sandbox stops) each adapter also lets go of what it holds. */
34221
+ async flush(final = false) {
34222
+ for (const kind of this.kinds) this.check(kind);
34223
+ if (!final) return;
34224
+ for (const timer of this.timers) clearInterval(timer);
34225
+ for (const kind of this.kinds) {
34226
+ try {
34227
+ await this.adapter(kind).release?.();
34228
+ } catch (e) {
34229
+ this.o.warn?.(SERVICE_SPECS[kind].label + ": could not let go of the sign-in: " + errMsg(e));
34230
+ }
34231
+ }
34232
+ }
34233
+ };
34234
+
34235
+ // src/guest/daemon/accounts.ts
34236
+ var watch = null;
34237
+ function startAccountWatch() {
34238
+ const kinds = session.accountLeases ?? [];
34239
+ if (!kinds.length) return;
34240
+ watch = new AccountWatch(kinds, { dataDir, launchId: session.launchId, warn });
34241
+ watch.start();
34242
+ if (watch.watched().length) log("Service sign-ins kept for the next sandbox: " + watch.watched().join(", "));
34243
+ }
34244
+ async function flushAccounts(final = false) {
34245
+ try {
34246
+ await watch?.flush(final);
34247
+ } catch (e) {
34248
+ warn("service sign-ins: " + String(e));
34249
+ }
34250
+ }
34251
+
34252
+ // src/guest/daemon/idle-shutdown.ts
32873
34253
  var GRACE_MS = 15e3;
32874
34254
  var IdleShutdown = class {
32875
34255
  /** `busy`: a session runs or is starting. */
@@ -32886,7 +34266,7 @@ var IdleShutdown = class {
32886
34266
  log("Headless sandbox has no sessions left; shutting down.");
32887
34267
  safely("claude-mem save", saveClaudeMem);
32888
34268
  safely("agent databases save", saveLocalState);
32889
- spawnSync6(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true });
34269
+ void flushAccounts(true).finally(() => spawnSync6(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true }));
32890
34270
  }, GRACE_MS);
32891
34271
  }
32892
34272
  idle() {
@@ -32898,11 +34278,11 @@ var IdleShutdown = class {
32898
34278
  var CLOSE_WAIT_MS = 8e3;
32899
34279
  var ROOTS_KEPT_MS = 10 * 60 * 1e3;
32900
34280
  function terminalTab(id, title, cwd) {
32901
- const view = [process.execPath, path69.join(path69.dirname(process.argv[1]), "view.js"), id];
32902
- const wt = path69.join(toolsDir, "terminal", "wt.exe");
34281
+ const view = [process.execPath, path80.join(path80.dirname(process.argv[1]), "view.js"), id];
34282
+ const wt = path80.join(toolsDir, "terminal", "wt.exe");
32903
34283
  if (exists(wt))
32904
- spawn7(wt, ["-w", "0", "nt", "--title", title, "-d", cwd, ...view], { detached: true, stdio: "ignore" }).unref();
32905
- else spawn7(SYSTEM.cmd(), ["/d", "/c", "start", title, ...view], { detached: true, stdio: "ignore", cwd }).unref();
34284
+ spawn8(wt, ["-w", "0", "nt", "--title", title, "-d", cwd, ...view], { detached: true, stdio: "ignore" }).unref();
34285
+ else spawn8(SYSTEM.cmd(), ["/d", "/c", "start", title, ...view], { detached: true, stdio: "ignore", cwd }).unref();
32906
34286
  }
32907
34287
  var harnessFor = (req) => {
32908
34288
  if (req.harness === session.harnessName && session.harness) return session.harness;
@@ -32915,8 +34295,8 @@ var harnessFor = (req) => {
32915
34295
  function memoryEnv(env, sessions2) {
32916
34296
  const out = {};
32917
34297
  out.PTYHOST_BACKSTOP_MB = String(session.agentBackstop ?? "auto");
32918
- const cpus = usableCpus(os12.cpus().length, session.cpuLimitPercent ?? null);
32919
- const memoryGb = os12.totalmem() / 1024 ** 3;
34298
+ const cpus = usableCpus(os13.cpus().length, session.cpuLimitPercent ?? null);
34299
+ const memoryGb = os13.totalmem() / 1024 ** 3;
32920
34300
  const jobs = cargoJobs(cpus, memoryGb, sessions2);
32921
34301
  out.NUMBER_OF_PROCESSORS = String(cpus);
32922
34302
  if (!env.CARGO_BUILD_JOBS) out.CARGO_BUILD_JOBS = String(jobs);
@@ -32955,10 +34335,10 @@ var agentProgram = async (req, env, say) => {
32955
34335
  };
32956
34336
  function shellPaths() {
32957
34337
  const candidates = [
32958
- path69.join(pwshDir(), "pwsh.exe"),
32959
- path69.join(process.env.ProgramFiles ?? "C:\\Program Files", "PowerShell", "7", "pwsh.exe")
34338
+ path80.join(pwshDir(), "pwsh.exe"),
34339
+ path80.join(process.env.ProgramFiles ?? "C:\\Program Files", "PowerShell", "7", "pwsh.exe")
32960
34340
  ];
32961
- return { pwsh: candidates.find((f) => fs54.existsSync(f)) ?? null, powershell: SYSTEM.powershell(), cmd: SYSTEM.cmd() };
34341
+ return { pwsh: candidates.find((f) => fs63.existsSync(f)) ?? null, powershell: SYSTEM.powershell(), cmd: SYSTEM.cmd() };
32962
34342
  }
32963
34343
  var shellProgram = (shell) => {
32964
34344
  const line = commandLine(shell.file, shell.args);
@@ -32966,7 +34346,7 @@ var shellProgram = (shell) => {
32966
34346
  };
32967
34347
  var launchPtyHost = async (req, program, remote, env, sessions2, onSpawn) => {
32968
34348
  const port = await freePort();
32969
- const token = crypto4.randomBytes(24).toString("base64url");
34349
+ const token = crypto5.randomBytes(24).toString("base64url");
32970
34350
  const sessionEnv = {
32971
34351
  ...withRegistryPath(env),
32972
34352
  ...program.environment,
@@ -32992,7 +34372,7 @@ var launchPtyHost = async (req, program, remote, env, sessions2, onSpawn) => {
32992
34372
  } catch (e) {
32993
34373
  const tail = ptyHostLogTail(req.id);
32994
34374
  throw new Error(
32995
- errMsg(e) + (tail ? ". From its log:\n" + tail : "") + "\nLog: " + path69.join(dataDir, "logs", "ptyhost-" + req.id + ".log")
34375
+ errMsg(e) + (tail ? ". From its log:\n" + tail : "") + "\nLog: " + path80.join(dataDir, "logs", "ptyhost-" + req.id + ".log")
32996
34376
  );
32997
34377
  }
32998
34378
  return { child, port, token };
@@ -33106,7 +34486,7 @@ var SessionManager = class {
33106
34486
  };
33107
34487
  this.starting++;
33108
34488
  if (req.id !== session.launchId && process.env.AGENT_NO_TABS !== "1")
33109
- safely("terminal tab", () => terminalTab(req.id, name + " " + path69.basename(req.cwd), req.cwd));
34489
+ safely("terminal tab", () => terminalTab(req.id, name + " " + path80.basename(req.cwd), req.cwd));
33110
34490
  try {
33111
34491
  if (problem) throw new Error(problem);
33112
34492
  const place = await placeFor(req, say);
@@ -33268,6 +34648,7 @@ var SessionManager = class {
33268
34648
  else safely("post-agent hooks", () => runHooks("post-agent", process.env));
33269
34649
  safely("claude-mem save", saveClaudeMem);
33270
34650
  safely("agent databases save", saveLocalState);
34651
+ void flushAccounts();
33271
34652
  this.idle.check();
33272
34653
  }
33273
34654
  };
@@ -33600,10 +34981,10 @@ var GovernorCore = class {
33600
34981
  };
33601
34982
 
33602
34983
  // src/guest/governor/governor.ts
33603
- import fs55 from "node:fs";
33604
- import os13 from "node:os";
33605
- import path70 from "node:path";
33606
- import { spawn as spawn8 } from "node:child_process";
34984
+ import fs64 from "node:fs";
34985
+ import os14 from "node:os";
34986
+ import path81 from "node:path";
34987
+ import { spawn as spawn9 } from "node:child_process";
33607
34988
  import { createInterface } from "node:readline";
33608
34989
  var SampleSchema = external_exports.object({
33609
34990
  ramTotalMb: external_exports.number(),
@@ -33627,7 +35008,7 @@ var MemGovProcess = class {
33627
35008
  child = null;
33628
35009
  start() {
33629
35010
  try {
33630
- const child = spawn8(ensureCompiled("memgov"), ["serve", "--interval", "2"], {
35011
+ const child = spawn9(ensureCompiled("memgov"), ["serve", "--interval", "2"], {
33631
35012
  stdio: ["pipe", "pipe", "ignore"],
33632
35013
  windowsHide: true
33633
35014
  });
@@ -33672,12 +35053,12 @@ var MemGovProcess = class {
33672
35053
  };
33673
35054
  function appendToMemoryLog(line) {
33674
35055
  try {
33675
- const logs = path70.join(dataDir, "logs");
33676
- const newest = fs55.readdirSync(logs).filter((f) => /^memory-\d{8}-\d{6}\.log$/.test(f)).sort().pop();
35056
+ const logs = path81.join(dataDir, "logs");
35057
+ const newest = fs64.readdirSync(logs).filter((f) => /^memory-\d{8}-\d{6}\.log$/.test(f)).sort().pop();
33677
35058
  if (!newest) return;
33678
35059
  const t = /* @__PURE__ */ new Date();
33679
35060
  const stamp = [t.getHours(), t.getMinutes(), t.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
33680
- fs55.appendFileSync(path70.join(logs, newest), stamp + " | " + line + "\r\n");
35061
+ fs64.appendFileSync(path81.join(logs, newest), stamp + " | " + line + "\r\n");
33681
35062
  } catch {
33682
35063
  }
33683
35064
  }
@@ -33695,7 +35076,7 @@ var Governor = class {
33695
35076
  this.core = new GovernorCore({
33696
35077
  port: proc,
33697
35078
  profile,
33698
- maxCompilers: maxCompilers(os13.cpus().length, profile),
35079
+ maxCompilers: maxCompilers(os14.cpus().length, profile),
33699
35080
  now: () => Date.now(),
33700
35081
  logLine: appendToMemoryLog,
33701
35082
  warn,
@@ -33717,16 +35098,16 @@ var Governor = class {
33717
35098
  var governor = new Governor();
33718
35099
 
33719
35100
  // src/guest/daemon/live.ts
33720
- import fs57 from "node:fs";
33721
- import path72 from "node:path";
35101
+ import fs66 from "node:fs";
35102
+ import path83 from "node:path";
33722
35103
  import { spawnSync as spawnSync7 } from "node:child_process";
33723
35104
 
33724
35105
  // src/guest/daemon/live-folders.ts
33725
- import fs56 from "node:fs";
33726
- import path71 from "node:path";
35106
+ import fs65 from "node:fs";
35107
+ import path82 from "node:path";
33727
35108
 
33728
35109
  // src/shared/channel/live.ts
33729
- import crypto5 from "node:crypto";
35110
+ import crypto6 from "node:crypto";
33730
35111
  var LIVE_SHARE_NAME = /^agentsbx-[0-9a-f]{8,32}$/;
33731
35112
  var LIVE_FOLDER_NAME = /^[a-z0-9][a-z0-9_-]{0,63}$/;
33732
35113
  var LIVE_KEY = /^[0-9a-f]{64}$/;
@@ -33756,7 +35137,7 @@ var LiveReplySchema = external_exports.strictObject({
33756
35137
  finishedAt: external_exports.string().max(64)
33757
35138
  });
33758
35139
  function mac3(key2, payload) {
33759
- return crypto5.createHmac("sha256", Buffer.from(key2, "hex")).update(payload, "utf8").digest("hex");
35140
+ return crypto6.createHmac("sha256", Buffer.from(key2, "hex")).update(payload, "utf8").digest("hex");
33760
35141
  }
33761
35142
  function openLive(key2, envelope, o) {
33762
35143
  if (!key2 || !LIVE_KEY.test(key2))
@@ -33765,7 +35146,7 @@ function openLive(key2, envelope, o) {
33765
35146
  if (!env.success) return { refused: "not a live-folder request" };
33766
35147
  const want = Buffer.from(mac3(key2, env.data.payload), "hex");
33767
35148
  const got = Buffer.from(env.data.mac, "hex");
33768
- if (want.length !== got.length || !crypto5.timingSafeEqual(want, got))
35149
+ if (want.length !== got.length || !crypto6.timingSafeEqual(want, got))
33769
35150
  return { refused: "the signature does not match" };
33770
35151
  let json2;
33771
35152
  try {
@@ -33816,7 +35197,7 @@ var LiveFolderHandler = class {
33816
35197
  }
33817
35198
  read() {
33818
35199
  try {
33819
- const text = fs56.readFileSync(this.o.stateFile, "utf8");
35200
+ const text = fs65.readFileSync(this.o.stateFile, "utf8");
33820
35201
  const parsed = StateSchema.safeParse(JSON.parse(text));
33821
35202
  if (parsed.success && parsed.data.launchId === this.o.launchId) return parsed.data;
33822
35203
  } catch {
@@ -33824,7 +35205,7 @@ var LiveFolderHandler = class {
33824
35205
  return { key: null, launchId: this.o.launchId, seen: [], mappings: [] };
33825
35206
  }
33826
35207
  save(state) {
33827
- fs56.mkdirSync(path71.dirname(this.o.stateFile), { recursive: true });
35208
+ fs65.mkdirSync(path82.dirname(this.o.stateFile), { recursive: true });
33828
35209
  writeJsonAtomic(this.o.stateFile, state);
33829
35210
  }
33830
35211
  /** The key the boot handed over (from the one-shot secrets file). */
@@ -33835,30 +35216,30 @@ var LiveFolderHandler = class {
33835
35216
  /** C:\Workspace\<name> from a checked name only. */
33836
35217
  folderPath(name) {
33837
35218
  if (!LIVE_FOLDER_NAME.test(name)) throw new Error("not a plain folder name");
33838
- return path71.win32.join(this.o.workspaces ?? WORKSPACES_GUEST, name);
35219
+ return path82.win32.join(this.o.workspaces ?? WORKSPACES_GUEST, name);
33839
35220
  }
33840
35221
  /** One pass over run\live: every file is claimed (deleted) at once; valid ones are handled one after another. */
33841
35222
  tick() {
33842
35223
  const dir = this.o.run.liveDir;
33843
35224
  let names;
33844
35225
  try {
33845
- names = fs56.readdirSync(dir);
35226
+ names = fs65.readdirSync(dir);
33846
35227
  } catch {
33847
35228
  return;
33848
35229
  }
33849
35230
  for (const name of names.slice(0, 64)) {
33850
35231
  if (name.endsWith(".tmp")) continue;
33851
- const file3 = path71.join(dir, name);
35232
+ const file3 = path82.join(dir, name);
33852
35233
  let envelope = null;
33853
35234
  try {
33854
- const stat = fs56.lstatSync(file3);
35235
+ const stat = fs65.lstatSync(file3);
33855
35236
  if (stat.isFile() && stat.size <= MAX_REQUEST_BYTES && /^[A-Za-z0-9_-]{1,64}\.json$/.test(name))
33856
- envelope = JSON.parse(fs56.readFileSync(file3, "utf8"));
35237
+ envelope = JSON.parse(fs65.readFileSync(file3, "utf8"));
33857
35238
  } catch {
33858
35239
  envelope = null;
33859
35240
  } finally {
33860
35241
  try {
33861
- fs56.rmSync(file3, { recursive: true, force: true });
35242
+ fs65.rmSync(file3, { recursive: true, force: true });
33862
35243
  } catch {
33863
35244
  }
33864
35245
  }
@@ -33895,18 +35276,18 @@ var LiveFolderHandler = class {
33895
35276
  }
33896
35277
  reply(id, r) {
33897
35278
  try {
33898
- fs56.mkdirSync(this.o.run.liveRepliesDir, { recursive: true });
35279
+ fs65.mkdirSync(this.o.run.liveRepliesDir, { recursive: true });
33899
35280
  writeJsonAtomic(this.o.run.liveReplyFile(id), { id, ...r, finishedAt: new Date(this.now()).toISOString() });
33900
35281
  } catch (e) {
33901
35282
  this.log("live folder reply not written: " + errMsg(e));
33902
35283
  }
33903
35284
  }
33904
35285
  /** map with retries while the share is not there yet. */
33905
- async mapWithRetry(folder, share, readOnly) {
35286
+ async mapWithRetry(folder, share2, readOnly) {
33906
35287
  const tries = this.o.tries ?? 20;
33907
35288
  let code = EXIT_NO_SHARE;
33908
35289
  for (let i = 0; i < tries; i++) {
33909
- code = this.o.bind.map(folder, share, readOnly);
35290
+ code = this.o.bind.map(folder, share2, readOnly);
33910
35291
  if (code !== EXIT_NO_SHARE) return code;
33911
35292
  await (this.o.sleep ?? wait)(500);
33912
35293
  }
@@ -33916,14 +35297,14 @@ var LiveFolderHandler = class {
33916
35297
  assertFree(folder) {
33917
35298
  let exists2 = true;
33918
35299
  try {
33919
- fs56.lstatSync(folder);
35300
+ fs65.lstatSync(folder);
33920
35301
  } catch {
33921
35302
  exists2 = false;
33922
35303
  }
33923
35304
  if (exists2) throw new Error(folder + " exists already");
33924
- const parent = path71.dirname(folder);
33925
- fs56.mkdirSync(parent, { recursive: true });
33926
- if (!fs56.lstatSync(parent).isDirectory()) throw new Error(parent + " is not a plain folder");
35305
+ const parent = path82.dirname(folder);
35306
+ fs65.mkdirSync(parent, { recursive: true });
35307
+ if (!fs65.lstatSync(parent).isDirectory()) throw new Error(parent + " is not a plain folder");
33927
35308
  }
33928
35309
  async act(p) {
33929
35310
  const folder = this.folderPath(p.folder);
@@ -33938,21 +35319,21 @@ var LiveFolderHandler = class {
33938
35319
  this.save({ ...after, mappings: after.mappings.filter((m) => m.folder !== p.folder) });
33939
35320
  return { ok: true, message: "hidden: " + folder };
33940
35321
  }
33941
- const share = p.share ?? "";
35322
+ const share2 = p.share ?? "";
33942
35323
  this.assertFree(folder);
33943
35324
  if (p.kind === "canary") {
33944
- const code2 = await this.mapWithRetry(folder, share, true);
35325
+ const code2 = await this.mapWithRetry(folder, share2, true);
33945
35326
  if (code2 !== EXIT_OK) return { ok: false, message: "the test share could not be shown (" + code2 + ")" };
33946
35327
  try {
33947
- const file3 = path71.join(folder, "token.txt");
33948
- const stat = fs56.statSync(file3);
33949
- const token = stat.size <= 64 ? fs56.readFileSync(file3, "utf8").trim() : "";
35328
+ const file3 = path82.join(folder, "token.txt");
35329
+ const stat = fs65.statSync(file3);
35330
+ const token = stat.size <= 64 ? fs65.readFileSync(file3, "utf8").trim() : "";
33950
35331
  return LIVE_TOKEN.test(token) ? { ok: true, message: "read the test share", token } : { ok: false, message: "the test share holds no token" };
33951
35332
  } finally {
33952
35333
  this.o.bind.unmap(folder);
33953
35334
  }
33954
35335
  }
33955
- const code = await this.mapWithRetry(folder, share, p.readOnly);
35336
+ const code = await this.mapWithRetry(folder, share2, p.readOnly);
33956
35337
  if (code !== EXIT_OK)
33957
35338
  return {
33958
35339
  ok: false,
@@ -33963,7 +35344,7 @@ var LiveFolderHandler = class {
33963
35344
  ...state,
33964
35345
  mappings: [
33965
35346
  ...state.mappings.filter((m) => m.folder !== p.folder),
33966
- { folder: p.folder, share, readOnly: p.readOnly }
35347
+ { folder: p.folder, share: share2, readOnly: p.readOnly }
33967
35348
  ]
33968
35349
  });
33969
35350
  return { ok: true, message: "shown at " + folder };
@@ -33974,7 +35355,7 @@ var LiveFolderHandler = class {
33974
35355
  for (const m of this.read().mappings) {
33975
35356
  const folder = this.folderPath(m.folder);
33976
35357
  if (this.o.bind.mapped(folder) === EXIT_OK) continue;
33977
- fs56.mkdirSync(path71.dirname(folder), { recursive: true });
35358
+ fs65.mkdirSync(path82.dirname(folder), { recursive: true });
33978
35359
  if (this.o.bind.map(folder, m.share, m.readOnly) === EXIT_OK) done++;
33979
35360
  else this.log("live folder " + folder + " could not be shown again");
33980
35361
  }
@@ -33985,7 +35366,7 @@ var LiveFolderHandler = class {
33985
35366
  // src/guest/daemon/live.ts
33986
35367
  var BIND_TIMEOUT_MS = 3e4;
33987
35368
  var testing = Boolean(process.env.AGENT_DAEMON_STATE_DIR || process.env.AGENT_LOCAL_DIR);
33988
- var stateDir2 = process.env.AGENT_DAEMON_STATE_DIR ?? (process.env.AGENT_LOCAL_DIR ? path72.join(localDir, "daemon-state") : path72.join(process.env.ProgramData ?? "C:\\ProgramData", "AgentSandboxDaemon"));
35369
+ var stateDir2 = process.env.AGENT_DAEMON_STATE_DIR ?? (process.env.AGENT_LOCAL_DIR ? path83.join(localDir, "daemon-state") : path83.join(process.env.ProgramData ?? "C:\\ProgramData", "AgentSandboxDaemon"));
33989
35370
  function bindMount(args) {
33990
35371
  const r = spawnSync7(ensureCompiled("bindmount"), args, {
33991
35372
  windowsHide: true,
@@ -33995,12 +35376,12 @@ function bindMount(args) {
33995
35376
  return r.status ?? 1;
33996
35377
  }
33997
35378
  var realBind = {
33998
- map: (folder, share, readOnly) => bindMount(["map", folder, share, ...readOnly ? [] : ["rw"]]),
35379
+ map: (folder, share2, readOnly) => bindMount(["map", folder, share2, ...readOnly ? [] : ["rw"]]),
33999
35380
  unmap: (folder) => bindMount(["unmap", folder]),
34000
35381
  mapped: (folder) => bindMount(["mapped", folder])
34001
35382
  };
34002
35383
  function protectStateDir() {
34003
- fs57.mkdirSync(stateDir2, { recursive: true });
35384
+ fs66.mkdirSync(stateDir2, { recursive: true });
34004
35385
  if (!isWin || testMode || testing) return;
34005
35386
  spawnSync7(
34006
35387
  SYSTEM.icacls(),
@@ -34013,7 +35394,7 @@ function protectStateDir() {
34013
35394
  }
34014
35395
  var liveFolders = new LiveFolderHandler({
34015
35396
  run,
34016
- stateFile: path72.join(stateDir2, "live-folders.json"),
35397
+ stateFile: path83.join(stateDir2, "live-folders.json"),
34017
35398
  launchId: session.launchId,
34018
35399
  bind: realBind,
34019
35400
  log: warn
@@ -34043,9 +35424,9 @@ var Daemon = class {
34043
35424
  tick() {
34044
35425
  const { valid, invalid } = run.scanRequests();
34045
35426
  for (const file3 of invalid)
34046
- safely("removing an invalid request", () => fs58.rmSync(file3, { recursive: true, force: true }));
35427
+ safely("removing an invalid request", () => fs67.rmSync(file3, { recursive: true, force: true }));
34047
35428
  for (const req of valid) {
34048
- safely("claiming a request", () => fs58.rmSync(run.requestFile(req.id), { force: true }));
35429
+ safely("claiming a request", () => fs67.rmSync(run.requestFile(req.id), { force: true }));
34049
35430
  if (run.readSession(req.id)) continue;
34050
35431
  void Promise.resolve(this.handle(withRequestSecrets(req))).catch(
34051
35432
  (e) => respond(req.id, { ok: false, message: errMsg(e) })
@@ -34056,6 +35437,7 @@ var Daemon = class {
34056
35437
  this.lastMemSave = Date.now();
34057
35438
  safely("claude-mem save", saveClaudeMem);
34058
35439
  safely("agent databases save", saveLocalState);
35440
+ void flushAccounts();
34059
35441
  }
34060
35442
  }
34061
35443
  handle(req) {
@@ -34089,4 +35471,5 @@ safely("audit", () => startProcessCollector(() => sessions.roots()));
34089
35471
  safely("leftover processes", () => sessions.sweepLeftovers());
34090
35472
  safely("memory governor", () => governor.start());
34091
35473
  log("Memory governor: " + governor.describe());
35474
+ safely("service sign-ins", startAccountWatch);
34092
35475
  new Daemon().start();