windows-development-sandbox 1.23.2 → 1.25.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 (85) hide show
  1. package/config.example.json +0 -1
  2. package/dist/bin/agent-sandbox.js +2 -2
  3. package/dist/bin/{chunk-USTRSHIE.js → chunk-IZRGTSQ5.js} +158 -131
  4. package/dist/bin/{chunk-QFSJX2KW.js → chunk-KH4MI2U5.js} +1 -1
  5. package/dist/bin/{chunk-7YPEDAJD.js → chunk-SUYYVIDW.js} +1 -1
  6. package/dist/bin/claude-host.js +2 -2
  7. package/dist/bin/claude-sbx.js +2 -2
  8. package/dist/bin/codex-sbx.js +2 -2
  9. package/dist/bin/gemini-sbx.js +2 -2
  10. package/dist/bin/sandbox.js +2 -2
  11. package/dist/bin/sbx-hide.js +2 -2
  12. package/dist/bin/sbx-show.js +2 -2
  13. package/dist/core/config/defaults.js +0 -1
  14. package/dist/core/detect/toolchains.js +0 -6
  15. package/dist/core/schema/config.d.ts +1 -2
  16. package/dist/core/schema/toolchains.d.ts +1 -2
  17. package/dist/core/schema/toolchains.js +3 -6
  18. package/dist/guest/agents/agent-files.d.ts +11 -7
  19. package/dist/guest/agents/agent-files.js +37 -11
  20. package/dist/guest/agents/local-state.d.ts +2 -1
  21. package/dist/guest/agents/local-state.js +2 -1
  22. package/dist/guest/boot/boot-console.d.ts +28 -0
  23. package/dist/guest/boot/boot-console.js +98 -0
  24. package/dist/guest/boot/boot.d.ts +8 -1
  25. package/dist/guest/boot/boot.js +66 -42
  26. package/dist/guest/boot/graph.d.ts +9 -5
  27. package/dist/guest/boot/graph.js +8 -2
  28. package/dist/guest/boot/progress-view.d.ts +116 -0
  29. package/dist/guest/boot/progress-view.js +456 -0
  30. package/dist/guest/boot/runner.d.ts +20 -10
  31. package/dist/guest/boot/runner.js +39 -47
  32. package/dist/guest/runtime/log-line.d.ts +7 -0
  33. package/dist/guest/runtime/log-line.js +18 -0
  34. package/dist/guest/runtime/log.d.ts +17 -4
  35. package/dist/guest/runtime/log.js +40 -17
  36. package/dist/guest/runtime/process.d.ts +9 -0
  37. package/dist/guest/runtime/process.js +69 -8
  38. package/dist/guest/setup/environment.js +9 -4
  39. package/dist/guest/setup/hooks.d.ts +2 -0
  40. package/dist/guest/setup/hooks.js +4 -0
  41. package/dist/guest/setup/path-plan.d.ts +12 -0
  42. package/dist/guest/setup/path-plan.js +18 -0
  43. package/dist/guest/toolchains/native/unreal.js +4 -6
  44. package/dist/guest/toolchains/native/visual-studio.d.ts +14 -14
  45. package/dist/guest/toolchains/native/visual-studio.js +145 -174
  46. package/dist/guest/toolchains/native/vs-persist.d.ts +189 -0
  47. package/dist/guest/toolchains/native/vs-persist.js +256 -0
  48. package/dist/guest/toolchains/native/vs-request.d.ts +6 -26
  49. package/dist/guest/toolchains/native/vs-request.js +16 -50
  50. package/dist/guest/toolchains/plan.js +11 -14
  51. package/dist/host/migrate/migrations/drop-vs-install-files.d.ts +5 -0
  52. package/dist/host/migrate/migrations/drop-vs-install-files.js +34 -0
  53. package/dist/host/migrate/registry.js +7 -1
  54. package/dist/runtime/agent.js +67 -26
  55. package/dist/runtime/daemon.js +958 -716
  56. package/dist/runtime/db.js +67 -26
  57. package/dist/runtime/main.js +1792 -1038
  58. package/dist/runtime/netproxy.js +3 -6
  59. package/dist/runtime/tool.js +44 -24
  60. package/dist/runtime/view.js +4 -7
  61. package/dist/selftest/agent-paths.test.js +17 -1
  62. package/dist/selftest/agent-settings.test.js +36 -5
  63. package/dist/selftest/boot-console.test.d.ts +2 -0
  64. package/dist/selftest/boot-console.test.js +291 -0
  65. package/dist/selftest/boot-runner.test.js +10 -12
  66. package/dist/selftest/guest-boot.test.js +7 -1
  67. package/dist/selftest/index.js +2 -0
  68. package/dist/selftest/layout.test.js +4 -0
  69. package/dist/selftest/migrate.test.js +21 -0
  70. package/dist/selftest/persisted-installs.test.js +169 -33
  71. package/dist/selftest/support/engine-golden.js +2 -0
  72. package/dist/selftest/support/fixtures.d.ts +1 -2
  73. package/dist/shared/channel/schema.d.ts +3 -6
  74. package/dist/shared/pty/terminal.js +2 -1
  75. package/dist/sync/watcher.js +5 -1
  76. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  77. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  78. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  79. package/package.json +1 -1
  80. package/sandbox/scripts/restore-visual-studio.ps1 +78 -0
  81. package/sandbox/scripts/save-visual-studio.ps1 +106 -0
  82. package/schemas/config.schema.json +3 -7
  83. package/schemas/sandbox-config.schema.json +3 -7
  84. package/dist/guest/toolchains/native/autosdk.d.ts +0 -3
  85. package/dist/guest/toolchains/native/autosdk.js +0 -50
