windows-development-sandbox 1.23.2 → 1.25.1

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 (211) hide show
  1. package/config.example.json +5 -3
  2. package/dist/app/features/data/data.def.d.ts +4 -4
  3. package/dist/app/features/data/data.run.d.ts +1 -1
  4. package/dist/app/features/defs.d.ts +161 -6
  5. package/dist/app/features/defs.js +7 -0
  6. package/dist/app/features/projects/projects.def.d.ts +1 -1
  7. package/dist/app/features/projects/projects.run.d.ts +1 -1
  8. package/dist/app/features/unreal/index.d.ts +2 -0
  9. package/dist/app/features/unreal/index.js +3 -0
  10. package/dist/app/features/unreal/unreal.def.d.ts +236 -0
  11. package/dist/app/features/unreal/unreal.def.js +379 -0
  12. package/dist/app/features/unreal/unreal.run.d.ts +96 -0
  13. package/dist/app/features/unreal/unreal.run.js +217 -0
  14. package/dist/app/registry.js +5 -0
  15. package/dist/bin/agent-sandbox.js +2 -2
  16. package/dist/bin/{chunk-7YPEDAJD.js → chunk-3GAXLATK.js} +58 -5
  17. package/dist/bin/{chunk-USTRSHIE.js → chunk-F4PVBN23.js} +2615 -1515
  18. package/dist/bin/{chunk-QFSJX2KW.js → chunk-G3TG4ZT7.js} +1 -1
  19. package/dist/bin/claude-host.js +2 -2
  20. package/dist/bin/claude-sbx.js +2 -2
  21. package/dist/bin/codex-sbx.js +2 -2
  22. package/dist/bin/gemini-sbx.js +2 -2
  23. package/dist/bin/sandbox.js +2 -2
  24. package/dist/bin/sbx-hide.js +2 -2
  25. package/dist/bin/sbx-show.js +2 -2
  26. package/dist/cli/commands/launch/launch.js +5 -2
  27. package/dist/cli/commands/registry.js +3 -0
  28. package/dist/cli/manifest.d.ts +18 -0
  29. package/dist/cli/manifest.js +26 -0
  30. package/dist/cli/menu/coverage-exempt.js +1 -0
  31. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -0
  32. package/dist/cli/menu/pages/sandbox-page.js +34 -4
  33. package/dist/cli/menu/views.js +2 -0
  34. package/dist/core/config/defaults.js +18 -5
  35. package/dist/core/detect/toolchains.js +0 -6
  36. package/dist/core/schema/config.d.ts +10 -9
  37. package/dist/core/schema/pc-installs.d.ts +3 -1
  38. package/dist/core/schema/pc-installs.js +10 -1
  39. package/dist/core/schema/toolchains.d.ts +1 -2
  40. package/dist/core/schema/toolchains.js +4 -7
  41. package/dist/guest/accounts/kinds/epic.js +18 -13
  42. package/dist/guest/agents/agent-files.d.ts +11 -7
  43. package/dist/guest/agents/agent-files.js +37 -11
  44. package/dist/guest/agents/local-state.d.ts +2 -1
  45. package/dist/guest/agents/local-state.js +2 -1
  46. package/dist/guest/apps/after-install.d.ts +1 -1
  47. package/dist/guest/apps/after-install.js +6 -1
  48. package/dist/guest/apps/app-installer.d.ts +1 -0
  49. package/dist/guest/apps/app-installer.js +13 -3
  50. package/dist/guest/apps/comet-unpack.js +3 -2
  51. package/dist/guest/apps/resolvers-gamedev.js +55 -1
  52. package/dist/guest/boot/boot-console.d.ts +28 -0
  53. package/dist/guest/boot/boot-console.js +98 -0
  54. package/dist/guest/boot/boot.d.ts +8 -1
  55. package/dist/guest/boot/boot.js +80 -43
  56. package/dist/guest/boot/graph.d.ts +9 -5
  57. package/dist/guest/boot/graph.js +8 -2
  58. package/dist/guest/boot/guide.js +24 -0
  59. package/dist/guest/boot/progress-view.d.ts +116 -0
  60. package/dist/guest/boot/progress-view.js +456 -0
  61. package/dist/guest/boot/runner.d.ts +20 -10
  62. package/dist/guest/boot/runner.js +39 -47
  63. package/dist/guest/daemon/daemon.js +3 -0
  64. package/dist/guest/runtime/log-line.d.ts +7 -0
  65. package/dist/guest/runtime/log-line.js +18 -0
  66. package/dist/guest/runtime/log.d.ts +17 -4
  67. package/dist/guest/runtime/log.js +40 -17
  68. package/dist/guest/runtime/process.d.ts +9 -0
  69. package/dist/guest/runtime/process.js +69 -8
  70. package/dist/guest/setup/addon-mcp.d.ts +7 -0
  71. package/dist/guest/setup/addon-mcp.js +19 -4
  72. package/dist/guest/setup/browser-gpu.js +14 -11
  73. package/dist/guest/setup/environment.js +9 -4
  74. package/dist/guest/setup/headroom.js +4 -0
  75. package/dist/guest/setup/hooks.d.ts +2 -0
  76. package/dist/guest/setup/hooks.js +4 -0
  77. package/dist/guest/setup/path-plan.d.ts +12 -0
  78. package/dist/guest/setup/path-plan.js +18 -0
  79. package/dist/guest/toolchains/engines/epic-launcher.d.ts +26 -0
  80. package/dist/guest/toolchains/engines/epic-launcher.js +127 -0
  81. package/dist/guest/toolchains/engines/unreal-engines.d.ts +21 -1
  82. package/dist/guest/toolchains/engines/unreal-engines.js +163 -3
  83. package/dist/guest/toolchains/engines/unreal-status.d.ts +13 -0
  84. package/dist/guest/toolchains/engines/unreal-status.js +41 -0
  85. package/dist/guest/toolchains/native/debuggers.d.ts +6 -0
  86. package/dist/guest/toolchains/native/debuggers.js +57 -0
  87. package/dist/guest/toolchains/native/mesa.js +15 -8
  88. package/dist/guest/toolchains/native/rust-extras.d.ts +7 -0
  89. package/dist/guest/toolchains/native/rust-extras.js +23 -1
  90. package/dist/guest/toolchains/native/unreal.d.ts +2 -2
  91. package/dist/guest/toolchains/native/unreal.js +96 -20
  92. package/dist/guest/toolchains/native/visual-studio.d.ts +14 -14
  93. package/dist/guest/toolchains/native/visual-studio.js +145 -174
  94. package/dist/guest/toolchains/native/vs-persist.d.ts +189 -0
  95. package/dist/guest/toolchains/native/vs-persist.js +256 -0
  96. package/dist/guest/toolchains/native/vs-request.d.ts +6 -26
  97. package/dist/guest/toolchains/native/vs-request.js +16 -50
  98. package/dist/guest/toolchains/plan.js +23 -15
  99. package/dist/guest/toolchains/tools/vscode-profile.js +2 -0
  100. package/dist/host/accounts/kinds/epic.js +11 -5
  101. package/dist/host/accounts/source.d.ts +2 -0
  102. package/dist/host/accounts/source.js +1 -0
  103. package/dist/host/migrate/migrations/drop-vs-install-files.d.ts +5 -0
  104. package/dist/host/migrate/migrations/drop-vs-install-files.js +34 -0
  105. package/dist/host/migrate/registry.js +7 -1
  106. package/dist/host/pc-installs/discover.d.ts +2 -0
  107. package/dist/host/pc-installs/discover.js +25 -5
  108. package/dist/host/pc-installs/epic.d.ts +3 -0
  109. package/dist/host/pc-installs/epic.js +33 -2
  110. package/dist/host/pc-installs/source.d.ts +1 -1
  111. package/dist/host/pc-installs/unreal-vault.d.ts +11 -0
  112. package/dist/host/pc-installs/unreal-vault.js +78 -0
  113. package/dist/host/pc-installs/unreal.d.ts +36 -0
  114. package/dist/host/pc-installs/unreal.js +145 -2
  115. package/dist/host/profile/claude-profile.d.ts +8 -0
  116. package/dist/host/profile/claude-profile.js +43 -4
  117. package/dist/host/profile/index.d.ts +1 -1
  118. package/dist/host/profile/index.js +1 -1
  119. package/dist/runtime/agent.js +148 -33
  120. package/dist/runtime/daemon.js +3146 -1546
  121. package/dist/runtime/db.js +148 -33
  122. package/dist/runtime/main.js +3982 -2049
  123. package/dist/runtime/netproxy.js +84 -13
  124. package/dist/runtime/tool.js +125 -31
  125. package/dist/runtime/view.js +85 -14
  126. package/dist/selftest/agent-paths.test.js +18 -1
  127. package/dist/selftest/agent-settings.test.js +36 -5
  128. package/dist/selftest/agents-web.test.js +12 -0
  129. package/dist/selftest/boot-console.test.d.ts +2 -0
  130. package/dist/selftest/boot-console.test.js +291 -0
  131. package/dist/selftest/boot-runner.test.js +10 -12
  132. package/dist/selftest/engines.test.js +602 -3
  133. package/dist/selftest/guest-boot.test.js +7 -1
  134. package/dist/selftest/heavy-load.test.js +3 -1
  135. package/dist/selftest/hostile-input.test.js +11 -1
  136. package/dist/selftest/index.js +4 -0
  137. package/dist/selftest/layout.test.js +4 -0
  138. package/dist/selftest/menu-screens.js +3 -1
  139. package/dist/selftest/migrate.test.js +21 -0
  140. package/dist/selftest/mixamo.test.d.ts +2 -0
  141. package/dist/selftest/mixamo.test.js +60 -0
  142. package/dist/selftest/persisted-installs.test.js +169 -33
  143. package/dist/selftest/secrets.test.js +36 -1
  144. package/dist/selftest/support/engine-golden.js +5 -0
  145. package/dist/selftest/support/fixtures.d.ts +4 -3
  146. package/dist/selftest/support/unreal-sample.d.ts +2 -0
  147. package/dist/selftest/support/unreal-sample.js +83 -0
  148. package/dist/selftest/toolchains.test.js +32 -2
  149. package/dist/shared/accounts/index.d.ts +1 -1
  150. package/dist/shared/accounts/index.js +1 -1
  151. package/dist/shared/accounts/kinds/epic.d.ts +6 -1
  152. package/dist/shared/accounts/kinds/epic.js +11 -1
  153. package/dist/shared/apps/associations.d.ts +7 -0
  154. package/dist/shared/apps/associations.js +26 -0
  155. package/dist/shared/apps/catalogue-agents-web.d.ts +4 -1
  156. package/dist/shared/apps/catalogue-agents-web.js +5 -2
  157. package/dist/shared/apps/catalogue-gamedev.js +71 -1
  158. package/dist/shared/apps/index.d.ts +2 -0
  159. package/dist/shared/apps/index.js +2 -0
  160. package/dist/shared/apps/preview.d.ts +2 -0
  161. package/dist/shared/apps/preview.js +10 -0
  162. package/dist/shared/browser-policy.d.ts +14 -0
  163. package/dist/shared/browser-policy.js +22 -0
  164. package/dist/shared/channel/schema.d.ts +3 -6
  165. package/dist/shared/io/index.d.ts +1 -0
  166. package/dist/shared/io/index.js +1 -0
  167. package/dist/shared/io/rotate-log.d.ts +2 -0
  168. package/dist/shared/io/rotate-log.js +16 -0
  169. package/dist/shared/memory/policy.d.ts +5 -0
  170. package/dist/shared/memory/policy.js +7 -0
  171. package/dist/shared/paths/pc-installs.d.ts +13 -2
  172. package/dist/shared/paths/pc-installs.js +1 -0
  173. package/dist/shared/pty/terminal.js +2 -1
  174. package/dist/shared/readiness.d.ts +0 -1
  175. package/dist/shared/readiness.js +0 -1
  176. package/dist/shared/signer.d.ts +4 -0
  177. package/dist/shared/signer.js +2 -0
  178. package/dist/shared/unreal/engines.d.ts +161 -0
  179. package/dist/shared/unreal/engines.js +308 -0
  180. package/dist/shared/unreal/guide.d.ts +19 -0
  181. package/dist/shared/unreal/guide.js +105 -0
  182. package/dist/shared/unreal/index.d.ts +7 -0
  183. package/dist/shared/unreal/index.js +8 -0
  184. package/dist/shared/unreal/launcher-files.d.ts +88 -0
  185. package/dist/shared/unreal/launcher-files.js +292 -0
  186. package/dist/shared/unreal/mixamo.d.ts +5 -0
  187. package/dist/shared/unreal/mixamo.js +16 -0
  188. package/dist/shared/unreal/room.d.ts +17 -0
  189. package/dist/shared/unreal/room.js +34 -0
  190. package/dist/shared/unreal/status.d.ts +54 -0
  191. package/dist/shared/unreal/status.js +57 -0
  192. package/dist/shared/unreal/vault.d.ts +21 -0
  193. package/dist/shared/unreal/vault.js +67 -0
  194. package/dist/shared/unreal/vs-check.d.ts +39 -0
  195. package/dist/shared/unreal/vs-check.js +79 -0
  196. package/dist/sync/watcher.js +5 -1
  197. package/dist/web/index.html +1 -1
  198. package/dist/web/{main-CCILLX2M.js → main-FNE6XEHA.js} +84 -84
  199. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  200. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  201. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  202. package/package.json +1 -1
  203. package/sandbox/csharp/VsSetup.cs +210 -0
  204. package/sandbox/scripts/get-vs-setup.ps1 +93 -0
  205. package/sandbox/scripts/restore-visual-studio.ps1 +78 -0
  206. package/sandbox/scripts/save-visual-studio.ps1 +106 -0
  207. package/sandbox/scripts/set-registry-values.ps1 +35 -0
  208. package/schemas/config.schema.json +38 -9
  209. package/schemas/sandbox-config.schema.json +11 -8
  210. package/dist/guest/toolchains/native/autosdk.d.ts +0 -3
  211. package/dist/guest/toolchains/native/autosdk.js +0 -50
