windows-development-sandbox 1.17.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/README.md +92 -92
  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-BKF43GJ3.js} +51 -16
  19. package/dist/bin/{chunk-REE3EMHD.js → chunk-YD3A67RS.js} +3812 -1702
  20. package/dist/bin/{chunk-XYUVIVJT.js → chunk-Z5D32FN3.js} +1 -1
  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/agents/agent-files.d.ts +6 -0
  73. package/dist/guest/agents/agent-files.js +14 -0
  74. package/dist/guest/agents/local-state.d.ts +2 -0
  75. package/dist/guest/agents/local-state.js +13 -1
  76. package/dist/guest/apps/resolvers-gamedev.d.ts +2 -0
  77. package/dist/guest/apps/resolvers-gamedev.js +1 -0
  78. package/dist/guest/apps/resolvers-mobile.d.ts +2 -0
  79. package/dist/guest/apps/resolvers-mobile.js +1 -0
  80. package/dist/guest/apps/resolvers.js +4 -0
  81. package/dist/guest/boot/boot.d.ts +5 -0
  82. package/dist/guest/boot/boot.js +36 -1
  83. package/dist/guest/daemon/accounts.d.ts +3 -0
  84. package/dist/guest/daemon/accounts.js +25 -0
  85. package/dist/guest/daemon/daemon.js +2 -0
  86. package/dist/guest/daemon/idle-shutdown.js +3 -1
  87. package/dist/guest/daemon/sessions.js +2 -0
  88. package/dist/guest/devtools/android.d.ts +2 -0
  89. package/dist/guest/devtools/android.js +7 -0
  90. package/dist/guest/devtools/devtool.d.ts +9 -0
  91. package/dist/guest/devtools/devtool.js +5 -0
  92. package/dist/guest/devtools/fivem.d.ts +2 -0
  93. package/dist/guest/devtools/fivem.js +7 -0
  94. package/dist/guest/devtools/registry.d.ts +6 -0
  95. package/dist/guest/devtools/registry.js +12 -0
  96. package/dist/guest/devtools/steam.d.ts +2 -0
  97. package/dist/guest/devtools/steam.js +228 -0
  98. package/dist/guest/devtools/unity.d.ts +2 -0
  99. package/dist/guest/devtools/unity.js +7 -0
  100. package/dist/guest/entries/daemon.js +2 -0
  101. package/dist/guest/entries/tool.d.ts +1 -0
  102. package/dist/guest/entries/tool.js +17 -0
  103. package/dist/guest/toolchains/engines/godot.d.ts +4 -0
  104. package/dist/guest/toolchains/engines/godot.js +4 -0
  105. package/dist/guest/toolchains/engines/unity-release.d.ts +15 -0
  106. package/dist/guest/toolchains/engines/unity-release.js +6 -0
  107. package/dist/guest/toolchains/engines/unity.d.ts +4 -0
  108. package/dist/guest/toolchains/engines/unity.js +4 -0
  109. package/dist/guest/toolchains/engines/unreal-engines.d.ts +4 -0
  110. package/dist/guest/toolchains/engines/unreal-engines.js +4 -0
  111. package/dist/guest/toolchains/fivem/artifacts.d.ts +6 -0
  112. package/dist/guest/toolchains/fivem/artifacts.js +7 -0
  113. package/dist/guest/toolchains/fivem/fivem.d.ts +4 -0
  114. package/dist/guest/toolchains/fivem/fivem.js +4 -0
  115. package/dist/guest/toolchains/installers.d.ts +12 -0
  116. package/dist/guest/toolchains/installers.js +39 -0
  117. package/dist/guest/toolchains/languages/java.js +1 -1
  118. package/dist/guest/toolchains/languages/kotlin.d.ts +3 -0
  119. package/dist/guest/toolchains/languages/kotlin.js +6 -0
  120. package/dist/guest/toolchains/mobile/android-repo.d.ts +11 -0
  121. package/dist/guest/toolchains/mobile/android-repo.js +10 -0
  122. package/dist/guest/toolchains/mobile/android.d.ts +17 -0
  123. package/dist/guest/toolchains/mobile/android.js +16 -0
  124. package/dist/guest/toolchains/mobile/dart.d.ts +4 -0
  125. package/dist/guest/toolchains/mobile/dart.js +4 -0
  126. package/dist/guest/toolchains/mobile/flutter.d.ts +4 -0
  127. package/dist/guest/toolchains/mobile/flutter.js +4 -0
  128. package/dist/guest/toolchains/mobile/react-native.d.ts +4 -0
  129. package/dist/guest/toolchains/mobile/react-native.js +4 -0
  130. package/dist/guest/toolchains/native/unreal.d.ts +3 -7
  131. package/dist/guest/toolchains/native/unreal.js +16 -155
  132. package/dist/guest/toolchains/native/visual-studio.d.ts +15 -0
  133. package/dist/guest/toolchains/native/visual-studio.js +159 -0
  134. package/dist/guest/toolchains/native/vs-request.d.ts +19 -0
  135. package/dist/guest/toolchains/native/vs-request.js +46 -0
  136. package/dist/guest/toolchains/not-yet.d.ts +2 -0
  137. package/dist/guest/toolchains/not-yet.js +6 -0
  138. package/dist/guest/toolchains/persisted.d.ts +48 -0
  139. package/dist/guest/toolchains/persisted.js +159 -0
  140. package/dist/guest/toolchains/plan.js +80 -4
  141. package/dist/guest/toolchains/steam/apps.d.ts +27 -0
  142. package/dist/guest/toolchains/steam/apps.js +112 -0
  143. package/dist/guest/toolchains/steam/client.d.ts +5 -0
  144. package/dist/guest/toolchains/steam/client.js +67 -0
  145. package/dist/guest/toolchains/steam/commands.d.ts +58 -0
  146. package/dist/guest/toolchains/steam/commands.js +155 -0
  147. package/dist/guest/toolchains/steam/steam.d.ts +4 -0
  148. package/dist/guest/toolchains/steam/steam.js +61 -0
  149. package/dist/guest/toolchains/steam/steamcmd-install.d.ts +29 -0
  150. package/dist/guest/toolchains/steam/steamcmd-install.js +177 -0
  151. package/dist/guest/toolchains/steam/steamcmd.d.ts +6 -0
  152. package/dist/guest/toolchains/steam/steamcmd.js +23 -0
  153. package/dist/guest/toolchains/step.d.ts +10 -0
  154. package/dist/host/accounts/deliver.d.ts +26 -0
  155. package/dist/host/accounts/deliver.js +80 -0
  156. package/dist/host/accounts/handoff.d.ts +17 -0
  157. package/dist/host/accounts/handoff.js +110 -0
  158. package/dist/host/accounts/index.d.ts +6 -0
  159. package/dist/host/accounts/index.js +8 -0
  160. package/dist/host/accounts/kinds/appstore.d.ts +2 -0
  161. package/dist/host/accounts/kinds/appstore.js +10 -0
  162. package/dist/host/accounts/kinds/cfx.d.ts +2 -0
  163. package/dist/host/accounts/kinds/cfx.js +7 -0
  164. package/dist/host/accounts/kinds/epic.d.ts +2 -0
  165. package/dist/host/accounts/kinds/epic.js +15 -0
  166. package/dist/host/accounts/kinds/expo.d.ts +2 -0
  167. package/dist/host/accounts/kinds/expo.js +7 -0
  168. package/dist/host/accounts/kinds/keystore.d.ts +2 -0
  169. package/dist/host/accounts/kinds/keystore.js +7 -0
  170. package/dist/host/accounts/kinds/play.d.ts +2 -0
  171. package/dist/host/accounts/kinds/play.js +7 -0
  172. package/dist/host/accounts/kinds/steam.d.ts +6 -0
  173. package/dist/host/accounts/kinds/steam.js +31 -0
  174. package/dist/host/accounts/kinds/unity.d.ts +2 -0
  175. package/dist/host/accounts/kinds/unity.js +13 -0
  176. package/dist/host/accounts/leases.d.ts +40 -0
  177. package/dist/host/accounts/leases.js +62 -0
  178. package/dist/host/accounts/source.d.ts +21 -0
  179. package/dist/host/accounts/source.js +15 -0
  180. package/dist/host/accounts/sources.d.ts +5 -0
  181. package/dist/host/accounts/sources.js +18 -0
  182. package/dist/host/accounts/store.d.ts +23 -0
  183. package/dist/host/accounts/store.js +74 -0
  184. package/dist/host/audit/log.d.ts +1 -1
  185. package/dist/host/launch/generate.d.ts +2 -0
  186. package/dist/host/launch/generate.js +16 -1
  187. package/dist/host/launch/hints/android.d.ts +3 -0
  188. package/dist/host/launch/hints/android.js +3 -0
  189. package/dist/host/launch/hints/engines.d.ts +3 -0
  190. package/dist/host/launch/hints/engines.js +3 -0
  191. package/dist/host/launch/hints/fivem.d.ts +3 -0
  192. package/dist/host/launch/hints/fivem.js +3 -0
  193. package/dist/host/launch/hints/hint.d.ts +2 -0
  194. package/dist/host/launch/hints/hint.js +1 -0
  195. package/dist/host/launch/hints/index.d.ts +5 -0
  196. package/dist/host/launch/hints/index.js +29 -0
  197. package/dist/host/launch/hints/mobile.d.ts +3 -0
  198. package/dist/host/launch/hints/mobile.js +3 -0
  199. package/dist/host/launch/hints/steam.d.ts +7 -0
  200. package/dist/host/launch/hints/steam.js +59 -0
  201. package/dist/host/launch/index.d.ts +2 -2
  202. package/dist/host/launch/index.js +2 -2
  203. package/dist/host/launch/mappings.js +2 -0
  204. package/dist/host/launch/session-file.js +2 -0
  205. package/dist/host/launch/stage.js +10 -1
  206. package/dist/host/launch/toolchains.d.ts +7 -0
  207. package/dist/host/launch/toolchains.js +11 -0
  208. package/dist/host/pc-installs/discover.d.ts +19 -0
  209. package/dist/host/pc-installs/discover.js +59 -0
  210. package/dist/host/pc-installs/epic.d.ts +2 -0
  211. package/dist/host/pc-installs/epic.js +7 -0
  212. package/dist/host/pc-installs/index.d.ts +3 -0
  213. package/dist/host/pc-installs/index.js +2 -0
  214. package/dist/host/pc-installs/source.d.ts +9 -0
  215. package/dist/host/pc-installs/source.js +1 -0
  216. package/dist/host/pc-installs/steam.d.ts +16 -0
  217. package/dist/host/pc-installs/steam.js +143 -0
  218. package/dist/host/pc-installs/unity.d.ts +2 -0
  219. package/dist/host/pc-installs/unity.js +7 -0
  220. package/dist/host/pc-installs/unreal.d.ts +2 -0
  221. package/dist/host/pc-installs/unreal.js +7 -0
  222. package/dist/host/profile/accounts.d.ts +21 -6
  223. package/dist/host/profile/accounts.js +108 -28
  224. package/dist/host/profile/claude-login.d.ts +32 -2
  225. package/dist/host/profile/claude-login.js +100 -8
  226. package/dist/host/profile/index.d.ts +1 -1
  227. package/dist/host/profile/index.js +1 -1
  228. package/dist/host/secrets/launch-secrets.js +1 -0
  229. package/dist/runtime/agent.js +321 -9
  230. package/dist/runtime/daemon.js +1987 -595
  231. package/dist/runtime/db.js +334 -11
  232. package/dist/runtime/main.js +2530 -709
  233. package/dist/runtime/netproxy.js +321 -9
  234. package/dist/runtime/tool.js +28549 -0
  235. package/dist/runtime/view.js +321 -9
  236. package/dist/selftest/accounts.test.js +172 -1
  237. package/dist/selftest/agent-paths.test.js +13 -1
  238. package/dist/selftest/android.test.d.ts +2 -0
  239. package/dist/selftest/android.test.js +7 -0
  240. package/dist/selftest/app.test.js +1 -1
  241. package/dist/selftest/engines.test.d.ts +2 -0
  242. package/dist/selftest/engines.test.js +7 -0
  243. package/dist/selftest/fivem.test.d.ts +2 -0
  244. package/dist/selftest/fivem.test.js +7 -0
  245. package/dist/selftest/generate.test.js +1 -1
  246. package/dist/selftest/index.js +18 -0
  247. package/dist/selftest/menu-screens.js +1 -0
  248. package/dist/selftest/menu.test.js +2 -1
  249. package/dist/selftest/mobile.test.d.ts +2 -0
  250. package/dist/selftest/mobile.test.js +7 -0
  251. package/dist/selftest/pc-installs.test.d.ts +2 -0
  252. package/dist/selftest/pc-installs.test.js +111 -0
  253. package/dist/selftest/persisted-installs.test.d.ts +2 -0
  254. package/dist/selftest/persisted-installs.test.js +107 -0
  255. package/dist/selftest/projects.test.js +6 -4
  256. package/dist/selftest/service-accounts.test.d.ts +2 -0
  257. package/dist/selftest/service-accounts.test.js +320 -0
  258. package/dist/selftest/steam.test.d.ts +2 -0
  259. package/dist/selftest/steam.test.js +316 -0
  260. package/dist/selftest/storage-helper.test.js +31 -8
  261. package/dist/selftest/support/engine-golden.js +3 -0
  262. package/dist/selftest/support/fixtures.d.ts +87 -0
  263. package/dist/selftest/support/fixtures.js +4 -3
  264. package/dist/selftest/support/pc-memory.d.ts +2 -0
  265. package/dist/selftest/support/pc-memory.js +17 -0
  266. package/dist/selftest/support/web-preview.js +20 -1
  267. package/dist/selftest/unity.test.d.ts +2 -0
  268. package/dist/selftest/unity.test.js +7 -0
  269. package/dist/shared/accounts/fingerprint.d.ts +1 -0
  270. package/dist/shared/accounts/fingerprint.js +20 -0
  271. package/dist/shared/accounts/index.d.ts +5 -0
  272. package/dist/shared/accounts/index.js +7 -0
  273. package/dist/shared/accounts/kinds/epic.d.ts +10 -0
  274. package/dist/shared/accounts/kinds/epic.js +56 -0
  275. package/dist/shared/accounts/kinds/steam.d.ts +28 -0
  276. package/dist/shared/accounts/kinds/steam.js +99 -0
  277. package/dist/shared/accounts/kinds.d.ts +41 -0
  278. package/dist/shared/accounts/kinds.js +154 -0
  279. package/dist/shared/accounts/payloads.d.ts +151 -0
  280. package/dist/shared/accounts/payloads.js +128 -0
  281. package/dist/shared/apps/catalogue-gamedev.d.ts +2 -0
  282. package/dist/shared/apps/catalogue-gamedev.js +1 -0
  283. package/dist/shared/apps/catalogue-mobile.d.ts +2 -0
  284. package/dist/shared/apps/catalogue-mobile.js +1 -0
  285. package/dist/shared/apps/catalogue-modding.d.ts +2 -0
  286. package/dist/shared/apps/catalogue-modding.js +1 -0
  287. package/dist/shared/apps/catalogue.d.ts +1 -0
  288. package/dist/shared/apps/catalogue.js +6 -1
  289. package/dist/shared/channel/schema.d.ts +183 -0
  290. package/dist/shared/channel/secrets.d.ts +42 -0
  291. package/dist/shared/channel/secrets.js +3 -0
  292. package/dist/shared/download/downloader.d.ts +7 -0
  293. package/dist/shared/download/downloader.js +10 -3
  294. package/dist/shared/installs.d.ts +19 -0
  295. package/dist/shared/installs.js +13 -0
  296. package/dist/shared/io/bounded.d.ts +6 -0
  297. package/dist/shared/io/bounded.js +38 -0
  298. package/dist/shared/io/index.d.ts +2 -0
  299. package/dist/shared/io/index.js +2 -0
  300. package/dist/shared/io/text.d.ts +9 -0
  301. package/dist/shared/io/text.js +18 -0
  302. package/dist/shared/paths/guest-paths.js +1 -1
  303. package/dist/shared/paths/index.d.ts +1 -0
  304. package/dist/shared/paths/index.js +1 -0
  305. package/dist/shared/paths/pc-installs.d.ts +20 -0
  306. package/dist/shared/paths/pc-installs.js +19 -0
  307. package/dist/shared/vdf.d.ts +25 -0
  308. package/dist/shared/vdf.js +151 -0
  309. package/dist/sync/sync-cycle.js +9 -0
  310. package/dist/web/index.html +1 -1
  311. package/dist/web/{main-JTH3FT4O.js → main-CWIF4VQI.js} +63 -61
  312. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  313. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  314. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  315. package/package.json +1 -1
  316. package/sandbox/scripts/add-firewall-port.ps1 +13 -0
  317. package/sandbox/templates/fivem/README.txt +2 -0
  318. package/schemas/config.schema.json +485 -0
  319. 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,16 +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 ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;