@@ -0,0 +1,106 @@
1
+ #Requires -Version 5.1
2
+ # Saves a finished Visual Studio install onto the data disk, once (guest/toolchains/native/visual-studio.ts; what goes
3
+ # where is decided in vs-persist.ts). -PlanFile is JSON written by the runtime:
4
+ # copies: [{ name, from, to, optional }] each mirrored with robocopy (/MIR); a missing optional one is skipped
5
+ # registry: [{ view: '64'|'32', key, names: [..] | null, recurse }] string and DWORD values read under HKLM
6
+ # resultFile: where the result goes, as JSON: { copied: [names], registry: [{ view, key, name, kind, value }] }
7
+ # -LowPriority runs it (and robocopy) below normal priority. Safe to run again: robocopy copies only what differs.
8
+ # Exit 0 when every copy worked, 1 when one failed (no result file then), 2 for a bad plan.
9
+ param(
10
+ [Parameter(Mandatory = $true)][string]$PlanFile,
11
+ [switch]$LowPriority
12
+ )
13
+ $ErrorActionPreference = 'Stop'
14
+
15
+ if ($LowPriority) {
16
+ try {
17
+ [System.Diagnostics.Process]::GetCurrentProcess().PriorityClass = [System.Diagnostics.ProcessPriorityClass]::BelowNormal
18
+ } catch {
19
+ # Normal priority only makes the copy compete a little more with the sessions.
20
+ }
21
+ }
22
+
23
+ $plan = Get-Content -LiteralPath $PlanFile -Raw -Encoding UTF8 | ConvertFrom-Json
24
+ if (-not $plan.resultFile -or -not $plan.copies) {
25
+ Write-Error 'save-visual-studio: the plan has no copies or no result file'
26
+ exit 2
27
+ }
28
+ $robocopy = Join-Path $env:SystemRoot 'System32\Robocopy.exe'
29
+
30
+ function Copy-Folder([string]$From, [string]$To) {
31
+ New-Item -ItemType Directory -Force -Path $To | Out-Null
32
+ # /MIR drops files a previous capture left; /XJ skips links (the data disk refuses them); /A-:R keeps read-only
33
+ # files rewritable by the next capture.
34
+ & $robocopy $From $To /MIR /COPY:DAT /XJ /A-:R /R:1 /W:1 /MT:16 /NP /NFL /NDL /NJH /NJS | Where-Object { $_ -and $_.Trim() } | Out-Host
35
+ return $LASTEXITCODE
36
+ }
37
+
38
+ $copied = New-Object System.Collections.ArrayList
39
+ $failed = New-Object System.Collections.ArrayList
40
+ foreach ($copy in @($plan.copies)) {
41
+ if (-not (Test-Path -LiteralPath $copy.from -PathType Container)) {
42
+ if ($copy.optional) { continue }
43
+ [void]$failed.Add($copy.name + ' (' + $copy.from + ' is missing)')
44
+ continue
45
+ }
46
+ $code = Copy-Folder -From $copy.from -To $copy.to
47
+ if ($code -ge 8) { [void]$failed.Add($copy.name + ' (robocopy ' + $code + ')') } else { [void]$copied.Add([string]$copy.name) }
48
+ }
49
+ if ($failed.Count) {
50
+ Write-Error ('save-visual-studio: could not save ' + ($failed -join ', '))
51
+ exit 1
52
+ }
53
+
54
+ function Get-View([string]$View) {
55
+ if ($View -eq '32') { return [Microsoft.Win32.RegistryView]::Registry32 }
56
+ return [Microsoft.Win32.RegistryView]::Registry64
57
+ }
58
+
59
+ function Read-Values([Microsoft.Win32.RegistryKey]$Key, [string]$Path, [string]$View, $Names, [bool]$Recurse, $Out) {
60
+ $options = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames
61
+ foreach ($name in $Key.GetValueNames()) {
62
+ if ($null -ne $Names -and -not ($Names -contains $name)) { continue }
63
+ $kind = $Key.GetValueKind($name)
64
+ $value = $Key.GetValue($name, $null, $options)
65
+ $label = $null
66
+ if ($kind -eq [Microsoft.Win32.RegistryValueKind]::String) { $label = 'string' }
67
+ elseif ($kind -eq [Microsoft.Win32.RegistryValueKind]::ExpandString) { $label = 'expand' }
68
+ elseif ($kind -eq [Microsoft.Win32.RegistryValueKind]::DWord) { $label = 'dword'; $value = [int]$value }
69
+ if ($null -eq $label -or $null -eq $value) { continue }
70
+ [void]$Out.Add([ordered]@{ view = $View; key = $Path; name = $name; kind = $label; value = $value })
71
+ }
72
+ if (-not $Recurse) { return }
73
+ foreach ($sub in $Key.GetSubKeyNames()) {
74
+ $child = $Key.OpenSubKey($sub)
75
+ if ($null -eq $child) { continue }
76
+ try {
77
+ Read-Values -Key $child -Path ($Path + '\' + $sub) -View $View -Names $Names -Recurse $true -Out $Out
78
+ } finally {
79
+ $child.Close()
80
+ }
81
+ }
82
+ }
83
+
84
+ $values = New-Object System.Collections.ArrayList
85
+ foreach ($read in @($plan.registry)) {
86
+ $base = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, (Get-View $read.view))
87
+ try {
88
+ $key = $base.OpenSubKey([string]$read.key)
89
+ if ($null -eq $key) { continue }
90
+ try {
91
+ $names = $null
92
+ if ($null -ne $read.names) { $names = @($read.names) }
93
+ Read-Values -Key $key -Path ([string]$read.key) -View ([string]$read.view) -Names $names -Recurse ([bool]$read.recurse) -Out $values
94
+ } finally {
95
+ $key.Close()
96
+ }
97
+ } finally {
98
+ $base.Close()
99
+ }
100
+ }
101
+
102
+ $result = [ordered]@{ copied = @($copied.ToArray()); registry = @($values.ToArray()) }
103
+ $json = ConvertTo-Json -InputObject $result -Depth 6
104
+ [System.IO.File]::WriteAllText($plan.resultFile, $json, (New-Object System.Text.UTF8Encoding $false))
105
+ Write-Output ('Saved Visual Studio: ' + $copied.Count + ' folders, ' + $values.Count + ' registry values')
106
+ exit 0
@@ -864,7 +864,7 @@
864
864
  "const": "auto"