@@ -0,0 +1,217 @@
1
+ // The Unreal area's work: what the sandbox last found (tools\unreal\status.json, written by the guest, so it is read
2
+ // with its schema and its text made safe), what this PC has that the next sandbox maps (its engines, the folders you
3
+ // registered, the launcher's vault cache: bounded reads), registering an engine folder (pcInstalls.unrealEngineFolders)
4
+ // and opening the Epic Games Launcher in the running sandbox (an exec request).
5
+ import path from 'node:path';
6
+ import { humanBytes } from '../../../core/disk.js';
7
+ import { assertNoLinks, errMsg, fail, safeText } from '../../../core/util/index.js';
8
+ import { requireOnPc } from '../../../cli/commands/context.js';
9
+ import { SandboxChannel } from '../../../host/channel/index.js';
10
+ import { isSandboxRunning } from '../../../host/sandbox/index.js';
11
+ import { pcEnv } from '../../../host/accounts/index.js';
12
+ import { findEngineFolders, findUnrealInstalls, pcSourceBuilds, unrealPcFiles, } from '../../../host/pc-installs/unreal.js';
13
+ import { PC_VAULT_FS, vaultDirs } from '../../../host/pc-installs/unreal-vault.js';
14
+ import { readBoundedFile, readValid } from '../../../shared/io/index.js';
15
+ import { RunDir } from '../../../shared/channel/index.js';
16
+ import { ORIGIN_LABELS, parseBuildVersion, UNREAL_STATUS_FILE, UnrealStatusSchema, vaultPacks, versionText, } from '../../../shared/unreal/index.js';
17
+ import { implement } from '../../context.js';
18
+ import { ConfigFile } from '../settings/index.js';
19
+ import { forgetEngineFolder, openEpicLauncher, registerEngineFolder, unrealOverview, } from './unreal.def.js';
20
+ const win = path.win32;
21
+ /** The launcher the sandbox installs (the 64-bit one of launcher 17 and later). */
22
+ const GUEST_LAUNCHER = 'C:\\Program Files (x86)\\Epic Games\\Launcher\\Portal\\Binaries\\Win64\\EpicGamesLauncher.exe';
23
+ const MAX_PACKS_SHOWN = 40;
24
+ const s = (text) => safeText(text);
25
+ const sn = (text) => (text === null ? null : safeText(text));
26
+ export function readStatus(dataPath) {
27
+ const file = path.join(dataPath, 'tools', 'unreal', UNREAL_STATUS_FILE);
28
+ try {
29
+ assertNoLinks(dataPath, file);
30
+ }
31
+ catch {
32
+ return null; // A link under the data folder: never followed.
33
+ }
34
+ return readValid(UnrealStatusSchema, file);
35
+ }
36
+ const settingText = (v) => (Array.isArray(v) ? v.join(', ') || 'none' : String(v));
37
+ /** The overview from the sandbox's status and this PC's own look (no sandbox needed). */
38
+ export function unrealOverviewOf(ctx, status, pcLook) {
39
+ const config = ctx.loaded.config;
40
+ let pc = { engines: [], vault: [] };
41
+ let problem = null;
42
+ try {
43
+ pc = pcLook();
44
+ }
45
+ catch (e) {
46
+ problem = 'Could not look at this PC: ' + errMsg(e);
47
+ }
48
+ const projects = (status?.projects ?? []).map((p) => ({
49
+ project: s(win.basename(p.workspace)),
50
+ engine: p.engine === null ? null : s(status?.engines.find((e) => e.dir === p.engine)?.id ?? p.engine),
51
+ reason: s(p.reason),
52
+ }));
53
+ return {
54
+ setUp: status !== null,
55
+ checkedAt: status ? s(status.updatedAt) : null,
56
+ engines: (status?.engines ?? []).map((e) => ({
57
+ id: s(e.id),
58
+ version: s(e.version),
59
+ dir: s(e.dir),
60
+ where: ORIGIN_LABELS[e.origin],
61
+ writable: e.writable,
62
+ build: e.build,
63
+ sizeBytes: e.sizeBytes,
64
+ projects: (status?.projects ?? [])
65
+ .filter((p) => p.engine?.toLowerCase() === e.dir.toLowerCase())
66
+ .map((p) => s(win.basename(p.workspace))),
67
+ })),
68
+ projects,
69
+ launcher: {
70
+ installed: status?.launcher.installed ?? false,
71
+ installLocation: sn(status?.launcher.installLocation ?? null),
72
+ problem: sn(status?.launcher.problem ?? null),
73
+ free: status?.launcher.freeBytes ? humanBytes(status.launcher.freeBytes) : null,
74
+ },
75
+ visualStudio: {
76
+ version: s(status?.visualStudio.version ?? ''),
77
+ path: s(status?.visualStudio.path ?? ''),
78
+ how: s(status?.visualStudio.how ?? ''),
79
+ check: s(status?.visualStudio.check ?? ''),
80
+ ok: status?.visualStudio.ok ?? false,
81
+ },
82
+ debugger: sn(status?.debugger ?? null),
83
+ ddc: sn(status?.ddc.dir ?? null),
84
+ mcpUrl: sn(status?.mcpUrl ?? null),
85
+ pc: { setting: settingText(config.pcInstalls.unrealEngines), engines: pc.engines, problem },
86
+ vault: { setting: settingText(config.pcInstalls.unrealAssets), folders: pc.vault },
87
+ settings: {
88
+ enabled: settingText(config.toolchains.unreal.enabled),
89
+ acceptLicense: config.toolchains.unreal.acceptLicense,
90
+ persistEngines: config.toolchains.unreal.persistEngines,
91
+ derivedDataCache: config.toolchains.unreal.derivedDataCache,
92
+ visualStudio: config.toolchains.unreal.visualStudio,
93
+ },
94
+ };
95
+ }
96
+ /** What this PC has for the next sandbox: its engines, the registered folders, its vault packs. */
97
+ function lookAtPc(ctx) {
98
+ const config = ctx.loaded.config.pcInstalls;
99
+ const pc = pcEnv();
100
+ const files = unrealPcFiles(pc);
101
+ const folders = findEngineFolders(files, config.unrealEngineFolders);
102
+ const installs = config.unrealEngines === false
103
+ ? []
104
+ : findUnrealInstalls(files, Array.isArray(config.unrealEngines) ? config.unrealEngines : true);
105
+ const engines = [
106
+ ...folders,
107
+ ...installs.filter((i) => !folders.some((f) => f.host.toLowerCase() === i.host.toLowerCase())),
108
+ ].map((e) => ({
109
+ id: e.id,
110
+ name: e.name,
111
+ folder: e.host,
112
+ writable: e.writable === true,
113
+ source: false,
114
+ }));
115
+ const loose = pcSourceBuilds(files)
116
+ .filter((b) => !folders.some((f) => f.host.toLowerCase() === b.host.toLowerCase()))
117
+ .map((b) => ({
118
+ id: '',
119
+ name: 'Unreal Engine ' + b.version + ' (source build)',
120
+ folder: b.host,
121
+ writable: false,
122
+ source: true,
123
+ }));
124
+ const vault = config.unrealAssets === false
125
+ ? []
126
+ : vaultDirs(pc, PC_VAULT_FS.isDir).map((folder) => {
127
+ const packs = vaultPacks(folder, PC_VAULT_FS);
128
+ return {
129
+ folder,
130
+ packs: packs.slice(0, MAX_PACKS_SHOWN).map((p) => ({
131
+ name: p.name,
132
+ size: (p.partial ? 'at least ' : '') + humanBytes(p.sizeBytes),
133
+ kind: p.kind,
134
+ })),
135
+ more: Math.max(0, packs.length - MAX_PACKS_SHOWN),
136
+ };
137
+ });
138
+ return { engines: [...engines, ...loose], vault };
139
+ }
140
+ export const unrealOverviewRun = implement(unrealOverview, (ctx) => unrealOverviewOf(ctx, readStatus(ctx.dataPath), () => lookAtPc(ctx)));
141
+ /** The engine in a folder of this PC, or a failure that says what is wrong. */
142
+ export function engineFolderProblem(folder, read) {
143
+ if (!win.isAbsolute(folder))
144
+ return 'Give the full path of the engine folder (e.g. D:\\UnrealEngine).';
145
+ const bytes = read(win.join(folder, 'Engine', 'Build', 'Build.version'), 64 * 1024);
146
+ if (!bytes)
147
+ return 'No Engine\\Build\\Build.version in ' + folder + ': that is not an Unreal Engine folder.';
148
+ return parseBuildVersion(bytes.toString('utf8')) ? null : folder + '\\Engine\\Build\\Build.version is not readable.';
149
+ }
150
+ export const registerEngineFolderRun = implement(registerEngineFolder, async (ctx, input, io) => {
151
+ requireOnPc('unreal add-engine');
152
+ const folder = input.folder ??
153
+ (await io.path({
154
+ title: 'Which Unreal Engine folder?',
155
+ lines: [
156
+ 'The folder that holds Engine\\Build\\Build.version (a source build, or a copy of an engine).',
157
+ 'The next sandbox maps it writable and registers it.',
158
+ ],
159
+ pathKind: 'dir',
160
+ validate: (v) => engineFolderProblem(win.resolve(v), readBoundedFile) ?? true,
161
+ }));
162
+ if (!folder)
163
+ fail('No folder given.', 'Nothing was changed.');
164
+ const dir = win.resolve(folder);
165
+ const problem = engineFolderProblem(dir, readBoundedFile);
166
+ if (problem)
167
+ fail(problem, 'Pick the folder that has Engine\\Build\\Build.version in it.');
168
+ const file = ConfigFile.user(ctx.loaded.configPath);
169
+ const now = file.userConfig().pcInstalls.unrealEngineFolders;
170
+ if (now.some((f) => win.resolve(f).toLowerCase() === dir.toLowerCase()))
171
+ return { message: dir + ' is registered already.' };
172
+ if (now.length >= 8)
173
+ fail('8 engine folders are registered already.', 'Forget one first.');
174
+ const outcome = file.set(['pcInstalls', 'unrealEngineFolders'], [...now, dir]);
175
+ if (typeof outcome === 'object')
176
+ fail('Could not save the folder: ' + outcome.problems.join('; '));
177
+ const v = parseBuildVersion(readBoundedFile(win.join(dir, 'Engine', 'Build', 'Build.version'), 64 * 1024).toString('utf8'));
178
+ return {
179
+ message: 'Registered Unreal Engine ' +
180
+ versionText(v) +
181
+ ' at ' +
182
+ dir +
183
+ '. The next sandbox maps it writable and registers it' +
184
+ (isSandboxRunning() ? ' (restart the sandbox to get it now).' : '.'),
185
+ };
186
+ });
187
+ export const forgetEngineFolderRun = implement(forgetEngineFolder, (ctx, input) => {
188
+ requireOnPc('unreal forget-engine');
189
+ const file = ConfigFile.user(ctx.loaded.configPath);
190
+ const now = file.userConfig().pcInstalls.unrealEngineFolders;
191
+ const dir = win.resolve(input.folder).toLowerCase();
192
+ const left = now.filter((f) => win.resolve(f).toLowerCase() !== dir);
193
+ if (left.length === now.length)
194
+ return { message: input.folder + ' was not registered.' };
195
+ const outcome = file.set(['pcInstalls', 'unrealEngineFolders'], left);
196
+ if (typeof outcome === 'object')
197
+ fail('Could not save: ' + outcome.problems.join('; '));
198
+ return { message: 'Forgot ' + input.folder + '; the next sandbox does not map it (nothing on this PC was deleted).' };
199
+ });
200
+ export const openEpicLauncherRun = implement(openEpicLauncher, async (ctx, _input, io) => {
201
+ requireOnPc('unreal launcher');
202
+ if (!isSandboxRunning())
203
+ fail('No sandbox is running.', 'Start one for a project with a .uproject; the launcher opens in its window.');
204
+ const status = new RunDir(ctx.dataPath).readSandboxStatus();
205
+ if (status?.phase !== 'ready')
206
+ fail('The sandbox is not ready yet.', 'Try again in a moment.');
207
+ if (!readStatus(ctx.dataPath)?.launcher.installed)
208
+ fail('The Epic Games Launcher is not installed in this sandbox.', 'It is installed when the sandbox is set up for Unreal with the licence accepted (Unreal set-up settings).');
209
+ io.progress('Opening the Epic Games Launcher in the sandbox…');
210
+ const result = await new SandboxChannel(ctx.dataPath).exec(['C:\\Windows\\explorer.exe', GUEST_LAUNCHER], status.guestWorkspace ?? 'C:\\', 30);
211
+ // explorer.exe returns 1 even when it started the program.
212
+ if (!result.ok && result.exitCode !== 1)
213
+ fail('The sandbox could not open it: ' + safeText(result.message));
214
+ return {
215
+ message: 'The Epic Games Launcher opens in the sandbox window. Sign in once; engines install to the data disk.',
216
+ };
217
+ });
@@ -20,6 +20,7 @@ import { agentCommandsOffRun, agentCommandsOnRun, agentCommandsStatusRun } from
20
20
  import { vpnLoginRun, vpnLogoutRun, vpnStatusRun } from './features/vpn/index.js';
