windows-development-sandbox 1.0.5 → 1.4.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.
- package/LICENSE +21 -0
- package/README.md +25 -8
- package/config.example.json +55 -5
- package/dist/api.js +2 -1
- package/dist/cli/args.d.ts +23 -0
- package/dist/cli/args.js +38 -4
- package/dist/cli/colors.d.ts +24 -0
- package/dist/cli/colors.js +42 -0
- package/dist/cli/commands/accounts.js +2 -2
- package/dist/cli/commands/agent-commands.d.ts +6 -0
- package/dist/cli/commands/agent-commands.js +61 -0
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.js +5 -1
- package/dist/cli/commands/data/clean.d.ts +15 -0
- package/dist/cli/commands/data/clean.js +106 -0
- package/dist/cli/commands/data/collect.d.ts +11 -0
- package/dist/cli/commands/data/collect.js +54 -0
- package/dist/cli/commands/data/index.d.ts +4 -0
- package/dist/cli/commands/data/index.js +45 -0
- package/dist/cli/commands/data/remove.d.ts +2 -0
- package/dist/cli/commands/data/remove.js +30 -0
- package/dist/cli/commands/index.d.ts +6 -4
- package/dist/cli/commands/index.js +6 -4
- package/dist/cli/commands/launch.d.ts +26 -2
- package/dist/cli/commands/launch.js +256 -42
- package/dist/cli/commands/maintenance.d.ts +2 -0
- package/dist/cli/commands/maintenance.js +67 -5
- package/dist/cli/commands/project.d.ts +29 -0
- package/dist/cli/commands/project.js +63 -0
- package/dist/cli/commands/projects.d.ts +14 -0
- package/dist/cli/commands/projects.js +146 -0
- package/dist/cli/commands/repair/checks.d.ts +2 -0
- package/dist/cli/commands/{repair.js → repair/checks.js} +19 -181
- package/dist/cli/commands/{repair.d.ts → repair/finders.d.ts} +0 -29
- package/dist/cli/commands/repair/finders.js +108 -0
- package/dist/cli/commands/repair/index.d.ts +12 -0
- package/dist/cli/commands/repair/index.js +61 -0
- package/dist/cli/commands/repair/types.d.ts +26 -0
- package/dist/cli/commands/repair/types.js +3 -0
- package/dist/cli/commands/restart.d.ts +6 -0
- package/dist/cli/commands/restart.js +85 -0
- package/dist/cli/commands/sessions.d.ts +2 -1
- package/dist/cli/commands/sessions.js +189 -45
- package/dist/cli/commands/setup/checks.d.ts +13 -0
- package/dist/cli/commands/setup/checks.js +71 -0
- package/dist/cli/commands/{setup.d.ts → setup/facts.d.ts} +1 -15
- package/dist/cli/commands/setup/facts.js +60 -0
- package/dist/cli/commands/setup/index.d.ts +2 -0
- package/dist/cli/commands/setup/index.js +43 -0
- package/dist/cli/commands/user-config.d.ts +8 -0
- package/dist/cli/commands/user-config.js +41 -0
- package/dist/cli/history.d.ts +11 -0
- package/dist/cli/history.js +21 -0
- package/dist/cli/index.d.ts +7 -1
- package/dist/cli/index.js +42 -15
- package/dist/cli/manifest.d.ts +8 -0
- package/dist/cli/manifest.js +40 -15
- package/dist/cli/menu/apps.d.ts +21 -0
- package/dist/cli/menu/apps.js +122 -0
- package/dist/cli/menu/command-form.d.ts +28 -0
- package/dist/cli/menu/command-form.js +219 -0
- package/dist/cli/menu/index.d.ts +26 -0
- package/dist/cli/menu/index.js +180 -0
- package/dist/cli/menu/settings/categories.d.ts +9 -0
- package/dist/cli/menu/settings/categories.js +28 -0
- package/dist/cli/menu/settings/config-file.d.ts +40 -0
- package/dist/cli/menu/settings/config-file.js +71 -0
- package/dist/cli/menu/settings/editors.d.ts +30 -0
- package/dist/cli/menu/settings/editors.js +305 -0
- package/dist/cli/menu/settings/index.d.ts +32 -0
- package/dist/cli/menu/settings/index.js +136 -0
- package/dist/cli/menu/settings/schema-node.d.ts +62 -0
- package/dist/cli/menu/settings/schema-node.js +104 -0
- package/dist/cli/menu/several.d.ts +20 -0
- package/dist/cli/menu/several.js +102 -0
- package/dist/cli/progress.d.ts +9 -0
- package/dist/cli/progress.js +49 -0
- package/dist/cli/tui/app.d.ts +39 -0
- package/dist/cli/tui/app.js +52 -0
- package/dist/cli/tui/dialogs.d.ts +57 -0
- package/dist/cli/tui/dialogs.js +162 -0
- package/dist/cli/tui/frame.d.ts +18 -0
- package/dist/cli/tui/frame.js +27 -0
- package/dist/cli/tui/index.d.ts +7 -0
- package/dist/cli/tui/index.js +8 -0
- package/dist/cli/tui/list-screen.d.ts +101 -0
- package/dist/cli/tui/list-screen.js +299 -0
- package/dist/cli/tui/terminal.d.ts +37 -0
- package/dist/cli/tui/terminal.js +89 -0
- package/dist/cli/tui/text.d.ts +20 -0
- package/dist/cli/tui/text.js +105 -0
- package/dist/cli/tui/theme.d.ts +45 -0
- package/dist/cli/tui/theme.js +30 -0
- package/dist/cli/validate.d.ts +17 -0
- package/dist/cli/validate.js +89 -0
- package/dist/core/config.js +12 -6
- package/dist/core/disk.d.ts +16 -0
- package/dist/core/disk.js +55 -0
- package/dist/core/local-config.d.ts +23 -0
- package/dist/core/local-config.js +79 -7
- package/dist/core/project-policy.d.ts +15 -0
- package/dist/core/project-policy.js +35 -0
- package/dist/core/prompt.d.ts +4 -0
- package/dist/core/prompt.js +15 -0
- package/dist/core/safe-paths.d.ts +4 -0
- package/dist/core/safe-paths.js +37 -0
- package/dist/core/schema/apps.d.ts +40 -0
- package/dist/core/schema/apps.js +27 -0
- package/dist/core/schema/common.d.ts +17 -0
- package/dist/core/schema/common.js +15 -0
- package/dist/core/schema/config.d.ts +659 -0
- package/dist/core/schema/config.js +75 -0
- package/dist/core/schema/databases.d.ts +33 -0
- package/dist/core/schema/databases.js +35 -0
- package/dist/core/schema/harness.d.ts +12 -0
- package/dist/core/schema/harness.js +17 -0
- package/dist/core/schema/json-schema.d.ts +5 -0
- package/dist/core/schema/json-schema.js +25 -0
- package/dist/core/schema/profile.d.ts +32 -0
- package/dist/core/schema/profile.js +31 -0
- package/dist/core/schema/projects.d.ts +9 -0
- package/dist/core/schema/projects.js +11 -0
- package/dist/core/schema/sandbox.d.ts +78 -0
- package/dist/core/schema/sandbox.js +64 -0
- package/dist/core/schema/toolchains.d.ts +96 -0
- package/dist/core/schema/toolchains.js +88 -0
- package/dist/core/schema.d.ts +6 -604
- package/dist/core/schema.js +8 -264
- package/dist/core/types.d.ts +35 -1
- package/dist/core/util.d.ts +9 -0
- package/dist/core/util.js +14 -3
- package/dist/core/workspace.d.ts +0 -5
- package/dist/core/workspace.js +33 -50
- package/dist/guest/apps/index.d.ts +10 -0
- package/dist/guest/apps/index.js +206 -0
- package/dist/guest/apps/resolvers.d.ts +8 -0
- package/dist/guest/apps/resolvers.js +90 -0
- package/dist/guest/audit-parse.d.ts +7 -0
- package/dist/guest/audit-parse.js +24 -0
- package/dist/guest/audit.d.ts +4 -0
- package/dist/guest/audit.js +47 -0
- package/dist/guest/boot-env.d.ts +4 -0
- package/dist/guest/boot-env.js +25 -0
- package/dist/guest/cmdline.d.ts +12 -0
- package/dist/guest/cmdline.js +23 -0
- package/dist/guest/daemon/exec.d.ts +5 -0
- package/dist/guest/daemon/exec.js +32 -0
- package/dist/guest/daemon/project.d.ts +14 -0
- package/dist/guest/daemon/project.js +132 -0
- package/dist/guest/daemon/relays.d.ts +1 -0
- package/dist/guest/daemon/relays.js +18 -0
- package/dist/guest/daemon/session.d.ts +13 -0
- package/dist/guest/daemon/session.js +139 -0
- package/dist/guest/daemon/shutdown.d.ts +1 -0
- package/dist/guest/daemon/shutdown.js +21 -0
- package/dist/guest/daemon/state.d.ts +17 -0
- package/dist/guest/daemon/state.js +31 -0
- package/dist/guest/daemon.js +12 -141
- package/dist/guest/db.js +18 -3
- package/dist/guest/env.d.ts +3 -0
- package/dist/guest/env.js +7 -3
- package/dist/guest/guide.d.ts +6 -2
- package/dist/guest/guide.js +5 -4
- package/dist/guest/helpers.d.ts +3 -0
- package/dist/guest/helpers.js +26 -0
- package/dist/guest/main.js +31 -8
- package/dist/guest/netproxy.d.ts +1 -0
- package/dist/guest/netproxy.js +100 -0
- package/dist/guest/ports.d.ts +6 -0
- package/dist/guest/ports.js +22 -0
- package/dist/guest/project-context.d.ts +7 -0
- package/dist/guest/project-context.js +10 -0
- package/dist/guest/project-env.d.ts +20 -0
- package/dist/guest/project-env.js +20 -0
- package/dist/guest/project-status.d.ts +5 -0
- package/dist/guest/project-status.js +17 -0
- package/dist/guest/ptyhost.d.ts +0 -18
- package/dist/guest/ptyhost.js +17 -65
- package/dist/guest/setup/agents.d.ts +5 -2
- package/dist/guest/setup/agents.js +22 -8
- package/dist/guest/setup/claude.d.ts +0 -4
- package/dist/guest/setup/claude.js +59 -5
- package/dist/guest/setup/environment.d.ts +13 -3
- package/dist/guest/setup/environment.js +14 -10
- package/dist/guest/setup/hooks.d.ts +9 -1
- package/dist/guest/setup/hooks.js +28 -14
- package/dist/guest/setup/network.d.ts +9 -0
- package/dist/guest/setup/network.js +97 -4
- package/dist/guest/setup/user.js +4 -0
- package/dist/guest/toolchains/catalogue.d.ts +4 -0
- package/dist/guest/toolchains/catalogue.js +2 -2
- package/dist/guest/toolchains/cli.js +25 -17
- package/dist/guest/toolchains/common.d.ts +18 -1
- package/dist/guest/toolchains/common.js +34 -11
- package/dist/guest/toolchains/databases/dynamodb.d.ts +8 -0
- package/dist/guest/toolchains/databases/dynamodb.js +52 -0
- package/dist/guest/toolchains/{databases.d.ts → databases/index.d.ts} +2 -3
- package/dist/guest/toolchains/databases/index.js +62 -0
- package/dist/guest/toolchains/databases/mongodb.d.ts +3 -0
- package/dist/guest/toolchains/databases/mongodb.js +31 -0
- package/dist/guest/toolchains/databases/mysql.d.ts +3 -0
- package/dist/guest/toolchains/databases/mysql.js +38 -0
- package/dist/guest/toolchains/databases/postgres.d.ts +5 -0
- package/dist/guest/toolchains/databases/postgres.js +38 -0
- package/dist/guest/toolchains/databases/redis.d.ts +3 -0
- package/dist/guest/toolchains/databases/redis.js +16 -0
- package/dist/guest/toolchains/databases/server.d.ts +14 -0
- package/dist/guest/toolchains/databases/server.js +52 -0
- package/dist/guest/toolchains/git.js +25 -16
- package/dist/guest/toolchains/go.js +1 -1
- package/dist/guest/toolchains/index.d.ts +13 -9
- package/dist/guest/toolchains/index.js +40 -82
- package/dist/guest/toolchains/java.js +5 -5
- package/dist/guest/toolchains/leftovers.d.ts +2 -0
- package/dist/guest/toolchains/leftovers.js +26 -0
- package/dist/guest/toolchains/managers.js +12 -10
- package/dist/guest/toolchains/{binstall.js → native/binstall.js} +6 -9
- package/dist/guest/toolchains/native/cpp.d.ts +4 -0
- package/dist/guest/toolchains/native/cpp.js +38 -0
- package/dist/guest/toolchains/native/dotnet.d.ts +4 -0
- package/dist/guest/toolchains/native/dotnet.js +103 -0
- package/dist/guest/toolchains/native/mesa.d.ts +7 -0
- package/dist/guest/toolchains/native/mesa.js +56 -0
- package/dist/guest/toolchains/native/msvc/environment.d.ts +16 -0
- package/dist/guest/toolchains/native/msvc/environment.js +57 -0
- package/dist/guest/toolchains/native/msvc/index.d.ts +6 -0
- package/dist/guest/toolchains/native/msvc/index.js +48 -0
- package/dist/guest/toolchains/native/msvc/packages.d.ts +6 -0
- package/dist/guest/toolchains/native/msvc/packages.js +156 -0
- package/dist/guest/toolchains/native/msvc/tree.d.ts +15 -0
- package/dist/guest/toolchains/native/msvc/tree.js +21 -0
- package/dist/guest/toolchains/native/rust.d.ts +3 -0
- package/dist/guest/toolchains/native/rust.js +45 -0
- package/dist/guest/toolchains/node.js +26 -6
- package/dist/guest/toolchains/plan.d.ts +24 -0
- package/dist/guest/toolchains/plan.js +140 -0
- package/dist/guest/toolchains/pwsh.js +1 -1
- package/dist/guest/toolchains/python.js +43 -12
- package/dist/guest/toolchains/runtimes.d.ts +2 -0
- package/dist/guest/toolchains/runtimes.js +6 -8
- package/dist/guest/toolchains/scripting/php.d.ts +3 -0
- package/dist/guest/toolchains/scripting/php.js +71 -0
- package/dist/guest/toolchains/scripting/ruby.d.ts +3 -0
- package/dist/guest/toolchains/scripting/ruby.js +47 -0
- package/dist/guest/toolchains/scripting/vcruntime.d.ts +7 -0
- package/dist/guest/toolchains/scripting/vcruntime.js +45 -0
- package/dist/guest/toolchains/vscode-profile.d.ts +30 -0
- package/dist/guest/toolchains/vscode-profile.js +69 -0
- package/dist/guest/toolchains/vscode.d.ts +17 -0
- package/dist/guest/toolchains/vscode.js +87 -1
- package/dist/guest/view.js +21 -1
- package/dist/host/accounts.js +14 -5
- package/dist/host/agent-commands.d.ts +25 -0
- package/dist/host/agent-commands.js +145 -0
- package/dist/host/attach.d.ts +17 -0
- package/dist/host/attach.js +70 -0
- package/dist/host/audit/collect.d.ts +34 -0
- package/dist/host/audit/collect.js +126 -0
- package/dist/host/audit/log.d.ts +46 -0
- package/dist/host/audit/log.js +143 -0
- package/dist/host/channel.d.ts +23 -22
- package/dist/host/channel.js +66 -84
- package/dist/host/claude-profile.js +7 -3
- package/dist/host/cleanup.js +2 -11
- package/dist/host/database-plan.d.ts +12 -0
- package/dist/host/database-plan.js +52 -0
- package/dist/host/generate.d.ts +10 -12
- package/dist/host/generate.js +58 -135
- package/dist/host/join.d.ts +28 -0
- package/dist/host/join.js +76 -0
- package/dist/host/launch/mappings.d.ts +3 -0
- package/dist/host/launch/mappings.js +54 -0
- package/dist/host/launch/projects.d.ts +15 -0
- package/dist/host/launch/projects.js +56 -0
- package/dist/host/launch/stage.d.ts +11 -0
- package/dist/host/launch/stage.js +66 -0
- package/dist/host/launch/wsb.d.ts +10 -0
- package/dist/host/launch/wsb.js +34 -0
- package/dist/host/motw.d.ts +17 -0
- package/dist/host/motw.js +74 -0
- package/dist/host/pc-scan.d.ts +6 -0
- package/dist/host/pc-scan.js +37 -0
- package/dist/host/platform.d.ts +2 -0
- package/dist/host/platform.js +16 -1
- package/dist/host/port-forward.d.ts +8 -0
- package/dist/host/port-forward.js +37 -0
- package/dist/host/project-scan.d.ts +1 -17
- package/dist/host/project-scan.js +2 -86
- package/dist/host/projects.d.ts +100 -0
- package/dist/host/projects.js +147 -0
- package/dist/host/repo-guard.d.ts +25 -5
- package/dist/host/repo-guard.js +242 -23
- package/dist/host/stops.d.ts +67 -0
- package/dist/host/stops.js +126 -0
- package/dist/host/terminal.d.ts +8 -0
- package/dist/host/terminal.js +48 -1
- package/dist/host/test-guard.d.ts +6 -0
- package/dist/host/test-guard.js +15 -0
- package/dist/host/window.js +7 -3
- package/dist/host/workspace-view/index.d.ts +20 -0
- package/dist/host/workspace-view/index.js +53 -0
- package/dist/host/workspace-view/rules.d.ts +26 -0
- package/dist/host/workspace-view/rules.js +93 -0
- package/dist/host/workspace-view/view.d.ts +50 -0
- package/dist/host/workspace-view/view.js +281 -0
- package/dist/host/wsb.d.ts +37 -0
- package/dist/host/wsb.js +101 -0
- package/dist/runtime/daemon.js +11791 -2821
- package/dist/runtime/db.js +6585 -466
- package/dist/runtime/main.js +10238 -1724
- package/dist/runtime/netproxy.js +25936 -0
- package/dist/runtime/view.js +6183 -59
- package/dist/selftest/accounts.test.d.ts +2 -0
- package/dist/selftest/accounts.test.js +44 -0
- package/dist/selftest/agent-commands.test.d.ts +2 -0
- package/dist/selftest/agent-commands.test.js +47 -0
- package/dist/selftest/audit.test.d.ts +2 -0
- package/dist/selftest/audit.test.js +57 -0
- package/dist/selftest/channel.test.d.ts +2 -0
- package/dist/selftest/channel.test.js +44 -0
- package/dist/selftest/cli.test.d.ts +2 -2
- package/dist/selftest/cli.test.js +145 -27
- package/dist/selftest/cmdline.test.d.ts +2 -0
- package/dist/selftest/cmdline.test.js +45 -0
- package/dist/selftest/config.test.d.ts +2 -3
- package/dist/selftest/config.test.js +36 -72
- package/dist/selftest/data.test.d.ts +2 -2
- package/dist/selftest/data.test.js +77 -70
- package/dist/selftest/detect.test.d.ts +2 -2
- package/dist/selftest/detect.test.js +54 -38
- package/dist/selftest/fixtures.d.ts +89 -4
- package/dist/selftest/fixtures.js +43 -24
- package/dist/selftest/generate.test.d.ts +2 -0
- package/dist/selftest/generate.test.js +68 -0
- package/dist/selftest/git-access.test.d.ts +2 -0
- package/dist/selftest/git-access.test.js +26 -0
- package/dist/selftest/guest-boot.test.d.ts +2 -0
- package/dist/selftest/guest-boot.test.js +76 -0
- package/dist/selftest/harness.d.ts +44 -7
- package/dist/selftest/harness.js +62 -21
- package/dist/selftest/host-sim.test.d.ts +2 -0
- package/dist/selftest/host-sim.test.js +93 -0
- package/dist/selftest/hostile-input.test.d.ts +2 -0
- package/dist/selftest/hostile-input.test.js +54 -0
- package/dist/selftest/index.d.ts +8 -1
- package/dist/selftest/index.js +137 -35
- package/dist/selftest/links.test.d.ts +2 -0
- package/dist/selftest/links.test.js +50 -0
- package/dist/selftest/live-daemon.test.d.ts +2 -0
- package/dist/selftest/live-daemon.test.js +91 -0
- package/dist/selftest/live-git.test.d.ts +2 -0
- package/dist/selftest/live-git.test.js +60 -0
- package/dist/selftest/live-network.test.d.ts +2 -0
- package/dist/selftest/live-network.test.js +63 -0
- package/dist/selftest/live-projects.test.d.ts +2 -0
- package/dist/selftest/live-projects.test.js +127 -0
- package/dist/selftest/live.d.ts +65 -0
- package/dist/selftest/live.js +109 -0
- package/dist/selftest/local-config.test.d.ts +2 -0
- package/dist/selftest/local-config.test.js +120 -0
- package/dist/selftest/mirror.test.d.ts +2 -3
- package/dist/selftest/mirror.test.js +92 -65
- package/dist/selftest/network.test.d.ts +2 -0
- package/dist/selftest/network.test.js +40 -0
- package/dist/selftest/personalization.test.d.ts +2 -0
- package/dist/selftest/personalization.test.js +53 -0
- package/dist/selftest/projects.test.d.ts +2 -0
- package/dist/selftest/projects.test.js +254 -0
- package/dist/selftest/repair.test.d.ts +2 -0
- package/dist/selftest/repair.test.js +42 -0
- package/dist/selftest/repo-guard.test.d.ts +2 -0
- package/dist/selftest/repo-guard.test.js +121 -0
- package/dist/selftest/secrets.test.d.ts +2 -0
- package/dist/selftest/secrets.test.js +71 -0
- package/dist/selftest/setup.test.d.ts +2 -2
- package/dist/selftest/setup.test.js +45 -22
- package/dist/selftest/suite.d.ts +13 -0
- package/dist/selftest/suite.js +1 -0
- package/dist/selftest/sync.test.d.ts +2 -3
- package/dist/selftest/sync.test.js +130 -78
- package/dist/selftest/test-guard.test.d.ts +2 -0
- package/dist/selftest/test-guard.test.js +49 -0
- package/dist/selftest/toolchains.test.d.ts +2 -0
- package/dist/selftest/toolchains.test.js +133 -0
- package/dist/selftest/workspace-view.test.d.ts +2 -0
- package/dist/selftest/workspace-view.test.js +89 -0
- package/dist/selftest/workspace.test.d.ts +2 -0
- package/dist/selftest/workspace.test.js +53 -0
- package/dist/shared/apps.d.ts +49 -0
- package/dist/shared/apps.js +114 -0
- package/dist/shared/download.d.ts +3 -1
- package/dist/shared/download.js +19 -4
- package/dist/shared/netpolicy.d.ts +27 -0
- package/dist/shared/netpolicy.js +51 -0
- package/dist/shared/paths.d.ts +5 -0
- package/dist/shared/paths.js +6 -0
- package/dist/shared/projects.d.ts +53 -0
- package/dist/shared/projects.js +67 -0
- package/dist/shared/pty-client.d.ts +9 -4
- package/dist/shared/pty-client.js +139 -17
- package/dist/shared/rundir.d.ts +12 -1
- package/dist/shared/rundir.js +14 -4
- package/dist/shared/safe-remove.js +11 -0
- package/dist/shared/schema.d.ts +453 -0
- package/dist/shared/schema.js +43 -2
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/shared/test-guard.d.ts +4 -0
- package/dist/shared/test-guard.js +37 -0
- package/dist/sync/claude-mem.js +6 -3
- package/dist/sync/history.d.ts +29 -12
- package/dist/sync/history.js +72 -25
- package/dist/sync/watcher.d.ts +8 -0
- package/dist/sync/watcher.js +99 -8
- package/package.json +7 -6
- package/sandbox/bootstrap.ps1 +258 -258
- package/sandbox/cargoshim.cs +56 -0
- package/sandbox/cpucap.cs +33 -0
- package/sandbox/cpucap.ps1 +20 -0
- package/sandbox/logon.cmd +24 -16
- package/sandbox/memlog.ps1 +34 -0
- package/sandbox/openssl.cs +42 -0
- package/sandbox/pagefile.cs +31 -0
- package/sandbox/pagefile.ps1 +21 -0
- package/sandbox/ptyhost.cs +120 -11
- package/sandbox/trust.cmd +35 -35
- package/schemas/config.schema.json +403 -3
- package/schemas/sandbox-config.schema.json +143 -13
- package/dist/cli/commands/data.d.ts +0 -46
- package/dist/cli/commands/data.js +0 -249
- package/dist/cli/commands/setup.js +0 -152
- package/dist/cli/menu.d.ts +0 -22
- package/dist/cli/menu.js +0 -187
- package/dist/cli/settings.d.ts +0 -11
- package/dist/cli/settings.js +0 -156
- package/dist/guest/toolchains/databases.js +0 -226
- package/dist/guest/toolchains/msvc.d.ts +0 -10
- package/dist/guest/toolchains/msvc.js +0 -216
- package/dist/guest/toolchains/native.d.ts +0 -12
- package/dist/guest/toolchains/native.js +0 -220
- package/dist/guest/toolchains/scripting.d.ts +0 -10
- package/dist/guest/toolchains/scripting.js +0 -137
- package/dist/selftest/guest.test.d.ts +0 -3
- package/dist/selftest/guest.test.js +0 -61
- package/dist/selftest/helpers.test.d.ts +0 -2
- package/dist/selftest/helpers.test.js +0 -125
- package/dist/selftest/host.test.d.ts +0 -2
- package/dist/selftest/host.test.js +0 -71
- package/dist/selftest/live.test.d.ts +0 -7
- package/dist/selftest/live.test.js +0 -127
- package/dist/selftest/security.test.d.ts +0 -3
- package/dist/selftest/security.test.js +0 -143
- /package/dist/guest/toolchains/{binstall.d.ts → native/binstall.d.ts} +0 -0
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
// Databases inside the sandbox: PostgreSQL, MariaDB (MySQL-compatible), MongoDB and Redis. Binaries live in
|
|
2
|
-
// C:\AgentData\tools, data in C:\AgentData\databases (both persist), and every server listens on localhost only.
|
|
3
|
-
// Which ones run was decided on the host (session.databases): only what the project needs.
|
|
4
|
-
import fs from 'node:fs';
|
|
5
|
-
import net from 'node:net';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import { spawn, spawnSync } from 'node:child_process';
|
|
8
|
-
import { fetchJson, fetchText, githubAsset, installArchive } from '../../shared/download.js';
|
|
9
|
-
import { SYSTEM } from '../../shared/system.js';
|
|
10
|
-
import { ensureJdk } from './java.js';
|
|
11
|
-
import { dataDir, dryRun, execAsync, exists, log, logsDir, mkdirp } from '../env.js';
|
|
12
|
-
import { resolveCached, tool } from './common.js';
|
|
13
|
-
const dataFor = (name) => path.join(dataDir, 'databases', name);
|
|
14
|
-
export const portOpen = (port) => new Promise((resolve) => {
|
|
15
|
-
const socket = net.connect({ host: '127.0.0.1', port }, () => { socket.destroy(); resolve(true); });
|
|
16
|
-
socket.once('error', () => resolve(false));
|
|
17
|
-
});
|
|
18
|
-
const waitForPort = async (port, seconds) => {
|
|
19
|
-
for (const end = Date.now() + seconds * 1000; Date.now() < end;) {
|
|
20
|
-
if (await portOpen(port))
|
|
21
|
-
return true;
|
|
22
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
23
|
-
}
|
|
24
|
-
return false;
|
|
25
|
-
};
|
|
26
|
-
/** Starts a server detached (it outlives the boot script) with its output in logs\<name>.log, and waits for its port. */
|
|
27
|
-
const startServer = async (name, exe, args, port) => {
|
|
28
|
-
if (await portOpen(port))
|
|
29
|
-
throw new Error('port ' + port + ' is already in use (change databases.' + name + '.port)');
|
|
30
|
-
const logFile = path.join(logsDir, name + '.log');
|
|
31
|
-
const out = fs.openSync(logFile, 'a');
|
|
32
|
-
spawn(exe, args, { detached: true, stdio: ['ignore', out, out], windowsHide: true }).unref();
|
|
33
|
-
fs.closeSync(out);
|
|
34
|
-
if (!(await waitForPort(port, 60)))
|
|
35
|
-
throw new Error(name + ' did not start listening on port ' + port + '; see ' + logFile);
|
|
36
|
-
};
|
|
37
|
-
/** Lock files a sandbox that was closed without shutting the server down leaves behind (this VM never ran it). */
|
|
38
|
-
const clearStaleLocks = (dir, files) => { for (const f of files)
|
|
39
|
-
fs.rmSync(path.join(dir, f), { force: true }); };
|
|
40
|
-
const setupPostgres = async (env, plan) => {
|
|
41
|
-
const exact = await resolveCached('postgres:' + plan.version, async () => {
|
|
42
|
-
const versions = (await fetchJson('https://www.postgresql.org/versions.json')).filter((v) => v.supported);
|
|
43
|
-
const hit = plan.version === 'latest' ? versions.find((v) => v.current) ?? versions[versions.length - 1] : versions.find((v) => v.major === plan.version.split('.')[0]);
|
|
44
|
-
return hit ? hit.major + '.' + hit.latestMinor : Promise.reject(new Error('No supported PostgreSQL ' + plan.version));
|
|
45
|
-
});
|
|
46
|
-
const home = tool('postgres', exact);
|
|
47
|
-
const bin = path.join(home, 'bin');
|
|
48
|
-
if (!exists(path.join(bin, 'pg_ctl.exe'))) {
|
|
49
|
-
log('Downloading PostgreSQL ' + exact + ' (~330 MB once) ...');
|
|
50
|
-
// EDB publishes no checksums; the download is HTTPS from EnterpriseDB, PostgreSQL's official Windows packager.
|
|
51
|
-
await installArchive('https://get.enterprisedb.com/postgresql/postgresql-' + exact + '-1-windows-x64-binaries.zip', home, { locate: 'pg_ctl.exe', up: 1, fileName: 'postgresql-' + exact + '.zip', members: ['pgsql/bin', 'pgsql/lib', 'pgsql/share', 'pgsql/include'] });
|
|
52
|
-
}
|
|
53
|
-
const data = dataFor('postgres-' + exact.split('.')[0]);
|
|
54
|
-
if (!exists(path.join(data, 'PG_VERSION'))) {
|
|
55
|
-
log('Creating the PostgreSQL database cluster ...');
|
|
56
|
-
mkdirp(path.dirname(data));
|
|
57
|
-
await execAsync(path.join(bin, 'initdb.exe'), ['-D', data, '-U', 'postgres', '-A', 'trust', '-E', 'UTF8', '--locale=C'], { stdio: 'ignore' });
|
|
58
|
-
}
|
|
59
|
-
clearStaleLocks(data, ['postmaster.pid']);
|
|
60
|
-
// postgres.exe refuses to run as an administrator (the sandbox user is one); pg_ctl drops the rights first.
|
|
61
|
-
if (await portOpen(plan.port))
|
|
62
|
-
throw new Error('port ' + plan.port + ' is already in use (change databases.postgres.port)');
|
|
63
|
-
await execAsync(path.join(bin, 'pg_ctl.exe'), ['start', '-D', data, '-w', '-t', '60', '-l', path.join(logsDir, 'postgres.log'), '-o', '-p ' + plan.port + ' -c listen_addresses=localhost'], { stdio: 'ignore' });
|
|
64
|
-
Object.assign(env.vars, { PGHOST: 'localhost', PGPORT: String(plan.port), PGUSER: 'postgres' });
|
|
65
|
-
env.prepend.push(bin);
|
|
66
|
-
env.summary.push('postgres ' + exact + ': localhost:' + plan.port + ', user postgres, no password (postgres://postgres@localhost:' + plan.port + '/postgres)');
|
|
67
|
-
};
|
|
68
|
-
const MARIA = 'https://downloads.mariadb.org/rest-api/mariadb/';
|
|
69
|
-
const setupMysql = async (env, plan) => {
|
|
70
|
-
const series = await resolveCached('mariadb:' + plan.version, async () => {
|
|
71
|
-
if (plan.version !== 'lts')
|
|
72
|
-
return plan.version;
|
|
73
|
-
const { major_releases: all } = await fetchJson(MARIA);
|
|
74
|
-
return all.find((r) => r.release_status === 'Stable' && r.release_support_type === 'Long Term Support')?.release_id ?? Promise.reject(new Error('No MariaDB LTS release found'));
|
|
75
|
-
});
|
|
76
|
-
const latest = async () => {
|
|
77
|
-
const { releases } = await fetchJson(MARIA + series + '/latest/');
|
|
78
|
-
const [version, release] = Object.entries(releases)[0] ?? [];
|
|
79
|
-
const zip = release?.files.find((f) => /-winx64\.zip$/.test(f.file_name));
|
|
80
|
-
return zip ? { version, zip } : Promise.reject(new Error('No MariaDB ' + series + ' zip for Windows'));
|
|
81
|
-
};
|
|
82
|
-
const version = await resolveCached('mariadb-version:' + series, async () => (await latest()).version);
|
|
83
|
-
const home = tool('mariadb', version);
|
|
84
|
-
const bin = path.join(home, 'bin');
|
|
85
|
-
if (!exists(path.join(bin, 'mariadbd.exe'))) {
|
|
86
|
-
const { zip } = await latest();
|
|
87
|
-
log('Downloading MariaDB ' + version + ' ...');
|
|
88
|
-
await installArchive(zip.file_download_url.replace(/^http:/, 'https:'), home, { sha256: zip.checksum?.sha256sum ?? null, locate: 'mariadbd.exe', up: 1, fileName: zip.file_name });
|
|
89
|
-
}
|
|
90
|
-
const data = dataFor('mariadb');
|
|
91
|
-
if (!exists(path.join(data, 'mysql'))) {
|
|
92
|
-
log('Creating the MariaDB data folder ...');
|
|
93
|
-
mkdirp(path.dirname(data));
|
|
94
|
-
await execAsync(path.join(bin, 'mariadb-install-db.exe'), ['--datadir=' + data, '--port=' + plan.port], { stdio: 'ignore' });
|
|
95
|
-
}
|
|
96
|
-
await startServer('mysql', path.join(bin, 'mariadbd.exe'), ['--datadir=' + data, '--port=' + plan.port, '--bind-address=127.0.0.1', '--console'], plan.port);
|
|
97
|
-
Object.assign(env.vars, { MYSQL_HOST: '127.0.0.1', MYSQL_TCP_PORT: String(plan.port) });
|
|
98
|
-
env.prepend.push(bin);
|
|
99
|
-
env.summary.push('mysql (MariaDB ' + version + '): 127.0.0.1:' + plan.port + ', user root, no password (mysql://root@127.0.0.1:' + plan.port + ')');
|
|
100
|
-
};
|
|
101
|
-
const setupMongo = async (env, plan) => {
|
|
102
|
-
const find = async () => {
|
|
103
|
-
const { versions } = await fetchJson('https://downloads.mongodb.org/full.json');
|
|
104
|
-
const prod = versions.filter((v) => v.production_release);
|
|
105
|
-
const hit = plan.version === 'latest' ? prod[0] : prod.find((v) => v.version === plan.version || v.version.startsWith(plan.version + '.'));
|
|
106
|
-
const archive = hit?.downloads.find((d) => d.target === 'windows' && d.arch === 'x86_64' && d.edition === 'base')?.archive;
|
|
107
|
-
return hit && archive ? { version: hit.version, archive } : Promise.reject(new Error('No MongoDB ' + plan.version + ' for Windows'));
|
|
108
|
-
};
|
|
109
|
-
const version = await resolveCached('mongodb:' + plan.version, async () => (await find()).version);
|
|
110
|
-
const home = tool('mongodb', version);
|
|
111
|
-
if (!exists(path.join(home, 'bin', 'mongod.exe'))) {
|
|
112
|
-
const { archive } = await find();
|
|
113
|
-
log('Downloading MongoDB ' + version + ' ...');
|
|
114
|
-
await installArchive(archive.url, home, { sha256: archive.sha256, locate: 'mongod.exe', up: 1 });
|
|
115
|
-
}
|
|
116
|
-
const shell = tool('mongosh');
|
|
117
|
-
if (!exists(path.join(shell, 'mongosh.exe'))) {
|
|
118
|
-
const asset = await githubAsset('mongodb-js/mongosh', /^mongosh-[\d.]+-win32-x64\.zip$/);
|
|
119
|
-
log('Downloading mongosh ...');
|
|
120
|
-
await installArchive(asset.url, shell, { sha256: asset.sha256, locate: 'mongosh.exe', fileName: asset.name });
|
|
121
|
-
}
|
|
122
|
-
const data = mkdirp(dataFor('mongodb'));
|
|
123
|
-
clearStaleLocks(data, ['mongod.lock']);
|
|
124
|
-
await startServer('mongodb', path.join(home, 'bin', 'mongod.exe'), ['--dbpath', data, '--bind_ip', '127.0.0.1', '--port', String(plan.port)], plan.port);
|
|
125
|
-
env.prepend.push(path.join(home, 'bin'), shell);
|
|
126
|
-
env.summary.push('mongodb ' + version + ': mongodb://127.0.0.1:' + plan.port + ' (mongosh on PATH)');
|
|
127
|
-
};
|
|
128
|
-
// ---- Redis -------------------------------------------------------------------------------------------------------
|
|
129
|
-
const setupRedis = async (env, plan) => {
|
|
130
|
-
const home = tool('redis');
|
|
131
|
-
if (!exists(path.join(home, 'redis-server.exe'))) {
|
|
132
|
-
// Redis has no official Windows build; this is the maintained community build of upstream Redis (MSYS2).
|
|
133
|
-
const asset = await githubAsset('redis-windows/redis-windows', /^Redis-[\d.]+-Windows-x64-msys2\.zip$/);
|
|
134
|
-
log('Downloading ' + asset.name + ' ...');
|
|
135
|
-
await installArchive(asset.url, home, { sha256: asset.sha256, locate: 'redis-server.exe', fileName: asset.name });
|
|
136
|
-
}
|
|
137
|
-
const data = mkdirp(dataFor('redis'));
|
|
138
|
-
await startServer('redis', path.join(home, 'redis-server.exe'), ['--port', String(plan.port), '--bind', '127.0.0.1', '--dir', data.replace(/\\/g, '/'), '--appendonly', 'yes'], plan.port);
|
|
139
|
-
env.prepend.push(home);
|
|
140
|
-
env.summary.push('redis: redis://127.0.0.1:' + plan.port + ' (redis-cli on PATH)');
|
|
141
|
-
};
|
|
142
|
-
// ---- DynamoDB Local + dynamodb-admin -------------------------------------------------------------------------------
|
|
143
|
-
const DYNAMO_ZIP = 'https://d1ni2b6xgvw0s0.cloudfront.net/v2.x/dynamodb_local_latest.zip';
|
|
144
|
-
/**
|
|
145
|
-
* Amazon's DynamoDB Local (a Java program; the Java toolchain step runs first, else this installs the LTS JDK) and
|
|
146
|
-
* dynamodb-admin, the web UI to browse and edit tables, installed with the runner's own npm. Every AWS SDK picks the
|
|
147
|
-
* local endpoint up from AWS_ENDPOINT_URL_DYNAMODB, with dummy credentials (real ones never reach the sandbox).
|
|
148
|
-
*/
|
|
149
|
-
const setupDynamo = async (env, plan) => {
|
|
150
|
-
const java = path.join(await ensureJdk(), 'bin', 'java.exe');
|
|
151
|
-
const home = tool('dynamodb-local');
|
|
152
|
-
if (!exists(path.join(home, 'DynamoDBLocal.jar'))) {
|
|
153
|
-
log('Downloading DynamoDB Local ...');
|
|
154
|
-
const sha256 = (await fetchText(DYNAMO_ZIP + '.sha256')).trim().split(/\s+/)[0];
|
|
155
|
-
await installArchive(DYNAMO_ZIP, home, { sha256, locate: 'DynamoDBLocal.jar', fileName: 'dynamodb_local.zip' });
|
|
156
|
-
}
|
|
157
|
-
const data = mkdirp(dataFor('dynamodb'));
|
|
158
|
-
// -sharedDb: one database whatever region/credentials a client uses, so the admin UI and the app see the same tables.
|
|
159
|
-
await startServer('dynamodb', java, ['-Djava.library.path=' + path.join(home, 'DynamoDBLocal_lib'), '-jar', path.join(home, 'DynamoDBLocal.jar'), '-sharedDb', '-dbPath', data, '-port', String(plan.port)], plan.port);
|
|
160
|
-
const endpoint = 'http://localhost:' + plan.port;
|
|
161
|
-
const aws = { AWS_ENDPOINT_URL_DYNAMODB: endpoint, DYNAMO_ENDPOINT: endpoint, AWS_ACCESS_KEY_ID: 'local', AWS_SECRET_ACCESS_KEY: 'local', AWS_REGION: 'us-east-1', AWS_DEFAULT_REGION: 'us-east-1' };
|
|
162
|
-
Object.assign(env.vars, aws);
|
|
163
|
-
env.summary.push('dynamodb (DynamoDB Local): ' + endpoint + ' (AWS SDKs use it automatically via AWS_ENDPOINT_URL_DYNAMODB; dummy credentials)');
|
|
164
|
-
if (!plan.adminPort)
|
|
165
|
-
return;
|
|
166
|
-
const prefix = tool('dynamodb-admin');
|
|
167
|
-
const script = path.join(prefix, 'node_modules', 'dynamodb-admin', 'dist', 'dynamodb-admin.js');
|
|
168
|
-
if (!exists(script)) {
|
|
169
|
-
log('Installing dynamodb-admin (web UI for DynamoDB) ...');
|
|
170
|
-
const npmCli = path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
|
171
|
-
await execAsync(process.execPath, [npmCli, 'install', '--global', '--prefix', prefix, 'dynamodb-admin', '--no-fund', '--no-audit'], { stdio: 'ignore' });
|
|
172
|
-
}
|
|
173
|
-
const admin = { ...process.env, ...aws, DYNAMO_ENDPOINT: endpoint };
|
|
174
|
-
// The database matters more than its UI: a taken port is reported, not fatal.
|
|
175
|
-
if (await portOpen(plan.adminPort)) {
|
|
176
|
-
env.summary.push('dynamodb-admin: NOT started, port ' + plan.adminPort + ' is in use (change databases.dynamodb.adminPort)');
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
const out = fs.openSync(path.join(logsDir, 'dynamodb-admin.log'), 'a');
|
|
180
|
-
spawn(process.execPath, [script, '--port', String(plan.adminPort), '--dynamo-endpoint', endpoint, '--skip-default-credentials'], { detached: true, stdio: ['ignore', out, out], windowsHide: true, env: admin }).unref();
|
|
181
|
-
fs.closeSync(out);
|
|
182
|
-
if (!(await waitForPort(plan.adminPort, 30)))
|
|
183
|
-
throw new Error('dynamodb-admin did not start; see ' + path.join(logsDir, 'dynamodb-admin.log'));
|
|
184
|
-
env.summary.push('dynamodb-admin: http://localhost:' + plan.adminPort + ' (browse and edit tables in the sandbox\'s browser)');
|
|
185
|
-
};
|
|
186
|
-
const SETUP = { postgres: setupPostgres, mysql: setupMysql, mongodb: setupMongo, redis: setupRedis, dynamodb: setupDynamo };
|
|
187
|
-
export const DATABASE_NAMES = { postgres: 'PostgreSQL', mysql: 'MySQL (MariaDB)', mongodb: 'MongoDB', redis: 'Redis', dynamodb: 'DynamoDB Local', sqlserver: 'SQL Server' };
|
|
188
|
-
/** The process listening on a local TCP port (netstat: no PowerShell start-up cost), or null. */
|
|
189
|
-
const listenerPid = (port) => {
|
|
190
|
-
const out = spawnSync(SYSTEM.netstat(), ['-ano', '-p', 'TCP'], { encoding: 'utf8', windowsHide: true }).stdout ?? '';
|
|
191
|
-
const hit = out.split(/\r?\n/).map((l) => /^\s*TCP\s+\S+:(\d+)\s+\S+\s+LISTENING\s+(\d+)/.exec(l)).find((m) => m && Number(m[1]) === port);
|
|
192
|
-
return hit ? Number(hit[2]) : null;
|
|
193
|
-
};
|
|
194
|
-
/** Stops a database (and DynamoDB's admin UI). PostgreSQL shuts down cleanly through pg_ctl; the others are ended. */
|
|
195
|
-
export const stopDatabase = async (plan) => {
|
|
196
|
-
if (!(await portOpen(plan.port)))
|
|
197
|
-
return false;
|
|
198
|
-
if (plan.database === 'postgres' && exists(tool('postgres'))) {
|
|
199
|
-
for (const version of fs.readdirSync(tool('postgres'))) {
|
|
200
|
-
const data = dataFor('postgres-' + version.split('.')[0]);
|
|
201
|
-
const pgCtl = path.join(tool('postgres', version), 'bin', 'pg_ctl.exe');
|
|
202
|
-
if (exists(path.join(data, 'postmaster.pid')) && exists(pgCtl))
|
|
203
|
-
await execAsync(pgCtl, ['stop', '-D', data, '-m', 'fast', '-w'], { stdio: 'ignore' });
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
for (const port of [plan.port, plan.adminPort ?? 0]) {
|
|
207
|
-
const pid = port && listenerPid(port);
|
|
208
|
-
if (pid)
|
|
209
|
-
try {
|
|
210
|
-
process.kill(pid);
|
|
211
|
-
}
|
|
212
|
-
catch { /* already gone */ }
|
|
213
|
-
}
|
|
214
|
-
return true;
|
|
215
|
-
};
|
|
216
|
-
export const setupDatabase = async (env, plan) => {
|
|
217
|
-
if (plan.database === 'sqlserver') {
|
|
218
|
-
env.summary.push('sqlserver: NOT available (SQL Server cannot start inside Windows Sandbox). Use the one on the PC via hostAccess.forwards, or switch the project to Postgres/SQLite for local work');
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
if (dryRun) {
|
|
222
|
-
log('(dry run) would run ' + DATABASE_NAMES[plan.database] + ' on port ' + plan.port + ' (' + plan.reasons.join('; ') + ')');
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
await SETUP[plan.database](env, plan);
|
|
226
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Toolchains } from '../../core/types.js';
|
|
2
|
-
import { type ToolEnv } from './common.js';
|
|
3
|
-
/** Variables vcvars64.bat would set for this tree (host x64, target x64). */
|
|
4
|
-
export declare const vcvars: (root: string, msvc: string, sdk: string) => {
|
|
5
|
-
vars: Record<string, string>;
|
|
6
|
-
path: string[];
|
|
7
|
-
};
|
|
8
|
-
/** The vcvars environment of an installed tree (for steps that run before the agent's environment exists). */
|
|
9
|
-
export declare const installedMsvcEnv: () => ReturnType<typeof vcvars> | null;
|
|
10
|
-
export declare const setupMsvc: (env: ToolEnv, config: Toolchains["msvc"]) => Promise<void>;
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
// MSVC (cl, link) and the Windows SDK without an installer, the way mmozeiko's portable-msvc.py does it: packages
|
|
2
|
-
// from Microsoft's Visual Studio channel manifest (each payload checked against the manifest's sha256), the compiler
|
|
3
|
-
// unpacked from its .vsix, the SDK from its .msi files with `msiexec /a`. Laid out like a Build Tools install, with
|
|
4
|
-
// vcvars64.bat and a vswhere that points at it, so CMake, cargo (msvc host), node-gyp and vcvars-based scripts work.
|
|
5
|
-
// Use is governed by the Visual Studio licence terms: it only installs with toolchains.msvc.acceptLicense.
|
|
6
|
-
import fs from 'node:fs';
|
|
7
|
-
import path from 'node:path';
|
|
8
|
-
import { download, extractArchive, fetchJson } from '../../shared/download.js';
|
|
9
|
-
import { safeRemove } from '../../shared/safe-remove.js';
|
|
10
|
-
import { system32 } from '../../shared/system.js';
|
|
11
|
-
import { dryRun, execAsync, exists, log, mkdirp } from '../env.js';
|
|
12
|
-
import { ensureCompiled } from '../ptyhost.js';
|
|
13
|
-
import { tool } from './common.js';
|
|
14
|
-
import { msiCabs, pickMsvcVersion, pickWindowsSdk } from './versions.js';
|
|
15
|
-
const CHANNEL = 'https://aka.ms/vs/17/release/channel';
|
|
16
|
-
const ROOT = tool('msvc');
|
|
17
|
-
const MANIFEST_DAY_MS = 24 * 60 * 60 * 1000;
|
|
18
|
-
/** Where build tools look for vswhere (local to the sandbox, so it is written each boot). */
|
|
19
|
-
const VSWHERE_DIR = path.join(process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)', 'Microsoft Visual Studio', 'Installer');
|
|
20
|
-
/** The VS manifest (~18 MB), cached for a day. */
|
|
21
|
-
const manifest = async () => {
|
|
22
|
-
const cached = path.join(ROOT, '.manifest.json');
|
|
23
|
-
if (exists(cached) && Date.now() - fs.statSync(cached).mtimeMs < MANIFEST_DAY_MS)
|
|
24
|
-
return JSON.parse(fs.readFileSync(cached, 'utf8'));
|
|
25
|
-
const channel = await fetchJson(CHANNEL);
|
|
26
|
-
const item = channel.channelItems.find((i) => i.id === 'Microsoft.VisualStudio.Manifests.VisualStudio')?.payloads?.[0];
|
|
27
|
-
if (!item)
|
|
28
|
-
throw new Error('the Visual Studio channel has no package manifest');
|
|
29
|
-
mkdirp(ROOT);
|
|
30
|
-
// The channel's sha256 for the manifest is not the file's hash (portable-msvc.py does not check it either); the
|
|
31
|
-
// manifest comes over HTTPS from Microsoft, and every package payload it lists IS checked against its own sha256.
|
|
32
|
-
await download(item.url, cached);
|
|
33
|
-
return JSON.parse(fs.readFileSync(cached, 'utf8'));
|
|
34
|
-
};
|
|
35
|
-
/** The compiler's packages (host x64, target x64): tools, resources, CRT headers/libs, ASAN/PGO headers, DIA SDK. */
|
|
36
|
-
const MSVC_PARTS = ['tools.hostx64.targetx64.base', 'tools.hostx64.targetx64.res.base', 'crt.headers.base', 'crt.x64.desktop.base', 'crt.x64.store.base', 'crt.source.base', 'asan.headers.base', 'pgo.headers.base'];
|
|
37
|
-
/** The SDK's .msi files (Desktop + UCRT + Store headers/libs/tools for x64), as in portable-msvc.py. */
|
|
38
|
-
const SDK_MSIS = [
|
|
39
|
-
'Windows SDK for Windows Store Apps Tools-x86_en-us.msi', 'Windows SDK for Windows Store Apps Headers-x86_en-us.msi',
|
|
40
|
-
'Windows SDK for Windows Store Apps Headers OnecoreUap-x86_en-us.msi', 'Windows SDK for Windows Store Apps Libs-x86_en-us.msi',
|
|
41
|
-
'Universal CRT Headers Libraries and Sources-x86_en-us.msi', 'Windows SDK Desktop Headers x86-x86_en-us.msi',
|
|
42
|
-
'Windows SDK Desktop Headers x64-x86_en-us.msi', 'Windows SDK Desktop Libs x64-x86_en-us.msi', 'Windows SDK Desktop Tools x64-x86_en-us.msi',
|
|
43
|
-
];
|
|
44
|
-
/** .vsix contents are percent-encoded file names under Contents/; unpack them into the root, names decoded. */
|
|
45
|
-
const unpackVsix = async (vsix, work) => {
|
|
46
|
-
const out = mkdirp(path.join(work, 'vsix-' + path.basename(vsix)));
|
|
47
|
-
await extractArchive(vsix, out, ['Contents']);
|
|
48
|
-
const decode = (dir) => {
|
|
49
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
50
|
-
const from = path.join(dir, entry.name);
|
|
51
|
-
let name = entry.name;
|
|
52
|
-
try {
|
|
53
|
-
if (name.includes('%'))
|
|
54
|
-
name = decodeURIComponent(name);
|
|
55
|
-
}
|
|
56
|
-
catch { /* not percent-encoded after all */ }
|
|
57
|
-
const to = path.join(dir, name);
|
|
58
|
-
if (to !== from)
|
|
59
|
-
fs.renameSync(from, to);
|
|
60
|
-
if (entry.isDirectory())
|
|
61
|
-
decode(to);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
decode(out);
|
|
65
|
-
fs.cpSync(path.join(out, 'Contents'), ROOT, { recursive: true, force: true });
|
|
66
|
-
safeRemove(out, work);
|
|
67
|
-
};
|
|
68
|
-
const install = async (config) => {
|
|
69
|
-
const m = await manifest();
|
|
70
|
-
const byId = new Map();
|
|
71
|
-
for (const p of m.packages)
|
|
72
|
-
byId.set(p.id.toLowerCase(), [...(byId.get(p.id.toLowerCase()) ?? []), p]);
|
|
73
|
-
const pick = (id) => byId.get(id.toLowerCase())?.find((p) => !p.language || p.language === 'en-US');
|
|
74
|
-
const ids = [...byId.keys()];
|
|
75
|
-
const version = pickMsvcVersion(ids, config.msvcVersion);
|
|
76
|
-
if (!version)
|
|
77
|
-
throw new Error('no MSVC ' + config.msvcVersion + ' in the Visual Studio manifest');
|
|
78
|
-
const sdk = pickWindowsSdk(ids, config.sdkVersion);
|
|
79
|
-
if (!sdk)
|
|
80
|
-
throw new Error('no Windows SDK ' + config.sdkVersion + ' in the Visual Studio manifest');
|
|
81
|
-
const work = mkdirp(path.join(ROOT, '.download'));
|
|
82
|
-
const fetchPayload = async (p) => {
|
|
83
|
-
const file = path.join(work, path.basename(p.fileName.replace(/\\/g, '/')));
|
|
84
|
-
if (!exists(file))
|
|
85
|
-
await download(p.url, file, p.sha256);
|
|
86
|
-
return file;
|
|
87
|
-
};
|
|
88
|
-
log('Downloading MSVC ' + version + ' (compiler, CRT) ...');
|
|
89
|
-
for (const part of MSVC_PARTS) {
|
|
90
|
-
const p = pick('microsoft.vc.' + version + '.' + part);
|
|
91
|
-
if (!p) {
|
|
92
|
-
if (part.startsWith('tools') || part.startsWith('crt.headers') || part.startsWith('crt.x64.desktop'))
|
|
93
|
-
throw new Error('MSVC ' + version + ' has no ' + part);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
for (const payload of p.payloads ?? [])
|
|
97
|
-
await unpackVsix(await fetchPayload(payload), work);
|
|
98
|
-
}
|
|
99
|
-
const dia = pick('microsoft.visualcpp.dia.sdk');
|
|
100
|
-
for (const payload of dia?.payloads ?? [])
|
|
101
|
-
await unpackVsix(await fetchPayload(payload), work);
|
|
102
|
-
// The SDK component depends on the package that holds the .msi/.cab payloads (e.g. Win11SDK_10.0.26100).
|
|
103
|
-
const sdkPackage = pick(Object.keys(pick(sdk.componentId)?.dependencies ?? {})[0] ?? '');
|
|
104
|
-
if (!sdkPackage?.payloads)
|
|
105
|
-
throw new Error('the Windows SDK ' + sdk.build + ' package has no payloads');
|
|
106
|
-
log('Downloading the Windows SDK ' + sdk.build + ' (headers, libraries) ...');
|
|
107
|
-
const payload = (name) => sdkPackage.payloads.find((p) => p.fileName.toLowerCase() === ('installers\\' + name).toLowerCase());
|
|
108
|
-
const msis = [];
|
|
109
|
-
for (const name of SDK_MSIS) {
|
|
110
|
-
const p = payload(name);
|
|
111
|
-
if (!p)
|
|
112
|
-
throw new Error('the Windows SDK package has no ' + name);
|
|
113
|
-
const file = await fetchPayload(p);
|
|
114
|
-
msis.push(file);
|
|
115
|
-
for (const cab of msiCabs(fs.readFileSync(file))) {
|
|
116
|
-
const c = payload(cab);
|
|
117
|
-
if (c)
|
|
118
|
-
await fetchPayload(c);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
for (const msi of msis) {
|
|
122
|
-
// An administrative install only unpacks files; its verbose log explains a failure (e.g. a path over 260 characters).
|
|
123
|
-
const logFile = msi + '.log';
|
|
124
|
-
try {
|
|
125
|
-
await execAsync(system32('msiexec.exe'), ['/a', msi, '/quiet', '/qn', 'TARGETDIR=' + ROOT, '/l*v', logFile], { stdio: 'ignore' });
|
|
126
|
-
}
|
|
127
|
-
catch (e) {
|
|
128
|
-
const lines = exists(logFile) ? fs.readFileSync(logFile, 'utf16le').split(/\r?\n/).filter((l) => /error|return value 3|failed/i.test(l)).slice(-4).join(' | ') : '';
|
|
129
|
-
throw new Error(path.basename(msi) + ' did not unpack: ' + (e instanceof Error ? e.message : String(e)) + (lines ? ' (' + lines.slice(0, 600) + ')' : ''));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// msiexec /a also copies every .msi into the target; they are not needed.
|
|
133
|
-
for (const name of fs.readdirSync(ROOT).filter((n) => n.toLowerCase().endsWith('.msi')))
|
|
134
|
-
fs.rmSync(path.join(ROOT, name), { force: true });
|
|
135
|
-
safeRemove(work, ROOT);
|
|
136
|
-
const sdkVersion = fs.readdirSync(path.join(ROOT, 'Windows Kits', '10', 'Include')).filter((d) => d.startsWith('10.0.' + sdk.build)).sort().pop();
|
|
137
|
-
if (!sdkVersion)
|
|
138
|
-
throw new Error('the Windows SDK did not unpack (no Include\\10.0.' + sdk.build + '.*)');
|
|
139
|
-
// The tools folder is named after the toolset (14.44.35207), not the package version (14.44.17.14).
|
|
140
|
-
const toolsRoot = path.join(ROOT, 'VC', 'Tools', 'MSVC');
|
|
141
|
-
const tools = fs.readdirSync(toolsRoot).filter((d) => exists(path.join(toolsRoot, d, 'bin', 'Hostx64', 'x64', 'cl.exe'))).sort((a, b) => a.localeCompare(b, undefined, { numeric: true })).pop();
|
|
142
|
-
if (!tools)
|
|
143
|
-
throw new Error('MSVC ' + version + ' did not unpack (no cl.exe under VC\\Tools\\MSVC)');
|
|
144
|
-
return { msvc: tools, sdk: sdkVersion };
|
|
145
|
-
};
|
|
146
|
-
/** Variables vcvars64.bat would set for this tree (host x64, target x64). */
|
|
147
|
-
export const vcvars = (root, msvc, sdk) => {
|
|
148
|
-
const vc = path.join(root, 'VC', 'Tools', 'MSVC', msvc);
|
|
149
|
-
const kits = path.join(root, 'Windows Kits', '10');
|
|
150
|
-
const inc = (...p) => path.join(kits, 'Include', sdk, ...p);
|
|
151
|
-
const lib = (...p) => path.join(kits, 'Lib', sdk, ...p);
|
|
152
|
-
return {
|
|
153
|
-
vars: {
|
|
154
|
-
VSINSTALLDIR: root + '\\', VCINSTALLDIR: path.join(root, 'VC') + '\\', VCToolsInstallDir: vc + '\\', VCToolsVersion: msvc, VisualStudioVersion: '17.0',
|
|
155
|
-
WindowsSdkDir: kits + '\\', WindowsSDKVersion: sdk + '\\', WindowsSDKLibVersion: sdk + '\\', UniversalCRTSdkDir: kits + '\\', UCRTVersion: sdk,
|
|
156
|
-
VSCMD_ARG_HOST_ARCH: 'x64', VSCMD_ARG_TGT_ARCH: 'x64', Platform: 'x64',
|
|
157
|
-
INCLUDE: [path.join(vc, 'include'), inc('ucrt'), inc('shared'), inc('um'), inc('winrt'), inc('cppwinrt')].join(';'),
|
|
158
|
-
LIB: [path.join(vc, 'lib', 'x64'), lib('ucrt', 'x64'), lib('um', 'x64')].join(';'),
|
|
159
|
-
LIBPATH: [path.join(vc, 'lib', 'x64'), path.join(vc, 'lib', 'x86', 'store', 'references')].join(';'),
|
|
160
|
-
},
|
|
161
|
-
path: [path.join(vc, 'bin', 'Hostx64', 'x64'), path.join(kits, 'bin', sdk, 'x64')],
|
|
162
|
-
};
|
|
163
|
-
};
|
|
164
|
-
/** vcvars64.bat / vcvarsall.bat in the usual place, for scripts that `call` them. */
|
|
165
|
-
const writeVcvars = (env) => {
|
|
166
|
-
const dir = mkdirp(path.join(ROOT, 'VC', 'Auxiliary', 'Build'));
|
|
167
|
-
const lines = ['@echo off', 'rem Written by Windows Development Sandbox for its portable MSVC (host x64, target x64).',
|
|
168
|
-
...Object.entries(env.vars).map(([k, v]) => 'set "' + k + '=' + v + '"'), 'set "PATH=' + env.path.join(';') + ';%PATH%"', 'exit /b 0'];
|
|
169
|
-
fs.writeFileSync(path.join(dir, 'vcvars64.bat'), lines.join('\r\n') + '\r\n');
|
|
170
|
-
fs.writeFileSync(path.join(dir, 'vcvarsall.bat'), ['@echo off', 'rem Only x64 (amd64) is installed.', 'call "%~dp0vcvars64.bat"', 'exit /b %errorlevel%'].join('\r\n') + '\r\n');
|
|
171
|
-
};
|
|
172
|
-
/** vswhere.exe where Visual Studio's installer would put it, answering with this tree. */
|
|
173
|
-
const installVswhere = (msvc) => {
|
|
174
|
-
mkdirp(VSWHERE_DIR);
|
|
175
|
-
fs.copyFileSync(ensureCompiled('vswhere'), path.join(VSWHERE_DIR, 'vswhere.exe'));
|
|
176
|
-
const [major, minor] = msvc.split('.').slice(2);
|
|
177
|
-
fs.writeFileSync(path.join(VSWHERE_DIR, 'vswhere.json'), JSON.stringify({ installationPath: ROOT, installationVersion: '17.' + (minor ?? '0') + '.0.' + (major ?? '0') }));
|
|
178
|
-
};
|
|
179
|
-
/** The vcvars environment of an installed tree (for steps that run before the agent's environment exists). */
|
|
180
|
-
export const installedMsvcEnv = () => {
|
|
181
|
-
try {
|
|
182
|
-
const done = JSON.parse(fs.readFileSync(path.join(ROOT, '.installed.json'), 'utf8'));
|
|
183
|
-
return exists(path.join(ROOT, 'VC', 'Tools', 'MSVC', done.msvc, 'bin', 'Hostx64', 'x64', 'cl.exe')) ? vcvars(ROOT, done.msvc, done.sdk) : null;
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
return null;
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
export const setupMsvc = async (env, config) => {
|
|
190
|
-
if (!config.acceptLicense) {
|
|
191
|
-
throw new Error('MSVC is installed only with toolchains.msvc.acceptLicense = true: its use is governed by the Visual Studio licence terms (https://visualstudio.microsoft.com/license-terms/), which need a Visual Studio licence');
|
|
192
|
-
}
|
|
193
|
-
if (dryRun) {
|
|
194
|
-
log('(dry run) would provision MSVC ' + config.msvcVersion + ' and Windows SDK ' + config.sdkVersion);
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
const marker = path.join(ROOT, '.installed.json');
|
|
198
|
-
const want = config.msvcVersion + '/' + config.sdkVersion;
|
|
199
|
-
let done = exists(marker) ? JSON.parse(fs.readFileSync(marker, 'utf8')) : null;
|
|
200
|
-
if (!done || done.want !== want || !exists(path.join(ROOT, 'VC', 'Tools', 'MSVC', done.msvc, 'bin', 'Hostx64', 'x64', 'cl.exe'))) {
|
|
201
|
-
log('Installing MSVC and the Windows SDK (~1-2 GB, once; licence accepted in toolchains.msvc.acceptLicense) ...');
|
|
202
|
-
// A previous attempt's verified downloads (.download) are kept; everything it unpacked is redone.
|
|
203
|
-
if (exists(ROOT))
|
|
204
|
-
for (const name of fs.readdirSync(ROOT).filter((n) => n !== '.manifest.json' && n !== '.download'))
|
|
205
|
-
safeRemove(path.join(ROOT, name), ROOT);
|
|
206
|
-
const installed = await install(config);
|
|
207
|
-
done = { ...installed, want };
|
|
208
|
-
fs.writeFileSync(marker, JSON.stringify(done, null, 2));
|
|
209
|
-
}
|
|
210
|
-
const vc = vcvars(ROOT, done.msvc, done.sdk);
|
|
211
|
-
writeVcvars(vc);
|
|
212
|
-
installVswhere(done.msvc);
|
|
213
|
-
Object.assign(env.vars, vc.vars);
|
|
214
|
-
env.prepend.push(...vc.path);
|
|
215
|
-
env.summary.push('msvc: ' + done.msvc + ', Windows SDK ' + done.sdk + ' (cl, link; vcvars64.bat and vswhere work)');
|
|
216
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Toolchains } from '../../core/types.js';
|
|
2
|
-
import { type ToolEnv } from './common.js';
|
|
3
|
-
/** MinGW-w64 GCC from WinLibs: gcc/g++/mingw32-make for the agent, and the linker for Rust's GNU host. */
|
|
4
|
-
export declare const setupCpp: (env: ToolEnv, config: Toolchains["cpp"]) => Promise<void>;
|
|
5
|
-
/**
|
|
6
|
-
* Mesa 3D for Windows (llvmpipe): OpenGL 4.5 on the CPU when the sandbox has no GPU. Windows only offers OpenGL 1.1 in
|
|
7
|
-
* software, and opengl32.dll cannot be replaced system-wide, so programs pick Mesa up from their own folder.
|
|
8
|
-
*/
|
|
9
|
-
export declare const setupMesa: (env: ToolEnv, config: Toolchains["mesa"]) => Promise<void>;
|
|
10
|
-
export declare const setupRust: (env: ToolEnv, config: Toolchains["rust"], refresh: boolean) => Promise<void>;
|
|
11
|
-
/** .NET SDK channels from config plus whatever the workspace's global.json pins. Installs are remembered in a marker. */
|
|
12
|
-
export declare const setupDotnet: (env: ToolEnv, config: Toolchains["dotnet"], refresh: boolean) => Promise<void>;
|