865
865
  }
866
866
  ],
867
- "description": "Unreal Engine development: Visual Studio Community 2022 with the C++ game workload (MSVC, a Windows 11 SDK, .NET Framework targeting packs, Unreal integration and the Epic Games Launcher) and the DirectX End-User Runtime. A real installer: it runs every boot (~10 GB on the sandbox disk). The engine itself comes from the Epic Games Launcher or its source. true, false, or \"auto\" = only when the project has a .uproject or .uplugin."
867
+ "description": "Unreal Engine development: Visual Studio Community 2022 with the C++ game workload (MSVC, a Windows 11 SDK, .NET Framework targeting packs, Unreal integration and the Epic Games Launcher) and the DirectX End-User Runtime. Visual Studio is installed once and kept on the data disk (~6.5 GB); later boots put it back in seconds. The engine itself comes from the Epic Games Launcher or its source. true, false, or \"auto\" = only when the project has a .uproject or .uplugin."
868
868
  },
869
869
  "acceptLicense": {
870
870
  "type": "boolean",
@@ -877,17 +877,13 @@
877
877
  },
878
878
  "description": "More Visual Studio workload or component IDs to add, e.g. [\"Microsoft.VisualStudio.Component.VC.Llvm.Clang\"]."
879
879
  },
880
- "keepInstallFiles": {
881
- "type": "boolean",
882
- "description": "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."
883
- },
884
880
  "visualStudio": {
885
881
  "type": "string",
886
882
  "enum": [
887
883
  "full",
888
- "autosdk"
884
+ "buildtools"
889
885
  ],
890
- "description": "\"full\": install Visual Studio Community (the engine finds it through the Setup API; ~10 GB, redone every boot). \"autosdk\" (experimental): skip Visual Studio and build an Unreal AutoSDK tree from the portable MSVC in tools\\unreal\\autosdk (kept between sandboxes); UnrealBuildTool finds MSVC through AutoSDK, but the editor's Visual Studio integration is not available. Needs toolchains.msvc (turned on for you)."
886
+ "description": "\"full\": Visual Studio Community with the C++ game workload (the IDE, its debugger and Unreal integration). \"buildtools\": only the Visual Studio Build Tools (MSVC, the Windows SDK and the .NET Framework parts UnrealBuildTool needs; no IDE). Either is installed once and kept on the data disk (tools\\visualstudio\\persist, ~6.5 GB for Community); later boots put it back in seconds."
891
887
  },