31025
- var VS_DIR = tool("visualstudio");
31026
- var BOOTSTRAPPER = path55.join(VS_DIR, "vs_community.exe");
31027
- var LAYOUT = path55.join(VS_DIR, "layout");
31028
- var LAYOUT_MARKER = path55.join(LAYOUT, ".complete.json");
31029
- var LayoutSchema = external_exports.object({ components: external_exports.array(external_exports.string()) });
31030
- var VSWHERE = path55.join(
31031
- 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)",
31032
31604
  "Microsoft Visual Studio",
31033
31605
  "Installer",
31034
31606
  "vswhere.exe"
@@ -31047,142 +31619,153 @@ function installedVs() {
31047
31619
  const at = ask("installationPath");
31048
31620
  return at ? { path: at, version: ask("installationVersion") || "installed" } : null;
31049
31621
  }
31050
- async function signedInstaller(url2, file3, what) {
31051
- if (!exists(file3)) {
31052
- log("Downloading " + what + " ...");
31053
- mkdirp(path55.dirname(file3));
31054
- await downloadFile(url2, file3);
31055
- }
31056
- if (signerOf(file3) !== MICROSOFT_SIGNER) {
31057
- fs43.rmSync(file3, { force: true });
31058
- throw new Error(path55.basename(file3) + " is not signed by Microsoft; deleted it (it is downloaded again next boot)");
31059
- }
31060
- return file3;
31622
+ function layoutDir(product) {
31623
+ return path56.join(VS_DIR, product === "community" ? "layout" : "layout-buildtools");
31061
31624
  }
31062
- function freeBytes(dir) {
31063
- try {
31064
- const s = fs43.statfsSync(dir);
31065
- return s.bavail * s.bsize;
31066
- } catch {
31067
- return 0;
31068
- }
31069
- }
31070
- async function layoutInstaller(bootstrapper, ids) {
31071
- 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);
31072
31629
  const has = () => {
31073
- if (!exists(LAYOUT_MARKER) || !exists(installer)) return false;
31630
+ if (!exists(marker) || !exists(installer)) return false;
31074
31631
  try {
31075
- const done = LayoutSchema.parse(JSON.parse(fs43.readFileSync(LAYOUT_MARKER, "utf8")));
31076
- 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));
31077
31634
  } catch {
31078
31635
  return false;
31079
31636
  }
31080
31637
  };
31081
31638
  if (has()) return installer;
31082
31639
  if (freeBytes(mkdirp(VS_DIR)) < LAYOUT_ROOM_BYTES) {
31083
- 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
+ );
31084
31643
  return null;
31085
31644
  }
31086
31645
  log("Saving the Visual Studio install files for later boots (~10 GB, once) ...");
31087
- fs43.rmSync(LAYOUT_MARKER, { force: true });
31646
+ fs46.rmSync(marker, { force: true });
31088
31647
  const code = await spawnAsync(bootstrapper, [
31089
31648
  "--layout",
31090
- LAYOUT,
31649
+ layout,
31091
31650
  "--lang",
31092
31651
  "en-US",
31093
31652
  "--quiet",
31094
31653
  "--wait",
31095
- ...ids.flatMap((id) => ["--add", id])
31654
+ ...req.components.flatMap((id) => ["--add", id])
31096
31655
  ]);
31097
31656
  if (!OK_EXIT_CODES2.includes(code) || !exists(installer)) {
31098
- 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");
31099
31658
  return null;
31100
31659
  }
31101
- writeJsonAtomic(LAYOUT_MARKER, { components: [...ids] });
31660
+ writeJsonAtomic(marker, { components: [...req.components] });
31102
31661
  return installer;
31103
31662
  }
31104
- async function installVisualStudio(config2, ids) {
31105
- 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
+ );
31106
31671
  let installer = null;
