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
@@ -0,0 +1,159 @@
1
+ // Large installs kept between sandboxes in C:\AgentData\tools (engines, editors, SDKs: 1-60 GB each). One version is
2
+ // a folder tools\<name>\<version>; it counts as installed only with its .complete.json and its marker file. A new one
3
+ // is checked for room first, built in a staging folder next to it (with TEMP inside it: moving from the sandbox's own
4
+ // disk into a mapped folder fails silently) and moved into place when done. Every install's size and last use go in
5
+ // tools\installs.json, so `sandbox data` shows them without walking 60 GB, and versions beyond keepVersions go (the
6
+ // least recently used first). No runtime imports: the self-test loads this file with its own folders.
7
+ import crypto from 'node:crypto';
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import { readValid, writeJsonAtomic } from '../../shared/io/json.js';
11
+ import { safeRemove } from '../../shared/io/safe-remove.js';
12
+ import { dataDir } from '../runtime/paths.js';
13
+ import { INSTALL_RECORDS_FILE, InstallRecordsSchema } from '../../shared/installs.js';
14
+ const GB = 1024 ** 3;
15
+ /** What stays free on the sandbox's own disk after a real installer: the paging file and every build need it. */
16
+ export const LOCAL_RESERVE_BYTES = 13 * GB;
17
+ const MARKER = '.complete.json';
18
+ const MAX_WALK = 2_000_000;
19
+ const NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
20
+ export { InstallRecordsSchema } from '../../shared/installs.js';
21
+ const toolsOf = (deps) => deps.toolsDir ?? path.join(dataDir, 'tools');
22
+ const recordsFile = (deps) => path.join(toolsOf(deps), INSTALL_RECORDS_FILE);
23
+ function checkSpec(spec) {
24
+ const parts = spec.name.split('/');
25
+ if (parts.length > 2 || !parts.every((p) => NAME.test(p)) || !NAME.test(spec.version))
26
+ throw new Error('not a usable install name: ' + spec.name + ' ' + spec.version);
27
+ }
28
+ /** Free bytes for this user on the disk holding `dir` (0 when it cannot be told). */
29
+ export function freeBytes(dir, deps = {}) {
30
+ try {
31
+ const s = (deps.statfs ?? fs.statfsSync)(dir);
32
+ return s.bavail * s.bsize;
33
+ }
34
+ catch {
35
+ return 0;
36
+ }
37
+ }
38
+ const gb = (bytes) => (bytes / GB).toFixed(1) + ' GB';
39
+ /** Throws (with the fix) when the disk holding `dir` has less than `needBytes` free. */
40
+ export function assertRoom(dir, needBytes, what, fix, deps = {}) {
41
+ const free = freeBytes(dir, deps);
42
+ if (free < needBytes)
43
+ throw new Error('not installing ' + what + ': ' + gb(free) + ' free where it goes, it needs ' + gb(needBytes) + '. ' + fix);
44
+ }
45
+ /** A real installer on the sandbox's own disk (C:): its size plus 13 GB must stay free (paging file, builds). */
46
+ export function assertLocalRoom(needBytes, what, deps = {}) {
47
+ const drive = deps.localDir ?? (process.env.SystemDrive ?? 'C:') + '\\';
48
+ assertRoom(drive, needBytes + LOCAL_RESERVE_BYTES, what, "The sandbox's own disk also holds the paging file and every build: give the sandbox less to install, or a smaller sandbox.pageFileMb.", deps);
49
+ }
50
+ export function installRecords(deps = {}) {
51
+ return readValid(InstallRecordsSchema, recordsFile(deps))?.installs ?? [];
52
+ }
53
+ function writeRecords(records, deps) {
54
+ fs.mkdirSync(toolsOf(deps), { recursive: true });
55
+ writeJsonAtomic(recordsFile(deps), { installs: [...records] });
56
+ }
57
+ /** Notes that a version was used now (it is kept over ones used longer ago). */
58
+ export function recordUse(name, version, deps = {}) {
59
+ const now = new Date().toISOString();
60
+ const all = installRecords(deps);
61
+ const known = all.find((r) => r.name === name && r.version === version);
62
+ writeRecords(known
63
+ ? all.map((r) => (r === known ? { ...r, usedAt: now } : r))
64
+ : [...all, { name, version, sizeBytes: null, installedAt: now, usedAt: now }], deps);
65
+ }
66
+ /** The bytes under a folder (links not followed), or null when there are too many files to count. */
67
+ function folderSize(dir) {
68
+ let total = 0;
69
+ let seen = 0;
70
+ const stack = [dir];
71
+ while (stack.length) {
72
+ const current = stack.pop();
73
+ let entries;
74
+ try {
75
+ entries = fs.readdirSync(current, { withFileTypes: true });
76
+ }
77
+ catch {
78
+ continue;
79
+ }
80
+ for (const e of entries) {
81
+ if (++seen > MAX_WALK)
82
+ return null;
83
+ const full = path.join(current, e.name);
84
+ if (e.isDirectory())
85
+ stack.push(full);
86
+ else if (e.isFile())
87
+ try {
88
+ total += fs.statSync(full).size;
89
+ }
90
+ catch {
91
+ // Gone while counting: not counted.
92
+ }
93
+ }
94
+ }
95
+ return total;
96
+ }
97
+ function complete(dir, marker) {
98
+ return fs.existsSync(path.join(dir, MARKER)) && fs.existsSync(path.join(dir, marker));
99
+ }
100
+ /** Removes versions of a tool beyond `keep` (the least recently used first), never `current`. */
101
+ function prune(spec, deps) {
102
+ if (!spec.keepVersions)
103
+ return;
104
+ const root = path.join(toolsOf(deps), ...spec.name.split('/'));
105
+ const mine = installRecords(deps)
106
+ .filter((r) => r.name === spec.name && r.version !== spec.version)
107
+ .sort((a, b) => b.usedAt.localeCompare(a.usedAt));
108
+ const gone = mine.slice(Math.max(0, spec.keepVersions - 1));
109
+ for (const r of gone) {
110
+ if (!NAME.test(r.version))
111
+ continue;
112
+ safeRemove(path.join(root, r.version), root);
113
+ deps.log?.('Removed ' + spec.name + ' ' + r.version + ' (keepVersions ' + spec.keepVersions + ')');
114
+ }
115
+ const isGone = (r) => r.name === spec.name && gone.some((g) => g.version === r.version);
116
+ if (gone.length)
117
+ writeRecords(installRecords(deps).filter((r) => !isGone(r)), deps);
118
+ }
119
+ /**
120
+ * The version's folder, installed by `install(staging, temp)` when it is not there yet. The installer puts the
121
+ * version's files in `staging` and its temporary files in `temp` (inside staging); a failed install leaves nothing.
122
+ */
123
+ export async function ensurePersisted(spec, install, deps = {}) {
124
+ checkSpec(spec);
125
+ const root = path.join(toolsOf(deps), ...spec.name.split('/'));
126
+ const dir = path.join(root, spec.version);
127
+ if (complete(dir, spec.marker)) {
128
+ recordUse(spec.name, spec.version, deps);
129
+ const known = installRecords(deps).find((r) => r.name === spec.name && r.version === spec.version);
130
+ return { dir, fresh: false, sizeBytes: known?.sizeBytes ?? null };
131
+ }
132
+ fs.mkdirSync(root, { recursive: true });
133
+ assertRoom(root, spec.needBytes, spec.what, 'Free room on that disk (with contained storage: raise storage.containedMaxGb), or keep fewer versions.', deps);
134
+ const staging = path.join(root, '.staging-' + spec.version + '-' + crypto.randomBytes(3).toString('hex'));
135
+ const temp = path.join(staging, '.temp');
136
+ fs.mkdirSync(temp, { recursive: true });
137
+ try {
138
+ await install(staging, temp);
139
+ if (!fs.existsSync(path.join(staging, spec.marker)))
140
+ throw new Error(spec.what + ': the install finished without ' + spec.marker);
141
+ safeRemove(temp, staging);
142
+ const sizeBytes = folderSize(staging);
143
+ writeJsonAtomic(path.join(staging, MARKER), { name: spec.name, version: spec.version, sizeBytes });
144
+ if (fs.existsSync(dir))
145
+ safeRemove(dir, root);
146
+ fs.renameSync(staging, dir);
147
+ const now = new Date().toISOString();
148
+ writeRecords([
149
+ ...installRecords(deps).filter((r) => !(r.name === spec.name && r.version === spec.version)),
150
+ { name: spec.name, version: spec.version, sizeBytes, installedAt: now, usedAt: now },
151
+ ], deps);
152
+ prune(spec, deps);
153
+ return { dir, fresh: true, sizeBytes };
154
+ }
155
+ finally {
156
+ if (fs.existsSync(staging))
157
+ safeRemove(staging, root);
158
+ }
159
+ }
@@ -21,6 +21,17 @@ import { setupPhp } from './languages/php.js';
21
21
  import { setupRuby } from './languages/ruby.js';