892
888
  "persistEngines": {
893
889
  "type": "boolean",
@@ -549,7 +549,7 @@
549
549
  "const": "auto"
550
550
  }
551
551
  ],
552
- "description": "Unreal Engine development: Visual Studio Community 2022 with the C++ game workload (MSVC, a Windows 11 SDK, .NET Framework targeting packs, Unreal integration and the Epic Games Launcher) and the DirectX End-User Runtime. A real installer: it runs every boot (~10 GB on the sandbox disk). The engine itself comes from the Epic Games Launcher or its source. true, false, or \"auto\" = only when the project has a .uproject or .uplugin."
552
+ "description": "Unreal Engine development: Visual Studio Community 2022 with the C++ game workload (MSVC, a Windows 11 SDK, .NET Framework targeting packs, Unreal integration and the Epic Games Launcher) and the DirectX End-User Runtime. Visual Studio is installed once and kept on the data disk (~6.5 GB); later boots put it back in seconds. The engine itself comes from the Epic Games Launcher or its source. true, false, or \"auto\" = only when the project has a .uproject or .uplugin."
553
553
  },
554
554
  "acceptLicense": {
555
555
  "type": "boolean",
@@ -562,17 +562,13 @@
562
562
  },
563
563
  "description": "More Visual Studio workload or component IDs to add, e.g. [\"Microsoft.VisualStudio.Component.VC.Llvm.Clang\"]."
564
564
  },
565
- "keepInstallFiles": {
566
- "type": "boolean",
567
- "description": "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."
568
- },
569
565
  "visualStudio": {
570
566
  "type": "string",
571
567
  "enum": [
572
568
  "full",
573
- "autosdk"
569
+ "buildtools"
574
570
  ],
575
- "description": "\"full\": install Visual Studio Community (the engine finds it through the Setup API; ~10 GB, redone every boot). \"autosdk\" (experimental): skip Visual Studio and build an Unreal AutoSDK tree from the portable MSVC in tools\\unreal\\autosdk (kept between sandboxes); UnrealBuildTool finds MSVC through AutoSDK, but the editor's Visual Studio integration is not available. Needs toolchains.msvc (turned on for you)."
571
+ "description": "\"full\": Visual Studio Community with the C++ game workload (the IDE, its debugger and Unreal integration). \"buildtools\": only the Visual Studio Build Tools (MSVC, the Windows SDK and the .NET Framework parts UnrealBuildTool needs; no IDE). Either is installed once and kept on the data disk (tools\\visualstudio\\persist, ~6.5 GB for Community); later boots put it back in seconds."
576
572
  },
