windows-development-sandbox 1.9.0 → 1.11.3
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/README.md +64 -17
- package/config.example.json +7 -2
- package/dist/app/features/accounts/accounts.def.d.ts +122 -0
- package/dist/app/features/accounts/accounts.def.js +243 -0
- package/dist/app/features/accounts/accounts.run.d.ts +51 -0
- package/dist/app/features/accounts/accounts.run.js +125 -0
- package/dist/app/features/accounts/index.d.ts +2 -0
- package/dist/app/features/accounts/index.js +3 -0
- package/dist/app/features/agents/agent-entry.d.ts +17 -0
- package/dist/app/features/agents/agent-entry.js +50 -0
- package/dist/app/features/agents/agents.def.d.ts +65 -0
- package/dist/app/features/agents/agents.def.js +142 -0
- package/dist/app/features/agents/agents.run.d.ts +31 -0
- package/dist/app/features/agents/agents.run.js +189 -0
- package/dist/app/features/agents/index.d.ts +3 -0
- package/dist/app/features/agents/index.js +4 -0
- package/dist/app/features/apps/apps-rows.d.ts +31 -0
- package/dist/app/features/apps/apps-rows.js +73 -0
- package/dist/app/features/apps/apps.def.d.ts +181 -0
- package/dist/app/features/apps/apps.def.js +264 -0
- package/dist/app/features/apps/apps.run.d.ts +58 -0
- package/dist/app/features/apps/apps.run.js +76 -0
- package/dist/app/features/apps/index.d.ts +3 -0
- package/dist/app/features/apps/index.js +4 -0
- package/dist/app/features/data/data.def.d.ts +154 -0
- package/dist/app/features/data/data.def.js +201 -0
- package/dist/app/features/data/data.run.d.ts +46 -0
- package/dist/app/features/data/data.run.js +141 -0
- package/dist/app/features/data/index.d.ts +2 -0
- package/dist/app/features/data/index.js +3 -0
- package/dist/app/features/defs.d.ts +952 -4
- package/dist/app/features/defs.js +147 -10
- package/dist/app/features/engine/engine.def.d.ts +228 -0
- package/dist/app/features/engine/engine.def.js +194 -0
- package/dist/app/features/engine/engine.run.d.ts +72 -0
- package/dist/app/features/engine/engine.run.js +77 -0
- package/dist/app/features/engine/index.d.ts +2 -0
- package/dist/app/features/engine/index.js +4 -0
- package/dist/app/features/files/files.def.d.ts +51 -0
- package/dist/app/features/files/files.def.js +38 -0
- package/dist/app/features/files/files.run.d.ts +20 -0
- package/dist/app/features/files/files.run.js +59 -0
- package/dist/app/features/files/index.d.ts +2 -0
- package/dist/app/features/files/index.js +3 -0
- package/dist/app/features/github/github.def.d.ts +80 -0
- package/dist/app/features/github/github.def.js +142 -0
- package/dist/app/features/github/github.run.d.ts +36 -0
- package/dist/app/features/github/github.run.js +59 -0
- package/dist/app/features/github/index.d.ts +2 -0
- package/dist/app/features/github/index.js +3 -0
- package/dist/app/features/health/health.def.d.ts +275 -0
- package/dist/app/features/health/health.def.js +281 -0
- package/dist/app/features/health/health.run.d.ts +125 -0
- package/dist/app/features/health/health.run.js +204 -0
- package/dist/app/features/health/index.d.ts +2 -0
- package/dist/app/features/health/index.js +3 -0
- package/dist/app/features/logs/index.d.ts +2 -0
- package/dist/app/features/logs/index.js +3 -0
- package/dist/app/features/logs/logs.def.d.ts +78 -0
- package/dist/app/features/logs/logs.def.js +115 -0
- package/dist/app/features/logs/logs.run.d.ts +20 -0
- package/dist/app/features/logs/logs.run.js +42 -0
- package/dist/app/features/projects/index.d.ts +2 -0
- package/dist/app/features/projects/index.js +3 -0
- package/dist/app/features/projects/projects.def.d.ts +101 -0
- package/dist/app/features/projects/projects.def.js +208 -0
- package/dist/app/features/projects/projects.run.d.ts +56 -0
- package/dist/app/features/projects/projects.run.js +155 -0
- package/dist/app/features/sandbox/sandbox.def.js +11 -5
- package/dist/app/features/sessions/sessions.def.js +3 -0
- package/dist/app/features/settings/categories.def.js +3 -2
- package/dist/{cli/menu/settings/share.d.ts → app/features/settings/settings-share.d.ts} +1 -1
- package/dist/{cli/menu/settings/share.js → app/features/settings/settings-share.js} +3 -2
- package/dist/app/features/settings/settings.def.d.ts +22 -5
- package/dist/app/features/settings/settings.def.js +81 -6
- package/dist/app/features/settings/settings.run.d.ts +17 -0
- package/dist/app/features/settings/settings.run.js +89 -4
- package/dist/app/features/storage/index.d.ts +2 -0
- package/dist/app/features/storage/index.js +3 -0
- package/dist/app/features/storage/storage.def.d.ts +133 -0
- package/dist/app/features/storage/storage.def.js +225 -0
- package/dist/app/features/storage/storage.run.d.ts +62 -0
- package/dist/app/features/storage/storage.run.js +370 -0
- package/dist/app/features/updates/index.d.ts +3 -0
- package/dist/app/features/updates/index.js +4 -0
- package/dist/app/features/updates/update-lines.d.ts +13 -0
- package/dist/app/features/updates/update-lines.js +61 -0
- package/dist/app/features/updates/updates.def.d.ts +89 -0
- package/dist/app/features/updates/updates.def.js +225 -0
- package/dist/app/features/updates/updates.run.d.ts +48 -0
- package/dist/app/features/updates/updates.run.js +154 -0
- package/dist/app/features/vpn/index.d.ts +2 -0
- package/dist/app/features/vpn/index.js +3 -0
- package/dist/app/features/vpn/vpn.def.d.ts +112 -0
- package/dist/app/features/vpn/vpn.def.js +174 -0
- package/dist/app/features/vpn/vpn.run.d.ts +37 -0
- package/dist/app/features/vpn/vpn.run.js +54 -0
- package/dist/app/features/web/index.d.ts +2 -0
- package/dist/app/features/web/index.js +3 -0
- package/dist/app/features/web/web.def.d.ts +33 -0
- package/dist/app/features/web/web.def.js +90 -0
- package/dist/app/features/web/web.run.d.ts +24 -0
- package/dist/app/features/web/web.run.js +93 -0
- package/dist/app/kernel/define.d.ts +10 -1
- package/dist/app/kernel/io.d.ts +34 -0
- package/dist/app/kernel/io.js +9 -0
- package/dist/app/kernel/rpc.d.ts +17 -0
- package/dist/app/kernel/text.d.ts +2 -0
- package/dist/app/kernel/text.js +7 -0
- package/dist/app/kernel/view.d.ts +24 -1
- package/dist/app/kernel/view.js +1 -1
- package/dist/app/registry.js +74 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/commands/context.d.ts +7 -0
- package/dist/cli/commands/context.js +29 -2
- package/dist/cli/commands/engine.js +5 -58
- package/dist/cli/commands/github.d.ts +2 -0
- package/dist/cli/commands/github.js +11 -0
- package/dist/cli/commands/index.d.ts +3 -5
- package/dist/cli/commands/index.js +3 -5
- package/dist/cli/commands/launch/launch.js +23 -4
- package/dist/cli/commands/launch/running.js +4 -1
- package/dist/cli/commands/maintenance/config.js +1 -6
- package/dist/cli/commands/maintenance/index.d.ts +0 -1
- package/dist/cli/commands/maintenance/index.js +1 -2
- package/dist/cli/commands/maintenance/logs.js +27 -32
- package/dist/cli/commands/maintenance/migrate.d.ts +0 -8
- package/dist/cli/commands/maintenance/migrate.js +2 -44
- package/dist/cli/commands/maintenance/update.d.ts +0 -19
- package/dist/cli/commands/maintenance/update.js +1 -99
- package/dist/cli/commands/projects/index.d.ts +0 -1
- package/dist/cli/commands/projects/index.js +0 -1
- package/dist/cli/commands/registry.d.ts +1 -1
- package/dist/cli/commands/registry.js +29 -11
- package/dist/cli/commands/repair/checks/data.js +1 -1
- package/dist/cli/commands/repair/checks/hcs.js +28 -1
- package/dist/cli/commands/repair/checks/sandbox.js +1 -1
- package/dist/cli/commands/repair/health-run.d.ts +30 -0
- package/dist/cli/commands/repair/health-run.js +32 -0
- package/dist/cli/commands/repair/printer.d.ts +2 -2
- package/dist/cli/commands/repair/printer.js +2 -11
- package/dist/cli/commands/repair/run.d.ts +1 -21
- package/dist/cli/commands/repair/run.js +13 -70
- package/dist/cli/commands/storage/index.d.ts +0 -1
- package/dist/cli/commands/storage/index.js +0 -1
- package/dist/cli/commands/storage/offer.js +6 -2
- package/dist/cli/commands/vpn.d.ts +1 -3
- package/dist/cli/commands/vpn.js +8 -88
- package/dist/cli/commands/web.d.ts +7 -1
- package/dist/cli/commands/web.js +45 -71
- package/dist/cli/index.js +3 -2
- package/dist/cli/manifest.d.ts +16 -153
- package/dist/cli/manifest.js +20 -50
- package/dist/cli/menu/command-form.js +1 -2
- package/dist/cli/menu/io-menu.d.ts +2 -2
- package/dist/cli/menu/io-menu.js +6 -4
- package/dist/cli/menu/menu.js +1 -1
- package/dist/cli/menu/pages/accounts-page.d.ts +5 -17
- package/dist/cli/menu/pages/accounts-page.js +28 -170
- package/dist/cli/menu/pages/agents-page.d.ts +17 -18
- package/dist/cli/menu/pages/agents-page.js +67 -124
- package/dist/cli/menu/pages/apps-page.d.ts +15 -8
- package/dist/cli/menu/pages/apps-page.js +121 -29
- package/dist/cli/menu/pages/list-page.js +10 -1
- package/dist/cli/menu/pages/maintenance-page.d.ts +51 -52
- package/dist/cli/menu/pages/maintenance-page.js +246 -427
- package/dist/cli/menu/pages/sandbox-page.d.ts +3 -5
- package/dist/cli/menu/pages/sandbox-page.js +34 -112
- package/dist/cli/menu/pages/settings-page.d.ts +21 -3
- package/dist/cli/menu/pages/settings-page.js +89 -17
- package/dist/cli/menu/render-view.js +2 -1
- package/dist/cli/menu/settings/index.d.ts +0 -1
- package/dist/cli/menu/settings/index.js +3 -3
- package/dist/cli/menu/views.js +28 -0
- package/dist/cli/operations/handler.js +7 -3
- package/dist/cli/operations/input.d.ts +1 -1
- package/dist/cli/operations/input.js +29 -5
- package/dist/cli/operations/io-cli.js +9 -1
- package/dist/cli/operations/spec.js +8 -2
- package/dist/cli/output/render-view.js +2 -0
- package/dist/cli/{commands/data/collect.js → services/data-collect.js} +2 -2
- package/dist/cli/{commands/data/remove.js → services/data-remove.js} +2 -2
- package/dist/cli/services/data-service.d.ts +1 -1
- package/dist/cli/services/data-service.js +2 -2
- package/dist/cli/services/databases-service.d.ts +5 -0
- package/dist/cli/services/databases-service.js +15 -0
- package/dist/cli/services/health-service.d.ts +8 -4
- package/dist/cli/services/health-service.js +10 -8
- package/dist/cli/services/index.d.ts +4 -1
- package/dist/cli/services/index.js +4 -1
- package/dist/cli/services/logs-service.d.ts +7 -0
- package/dist/cli/services/logs-service.js +13 -0
- package/dist/cli/services/storage-service.d.ts +19 -0
- package/dist/cli/services/storage-service.js +71 -0
- package/dist/cli/services/vpn-service.d.ts +6 -4
- package/dist/cli/services/vpn-service.js +5 -11
- package/dist/cli/services/web-service.d.ts +4 -3
- package/dist/cli/services/web-service.js +12 -32
- package/dist/core/config/defaults.js +3 -2
- package/dist/core/schema/config.d.ts +6 -0
- package/dist/core/schema/config.js +2 -0
- package/dist/core/schema/github.d.ts +4 -0
- package/dist/core/schema/github.js +7 -0
- package/dist/core/schema/index.d.ts +1 -0
- package/dist/core/schema/index.js +1 -0
- package/dist/core/schema/profile.d.ts +1 -0
- package/dist/core/schema/profile.js +3 -0
- package/dist/core/schema/sandbox.js +3 -3
- package/dist/core/schema/toolchains.js +2 -2
- package/dist/core/schema/vpn.js +1 -1
- package/dist/core/schema/web.d.ts +1 -0
- package/dist/core/schema/web.js +4 -1
- package/dist/core/types.d.ts +6 -3
- package/dist/guest/boot/boot.js +11 -1
- package/dist/guest/daemon/daemon.js +1 -1
- package/dist/guest/daemon/sessions.d.ts +3 -2
- package/dist/guest/daemon/sessions.js +38 -7
- package/dist/guest/governor/core.d.ts +44 -0
- package/dist/guest/governor/core.js +124 -0
- package/dist/guest/governor/decide.d.ts +53 -15
- package/dist/guest/governor/decide.js +155 -72
- package/dist/guest/governor/governor.d.ts +2 -35
- package/dist/guest/governor/governor.js +35 -99
- package/dist/guest/governor/index.d.ts +1 -0
- package/dist/guest/governor/index.js +1 -0
- package/dist/guest/network/firewall.d.ts +3 -0
- package/dist/guest/network/firewall.js +65 -23
- package/dist/guest/runtime/process.js +53 -5
- package/dist/guest/sessions/viewer.js +5 -1
- package/dist/guest/setup/claude-mem.js +12 -4
- package/dist/guest/setup/github-token.d.ts +7 -0
- package/dist/guest/setup/github-token.js +65 -0
- package/dist/guest/toolchains/languages/node.js +40 -4
- package/dist/guest/toolchains/native/rust-extras.js +2 -2
- package/dist/guest/toolchains/tools/cli.d.ts +8 -0
- package/dist/guest/toolchains/tools/cli.js +16 -2
- package/dist/guest/vpn/openvpn.d.ts +5 -0
- package/dist/guest/vpn/openvpn.js +14 -1
- package/dist/guest/vpn/vpn.js +55 -16
- package/dist/guest/vpn/wireguard.js +2 -0
- package/dist/host/channel/attach.d.ts +1 -0
- package/dist/host/channel/attach.js +1 -0
- package/dist/host/channel/channel.d.ts +1 -1
- package/dist/host/channel/channel.js +2 -2
- package/dist/host/engines/hcs/check.d.ts +1 -0
- package/dist/host/engines/hcs/check.js +1 -1
- package/dist/host/engines/hcs/engine.d.ts +1 -1
- package/dist/host/engines/hcs/engine.js +6 -4
- package/dist/host/engines/hcs/helper.d.ts +11 -0
- package/dist/host/engines/hcs/helper.js +31 -2
- package/dist/host/engines/hcs/leftovers.d.ts +42 -0
- package/dist/host/engines/hcs/leftovers.js +101 -0
- package/dist/host/engines/index.d.ts +1 -0
- package/dist/host/engines/index.js +1 -0
- package/dist/host/github/deliver.d.ts +13 -0
- package/dist/host/github/deliver.js +51 -0
- package/dist/host/github/index.d.ts +2 -0
- package/dist/host/github/index.js +3 -0
- package/dist/host/github/token.d.ts +21 -0
- package/dist/host/github/token.js +74 -0
- package/dist/host/launch/generate.js +11 -5
- package/dist/host/launch/index.d.ts +1 -1
- package/dist/host/launch/index.js +1 -1
- package/dist/host/launch/session-file.js +1 -2
- package/dist/host/launch/wsb-file.d.ts +11 -7
- package/dist/host/launch/wsb-file.js +30 -12
- package/dist/host/life/host-memory.d.ts +1 -0
- package/dist/host/life/host-memory.js +4 -1
- package/dist/host/life/watchdog.d.ts +11 -0
- package/dist/host/life/watchdog.js +36 -4
- package/dist/host/sandbox/tasklist.d.ts +6 -0
- package/dist/host/sandbox/tasklist.js +37 -0
- package/dist/host/secrets/launch-secrets.d.ts +2 -1
- package/dist/host/secrets/launch-secrets.js +4 -2
- package/dist/host/vpn/status.js +13 -3
- package/dist/host/web/backend.d.ts +1 -3
- package/dist/host/web/index.d.ts +2 -1
- package/dist/host/web/index.js +2 -1
- package/dist/host/web/live.d.ts +23 -0
- package/dist/host/web/live.js +107 -0
- package/dist/host/web/rpc.d.ts +6 -1
- package/dist/host/web/rpc.js +23 -31
- package/dist/host/web/runner.d.ts +4 -0
- package/dist/host/web/runner.js +12 -1
- package/dist/host/web/server.d.ts +30 -2
- package/dist/host/web/server.js +87 -29
- package/dist/host/web/state.d.ts +1 -0
- package/dist/host/web/state.js +2 -0
- package/dist/runtime/agent.js +44 -16
- package/dist/runtime/daemon.js +1154 -857
- package/dist/runtime/db.js +44 -16
- package/dist/runtime/main.js +532 -115
- package/dist/runtime/netproxy.js +34 -9
- package/dist/runtime/view.js +499 -149
- package/dist/selftest/app.test.js +620 -12
- package/dist/selftest/channel.test.js +18 -1
- package/dist/selftest/cli.test.js +1 -1
- package/dist/selftest/config.test.js +1 -1
- package/dist/selftest/contained.test.js +1 -1
- package/dist/selftest/data.test.js +1 -2
- package/dist/selftest/engine.test.js +3 -1
- package/dist/selftest/github.test.d.ts +2 -0
- package/dist/selftest/github.test.js +243 -0
- package/dist/selftest/guest-boot.test.js +47 -1
- package/dist/selftest/hcs.test.js +105 -8
- package/dist/selftest/health.test.js +71 -0
- package/dist/selftest/heavy-load.test.js +152 -66
- package/dist/selftest/index.js +4 -0
- package/dist/selftest/layout.test.js +8 -0
- package/dist/selftest/live-terminal.test.js +74 -0
- package/dist/selftest/menu-screens.js +171 -56
- package/dist/selftest/menu.test.js +54 -37
- package/dist/selftest/migrate.test.js +14 -12
- package/dist/selftest/network.test.js +20 -1
- package/dist/selftest/powershell-variables.test.d.ts +2 -0
- package/dist/selftest/powershell-variables.test.js +61 -0
- package/dist/selftest/support/engine-golden.js +1 -0
- package/dist/selftest/support/fixtures.d.ts +5 -0
- package/dist/selftest/support/web-preview.d.ts +1 -0
- package/dist/selftest/support/web-preview.js +856 -0
- package/dist/selftest/update-service.test.js +15 -8
- package/dist/selftest/vpn.test.js +86 -2
- package/dist/selftest/web.test.js +58 -11
- package/dist/shared/channel/run-dir.d.ts +2 -0
- package/dist/shared/channel/run-dir.js +3 -0
- package/dist/shared/channel/schema.d.ts +7 -0
- package/dist/shared/channel/schema.js +9 -1
- package/dist/shared/channel/secrets.d.ts +1 -0
- package/dist/shared/channel/secrets.js +3 -0
- package/dist/shared/github/index.d.ts +1 -0
- package/dist/shared/github/index.js +2 -0
- package/dist/shared/github/token.d.ts +29 -0
- package/dist/shared/github/token.js +89 -0
- package/dist/shared/io/copy-tree.d.ts +7 -0
- package/dist/shared/io/copy-tree.js +45 -0
- package/dist/shared/io/index.d.ts +2 -0
- package/dist/shared/io/index.js +2 -0
- package/dist/shared/io/robocopy-result.d.ts +6 -0
- package/dist/shared/io/robocopy-result.js +23 -0
- package/dist/shared/memory/policy.d.ts +38 -12
- package/dist/shared/memory/policy.js +58 -19
- package/dist/shared/network/firewall-rules.d.ts +8 -0
- package/dist/shared/network/firewall-rules.js +28 -0
- package/dist/shared/pty/ctrl-c.d.ts +18 -0
- package/dist/shared/pty/ctrl-c.js +36 -0
- package/dist/shared/pty/index.d.ts +1 -0
- package/dist/shared/pty/index.js +1 -0
- package/dist/shared/pty/terminal.d.ts +2 -0
- package/dist/shared/pty/terminal.js +21 -2
- package/dist/shared/vpn/kill-switch.d.ts +13 -2
- package/dist/shared/vpn/kill-switch.js +88 -8
- package/dist/shared/web/protocol.d.ts +0 -4
- package/dist/sync/watcher.js +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/{main-T5DMCHYV.css → main-6JF3ASB5.css} +1 -1
- package/dist/web/main-Z645W45E.js +219 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/MemoryStatus.cs +128 -107
- package/native/scripts/memory-status.ps1 +10 -2
- package/package.json +10 -3
- package/sandbox/csharp/MemGov.cs +668 -398
- package/sandbox/csharp/PtyHost.cs +104 -15
- package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
- package/sandbox/csharp/SandboxTools/Program.cs +1 -1
- package/sandbox/scripts/new-shortcuts.ps1 +3 -1
- package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
- package/schemas/config.schema.json +25 -7
- package/schemas/sandbox-config.schema.json +7 -3
- package/dist/cli/commands/accounts.d.ts +0 -2
- package/dist/cli/commands/accounts.js +0 -96
- package/dist/cli/commands/data/clean.d.ts +0 -3
- package/dist/cli/commands/data/clean.js +0 -60
- package/dist/cli/commands/data/index.d.ts +0 -4
- package/dist/cli/commands/data/index.js +0 -62
- package/dist/cli/commands/maintenance/clean.d.ts +0 -2
- package/dist/cli/commands/maintenance/clean.js +0 -24
- package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
- package/dist/cli/commands/maintenance/config-share.js +0 -80
- package/dist/cli/commands/projects/projects.d.ts +0 -2
- package/dist/cli/commands/projects/projects.js +0 -162
- package/dist/cli/commands/storage/contained.d.ts +0 -3
- package/dist/cli/commands/storage/contained.js +0 -179
- package/dist/cli/commands/storage/storage.d.ts +0 -8
- package/dist/cli/commands/storage/storage.js +0 -179
- package/dist/cli/menu/add-agent.d.ts +0 -47
- package/dist/cli/menu/add-agent.js +0 -168
- package/dist/cli/menu/apps.d.ts +0 -69
- package/dist/cli/menu/apps.js +0 -214
- package/dist/cli/menu/data-folder.d.ts +0 -18
- package/dist/cli/menu/data-folder.js +0 -99
- package/dist/cli/menu/share-settings.d.ts +0 -21
- package/dist/cli/menu/share-settings.js +0 -112
- package/dist/cli/menu/vpn-login.d.ts +0 -16
- package/dist/cli/menu/vpn-login.js +0 -74
- package/dist/web/main-NRRS5O6Z.js +0 -157
- /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
- /package/dist/cli/{commands/data/remove.d.ts → services/data-remove.d.ts} +0 -0
package/dist/runtime/main.js
CHANGED
|
@@ -5532,7 +5532,7 @@ var require_lodash = __commonJS({
|
|
|
5532
5532
|
});
|
|
5533
5533
|
|
|
5534
5534
|
// src/guest/entries/main.ts
|
|
5535
|
-
import
|
|
5535
|
+
import fs61 from "node:fs";
|
|
5536
5536
|
import path74 from "node:path";
|
|
5537
5537
|
|
|
5538
5538
|
// src/guest/runtime/paths.ts
|
|
@@ -25411,6 +25411,9 @@ var AttachSchema = external_exports.strictObject({
|
|
|
25411
25411
|
),
|
|
25412
25412
|
autoHide: external_exports.boolean().describe(
|
|
25413
25413
|
"Hide the Windows Sandbox window whenever this terminal attaches; it keeps running (sandbox show brings it back)."
|
|
25414
|
+
),
|
|
25415
|
+
confirmCtrlC: external_exports.boolean().describe(
|
|
25416
|
+
'In an attached terminal and the sandbox window, a single Ctrl+C is held back (the title says so) and only a second one within 1.5 seconds reaches the agent: a Ctrl+C meant as "copy" no longer stops it. Esc still stops an agent.'
|
|
25414
25417
|
)
|
|
25415
25418
|
});
|
|
25416
25419
|
var AgentCommandsSchema = external_exports.strictObject({
|
|
@@ -25455,7 +25458,9 @@ var SandboxSchema = external_exports.strictObject({
|
|
|
25455
25458
|
engine: external_exports.enum(["windows-sandbox", "hcs"]).describe(
|
|
25456
25459
|
'(alpha) What runs the sandbox. "windows-sandbox" = Windows Sandbox (the default: desktop, Windows Terminal, GPU, clipboard, audio, printers). "hcs" = a headless Hyper-V isolated Server Core container for agents (no desktop, GPU or clipboard); it needs Windows features and an image on this PC (sandbox engine check hcs lists what is missing), and starting it is not enabled yet in this alpha. sandbox engine shows what each engine can do. Yours only: a project file (.sandbox-config.json) cannot set it.'
|
|
25457
25460
|
),
|
|
25458
|
-
memoryMb: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(2048)]).describe(
|
|
25461
|
+
memoryMb: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(2048)]).describe(
|
|
25462
|
+
'Sandbox RAM in MB (>= 2048), or "auto": free RAM minus reserveHostMb, capped at maxMemoryMb. Never more than this PC can keep in RAM for it (its RAM minus the larger of reserveHostMb and 25 %, 2 GB more with vGPU): a bigger value is lowered.'
|
|
25463
|
+
),
|
|
25459
25464
|
maxMemoryMb: external_exports.number().int().positive().describe('Upper limit for memoryMb "auto".'),
|
|
25460
25465
|
maxMemoryPercent: external_exports.number().int().min(10).max(100).describe(`memoryMb "auto" never takes more than this share of this PC's total RAM (percent).`),
|
|
25461
25466
|
cpuLimit: external_exports.union([external_exports.literal("none"), external_exports.number().int().min(5).max(100)]).describe(
|
|
@@ -25468,10 +25473,10 @@ var SandboxSchema = external_exports.strictObject({
|
|
|
25468
25473
|
'Memory always left for this PC when memoryMb is "auto": the sandbox gets at most (free RAM, and RAM plus paging file still unused) minus this.'
|
|
25469
25474
|
),
|
|
25470
25475
|
agentMemoryHeadroomMb: external_exports.union([external_exports.literal("auto"), external_exports.literal("none"), external_exports.number().int().min(0)]).describe(
|
|
25471
|
-
'
|
|
25476
|
+
'The last resort that keeps the sandbox up, in MB below its commit limit (RAM plus paging file): builds are slowed down long before (sandbox.pressureResponse); only if everything the agents start together would take the sandbox to the very edge of its memory, where Windows inside it would start failing, is a build refused memory instead of Windows. "auto" = the larger of 1536 MB and 3 % of the commit limit; "none" = no backstop. Yours only: a project file cannot change it.'
|
|
25472
25477
|
),
|
|
25473
25478
|
pressureResponse: external_exports.boolean().describe(
|
|
25474
|
-
"When the sandbox (or this PC) runs low on memory, slow
|
|
25479
|
+
"When the sandbox (or this PC) runs low on memory, slow builds down in steps, like a PC that gets slower instead of failing: build programs get lower CPU and memory priority, then less CPU, then compilers take turns (the waiting ones briefly suspended and trimmed to the paging file). Nothing is stopped or killed, and the agents themselves are never touched. Yours only: a project file cannot change it."
|
|
25475
25480
|
),
|
|
25476
25481
|
vGpu: external_exports.boolean().describe(
|
|
25477
25482
|
"Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface. The sandbox then uses this PC's graphics card, and with some graphics drivers heavy use can freeze the whole PC: turn it on only when a program in the sandbox needs the GPU (the mesa toolchain gives software OpenGL without it)."
|
|
@@ -25617,7 +25622,7 @@ var ToolchainsSchema = external_exports.strictObject({
|
|
|
25617
25622
|
`GNU host: "lld" links with Rust's own lld through MinGW's gcc (much less memory than GNU ld), "gnu" with GNU ld.`
|
|
25618
25623
|
),
|
|
25619
25624
|
linkSlots: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(1).max(32)]).describe(
|
|
25620
|
-
'GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per
|
|
25625
|
+
'GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per 3 GB of sandbox memory after 6 GB, 2 to 8 (the memory governor slows links down too when memory runs short).'
|
|
25621
25626
|
)
|
|
25622
25627
|
}),
|
|
25623
25628
|
msvc: external_exports.strictObject({
|
|
@@ -25692,7 +25697,7 @@ var ToolchainsSchema = external_exports.strictObject({
|
|
|
25692
25697
|
}),
|
|
25693
25698
|
cli: external_exports.strictObject({
|
|
25694
25699
|
gh: EnabledSchema.describe(
|
|
25695
|
-
'GitHub CLI (gh). Only with provisioning.git.access "full": gh can push and merge through the GitHub API, past a read-only git. Your PC\'s gh login is never copied; `gh auth login` inside persists (GH_CONFIG_DIR). "auto" = when the project has a .github folder.'
|
|
25700
|
+
'GitHub CLI (gh). Only with provisioning.git.access "full": gh can push and merge through the GitHub API, past a read-only git. Your PC\'s gh login is never copied; `gh auth login` inside persists (GH_CONFIG_DIR), unless a token you saved for sandboxes is handed over (github.shareToken). "auto" = when the project has a .github folder.'
|
|
25696
25701
|
),
|
|
25697
25702
|
zstd: EnabledSchema.describe('Zstandard (zstd). "auto" = off; set true to get it.'),
|
|
25698
25703
|
openssl: EnabledSchema.describe(
|
|
@@ -26595,16 +26600,17 @@ var ResumeSchema = external_exports.strictObject({
|
|
|
26595
26600
|
// src/core/schema/web.ts
|
|
26596
26601
|
var WebSchema = external_exports.strictObject({
|
|
26597
26602
|
enabled: external_exports.boolean().describe(
|
|
26598
|
-
"(Beta)
|
|
26603
|
+
"(Beta) The web UI: your sandbox sessions in a browser on this PC (http://127.0.0.1:<port>, this PC only). On: every sandbox start also starts it in the background (it keeps running until sandbox web stop or a restart of the PC). Off: only sandbox web start runs it. Open it signed in with sandbox web open."
|
|
26599
26604
|
),
|
|
26600
|
-
port: external_exports.number().int().min(1024).max(65535).describe("Port of the web UI on 127.0.0.1 (this PC only). Pick another when it is taken.")
|
|
26605
|
+
port: external_exports.number().int().min(1024).max(65535).describe("Port of the web UI on 127.0.0.1 (this PC only). Pick another when it is taken."),
|
|
26606
|
+
openOnLaunch: external_exports.boolean().describe("(Beta) With the web UI on: open it in your browser, already signed in, every time a sandbox starts.")
|
|
26601
26607
|
});
|
|
26602
26608
|
|
|
26603
26609
|
// src/core/schema/vpn.ts
|
|
26604
26610
|
var VPN_PROVIDERS = ["nordvpn", "openvpn-file", "wireguard-file"];
|
|
26605
26611
|
var VpnSchema = external_exports.strictObject({
|
|
26606
26612
|
enabled: external_exports.boolean().describe(
|
|
26607
|
-
"Send the sandbox's traffic through a VPN. Only the sandbox: your PC's own connection is untouched. Needs a saved login first (sandbox vpn login). The agent in the sandbox can read that login and can turn the tunnel off (it is the administrator there)."
|
|
26613
|
+
"(Alpha: not yet tried on a real PC) Send the sandbox's traffic through a VPN. Only the sandbox: your PC's own connection is untouched. Needs a saved login first (sandbox vpn login). The agent in the sandbox can read that login and can turn the tunnel off (it is the administrator there)."
|
|
26608
26614
|
),
|
|
26609
26615
|
provider: external_exports.enum(VPN_PROVIDERS).describe(
|
|
26610
26616
|
"nordvpn: a recommended NordVPN server is picked at every launch. openvpn-file: your own .ovpn file (configFile). wireguard-file: your own WireGuard .conf (configFile), e.g. from your company."
|
|
@@ -26619,6 +26625,13 @@ var VpnSchema = external_exports.strictObject({
|
|
|
26619
26625
|
)
|
|
26620
26626
|
});
|
|
26621
26627
|
|
|
26628
|
+
// src/core/schema/github.ts
|
|
26629
|
+
var GithubSchema = external_exports.strictObject({
|
|
26630
|
+
shareToken: external_exports.boolean().describe(
|
|
26631
|
+
'Give each sandbox the GitHub token you saved with `sandbox github login` (best a fine-grained token limited to some repositories and permissions), so gh and https git work there without logging in. Only with provisioning.git.access "full". The agent in the sandbox can read the token and use it for whatever it allows. A project file (.sandbox-config.json) cannot turn this on.'
|
|
26632
|
+
)
|
|
26633
|
+
});
|
|
26634
|
+
|
|
26622
26635
|
// src/core/schema/config.ts
|
|
26623
26636
|
var ConfigSchema = external_exports.strictObject({
|
|
26624
26637
|
$schema: SchemaRefSchema.optional(),
|
|
@@ -26649,6 +26662,7 @@ var ConfigSchema = external_exports.strictObject({
|
|
|
26649
26662
|
}),
|
|
26650
26663
|
network: NetworkSchema,
|
|
26651
26664
|
vpn: VpnSchema,
|
|
26665
|
+
github: GithubSchema,
|
|
26652
26666
|
provisioning: ProvisioningSchema,
|
|
26653
26667
|
downloads: DownloadsSchema,
|
|
26654
26668
|
toolchains: ToolchainsSchema,
|
|
@@ -26811,19 +26825,25 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
|
26811
26825
|
id: IdSchema,
|
|
26812
26826
|
reason: Text(300),
|
|
26813
26827
|
seconds: external_exports.number().int().min(10).max(300),
|
|
26828
|
+
/** "severe": the PC is nearly out of memory; builds go to the governor's last step at once. */
|
|
26829
|
+
level: external_exports.enum(["slow", "severe"]).optional(),
|
|
26814
26830
|
createdAt: TimeSchema
|
|
26815
26831
|
})
|
|
26816
26832
|
]);
|
|
26817
26833
|
var PressureStatusSchema = external_exports.object({
|
|
26818
26834
|
level: external_exports.enum(["ok", "throttled", "suspending"]),
|
|
26835
|
+
/** The governor's dial, 0 (nothing wrong) to 4 (one compiler at a time). */
|
|
26836
|
+
step: external_exports.number().int().min(0).max(4).optional(),
|
|
26819
26837
|
profile: external_exports.enum(["normal", "gentle"]),
|
|
26820
26838
|
/** Share of the sandbox's RAM still free and of its commit limit in use (percent). */
|
|
26821
26839
|
ramFreePercent: external_exports.number().int().min(0).max(100),
|
|
26822
26840
|
commitPercent: external_exports.number().int().min(0).max(100),
|
|
26823
26841
|
/** Programs running at lower priority because of it. */
|
|
26824
26842
|
lowered: external_exports.number().int().min(0).max(1024),
|
|
26825
|
-
/**
|
|
26843
|
+
/** Compilers waiting their turn right now (name, process id, seconds until they may go on). */
|
|
26826
26844
|
paused: external_exports.array(external_exports.object({ name: Text(64), pid: external_exports.number().int(), seconds: external_exports.number().int().min(0).max(60) })).max(8),
|
|
26845
|
+
/** The CPU share the compilers get together (percent; 100 = no cap). */
|
|
26846
|
+
cpuPercent: external_exports.number().int().min(0).max(100).optional(),
|
|
26827
26847
|
/** The PC itself asked for slowing down (its memory or CPU is low). */
|
|
26828
26848
|
pcLow: external_exports.boolean(),
|
|
26829
26849
|
lastAction: Text(300),
|
|
@@ -26867,6 +26887,8 @@ var VpnStatusSchema = external_exports.object({
|
|
|
26867
26887
|
state: external_exports.enum(["off", "starting", "up", "failed"]),
|
|
26868
26888
|
message: Text(2e3),
|
|
26869
26889
|
killSwitch: external_exports.boolean(),
|
|
26890
|
+
/** A direct connection was tried after the kill switch was applied: false = it still got out. */
|
|
26891
|
+
killSwitchHeld: external_exports.boolean().optional(),
|
|
26870
26892
|
/** The server's name, e.g. uk2201.nordvpn.com. */
|
|
26871
26893
|
server: Text(128).optional(),
|
|
26872
26894
|
/** What the sandbox's traffic looks like from outside, once the tunnel is up. */
|
|
@@ -27014,6 +27036,21 @@ function safeRemove(target, root) {
|
|
|
27014
27036
|
fs3.rmSync(target, { recursive: true, force: true, maxRetries: 2 });
|
|
27015
27037
|
}
|
|
27016
27038
|
|
|
27039
|
+
// src/shared/io/robocopy-result.ts
|
|
27040
|
+
function robocopyFailed(code) {
|
|
27041
|
+
return code === null || code >= 8;
|
|
27042
|
+
}
|
|
27043
|
+
function robocopyMeaning(code) {
|
|
27044
|
+
if (code === null) return "robocopy did not finish";
|
|
27045
|
+
if (code >= 16) return "robocopy stopped with a fatal error (bad path or no access)";
|
|
27046
|
+
if (code >= 8) return code & 1 ? "some files were copied and some could not be" : "files could not be copied";
|
|
27047
|
+
return code === 0 ? "nothing to copy" : "copied";
|
|
27048
|
+
}
|
|
27049
|
+
function robocopyErrors(output3, max = 3) {
|
|
27050
|
+
const lines = output3.split(/\r?\n/).map((l) => l.trim()).filter((l) => /\bERROR\b/.test(l) || /^The (process|system) cannot/i.test(l));
|
|
27051
|
+
return lines.slice(0, max).map((l) => l.length > 220 ? l.slice(0, 217) + "..." : l);
|
|
27052
|
+
}
|
|
27053
|
+
|
|
27017
27054
|
// src/shared/channel/run-dir.ts
|
|
27018
27055
|
function safeId(id) {
|
|
27019
27056
|
return IdSchema.parse(id);
|
|
@@ -27039,6 +27076,8 @@ var RunDir = class {
|
|
|
27039
27076
|
vpnFile;
|
|
27040
27077
|
/** What the memory governor in the sandbox is doing (pressure.json). */
|
|
27041
27078
|
pressureFile;
|
|
27079
|
+
/** What the sandbox's programs may really use (budget.json): processors, memory, build jobs, link slots. */
|
|
27080
|
+
budgetFile;
|
|
27042
27081
|
requestsDir;
|
|
27043
27082
|
responsesDir;
|
|
27044
27083
|
sessionsDir;
|
|
@@ -27052,6 +27091,7 @@ var RunDir = class {
|
|
|
27052
27091
|
this.sandboxFile = path6.join(this.root, "sandbox.json");
|
|
27053
27092
|
this.vpnFile = path6.join(this.root, "vpn.json");
|
|
27054
27093
|
this.pressureFile = path6.join(this.root, "pressure.json");
|
|
27094
|
+
this.budgetFile = path6.join(this.root, "budget.json");
|
|
27055
27095
|
this.requestsDir = path6.join(this.root, "requests");
|
|
27056
27096
|
this.responsesDir = path6.join(this.root, "responses");
|
|
27057
27097
|
this.sessionsDir = path6.join(this.root, "sessions");
|
|
@@ -27491,7 +27531,7 @@ function writeStatus(phase, message) {
|
|
|
27491
27531
|
}
|
|
27492
27532
|
|
|
27493
27533
|
// src/guest/boot/boot.ts
|
|
27494
|
-
import
|
|
27534
|
+
import fs60 from "node:fs";
|
|
27495
27535
|
import path73 from "node:path";
|
|
27496
27536
|
import { spawn as spawn9 } from "node:child_process";
|
|
27497
27537
|
|
|
@@ -27596,7 +27636,16 @@ function execOutput(file3, args, options = {}) {
|
|
|
27596
27636
|
return result.status === 0 ? String(result.stdout ?? "").trim() : "";
|
|
27597
27637
|
}
|
|
27598
27638
|
function runScript(name, args = []) {
|
|
27599
|
-
|
|
27639
|
+
const result = spawnSync(SYSTEM.powershell(), scriptArgs(name, args), {
|
|
27640
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
27641
|
+
encoding: "utf8",
|
|
27642
|
+
windowsHide: true
|
|
27643
|
+
});
|
|
27644
|
+
if (result.error) throw result.error;
|
|
27645
|
+
const errors = String(result.stderr ?? "").trim();
|
|
27646
|
+
if (errors) process.stderr.write(errors + "\n");
|
|
27647
|
+
if (result.status !== 0)
|
|
27648
|
+
throw new Error(name + " failed with exit code " + result.status + (errors ? ": " + errors.slice(0, 400) : ""));
|
|
27600
27649
|
}
|
|
27601
27650
|
function scriptOutput(name, args = [], options = {}) {
|
|
27602
27651
|
return execOutput(SYSTEM.powershell(), scriptArgs(name, args), options);
|
|
@@ -27622,14 +27671,40 @@ function robocopy(from, to, files = []) {
|
|
|
27622
27671
|
fs12.copyFileSync(path15.join(from, f), path15.join(to, f));
|
|
27623
27672
|
return;
|
|
27624
27673
|
}
|
|
27625
|
-
const what = files.length ? files : ["/E"
|
|
27626
|
-
const
|
|
27627
|
-
|
|
27628
|
-
[
|
|
27629
|
-
|
|
27674
|
+
const what = files.length ? files : ["/E"];
|
|
27675
|
+
const passes = [
|
|
27676
|
+
["/MT:16", "/R:1", "/W:1"],
|
|
27677
|
+
["/MT:1", "/R:4", "/W:3"]
|
|
27678
|
+
];
|
|
27679
|
+
let code = null;
|
|
27680
|
+
let output3 = "";
|
|
27681
|
+
for (const pass of passes) {
|
|
27682
|
+
const result = spawnSync(
|
|
27683
|
+
SYSTEM.robocopy(),
|
|
27684
|
+
[
|
|
27685
|
+
from,
|
|
27686
|
+
to,
|
|
27687
|
+
...what,
|
|
27688
|
+
...files.length ? [] : [pass[0]],
|
|
27689
|
+
pass[1],
|
|
27690
|
+
pass[2],
|
|
27691
|
+
"/NFL",
|
|
27692
|
+
"/NDL",
|
|
27693
|
+
"/NJH",
|
|
27694
|
+
"/NJS",
|
|
27695
|
+
"/NP",
|
|
27696
|
+
"/XJ"
|
|
27697
|
+
],
|
|
27698
|
+
{ encoding: "utf8", windowsHide: true }
|
|
27699
|
+
);
|
|
27700
|
+
code = result.status;
|
|
27701
|
+
output3 = String(result.stdout ?? "") + String(result.stderr ?? "");
|
|
27702
|
+
if (!robocopyFailed(code)) return;
|
|
27703
|
+
}
|
|
27704
|
+
const why = robocopyErrors(output3);
|
|
27705
|
+
throw new Error(
|
|
27706
|
+
"robocopy " + from + " -> " + to + " failed (exit " + code + ": " + robocopyMeaning(code) + ")" + (why.length ? ": " + why.join(" | ") : "")
|
|
27630
27707
|
);
|
|
27631
|
-
if ((result.status ?? 16) >= 8)
|
|
27632
|
-
throw new Error("robocopy " + from + " -> " + to + " failed (exit " + result.status + ")");
|
|
27633
27708
|
}
|
|
27634
27709
|
function copyNode(from, to) {
|
|
27635
27710
|
const work = stagingFolder(to);
|
|
@@ -29183,9 +29258,17 @@ async function setupUv(env) {
|
|
|
29183
29258
|
function ghConfigDir() {
|
|
29184
29259
|
return path34.join(stateDir, "gh");
|
|
29185
29260
|
}
|
|
29261
|
+
function deliveredGhConfigDir() {
|
|
29262
|
+
return path34.join(localDir, "gh-token");
|
|
29263
|
+
}
|
|
29264
|
+
function ghExePath() {
|
|
29265
|
+
const entry = CLI_TOOLS.find((t) => t.name === "gh");
|
|
29266
|
+
const dir = tool("cli", "gh");
|
|
29267
|
+
return path34.join(entry?.subdir ? path34.join(dir, entry.subdir) : dir, entry?.exe ?? "gh.exe");
|
|
29268
|
+
}
|
|
29186
29269
|
var toolVars = {
|
|
29187
29270
|
gh: () => ({
|
|
29188
|
-
GH_CONFIG_DIR: mkdirp(ghConfigDir()),
|
|
29271
|
+
GH_CONFIG_DIR: exists(deliveredGhConfigDir()) ? deliveredGhConfigDir() : mkdirp(ghConfigDir()),
|
|
29189
29272
|
GH_NO_UPDATE_NOTIFIER: "1",
|
|
29190
29273
|
GH_NO_EXTENSION_UPDATE_NOTIFIER: "1"
|
|
29191
29274
|
})
|
|
@@ -29990,6 +30073,10 @@ var ensureNvm = async () => {
|
|
|
29990
30073
|
log("Downloading nvm-windows (" + asset.url.split("/").slice(-2, -1)[0] + ") ...");
|
|
29991
30074
|
await downloader.archive(asset.url, NVM_HOME, { sha256: asset.sha256, locate: "nvm.exe", fileName: asset.name });
|
|
29992
30075
|
};
|
|
30076
|
+
var hostNodeFolder = (version2) => {
|
|
30077
|
+
const dir = path45.join(hostToolsDir, "node");
|
|
30078
|
+
return session.hostTools.nodeVersion?.replace(/^v/, "") === version2 && exists(path45.join(dir, "node.exe")) ? dir : null;
|
|
30079
|
+
};
|
|
29993
30080
|
var installNodeVersion = async (version2) => {
|
|
29994
30081
|
const dir = path45.join(NVM_HOME, "v" + version2);
|
|
29995
30082
|
const fromHost = path45.join(HOST_NVM, "v" + version2);
|
|
@@ -29999,6 +30086,12 @@ var installNodeVersion = async (version2) => {
|
|
|
29999
30086
|
copyNode(fromHost, dir);
|
|
30000
30087
|
return;
|
|
30001
30088
|
}
|
|
30089
|
+
const hostNode = hostNodeFolder(version2);
|
|
30090
|
+
if (hostNode) {
|
|
30091
|
+
log("Copying Node " + version2 + " from this PC (without global packages) ...");
|
|
30092
|
+
copyNode(hostNode, dir);
|
|
30093
|
+
return;
|
|
30094
|
+
}
|
|
30002
30095
|
log("Downloading Node " + version2 + " (~30 MB once) ...");
|
|
30003
30096
|
mkdirp(NVM_TEMP);
|
|
30004
30097
|
let out;
|
|
@@ -30007,8 +30100,13 @@ var installNodeVersion = async (version2) => {
|
|
|
30007
30100
|
} finally {
|
|
30008
30101
|
safeRemove(NVM_TEMP, NVM_HOME);
|
|
30009
30102
|
}
|
|
30010
|
-
if (!exists(path45.join(dir, "node.exe")))
|
|
30011
|
-
|
|
30103
|
+
if (!exists(path45.join(dir, "node.exe"))) {
|
|
30104
|
+
const tail2 = out.trim().split(/\r?\n/).filter(Boolean).slice(-3).join(" ");
|
|
30105
|
+
const why = /complete/i.test(out) ? "nvm said it finished, but its move into the data folder did not happen" : "nvm could not download or unpack it: check the internet connection and the free disk space";
|
|
30106
|
+
throw new Error(
|
|
30107
|
+
"nvm install " + version2 + " did not leave " + path45.join(dir, "node.exe") + " (" + why + ")" + (tail2 ? ". nvm printed: " + tail2 : "")
|
|
30108
|
+
);
|
|
30109
|
+
}
|
|
30012
30110
|
};
|
|
30013
30111
|
var activate = async (version2) => {
|
|
30014
30112
|
await nvm(["use", version2]);
|
|
@@ -30016,6 +30114,10 @@ var activate = async (version2) => {
|
|
|
30016
30114
|
fs36.rmSync(NVM_SYMLINK, { recursive: true, force: true });
|
|
30017
30115
|
fs36.symlinkSync(path45.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
|
|
30018
30116
|
};
|
|
30117
|
+
var PLAYWRIGHT_VARS = () => ({
|
|
30118
|
+
PLAYWRIGHT_BROWSERS_PATH: tool("ms-playwright"),
|
|
30119
|
+
PLAYWRIGHT_MCP_BROWSER: "msedge"
|
|
30120
|
+
});
|
|
30019
30121
|
async function setupNode(env, versions, config2) {
|
|
30020
30122
|
if (dryRun) {
|
|
30021
30123
|
log("(dry run) would provision nvm and Node " + versions.node.spec + " (from " + versions.node.source + ")");
|
|
@@ -30049,13 +30151,14 @@ async function setupNode(env, versions, config2) {
|
|
|
30049
30151
|
warn("Node " + version2 + " from this PC: " + errMsg(e));
|
|
30050
30152
|
}
|
|
30051
30153
|
}
|
|
30052
|
-
Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK });
|
|
30154
|
+
Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK, ...PLAYWRIGHT_VARS() });
|
|
30053
30155
|
if (duringSession()) env.prepend.push(path45.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
|
|
30054
30156
|
else {
|
|
30055
30157
|
await activate(main);
|
|
30056
30158
|
env.prepend.push(NVM_HOME, NVM_SYMLINK);
|
|
30057
30159
|
}
|
|
30058
30160
|
env.summary.push("node: " + main + " (from " + versions.node.source + ", switch with nvm use)");
|
|
30161
|
+
env.summary.push("playwright: ready (Edge; browsers it downloads are kept; in tests use channel: 'msedge')");
|
|
30059
30162
|
await packageManagers(env, config2, main);
|
|
30060
30163
|
}
|
|
30061
30164
|
var packageManagers = async (env, config2, version2) => {
|
|
@@ -31966,11 +32069,17 @@ import os8 from "node:os";
|
|
|
31966
32069
|
import path51 from "node:path";
|
|
31967
32070
|
|
|
31968
32071
|
// src/shared/memory/policy.ts
|
|
32072
|
+
function buildJobs(cpus, memoryGb) {
|
|
32073
|
+
return Math.max(2, Math.min(cpus, Math.floor((memoryGb - 6) / 3)));
|
|
32074
|
+
}
|
|
32075
|
+
function linkSlotsFor(memoryGb) {
|
|
32076
|
+
return Math.max(2, Math.min(8, Math.floor((memoryGb - 6) / 3)));
|
|
32077
|
+
}
|
|
31969
32078
|
function cargoJobs(cpus, memoryGb, sessions) {
|
|
31970
|
-
const byCpu = Math.max(2, Math.min(
|
|
32079
|
+
const byCpu = Math.max(2, Math.min(8, Math.floor(cpus / 4)));
|
|
31971
32080
|
const byMemory = Math.max(1, Math.floor(memoryGb / 4));
|
|
31972
32081
|
const jobs = Math.min(byCpu, byMemory);
|
|
31973
|
-
return Math.max(1, Math.min(jobs, Math.floor(
|
|
32082
|
+
return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions))));
|
|
31974
32083
|
}
|
|
31975
32084
|
|
|
31976
32085
|
// src/guest/toolchains/native/rust-extras.ts
|
|
@@ -31993,7 +32102,7 @@ function linkGate(env, rust, host) {
|
|
|
31993
32102
|
const gate = path51.join(mkdirp(tool("shims")), "linkgate.exe");
|
|
31994
32103
|
fs41.copyFileSync(ensureCompiled("linkgate"), gate);
|
|
31995
32104
|
const memoryGb = os8.totalmem() / 1024 ** 3;
|
|
31996
|
-
const slots = rust.linkSlots === "auto" ?
|
|
32105
|
+
const slots = rust.linkSlots === "auto" ? linkSlotsFor(memoryGb) : rust.linkSlots;
|
|
31997
32106
|
env.vars.AGENT_LINK_SLOTS = String(slots);
|
|
31998
32107
|
env.vars.AGENT_REAL_LINKER = gcc;
|
|
31999
32108
|
env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gate;
|
|
@@ -33042,9 +33151,31 @@ function buildFirewallCommands(exemptIps) {
|
|
|
33042
33151
|
}
|
|
33043
33152
|
return commands;
|
|
33044
33153
|
}
|
|
33154
|
+
var ATTACH_RULE = "AgentSandbox-Attach";
|
|
33155
|
+
function hasShortName(file3) {
|
|
33156
|
+
return file3.split(/[/\\]/).some((part) => /~\d/.test(part));
|
|
33157
|
+
}
|
|
33158
|
+
function attachRuleCommands(ptyHostExe) {
|
|
33159
|
+
return [
|
|
33160
|
+
["advfirewall", "firewall", "delete", "rule", "name=" + ATTACH_RULE],
|
|
33161
|
+
[
|
|
33162
|
+
"advfirewall",
|
|
33163
|
+
"firewall",
|
|
33164
|
+
"add",
|
|
33165
|
+
"rule",
|
|
33166
|
+
"name=" + ATTACH_RULE,
|
|
33167
|
+
"dir=in",
|
|
33168
|
+
"action=allow",
|
|
33169
|
+
"enable=yes",
|
|
33170
|
+
"profile=any",
|
|
33171
|
+
"protocol=tcp",
|
|
33172
|
+
"remoteip=LocalSubnet",
|
|
33173
|
+
"program=" + ptyHostExe
|
|
33174
|
+
]
|
|
33175
|
+
];
|
|
33176
|
+
}
|
|
33045
33177
|
|
|
33046
33178
|
// src/guest/network/firewall.ts
|
|
33047
|
-
var ATTACH_RULE = "AgentSandbox-Attach";
|
|
33048
33179
|
var netsh = (args) => {
|
|
33049
33180
|
const r = spawnSync5(SYSTEM.netsh(), args, { encoding: "utf8", windowsHide: true });
|
|
33050
33181
|
return { status: r.status, out: (r.stdout ?? "") + (r.stderr ?? "") };
|
|
@@ -33078,23 +33209,38 @@ var waitForInternet = async (seconds) => {
|
|
|
33078
33209
|
}
|
|
33079
33210
|
return false;
|
|
33080
33211
|
};
|
|
33081
|
-
var
|
|
33082
|
-
|
|
33083
|
-
|
|
33084
|
-
|
|
33085
|
-
|
|
33086
|
-
|
|
33087
|
-
|
|
33088
|
-
|
|
33089
|
-
|
|
33090
|
-
|
|
33091
|
-
|
|
33092
|
-
|
|
33093
|
-
|
|
33094
|
-
|
|
33095
|
-
|
|
33096
|
-
|
|
33097
|
-
];
|
|
33212
|
+
var problems = [];
|
|
33213
|
+
function networkProblems() {
|
|
33214
|
+
return problems;
|
|
33215
|
+
}
|
|
33216
|
+
function longPath(file3) {
|
|
33217
|
+
if (!hasShortName(file3)) return file3;
|
|
33218
|
+
try {
|
|
33219
|
+
return fs48.realpathSync.native(file3);
|
|
33220
|
+
} catch {
|
|
33221
|
+
return file3;
|
|
33222
|
+
}
|
|
33223
|
+
}
|
|
33224
|
+
async function applyAttachRule(ptyHostExe) {
|
|
33225
|
+
if (!session.attach.enabled) return;
|
|
33226
|
+
if (!ptyHostExe) {
|
|
33227
|
+
problems.push("attach: the session host was not built, so the firewall rule for it was not created");
|
|
33228
|
+
warn(problems[problems.length - 1]);
|
|
33229
|
+
return;
|
|
33230
|
+
}
|
|
33231
|
+
let last = "";
|
|
33232
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
33233
|
+
try {
|
|
33234
|
+
run2(attachRuleCommands(longPath(ptyHostExe)));
|
|
33235
|
+
return;
|
|
33236
|
+
} catch (e) {
|
|
33237
|
+
last = errMsg(e);
|
|
33238
|
+
if (attempt < 3) await new Promise((r) => setTimeout(r, 1e3));
|
|
33239
|
+
}
|
|
33240
|
+
}
|
|
33241
|
+
problems.push("attach: the firewall rule for the session host could not be created (" + last + ")");
|
|
33242
|
+
warn("PROTECTION MISSING: " + problems[problems.length - 1]);
|
|
33243
|
+
}
|
|
33098
33244
|
function run2(commands) {
|
|
33099
33245
|
for (const c of commands) {
|
|
33100
33246
|
const r = netsh(c);
|
|
@@ -33107,13 +33253,14 @@ async function applyNetworkPolicy(ptyHostExe) {
|
|
|
33107
33253
|
log("Networking is disabled for this sandbox.");
|
|
33108
33254
|
return "offline";
|
|
33109
33255
|
}
|
|
33110
|
-
const
|
|
33111
|
-
const exempt =
|
|
33112
|
-
const lanRules =
|
|
33256
|
+
const block2 = session.network.blockPrivateRanges;
|
|
33257
|
+
const exempt = block2 ? discoverExemptIps() : [];
|
|
33258
|
+
const lanRules = block2 ? buildFirewallCommands(exempt) : [];
|
|
33259
|
+
const forwardRules = forwardRule();
|
|
33113
33260
|
const commands = [
|
|
33114
33261
|
...lanRules,
|
|
33115
|
-
...ptyHostExe && session.attach.enabled ?
|
|
33116
|
-
...
|
|
33262
|
+
...ptyHostExe && session.attach.enabled ? attachRuleCommands(ptyHostExe) : [],
|
|
33263
|
+
...forwardRules
|
|
33117
33264
|
];
|
|
33118
33265
|
if (isWin && !dryRun) {
|
|
33119
33266
|
try {
|
|
@@ -33127,20 +33274,33 @@ async function applyNetworkPolicy(ptyHostExe) {
|
|
|
33127
33274
|
warn("network.dns could not be applied: " + errMsg(e));
|
|
33128
33275
|
}
|
|
33129
33276
|
}
|
|
33130
|
-
if (!
|
|
33131
|
-
if (
|
|
33277
|
+
if (!block2) log("Private-range blocking disabled by config.");
|
|
33278
|
+
if (block2)
|
|
33132
33279
|
log(
|
|
33133
33280
|
"Gateway/DNS addresses kept reachable for DNS only: " + (exempt.length ? [...new Set(exempt)].join(", ") : "(none found)")
|
|
33134
33281
|
);
|
|
33135
33282
|
if (!isWin || dryRun) {
|
|
33136
33283
|
log("(dry run) firewall plan:");
|
|
33137
33284
|
for (const c of commands) log(" netsh " + c.join(" "));
|
|
33138
|
-
return
|
|
33285
|
+
return block2 ? "blocked" : "open";
|
|
33139
33286
|
}
|
|
33140
33287
|
if (commands.length === 0) return "open";
|
|
33141
|
-
const online =
|
|
33142
|
-
|
|
33143
|
-
|
|
33288
|
+
const online = block2 ? await waitForInternet(30) : true;
|
|
33289
|
+
const failures = [];
|
|
33290
|
+
try {
|
|
33291
|
+
run2(lanRules);
|
|
33292
|
+
} catch (e) {
|
|
33293
|
+
failures.push(errMsg(e));
|
|
33294
|
+
}
|
|
33295
|
+
await applyAttachRule(ptyHostExe);
|
|
33296
|
+
try {
|
|
33297
|
+
run2(forwardRules);
|
|
33298
|
+
} catch (e) {
|
|
33299
|
+
problems.push("forwardPorts: the firewall rule for the relays could not be created (" + errMsg(e) + ")");
|
|
33300
|
+
warn("PROTECTION MISSING: " + problems[problems.length - 1]);
|
|
33301
|
+
}
|
|
33302
|
+
if (failures.length) throw new Error(failures[0]);
|
|
33303
|
+
if (!block2) return "open";
|
|
33144
33304
|
if (online && !await waitForInternet(15)) {
|
|
33145
33305
|
run2(lanRules.filter((c) => c[2] === "delete"));
|
|
33146
33306
|
warn(
|
|
@@ -33370,18 +33530,109 @@ function setupGitConfig(env) {
|
|
|
33370
33530
|
spawnSync7(git, ["config", "--global", "core.autocrlf", "input"], { env: rest, windowsHide: true, stdio: "ignore" });
|
|
33371
33531
|
}
|
|
33372
33532
|
|
|
33533
|
+
// src/guest/setup/github-token.ts
|
|
33534
|
+
import fs53 from "node:fs";
|
|
33535
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
33536
|
+
|
|
33537
|
+
// src/shared/github/token.ts
|
|
33538
|
+
var MIN_LENGTH = 20;
|
|
33539
|
+
var MAX_LENGTH = 255;
|
|
33540
|
+
var PRINTABLE = /^[\x21-\x7e]+$/;
|
|
33541
|
+
var GithubTokenSchema = external_exports.string().min(MIN_LENGTH).max(MAX_LENGTH).regex(PRINTABLE);
|
|
33542
|
+
var TOKEN_VARIABLES = /^(GH_TOKEN|GITHUB_TOKEN|GH_ENTERPRISE_TOKEN|GITHUB_ENTERPRISE_TOKEN)$/i;
|
|
33543
|
+
var ghEnv = (base, configDir) => ({
|
|
33544
|
+
...Object.fromEntries(
|
|
33545
|
+
Object.entries(base).filter((e) => e[1] !== void 0 && !TOKEN_VARIABLES.test(e[0]))
|
|
33546
|
+
),
|
|
33547
|
+
GH_CONFIG_DIR: configDir,
|
|
33548
|
+
GH_PROMPT_DISABLED: "1",
|
|
33549
|
+
GH_NO_UPDATE_NOTIFIER: "1"
|
|
33550
|
+
});
|
|
33551
|
+
function ghLoginCommand(ghExe, configDir, token, base) {
|
|
33552
|
+
return {
|
|
33553
|
+
file: ghExe,
|
|
33554
|
+
args: [
|
|
33555
|
+
"auth",
|
|
33556
|
+
"login",
|
|
33557
|
+
"--hostname",
|
|
33558
|
+
"github.com",
|
|
33559
|
+
"--git-protocol",
|
|
33560
|
+
"https",
|
|
33561
|
+
"--insecure-storage",
|
|
33562
|
+
"--with-token"
|
|
33563
|
+
],
|
|
33564
|
+
input: token + "\n",
|
|
33565
|
+
env: ghEnv(base, configDir)
|
|
33566
|
+
};
|
|
33567
|
+
}
|
|
33568
|
+
function ghSetupGitCommand(ghExe, configDir, base) {
|
|
33569
|
+
return { file: ghExe, args: ["auth", "setup-git", "--hostname", "github.com"], env: ghEnv(base, configDir) };
|
|
33570
|
+
}
|
|
33571
|
+
function ghOutputText(text, token) {
|
|
33572
|
+
const clean = token ? text.split(token).join("***") : text;
|
|
33573
|
+
return clean.replace(/\s+/g, " ").trim().slice(0, 300);
|
|
33574
|
+
}
|
|
33575
|
+
|
|
33576
|
+
// src/guest/setup/github-token.ts
|
|
33577
|
+
var GH_TIMEOUT_MS = 6e4;
|
|
33578
|
+
function prepareGithubFolder(token) {
|
|
33579
|
+
const dir = deliveredGhConfigDir();
|
|
33580
|
+
fs53.rmSync(dir, { recursive: true, force: true });
|
|
33581
|
+
if (!token) return false;
|
|
33582
|
+
mkdirp(dir);
|
|
33583
|
+
return true;
|
|
33584
|
+
}
|
|
33585
|
+
function runGh(command, token, what) {
|
|
33586
|
+
const result = spawnSync8(command.file, [...command.args], {
|
|
33587
|
+
env: command.env,
|
|
33588
|
+
encoding: "utf8",
|
|
33589
|
+
windowsHide: true,
|
|
33590
|
+
timeout: GH_TIMEOUT_MS,
|
|
33591
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
33592
|
+
...command.input !== void 0 ? { input: command.input } : {}
|
|
33593
|
+
});
|
|
33594
|
+
if (result.error) throw new Error(what + " could not run: " + ghOutputText(result.error.message, token));
|
|
33595
|
+
if (result.status !== 0)
|
|
33596
|
+
throw new Error(
|
|
33597
|
+
what + " failed: " + ghOutputText(String(result.stderr ?? "") || String(result.stdout ?? ""), token)
|
|
33598
|
+
);
|
|
33599
|
+
}
|
|
33600
|
+
function loginGithub(token, env) {
|
|
33601
|
+
if (dryRun) {
|
|
33602
|
+
log("(dry run) would log gh in with the GitHub token from your PC");
|
|
33603
|
+
return;
|
|
33604
|
+
}
|
|
33605
|
+
const gh2 = ghExePath();
|
|
33606
|
+
const dir = deliveredGhConfigDir();
|
|
33607
|
+
if (!exists(gh2) || env.GH_CONFIG_DIR !== dir) {
|
|
33608
|
+
fs53.rmSync(dir, { recursive: true, force: true });
|
|
33609
|
+
log("A GitHub token arrived, but gh is not set up in this sandbox (toolchains.cli.gh), so it is not used.");
|
|
33610
|
+
return;
|
|
33611
|
+
}
|
|
33612
|
+
try {
|
|
33613
|
+
runGh(ghLoginCommand(gh2, dir, token, env), token, "gh auth login");
|
|
33614
|
+
runGh(ghSetupGitCommand(gh2, dir, env), token, "gh auth setup-git");
|
|
33615
|
+
} catch (e) {
|
|
33616
|
+
fs53.rmSync(dir, { recursive: true, force: true });
|
|
33617
|
+
env.GH_CONFIG_DIR = mkdirp(ghConfigDir());
|
|
33618
|
+
addMachineEnvironment({ GH_CONFIG_DIR: env.GH_CONFIG_DIR }, []);
|
|
33619
|
+
throw e;
|
|
33620
|
+
}
|
|
33621
|
+
log("gh and https git to github.com use the GitHub token from your PC (github.shareToken); the agent can read it.");
|
|
33622
|
+
}
|
|
33623
|
+
|
|
33373
33624
|
// src/guest/sessions/pty-host.ts
|
|
33374
33625
|
function ensurePtyHost() {
|
|
33375
33626
|
return ensureCompiled("ptyhost");
|
|
33376
33627
|
}
|
|
33377
33628
|
|
|
33378
33629
|
// src/guest/toolchains/leftovers.ts
|
|
33379
|
-
import
|
|
33630
|
+
import fs54 from "node:fs";
|
|
33380
33631
|
import path66 from "node:path";
|
|
33381
33632
|
var STAGING = /\.staging-[0-9a-f]+$/i;
|
|
33382
33633
|
var entries2 = (dir) => {
|
|
33383
33634
|
try {
|
|
33384
|
-
return
|
|
33635
|
+
return fs54.readdirSync(dir, { withFileTypes: true });
|
|
33385
33636
|
} catch {
|
|
33386
33637
|
return [];
|
|
33387
33638
|
}
|
|
@@ -33398,17 +33649,17 @@ function pruneToolLeftovers() {
|
|
|
33398
33649
|
|
|
33399
33650
|
// src/guest/audit/process-audit.ts
|
|
33400
33651
|
import path67 from "node:path";
|
|
33401
|
-
import { spawnSync as
|
|
33652
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
33402
33653
|
var PROCESS_CREATION = "{0CCE922B-69AE-11D9-BED3-505054503030}";
|
|
33403
33654
|
var auditOn = () => Boolean(session.auditProcesses) && isWin && !dryRun;
|
|
33404
33655
|
function enableProcessAudit() {
|
|
33405
33656
|
if (!auditOn()) return;
|
|
33406
|
-
|
|
33657
|
+
spawnSync9(
|
|
33407
33658
|
path67.join(process.env.WINDIR ?? "C:\\Windows", "System32", "auditpol.exe"),
|
|
33408
33659
|
["/set", "/subcategory:" + PROCESS_CREATION, "/success:enable"],
|
|
33409
33660
|
{ windowsHide: true, stdio: "ignore" }
|
|
33410
33661
|
);
|
|
33411
|
-
|
|
33662
|
+
spawnSync9(
|
|
33412
33663
|
SYSTEM.reg(),
|
|
33413
33664
|
[
|
|
33414
33665
|
"add",
|
|
@@ -33428,7 +33679,8 @@ function enableProcessAudit() {
|
|
|
33428
33679
|
|
|
33429
33680
|
// src/guest/vpn/vpn.ts
|
|
33430
33681
|
import dns2 from "node:dns";
|
|
33431
|
-
import
|
|
33682
|
+
import fs58 from "node:fs";
|
|
33683
|
+
import net3 from "node:net";
|
|
33432
33684
|
import os14 from "node:os";
|
|
33433
33685
|
import path71 from "node:path";
|
|
33434
33686
|
|
|
@@ -33584,22 +33836,22 @@ function directiveOf(line) {
|
|
|
33584
33836
|
return { name: parts2[0].toLowerCase(), args: parts2.slice(1) };
|
|
33585
33837
|
}
|
|
33586
33838
|
function inspectOvpn(text) {
|
|
33587
|
-
const
|
|
33839
|
+
const problems2 = [];
|
|
33588
33840
|
const found = [];
|
|
33589
33841
|
const refuse = (message) => {
|
|
33590
|
-
if (
|
|
33842
|
+
if (problems2.length < 20 && !problems2.includes(message)) problems2.push(message);
|
|
33591
33843
|
};
|
|
33592
33844
|
if (Buffer.byteLength(text, "utf8") > MAX_OVPN_BYTES) return { ok: false, problems: ["the file is too big"] };
|
|
33593
33845
|
if (text.includes("\0")) return { ok: false, problems: ["the file is not text"] };
|
|
33594
33846
|
const lines = text.split(/\r?\n/);
|
|
33595
33847
|
if (lines.length > MAX_LINES) return { ok: false, problems: ["the file has too many lines"] };
|
|
33596
|
-
let
|
|
33848
|
+
let block2 = null;
|
|
33597
33849
|
let defaultProto = "udp";
|
|
33598
33850
|
lines.forEach((line, i) => {
|
|
33599
33851
|
const at = "line " + (i + 1) + ": ";
|
|
33600
33852
|
const trimmed = line.trim();
|
|
33601
|
-
if (
|
|
33602
|
-
if (trimmed.toLowerCase() === "</" +
|
|
33853
|
+
if (block2) {
|
|
33854
|
+
if (trimmed.toLowerCase() === "</" + block2 + ">") block2 = null;
|
|
33603
33855
|
else if (/^<\/?[A-Za-z-]+>$/.test(trimmed)) refuse(at + "a section inside a section");
|
|
33604
33856
|
return;
|
|
33605
33857
|
}
|
|
@@ -33607,7 +33859,7 @@ function inspectOvpn(text) {
|
|
|
33607
33859
|
if (open2) {
|
|
33608
33860
|
const tag = open2[1].toLowerCase();
|
|
33609
33861
|
if (!BLOCKS.has(tag)) refuse(at + "<" + tag + "> is not allowed");
|
|
33610
|
-
|
|
33862
|
+
block2 = tag;
|
|
33611
33863
|
return;
|
|
33612
33864
|
}
|
|
33613
33865
|
const d = directiveOf(line);
|
|
@@ -33632,10 +33884,10 @@ function inspectOvpn(text) {
|
|
|
33632
33884
|
}
|
|
33633
33885
|
});
|
|
33634
33886
|
const remotes = found.map((r) => ({ host: r.host, port: r.port, proto: r.proto ?? defaultProto }));
|
|
33635
|
-
if (
|
|
33887
|
+
if (block2) refuse("a <" + block2 + "> section is never closed");
|
|
33636
33888
|
if (remotes.length === 0) refuse("it names no remote server");
|
|
33637
33889
|
if (remotes.length > 64) refuse("it names too many servers");
|
|
33638
|
-
return
|
|
33890
|
+
return problems2.length ? { ok: false, problems: problems2 } : { ok: true, remotes };
|
|
33639
33891
|
}
|
|
33640
33892
|
function assertSafeOvpn(text, what) {
|
|
33641
33893
|
const report = inspectOvpn(text);
|
|
@@ -33672,9 +33924,9 @@ var inRange = (text, low, high) => {
|
|
|
33672
33924
|
};
|
|
33673
33925
|
var splitList = (text) => text.split(",").map((s) => s.trim()).filter(Boolean);
|
|
33674
33926
|
function inspectWireguard(text) {
|
|
33675
|
-
const
|
|
33927
|
+
const problems2 = [];
|
|
33676
33928
|
const refuse = (message) => {
|
|
33677
|
-
if (
|
|
33929
|
+
if (problems2.length < 20 && !problems2.includes(message)) problems2.push(message);
|
|
33678
33930
|
};
|
|
33679
33931
|
if (Buffer.byteLength(text, "utf8") > MAX_WIREGUARD_BYTES) return { ok: false, problems: ["the file is too big"] };
|
|
33680
33932
|
if (text.includes("\0")) return { ok: false, problems: ["the file is not text"] };
|
|
@@ -33716,7 +33968,7 @@ function inspectWireguard(text) {
|
|
|
33716
33968
|
if (interfaces.length !== 1) refuse("it needs exactly one [Interface] section");
|
|
33717
33969
|
if (peers.length === 0) refuse("it has no [Peer] section");
|
|
33718
33970
|
if (peers.length > MAX_PEERS) refuse("it has too many [Peer] sections");
|
|
33719
|
-
if (
|
|
33971
|
+
if (problems2.length) return { ok: false, problems: problems2 };
|
|
33720
33972
|
const face = interfaces[0];
|
|
33721
33973
|
const privateKey = one(face, "privatekey");
|
|
33722
33974
|
if (!privateKey) refuse("[Interface] has no PrivateKey");
|
|
@@ -33763,7 +34015,7 @@ function inspectWireguard(text) {
|
|
|
33763
34015
|
...keepalive !== void 0 ? { keepalive } : {}
|
|
33764
34016
|
});
|
|
33765
34017
|
});
|
|
33766
|
-
if (
|
|
34018
|
+
if (problems2.length || !privateKey) return { ok: false, problems: problems2 };
|
|
33767
34019
|
return {
|
|
33768
34020
|
ok: true,
|
|
33769
34021
|
config: {
|
|
@@ -33841,8 +34093,22 @@ var drop = (name) => [
|
|
|
33841
34093
|
"rule",
|
|
33842
34094
|
"name=" + VPN_RULE_PREFIX + name
|
|
33843
34095
|
];
|
|
34096
|
+
var block = (name, extra) => [
|
|
34097
|
+
"advfirewall",
|
|
34098
|
+
"firewall",
|
|
34099
|
+
"add",
|
|
34100
|
+
"rule",
|
|
34101
|
+
"name=" + VPN_RULE_PREFIX + name,
|
|
34102
|
+
"dir=out",
|
|
34103
|
+
"action=block",
|
|
34104
|
+
"enable=yes",
|
|
34105
|
+
"profile=any",
|
|
34106
|
+
...extra
|
|
34107
|
+
];
|
|
34108
|
+
var BLOCK_RULES = ["Block-Internet", "Block-IPv6", "Block-DNS-UDP", "Block-DNS-TCP"];
|
|
33844
34109
|
function ruleNames(serverCount) {
|
|
33845
34110
|
return [
|
|
34111
|
+
...BLOCK_RULES,
|
|
33846
34112
|
"Loopback",
|
|
33847
34113
|
"DHCP",
|
|
33848
34114
|
"Host",
|
|
@@ -33850,6 +34116,39 @@ function ruleNames(serverCount) {
|
|
|
33850
34116
|
...Array.from({ length: Math.max(serverCount, 0) }, (_v, i) => "Server-" + (i + 1))
|
|
33851
34117
|
];
|
|
33852
34118
|
}
|
|
34119
|
+
var NOT_INTERNET = [
|
|
34120
|
+
["0.0.0.0", "0.255.255.255"],
|
|
34121
|
+
["10.0.0.0", "10.255.255.255"],
|
|
34122
|
+
["100.64.0.0", "100.127.255.255"],
|
|
34123
|
+
["127.0.0.0", "127.255.255.255"],
|
|
34124
|
+
["169.254.0.0", "169.254.255.255"],
|
|
34125
|
+
["172.16.0.0", "172.31.255.255"],
|
|
34126
|
+
["192.168.0.0", "192.168.255.255"],
|
|
34127
|
+
["224.0.0.0", "255.255.255.255"]
|
|
34128
|
+
];
|
|
34129
|
+
var LAST_IPV4 = 4294967295;
|
|
34130
|
+
function ipNumber(ip) {
|
|
34131
|
+
return ip.split(".").reduce((n, part) => n * 256 + Number(part), 0);
|
|
34132
|
+
}
|
|
34133
|
+
function ipText(n) {
|
|
34134
|
+
return [24, 16, 8, 0].map((shift) => Math.floor(n / 2 ** shift) % 256).join(".");
|
|
34135
|
+
}
|
|
34136
|
+
function ipv4Except(excluded) {
|
|
34137
|
+
const sorted = [...excluded].sort((a, b) => a[0] - b[0]);
|
|
34138
|
+
const out = [];
|
|
34139
|
+
let next = 0;
|
|
34140
|
+
for (const [from, to] of sorted) {
|
|
34141
|
+
if (from > next) out.push(ipText(next) + "-" + ipText(from - 1));
|
|
34142
|
+
next = Math.max(next, to + 1);
|
|
34143
|
+
}
|
|
34144
|
+
if (next <= LAST_IPV4) out.push(ipText(next) + "-" + ipText(LAST_IPV4));
|
|
34145
|
+
return out.join(",");
|
|
34146
|
+
}
|
|
34147
|
+
function internetExcept(servers) {
|
|
34148
|
+
const ranges = NOT_INTERNET.map(([a, b]) => [ipNumber(a), ipNumber(b)]);
|
|
34149
|
+
for (const s of cleanServers(servers)) ranges.push([ipNumber(s.ip), ipNumber(s.ip)]);
|
|
34150
|
+
return ipv4Except(ranges);
|
|
34151
|
+
}
|
|
33853
34152
|
function cleanServers(servers) {
|
|
33854
34153
|
const seen = /* @__PURE__ */ new Set();
|
|
33855
34154
|
return servers.filter((s) => {
|
|
@@ -33864,6 +34163,10 @@ function killSwitchCommands(servers, ptyHostExe) {
|
|
|
33864
34163
|
return [
|
|
33865
34164
|
...ruleNames(Math.max(list.length, 8)).map(drop),
|
|
33866
34165
|
["advfirewall", "set", "allprofiles", "state", "on"],
|
|
34166
|
+
block("Block-Internet", ["protocol=any", "remoteip=" + internetExcept(list)]),
|
|
34167
|
+
block("Block-IPv6", ["protocol=any", "remoteip=2000::/3"]),
|
|
34168
|
+
block("Block-DNS-UDP", ["protocol=udp", "remoteport=53"]),
|
|
34169
|
+
block("Block-DNS-TCP", ["protocol=tcp", "remoteport=53"]),
|
|
33867
34170
|
["advfirewall", "set", "allprofiles", "firewallpolicy", "blockinbound,blockoutbound"],
|
|
33868
34171
|
rule("Loopback", ["protocol=any", "remoteip=127.0.0.0/8"]),
|
|
33869
34172
|
rule("DHCP", ["protocol=udp", "localport=68", "remoteport=67"]),
|
|
@@ -33875,7 +34178,21 @@ function killSwitchCommands(servers, ptyHostExe) {
|
|
|
33875
34178
|
}
|
|
33876
34179
|
function tunnelCommands(tunnelIp) {
|
|
33877
34180
|
if (!isIPv4(tunnelIp)) throw new Error("Not an IPv4 address: " + tunnelIp);
|
|
33878
|
-
|
|
34181
|
+
const n = ipNumber(tunnelIp);
|
|
34182
|
+
const notTunnel = ipv4Except([[n, n]]);
|
|
34183
|
+
return [
|
|
34184
|
+
...["Block-Internet", "Block-DNS-UDP", "Block-DNS-TCP"].map((name) => [
|
|
34185
|
+
"advfirewall",
|
|
34186
|
+
"firewall",
|
|
34187
|
+
"set",
|
|
34188
|
+
"rule",
|
|
34189
|
+
"name=" + VPN_RULE_PREFIX + name,
|
|
34190
|
+
"new",
|
|
34191
|
+
"localip=" + notTunnel
|
|
34192
|
+
]),
|
|
34193
|
+
drop("Tunnel"),
|
|
34194
|
+
rule("Tunnel", ["protocol=any", "localip=" + tunnelIp])
|
|
34195
|
+
];
|
|
33879
34196
|
}
|
|
33880
34197
|
function tunnelAddressFromLog(log2) {
|
|
33881
34198
|
const add = /net_addr_v4_add:\s*(\d{1,3}(?:\.\d{1,3}){3})\/\d+/.exec(log2);
|
|
@@ -33888,7 +34205,7 @@ function tunnelAddressFromLog(log2) {
|
|
|
33888
34205
|
|
|
33889
34206
|
// src/guest/vpn/openvpn.ts
|
|
33890
34207
|
import crypto4 from "node:crypto";
|
|
33891
|
-
import
|
|
34208
|
+
import fs55 from "node:fs";
|
|
33892
34209
|
import path68 from "node:path";
|
|
33893
34210
|
|
|
33894
34211
|
// src/shared/vpn/download.ts
|
|
@@ -33925,7 +34242,12 @@ function openvpnDownload(arch2 = process.arch) {
|
|
|
33925
34242
|
const entry = arch2 === "arm64" ? OPENVPN_MSI.arm64 : OPENVPN_MSI.x64;
|
|
33926
34243
|
return { ...entry, url: OPENVPN_MSI.base + entry.file };
|
|
33927
34244
|
}
|
|
33928
|
-
|
|
34245
|
+
function repairServiceQueries() {
|
|
34246
|
+
const did = scriptOutput("repair-wmi-services.ps1");
|
|
34247
|
+
if (did === "removed") log("VPN: repaired the Windows service queries installers use (a Windows Sandbox gap).");
|
|
34248
|
+
else if (did !== "absent" && did !== "kept") warn("VPN: could not check the Windows service queries installers use.");
|
|
34249
|
+
}
|
|
34250
|
+
var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs55.readFileSync(file3)).digest("hex") === sha256;
|
|
33929
34251
|
async function ensureOpenVpn() {
|
|
33930
34252
|
const exe = openvpnExe();
|
|
33931
34253
|
if (!isWin || dryRun) return exe;
|
|
@@ -33936,6 +34258,7 @@ async function ensureOpenVpn() {
|
|
|
33936
34258
|
log("VPN: downloading OpenVPN " + OPENVPN_MSI.version + " (about 6 MB)");
|
|
33937
34259
|
await downloader.file(dl.url, msi, dl.sha256);
|
|
33938
34260
|
}
|
|
34261
|
+
repairServiceQueries();
|
|
33939
34262
|
log("VPN: installing OpenVPN");
|
|
33940
34263
|
const logFile2 = path68.join(toolsDir, "downloads", "openvpn-install.log");
|
|
33941
34264
|
const code = await spawnAsync(SYSTEM.msiexec(), ["/i", msi, "/qn", "/norestart", "/l*v", logFile2], {
|
|
@@ -33949,7 +34272,7 @@ async function ensureOpenVpn() {
|
|
|
33949
34272
|
|
|
33950
34273
|
// src/guest/vpn/tunnel.ts
|
|
33951
34274
|
import { spawn as spawn7 } from "node:child_process";
|
|
33952
|
-
import
|
|
34275
|
+
import fs56 from "node:fs";
|
|
33953
34276
|
import os12 from "node:os";
|
|
33954
34277
|
import path69 from "node:path";
|
|
33955
34278
|
var DONE = "Initialization Sequence Completed";
|
|
@@ -33967,17 +34290,17 @@ function failureReason(text) {
|
|
|
33967
34290
|
}
|
|
33968
34291
|
var tail = (text, lines = 12) => text.trim().split(/\r?\n/).slice(-lines).join("\n");
|
|
33969
34292
|
async function startTunnel(o) {
|
|
33970
|
-
const dir =
|
|
34293
|
+
const dir = fs56.mkdtempSync(path69.join(os12.tmpdir(), "sbx-vpn-"));
|
|
33971
34294
|
const auth = path69.join(dir, "login.txt");
|
|
33972
34295
|
const logFile2 = path69.join(dir, "openvpn.log");
|
|
33973
34296
|
const keepLog = () => {
|
|
33974
34297
|
try {
|
|
33975
|
-
|
|
33976
|
-
|
|
34298
|
+
fs56.mkdirSync(logsDir, { recursive: true });
|
|
34299
|
+
fs56.copyFileSync(logFile2, path69.join(logsDir, "openvpn.log"));
|
|
33977
34300
|
} catch {
|
|
33978
34301
|
}
|
|
33979
34302
|
};
|
|
33980
|
-
|
|
34303
|
+
fs56.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
|
|
33981
34304
|
try {
|
|
33982
34305
|
const child = spawn7(
|
|
33983
34306
|
o.exe,
|
|
@@ -33995,7 +34318,7 @@ async function startTunnel(o) {
|
|
|
33995
34318
|
child.unref();
|
|
33996
34319
|
const deadline = Date.now() + (o.timeoutMs ?? 9e4);
|
|
33997
34320
|
for (; ; ) {
|
|
33998
|
-
const text =
|
|
34321
|
+
const text = fs56.existsSync(logFile2) ? fs56.readFileSync(logFile2, "utf8") : "";
|
|
33999
34322
|
if (text.includes(DONE)) {
|
|
34000
34323
|
keepLog();
|
|
34001
34324
|
const tunnelIp = tunnelAddressFromLog(text) ?? void 0;
|
|
@@ -34015,14 +34338,14 @@ async function startTunnel(o) {
|
|
|
34015
34338
|
await new Promise((r) => setTimeout(r, 500));
|
|
34016
34339
|
}
|
|
34017
34340
|
} finally {
|
|
34018
|
-
|
|
34341
|
+
fs56.rmSync(auth, { force: true });
|
|
34019
34342
|
}
|
|
34020
34343
|
}
|
|
34021
34344
|
|
|
34022
34345
|
// src/guest/vpn/wireguard.ts
|
|
34023
34346
|
import { execFile } from "node:child_process";
|
|
34024
34347
|
import crypto5 from "node:crypto";
|
|
34025
|
-
import
|
|
34348
|
+
import fs57 from "node:fs";
|
|
34026
34349
|
import os13 from "node:os";
|
|
34027
34350
|
import path70 from "node:path";
|
|
34028
34351
|
var WIREGUARD_TUNNEL = "sandbox";
|
|
@@ -34036,7 +34359,7 @@ function wireguardDownload(arch2 = process.arch) {
|
|
|
34036
34359
|
const entry = arch2 === "arm64" ? WIREGUARD_MSI.arm64 : WIREGUARD_MSI.x64;
|
|
34037
34360
|
return { ...entry, url: WIREGUARD_MSI.base + entry.file };
|
|
34038
34361
|
}
|
|
34039
|
-
var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(
|
|
34362
|
+
var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(fs57.readFileSync(file3)).digest("hex") === sha256;
|
|
34040
34363
|
async function ensureWireguard() {
|
|
34041
34364
|
const exe = wireguardExe();
|
|
34042
34365
|
if (!isWin || dryRun) return exe;
|
|
@@ -34047,6 +34370,7 @@ async function ensureWireguard() {
|
|
|
34047
34370
|
log("VPN: downloading WireGuard " + WIREGUARD_MSI.version + " (about 3 MB)");
|
|
34048
34371
|
await downloader.file(dl.url, msi, dl.sha256);
|
|
34049
34372
|
}
|
|
34373
|
+
repairServiceQueries();
|
|
34050
34374
|
log("VPN: installing WireGuard");
|
|
34051
34375
|
const logFile2 = path70.join(toolsDir, "downloads", "wireguard-install.log");
|
|
34052
34376
|
const code = await spawnAsync(
|
|
@@ -34081,9 +34405,9 @@ async function removeWireguardTunnel(exe) {
|
|
|
34081
34405
|
}
|
|
34082
34406
|
async function startWireguardTunnel(o) {
|
|
34083
34407
|
const root = path70.join(process.env.SystemRoot ?? "C:\\Windows", "Temp");
|
|
34084
|
-
const dir =
|
|
34408
|
+
const dir = fs57.mkdtempSync(path70.join(fs57.existsSync(root) ? root : os13.tmpdir(), "sbx-wg-"));
|
|
34085
34409
|
const file3 = path70.join(dir, WIREGUARD_TUNNEL + ".conf");
|
|
34086
|
-
|
|
34410
|
+
fs57.writeFileSync(file3, o.config, "utf8");
|
|
34087
34411
|
const fail = async (message) => {
|
|
34088
34412
|
await removeWireguardTunnel(o.exe);
|
|
34089
34413
|
return { ok: false, message };
|
|
@@ -34104,7 +34428,7 @@ async function startWireguardTunnel(o) {
|
|
|
34104
34428
|
await sleep(500);
|
|
34105
34429
|
}
|
|
34106
34430
|
} finally {
|
|
34107
|
-
|
|
34431
|
+
fs57.rmSync(dir, { recursive: true, force: true });
|
|
34108
34432
|
}
|
|
34109
34433
|
}
|
|
34110
34434
|
async function waitForHandshake(exe, poke, timeoutMs = 3e4) {
|
|
@@ -34173,15 +34497,47 @@ async function publicAddress() {
|
|
|
34173
34497
|
}
|
|
34174
34498
|
}
|
|
34175
34499
|
var hasAdapter2 = (ip) => Object.values(os14.networkInterfaces()).some((list) => (list ?? []).some((i) => i.address === ip));
|
|
34500
|
+
var PROBE_TARGETS = ["1.1.1.1", "8.8.8.8", "9.9.9.9"];
|
|
34501
|
+
var PROBE_TIMEOUT_MS = 3e3;
|
|
34502
|
+
function connects(ip, port) {
|
|
34503
|
+
return new Promise((resolve2) => {
|
|
34504
|
+
const socket = net3.connect({ host: ip, port });
|
|
34505
|
+
const done = (ok) => {
|
|
34506
|
+
socket.destroy();
|
|
34507
|
+
resolve2(ok);
|
|
34508
|
+
};
|
|
34509
|
+
socket.setTimeout(PROBE_TIMEOUT_MS, () => done(false));
|
|
34510
|
+
socket.once("connect", () => done(true));
|
|
34511
|
+
socket.once("error", () => done(false));
|
|
34512
|
+
});
|
|
34513
|
+
}
|
|
34514
|
+
async function directConnectionBlocked(servers) {
|
|
34515
|
+
const targets = PROBE_TARGETS.filter((ip) => !servers.some((s) => s.ip === ip));
|
|
34516
|
+
const results = await Promise.all(targets.map((ip) => connects(ip, 443)));
|
|
34517
|
+
return !results.some(Boolean);
|
|
34518
|
+
}
|
|
34176
34519
|
async function setupVpn(secrets, ptyHostExe) {
|
|
34177
34520
|
const vpn = session.vpn;
|
|
34178
34521
|
if (!vpn) return true;
|
|
34179
34522
|
const killSwitch = vpn.killSwitch;
|
|
34180
34523
|
let blocked = false;
|
|
34181
|
-
|
|
34182
|
-
|
|
34183
|
-
|
|
34184
|
-
|
|
34524
|
+
let held = false;
|
|
34525
|
+
const block2 = async (servers) => {
|
|
34526
|
+
if (!isWin || dryRun) {
|
|
34527
|
+
blocked = held = true;
|
|
34528
|
+
return;
|
|
34529
|
+
}
|
|
34530
|
+
try {
|
|
34531
|
+
run2(killSwitchCommands(servers, ptyHostExe ? longPath(ptyHostExe) : null));
|
|
34532
|
+
} finally {
|
|
34533
|
+
blocked = true;
|
|
34534
|
+
held = await directConnectionBlocked(servers);
|
|
34535
|
+
}
|
|
34536
|
+
if (held) log("VPN: kill switch on: nothing leaves the sandbox except through the tunnel (checked).");
|
|
34537
|
+
else
|
|
34538
|
+
warn(
|
|
34539
|
+
"VPN: the kill switch did not hold: a direct connection still got out. If the tunnel drops, traffic leaves through your normal connection."
|
|
34540
|
+
);
|
|
34185
34541
|
};
|
|
34186
34542
|
setVpnStatus("starting", "Starting the VPN");
|
|
34187
34543
|
try {
|
|
@@ -34197,7 +34553,7 @@ async function setupVpn(secrets, ptyHostExe) {
|
|
|
34197
34553
|
warn(
|
|
34198
34554
|
"VPN: AllowedIPs does not include 0.0.0.0/0: with the kill switch on, only the tunnel traffic can leave the sandbox."
|
|
34199
34555
|
);
|
|
34200
|
-
if (killSwitch)
|
|
34556
|
+
if (killSwitch) await block2(servers);
|
|
34201
34557
|
if (dryRun || !isWin) {
|
|
34202
34558
|
log("(dry run) would start the WireGuard tunnel " + vpn.server);
|
|
34203
34559
|
setVpnStatus("off", "dry run");
|
|
@@ -34212,11 +34568,11 @@ async function setupVpn(secrets, ptyHostExe) {
|
|
|
34212
34568
|
const credentials = secrets.vpn;
|
|
34213
34569
|
if (!credentials) throw new Error("the VPN login did not arrive (start the sandbox again)");
|
|
34214
34570
|
const profile = path71.join(launchDir, "vpn", "server.ovpn");
|
|
34215
|
-
const remotes = assertSafeOvpn(
|
|
34571
|
+
const remotes = assertSafeOvpn(fs58.readFileSync(profile, "utf8"), vpn.server);
|
|
34216
34572
|
const exe = await ensureOpenVpn();
|
|
34217
34573
|
const servers = await serverAddresses(remotes);
|
|
34218
34574
|
if (servers.length === 0) throw new Error("the VPN server addresses could not be found");
|
|
34219
|
-
if (killSwitch)
|
|
34575
|
+
if (killSwitch) await block2(servers);
|
|
34220
34576
|
if (dryRun || !isWin) {
|
|
34221
34577
|
log("(dry run) would start the VPN tunnel to " + vpn.server);
|
|
34222
34578
|
setVpnStatus("off", "dry run");
|
|
@@ -34235,18 +34591,21 @@ async function setupVpn(secrets, ptyHostExe) {
|
|
|
34235
34591
|
throw new Error("the tunnel reported it was up, but no network adapter with its address appeared");
|
|
34236
34592
|
const publicIp = await publicAddress();
|
|
34237
34593
|
log("VPN: up" + (publicIp ? " (the sandbox appears as " + publicIp + ")" : "") + ".");
|
|
34238
|
-
setVpnStatus("up", "The tunnel is up",
|
|
34594
|
+
setVpnStatus("up", "The tunnel is up", {
|
|
34595
|
+
...publicIp ? { publicIp } : {},
|
|
34596
|
+
...killSwitch ? { killSwitchHeld: held } : {}
|
|
34597
|
+
});
|
|
34239
34598
|
return true;
|
|
34240
34599
|
} catch (e) {
|
|
34241
34600
|
const reason = errMsg(e);
|
|
34242
34601
|
try {
|
|
34243
|
-
if (killSwitch && !blocked)
|
|
34602
|
+
if (killSwitch && !blocked) await block2([]);
|
|
34244
34603
|
} catch (blockError) {
|
|
34245
34604
|
warn("VPN: could not close the network after the failure: " + errMsg(blockError));
|
|
34246
34605
|
}
|
|
34247
|
-
const
|
|
34248
|
-
warn(
|
|
34249
|
-
setVpnStatus("failed", reason);
|
|
34606
|
+
const after = !killSwitch ? " The kill switch is off, so this sandbox is using your normal connection." : held ? " The kill switch is on, so this sandbox has NO internet access." : " The kill switch could NOT close the network, so this sandbox is ONLINE through your normal connection, without the VPN.";
|
|
34607
|
+
warn("VPN failed: " + reason + after);
|
|
34608
|
+
setVpnStatus("failed", reason, killSwitch ? { killSwitchHeld: held } : {});
|
|
34250
34609
|
return false;
|
|
34251
34610
|
}
|
|
34252
34611
|
}
|
|
@@ -34303,10 +34662,10 @@ var FrameReader = class {
|
|
|
34303
34662
|
};
|
|
34304
34663
|
|
|
34305
34664
|
// src/shared/pty/client.ts
|
|
34306
|
-
import
|
|
34665
|
+
import net4 from "node:net";
|
|
34307
34666
|
var connectOnce = (host, port, timeoutMs) => {
|
|
34308
34667
|
return new Promise((resolve2, reject) => {
|
|
34309
|
-
const socket =
|
|
34668
|
+
const socket = net4.connect({ host, port });
|
|
34310
34669
|
const timer = setTimeout(() => {
|
|
34311
34670
|
socket.destroy();
|
|
34312
34671
|
reject(new Error("timed out connecting to " + host + ":" + port));
|
|
@@ -34527,6 +34886,36 @@ function unfinishedSequence(data) {
|
|
|
34527
34886
|
return data.length;
|
|
34528
34887
|
}
|
|
34529
34888
|
|
|
34889
|
+
// src/shared/pty/ctrl-c.ts
|
|
34890
|
+
var CTRL_C_CONFIRM_MS = 1500;
|
|
34891
|
+
var CTRL_C_HINT = "Ctrl+C again to send it to the program (Esc stops an agent)";
|
|
34892
|
+
var OSC_TITLE = /\x1b\][02];([^\x07\x1b]{0,256})(?:\x07|\x1b\\)/g;
|
|
34893
|
+
var CtrlCGuard = class {
|
|
34894
|
+
armedAt = Number.NEGATIVE_INFINITY;
|
|
34895
|
+
lastTitle = "";
|
|
34896
|
+
/** What to send for one read from the keyboard: a lone Ctrl+C only when another came just before. */
|
|
34897
|
+
push(chunk, nowMs) {
|
|
34898
|
+
if (chunk.length !== 1 || chunk[0] !== 3) return { send: chunk, held: false };
|
|
34899
|
+
if (nowMs - this.armedAt <= CTRL_C_CONFIRM_MS) {
|
|
34900
|
+
this.armedAt = Number.NEGATIVE_INFINITY;
|
|
34901
|
+
return { send: chunk, held: false };
|
|
34902
|
+
}
|
|
34903
|
+
this.armedAt = nowMs;
|
|
34904
|
+
return { send: Buffer.alloc(0), held: true };
|
|
34905
|
+
}
|
|
34906
|
+
/** Remembers the title the program last set (from its output), to put it back after the hint. */
|
|
34907
|
+
watchOutput(text) {
|
|
34908
|
+
for (const m of text.matchAll(OSC_TITLE)) this.lastTitle = m[1];
|
|
34909
|
+
}
|
|
34910
|
+
/** The escape sequence that shows the hint, and the one that puts the program's title back. */
|
|
34911
|
+
hintTitle() {
|
|
34912
|
+
return "\x1B]0;" + CTRL_C_HINT + "\x07";
|
|
34913
|
+
}
|
|
34914
|
+
restoreTitle() {
|
|
34915
|
+
return "\x1B]0;" + this.lastTitle.replace(/[\x00-\x1f\x7f]/g, "") + "\x07";
|
|
34916
|
+
}
|
|
34917
|
+
};
|
|
34918
|
+
|
|
34530
34919
|
// src/shared/pty/terminal.ts
|
|
34531
34920
|
var MOUSE_OFF = "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1005l\x1B[?1006l\x1B[?1015l";
|
|
34532
34921
|
function fixWindowsKeys(chunk) {
|
|
@@ -34557,6 +34946,7 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
34557
34946
|
clearInterval(heartbeat);
|
|
34558
34947
|
clearInterval(sizeWatch);
|
|
34559
34948
|
clearTimeout(joinTimer);
|
|
34949
|
+
clearTimeout(hintTimer);
|
|
34560
34950
|
socket.destroy();
|
|
34561
34951
|
stdout.write("\x1B[0m\x1B[?25h" + MOUSE_OFF + "\r\n");
|
|
34562
34952
|
void (vtInput?.stop() ?? Promise.resolve()).then(() => {
|
|
@@ -34570,11 +34960,23 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
34570
34960
|
const sendInput = (data) => {
|
|
34571
34961
|
if (data.length && !done) socket.write(encodeFrame(FrameType.Input, swapKeys ? fixWindowsKeys(data) : data));
|
|
34572
34962
|
};
|
|
34963
|
+
const guard = options.confirmCtrlC ? new CtrlCGuard() : null;
|
|
34964
|
+
let hintTimer;
|
|
34573
34965
|
const onInput = (chunk) => {
|
|
34574
34966
|
if (options.detachKey !== void 0 && chunk.includes(options.detachKey)) {
|
|
34575
34967
|
finish({ reason: "detach" });
|
|
34576
34968
|
return;
|
|
34577
34969
|
}
|
|
34970
|
+
if (guard) {
|
|
34971
|
+
const decided = guard.push(chunk, Date.now());
|
|
34972
|
+
clearTimeout(hintTimer);
|
|
34973
|
+
if (decided.held) {
|
|
34974
|
+
stdout.write(guard.hintTitle());
|
|
34975
|
+
hintTimer = setTimeout(() => stdout.write(guard.restoreTitle()), CTRL_C_CONFIRM_MS);
|
|
34976
|
+
return;
|
|
34977
|
+
}
|
|
34978
|
+
if (decided.send.length === 1 && decided.send[0] === 3) stdout.write(guard.restoreTitle());
|
|
34979
|
+
}
|
|
34578
34980
|
clearTimeout(joinTimer);
|
|
34579
34981
|
sendInput(joiner.push(chunk));
|
|
34580
34982
|
if (joiner.holding()) joinTimer = setTimeout(() => sendInput(joiner.flush()), JOIN_MS);
|
|
@@ -34607,8 +35009,11 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
34607
35009
|
return;
|
|
34608
35010
|
}
|
|
34609
35011
|
for (const frame of frames) {
|
|
34610
|
-
if (frame.type === FrameType.Output)
|
|
34611
|
-
|
|
35012
|
+
if (frame.type === FrameType.Output) {
|
|
35013
|
+
const out = filter.push(frame.payload);
|
|
35014
|
+
guard?.watchOutput(out.toString("latin1"));
|
|
35015
|
+
stdout.write(out);
|
|
35016
|
+
} else if (frame.type === FrameType.Console) passthrough = frame.payload.toString("latin1") === "conpty.dll";
|
|
34612
35017
|
else if (frame.type === FrameType.Restarting) stdout.write(MOUSE_OFF + "\x1B[2J\x1B[3J\x1B[H");
|
|
34613
35018
|
else if (frame.type === FrameType.Exit)
|
|
34614
35019
|
finish({ reason: "exit", exitCode: frame.payload.length >= 4 ? frame.payload.readInt32LE(0) : 1 });
|
|
@@ -34661,7 +35066,10 @@ async function viewSession(id) {
|
|
|
34661
35066
|
return 1;
|
|
34662
35067
|
}
|
|
34663
35068
|
const socket = await connect({ ...session2.attach, addresses: ["127.0.0.1"] });
|
|
34664
|
-
const result = await runTerminalClient(socket, session2.attach.token, {
|
|
35069
|
+
const result = await runTerminalClient(socket, session2.attach.token, {
|
|
35070
|
+
clipboardWrites: true,
|
|
35071
|
+
confirmCtrlC: session.attach.confirmCtrlC !== false
|
|
35072
|
+
});
|
|
34665
35073
|
if (result.reason === "exit") console.log(session2.harness + " exited with code " + result.exitCode + ".");
|
|
34666
35074
|
else if (result.reason === "error") console.log("Session error: " + result.message);
|
|
34667
35075
|
return result.reason === "exit" ? result.exitCode : 1;
|
|
@@ -34716,7 +35124,7 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
|
|
|
34716
35124
|
}
|
|
34717
35125
|
|
|
34718
35126
|
// src/guest/runtime/secrets.ts
|
|
34719
|
-
import
|
|
35127
|
+
import fs59 from "node:fs";
|
|
34720
35128
|
|
|
34721
35129
|
// src/shared/channel/secrets.ts
|
|
34722
35130
|
var Environment = external_exports.record(external_exports.string().max(256), external_exports.string().max(65536));
|
|
@@ -34732,7 +35140,9 @@ var SecretsFileSchema = external_exports.strictObject({
|
|
|
34732
35140
|
/** VPN service credentials (vpn.provider's login), only for the launch's own sandbox. */
|
|
34733
35141
|
vpn: external_exports.strictObject({ username: external_exports.string().min(1).max(256), password: external_exports.string().min(1).max(1024) }).optional(),
|
|
34734
35142
|
/** The checked WireGuard config of vpn.provider wireguard-file (holds the private key). */
|
|
34735
|
-
wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional()
|
|
35143
|
+
wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional(),
|
|
35144
|
+
/** The GitHub token you saved for sandboxes (github.shareToken), only with git access "full". */
|
|
35145
|
+
githubToken: GithubTokenSchema.optional()
|
|
34736
35146
|
});
|
|
34737
35147
|
|
|
34738
35148
|
// src/guest/runtime/secrets.ts
|
|
@@ -34742,12 +35152,12 @@ function takeSecrets(id) {
|
|
|
34742
35152
|
const file3 = run.secretFile(id);
|
|
34743
35153
|
let text;
|
|
34744
35154
|
try {
|
|
34745
|
-
if (
|
|
34746
|
-
text =
|
|
35155
|
+
if (fs59.statSync(file3).size > MAX_BYTES) throw new Error("too big");
|
|
35156
|
+
text = fs59.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
|
|
34747
35157
|
} catch {
|
|
34748
35158
|
return {};
|
|
34749
35159
|
} finally {
|
|
34750
|
-
|
|
35160
|
+
fs59.rmSync(file3, { force: true });
|
|
34751
35161
|
}
|
|
34752
35162
|
try {
|
|
34753
35163
|
const parsed = SecretsFileSchema.safeParse(JSON.parse(text));
|
|
@@ -34800,7 +35210,7 @@ function startDaemon(env, secrets) {
|
|
|
34800
35210
|
function writeDbCommand() {
|
|
34801
35211
|
const dir = mkdirp(path73.join(localDir, "bin"));
|
|
34802
35212
|
const db = path73.join(path73.dirname(process.argv[1]), "db.js");
|
|
34803
|
-
|
|
35213
|
+
fs60.writeFileSync(
|
|
34804
35214
|
path73.join(dir, "sbx-db.cmd"),
|
|
34805
35215
|
'@setlocal\r\n@set AGENT_LOG_PREFIX=db\r\n@"' + process.execPath + '" "' + db + '" %*\r\n'
|
|
34806
35216
|
);
|
|
@@ -34810,8 +35220,8 @@ function writeDbCommand() {
|
|
|
34810
35220
|
function writeAgentCommands(dir) {
|
|
34811
35221
|
const install = { node: process.execPath, script: path73.join(path73.dirname(process.argv[1]), "agent.js") };
|
|
34812
35222
|
for (const shim3 of agentShims(toolsDir, session.agents ?? {}))
|
|
34813
|
-
|
|
34814
|
-
|
|
35223
|
+
fs60.writeFileSync(path73.join(dir, shim3.command + ".cmd"), shimText(shim3, install));
|
|
35224
|
+
fs60.writeFileSync(path73.join(dir, "sbx-agent.cmd"), sbxAgentText(install));
|
|
34815
35225
|
}
|
|
34816
35226
|
async function waitForPrimary() {
|
|
34817
35227
|
for (let i = 0; i < PRIMARY_POLLS; i++) {
|
|
@@ -34839,12 +35249,13 @@ var Boot = class {
|
|
|
34839
35249
|
log(
|
|
34840
35250
|
"Agent sandbox: " + session.project + " | workspace " + workspace + " | agent " + session.harnessName + " | log " + logPath
|
|
34841
35251
|
);
|
|
34842
|
-
if (!
|
|
35252
|
+
if (!fs60.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
|
|
34843
35253
|
throw new Error("Workspace folder is missing in the sandbox: " + workspace);
|
|
34844
35254
|
mkdirp(toolsDir);
|
|
34845
35255
|
mkdirp(run.root);
|
|
34846
35256
|
this.secrets = takeSecrets(session.launchId);
|
|
34847
35257
|
applyBootEnvironment(this.secrets.harnessEnvironment);
|
|
35258
|
+
prepareGithubFolder(this.secrets.githubToken);
|
|
34848
35259
|
await this.networkAndSessionHost();
|
|
34849
35260
|
await this.hooksAndDesktop();
|
|
34850
35261
|
const { tools, env } = await this.developerTools();
|
|
@@ -34883,6 +35294,7 @@ var Boot = class {
|
|
|
34883
35294
|
databases: session.databases ?? [],
|
|
34884
35295
|
apps: session.apps
|
|
34885
35296
|
});
|
|
35297
|
+
for (const p of networkProblems()) tools.summary.push("PROTECTION MISSING: " + p);
|
|
34886
35298
|
if (!dryRun) tools.prepend.push(writeDbCommand());
|
|
34887
35299
|
Object.assign(tools.vars, proxyEnv());
|
|
34888
35300
|
await soft("Network: allow only some hosts", async () => {
|
|
@@ -34926,6 +35338,11 @@ var Boot = class {
|
|
|
34926
35338
|
async gitIdentity(env) {
|
|
34927
35339
|
step(5, "Git identity");
|
|
34928
35340
|
await soft("Git config", () => setupGitConfig(env));
|
|
35341
|
+
const token = this.secrets.githubToken;
|
|
35342
|
+
if (token) {
|
|
35343
|
+
this.secrets = { ...this.secrets, githubToken: void 0 };
|
|
35344
|
+
await soft("GitHub token", () => loginGithub(token, env));
|
|
35345
|
+
}
|
|
34929
35346
|
}
|
|
34930
35347
|
async claude(tools) {
|
|
34931
35348
|
step(6, "Claude settings, history and claude-mem");
|
|
@@ -34987,7 +35404,7 @@ runBoot().catch((e) => {
|
|
|
34987
35404
|
const message = errMsg(e) + (e instanceof Error && e.stack ? "\n" + e.stack : "");
|
|
34988
35405
|
try {
|
|
34989
35406
|
setSandboxStatus("failed", errMsg(e));
|
|
34990
|
-
|
|
35407
|
+
fs61.writeFileSync(path74.join(logsDir, "guest-error.txt"), message);
|
|
34991
35408
|
} catch {
|
|
34992
35409
|
}
|
|
34993
35410
|
console.error(
|