22
22
  import { setupVcRuntime } from './native/vcruntime.js';
23
23
  import { setupVscode } from './tools/vscode.js';
24
+ import { ensureVisualStudio, visualStudioWanted } from './native/visual-studio.js';
25
+ import { duringSession } from '../runtime/project-context.js';
26
+ import { setupSteam } from './steam/steam.js';
27
+ import { setupGodot } from './engines/godot.js';
28
+ import { setupUnity } from './engines/unity.js';
29
+ import { setupFivem } from './fivem/fivem.js';
30
+ import { setupAndroid } from './mobile/android.js';
31
+ import { setupFlutter } from './mobile/flutter.js';
32
+ import { setupDart } from './mobile/dart.js';
33
+ import { setupReactNative } from './mobile/react-native.js';
34
+ import { setupKotlin } from './languages/kotlin.js';
24
35
  import { rustHost, rustCaches, cargoDefaults, cargoShim, linkGate } from './native/rust-extras.js';
25
36
  import { setupPythonTools } from './languages/python-tools.js';
26
37
  export function plan(config, versions, o) {
@@ -28,6 +39,14 @@ export function plan(config, versions, o) {
28
39
  const java = wanted(config.java.enabled, 'java');
29
40
  const python = wanted(config.python.enabled, 'python');
30
41
  const unreal = wanted(config.unreal.enabled, 'unreal');
42
+ const android = wanted(config.android.enabled, 'android');
43
+ // One Visual Studio for every toolchain that needs the real one (Unreal, Flutter desktop, Unity IL2CPP).
44
+ const vs = visualStudioWanted(config, (setting, name) => wanted(setting, name));
45
+ const ctx = {
46
+ refresh: o.refresh,
47
+ pcInstalls: o.pcInstalls ?? { items: [] },
48
+ duringSession: duringSession(),
49
+ };
31
50
  return [
32
51
  {
33
52
  name: 'Git',
@@ -45,18 +64,32 @@ export function plan(config, versions, o) {
45
64
  enabled: wanted(config.cpp.enabled, 'cpp') || wanted(config.rust.enabled, 'rust'),
46
65
  install: (env) => setupCpp(env, config.cpp),
47
66
  },
48
- // Unreal's Visual Studio brings MSVC and the real vswhere: the portable MSVC (and its stand-in vswhere) stays out.
49
- { name: 'Unreal', enabled: unreal, shared: true, install: (env) => setupUnreal(env, config.unreal) },
67
+ // Visual Studio brings MSVC and the real vswhere: the portable MSVC (and its stand-in vswhere) stays out.
68
+ {
69
+ name: 'Visual Studio',
70
+ enabled: vs !== null,
71
+ shared: true,
72
+ install: async (env) => {
73
+ await ensureVisualStudio(env, vs, { keepInstallFiles: config.unreal.keepInstallFiles });
74
+ },
75
+ },
76
+ {
77
+ name: 'Unreal',
78
+ enabled: unreal,
79
+ shared: true,
80
+ after: ['Visual Studio'],
81
+ install: (env) => setupUnreal(env, config.unreal, ctx),
82
+ },
50
83
  {
51
84
  name: 'MSVC',
52
- enabled: wanted(config.msvc.enabled, 'msvc') && !unreal,
85
+ enabled: wanted(config.msvc.enabled, 'msvc') && vs === null,
53
86
  install: (env) => setupMsvc(env, config.msvc),
54
87
  },
55
88
  // Rust links with MSVC (msvc host) or MinGW's gcc (GNU host): whichever it uses goes first.
56
89
  {
57
90
  name: 'Rust',
58
91
  enabled: wanted(config.rust.enabled, 'rust'),
59
- after: ['C/C++', 'MSVC', 'Unreal'],
92
+ after: ['C/C++', 'MSVC', 'Visual Studio', 'Unreal'],
60
93
  install: async (env) => {
61
94
  await setupRust(env, { ...config.rust, host: rustHost(config) }, o.refresh);
62
95
  Object.assign(env.vars, rustCaches(config.rust));
@@ -74,6 +107,49 @@ export function plan(config, versions, o) {
74
107
  },
75
108
  { name: 'Go', enabled: wanted(config.go.enabled, 'go'), install: (env) => setupGo(env, config.go) },
76
109
  { name: 'Java', enabled: java, install: (env) => setupJava(env, config.java) },
110
+ { name: 'Kotlin', enabled: java && config.java.kotlin, after: ['Java'], install: (env) => setupKotlin(env, ctx) },
111
+ // Game engines, stores and mobile: each module keeps its big installs in tools (persisted.ts).
112
+ {
113
+ name: 'Android SDK',
114
+ enabled: android,
115
+ after: ['Java'],
116
+ install: (env) => setupAndroid(env, config.android, ctx),
117
+ },
118
+ {
119
+ name: 'Steam',
120
+ enabled: wanted(config.steam.enabled, 'steam'),
121
+ install: (env) => setupSteam(env, config.steam, ctx),
122
+ },
123
+ {
124
+ name: 'Unity',
125
+ enabled: wanted(config.unity.enabled, 'unity'),
126
+ after: ['Visual Studio', 'Android SDK'],
127
+ install: (env) => setupUnity(env, config.unity, ctx),
128
+ },
129
+ {
130
+ name: 'Godot',
131
+ enabled: wanted(config.godot.enabled, 'godot'),
132
+ after: ['.NET', 'Android SDK'],
133
+ install: (env) => setupGodot(env, config.godot, ctx),
134
+ },
135
+ {
136
+ name: 'FiveM server',
137
+ enabled: wanted(config.fivem.enabled, 'fivem'),
138
+ install: (env) => setupFivem(env, config.fivem, ctx),
139
+ },
140
+ {
141
+ name: 'Flutter',
142
+ enabled: wanted(config.flutter.enabled, 'flutter'),
143
+ after: ['Visual Studio', 'Android SDK'],
144
+ install: (env) => setupFlutter(env, config.flutter, ctx),
145
+ },
146
+ { name: 'Dart', enabled: wanted(config.dart.enabled, 'dart'), install: (env) => setupDart(env, config.dart, ctx) },
147
+ {
148
+ name: 'React Native',
149
+ enabled: wanted(config.reactNative.enabled, 'reactNative'),
150
+ after: ['Android SDK'],
151
+ install: (env) => setupReactNative(env, config.reactNative, ctx),
152
+ },
77
153
  { name: 'Ruby', enabled: wanted(config.ruby.enabled, 'ruby'), install: (env) => setupRuby(env, config.ruby) },
78
154
  // PHP installs the Visual C++ runtime itself: one installer at a time.
79
155
  // Many apps (bat, delta, Neovim, most GUIs, your own programs) are built against it too.
@@ -0,0 +1,27 @@
1
+ import { type PersistedDeps } from '../persisted.js';
2
+ /** The room sbx-steam app wants free when you do not say (--need-gb). */
3
+ export declare const DEFAULT_APP_NEED_BYTES: number;
4
+ /** The name apps are recorded under in tools\installs.json (the version is the app ID). */
5
+ export declare const STEAM_APPS_RECORD = "steam-apps";
6
+ /** Throws (with the fix) when the disk that gets the app has less than `needBytes` free. */
7
+ export declare function assertAppRoom(dir: string, needBytes: number, what: string, deps?: PersistedDeps): void;
8
+ /** The bytes under a folder (links not followed), or null when there are too many files to count. */
9
+ export declare function folderSize(dir: string): number | null;
10
+ /** Records an app's size (and that it was used now) in tools\installs.json. */
11
+ export declare function recordApp(appId: string, sizeBytes: number | null, deps?: PersistedDeps): void;
12
+ export interface AppManifest {
13
+ readonly appId: string;
14
+ readonly name: string;
15
+ readonly installDir: string;
16
+ readonly buildId?: string;
17
+ }
18
+ /** An appmanifest_<id>.acf (bounded), or null. */
19
+ export declare function readAppManifest(file: string): AppManifest | null;
20
+ export interface InstalledApp {
21
+ readonly appId: string;
22
+ readonly name: string;
23
+ readonly dir: string;
24
+ readonly sizeBytes: number | null;
25
+ }
26
+ /** The apps in tools\steam-apps, with their names (from SteamCMD's manifest) and recorded sizes. */
27
+ export declare function installedApps(deps?: PersistedDeps): InstalledApp[];
@@ -0,0 +1,112 @@
1
+ // Games and dedicated servers that sbx-steam app downloads into tools\steam-apps\<appid> (kept between sandboxes):
2
+ // the room check before, the size afterwards in tools\installs.json (so `sandbox data` shows it without walking the
3
+ // folder), and what is there. No runtime imports: the self-test loads this file with its own folders.
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { INSTALL_RECORDS_FILE } from '../../../shared/installs.js';
7
+ import { readBoundedFile } from '../../../shared/io/bounded.js';
8
+ import { writeJsonAtomic } from '../../../shared/io/json.js';
9
+ import { parseVdf, vdfText } from '../../../shared/vdf.js';
10
+ import { toolsDir } from '../../runtime/paths.js';
11
+ import { assertRoom, installRecords } from '../persisted.js';
12
+ import { checkAppId, steamAppsRoot } from './commands.js';
13
+ const GB = 1024 ** 3;
14
+ /** The room sbx-steam app wants free when you do not say (--need-gb). */
15
+ export const DEFAULT_APP_NEED_BYTES = 5 * GB;
16
+ /** The name apps are recorded under in tools\installs.json (the version is the app ID). */
17
+ export const STEAM_APPS_RECORD = 'steam-apps';
18
+ const MAX_WALK = 2_000_000;
19
+ const MAX_MANIFEST_BYTES = 256 * 1024;
20
+ const toolsOf = (deps) => deps.toolsDir ?? toolsDir;
21
+ /** Throws (with the fix) when the disk that gets the app has less than `needBytes` free. */
22
+ export function assertAppRoom(dir, needBytes, what, deps = {}) {
23
+ let probe = dir;
24
+ while (!fs.existsSync(probe) && path.dirname(probe) !== probe)
25
+ probe = path.dirname(probe);
26
+ assertRoom(probe, needBytes, what, 'Free room on that disk (with contained storage: raise storage.containedMaxGb), or ask for less with --need-gb.', deps);
27
+ }
28
+ /** The bytes under a folder (links not followed), or null when there are too many files to count. */
29
+ export function folderSize(dir) {
30
+ let total = 0;
31
+ let seen = 0;
32
+ const stack = [dir];
33
+ while (stack.length) {
34
+ const current = stack.pop();
35
+ let entries;
36
+ try {
37
+ entries = fs.readdirSync(current, { withFileTypes: true });
38
+ }
39
+ catch {
40
+ continue;
41
+ }
42
+ for (const e of entries) {
43
+ if (++seen > MAX_WALK)
44
+ return null;
45
+ const full = path.join(current, e.name);
46
+ if (e.isDirectory())
47
+ stack.push(full);
48
+ else if (e.isFile())
49
+ try {
50
+ total += fs.lstatSync(full).size;
51
+ }
52
+ catch {
53
+ // Gone while counting: not counted.
54
+ }
55
+ }
56
+ }
57
+ return total;
58
+ }
59
+ /** Records an app's size (and that it was used now) in tools\installs.json. */
60
+ export function recordApp(appId, sizeBytes, deps = {}) {
61
+ checkAppId(appId);
62
+ const now = new Date().toISOString();
63
+ const all = installRecords(deps);
64
+ const known = all.find((r) => r.name === STEAM_APPS_RECORD && r.version === appId);
65
+ const record = {
66
+ name: STEAM_APPS_RECORD,
67
+ version: appId,
68
+ sizeBytes,
69
+ installedAt: known?.installedAt ?? now,
70
+ usedAt: now,
71
+ };
72
+ const installs = [...all.filter((r) => r !== known), record];
73
+ fs.mkdirSync(toolsOf(deps), { recursive: true });
74
+ writeJsonAtomic(path.join(toolsOf(deps), INSTALL_RECORDS_FILE), { installs });
75
+ }
76
+ /** An appmanifest_<id>.acf (bounded), or null. */
77
+ export function readAppManifest(file) {
78
+ const bytes = readBoundedFile(file, MAX_MANIFEST_BYTES);
79
+ const root = bytes ? parseVdf(bytes.toString('utf8'), { maxBytes: MAX_MANIFEST_BYTES }) : null;
80
+ const appId = vdfText(root, 'AppState', 'appid');
81
+ const installDir = vdfText(root, 'AppState', 'installdir');
82
+ if (!appId || !/^\d{1,10}$/.test(appId) || !installDir)
83
+ return null;
84
+ const buildId = vdfText(root, 'AppState', 'buildid');
85
+ return {
86
+ appId,
87
+ name: (vdfText(root, 'AppState', 'name') ?? appId).slice(0, 200),
88
+ installDir,
89
+ ...(buildId && /^\d{1,20}$/.test(buildId) ? { buildId } : {}),
90
+ };
91
+ }
92
+ /** The apps in tools\steam-apps, with their names (from SteamCMD's manifest) and recorded sizes. */
93
+ export function installedApps(deps = {}) {
94
+ const root = steamAppsRoot(toolsOf(deps));
95
+ let ids;
96
+ try {
97
+ ids = fs
98
+ .readdirSync(root)
99
+ .filter((n) => /^[1-9]\d{0,9}$/.test(n))
100
+ .slice(0, 1000);
101
+ }
102
+ catch {
103
+ return [];
104
+ }
105
+ const records = installRecords(deps);
106
+ return ids.map((appId) => {
107
+ const dir = path.join(root, appId);
108
+ const manifest = readAppManifest(path.join(dir, 'steamapps', 'appmanifest_' + appId + '.acf'));
109
+ const record = records.find((r) => r.name === STEAM_APPS_RECORD && r.version === appId);
110
+ return { appId, name: manifest?.name ?? '(not downloaded yet)', dir, sizeBytes: record?.sizeBytes ?? null };
111
+ });
112
+ }
@@ -0,0 +1,5 @@
1
+ import { type ToolEnv } from '../tool-env.js';
2
+ /** steam.exe in tools\steam when it is there and Valve-signed, else null. */
3
+ export declare function installedSteamClient(): string | null;
4
+ /** steam.exe ready to start, or null when it could not be set up (the reason is in the log and the summary). */
5
+ export declare function ensureSteamClient(env: ToolEnv): Promise<string | null>;
@@ -0,0 +1,67 @@
1
+ // The Steam client (toolchains.steam.client): SteamSetup.exe (Valve-signed) unpacked silently into tools\steam once;
2
+ // steam.exe then fetches and updates the rest of itself in place when you start it (sbx-steam client). You sign in to
3
+ // it in each sandbox: its login is very likely tied to the Windows user, so it does not carry over.
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { errMsg } from '../../../core/util/errors.js';
7
+ import { moveIntoPlace, spawnAsync, stagingFolder } from '../../../shared/download/index.js';
8
+ import { safeRemove } from '../../../shared/io/safe-remove.js';
9
+ import { exists } from '../../runtime/fs.js';
10
+ import { log } from '../../runtime/log.js';
11
+ import { toolsDir } from '../../runtime/paths.js';
12
+ import { SIGNERS, signedBy, signedInstaller } from '../installers.js';
13
+ import { assertRoom } from '../persisted.js';
14
+ import { tool } from '../tool-env.js';
15
+ import { STEAM_CLIENT_URL, steamClientDir } from './commands.js';
16
+ const GB = 1024 ** 3;
17
+ /** The client grows to 1-1.5 GB once it has updated itself (games come on top). */
18
+ const CLIENT_NEED_BYTES = 2 * GB;
19
+ const SETUP_TIMEOUT_MS = 10 * 60 * 1000;
20
+ /** steam.exe in tools\steam when it is there and Valve-signed, else null. */
21
+ export function installedSteamClient() {
22
+ const exe = path.join(steamClientDir(), 'steam.exe');
23
+ return exists(exe) && signedBy(exe, SIGNERS.valve) ? exe : null;
24
+ }
25
+ async function installSteamClient() {
26
+ const dir = steamClientDir();
27
+ const exe = path.join(dir, 'steam.exe');
28
+ if (exists(exe)) {
29
+ if (!signedBy(exe, SIGNERS.valve))
30
+ throw new Error('tools\\steam\\steam.exe is not signed by Valve');
31
+ return exe;
32
+ }
33
+ fs.mkdirSync(toolsDir, { recursive: true });
34
+ assertRoom(toolsDir, CLIENT_NEED_BYTES, 'the Steam client', 'Free room on the data disk.');
35
+ const setup = await signedInstaller(STEAM_CLIENT_URL, path.join(tool('steam-setup'), 'SteamSetup.exe'), 'the Steam client installer (~2 MB once)', SIGNERS.valve);
36
+ const work = stagingFolder(dir);
37
+ fs.mkdirSync(work, { recursive: true });
38
+ try {
39
+ log('Unpacking the Steam client into tools\\steam ...');
40
+ // NSIS: /S silent, /D= the folder (last, unquoted: the staging path has no spaces).
41
+ const code = await spawnAsync(setup, ['/S', '/D=' + work], { timeout: SETUP_TIMEOUT_MS });
42
+ const unpacked = path.join(work, 'steam.exe');
43
+ if (!exists(unpacked))
44
+ throw new Error('SteamSetup.exe did not unpack steam.exe (exit code ' + code + ')');
45
+ if (!signedBy(unpacked, SIGNERS.valve))
46
+ throw new Error('the unpacked steam.exe is not signed by Valve');
47
+ moveIntoPlace(work, dir);
48
+ }
49
+ finally {
50
+ if (fs.existsSync(work))
51
+ safeRemove(work, path.dirname(work));
52
+ }
53
+ return exe;
54
+ }
55
+ /** steam.exe ready to start, or null when it could not be set up (the reason is in the log and the summary). */
56
+ export async function ensureSteamClient(env) {
57
+ try {
58
+ const exe = await installSteamClient();
59
+ env.summary.push('steam client: tools\\steam (start it with sbx-steam client; sign in there in each sandbox)');
60
+ return exe;
61
+ }
62
+ catch (e) {
63
+ log('Steam client: not set up: ' + errMsg(e));
64
+ env.summary.push('steam client: not set up (' + errMsg(e) + ')');
65
+ return null;
66
+ }
67
+ }
@@ -0,0 +1,58 @@
1
+ /** Where SteamCMD runs from in the sandbox (its own disk: its config\ holds the login). */
2
+ export declare const STEAMCMD_DIR = "C:\\SteamCMD";
3
+ /** Valve publishes no checksum for it: steamcmd.exe inside must be Valve-signed. */
4
+ export declare const STEAMCMD_URL = "https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip";
5
+ export declare const STEAM_CLIENT_URL = "https://steamcdn-a.akamaihd.net/client/installer/SteamSetup.exe";
6
+ /** SteamCMD's binaries, kept between sandboxes (never its config\ or sentry files). */
7
+ export declare function steamCmdStore(tools?: string): string;
8
+ /** Games and dedicated servers that sbx-steam app downloads: tools\steam-apps\<appid>. */
9
+ export declare function steamAppsRoot(tools?: string): string;
10
+ export declare function steamAppDir(appId: string, tools?: string): string;
11
+ /** Workshop items that sbx-steam workshop get downloads (a cache on the data disk). */
12
+ export declare function workshopCache(data?: string): string;
13
+ /** Where a downloaded workshop item is. */
14
+ export declare function workshopItemDir(cache: string, appId: string, item: string): string;
15
+ /** The Steam client (toolchains.steam.client), which updates itself in place. */
16
+ export declare function steamClientDir(tools?: string): string;
17
+ export declare const checkAppId: (v: string) => string;
18
+ export declare const checkItemId: (v: string) => string;
19
+ export declare const checkBranch: (v: string) => string;
20
+ /** A Steam account name, or "anonymous" (dedicated servers and free tools). */
21
+ export declare const checkLogin: (v: string) => string;
22
+ /** A full path SteamCMD can take as one value: no quotes, no `+` at the start of a part, no line breaks. */
23
+ export declare function checkPathValue(p: string, what: string): string;
24
+ export interface AppUpdate {
25
+ readonly appId: string;
26
+ readonly dir: string;
27
+ readonly login: string;
28
+ readonly beta?: string;
29
+ readonly validate?: boolean;
30
+ }
31
+ /** Downloads or updates an app (a game, a dedicated server) into a folder. force_install_dir comes before login. */
32
+ export declare function appUpdateArgs(o: AppUpdate): string[];
33
+ export interface WorkshopGet {
34
+ readonly appId: string;
35
+ readonly items: readonly string[];
36
+ readonly dir: string;
37
+ readonly login: string;
38
+ readonly validate?: boolean;
39
+ }
40
+ /** Downloads workshop items of an app into <dir>\steamapps\workshop\content\<app>\<item>. */
41
+ export declare function workshopGetArgs(o: WorkshopGet): string[];
42
+ /** Uploads a workshop item described by a workshop_item .vdf (a real account: not anonymous). */
43
+ export declare function workshopPushArgs(login: string, script: string): string[];
44
+ /** Uploads a build described by an app_build .vdf (ContentBuilder). */
45
+ export declare function appBuildArgs(login: string, script: string): string[];
46
+ /** Signs in (SteamCMD asks for the password and the Steam Guard code itself) and keeps the login. */
47
+ export declare function loginArgs(login: string): string[];
48
+ /** At most this much of a build or workshop script is read. */
49
+ export declare const MAX_SCRIPT_BYTES: number;
50
+ /** What a SteamCMD script is: its root block ("AppBuild" or "workshopitem"), or null. */
51
+ export declare function scriptKind(text: string): 'appbuild' | 'workshopitem' | null;
52
+ /** An app_build script's text with Preview on and/or a description (null when it is not an app_build script). */
53
+ export declare function withBuildSettings(text: string, o: {
54
+ readonly preview?: boolean;
55
+ readonly desc?: string;
56
+ }): string | null;
57
+ /** The script's text (bounded), or an error a person can act on. */
58
+ export declare function readScript(file: string): string;