31107
- if (config2.keepInstallFiles) {
31672
+ if (keepInstallFiles) {
31108
31673
  try {
31109
- installer = await layoutInstaller(bootstrapper, ids);
31674
+ installer = await layoutInstaller(req, bootstrapper);
31110
31675
  } catch (e) {
31111
- warn("unreal: the offline copy failed (" + errMsg(e) + "); downloading this boot");
31676
+ warn("Visual Studio: the offline copy failed (" + errMsg(e) + "); downloading this boot");
31112
31677
  }
31113
31678
  }
31114
- log(
31115
- "Installing Visual Studio Community 2022 with the C++ game workload" + (installer ? " from the saved install files" : " (downloads ~5-8 GB)") + " ..."
31116
- );
31679
+ log("Installing " + boot.name + (installer ? " from the saved install files" : " (downloads ~5-8 GB)") + " ...");
31117
31680
  const code = await spawnAsync(installer ?? bootstrapper, [
31118
31681
  "--quiet",
31119
31682
  "--wait",
31120
31683
  "--norestart",
31121
31684
  "--nocache",
31122
31685
  ...installer ? ["--noWeb"] : [],
31123
- ...ids.flatMap((id) => ["--add", id])
31686
+ ...req.components.flatMap((id) => ["--add", id])
31124
31687
  ]);
31125
31688
  if (!OK_EXIT_CODES2.includes(code) || !installedVs())
31126
31689
  throw new Error(
31127
31690
  "the Visual Studio installer failed (exit " + code + "); its logs are the dd_*.log files in " + os7.tmpdir()
31128
31691
  );
31129
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";
31130
31715
  async function installDirectX() {
31131
- const system322 = path55.join(process.env.WINDIR ?? "C:\\Windows", "System32");
31132
- 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;
31133
31718
  const redist = await signedInstaller(
31134
31719
  DIRECTX_URL,
31135
- path55.join(VS_DIR, "directx_Jun2010_redist.exe"),
31136
- "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
31137
31723
  );
31138
- const unpacked = path55.join(os7.tmpdir(), "directx-redist");
31139
- safeRemove(unpacked, os7.tmpdir());
31724
+ const unpacked = path57.join(os8.tmpdir(), "directx-redist");
31725
+ safeRemove(unpacked, os8.tmpdir());
31140
31726
  mkdirp(unpacked);
31141
- 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")))
31142
31728
  throw new Error("could not unpack the DirectX End-User Runtime");
31143
- const code = await spawnAsync(path55.join(unpacked, "DXSETUP.exe"), ["/silent"]);
31144
- safeRemove(unpacked, os7.tmpdir());
31729
+ const code = await spawnAsync(path57.join(unpacked, "DXSETUP.exe"), ["/silent"]);
31730
+ safeRemove(unpacked, os8.tmpdir());
31145
31731
  if (code !== 0) throw new Error("the DirectX End-User Runtime installer failed (exit " + code + ")");
31146
31732
  }
31147
- async function setupUnreal(env, config2) {
31733
+ async function setupUnreal(env, config2, ctx) {
31148
31734
  if (!config2.acceptLicense)
31149
31735
  throw new Error(
31150
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/)"
31151
31737
  );
31152
- const bad = config2.components.find((id) => !ID.test(id));
31153
- if (bad) throw new Error('toolchains.unreal.components: "' + bad + '" is not a Visual Studio component ID');
31154
- const ids = [.../* @__PURE__ */ new Set([...UNREAL_COMPONENTS, ...config2.components])];
31155
31738
  if (dryRun) {
31156
- 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");
31157
31740
  return;
31158
31741
  }
31159
- if (!installedVs()) await installVisualStudio(config2, ids);
31160
31742
  await installDirectX();
31743
+ await setupUnrealEngines(env, config2, ctx);
31161
31744
  const vs = installedVs();
31162
31745
  env.summary.push(
31163
- "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)"
31164
31747
  );
31165
31748
  }
31166
31749
 
31167
31750
  // src/guest/toolchains/native/rust.ts
31168
- import path57 from "node:path";
31751
+ import path59 from "node:path";
31169
31752
 
31170
31753
  // src/guest/toolchains/native/binstall.ts
31171
- import fs44 from "node:fs";
31172
- import path56 from "node:path";
31754
+ import fs47 from "node:fs";
31755
+ import path58 from "node:path";
31173
31756
  var ensureBinstall = async (cargoBin) => {
31174
- const target = path56.join(cargoBin, "cargo-binstall.exe");
31757
+ const target = path58.join(cargoBin, "cargo-binstall.exe");
31175
31758
  if (exists(target)) return true;
31176
31759
  try {
31177
31760
  const dir = tool("cargo-binstall");
31178
- if (!exists(path56.join(dir, "cargo-binstall.exe"))) {
31761
+ if (!exists(path58.join(dir, "cargo-binstall.exe"))) {
31179
31762
  await installFromGithub("cargo-bins/cargo-binstall", binstallAsset(arch), {
31180
31763
  dest: dir,
31181
31764
  what: "cargo-binstall for prebuilt Rust tools (~10 MB once)",
31182
31765
  locate: "cargo-binstall.exe"
31183
31766
  });
31184
31767
  }
31185
- fs44.copyFileSync(path56.join(dir, "cargo-binstall.exe"), target);
31768
+ fs47.copyFileSync(path58.join(dir, "cargo-binstall.exe"), target);
31186
31769
  return true;
31187
31770
  } catch (e) {
31188
31771
  warn("cargo-binstall unavailable, compiling crates with cargo install instead: " + errMsg(e));
@@ -31190,14 +31773,14 @@ var ensureBinstall = async (cargoBin) => {
31190
31773
  }
31191
31774
  };
31192
31775
  function crateInstaller(cargoHome, cargoEnv) {
31193
- const cargo = path56.join(cargoHome, "bin", "cargo.exe");
31776
+ const cargo = path58.join(cargoHome, "bin", "cargo.exe");
31194
31777
  let binstall = null;
31195
31778
  const binstallEnv = {
31196
31779
  ...cargoEnv,
31197
31780
  env: { ...cargoEnv.env ?? process.env, BINSTALL_DISABLE_TELEMETRY: "true" }
31198
31781
  };
31199
31782
  return async (crate) => {
31200
- binstall ??= ensureBinstall(path56.join(cargoHome, "bin"));
31783
+ binstall ??= ensureBinstall(path58.join(cargoHome, "bin"));
31201
31784
  if (await binstall) {
31202
31785
  try {
31203
31786
  await execAsync(
@@ -31219,7 +31802,7 @@ async function setupRust(env, config2, refresh) {
31219
31802
  const RUSTUP_HOME = tool("rust", "rustup");
31220
31803
  const CARGO_HOME = tool("rust", "cargo");
31221
31804
  const rustEnv = { env: { ...process.env, RUSTUP_HOME, CARGO_HOME } };
31222
- const rustup = path57.join(CARGO_HOME, "bin", "rustup.exe");
31805
+ const rustup = path59.join(CARGO_HOME, "bin", "rustup.exe");
31223
31806
  if (dryRun) {
31224
31807
  log("(dry run) would provision Rust " + config2.toolchain + " (" + config2.host + ")");
31225
31808
  return;
@@ -31255,9 +31838,9 @@ async function setupRust(env, config2, refresh) {
31255
31838
  if (refresh) await execAsync(rustup, ["update"], rustEnv);
31256
31839
  }
31257
31840
  Object.assign(env.vars, { RUSTUP_HOME, CARGO_HOME });
31258
- env.prepend.push(path57.join(CARGO_HOME, "bin"));
31841
+ env.prepend.push(path59.join(CARGO_HOME, "bin"));
31259
31842
  env.summary.push(
31260
- "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 + "]"
31261
31844
  );
31262
31845
  const toolchainKey = "rustup@" + config2.toolchain;
31263
31846
  await installOnce(
@@ -31278,36 +31861,36 @@ async function setupRust(env, config2, refresh) {
31278
31861
  env: {
31279
31862
  ...rustEnv.env,
31280
31863
  ...msvc.vars,
31281
- 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)
31282
31865
  }
31283
31866
  } : {
31284
31867
  env: {
31285
31868
  ...rustEnv.env,
31286
- CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: path57.join(mingw, "gcc.exe"),
31287
- 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)
31288
31871
  }
31289
31872
  };
31290
31873
  await installOnce(env, "cargo", config2.crates, crateInstaller(CARGO_HOME, cargoEnv));
31291
31874
  }
31292
31875
 
31293
31876
  // src/guest/toolchains/languages/node.ts
31294
- import fs45 from "node:fs";
31295
- import path58 from "node:path";
31877
+ import fs48 from "node:fs";
31878
+ import path60 from "node:path";
31296
31879
  import { spawn as spawn4 } from "node:child_process";
31297
31880
  var NVM_HOME = tool("nvm");
31298
- var NVM_SYMLINK = path58.join(localDir, "nodejs");
31299
- var HOST_NVM = path58.join(hostToolsDir, "nvm");
31881
+ var NVM_SYMLINK = path60.join(localDir, "nodejs");
31882
+ var HOST_NVM = path60.join(hostToolsDir, "nvm");
31300
31883
  var HOST_VERSIONS_MAX = 3;
31301
- 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)) : [];
31302
31885
  var resolveNode = (spec) => resolveCached("node:" + spec, async () => {
31303
31886
  const exact = spec.replace(/^v/, "");
31304
31887
  if (/^\d+\.\d+\.\d+$/.test(exact)) return exact;
31305
31888
  const releases = await fetchJson("https://nodejs.org/dist/index.json");
31306
31889
  return pickNodeVersion(releases, spec) ?? Promise.reject(new Error('No Node.js release matches "' + spec + '"'));
31307
31890
  });
31308
- var NVM_TEMP = path58.join(NVM_HOME, ".tmp");
31891
+ var NVM_TEMP = path60.join(NVM_HOME, ".tmp");
31309
31892
  var nvm = (args) => new Promise((resolve2) => {
31310
- const child = spawn4(path58.join(NVM_HOME, "nvm.exe"), args, {
31893
+ const child = spawn4(path60.join(NVM_HOME, "nvm.exe"), args, {
31311
31894
  windowsHide: true,
31312
31895
  env: { ...process.env, NVM_HOME, NVM_SYMLINK, TEMP: NVM_TEMP, TMP: NVM_TEMP }
31313
31896
  });
@@ -31322,12 +31905,12 @@ var nvm = (args) => new Promise((resolve2) => {
31322
31905
  child.once("close", () => resolve2(out));
31323
31906
  });
31324
31907
  var ensureNvm = async () => {
31325
- if (exists(path58.join(NVM_HOME, "nvm.exe"))) return;
31326
- 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"))) {
31327
31910
  log("Copying nvm from this PC ...");
31328
31911
  mkdirp(NVM_HOME);
31329
- 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"));
31330
- 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));
31331
31914
  return;
31332
31915
  }
31333
31916
  const asset = await githubAsset("coreybutler/nvm-windows", /^nvm-noinstall\.zip$/, true);
@@ -31335,14 +31918,14 @@ var ensureNvm = async () => {
31335
31918
  await downloader.archive(asset.url, NVM_HOME, { sha256: asset.sha256, locate: "nvm.exe", fileName: asset.name });
31336
31919
  };
31337
31920
  var hostNodeFolder = (version2) => {
31338
- const dir = path58.join(hostToolsDir, "node");
31339
- 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;
31340
31923
  };
31341
31924
  var installNodeVersion = async (version2) => {
31342
- const dir = path58.join(NVM_HOME, "v" + version2);
31343
- const fromHost = path58.join(HOST_NVM, "v" + version2);
31344
- if (exists(path58.join(dir, "node.exe"))) return;
31345
- 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"))) {
31346
31929
  log("Copying Node " + version2 + " from this PC's nvm (without global packages) ...");
31347
31930
  copyNode(fromHost, dir);
31348
31931
  return;
@@ -31361,19 +31944,19 @@ var installNodeVersion = async (version2) => {
31361
31944
  } finally {
31362
31945
  safeRemove(NVM_TEMP, NVM_HOME);
31363
31946
  }
31364
- if (!exists(path58.join(dir, "node.exe"))) {
31947
+ if (!exists(path60.join(dir, "node.exe"))) {
31365
31948
  const tail = out.trim().split(/\r?\n/).filter(Boolean).slice(-3).join(" ");
31366
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";
31367
31950
  throw new Error(
31368
- "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 : "")
31369
31952
  );
31370
31953
  }
31371
31954
  };
31372
31955
  var activate = async (version2) => {
31373
31956
  await nvm(["use", version2]);
31374
- if (exists(path58.join(NVM_SYMLINK, "node.exe"))) return;
31375
- fs45.rmSync(NVM_SYMLINK, { recursive: true, force: true });
31376
- 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");
31377
31960
  };
31378
31961
  var PLAYWRIGHT_VARS = () => ({
31379
31962
  PLAYWRIGHT_BROWSERS_PATH: tool("ms-playwright"),
@@ -31385,8 +31968,8 @@ async function setupNode(env, versions, config2) {
31385
31968
  return;
31386
31969
  }
31387
31970
  await ensureNvm();
31388
- fs45.writeFileSync(
31389
- path58.join(NVM_HOME, "settings.txt"),
31971
+ fs48.writeFileSync(
31972
+ path60.join(NVM_HOME, "settings.txt"),
31390
31973
  [
31391
31974
  "root: " + NVM_HOME,
31392
31975
  "path: " + NVM_SYMLINK,
@@ -31413,7 +31996,7 @@ async function setupNode(env, versions, config2) {
31413
31996
  }
31414
31997
  }
31415
31998
  Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK, ...PLAYWRIGHT_VARS() });
31416
- 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);
31417
32000
  else {
31418
32001
  await activate(main);
31419
32002
  env.prepend.push(NVM_HOME, NVM_SYMLINK);
@@ -31423,13 +32006,13 @@ async function setupNode(env, versions, config2) {
31423
32006
  await packageManagers(env, config2, main);
31424
32007
  }
31425
32008
  var packageManagers = async (env, config2, version2) => {
31426
- const dir = path58.join(NVM_HOME, "v" + version2);
31427
- const nodeEnv = { ...process.env, PATH: dir + path58.delimiter + (process.env.PATH ?? "") };
31428
- 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], {
31429
32012
  env: nodeEnv,
31430
32013
  stdio: "ignore"
31431
32014
  });
31432
- const corepackJs = path58.join(dir, "node_modules", "corepack", "dist", "corepack.js");
32015
+ const corepackJs = path60.join(dir, "node_modules", "corepack", "dist", "corepack.js");
31433
32016
  const extra = config2.corepack && !exists(corepackJs) ? ["corepack"] : [];
31434
32017
  await installOnce(
31435
32018
  env,
@@ -31450,7 +32033,7 @@ var packageManagers = async (env, config2, version2) => {
31450
32033
  }
31451
32034
  try {
31452
32035
  await execAsync(
31453
- path58.join(dir, "node.exe"),
32036
+ path60.join(dir, "node.exe"),
31454
32037
  [corepackJs, "enable", "--install-directory", mkdirp(tool("bin")), "pnpm", "yarn"],
31455
32038
  { env: nodeEnv, stdio: "ignore" }
31456
32039
  );
@@ -31475,8 +32058,8 @@ async function setupPwsh(env, refresh = false) {
31475
32058
  }
31476
32059
 
31477
32060
  // src/guest/toolchains/languages/python.ts
31478
- import fs46 from "node:fs";
31479
- import path59 from "node:path";
32061
+ import fs49 from "node:fs";
32062
+ import path61 from "node:path";
31480
32063
  var installPython = async (pkg, spec) => {
31481
32064
  const version2 = await resolveCached(pkg + ":" + spec, async () => {
31482
32065
  const { versions } = await fetchJson(
@@ -31485,7 +32068,7 @@ var installPython = async (pkg, spec) => {
31485
32068
  return pickPackageVersion(versions, spec) ?? Promise.reject(new Error("No " + pkg + ' release matches "' + spec + '"'));
31486
32069
  });
31487
32070
  const dir = tool("python", pkg + "-" + version2);
31488
- const exe = path59.join(dir, "python.exe");
32071
+ const exe = path61.join(dir, "python.exe");
31489
32072
  if (!exists(exe)) {
31490
32073
  log("Downloading Python " + version2 + (pkg === "python2" ? " (Python 2, " : " (") + "~30 MB once) ...");
31491
32074
  await downloader.archive(
@@ -31494,32 +32077,32 @@ var installPython = async (pkg, spec) => {
31494
32077
  { locate: "python.exe", fileName: pkg + "." + version2 + ".zip" }
31495
32078
  );
31496
32079
  }
31497
- 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")))
31498
32081
  await execAsync(exe, ["-m", "ensurepip", "--default-pip"], { stdio: "ignore" });
31499
32082
  return dir;
31500
32083
  };
31501
- var shimDir = (dir) => duringSession() ? tool("shims", path59.basename(dir)) : tool("shims");
32084
+ var shimDir = (dir) => duringSession() ? tool("shims", path61.basename(dir)) : tool("shims");
31502
32085
  var shim = (folder, name, program, args = []) => {
31503
32086
  const fixed = [program, ...args];
31504
- fs46.writeFileSync(
31505
- path59.join(mkdirp(folder), name + ".cmd"),
32087
+ fs49.writeFileSync(
32088
+ path61.join(mkdirp(folder), name + ".cmd"),
31506
32089
  "@echo off\r\n" + fixed.map((a) => '"' + a + '"').join(" ") + " %*\r\n"
31507
32090
  );
31508
32091
  const sh = fixed.map((a) => "'" + a.replace(/\\/g, "/").replace(/'/g, "'\\''") + "'").join(" ");
31509
- fs46.writeFileSync(path59.join(folder, name), "#!/bin/sh\nexec " + sh + ' "$@"\n');
32092
+ fs49.writeFileSync(path61.join(folder, name), "#!/bin/sh\nexec " + sh + ' "$@"\n');
31510
32093
  };
31511
32094
  var shimPair = (folder, version2, dir) => {
31512
- const python = path59.join(dir, "python.exe");
32095
+ const python = path61.join(dir, "python.exe");
31513
32096
  shim(folder, "python" + version2, python);
31514
32097
  shim(folder, "pip" + version2, python, ["-m", "pip"]);
31515
32098
  };
31516
32099
  var pyLauncher = (folder, py3, py2) => {
31517
- const script = path59.join(mkdirp(folder), "py-launcher.py");
31518
- fs46.writeFileSync(
32100
+ const script = path61.join(mkdirp(folder), "py-launcher.py");
32101
+ fs49.writeFileSync(
31519
32102
  script,
31520
32103
  [
31521
32104
  "import subprocess, sys",
31522
- "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),
31523
32106
  "args = sys.argv[1:]",
31524
32107
  "exe = PY3",
31525
32108
  "if args and args[0].startswith('-2'):",
@@ -31531,7 +32114,7 @@ var pyLauncher = (folder, py3, py2) => {
31531
32114
  ""
31532
32115
  ].join("\n")
31533
32116
  );
31534
- shim(folder, "py", path59.join(py3, "python.exe"), [script]);
32117
+ shim(folder, "py", path61.join(py3, "python.exe"), [script]);
31535
32118
  };
31536
32119
  async function setupPython(env, config2, versions) {
31537
32120
  if (dryRun) {
@@ -31541,10 +32124,10 @@ async function setupPython(env, config2, versions) {
31541
32124
  const py3 = await installPython("python", versions.python.spec);
31542
32125
  const shims = shimDir(py3);
31543
32126
  shimPair(shims, "3", py3);
31544
- env.prepend.push(py3, mkdirp(path59.join(py3, "Scripts")), shims);
32127
+ env.prepend.push(py3, mkdirp(path61.join(py3, "Scripts")), shims);
31545
32128
  env.vars.PYTHONIOENCODING = "utf-8";
31546
32129
  env.summary.push(
31547
- "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)"
31548
32131
  );
31549
32132
  if (!config2.python2) {
31550
32133
  pyLauncher(shims, py3, null);
@@ -31553,12 +32136,12 @@ async function setupPython(env, config2, versions) {
31553
32136
  const py2 = await installPython("python2", "2.7");
31554
32137
  shimPair(shims, "2", py2);
31555
32138
  pyLauncher(shims, py3, py2);
31556
- env.summary.push("python2: " + path59.basename(py2).replace("python2-", ""));
32139
+ env.summary.push("python2: " + path61.basename(py2).replace("python2-", ""));
31557
32140
  }
31558
32141
 
31559
32142
  // src/guest/toolchains/languages/php.ts
31560
- import fs47 from "node:fs";
31561
- import path60 from "node:path";
32143
+ import fs50 from "node:fs";
32144
+ import path62 from "node:path";
31562
32145
  var PHP_EXTENSIONS = [
31563
32146
  "curl",
31564
32147
  "fileinfo",
@@ -31576,11 +32159,11 @@ var PHP_EXTENSIONS = [
31576
32159
  var COMPOSER = "https://getcomposer.org/download/latest-stable/composer.phar";
31577
32160
  var phpBuild = async (spec) => {
31578
32161
  const releases = await fetchJson("https://windows.php.net/downloads/releases/releases.json");
31579
- const pick2 = pickPackageVersion(
32162
+ const pick3 = pickPackageVersion(
31580
32163
  Object.values(releases).map((r) => r.version),
31581
32164
  spec
31582
32165
  );
31583
- const release = Object.values(releases).find((r) => r.version === pick2);
32166
+ const release = Object.values(releases).find((r) => r.version === pick3);
31584
32167
  const build = release && Object.entries(release).find(
31585
32168
  ([key2, value]) => /^nts-vs\d+-x64$/.test(key2) && typeof value === "object" && value.zip
31586
32169
  )?.[1];
@@ -31589,16 +32172,16 @@ var phpBuild = async (spec) => {
31589
32172
  return { version: release.version, ...build.zip };
31590
32173
  };
31591
32174
  var writePhpIni = (home) => {
31592
- const ini = path60.join(home, "php.ini");
31593
- if (exists(ini) || !exists(path60.join(home, "php.ini-development"))) return;
31594
- 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") + '"');
31595
- 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"))))
31596
32179
  text = text.replace(new RegExp("^;(extension=" + ext + ")\\s*$", "m"), "$1");
31597
- fs47.writeFileSync(ini + ".tmp", text);
31598
- fs47.renameSync(ini + ".tmp", ini);
32180
+ fs50.writeFileSync(ini + ".tmp", text);
32181
+ fs50.renameSync(ini + ".tmp", ini);
31599
32182
  };
31600
32183
  var shim2 = (env, name, command) => {
31601
- 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");
31602
32185
  env.prepend.push(tool("shims"));
31603
32186
  };
31604
32187
  var setupComposer = async (env, php) => {
@@ -31610,7 +32193,7 @@ var setupComposer = async (env, php) => {
31610
32193
  }
31611
32194
  const composerHome = tool("composer-home");
31612
32195
  env.vars.COMPOSER_HOME = composerHome;
31613
- env.prepend.push(path60.join(composerHome, "vendor", "bin"));
32196
+ env.prepend.push(path62.join(composerHome, "vendor", "bin"));
31614
32197
  shim2(env, "composer", '"' + php + '" "' + phar + '"');
31615
32198
  env.summary.push(
31616
32199
  "composer: " + (/\d+\.\d+\.\d+/.exec(execOutput(php, [phar, "--version", "--no-ansi"]))?.[0] ?? "installed")
@@ -31625,7 +32208,7 @@ async function setupPhp(env, config2) {
31625
32208
  await setupVcRuntime(env, false);
31626
32209
  const version2 = await resolveCached("php:" + wantedSpec.spec, async () => (await phpBuild(wantedSpec.spec)).version);
31627
32210
  const home = tool("php", version2);
31628
- if (!exists(path60.join(home, "php.exe"))) {
32211
+ if (!exists(path62.join(home, "php.exe"))) {
31629
32212
  const build = await phpBuild(version2);
31630
32213
  log("Downloading PHP " + version2 + " (~30 MB once) ...");
31631
32214
  await downloader.archive("https://windows.php.net/downloads/releases/" + build.path, home, {
@@ -31637,11 +32220,11 @@ async function setupPhp(env, config2) {
31637
32220
  writePhpIni(home);
31638
32221
  env.prepend.push(home);
31639
32222
  env.summary.push("php: " + version2 + " (from " + wantedSpec.source + ")");
31640
- if (config2.composer) await setupComposer(env, path60.join(home, "php.exe"));
32223
+ if (config2.composer) await setupComposer(env, path62.join(home, "php.exe"));
31641
32224
  }
31642
32225
 
31643
32226
  // src/guest/toolchains/languages/ruby.ts
31644
- import path61 from "node:path";
32227
+ import path63 from "node:path";
31645
32228
  var RUBY_ASSET = /^rubyinstaller-(\d+\.\d+\.\d+)-(\d+)-x64\.7z$/;
31646
32229
  var buildNumber = (asset) => Number(RUBY_ASSET.exec(asset.name)?.[2] ?? 0);
31647
32230
  var rubyBuilds = async () => {
@@ -31669,7 +32252,7 @@ async function setupRuby(env, config2) {
31669
32252
  async () => pickPackageVersion([...(await rubyBuilds()).keys()], wantedSpec.spec) ?? Promise.reject(new Error('No RubyInstaller build matches "' + wantedSpec.spec + '"'))
31670
32253
  );
31671
32254
  const home = tool("ruby", version2);
31672
- if (!exists(path61.join(home, "bin", "ruby.exe"))) {
32255
+ if (!exists(path63.join(home, "bin", "ruby.exe"))) {
31673
32256
  const asset = (await rubyBuilds()).get(version2);
31674
32257
  if (!asset) throw new Error("RubyInstaller " + version2 + " is no longer published");
31675
32258
  log("Downloading Ruby " + version2 + " (~100 MB once) ...");
@@ -31682,11 +32265,11 @@ async function setupRuby(env, config2) {
31682
32265
  }
31683
32266
  const gems = tool("ruby-gems", version2.split(".").slice(0, 2).join("."));
31684
32267
  Object.assign(env.vars, { GEM_HOME: gems, BUNDLE_USER_HOME: tool("bundle-home") });
31685
- env.prepend.push(path61.join(home, "bin"), path61.join(gems, "bin"));
32268
+ env.prepend.push(path63.join(home, "bin"), path63.join(gems, "bin"));
31686
32269
  env.summary.push(
31687
- "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)"
31688
32271
  );
31689
- const gem = path61.join(home, "bin", "gem.cmd");
32272
+ const gem = path63.join(home, "bin", "gem.cmd");
31690
32273
  await installOnce(
31691
32274
  env,
31692
32275
  "gem@" + version2,
@@ -31698,9 +32281,9 @@ async function setupRuby(env, config2) {
31698
32281
  }
31699
32282
 
31700
32283
  // src/guest/toolchains/tools/vscode.ts
31701
- import fs48 from "node:fs";
31702
- import os8 from "node:os";
31703
- import path62 from "node:path";
32284
+ import fs51 from "node:fs";
32285
+ import os9 from "node:os";
32286
+ import path64 from "node:path";
31704
32287
 
31705
32288
  // node_modules/jsonc-parser/lib/esm/impl/scanner.js
31706
32289
  var CharacterCodes;
@@ -31880,14 +32463,14 @@ var ParseErrorCode;
31880
32463
  var VERSION_MARKER = ".agent-sandbox-version";
31881
32464
  var desktopShortcut = (exe) => {
31882
32465
  if (!isWin) return;
31883
- const link = path62.join(os8.homedir(), "Desktop", "Visual Studio Code.lnk");
32466
+ const link = path64.join(os9.homedir(), "Desktop", "Visual Studio Code.lnk");
31884
32467
  runScriptWithJson("new-shortcuts.ps1", "ListFile", [
31885
32468
  { link, target: exe, arguments: '"' + (process.env.AGENT_WORKSPACE ?? "") + '"' }
31886
32469
  ]);
31887
32470
  };
31888
32471
  async function setupVscode(env, refresh) {
31889
32472
  const root = tool("vscode");
31890
- const exe = path62.join(root, "Code.exe");
32473
+ const exe = path64.join(root, "Code.exe");
31891
32474
  if (dryRun) {
31892
32475
  log("(dry run) would provision VS Code");
31893
32476
  return;
@@ -31897,11 +32480,11 @@ async function setupVscode(env, refresh) {
31897
32480
  "https://update.code.visualstudio.com/api/update/win32-" + (arch === "arm64" ? "arm64" : "x64") + "-archive/stable/latest"
31898
32481
  );
31899
32482
  log("Downloading VS Code " + release.productVersion + " (~150 MB once) ...");
31900
- const keep = path62.join(root, "data");
32483
+ const keep = path64.join(root, "data");
31901
32484
  const parked = root + "-data";
31902
32485
  if (exists(keep)) {
31903
- fs48.rmSync(parked, { recursive: true, force: true });
31904
- fs48.renameSync(keep, parked);
32486
+ fs51.rmSync(parked, { recursive: true, force: true });
32487
+ fs51.renameSync(keep, parked);
31905
32488
  }
31906
32489
  try {
31907
32490
  await downloader.archive(release.url, root, {
@@ -31909,26 +32492,511 @@ async function setupVscode(env, refresh) {
31909
32492
  locate: "Code.exe",
31910
32493
  fileName: "vscode.zip"
31911
32494
  });
31912
- fs48.writeFileSync(path62.join(root, VERSION_MARKER), release.productVersion);
32495
+ fs51.writeFileSync(path64.join(root, VERSION_MARKER), release.productVersion);
31913
32496
  } finally {
31914
32497
  if (exists(parked)) {
31915
32498
  mkdirp(root);
31916
- fs48.rmSync(keep, { recursive: true, force: true });
31917
- fs48.renameSync(parked, keep);
32499
+ fs51.rmSync(keep, { recursive: true, force: true });
32500
+ fs51.renameSync(parked, keep);
31918
32501
  }
31919
32502
  }
31920
32503
  }
31921
- mkdirp(path62.join(root, "data"));
31922
- env.prepend.push(path62.join(root, "bin"));
32504
+ mkdirp(path64.join(root, "data"));
32505
+ env.prepend.push(path64.join(root, "bin"));
31923
32506
  desktopShortcut(exe);
31924
- 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";
31925
32508
  env.summary.push("vscode: " + version2 + " (portable; run code . or use the desktop shortcut)");
31926
32509
  }
31927
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
+
31928
32996
  // src/guest/toolchains/native/rust-extras.ts
31929
- import fs49 from "node:fs";
31930
- import os9 from "node:os";
31931
- import path63 from "node:path";
32997
+ import fs56 from "node:fs";
32998
+ import os10 from "node:os";
32999
+ import path70 from "node:path";
31932
33000
 
31933
33001
  // src/shared/memory/policy.ts
31934
33002
  var DIAL_STEPS = {
@@ -31977,41 +33045,41 @@ function maxCompilers(cpus, profile) {
31977
33045
  // src/guest/toolchains/native/rust-extras.ts
31978
33046
  var cargoTarget = (targetDir) => {
31979
33047
  if (targetDir === "shared" || targetDir === "separate") return null;
31980
- if (targetDir === "local") return path63.join(localDir, "cargo-target");
33048
+ if (targetDir === "local") return path70.join(localDir, "cargo-target");
31981
33049
  return targetDir;
31982
33050
  };
31983
33051
  function cargoShim(env, rust) {
31984
- const real = path63.join(tool("rust", "cargo", "bin"), "cargo.exe");
33052
+ const real = path70.join(tool("rust", "cargo", "bin"), "cargo.exe");
31985
33053
  if (rust.targetDir !== "separate" || !exists(real)) return;
31986
33054
  const dir = mkdirp(tool("shims", "cargo"));
31987
- fs49.copyFileSync(ensureCompiled("cargoshim"), path63.join(dir, "cargo.exe"));
33055
+ fs56.copyFileSync(ensureCompiled("cargoshim"), path70.join(dir, "cargo.exe"));
31988
33056
  env.prepend.unshift(dir);
31989
33057
  env.vars.AGENT_REAL_CARGO = real;
31990
33058
  }
31991
33059
  function linkGate(env, rust, host) {
31992
33060
  const gcc = tool("mingw", "mingw64", "bin", "gcc.exe");
31993
33061
  if (!host.endsWith("-pc-windows-gnu") || !exists(gcc)) return;
31994
- const gate = path63.join(mkdirp(tool("shims")), "linkgate.exe");
31995
- fs49.copyFileSync(ensureCompiled("linkgate"), gate);
31996
- 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;
31997
33065
  const slots = rust.linkSlots === "auto" ? linkSlotsFor(memoryGb) : rust.linkSlots;
31998
33066
  env.vars.AGENT_LINK_SLOTS = String(slots);
31999
33067
  env.vars.AGENT_REAL_LINKER = gcc;
32000
33068
  env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gate;
32001
33069
  const rustEnv = { ...process.env, RUSTUP_HOME: tool("rust", "rustup"), CARGO_HOME: tool("rust", "cargo") };
32002
33070
  const sysroot = rust.linker === "lld" ? execOutput(tool("rust", "cargo", "bin", "rustc.exe"), ["--print", "sysroot"], { env: rustEnv }) : "";
32003
- const lld = sysroot ? path63.join(sysroot, "lib", "rustlib", host, "bin", "gcc-ld") : "";
32004
- 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;
32005
33073
  env.summary.push(
32006
33074
  "rust linking: " + (env.vars.AGENT_LLD_DIR ? "lld" : "GNU ld") + ", at most " + env.vars.AGENT_LINK_SLOTS + " at once"
32007
33075
  );
32008
33076
  }
32009
33077
  function cargoDefaults(host) {
32010
33078
  const file3 = tool("rust", "cargo", "config.toml");
32011
- if (exists(file3) || !exists(path63.dirname(file3))) return;
32012
- 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);
32013
33081
  const gnu = host.endsWith("-gnu");
32014
- fs49.writeFileSync(
33082
+ fs56.writeFileSync(
32015
33083
  file3,
32016
33084
  [
32017
33085
  "# Written by windows-development-sandbox once; edit freely, it is never overwritten.",
@@ -32026,7 +33094,7 @@ function rustCaches(rust) {
32026
33094
  const target = cargoTarget(rust.targetDir);
32027
33095
  return {
32028
33096
  ...target ? { CARGO_TARGET_DIR: target } : {},
32029
- ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path63.join(dataDir, "cache", "sccache") }
33097
+ ...process.env.SCCACHE_DIR ? {} : { SCCACHE_DIR: path70.join(dataDir, "cache", "sccache") }
32030
33098
  };
32031
33099
  }
32032
33100
  function rustHost(config2) {
@@ -32054,6 +33122,13 @@ function plan(config2, versions, o) {
32054
33122
  const java = wanted(config2.java.enabled, "java");
32055
33123
  const python = wanted(config2.python.enabled, "python");
32056
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
+ };
32057
33132
  return [
32058
33133
  {
32059
33134
  name: "Git",
@@ -32071,18 +33146,32 @@ function plan(config2, versions, o) {
32071
33146
  enabled: wanted(config2.cpp.enabled, "cpp") || wanted(config2.rust.enabled, "rust"),
32072
33147
  install: (env) => setupCpp(env, config2.cpp)
32073
33148
  },
32074
- // Unreal's Visual Studio brings MSVC and the real vswhere: the portable MSVC (and its stand-in vswhere) stays out.
32075
- { 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
+ },
32076
33165
  {
32077
33166
  name: "MSVC",
32078
- enabled: wanted(config2.msvc.enabled, "msvc") && !unreal,
33167
+ enabled: wanted(config2.msvc.enabled, "msvc") && vs === null,
32079
33168
  install: (env) => setupMsvc(env, config2.msvc)
32080
33169
  },
32081
33170
  // Rust links with MSVC (msvc host) or MinGW's gcc (GNU host): whichever it uses goes first.
32082
33171
  {
32083
33172
  name: "Rust",
32084
33173
  enabled: wanted(config2.rust.enabled, "rust"),
32085
- after: ["C/C++", "MSVC", "Unreal"],
33174
+ after: ["C/C++", "MSVC", "Visual Studio", "Unreal"],
32086
33175
  install: async (env) => {
32087
33176
  await setupRust(env, { ...config2.rust, host: rustHost(config2) }, o.refresh);
32088
33177
  Object.assign(env.vars, rustCaches(config2.rust));
@@ -32100,6 +33189,49 @@ function plan(config2, versions, o) {
32100
33189
  },
32101
33190
  { name: "Go", enabled: wanted(config2.go.enabled, "go"), install: (env) => setupGo(env, config2.go) },
32102
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
+ },
32103
33235
  { name: "Ruby", enabled: wanted(config2.ruby.enabled, "ruby"), install: (env) => setupRuby(env, config2.ruby) },
32104
33236
  // PHP installs the Visual C++ runtime itself: one installer at a time.
32105
33237
  // Many apps (bat, delta, Neovim, most GUIs, your own programs) are built against it too.
@@ -32175,7 +33307,7 @@ function plan(config2, versions, o) {
32175
33307
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
32176
33308
 
32177
33309
  // src/guest/runtime/status.ts
32178
- import os10 from "node:os";
33310
+ import os11 from "node:os";
32179
33311
  var progress;
32180
33312
  function setSandboxStatus(phase, message, update) {
32181
33313
  try {
@@ -32199,7 +33331,7 @@ function fitProgress(p) {
32199
33331
  };
32200
33332
  }
32201
33333
  function ownAddresses() {
32202
- 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);
32203
33335
  }
32204
33336
  function writeStatus(phase, message) {
32205
33337
  writeJsonAtomic(run.sandboxFile, {
@@ -32344,21 +33476,21 @@ function cmdSet(env, names) {
32344
33476
  return names.filter((n) => env[n] !== void 0 && !/[\r\n]/.test(String(env[n]))).map((n) => '@set "' + n + "=" + String(env[n]).replace(/%/g, "%%") + '"');
32345
33477
  }
32346
33478
  function writeShell(spec, env, names) {
32347
- const dir = mkdirp(path64.join(localDir, "projects", spec.name));
32348
- fs50.writeFileSync(path64.join(dir, "env.cmd"), [...cmdSet(env, [...names, "PATH"]), ""].join("\r\n"));
32349
- fs50.writeFileSync(
32350
- path64.join(dir, "shell.cmd"),
32351
- ['@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(
32352
33484
  "\r\n"
32353
33485
  )
32354
33486
  );
32355
- const bin = mkdirp(path64.join(localDir, "bin"));
32356
- fs50.writeFileSync(
32357
- path64.join(bin, "sbx-shell.cmd"),
33487
+ const bin = mkdirp(path71.join(localDir, "bin"));
33488
+ fs57.writeFileSync(
33489
+ path71.join(bin, "sbx-shell.cmd"),
32358
33490
  [
32359
- '@if "%~1"=="" (echo Usage: sbx-shell ^<project^> ^(a terminal in that project with its tools^) & dir /b "' + path64.join(localDir, "projects") + '" & exit /b 2)',
32360
- '@if not exist "' + path64.join(localDir, "projects") + '\\%~1\\shell.cmd" (echo No project %~1 in this sandbox. & exit /b 2)',
32361
- '@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""',
32362
33494
  ""
32363
33495
  ].join("\r\n")
32364
33496
  );
@@ -32411,10 +33543,10 @@ async function setUp(spec, say) {
32411
33543
  }
32412
33544
  )
32413
33545
  );
32414
- tools.prepend.push(path64.join(localDir, "bin"));
33546
+ tools.prepend.push(path71.join(localDir, "bin"));
32415
33547
  const env = agentEnv(tools, { workspace: spec.workspace, project: spec.name, base });
32416
- const specFile = path64.join(mkdirp(path64.join(localDir, "projects", spec.name)), "project.json");
32417
- 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));
32418
33550
  env.AGENT_PROJECT_FILE = specFile;
32419
33551
  addMachineEnvironment(tools.vars, [...tools.prepend, ...tools.append], true);
32420
33552
  try {
@@ -32502,7 +33634,7 @@ function execCommand(req) {
32502
33634
  return;
32503
33635
  }
32504
33636
  const env = withRegistryPath(provisioner.provisionedFor(req.cwd)?.env ?? process.env);
32505
- const child = spawn5(
33637
+ const child = spawn6(
32506
33638
  SYSTEM.cmd(),
32507
33639
  ["/d", "/s", "/c", '"chcp 65001>nul & ' + req.command.map(quoteForCmd).join(" ") + '"'],
32508
33640
  { cwd: req.cwd, env, windowsHide: true, windowsVerbatimArguments: true }
@@ -32531,11 +33663,11 @@ function execCommand(req) {
32531
33663
  }
32532
33664
 
32533
33665
  // src/guest/daemon/sessions.ts
32534
- import fs54 from "node:fs";
32535
- import path69 from "node:path";
32536
- import crypto4 from "node:crypto";
32537
- import os12 from "node:os";
32538
- 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";
32539
33671
 
32540
33672
  // src/shared/pty/protocol.ts
32541
33673
  var FrameType = {
@@ -32613,7 +33745,7 @@ async function sendControl(endpoint, type) {
32613
33745
  var MAX_CLIPBOARD_STRING = 1024 * 1024;
32614
33746
 
32615
33747
  // src/guest/sessions/cmdline.ts
32616
- import path65 from "node:path";
33748
+ import path72 from "node:path";
32617
33749
  var quoted = (arg) => '"' + arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
32618
33750
  function quoteArg(arg) {
32619
33751
  return arg !== "" && !/[\s"]/.test(arg) ? arg : quoted(arg);
@@ -32627,7 +33759,7 @@ function cmdArgs(args) {
32627
33759
  }).join("");
32628
33760
  }
32629
33761
  function commandLine(file3, args) {
32630
- 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(" ");
32631
33763
  }
32632
33764
  function shellLaunch(asked, paths) {
32633
33765
  if (asked === "cmd") return { name: "cmd", file: paths.cmd, args: [] };
@@ -32641,9 +33773,9 @@ function shellLaunch(asked, paths) {
32641
33773
  }
32642
33774
 
32643
33775
  // src/guest/sessions/pty-host.ts
32644
- import fs51 from "node:fs";
32645
- import path66 from "node:path";
32646
- 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";
32647
33779
  function ensurePtyHost() {
32648
33780
  return ensureCompiled("ptyhost");
32649
33781
  }
@@ -32661,21 +33793,21 @@ async function waitForPtyHost(child, port, timeoutMs) {
32661
33793
  throw new Error("the session host did not start listening on port " + port);
32662
33794
  }
32663
33795
  function ptyHostLog(id) {
32664
- return path66.join(logsDir, "ptyhost-" + id + ".log");
33796
+ return path73.join(logsDir, "ptyhost-" + id + ".log");
32665
33797
  }
32666
33798
  function ptyHostLogTail(id, lines = 12) {
32667
33799
  try {
32668
- 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");
32669
33801
  } catch {
32670
33802
  return "";
32671
33803
  }
32672
33804
  }
32673
33805
  var conptyDll = () => {
32674
- const dll = path66.join(toolsDir, "conpty", "conpty.dll");
32675
- 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;
32676
33808
  };
32677
33809
  function startPtyHost(o) {
32678
- fs51.mkdirSync(run.treesDir, { recursive: true });
33810
+ fs58.mkdirSync(run.treesDir, { recursive: true });
32679
33811
  const env = {
32680
33812
  ...o.env,
32681
33813
  PTYHOST_BIND: o.remote ? "any" : "loopback",
@@ -32684,7 +33816,7 @@ function startPtyHost(o) {
32684
33816
  delete env.PTYHOST_CONPTY;
32685
33817
  const dll = conptyDll();
32686
33818
  if (dll) env.PTYHOST_CONPTY = dll;
32687
- return spawn6(
33819
+ return spawn7(
32688
33820
  o.exe,
32689
33821
  [String(o.port), o.token, String(o.cols), String(o.rows), ptyHostLog(o.id), o.command, o.restartCommand],
32690
33822
  { cwd: o.cwd, env, detached: true, stdio: "ignore", windowsHide: true }
@@ -32693,13 +33825,13 @@ function startPtyHost(o) {
32693
33825
  var END_TREE_MS = 3e4;
32694
33826
  function endLeftoverTree(id, exe = ensurePtyHost()) {
32695
33827
  const file3 = run.treeFile(id);
32696
- if (!fs51.existsSync(file3)) return Promise.resolve(null);
33828
+ if (!fs58.existsSync(file3)) return Promise.resolve(null);
32697
33829
  return new Promise((resolve2) => {
32698
33830
  execFile(exe, ["--end-tree", file3], { timeout: END_TREE_MS, windowsHide: true }, (error62, stdout) => {
32699
33831
  const code = error62 ? typeof error62.code === "number" ? error62.code : -1 : 0;
32700
33832
  if (code !== 3)
32701
33833
  try {
32702
- fs51.rmSync(file3, { force: true });
33834
+ fs58.rmSync(file3, { force: true });
32703
33835
  } catch {
32704
33836
  }
32705
33837
  resolve2(code === 0 ? stdout.trim().slice(0, 200) : code === 3 ? null : "could not end them (code " + code + ")");
@@ -32708,15 +33840,15 @@ function endLeftoverTree(id, exe = ensurePtyHost()) {
32708
33840
  }
32709
33841
  function recordedTrees() {
32710
33842
  try {
32711
- 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));
32712
33844
  } catch {
32713
33845
  return [];
32714
33846
  }
32715
33847
  }
32716
33848
 
32717
33849
  // src/guest/agents/agent-installer.ts
32718
- import fs52 from "node:fs";
32719
- import path67 from "node:path";
33850
+ import fs59 from "node:fs";
33851
+ import path74 from "node:path";
32720
33852
 
32721
33853
  // src/guest/agents/profile-links.ts
32722
33854
  var profileRoot = () => process.env.USERPROFILE ?? "";
@@ -32742,7 +33874,7 @@ var agentPaths2 = (name, harness) => agentPaths(toolsDir, name, harness);
32742
33874
  async function installViaNpm(name, harness, dir, env) {
32743
33875
  if (!harness.npmPackage)
32744
33876
  throw new Error("No npmPackage configured for " + name + " and no host executable was available.");
32745
- 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");
32746
33878
  const args = [npmCli, "install", "--global", "--prefix", dir, harness.npmPackage, "--no-fund", "--no-audit"];
32747
33879
  log("Installing " + harness.npmPackage + " (this can take a minute)...");
32748
33880
  if (dryRun) {
@@ -32753,7 +33885,7 @@ async function installViaNpm(name, harness, dir, env) {
32753
33885
  await execAsync(process.execPath, args, { env });
32754
33886
  }
32755
33887
  async function installViaUv(name, harness, dir, env) {
32756
- const uv = path67.join(toolsDir, "uv", "uv.exe");
33888
+ const uv = path74.join(toolsDir, "uv", "uv.exe");
32757
33889
  log("Installing " + harness.uvPackage + " with uv (this can take a minute)...");
32758
33890
  if (dryRun) {
32759
33891
  log("(dry run) uv tool install " + harness.uvPackage);
@@ -32768,8 +33900,8 @@ async function installViaUv(name, harness, dir, env) {
32768
33900
  });
32769
33901
  }
32770
33902
  function putOnPath(dir, env) {
32771
- const parts2 = (env.PATH ?? "").split(path67.delimiter);
32772
- 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);
32773
33905
  addMachineEnvironment({}, [dir], true);
32774
33906
  }
32775
33907
  var AgentInstaller = class {
@@ -32810,9 +33942,9 @@ var AgentInstaller = class {
32810
33942
  }
32811
33943
  mkdirp(p.dir);
32812
33944
  if (this.sourceOf(name, harness) === "host") {
32813
- const source = path67.join(hostToolsDir, "agents", name, harness.hostExecutable);
33945
+ const source = path74.join(hostToolsDir, "agents", name, harness.hostExecutable);
32814
33946
  if (exists(source) && p.exe) {
32815
- fs52.copyFileSync(source, p.exe);
33947
+ fs59.copyFileSync(source, p.exe);
32816
33948
  log("Copied " + name + " from this PC: " + source);
32817
33949
  return;
32818
33950
  }
@@ -32827,28 +33959,28 @@ var AgentInstaller = class {
32827
33959
  var agents = new AgentInstaller();
32828
33960
 
32829
33961
  // src/guest/network/addresses.ts
32830
- import os11 from "node:os";
33962
+ import os12 from "node:os";
32831
33963
  function guestAddresses() {
32832
- 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);
32833
33965
  }
32834
33966
 
32835
33967
  // src/guest/sessions/conversation.ts
32836
- import fs53 from "node:fs";
32837
- import path68 from "node:path";
33968
+ import fs60 from "node:fs";
33969
+ import path75 from "node:path";
32838
33970
  var MAX_FILES = 2e3;
32839
33971
  function conversationFiles(claudeDir2, cwd) {
32840
33972
  const names = /* @__PURE__ */ new Set([projectFolderName(cwd), projectFolderName(sandboxFolder(cwd))]);
32841
33973
  return [...names].flatMap((name) => {
32842
- const dir = path68.join(claudeDir2, "projects", name);
33974
+ const dir = path75.join(claudeDir2, "projects", name);
32843
33975
  let entries2;
32844
33976
  try {
32845
- entries2 = fs53.readdirSync(dir);
33977
+ entries2 = fs60.readdirSync(dir);
32846
33978
  } catch {
32847
33979
  return [];
32848
33980
  }
32849
33981
  return entries2.filter((e) => e.endsWith(".jsonl") && isConversationId(e.slice(0, -".jsonl".length))).slice(0, MAX_FILES).flatMap((e) => {
32850
33982
  try {
32851
- 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 }];
32852
33984
  } catch {
32853
33985
  return [];
32854
33986
  }
@@ -32861,6 +33993,263 @@ function findConversation(claudeDir2, cwd, sessionStartMs, claimed) {
32861
33993
 
32862
33994
  // src/guest/daemon/idle-shutdown.ts
32863
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
32864
34253
  var GRACE_MS = 15e3;
32865
34254
  var IdleShutdown = class {
32866
34255
  /** `busy`: a session runs or is starting. */
@@ -32877,7 +34266,7 @@ var IdleShutdown = class {
32877
34266
  log("Headless sandbox has no sessions left; shutting down.");
32878
34267
  safely("claude-mem save", saveClaudeMem);
32879
34268
  safely("agent databases save", saveLocalState);
32880
- spawnSync6(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true });
34269
+ void flushAccounts(true).finally(() => spawnSync6(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true }));
32881
34270
  }, GRACE_MS);
32882
34271
  }
32883
34272
  idle() {
@@ -32889,11 +34278,11 @@ var IdleShutdown = class {
32889
34278
  var CLOSE_WAIT_MS = 8e3;
32890
34279
  var ROOTS_KEPT_MS = 10 * 60 * 1e3;
32891
34280
  function terminalTab(id, title, cwd) {
32892
- const view = [process.execPath, path69.join(path69.dirname(process.argv[1]), "view.js"), id];
32893
- 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");
32894
34283
  if (exists(wt))
32895
- spawn7(wt, ["-w", "0", "nt", "--title", title, "-d", cwd, ...view], { detached: true, stdio: "ignore" }).unref();
32896
- 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();
32897
34286
  }
32898
34287
  var harnessFor = (req) => {
32899
34288
  if (req.harness === session.harnessName && session.harness) return session.harness;
@@ -32906,8 +34295,8 @@ var harnessFor = (req) => {
32906
34295
  function memoryEnv(env, sessions2) {
32907
34296
  const out = {};
32908
34297
  out.PTYHOST_BACKSTOP_MB = String(session.agentBackstop ?? "auto");
32909
- const cpus = usableCpus(os12.cpus().length, session.cpuLimitPercent ?? null);
32910
- const memoryGb = os12.totalmem() / 1024 ** 3;
34298
+ const cpus = usableCpus(os13.cpus().length, session.cpuLimitPercent ?? null);
34299
+ const memoryGb = os13.totalmem() / 1024 ** 3;
32911
34300
  const jobs = cargoJobs(cpus, memoryGb, sessions2);
32912
34301
  out.NUMBER_OF_PROCESSORS = String(cpus);
32913
34302
  if (!env.CARGO_BUILD_JOBS) out.CARGO_BUILD_JOBS = String(jobs);
@@ -32946,10 +34335,10 @@ var agentProgram = async (req, env, say) => {
32946
34335
  };
32947
34336
  function shellPaths() {
32948
34337
  const candidates = [
32949
- path69.join(pwshDir(), "pwsh.exe"),
32950
- 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")
32951
34340
  ];
32952
- 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() };
32953
34342
  }
32954
34343
  var shellProgram = (shell) => {
32955
34344
  const line = commandLine(shell.file, shell.args);
@@ -32957,7 +34346,7 @@ var shellProgram = (shell) => {
32957
34346
  };
32958
34347
  var launchPtyHost = async (req, program, remote, env, sessions2, onSpawn) => {
32959
34348
  const port = await freePort();
32960
- const token = crypto4.randomBytes(24).toString("base64url");
34349
+ const token = crypto5.randomBytes(24).toString("base64url");
32961
34350
  const sessionEnv = {
32962
34351
  ...withRegistryPath(env),
32963
34352
  ...program.environment,
@@ -32983,7 +34372,7 @@ var launchPtyHost = async (req, program, remote, env, sessions2, onSpawn) => {
32983
34372
  } catch (e) {
32984
34373
  const tail = ptyHostLogTail(req.id);
32985
34374
  throw new Error(
32986
- 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")
32987
34376
  );
32988
34377
  }
32989
34378
  return { child, port, token };
@@ -33097,7 +34486,7 @@ var SessionManager = class {
33097
34486
  };
33098
34487
  this.starting++;
33099
34488
  if (req.id !== session.launchId && process.env.AGENT_NO_TABS !== "1")
33100
- 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));
33101
34490
  try {
33102
34491
  if (problem) throw new Error(problem);
33103
34492
  const place = await placeFor(req, say);
@@ -33259,6 +34648,7 @@ var SessionManager = class {
33259
34648
  else safely("post-agent hooks", () => runHooks("post-agent", process.env));
33260
34649
  safely("claude-mem save", saveClaudeMem);
33261
34650
  safely("agent databases save", saveLocalState);
34651
+ void flushAccounts();
33262
34652
  this.idle.check();
33263
34653
  }
33264
34654
  };
@@ -33591,10 +34981,10 @@ var GovernorCore = class {
33591
34981
  };
33592
34982
 
33593
34983
  // src/guest/governor/governor.ts
33594
- import fs55 from "node:fs";
33595
- import os13 from "node:os";
33596
- import path70 from "node:path";
33597
- 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";
33598
34988
  import { createInterface } from "node:readline";
33599
34989
  var SampleSchema = external_exports.object({
33600
34990
  ramTotalMb: external_exports.number(),
@@ -33618,7 +35008,7 @@ var MemGovProcess = class {
33618
35008
  child = null;
33619
35009
  start() {
33620
35010
  try {
33621
- const child = spawn8(ensureCompiled("memgov"), ["serve", "--interval", "2"], {
35011
+ const child = spawn9(ensureCompiled("memgov"), ["serve", "--interval", "2"], {
33622
35012
  stdio: ["pipe", "pipe", "ignore"],
33623
35013
  windowsHide: true
33624
35014
  });
@@ -33663,12 +35053,12 @@ var MemGovProcess = class {
33663
35053
  };
33664
35054
  function appendToMemoryLog(line) {
33665
35055
  try {
33666
- const logs = path70.join(dataDir, "logs");
33667
- 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();
33668
35058
  if (!newest) return;
33669
35059
  const t = /* @__PURE__ */ new Date();
33670
35060
  const stamp = [t.getHours(), t.getMinutes(), t.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
33671
- fs55.appendFileSync(path70.join(logs, newest), stamp + " | " + line + "\r\n");
35061
+ fs64.appendFileSync(path81.join(logs, newest), stamp + " | " + line + "\r\n");
33672
35062
  } catch {
33673
35063
  }
33674
35064
  }
@@ -33686,7 +35076,7 @@ var Governor = class {
33686
35076
  this.core = new GovernorCore({
33687
35077
  port: proc,
33688
35078
  profile,
33689
- maxCompilers: maxCompilers(os13.cpus().length, profile),
35079
+ maxCompilers: maxCompilers(os14.cpus().length, profile),
33690
35080
  now: () => Date.now(),
33691
35081
  logLine: appendToMemoryLog,
33692
35082
  warn,
@@ -33708,16 +35098,16 @@ var Governor = class {
33708
35098
  var governor = new Governor();
33709
35099
 
33710
35100
  // src/guest/daemon/live.ts
33711
- import fs57 from "node:fs";
33712
- import path72 from "node:path";
35101
+ import fs66 from "node:fs";
35102
+ import path83 from "node:path";
33713
35103
  import { spawnSync as spawnSync7 } from "node:child_process";
33714
35104
 
33715
35105
  // src/guest/daemon/live-folders.ts
33716
- import fs56 from "node:fs";
33717
- import path71 from "node:path";
35106
+ import fs65 from "node:fs";
35107
+ import path82 from "node:path";
33718
35108
 
33719
35109
  // src/shared/channel/live.ts
33720
- import crypto5 from "node:crypto";
35110
+ import crypto6 from "node:crypto";
33721
35111
  var LIVE_SHARE_NAME = /^agentsbx-[0-9a-f]{8,32}$/;
33722
35112
  var LIVE_FOLDER_NAME = /^[a-z0-9][a-z0-9_-]{0,63}$/;
33723
35113
  var LIVE_KEY = /^[0-9a-f]{64}$/;
@@ -33747,7 +35137,7 @@ var LiveReplySchema = external_exports.strictObject({
33747
35137
  finishedAt: external_exports.string().max(64)
33748
35138
  });
33749
35139
  function mac3(key2, payload) {
33750
- 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");
33751
35141
  }
33752
35142
  function openLive(key2, envelope, o) {
33753
35143
  if (!key2 || !LIVE_KEY.test(key2))
@@ -33756,7 +35146,7 @@ function openLive(key2, envelope, o) {
33756
35146
  if (!env.success) return { refused: "not a live-folder request" };
33757
35147
  const want = Buffer.from(mac3(key2, env.data.payload), "hex");
33758
35148
  const got = Buffer.from(env.data.mac, "hex");
33759
- if (want.length !== got.length || !crypto5.timingSafeEqual(want, got))
35149
+ if (want.length !== got.length || !crypto6.timingSafeEqual(want, got))
33760
35150
  return { refused: "the signature does not match" };
33761
35151
  let json2;
33762
35152
  try {
@@ -33807,7 +35197,7 @@ var LiveFolderHandler = class {
33807
35197
  }
33808
35198
  read() {
33809
35199
  try {
33810
- const text = fs56.readFileSync(this.o.stateFile, "utf8");
35200
+ const text = fs65.readFileSync(this.o.stateFile, "utf8");
33811
35201
  const parsed = StateSchema.safeParse(JSON.parse(text));
33812
35202
  if (parsed.success && parsed.data.launchId === this.o.launchId) return parsed.data;
33813
35203
  } catch {
@@ -33815,7 +35205,7 @@ var LiveFolderHandler = class {
33815
35205
  return { key: null, launchId: this.o.launchId, seen: [], mappings: [] };
33816
35206
  }
33817
35207
  save(state) {
33818
- fs56.mkdirSync(path71.dirname(this.o.stateFile), { recursive: true });
35208
+ fs65.mkdirSync(path82.dirname(this.o.stateFile), { recursive: true });
33819
35209
  writeJsonAtomic(this.o.stateFile, state);
33820
35210
  }
33821
35211
  /** The key the boot handed over (from the one-shot secrets file). */
@@ -33826,30 +35216,30 @@ var LiveFolderHandler = class {
33826
35216
  /** C:\Workspace\<name> from a checked name only. */
33827
35217
  folderPath(name) {
33828
35218
  if (!LIVE_FOLDER_NAME.test(name)) throw new Error("not a plain folder name");
33829
- return path71.win32.join(this.o.workspaces ?? WORKSPACES_GUEST, name);
35219
+ return path82.win32.join(this.o.workspaces ?? WORKSPACES_GUEST, name);
33830
35220
  }
33831
35221
  /** One pass over run\live: every file is claimed (deleted) at once; valid ones are handled one after another. */
33832
35222
  tick() {
33833
35223
  const dir = this.o.run.liveDir;
33834
35224
  let names;
33835
35225
  try {
33836
- names = fs56.readdirSync(dir);
35226
+ names = fs65.readdirSync(dir);
33837
35227
  } catch {
33838
35228
  return;
33839
35229
  }
33840
35230
  for (const name of names.slice(0, 64)) {
33841
35231
  if (name.endsWith(".tmp")) continue;
33842
- const file3 = path71.join(dir, name);
35232
+ const file3 = path82.join(dir, name);
33843
35233
  let envelope = null;
33844
35234
  try {
33845
- const stat = fs56.lstatSync(file3);
35235
+ const stat = fs65.lstatSync(file3);
33846
35236
  if (stat.isFile() && stat.size <= MAX_REQUEST_BYTES && /^[A-Za-z0-9_-]{1,64}\.json$/.test(name))
33847
- envelope = JSON.parse(fs56.readFileSync(file3, "utf8"));
35237
+ envelope = JSON.parse(fs65.readFileSync(file3, "utf8"));
33848
35238
  } catch {
33849
35239
  envelope = null;
33850
35240
  } finally {
33851
35241
  try {
33852
- fs56.rmSync(file3, { recursive: true, force: true });
35242
+ fs65.rmSync(file3, { recursive: true, force: true });
33853
35243
  } catch {
33854
35244
  }
33855
35245
  }
@@ -33886,18 +35276,18 @@ var LiveFolderHandler = class {
33886
35276
  }
33887
35277
  reply(id, r) {
33888
35278
  try {
33889
- fs56.mkdirSync(this.o.run.liveRepliesDir, { recursive: true });
35279
+ fs65.mkdirSync(this.o.run.liveRepliesDir, { recursive: true });
33890
35280
  writeJsonAtomic(this.o.run.liveReplyFile(id), { id, ...r, finishedAt: new Date(this.now()).toISOString() });
33891
35281
  } catch (e) {
33892
35282
  this.log("live folder reply not written: " + errMsg(e));
33893
35283
  }
33894
35284
  }
33895
35285
  /** map with retries while the share is not there yet. */
33896
- async mapWithRetry(folder, share, readOnly) {
35286
+ async mapWithRetry(folder, share2, readOnly) {
33897
35287
  const tries = this.o.tries ?? 20;
33898
35288
  let code = EXIT_NO_SHARE;
33899
35289
  for (let i = 0; i < tries; i++) {
33900
- code = this.o.bind.map(folder, share, readOnly);
35290
+ code = this.o.bind.map(folder, share2, readOnly);
33901
35291
  if (code !== EXIT_NO_SHARE) return code;
33902
35292
  await (this.o.sleep ?? wait)(500);
33903
35293
  }
@@ -33907,14 +35297,14 @@ var LiveFolderHandler = class {
33907
35297
  assertFree(folder) {
33908
35298
  let exists2 = true;
33909
35299
  try {
33910
- fs56.lstatSync(folder);
35300
+ fs65.lstatSync(folder);
33911
35301
  } catch {
33912
35302
  exists2 = false;
33913
35303
  }
33914
35304
  if (exists2) throw new Error(folder + " exists already");
33915
- const parent = path71.dirname(folder);
33916
- fs56.mkdirSync(parent, { recursive: true });
33917
- 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");
33918
35308
  }
33919
35309
  async act(p) {
33920
35310
  const folder = this.folderPath(p.folder);
@@ -33929,21 +35319,21 @@ var LiveFolderHandler = class {
33929
35319
  this.save({ ...after, mappings: after.mappings.filter((m) => m.folder !== p.folder) });
33930
35320
  return { ok: true, message: "hidden: " + folder };
33931
35321
  }
33932
- const share = p.share ?? "";
35322
+ const share2 = p.share ?? "";
33933
35323
  this.assertFree(folder);
33934
35324
  if (p.kind === "canary") {
33935
- const code2 = await this.mapWithRetry(folder, share, true);
35325
+ const code2 = await this.mapWithRetry(folder, share2, true);
33936
35326
  if (code2 !== EXIT_OK) return { ok: false, message: "the test share could not be shown (" + code2 + ")" };
33937
35327
  try {
33938
- const file3 = path71.join(folder, "token.txt");
33939
- const stat = fs56.statSync(file3);
33940
- 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() : "";
33941
35331
  return LIVE_TOKEN.test(token) ? { ok: true, message: "read the test share", token } : { ok: false, message: "the test share holds no token" };
33942
35332
  } finally {
33943
35333
  this.o.bind.unmap(folder);
33944
35334
  }
33945
35335
  }
33946
- const code = await this.mapWithRetry(folder, share, p.readOnly);
35336
+ const code = await this.mapWithRetry(folder, share2, p.readOnly);
33947
35337
  if (code !== EXIT_OK)
33948
35338
  return {
33949
35339
  ok: false,
@@ -33954,7 +35344,7 @@ var LiveFolderHandler = class {
33954
35344
  ...state,
33955
35345
  mappings: [
33956
35346
  ...state.mappings.filter((m) => m.folder !== p.folder),
33957
- { folder: p.folder, share, readOnly: p.readOnly }
35347
+ { folder: p.folder, share: share2, readOnly: p.readOnly }
33958
35348
  ]
33959
35349
  });
33960
35350
  return { ok: true, message: "shown at " + folder };
@@ -33965,7 +35355,7 @@ var LiveFolderHandler = class {
33965
35355
  for (const m of this.read().mappings) {
33966
35356
  const folder = this.folderPath(m.folder);
33967
35357
  if (this.o.bind.mapped(folder) === EXIT_OK) continue;
33968
- fs56.mkdirSync(path71.dirname(folder), { recursive: true });
35358
+ fs65.mkdirSync(path82.dirname(folder), { recursive: true });
33969
35359
  if (this.o.bind.map(folder, m.share, m.readOnly) === EXIT_OK) done++;
33970
35360
  else this.log("live folder " + folder + " could not be shown again");
33971
35361
  }
@@ -33976,7 +35366,7 @@ var LiveFolderHandler = class {
33976
35366
  // src/guest/daemon/live.ts
33977
35367
  var BIND_TIMEOUT_MS = 3e4;
33978
35368
  var testing = Boolean(process.env.AGENT_DAEMON_STATE_DIR || process.env.AGENT_LOCAL_DIR);
33979
- 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"));
33980
35370
  function bindMount(args) {
33981
35371
  const r = spawnSync7(ensureCompiled("bindmount"), args, {
33982
35372
  windowsHide: true,
@@ -33986,12 +35376,12 @@ function bindMount(args) {
33986
35376
  return r.status ?? 1;
33987
35377
  }
33988
35378
  var realBind = {
33989
- map: (folder, share, readOnly) => bindMount(["map", folder, share, ...readOnly ? [] : ["rw"]]),
35379
+ map: (folder, share2, readOnly) => bindMount(["map", folder, share2, ...readOnly ? [] : ["rw"]]),
33990
35380
  unmap: (folder) => bindMount(["unmap", folder]),
33991
35381
  mapped: (folder) => bindMount(["mapped", folder])
33992
35382
  };
33993
35383
  function protectStateDir() {
33994
- fs57.mkdirSync(stateDir2, { recursive: true });
35384
+ fs66.mkdirSync(stateDir2, { recursive: true });
33995
35385
  if (!isWin || testMode || testing) return;
33996
35386
  spawnSync7(
33997
35387
  SYSTEM.icacls(),
@@ -34004,7 +35394,7 @@ function protectStateDir() {
34004
35394
  }
34005
35395
  var liveFolders = new LiveFolderHandler({
34006
35396
  run,
34007
- stateFile: path72.join(stateDir2, "live-folders.json"),
35397
+ stateFile: path83.join(stateDir2, "live-folders.json"),
34008
35398
  launchId: session.launchId,
34009
35399
  bind: realBind,
34010
35400
  log: warn
@@ -34034,9 +35424,9 @@ var Daemon = class {
34034
35424
  tick() {
34035
35425
  const { valid, invalid } = run.scanRequests();
34036
35426
  for (const file3 of invalid)
34037
- 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 }));
34038
35428
  for (const req of valid) {
34039
- 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 }));
34040
35430
  if (run.readSession(req.id)) continue;
34041
35431
  void Promise.resolve(this.handle(withRequestSecrets(req))).catch(
34042
35432
  (e) => respond(req.id, { ok: false, message: errMsg(e) })
@@ -34047,6 +35437,7 @@ var Daemon = class {
34047
35437
  this.lastMemSave = Date.now();
34048
35438
  safely("claude-mem save", saveClaudeMem);
34049
35439
  safely("agent databases save", saveLocalState);
35440
+ void flushAccounts();
34050
35441
  }
34051
35442
  }
34052
35443
  handle(req) {
@@ -34080,4 +35471,5 @@ safely("audit", () => startProcessCollector(() => sessions.roots()));
34080
35471
  safely("leftover processes", () => sessions.sweepLeftovers());
34081
35472
  safely("memory governor", () => governor.start());
34082
35473
  log("Memory governor: " + governor.describe());
35474
+ safely("service sign-ins", startAccountWatch);
34083
35475
  new Daemon().start();