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
|
@@ -5,6 +5,7 @@ import { fetchJson, installArchive } from '../../shared/download.js';
|
|
|
5
5
|
import { dryRun, execAsync, exists, log, mkdirp } from '../env.js';
|
|
6
6
|
import { resolveCached, tool } from './common.js';
|
|
7
7
|
import { pickPackageVersion } from './versions.js';
|
|
8
|
+
import { duringSession } from '../project-context.js';
|
|
8
9
|
const installPython = async (pkg, spec) => {
|
|
9
10
|
const version = await resolveCached(pkg + ':' + spec, async () => {
|
|
10
11
|
const { versions } = await fetchJson('https://api.nuget.org/v3-flatcontainer/' + pkg + '/index.json');
|
|
@@ -13,21 +14,47 @@ const installPython = async (pkg, spec) => {
|
|
|
13
14
|
const dir = tool('python', pkg + '-' + version);
|
|
14
15
|
const exe = path.join(dir, 'python.exe');
|
|
15
16
|
if (!exists(exe)) {
|
|
16
|
-
log('Downloading ' +
|
|
17
|
+
log('Downloading Python ' + version + (pkg === 'python2' ? ' (Python 2, ' : ' (') + '~30 MB once) ...');
|
|
17
18
|
await installArchive('https://api.nuget.org/v3-flatcontainer/' + pkg + '/' + version + '/' + pkg + '.' + version + '.nupkg', dir, { locate: 'python.exe', fileName: pkg + '.' + version + '.zip' });
|
|
18
19
|
}
|
|
19
20
|
if (!exists(path.join(dir, 'Scripts', 'pip.exe')) && !exists(path.join(dir, 'Scripts', 'pip2.exe')))
|
|
20
21
|
await execAsync(exe, ['-m', 'ensurepip', '--default-pip'], { stdio: 'ignore' });
|
|
21
22
|
return dir;
|
|
22
23
|
};
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The shims folder: tools\shims at boot. A project added later gets one per Python version (tools\shims\<version>)
|
|
26
|
+
* so the boot project's python3.cmd keeps pointing at its own version.
|
|
27
|
+
*/
|
|
28
|
+
const shimDir = (dir) => (duringSession() ? tool('shims', path.basename(dir)) : tool('shims'));
|
|
29
|
+
/** Writes `<name>.cmd` into the shims folder, e.g. python2.cmd. */
|
|
30
|
+
const shim = (folder, name, command) => {
|
|
31
|
+
fs.writeFileSync(path.join(mkdirp(folder), name + '.cmd'), '@echo off\r\n' + command + ' %*\r\n');
|
|
26
32
|
};
|
|
27
|
-
const shimPair = (version, dir) => {
|
|
33
|
+
const shimPair = (folder, version, dir) => {
|
|
28
34
|
const python = '"' + path.join(dir, 'python.exe') + '"';
|
|
29
|
-
shim('python' + version, python);
|
|
30
|
-
shim('pip' + version, python + ' -m pip');
|
|
35
|
+
shim(folder, 'python' + version, python);
|
|
36
|
+
shim(folder, 'pip' + version, python + ' -m pip');
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* `py` like the Python launcher Windows installs: `py -3 x.py`, `py -3.12 ...`, `py -2 ...`, `py x.py`. The launcher
|
|
40
|
+
* itself is not portable, so py.cmd runs a small script that picks the interpreter (cmd's %* ignores shift).
|
|
41
|
+
*/
|
|
42
|
+
const pyLauncher = (folder, py3, py2) => {
|
|
43
|
+
const script = path.join(mkdirp(folder), 'py-launcher.py');
|
|
44
|
+
fs.writeFileSync(script, [
|
|
45
|
+
'import subprocess, sys',
|
|
46
|
+
'PY3, PY2 = ' + JSON.stringify(path.join(py3, 'python.exe')) + ', ' + JSON.stringify(py2 ? path.join(py2, 'python.exe') : null),
|
|
47
|
+
'args = sys.argv[1:]',
|
|
48
|
+
'exe = PY3',
|
|
49
|
+
"if args and args[0].startswith('-2'):",
|
|
50
|
+
' if not PY2: sys.exit("py: Python 2 is not installed (toolchains.python.python2)")',
|
|
51
|
+
' exe, args = PY2, args[1:]',
|
|
52
|
+
"elif args and (args[0] == '-3' or args[0].startswith('-3.') or args[0].startswith('-3-')):",
|
|
53
|
+
' args = args[1:]',
|
|
54
|
+
'sys.exit(subprocess.call([exe] + args))',
|
|
55
|
+
'',
|
|
56
|
+
].join('\n'));
|
|
57
|
+
shim(folder, 'py', '"' + path.join(py3, 'python.exe') + '" "' + script + '"');
|
|
31
58
|
};
|
|
32
59
|
export const setupPython = async (env, config, versions) => {
|
|
33
60
|
if (dryRun) {
|
|
@@ -35,13 +62,17 @@ export const setupPython = async (env, config, versions) => {
|
|
|
35
62
|
return;
|
|
36
63
|
}
|
|
37
64
|
const py3 = await installPython('python', versions.python.spec);
|
|
38
|
-
|
|
39
|
-
|
|
65
|
+
const shims = shimDir(py3);
|
|
66
|
+
shimPair(shims, '3', py3);
|
|
67
|
+
env.prepend.push(py3, path.join(py3, 'Scripts'), shims);
|
|
40
68
|
env.vars.PYTHONIOENCODING = 'utf-8';
|
|
41
|
-
env.summary.push('python: ' + path.basename(py3).replace('python-', '') + ' (from ' + versions.python.source + ')');
|
|
42
|
-
if (!config.python2)
|
|
69
|
+
env.summary.push('python: ' + path.basename(py3).replace('python-', '') + ' (from ' + versions.python.source + '; py works too)');
|
|
70
|
+
if (!config.python2) {
|
|
71
|
+
pyLauncher(shims, py3, null);
|
|
43
72
|
return;
|
|
73
|
+
}
|
|
44
74
|
const py2 = await installPython('python2', '2.7');
|
|
45
|
-
shimPair('2', py2);
|
|
75
|
+
shimPair(shims, '2', py2);
|
|
76
|
+
pyLauncher(shims, py3, py2);
|
|
46
77
|
env.summary.push('python2: ' + path.basename(py2).replace('python2-', ''));
|
|
47
78
|
};
|
|
@@ -7,6 +7,8 @@ export interface SingleExeOptions {
|
|
|
7
7
|
versionArgs?: string[];
|
|
8
8
|
/** Appended to the summary line, e.g. " (PowerShell 7)". */
|
|
9
9
|
note?: string;
|
|
10
|
+
/** Rough download size for the progress line, e.g. "35 MB". */
|
|
11
|
+
size?: string;
|
|
10
12
|
}
|
|
11
13
|
/** A tool from one GitHub release archive, into `dir` (atomically), on PATH. */
|
|
12
14
|
export declare const setupSingleExe: (env: ToolEnv, name: string, repo: string, pattern: RegExp, exeName: string, dir: string, options?: SingleExeOptions) => Promise<void>;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// Bun, uv and Deno: single-binary tools from GitHub releases (claude-mem needs Bun and uv).
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { githubAsset, installArchive } from '../../shared/download.js';
|
|
4
3
|
import { dryRun, exists, localDir, log } from '../env.js';
|
|
5
|
-
import { arch, tool, versionOf } from './common.js';
|
|
4
|
+
import { arch, installFromGithub, tool, versionOf } from './common.js';
|
|
6
5
|
/** A tool from one GitHub release archive, into `dir` (atomically), on PATH. */
|
|
7
6
|
export const setupSingleExe = async (env, name, repo, pattern, exeName, dir, options = {}) => {
|
|
8
7
|
if (dryRun) {
|
|
@@ -12,9 +11,8 @@ export const setupSingleExe = async (env, name, repo, pattern, exeName, dir, opt
|
|
|
12
11
|
const bin = options.subdir ? path.join(dir, options.subdir) : dir;
|
|
13
12
|
const exe = path.join(bin, exeName);
|
|
14
13
|
if (!exists(exe) || options.refresh) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
await installArchive(asset.url, dir, { sha256: asset.sha256, fileName: asset.name, ...(options.subdir ? {} : { locate: exeName }) });
|
|
14
|
+
const size = options.size ? ', ~' + options.size : '';
|
|
15
|
+
await installFromGithub(repo, pattern, { dest: dir, what: (a) => name + ' (' + a.name + size + ' once)', ...(options.subdir ? {} : { locate: exeName }) });
|
|
18
16
|
}
|
|
19
17
|
if (!exists(exe))
|
|
20
18
|
throw new Error(exeName + ' missing after installing ' + name);
|
|
@@ -22,19 +20,19 @@ export const setupSingleExe = async (env, name, repo, pattern, exeName, dir, opt
|
|
|
22
20
|
env.summary.push(name + ': ' + versionOf(exe, options.versionArgs) + (options.note ?? ''));
|
|
23
21
|
};
|
|
24
22
|
export const setupBun = async (env) => {
|
|
25
|
-
await setupSingleExe(env, 'bun', 'oven-sh/bun', arch === 'arm64' ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/, 'bun.exe', tool('bun', 'bin'));
|
|
23
|
+
await setupSingleExe(env, 'bun', 'oven-sh/bun', arch === 'arm64' ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/, 'bun.exe', tool('bun', 'bin'), { size: '35 MB' });
|
|
26
24
|
// Bun cannot keep its cache or temp files on a mapped folder (EINVAL); they go to the sandbox's own disk.
|
|
27
25
|
Object.assign(env.vars, { BUN_INSTALL: tool('bun'), BUN_INSTALL_CACHE_DIR: path.join(localDir, 'bun-cache'), BUN_TMPDIR: path.join(localDir, 'bun-tmp') });
|
|
28
26
|
};
|
|
29
27
|
export const setupDeno = async (env) => {
|
|
30
|
-
await setupSingleExe(env, 'deno', 'denoland/deno', arch === 'arm64' ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/, 'deno.exe', tool('deno', 'bin'));
|
|
28
|
+
await setupSingleExe(env, 'deno', 'denoland/deno', arch === 'arm64' ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/, 'deno.exe', tool('deno', 'bin'), { size: '40 MB' });
|
|
31
29
|
// `deno install` puts commands in DENO_INSTALL_ROOT/bin: the folder deno.exe is in, already on PATH.
|
|
32
30
|
Object.assign(env.vars, { DENO_DIR: tool('deno-cache'), DENO_INSTALL_ROOT: tool('deno'), DENO_NO_UPDATE_CHECK: '1' });
|
|
33
31
|
};
|
|
34
32
|
/** Where uv keeps its cache, Pythons and tools (persistent). */
|
|
35
33
|
export const uvVars = () => ({ UV_CACHE_DIR: tool('uv-cache'), UV_PYTHON_INSTALL_DIR: tool('uv-python'), UV_TOOL_DIR: tool('uv-tools'), UV_TOOL_BIN_DIR: tool('uv-bin') });
|
|
36
34
|
export const setupUv = async (env) => {
|
|
37
|
-
await setupSingleExe(env, 'uv', 'astral-sh/uv', arch === 'arm64' ? /^uv-aarch64-pc-windows-msvc\.zip$/ : /^uv-x86_64-pc-windows-msvc\.zip$/, 'uv.exe', tool('uv'));
|
|
35
|
+
await setupSingleExe(env, 'uv', 'astral-sh/uv', arch === 'arm64' ? /^uv-aarch64-pc-windows-msvc\.zip$/ : /^uv-x86_64-pc-windows-msvc\.zip$/, 'uv.exe', tool('uv'), { size: '20 MB' });
|
|
38
36
|
Object.assign(env.vars, uvVars());
|
|
39
37
|
env.prepend.push(tool('uv-bin'));
|
|
40
38
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// PHP from windows.php.net, with Composer. Composer's global packages live in persistent storage.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fetchJson, fetchText, installArchive } from '../../../shared/download.js';
|
|
5
|
+
import { dryRun, execOutput, exists, log, mkdirp } from '../../env.js';
|
|
6
|
+
import { downloadFile, resolveCached, tool, versionFromFiles } from '../common.js';
|
|
7
|
+
import { pickPackageVersion } from '../versions.js';
|
|
8
|
+
import { setupVcRuntime } from './vcruntime.js';
|
|
9
|
+
const PHP_EXTENSIONS = ['curl', 'fileinfo', 'gd', 'intl', 'mbstring', 'openssl', 'pdo_mysql', 'pdo_pgsql', 'pdo_sqlite', 'sodium', 'sqlite3', 'zip'];
|
|
10
|
+
const COMPOSER = 'https://getcomposer.org/download/latest-stable/composer.phar';
|
|
11
|
+
/** The non-thread-safe x64 zip of the newest release matching `spec` ("8" -> newest 8.x, "8.3" -> newest 8.3.x). */
|
|
12
|
+
const phpBuild = async (spec) => {
|
|
13
|
+
const releases = await fetchJson('https://windows.php.net/downloads/releases/releases.json');
|
|
14
|
+
const pick = pickPackageVersion(Object.values(releases).map((r) => r.version), spec);
|
|
15
|
+
const release = Object.values(releases).find((r) => r.version === pick);
|
|
16
|
+
const build = release && Object.entries(release).find(([key, value]) => /^nts-vs\d+-x64$/.test(key) && typeof value === 'object' && value.zip)?.[1];
|
|
17
|
+
if (!release || typeof build !== 'object' || !build.zip)
|
|
18
|
+
throw new Error('No PHP build for Windows matches "' + spec + '"');
|
|
19
|
+
return { version: release.version, ...build.zip };
|
|
20
|
+
};
|
|
21
|
+
/** php.ini from the development template with the common extensions switched on (written whole, then renamed). */
|
|
22
|
+
const writePhpIni = (home) => {
|
|
23
|
+
const ini = path.join(home, 'php.ini');
|
|
24
|
+
if (exists(ini) || !exists(path.join(home, 'php.ini-development')))
|
|
25
|
+
return;
|
|
26
|
+
let text = fs.readFileSync(path.join(home, 'php.ini-development'), 'utf8')
|
|
27
|
+
.replace(/^;\s*extension_dir\s*=\s*"ext"/m, 'extension_dir = "' + path.join(home, 'ext') + '"');
|
|
28
|
+
for (const ext of PHP_EXTENSIONS.filter((e) => exists(path.join(home, 'ext', 'php_' + e + '.dll'))))
|
|
29
|
+
text = text.replace(new RegExp('^;(extension=' + ext + ')\\s*$', 'm'), '$1');
|
|
30
|
+
fs.writeFileSync(ini + '.tmp', text);
|
|
31
|
+
fs.renameSync(ini + '.tmp', ini);
|
|
32
|
+
};
|
|
33
|
+
/** Writes `<name>.cmd` into tools\shims (on PATH). */
|
|
34
|
+
const shim = (env, name, command) => {
|
|
35
|
+
fs.writeFileSync(path.join(mkdirp(tool('shims')), name + '.cmd'), '@echo off\r\n' + command + ' %*\r\n');
|
|
36
|
+
env.prepend.push(tool('shims'));
|
|
37
|
+
};
|
|
38
|
+
const setupComposer = async (env, php) => {
|
|
39
|
+
const phar = tool('composer', 'composer.phar');
|
|
40
|
+
if (!exists(phar)) {
|
|
41
|
+
log('Downloading Composer (~3 MB once) ...');
|
|
42
|
+
const sha256 = (await fetchText(COMPOSER + '.sha256sum')).trim().split(/\s+/)[0];
|
|
43
|
+
await downloadFile(COMPOSER, phar, sha256);
|
|
44
|
+
}
|
|
45
|
+
const composerHome = tool('composer-home');
|
|
46
|
+
env.vars.COMPOSER_HOME = composerHome;
|
|
47
|
+
env.prepend.push(path.join(composerHome, 'vendor', 'bin'));
|
|
48
|
+
shim(env, 'composer', '"' + php + '" "' + phar + '"');
|
|
49
|
+
env.summary.push('composer: ' + (/\d+\.\d+\.\d+/.exec(execOutput(php, [phar, '--version', '--no-ansi']))?.[0] ?? 'installed'));
|
|
50
|
+
};
|
|
51
|
+
export const setupPhp = async (env, config) => {
|
|
52
|
+
const wantedSpec = versionFromFiles(['.php-version']) ?? { spec: config.version, source: 'config' };
|
|
53
|
+
if (dryRun) {
|
|
54
|
+
log('(dry run) would provision PHP ' + wantedSpec.spec + (config.composer ? ' + Composer' : ''));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// No summary line of its own: the Visual C++ runtime step (which runs first) already reports it.
|
|
58
|
+
await setupVcRuntime(env, false);
|
|
59
|
+
const version = await resolveCached('php:' + wantedSpec.spec, async () => (await phpBuild(wantedSpec.spec)).version);
|
|
60
|
+
const home = tool('php', version);
|
|
61
|
+
if (!exists(path.join(home, 'php.exe'))) {
|
|
62
|
+
const build = await phpBuild(version);
|
|
63
|
+
log('Downloading PHP ' + version + ' (~30 MB once) ...');
|
|
64
|
+
await installArchive('https://windows.php.net/downloads/releases/' + build.path, home, { sha256: build.sha256, locate: 'php.exe', fileName: build.path });
|
|
65
|
+
}
|
|
66
|
+
writePhpIni(home);
|
|
67
|
+
env.prepend.push(home);
|
|
68
|
+
env.summary.push('php: ' + version + ' (from ' + wantedSpec.source + ')');
|
|
69
|
+
if (config.composer)
|
|
70
|
+
await setupComposer(env, path.join(home, 'php.exe'));
|
|
71
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Ruby from RubyInstaller. Gems live in persistent storage.
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fetchJson, installArchive } from '../../../shared/download.js';
|
|
4
|
+
import { SYSTEM } from '../../../shared/system.js';
|
|
5
|
+
import { dryRun, execAsync, exists, log } from '../../env.js';
|
|
6
|
+
import { installOnce, resolveCached, tool, versionFromFiles, versionOf } from '../common.js';
|
|
7
|
+
import { pickPackageVersion } from '../versions.js';
|
|
8
|
+
const RUBY_ASSET = /^rubyinstaller-(\d+\.\d+\.\d+)-(\d+)-x64\.7z$/;
|
|
9
|
+
/** The build number after the version in a RubyInstaller file name (rubyinstaller-3.3.1-1-x64.7z -> 1). */
|
|
10
|
+
const buildNumber = (asset) => Number(RUBY_ASSET.exec(asset.name)?.[2] ?? 0);
|
|
11
|
+
/** RubyInstaller builds per Ruby version (newest build of each), from its GitHub releases. */
|
|
12
|
+
const rubyBuilds = async () => {
|
|
13
|
+
const releases = await fetchJson('https://api.github.com/repos/oneclick/rubyinstaller2/releases?per_page=100');
|
|
14
|
+
const builds = new Map();
|
|
15
|
+
for (const asset of releases.filter((r) => !r.draft && !r.prerelease).flatMap((r) => r.assets)) {
|
|
16
|
+
const version = RUBY_ASSET.exec(asset.name)?.[1];
|
|
17
|
+
if (!version)
|
|
18
|
+
continue;
|
|
19
|
+
const known = builds.get(version);
|
|
20
|
+
if (!known || buildNumber(known) < buildNumber(asset))
|
|
21
|
+
builds.set(version, asset);
|
|
22
|
+
}
|
|
23
|
+
return builds;
|
|
24
|
+
};
|
|
25
|
+
const sha256Of = (asset) => (asset.digest?.startsWith('sha256:') ? asset.digest.slice(7) : null);
|
|
26
|
+
export const setupRuby = async (env, config) => {
|
|
27
|
+
const wantedSpec = versionFromFiles(['.ruby-version']) ?? { spec: config.version, source: 'config' };
|
|
28
|
+
if (dryRun) {
|
|
29
|
+
log('(dry run) would provision Ruby ' + wantedSpec.spec);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const version = await resolveCached('ruby:' + wantedSpec.spec, async () => pickPackageVersion([...(await rubyBuilds()).keys()], wantedSpec.spec) ?? Promise.reject(new Error('No RubyInstaller build matches "' + wantedSpec.spec + '"')));
|
|
33
|
+
const home = tool('ruby', version);
|
|
34
|
+
if (!exists(path.join(home, 'bin', 'ruby.exe'))) {
|
|
35
|
+
const asset = (await rubyBuilds()).get(version);
|
|
36
|
+
if (!asset)
|
|
37
|
+
throw new Error('RubyInstaller ' + version + ' is no longer published');
|
|
38
|
+
log('Downloading Ruby ' + version + ' (~100 MB once) ...');
|
|
39
|
+
await installArchive(asset.browser_download_url, home, { sha256: sha256Of(asset), locate: 'ruby.exe', up: 1, fileName: asset.name });
|
|
40
|
+
}
|
|
41
|
+
const gems = tool('ruby-gems', version.split('.').slice(0, 2).join('.'));
|
|
42
|
+
Object.assign(env.vars, { GEM_HOME: gems, BUNDLE_USER_HOME: tool('bundle-home') });
|
|
43
|
+
env.prepend.push(path.join(home, 'bin'), path.join(gems, 'bin'));
|
|
44
|
+
env.summary.push('ruby: ' + versionOf(path.join(home, 'bin', 'ruby.exe')) + ' (from ' + wantedSpec.source + '; gems with C extensions need MSYS2, not included)');
|
|
45
|
+
const gem = path.join(home, 'bin', 'gem.cmd');
|
|
46
|
+
await installOnce(env, 'gem@' + version, config.gems, (pkg) => execAsync(SYSTEM.cmd(), ['/d', '/c', gem, 'install', pkg, '--no-document'], { env: { ...process.env, GEM_HOME: gems } }));
|
|
47
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ToolEnv } from '../common.js';
|
|
2
|
+
/**
|
|
3
|
+
* A real installer (it writes to System32), so it runs on every boot; the installer itself is kept in persistent
|
|
4
|
+
* storage and only run when Microsoft's signature on it checks out. Resolves true when this call ran the installer.
|
|
5
|
+
* Only the "Visual C++ runtime" step reports it (`summary`); PHP calls it again just to be sure.
|
|
6
|
+
*/
|
|
7
|
+
export declare const setupVcRuntime: (env: ToolEnv, summary?: boolean) => Promise<boolean>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// The Visual C++ runtime (vcruntime140.dll & co.) that PHP and other native tools need.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnAsync } from '../../../shared/download.js';
|
|
5
|
+
import { SYSTEM } from '../../../shared/system.js';
|
|
6
|
+
import { dryRun, execOutput, exists, log } from '../../env.js';
|
|
7
|
+
import { downloadFile, tool } from '../common.js';
|
|
8
|
+
const VC_REDIST = 'https://aka.ms/vs/17/release/vc_redist.x64.exe';
|
|
9
|
+
const MICROSOFT_SIGNER = 'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US';
|
|
10
|
+
/** 1638: a newer version is already installed; 3010: installed, a restart would finish it (not needed for the DLLs). */
|
|
11
|
+
const OK_EXIT_CODES = [0, 1638, 3010];
|
|
12
|
+
/** The subject of a valid Authenticode signature, or '' when the file is unsigned or tampered with. */
|
|
13
|
+
const signerOf = (file) => execOutput(SYSTEM.powershell(), ['-NoLogo', '-NoProfile', '-Command',
|
|
14
|
+
"$s = Get-AuthenticodeSignature -LiteralPath '" + file.replace(/'/g, "''") + "'; if ($s.Status -eq 'Valid') { $s.SignerCertificate.Subject }"]).trim();
|
|
15
|
+
/**
|
|
16
|
+
* A real installer (it writes to System32), so it runs on every boot; the installer itself is kept in persistent
|
|
17
|
+
* storage and only run when Microsoft's signature on it checks out. Resolves true when this call ran the installer.
|
|
18
|
+
* Only the "Visual C++ runtime" step reports it (`summary`); PHP calls it again just to be sure.
|
|
19
|
+
*/
|
|
20
|
+
export const setupVcRuntime = async (env, summary = true) => {
|
|
21
|
+
if (dryRun) {
|
|
22
|
+
log('(dry run) would install the Visual C++ runtime');
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const system32 = path.join(process.env.WINDIR ?? 'C:\\Windows', 'System32');
|
|
26
|
+
const missing = !exists(path.join(system32, 'vcruntime140.dll')) || !exists(path.join(system32, 'msvcp140.dll'));
|
|
27
|
+
if (missing) {
|
|
28
|
+
const installer = tool('vcredist', 'vc_redist.x64.exe');
|
|
29
|
+
if (!exists(installer)) {
|
|
30
|
+
log('Downloading the Visual C++ runtime (~25 MB once) ...');
|
|
31
|
+
await downloadFile(VC_REDIST, installer);
|
|
32
|
+
}
|
|
33
|
+
if (signerOf(installer) !== MICROSOFT_SIGNER) {
|
|
34
|
+
fs.rmSync(installer, { force: true });
|
|
35
|
+
throw new Error('vc_redist.x64.exe is not signed by Microsoft; deleted it (it is downloaded again next boot)');
|
|
36
|
+
}
|
|
37
|
+
log('Installing the Visual C++ runtime ...');
|
|
38
|
+
const code = await spawnAsync(installer, ['/install', '/quiet', '/norestart']);
|
|
39
|
+
if (!OK_EXIT_CODES.includes(code ?? -1) || !exists(path.join(system32, 'vcruntime140.dll')))
|
|
40
|
+
throw new Error('the Visual C++ runtime installer failed (exit ' + code + ')');
|
|
41
|
+
}
|
|
42
|
+
if (summary)
|
|
43
|
+
env.summary.push('vc++ runtime: installed');
|
|
44
|
+
return missing;
|
|
45
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Where the sandbox's tools are (absent = not installed). */
|
|
2
|
+
export interface ToolPaths {
|
|
3
|
+
javaHome?: string;
|
|
4
|
+
python?: string;
|
|
5
|
+
goRoot?: string;
|
|
6
|
+
go?: string;
|
|
7
|
+
gcc?: string;
|
|
8
|
+
cl?: string;
|
|
9
|
+
cmake?: string;
|
|
10
|
+
dotnet?: string;
|
|
11
|
+
node?: string;
|
|
12
|
+
pwsh?: string;
|
|
13
|
+
git?: string;
|
|
14
|
+
bash?: string;
|
|
15
|
+
php?: string;
|
|
16
|
+
ruby?: string;
|
|
17
|
+
deno?: string;
|
|
18
|
+
}
|
|
19
|
+
/** User settings for the sandbox's VS Code. Only keys with a value are set; the caller removes the ones it set before. */
|
|
20
|
+
export declare const vscodeSettings: (p: ToolPaths) => Record<string, unknown>;
|
|
21
|
+
export declare const EXTENSION_ID: RegExp;
|
|
22
|
+
/** The extensions to have: always EditorConfig, then per toolchain and database in use, the project's, and yours. */
|
|
23
|
+
export declare const vscodeExtensions: (o: {
|
|
24
|
+
toolchains: string[];
|
|
25
|
+
databases: string[];
|
|
26
|
+
recommended: string[];
|
|
27
|
+
extra: string[];
|
|
28
|
+
}) => string[];
|
|
29
|
+
/** Extensions not installed yet, from the names of the folders in VS Code's extensions folder (publisher.name-1.2.3). */
|
|
30
|
+
export declare const missingExtensions: (wanted: string[], folders: string[]) => string[];
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// What VS Code is told about the sandbox: the settings that point it at the sandbox's own tools, and the extensions
|
|
2
|
+
// for the languages in use. Pure (tested); vscode.ts finds the paths and writes them.
|
|
3
|
+
/** The JDK's major version from its folder name (jdk-21.0.5+11 -> 21). */
|
|
4
|
+
const javaMajor = (home) => /(?:jdk|jre)?-?(\d{1,2})(?:[.+_-]|$)/i.exec(home.split(/[\\/]/).pop() ?? '')?.[1];
|
|
5
|
+
/** User settings for the sandbox's VS Code. Only keys with a value are set; the caller removes the ones it set before. */
|
|
6
|
+
export const vscodeSettings = (p) => {
|
|
7
|
+
const profiles = {};
|
|
8
|
+
if (p.pwsh)
|
|
9
|
+
profiles['PowerShell 7'] = { path: p.pwsh, args: ['-NoLogo'] };
|
|
10
|
+
if (p.bash)
|
|
11
|
+
profiles['Git Bash'] = { path: p.bash, args: ['--login', '-i'] };
|
|
12
|
+
const settings = {
|
|
13
|
+
'telemetry.telemetryLevel': 'off',
|
|
14
|
+
'update.mode': 'none',
|
|
15
|
+
'workbench.startupEditor': 'none',
|
|
16
|
+
'git.path': p.git,
|
|
17
|
+
'terminal.integrated.profiles.windows': Object.keys(profiles).length ? profiles : undefined,
|
|
18
|
+
'terminal.integrated.defaultProfile.windows': p.pwsh ? 'PowerShell 7' : undefined,
|
|
19
|
+
'python.defaultInterpreterPath': p.python,
|
|
20
|
+
'java.jdt.ls.java.home': p.javaHome,
|
|
21
|
+
'java.configuration.runtimes': p.javaHome ? [{ name: 'JavaSE-' + (javaMajor(p.javaHome) ?? '21'), path: p.javaHome, default: true }] : undefined,
|
|
22
|
+
'maven.terminal.useJavaHome': p.javaHome ? true : undefined,
|
|
23
|
+
'go.goroot': p.goRoot,
|
|
24
|
+
'go.alternateTools': p.go ? { go: p.go } : undefined,
|
|
25
|
+
'C_Cpp.default.compilerPath': p.cl ?? p.gcc,
|
|
26
|
+
'cmake.cmakePath': p.cmake,
|
|
27
|
+
'dotnet.dotnetPath': p.dotnet ? p.dotnet.replace(/[\\/]dotnet\.exe$/i, '') : undefined,
|
|
28
|
+
'dotnetAcquisitionExtension.existingDotnetPath': p.dotnet ? [{ extensionId: 'ms-dotnettools.csharp', path: p.dotnet }] : undefined,
|
|
29
|
+
'php.validate.executablePath': p.php,
|
|
30
|
+
'php.debug.executablePath': p.php,
|
|
31
|
+
'rubyLsp.rubyVersionManager': p.ruby ? { identifier: 'none' } : undefined,
|
|
32
|
+
'deno.path': p.deno,
|
|
33
|
+
'powershell.powerShellAdditionalExePaths': p.pwsh ? { 'PowerShell 7 (sandbox)': p.pwsh } : undefined,
|
|
34
|
+
'npm.packageManager': 'auto',
|
|
35
|
+
};
|
|
36
|
+
return Object.fromEntries(Object.entries(settings).filter(([, v]) => v !== undefined));
|
|
37
|
+
};
|
|
38
|
+
/** Extensions per toolchain (Marketplace ids). */
|
|
39
|
+
const BY_TOOLCHAIN = {
|
|
40
|
+
node: ['dbaeumer.vscode-eslint', 'esbenp.prettier-vscode'],
|
|
41
|
+
python: ['ms-python.python', 'ms-python.debugpy'],
|
|
42
|
+
java: ['redhat.java', 'vscjava.vscode-java-debug', 'vscjava.vscode-java-test', 'vscjava.vscode-maven', 'vscjava.vscode-gradle'],
|
|
43
|
+
go: ['golang.go'],
|
|
44
|
+
rust: ['rust-lang.rust-analyzer', 'vadimcn.vscode-lldb'],
|
|
45
|
+
cpp: ['ms-vscode.cpptools', 'ms-vscode.cmake-tools'],
|
|
46
|
+
msvc: ['ms-vscode.cpptools', 'ms-vscode.cmake-tools'],
|
|
47
|
+
dotnet: ['ms-dotnettools.csharp'],
|
|
48
|
+
ruby: ['shopify.ruby-lsp'],
|
|
49
|
+
php: ['bmewburn.vscode-intelephense-client', 'xdebug.php-debug'],
|
|
50
|
+
deno: ['denoland.vscode-deno'],
|
|
51
|
+
pwsh: ['ms-vscode.powershell'],
|
|
52
|
+
};
|
|
53
|
+
const BY_DATABASE = {
|
|
54
|
+
postgres: ['mtxr.sqltools', 'mtxr.sqltools-driver-pg'],
|
|
55
|
+
mysql: ['mtxr.sqltools', 'mtxr.sqltools-driver-mysql'],
|
|
56
|
+
mongodb: ['mongodb.mongodb-vscode'],
|
|
57
|
+
redis: ['redis.redis-for-vscode'],
|
|
58
|
+
};
|
|
59
|
+
export const EXTENSION_ID = /^[\w-]+\.[\w-]+$/;
|
|
60
|
+
/** The extensions to have: always EditorConfig, then per toolchain and database in use, the project's, and yours. */
|
|
61
|
+
export const vscodeExtensions = (o) => {
|
|
62
|
+
const all = ['editorconfig.editorconfig', ...o.toolchains.flatMap((t) => BY_TOOLCHAIN[t] ?? []), ...o.databases.flatMap((d) => BY_DATABASE[d] ?? []), ...o.recommended, ...o.extra];
|
|
63
|
+
return [...new Set(all.map((e) => e.toLowerCase()))].filter((e) => EXTENSION_ID.test(e));
|
|
64
|
+
};
|
|
65
|
+
/** Extensions not installed yet, from the names of the folders in VS Code's extensions folder (publisher.name-1.2.3). */
|
|
66
|
+
export const missingExtensions = (wanted, folders) => {
|
|
67
|
+
const have = folders.map((f) => f.toLowerCase());
|
|
68
|
+
return wanted.filter((id) => !have.some((f) => f.startsWith(id + '-')));
|
|
69
|
+
};
|
|
@@ -1,2 +1,19 @@
|
|
|
1
|
+
import type { Toolchains } from '../../core/types.js';
|
|
1
2
|
import { type ToolEnv } from './common.js';
|
|
3
|
+
/**
|
|
4
|
+
* After every toolchain is installed: points VS Code at the sandbox's own JDK, Python, Go, compilers, .NET, Git and
|
|
5
|
+
* terminals (user settings; only the keys this tool manages are changed, your own stay), and installs the extensions
|
|
6
|
+
* for the languages in use in the background (they persist, so only new ones are downloaded).
|
|
7
|
+
*/
|
|
8
|
+
export declare const configureVscode: (tools: {
|
|
9
|
+
vars: Record<string, string>;
|
|
10
|
+
prepend: string[];
|
|
11
|
+
append: string[];
|
|
12
|
+
summary: string[];
|
|
13
|
+
}, o: {
|
|
14
|
+
toolchains: string[];
|
|
15
|
+
databases: string[];
|
|
16
|
+
config: Toolchains["vscode"];
|
|
17
|
+
workspace: string;
|
|
18
|
+
}) => void;
|
|
2
19
|
export declare const setupVscode: (env: ToolEnv, refresh: boolean) => Promise<void>;
|
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { applyEdits, modify, parse as parseJsonc } from 'jsonc-parser';
|
|
6
8
|
import { fetchJson, installArchive } from '../../shared/download.js';
|
|
7
|
-
import {
|
|
9
|
+
import { SYSTEM } from '../../shared/system.js';
|
|
10
|
+
import { dryRun, exists, isWin, log, logsDir, mkdirp, powershell } from '../env.js';
|
|
8
11
|
import { arch, tool } from './common.js';
|
|
12
|
+
import { EXTENSION_ID, missingExtensions, vscodeExtensions, vscodeSettings } from './vscode-profile.js';
|
|
9
13
|
/** Newer builds keep their files under a commit-hash folder, so the installed version is recorded here. */
|
|
10
14
|
const VERSION_MARKER = '.agent-sandbox-version';
|
|
11
15
|
const desktopShortcut = (exe) => {
|
|
@@ -15,6 +19,88 @@ const desktopShortcut = (exe) => {
|
|
|
15
19
|
const q = (s) => "'" + s.replace(/'/g, "''") + "'";
|
|
16
20
|
powershell('$s = (New-Object -ComObject WScript.Shell).CreateShortcut(' + q(link) + '); $s.TargetPath = ' + q(exe) + '; $s.Arguments = ' + q('"' + (process.env.AGENT_WORKSPACE ?? '') + '"') + '; $s.Save()');
|
|
17
21
|
};
|
|
22
|
+
/** The first of `names` in one of `dirs`. */
|
|
23
|
+
const findIn = (dirs, ...names) => {
|
|
24
|
+
for (const dir of dirs)
|
|
25
|
+
for (const name of names) {
|
|
26
|
+
const file = path.join(dir, name);
|
|
27
|
+
if (exists(file))
|
|
28
|
+
return file;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
32
|
+
/** The project's .vscode/extensions.json recommendations (bounded; anything odd is ignored). */
|
|
33
|
+
const recommendedBy = (workspace) => {
|
|
34
|
+
const file = path.join(workspace, '.vscode', 'extensions.json');
|
|
35
|
+
try {
|
|
36
|
+
if (!exists(file) || fs.statSync(file).size > 64 * 1024)
|
|
37
|
+
return [];
|
|
38
|
+
const data = parseJsonc(fs.readFileSync(file, 'utf8'));
|
|
39
|
+
return Array.isArray(data?.recommendations) ? data.recommendations.filter((r) => typeof r === 'string' && EXTENSION_ID.test(r)).slice(0, 50) : [];
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* After every toolchain is installed: points VS Code at the sandbox's own JDK, Python, Go, compilers, .NET, Git and
|
|
47
|
+
* terminals (user settings; only the keys this tool manages are changed, your own stay), and installs the extensions
|
|
48
|
+
* for the languages in use in the background (they persist, so only new ones are downloaded).
|
|
49
|
+
*/
|
|
50
|
+
export const configureVscode = (tools, o) => {
|
|
51
|
+
const root = tool('vscode');
|
|
52
|
+
const code = path.join(root, 'bin', 'code.cmd');
|
|
53
|
+
if (dryRun) {
|
|
54
|
+
log('(dry run) would set up VS Code for: ' + o.toolchains.join(', '));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!exists(path.join(root, 'Code.exe')))
|
|
58
|
+
return;
|
|
59
|
+
const dirs = [...tools.prepend, ...tools.append];
|
|
60
|
+
const git = findIn([tool('git', 'cmd'), ...dirs], 'git.exe');
|
|
61
|
+
const settings = vscodeSettings({
|
|
62
|
+
javaHome: tools.vars.JAVA_HOME, goRoot: tools.vars.GOROOT, go: findIn(dirs, 'go.exe'), python: findIn(dirs, 'python.exe'), gcc: findIn(dirs, 'gcc.exe'), cl: findIn(dirs, 'cl.exe'),
|
|
63
|
+
cmake: findIn(dirs, 'cmake.exe'), dotnet: findIn(dirs, 'dotnet.exe'), node: findIn(dirs, 'node.exe'), pwsh: findIn(dirs, 'pwsh.exe'), git,
|
|
64
|
+
bash: git ? findIn([path.join(path.dirname(path.dirname(git)), 'bin')], 'bash.exe') : undefined, php: findIn(dirs, 'php.exe'), ruby: findIn(dirs, 'ruby.exe'), deno: findIn(dirs, 'deno.exe'),
|
|
65
|
+
});
|
|
66
|
+
writeManagedSettings(path.join(root, 'data', 'user-data', 'User', 'settings.json'), path.join(root, 'data', '.agent-sandbox-managed.json'), settings);
|
|
67
|
+
const wanted = vscodeExtensions({ toolchains: o.toolchains, databases: o.databases, recommended: o.config.recommended ? recommendedBy(o.workspace) : [], extra: o.config.extensions });
|
|
68
|
+
let folders = [];
|
|
69
|
+
try {
|
|
70
|
+
folders = fs.readdirSync(path.join(root, 'data', 'extensions'));
|
|
71
|
+
}
|
|
72
|
+
catch { /* none yet */ }
|
|
73
|
+
const missing = missingExtensions(wanted, folders);
|
|
74
|
+
tools.summary.push('vscode: set up for ' + (o.toolchains.join(', ') || 'Node') + (missing.length ? '; installing ' + missing.length + ' extension(s) in the background' : '; extensions ready'));
|
|
75
|
+
if (!missing.length)
|
|
76
|
+
return;
|
|
77
|
+
// In the background: the Marketplace can take a minute, and nothing else waits for it.
|
|
78
|
+
const logFile = fs.openSync(path.join(logsDir, 'vscode-extensions.log'), 'a');
|
|
79
|
+
spawn(SYSTEM.cmd(), ['/d', '/c', code, ...missing.flatMap((id) => ['--install-extension', id])], { detached: true, stdio: ['ignore', logFile, logFile], windowsHide: true }).unref();
|
|
80
|
+
fs.closeSync(logFile);
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Sets `values` in a settings file, keeping everything else (comments too), and removes keys this tool set last time
|
|
84
|
+
* but no longer has a value for (a toolchain turned off). The keys it manages are remembered in `managedFile`.
|
|
85
|
+
*/
|
|
86
|
+
const writeManagedSettings = (file, managedFile, values) => {
|
|
87
|
+
let text = exists(file) ? fs.readFileSync(file, 'utf8') : '{}';
|
|
88
|
+
let before = [];
|
|
89
|
+
try {
|
|
90
|
+
before = JSON.parse(fs.readFileSync(managedFile, 'utf8'));
|
|
91
|
+
}
|
|
92
|
+
catch { /* first time */ }
|
|
93
|
+
const format = { formattingOptions: { insertSpaces: true, tabSize: 2, eol: '\n' } };
|
|
94
|
+
for (const key of before.filter((k) => !(k in values))) {
|
|
95
|
+
if (parseJsonc(text)?.[key] !== undefined)
|
|
96
|
+
text = applyEdits(text, modify(text, [key], undefined, format));
|
|
97
|
+
}
|
|
98
|
+
for (const [key, value] of Object.entries(values))
|
|
99
|
+
text = applyEdits(text, modify(text, [key], value, format));
|
|
100
|
+
mkdirp(path.dirname(file));
|
|
101
|
+
fs.writeFileSync(file, text);
|
|
102
|
+
fs.writeFileSync(managedFile, JSON.stringify(Object.keys(values)));
|
|
103
|
+
};
|
|
18
104
|
export const setupVscode = async (env, refresh) => {
|
|
19
105
|
const root = tool('vscode');
|
|
20
106
|
const exe = path.join(root, 'Code.exe');
|
package/dist/guest/view.js
CHANGED
|
@@ -3,8 +3,28 @@
|
|
|
3
3
|
import { connect, runTerminalClient } from '../shared/pty-client.js';
|
|
4
4
|
import { readSession } from '../shared/rundir.js';
|
|
5
5
|
import { dataDir } from './env.js';
|
|
6
|
+
/** A session that is still being set up (its project provisioning, its agent installing): show the progress until it runs. */
|
|
7
|
+
const waitUntilStarted = async (id) => {
|
|
8
|
+
let last = '';
|
|
9
|
+
for (let i = 0; i < 3600; i++) {
|
|
10
|
+
const s = readSession(dataDir, id);
|
|
11
|
+
if (s && s.phase !== 'starting')
|
|
12
|
+
return s;
|
|
13
|
+
if (s && s.message !== last) {
|
|
14
|
+
console.log(' ' + s.message);
|
|
15
|
+
last = s.message;
|
|
16
|
+
}
|
|
17
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
18
|
+
}
|
|
19
|
+
return readSession(dataDir, id);
|
|
20
|
+
};
|
|
6
21
|
export const viewSession = async (id) => {
|
|
7
|
-
const session =
|
|
22
|
+
const session = await waitUntilStarted(id);
|
|
23
|
+
if (session?.phase === 'failed') {
|
|
24
|
+
console.error('Session ' + id + ' could not start: ' + session.message);
|
|
25
|
+
await new Promise((r) => setTimeout(r, 30000));
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
8
28
|
if (!session?.attach) {
|
|
9
29
|
console.error('Session ' + id + ' is not running.');
|
|
10
30
|
return 1;
|