577
573
  "persistEngines": {
578
574
  "type": "boolean",
@@ -1,3 +0,0 @@
1
- import { type ToolEnv } from '../tool-env.js';
2
- /** Makes the AutoSDK tree from the portable MSVC if it is missing for this MSVC and SDK, and points Unreal at it. */
3
- export declare function setupAutosdk(env: ToolEnv): Promise<void>;
@@ -1,50 +0,0 @@
1
- // Unreal without Visual Studio (toolchains.unreal.visualStudio = "autosdk", experimental): an AutoSDK tree made from
2
- // the portable MSVC (tools\msvc), at tools\unreal\autosdk, which UnrealBuildTool finds through UE_SDKS_ROOT. Made of
3
- // copies (mapped folders refuse links), once; kept between sandboxes. The editor's Visual Studio integration is not
4
- // available.
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
- import { z } from 'zod';
8
- import { writeJsonAtomic } from '../../../shared/io/json.js';
9
- import { robocopyFailed } from '../../../shared/io/robocopy-result.js';
10
- import { spawnAsync } from '../../../shared/download/index.js';
11
- import { SYSTEM } from '../../../shared/system.js';
12
- import { exists, mkdirp } from '../../runtime/fs.js';
13
- import { log } from '../../runtime/log.js';
14
- import { tool } from '../tool-env.js';
15
- import { hasCompiler, readInstalled, ROOT as MSVC_ROOT } from './msvc/tree.js';
16
- import { autosdkLayout } from './vs-request.js';
17
- const AUTOSDK_DIR = tool('unreal', 'autosdk');
18
- const MARKER = path.join(AUTOSDK_DIR, '.complete.json');
19
- const MarkerSchema = z.object({ msvc: z.string(), sdk: z.string() });
20
- function builtFor(msvc, sdk) {
21
- try {
22
- const done = MarkerSchema.parse(JSON.parse(fs.readFileSync(MARKER, 'utf8')));
23
- return done.msvc === msvc && done.sdk === sdk;
24
- }
25
- catch {
26
- return false; // No marker, or a half-written one: build again.
27
- }
28
- }
29
- /** Makes the AutoSDK tree from the portable MSVC if it is missing for this MSVC and SDK, and points Unreal at it. */
30
- export async function setupAutosdk(env) {
31
- const msvc = readInstalled();
32
- if (!msvc || !hasCompiler(msvc.msvc))
33
- throw new Error('toolchains.unreal.visualStudio = "autosdk" builds from the portable MSVC, which is not installed ' +
34
- '(is toolchains.msvc off?)');
35
- if (!builtFor(msvc.msvc, msvc.sdk)) {
36
- log('Making the Unreal AutoSDK from MSVC ' + msvc.msvc + ' (~2 GB, once) ...');
37
- fs.rmSync(MARKER, { force: true });
38
- for (const pair of autosdkLayout(MSVC_ROOT, msvc.msvc, msvc.sdk, AUTOSDK_DIR)) {
39
- mkdirp(pair.to);
40
- const code = await spawnAsync(SYSTEM.robocopy(), [pair.from, pair.to, '/E', '/COPY:DAT', '/R:1', '/W:1', '/NP']);
41
- if (robocopyFailed(code))
42
- throw new Error('could not copy ' + pair.from + ' into the AutoSDK (robocopy ' + code + ')');
43
- }
44
- writeJsonAtomic(MARKER, { msvc: msvc.msvc, sdk: msvc.sdk });
45
- }
46
- if (!exists(MARKER))
47
- throw new Error('the Unreal AutoSDK was not completed');
48
- env.vars['UE_SDKS_ROOT'] = AUTOSDK_DIR;
49
- env.summary.push('unreal autosdk: MSVC ' + msvc.msvc + ', Windows SDK ' + msvc.sdk + ' (UE_SDKS_ROOT=' + AUTOSDK_DIR + ')');
50
- }