21
21
  import { githubLoginRun, githubLogoutRun, githubStatusRun } from './features/github/index.js';
22
22
  import { accessStatusRun, allowDeviceRun, lanOffRun, lanOnRun, revokeAccessRun, revokeAllAccessRun, } from './features/access/index.js';
23
+ import { forgetEngineFolderRun, openEpicLauncherRun, registerEngineFolderRun, unrealOverviewRun, } from './features/unreal/index.js';
23
24
  export const IMPLEMENTATIONS = [
24
25
  sandboxStatusRun,
25
26
  showWindowRun,
@@ -109,6 +110,10 @@ export const IMPLEMENTATIONS = [
109
110
  revokeAllAccessRun,
110
111
  lanOnRun,
111
112
  lanOffRun,
113
+ unrealOverviewRun,
114
+ registerEngineFolderRun,
115
+ forgetEngineFolderRun,
116
+ openEpicLauncherRun,
112
117
  ];
113
118
  export function implementationOf(id) {
114
119
  return IMPLEMENTATIONS.find((i) => i.def.id === id);
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7YPEDAJD.js";
6
- import "./chunk-USTRSHIE.js";
5
+ } from "./chunk-3GAXLATK.js";
6
+ import "./chunk-F4PVBN23.js";
7
7
 
8
8
  // src/bin/agent-sandbox.ts
9
9
  run(process.argv.slice(2));
@@ -223,6 +223,9 @@ import {
223
223
  takeHiddenInstallNotice,
224
224
  toWireError,
225
225
  trustStorePath,
226
+ unrealOverview,
227
+ unrealPage,
228
+ unrealView,
226
229
  updatesPage,
227
230
  updatesStatus,
228
231
  updatesView,
@@ -251,7 +254,7 @@ import {
251
254
  withOperationCommands,
252
255
  working,
253
256
  writeJson
254
- } from "./chunk-USTRSHIE.js";
257
+ } from "./chunk-F4PVBN23.js";
255
258
 
256
259
  // node_modules/commander/lib/error.js
257
260
  var require_error = __commonJS({
@@ -4066,6 +4069,32 @@ var COMMAND_LIST = [
4066
4069
  ],
4067
4070
  json
4068
4071
  },
4072
+ {
4073
+ name: "unreal",
4074
+ summary: "Unreal Engine: the sandbox's engines, this PC's engines and assets, register an engine folder, open the launcher",
4075
+ group: "Projects & accounts",
4076
+ json,
4077
+ examples: [
4078
+ "sandbox unreal engines, which project uses which, Visual Studio",
4079
+ "sandbox unreal add-engine D:\\UE5 use this engine folder in sandboxes (writable)",
4080
+ "sandbox unreal launcher open the Epic Games Launcher in the running sandbox"
4081
+ ],
4082
+ args: [
4083
+ {
4084
+ name: "action",
4085
+ description: "status, add-engine, forget-engine, launcher",
4086
+ required: false,
4087
+ choices: ["status"]
4088
+ },
4089
+ {
4090
+ name: "folder",
4091
+ description: "(add-engine, forget-engine) the engine folder",
4092
+ required: false,
4093
+ when: []
4094
+ }
4095
+ ],
4096
+ options: []
4097
+ },
4069
4098
  {
4070
4099
  name: "engine",
4071
4100
  summary: "(beta) what runs your sandbox (Windows Sandbox or HCS) and what each engine can do on this PC",
@@ -6738,6 +6767,7 @@ var MENU_VIEWS = [
6738
6767
  { view: accountsView, section: "Accounts" },
6739
6768
  { view: appsView, section: "Apps" },
6740
6769
  { view: projectsView, section: "Sandbox" },
6770
+ { view: unrealView, section: "Sandbox" },
6741
6771
  { view: healthView, section: "Maintenance" },
6742
6772
  { view: dataView, section: "Maintenance" },
6743
6773
  { view: storageView, section: "Maintenance" },
@@ -8614,8 +8644,16 @@ var CATEGORIES3 = [
8614
8644
  label: "Projects",
8615
8645
  description: "Project roots (folders of projects, opened without a restart) and the projects started before."
8616
8646
  },
8617
- { id: "databases", label: "Databases", description: "Databases the sandbox can run: start and stop them." }
8647
+ { id: "databases", label: "Databases", description: "Databases the sandbox can run: start and stop them." },
8648
+ {
8649
+ id: "unreal",
8650
+ label: "Unreal Engine",
8651
+ description: "Engines, which project uses which, this PC's engines and assets, Visual Studio and the debugger."
8652
+ }
8618
8653
  ];
8654
+ function unrealMenu(m) {
8655
+ return m.unreal ? menuView(unrealPage(m.unreal), { category: "unreal", prefix: "unreal:", refresh: false }) : void 0;
8656
+ }
8619
8657
  function statusView(m) {
8620
8658
  return menuView(sandboxPage(m.report), { category: "status", prefix: "status:", refresh: false });
8621
8659
  }
@@ -8624,6 +8662,7 @@ function projectsView2(m) {
8624
8662
  }
8625
8663
  function viewFor(m, category) {
8626
8664
  if (category === "projects") return projectsView2(m);
8665
+ if (category === "unreal") return unrealMenu(m);
8627
8666
  if (category === "status" || category === void 0) return statusView(m);
8628
8667
  return void 0;
8629
8668
  }
@@ -8650,12 +8689,23 @@ function sandboxOptions(m) {
8650
8689
  section: "Databases",
8651
8690
  description: d.title + ". Enter " + (d.running ? "stops" : "starts") + " it (the first start downloads it)."
8652
8691
  }));
8692
+ const unreal = unrealMenu(m);
8693
+ const noUnreal = unreal ? [] : [
8694
+ {
8695
+ value: "info:unreal",
8696
+ label: "Could not read the Unreal set-up",
8697
+ category: "unreal",
8698
+ section: "Unreal Engine",
8699
+ description: "l looks again.",
8700
+ disabled: "l looks again."
8701
+ }
8702
+ ];
8653
8703
  return {
8654
8704
  path: [],
8655
- items: [...statusItems, ...projects.items, ...databases, ...noDatabases],
8705
+ items: [...statusItems, ...projects.items, ...databases, ...noDatabases, ...unreal?.items ?? [], ...noUnreal],
8656
8706
  categories: CATEGORIES3,
8657
8707
  empty: "Nothing here yet.",
8658
- actions: (category) => category === "projects" ? [...projects.actions, REFRESH] : category === "databases" ? [REFRESH] : [...status.actions, REFRESH],
8708
+ actions: (category) => category === "projects" ? [...projects.actions, REFRESH] : category === "databases" ? [REFRESH] : category === "unreal" ? [...unreal?.actions ?? [], REFRESH] : [...status.actions, REFRESH],
8659
8709
  enterLabel: (category, id) => viewFor(m, category)?.enterLabel(category, id) || enterLabel2(id ?? "", m)
8660
8710
  };
8661
8711
  }
@@ -8708,7 +8758,8 @@ var SandboxPage = class extends ListPage {
8708
8758
  report: report2,
8709
8759
  projects: await readQuery(listProjects, this.ctx),
8710
8760
  databases,
8711
- defaultAgent: this.defaultAgent()
8761
+ defaultAgent: this.defaultAgent(),
8762
+ unreal: await readQuery(unrealOverview, this.ctx).catch(() => null)
8712
8763
  };
8713
8764
  }
8714
8765
  /** The folder `sbx-db` runs in: the sandbox's own workspace. */
@@ -10478,6 +10529,8 @@ var HANDLERS = {
10478
10529
  );
10479
10530
  },
10480
10531
  engine,
10532
+ // The bare command shows the overview; its actions (add-engine, forget-engine, launcher) are the operations' hints.
10533
+ unreal: definitionHandler(unrealOverview),
10481
10534
  "host-claude": claudeHost,
10482
10535
  host: hostCommand,
10483
10536
  _watch: watcher,