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/shared/io/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Exit code 8 and up means something could not be copied; below that every file is in place. */
|
|
2
|
+
export declare function robocopyFailed(code: number | null): boolean;
|
|
3
|
+
/** The exit code in plain words (it is a bit field: 1 copied, 2 extras, 4 mismatches, 8 failures, 16 fatal). */
|
|
4
|
+
export declare function robocopyMeaning(code: number | null): string;
|
|
5
|
+
/** The first few ERROR lines of robocopy's output (what went wrong and on which file), one line each. */
|
|
6
|
+
export declare function robocopyErrors(output: string, max?: number): string[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Reading robocopy's exit code and output (pure; the guest and the tests share it).
|
|
2
|
+
/** Exit code 8 and up means something could not be copied; below that every file is in place. */
|
|
3
|
+
export function robocopyFailed(code) {
|
|
4
|
+
return code === null || code >= 8;
|
|
5
|
+
}
|
|
6
|
+
/** The exit code in plain words (it is a bit field: 1 copied, 2 extras, 4 mismatches, 8 failures, 16 fatal). */
|
|
7
|
+
export function robocopyMeaning(code) {
|
|
8
|
+
if (code === null)
|
|
9
|
+
return 'robocopy did not finish';
|
|
10
|
+
if (code >= 16)
|
|
11
|
+
return 'robocopy stopped with a fatal error (bad path or no access)';
|
|
12
|
+
if (code >= 8)
|
|
13
|
+
return code & 1 ? 'some files were copied and some could not be' : 'files could not be copied';
|
|
14
|
+
return code === 0 ? 'nothing to copy' : 'copied';
|
|
15
|
+
}
|
|
16
|
+
/** The first few ERROR lines of robocopy's output (what went wrong and on which file), one line each. */
|
|
17
|
+
export function robocopyErrors(output, max = 3) {
|
|
18
|
+
const lines = output
|
|
19
|
+
.split(/\r?\n/)
|
|
20
|
+
.map((l) => l.trim())
|
|
21
|
+
.filter((l) => /\bERROR\b/.test(l) || /^The (process|system) cannot/i.test(l));
|
|
22
|
+
return lines.slice(0, max).map((l) => (l.length > 220 ? l.slice(0, 217) + '...' : l));
|
|
23
|
+
}
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
export type LoadProfile = 'normal' | 'gentle';
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
readonly
|
|
10
|
-
readonly
|
|
11
|
-
readonly
|
|
2
|
+
/**
|
|
3
|
+
* One step of the guest governor's dial. It turns up when available RAM falls below `availablePercent` of the
|
|
4
|
+
* sandbox's RAM, commit rises above `commitPercent` of its limit, or (from step 3) the commit would reach its limit
|
|
5
|
+
* within `secondsToLimit` at the rate it is growing. It turns down one step after `calmSamples` samples in a row that
|
|
6
|
+
* are clear of the step by the margins below.
|
|
7
|
+
*/
|
|
8
|
+
export interface DialStep {
|
|
9
|
+
readonly availablePercent: number;
|
|
10
|
+
readonly commitPercent: number;
|
|
11
|
+
readonly secondsToLimit?: number;
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
/** Steps 1 to 4 of the dial, per profile (index 0 is step 1). The gentle profile (vGPU on) turns earlier. */
|
|
14
|
+
export declare const DIAL_STEPS: Readonly<Record<LoadProfile, readonly DialStep[]>>;
|
|
15
|
+
/** How clear of a step a sample must be to count as calm: this much more RAM free and this much less commit. */
|
|
16
|
+
export declare const DIAL_EXIT_MARGIN: {
|
|
17
|
+
readonly availablePercent: 5;
|
|
18
|
+
readonly commitPercent: 4;
|
|
19
|
+
};
|
|
20
|
+
export declare const DIAL_CALM_SAMPLES = 3;
|
|
21
|
+
/** The CPU share (percent of the sandbox) the compilers get together at each step; 100 = no cap. */
|
|
22
|
+
export declare const DIAL_CPU_RATE: readonly number[];
|
|
23
|
+
/** How many of the compilers running may go on at each step (the rest wait their turn), as a share of them. */
|
|
24
|
+
export declare function compilersAllowed(step: number, running: number): number;
|
|
14
25
|
/** The PC watchdog: when this PC itself is low. */
|
|
15
26
|
export interface HostThresholds {
|
|
16
27
|
/** Low when available RAM is below max(this, availableShare of total RAM)... */
|
|
@@ -23,11 +34,26 @@ export interface HostThresholds {
|
|
|
23
34
|
/** Total CPU above this (percent) for cpuSeconds. */
|
|
24
35
|
readonly cpuPercent: number;
|
|
25
36
|
readonly cpuSeconds: number;
|
|
37
|
+
/** The disks' queue length (all together) at or above this for diskSeconds: builds writing through mapped folders. */
|
|
38
|
+
readonly diskQueue: number;
|
|
39
|
+
readonly diskSeconds: number;
|
|
26
40
|
}
|
|
27
41
|
export declare const HOST_THRESHOLDS: Readonly<Record<LoadProfile, HostThresholds>>;
|
|
28
42
|
/** The CPU cap (percent of the PC) the gentle profile uses: 15 points lower, never below 50. "none" = 100. */
|
|
29
43
|
export declare function gentleCpuLimit(cpuLimit: 'none' | number): number;
|
|
30
44
|
/** The CPU cap the sandbox runs with (percent; null = none) for a profile. */
|
|
31
45
|
export declare function effectiveCpuLimit(cpuLimit: 'none' | number, profile: LoadProfile): number | null;
|
|
32
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* The build budget of the whole sandbox: how many compile jobs fit together (about 3 GB each after 6 GB for Windows,
|
|
48
|
+
* the agents and their tools), never more than the processors the sandbox may use. The governor slows them down when
|
|
49
|
+
* memory runs short anyway; this keeps builds from starting far more than fits.
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildJobs(cpus: number, memoryGb: number): number;
|
|
52
|
+
/** Links that may run at once in the whole sandbox ("auto"): one per 3 GB after 6 GB, 2 to 8. */
|
|
53
|
+
export declare function linkSlotsFor(memoryGb: number): number;
|
|
54
|
+
/** The processors the sandbox's programs may use with a CPU cap of `percent` (affinity): at least 2. */
|
|
55
|
+
export declare function usableCpus(cpus: number, percent: number | null): number;
|
|
56
|
+
/** Cargo jobs for one more agent session: what fits the memory and CPUs, shared with the sessions already building. */
|
|
33
57
|
export declare function cargoJobs(cpus: number, memoryGb: number, sessions: number): number;
|
|
58
|
+
/** The most heavy compilers (rustc, clippy-driver, link ...) that run at once in the agents' job: only with vGPU on. */
|
|
59
|
+
export declare function maxCompilers(cpus: number, profile: LoadProfile): number | null;
|
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
// What "heavy load" means, decided once for the host watchdog and the guest governor (pure, no I/O). Every
|
|
2
2
|
// protection is on by default; the gentle profile (vGPU on: a graphics driver hang can freeze the whole PC) triggers
|
|
3
3
|
// earlier and runs the sandbox with less CPU.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
gentle:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
4
|
+
/** Steps 1 to 4 of the dial, per profile (index 0 is step 1). The gentle profile (vGPU on) turns earlier. */
|
|
5
|
+
export const DIAL_STEPS = {
|
|
6
|
+
normal: [
|
|
7
|
+
{ availablePercent: 15, commitPercent: 80 },
|
|
8
|
+
{ availablePercent: 10, commitPercent: 88 },
|
|
9
|
+
{ availablePercent: 6, commitPercent: 94, secondsToLimit: 20 },
|
|
10
|
+
{ availablePercent: 4, commitPercent: 97, secondsToLimit: 8 },
|
|
11
|
+
],
|
|
12
|
+
gentle: [
|
|
13
|
+
{ availablePercent: 20, commitPercent: 75 },
|
|
14
|
+
{ availablePercent: 15, commitPercent: 85 },
|
|
15
|
+
{ availablePercent: 8, commitPercent: 92, secondsToLimit: 25 },
|
|
16
|
+
{ availablePercent: 5, commitPercent: 96, secondsToLimit: 10 },
|
|
17
|
+
],
|
|
19
18
|
};
|
|
19
|
+
/** How clear of a step a sample must be to count as calm: this much more RAM free and this much less commit. */
|
|
20
|
+
export const DIAL_EXIT_MARGIN = { availablePercent: 5, commitPercent: 4 };
|
|
21
|
+
export const DIAL_CALM_SAMPLES = 3;
|
|
22
|
+
/** The CPU share (percent of the sandbox) the compilers get together at each step; 100 = no cap. */
|
|
23
|
+
export const DIAL_CPU_RATE = [100, 100, 60, 35, 15];
|
|
24
|
+
/** How many of the compilers running may go on at each step (the rest wait their turn), as a share of them. */
|
|
25
|
+
export function compilersAllowed(step, running) {
|
|
26
|
+
if (step <= 1 || running <= 1)
|
|
27
|
+
return running;
|
|
28
|
+
if (step === 2)
|
|
29
|
+
return Math.max(1, Math.ceil(running * 0.6));
|
|
30
|
+
if (step === 3)
|
|
31
|
+
return Math.max(1, Math.ceil(running / 3));
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
20
34
|
export const HOST_THRESHOLDS = {
|
|
21
35
|
normal: {
|
|
22
36
|
availableMinMb: 4096,
|
|
@@ -25,6 +39,8 @@ export const HOST_THRESHOLDS = {
|
|
|
25
39
|
calmSamples: 3,
|
|
26
40
|
cpuPercent: 95,
|
|
27
41
|
cpuSeconds: 60,
|
|
42
|
+
diskQueue: 32,
|
|
43
|
+
diskSeconds: 40,
|
|
28
44
|
},
|
|
29
45
|
gentle: {
|
|
30
46
|
availableMinMb: 6144,
|
|
@@ -33,6 +49,8 @@ export const HOST_THRESHOLDS = {
|
|
|
33
49
|
calmSamples: 3,
|
|
34
50
|
cpuPercent: 90,
|
|
35
51
|
cpuSeconds: 45,
|
|
52
|
+
diskQueue: 16,
|
|
53
|
+
diskSeconds: 30,
|
|
36
54
|
},
|
|
37
55
|
};
|
|
38
56
|
/** The CPU cap (percent of the PC) the gentle profile uses: 15 points lower, never below 50. "none" = 100. */
|
|
@@ -45,11 +63,32 @@ export function effectiveCpuLimit(cpuLimit, profile) {
|
|
|
45
63
|
return Math.min(gentleCpuLimit(cpuLimit), cpuLimit === 'none' ? 100 : cpuLimit);
|
|
46
64
|
return cpuLimit === 'none' ? null : cpuLimit;
|
|
47
65
|
}
|
|
48
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* The build budget of the whole sandbox: how many compile jobs fit together (about 3 GB each after 6 GB for Windows,
|
|
68
|
+
* the agents and their tools), never more than the processors the sandbox may use. The governor slows them down when
|
|
69
|
+
* memory runs short anyway; this keeps builds from starting far more than fits.
|
|
70
|
+
*/
|
|
71
|
+
export function buildJobs(cpus, memoryGb) {
|
|
72
|
+
return Math.max(2, Math.min(cpus, Math.floor((memoryGb - 6) / 3)));
|
|
73
|
+
}
|
|
74
|
+
/** Links that may run at once in the whole sandbox ("auto"): one per 3 GB after 6 GB, 2 to 8. */
|
|
75
|
+
export function linkSlotsFor(memoryGb) {
|
|
76
|
+
return Math.max(2, Math.min(8, Math.floor((memoryGb - 6) / 3)));
|
|
77
|
+
}
|
|
78
|
+
/** The processors the sandbox's programs may use with a CPU cap of `percent` (affinity): at least 2. */
|
|
79
|
+
export function usableCpus(cpus, percent) {
|
|
80
|
+
if (percent === null || percent >= 100)
|
|
81
|
+
return cpus;
|
|
82
|
+
return Math.max(2, Math.min(cpus, Math.floor((cpus * percent) / 100)));
|
|
83
|
+
}
|
|
84
|
+
/** Cargo jobs for one more agent session: what fits the memory and CPUs, shared with the sessions already building. */
|
|
49
85
|
export function cargoJobs(cpus, memoryGb, sessions) {
|
|
50
|
-
const byCpu = Math.max(2, Math.min(
|
|
86
|
+
const byCpu = Math.max(2, Math.min(8, Math.floor(cpus / 4)));
|
|
51
87
|
const byMemory = Math.max(1, Math.floor(memoryGb / 4));
|
|
52
88
|
const jobs = Math.min(byCpu, byMemory);
|
|
53
|
-
|
|
54
|
-
|
|
89
|
+
return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions))));
|
|
90
|
+
}
|
|
91
|
+
/** The most heavy compilers (rustc, clippy-driver, link ...) that run at once in the agents' job: only with vGPU on. */
|
|
92
|
+
export function maxCompilers(cpus, profile) {
|
|
93
|
+
return profile === 'gentle' ? Math.max(2, Math.floor(cpus / 4)) : null;
|
|
55
94
|
}
|
|
@@ -22,3 +22,11 @@ export declare function parseDnsServers(ipconfigAll: string): string[];
|
|
|
22
22
|
* keeps working.
|
|
23
23
|
*/
|
|
24
24
|
export declare function buildFirewallCommands(exemptIps: string[]): string[][];
|
|
25
|
+
export declare const ATTACH_RULE = "AgentSandbox-Attach";
|
|
26
|
+
/**
|
|
27
|
+
* True when a Windows path has an 8.3 short name in it (`C:\Users\WDAGUT~1\...`). netsh refuses `program=` paths
|
|
28
|
+
* like that ("The application name could not be resolved"), so they are expanded first.
|
|
29
|
+
*/
|
|
30
|
+
export declare function hasShortName(file: string): boolean;
|
|
31
|
+
/** Inbound rule for ptyhost only, and only from the sandbox's own subnet (where the host's Hyper-V adapter is). */
|
|
32
|
+
export declare function attachRuleCommands(ptyHostExe: string): string[][];
|
|
@@ -135,3 +135,31 @@ export function buildFirewallCommands(exemptIps) {
|
|
|
135
135
|
}
|
|
136
136
|
return commands;
|
|
137
137
|
}
|
|
138
|
+
export const ATTACH_RULE = 'AgentSandbox-Attach';
|
|
139
|
+
/**
|
|
140
|
+
* True when a Windows path has an 8.3 short name in it (`C:\Users\WDAGUT~1\...`). netsh refuses `program=` paths
|
|
141
|
+
* like that ("The application name could not be resolved"), so they are expanded first.
|
|
142
|
+
*/
|
|
143
|
+
export function hasShortName(file) {
|
|
144
|
+
return file.split(/[/\\]/).some((part) => /~\d/.test(part));
|
|
145
|
+
}
|
|
146
|
+
/** Inbound rule for ptyhost only, and only from the sandbox's own subnet (where the host's Hyper-V adapter is). */
|
|
147
|
+
export function attachRuleCommands(ptyHostExe) {
|
|
148
|
+
return [
|
|
149
|
+
['advfirewall', 'firewall', 'delete', 'rule', 'name=' + ATTACH_RULE],
|
|
150
|
+
[
|
|
151
|
+
'advfirewall',
|
|
152
|
+
'firewall',
|
|
153
|
+
'add',
|
|
154
|
+
'rule',
|
|
155
|
+
'name=' + ATTACH_RULE,
|
|
156
|
+
'dir=in',
|
|
157
|
+
'action=allow',
|
|
158
|
+
'enable=yes',
|
|
159
|
+
'profile=any',
|
|
160
|
+
'protocol=tcp',
|
|
161
|
+
'remoteip=LocalSubnet',
|
|
162
|
+
'program=' + ptyHostExe,
|
|
163
|
+
],
|
|
164
|
+
];
|
|
165
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** A second Ctrl+C within this long sends it. */
|
|
2
|
+
export declare const CTRL_C_CONFIRM_MS = 1500;
|
|
3
|
+
/** What the title shows while a Ctrl+C is held back. */
|
|
4
|
+
export declare const CTRL_C_HINT = "Ctrl+C again to send it to the program (Esc stops an agent)";
|
|
5
|
+
export declare class CtrlCGuard {
|
|
6
|
+
private armedAt;
|
|
7
|
+
private lastTitle;
|
|
8
|
+
/** What to send for one read from the keyboard: a lone Ctrl+C only when another came just before. */
|
|
9
|
+
push(chunk: Buffer, nowMs: number): {
|
|
10
|
+
send: Buffer;
|
|
11
|
+
held: boolean;
|
|
12
|
+
};
|
|
13
|
+
/** Remembers the title the program last set (from its output), to put it back after the hint. */
|
|
14
|
+
watchOutput(text: string): void;
|
|
15
|
+
/** The escape sequence that shows the hint, and the one that puts the program's title back. */
|
|
16
|
+
hintTitle(): string;
|
|
17
|
+
restoreTitle(): string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// A lone Ctrl+C is easy to send by accident: it is "copy" everywhere else, and a terminal sends it to the program when
|
|
2
|
+
// the selection it was meant for has just been cleared by a redraw (an agent's spinner redraws all the time). With
|
|
3
|
+
// attach.confirmCtrlC the terminal client holds a lone Ctrl+C back until it is pressed again within a moment; Esc still
|
|
4
|
+
// stops an agent at once. Pure, so it is tested without a terminal.
|
|
5
|
+
/** A second Ctrl+C within this long sends it. */
|
|
6
|
+
export const CTRL_C_CONFIRM_MS = 1500;
|
|
7
|
+
/** What the title shows while a Ctrl+C is held back. */
|
|
8
|
+
export const CTRL_C_HINT = 'Ctrl+C again to send it to the program (Esc stops an agent)';
|
|
9
|
+
const OSC_TITLE = /\x1b\][02];([^\x07\x1b]{0,256})(?:\x07|\x1b\\)/g;
|
|
10
|
+
export class CtrlCGuard {
|
|
11
|
+
armedAt = Number.NEGATIVE_INFINITY;
|
|
12
|
+
lastTitle = '';
|
|
13
|
+
/** What to send for one read from the keyboard: a lone Ctrl+C only when another came just before. */
|
|
14
|
+
push(chunk, nowMs) {
|
|
15
|
+
if (chunk.length !== 1 || chunk[0] !== 0x03)
|
|
16
|
+
return { send: chunk, held: false };
|
|
17
|
+
if (nowMs - this.armedAt <= CTRL_C_CONFIRM_MS) {
|
|
18
|
+
this.armedAt = Number.NEGATIVE_INFINITY;
|
|
19
|
+
return { send: chunk, held: false };
|
|
20
|
+
}
|
|
21
|
+
this.armedAt = nowMs;
|
|
22
|
+
return { send: Buffer.alloc(0), held: true };
|
|
23
|
+
}
|
|
24
|
+
/** Remembers the title the program last set (from its output), to put it back after the hint. */
|
|
25
|
+
watchOutput(text) {
|
|
26
|
+
for (const m of text.matchAll(OSC_TITLE))
|
|
27
|
+
this.lastTitle = m[1];
|
|
28
|
+
}
|
|
29
|
+
/** The escape sequence that shows the hint, and the one that puts the program's title back. */
|
|
30
|
+
hintTitle() {
|
|
31
|
+
return '\x1b]0;' + CTRL_C_HINT + '\x07';
|
|
32
|
+
}
|
|
33
|
+
restoreTitle() {
|
|
34
|
+
return '\x1b]0;' + this.lastTitle.replace(/[\x00-\x1f\x7f]/g, '') + '\x07';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -2,5 +2,6 @@ export { FrameType, HelloFlag, PING_INTERVAL_MS, type Frame, DETACH_KEY, encodeF
|
|
|
2
2
|
export { type Endpoint, connect, sendControl, type Viewers, queryViewers } from './client.js';
|
|
3
3
|
export { type ClientResult, MOUSE_OFF, fixWindowsKeys, runTerminalClient } from './terminal.js';
|
|
4
4
|
export { JOIN_MS, InputJoiner } from './input-joiner.js';
|
|
5
|
+
export { CTRL_C_CONFIRM_MS, CTRL_C_HINT, CtrlCGuard } from './ctrl-c.js';
|
|
5
6
|
export { type VtInput, enableVtInput } from './console-input.js';
|
|
6
7
|
export { OutputFilter } from './output-filter.js';
|
package/dist/shared/pty/index.js
CHANGED
|
@@ -2,5 +2,6 @@ export { FrameType, HelloFlag, PING_INTERVAL_MS, DETACH_KEY, encodeFrame, helloF
|
|
|
2
2
|
export { connect, sendControl, queryViewers } from './client.js';
|
|
3
3
|
export { MOUSE_OFF, fixWindowsKeys, runTerminalClient } from './terminal.js';
|
|
4
4
|
export { JOIN_MS, InputJoiner } from './input-joiner.js';
|
|
5
|
+
export { CTRL_C_CONFIRM_MS, CTRL_C_HINT, CtrlCGuard } from './ctrl-c.js';
|
|
5
6
|
export { enableVtInput } from './console-input.js';
|
|
6
7
|
export { OutputFilter } from './output-filter.js';
|
|
@@ -24,7 +24,9 @@ export declare function fixWindowsKeys(chunk: Buffer): Buffer;
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function runTerminalClient(socket: net.Socket, token: string,
|
|
26
26
|
/** clipboardWrites: the agent's "copy" (OSC 52) reaches the clipboard; see OutputFilterOptions. */
|
|
27
|
+
/** confirmCtrlC: a lone Ctrl+C is held back until it is pressed again (CtrlCGuard, attach.confirmCtrlC). */
|
|
27
28
|
options?: {
|
|
28
29
|
detachKey?: number;
|
|
29
30
|
clipboardWrites?: boolean;
|
|
31
|
+
confirmCtrlC?: boolean;
|
|
30
32
|
}): Promise<ClientResult>;
|
|
@@ -2,6 +2,7 @@ import { FrameReader, encodeFrame, FrameType, resizeFrame, PING_INTERVAL_MS, hel
|
|
|
2
2
|
import { OutputFilter } from './output-filter.js';
|
|
3
3
|
import { enableVtInput } from './console-input.js';
|
|
4
4
|
import { InputJoiner, JOIN_MS } from './input-joiner.js';
|
|
5
|
+
import { CTRL_C_CONFIRM_MS, CtrlCGuard } from './ctrl-c.js';
|
|
5
6
|
/**
|
|
6
7
|
* Turns off every mouse tracking mode a program may have turned on in your terminal (normal, button, any, UTF-8, SGR,
|
|
7
8
|
* urxvt).
|
|
@@ -22,6 +23,7 @@ export function fixWindowsKeys(chunk) {
|
|
|
22
23
|
*/
|
|
23
24
|
export function runTerminalClient(socket, token,
|
|
24
25
|
/** clipboardWrites: the agent's "copy" (OSC 52) reaches the clipboard; see OutputFilterOptions. */
|
|
26
|
+
/** confirmCtrlC: a lone Ctrl+C is held back until it is pressed again (CtrlCGuard, attach.confirmCtrlC). */
|
|
25
27
|
options = {}) {
|
|
26
28
|
const stdin = process.stdin;
|
|
27
29
|
const stdout = process.stdout;
|
|
@@ -51,6 +53,7 @@ options = {}) {
|
|
|
51
53
|
clearInterval(heartbeat);
|
|
52
54
|
clearInterval(sizeWatch);
|
|
53
55
|
clearTimeout(joinTimer);
|
|
56
|
+
clearTimeout(hintTimer);
|
|
54
57
|
socket.destroy();
|
|
55
58
|
// The agent's mouse tracking ends with it: your terminal's wheel scrolls again (and clicks select text).
|
|
56
59
|
stdout.write('\x1b[0m\x1b[?25h' + MOUSE_OFF + '\r\n');
|
|
@@ -68,11 +71,24 @@ options = {}) {
|
|
|
68
71
|
if (data.length && !done)
|
|
69
72
|
socket.write(encodeFrame(FrameType.Input, swapKeys ? fixWindowsKeys(data) : data));
|
|
70
73
|
};
|
|
74
|
+
const guard = options.confirmCtrlC ? new CtrlCGuard() : null;
|
|
75
|
+
let hintTimer;
|
|
71
76
|
const onInput = (chunk) => {
|
|
72
77
|
if (options.detachKey !== undefined && chunk.includes(options.detachKey)) {
|
|
73
78
|
finish({ reason: 'detach' });
|
|
74
79
|
return;
|
|
75
80
|
}
|
|
81
|
+
if (guard) {
|
|
82
|
+
const decided = guard.push(chunk, Date.now());
|
|
83
|
+
clearTimeout(hintTimer);
|
|
84
|
+
if (decided.held) {
|
|
85
|
+
stdout.write(guard.hintTitle());
|
|
86
|
+
hintTimer = setTimeout(() => stdout.write(guard.restoreTitle()), CTRL_C_CONFIRM_MS);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (decided.send.length === 1 && decided.send[0] === 0x03)
|
|
90
|
+
stdout.write(guard.restoreTitle());
|
|
91
|
+
}
|
|
76
92
|
clearTimeout(joinTimer);
|
|
77
93
|
sendInput(joiner.push(chunk));
|
|
78
94
|
// A lone Esc key press is a "sequence" that never completes: send it after a moment.
|
|
@@ -116,8 +132,11 @@ options = {}) {
|
|
|
116
132
|
return;
|
|
117
133
|
}
|
|
118
134
|
for (const frame of frames) {
|
|
119
|
-
if (frame.type === FrameType.Output)
|
|
120
|
-
|
|
135
|
+
if (frame.type === FrameType.Output) {
|
|
136
|
+
const out = filter.push(frame.payload);
|
|
137
|
+
guard?.watchOutput(out.toString('latin1'));
|
|
138
|
+
stdout.write(out);
|
|
139
|
+
}
|
|
121
140
|
else if (frame.type === FrameType.Console)
|
|
122
141
|
passthrough = frame.payload.toString('latin1') === 'conpty.dll';
|
|
123
142
|
else if (frame.type === FrameType.Restarting)
|
|
@@ -6,11 +6,22 @@ export interface KillSwitchServer {
|
|
|
6
6
|
}
|
|
7
7
|
/** The rule names phase 1 and 2 may create (the servers get a number each). */
|
|
8
8
|
export declare function ruleNames(serverCount: number): string[];
|
|
9
|
+
/** Every IPv4 address except the given ranges, as a netsh address list ("a-b,c-d"). */
|
|
10
|
+
export declare function ipv4Except(excluded: readonly (readonly [number, number])[]): string;
|
|
11
|
+
/** The internet's IPv4 addresses without the VPN servers: what the kill switch blocks. */
|
|
12
|
+
export declare function internetExcept(servers: readonly KillSwitchServer[]): string;
|
|
9
13
|
/** Servers worth a rule: valid IPv4 addresses and ports, each endpoint once. */
|
|
10
14
|
export declare function cleanServers(servers: readonly KillSwitchServer[]): KillSwitchServer[];
|
|
11
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Phase 1: the block rules first (they hold whatever else allows), then outbound blocked by default, then what the
|
|
17
|
+
* tunnel and the attach channel need. `ptyHostExe` must be the long form of the path (netsh refuses 8.3 names).
|
|
18
|
+
*/
|
|
12
19
|
export declare function killSwitchCommands(servers: readonly KillSwitchServer[], ptyHostExe: string | null): string[][];
|
|
13
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Phase 2: everything that leaves from the tunnel's own address goes (it is inside the tunnel). The IPv4 block rules
|
|
22
|
+
* are changed in place to every other local address, so they never stop applying to the normal connection. Global
|
|
23
|
+
* IPv6 stays blocked (the tunnel is IPv4).
|
|
24
|
+
*/
|
|
14
25
|
export declare function tunnelCommands(tunnelIp: string): string[][];
|
|
15
26
|
/** Takes the kill switch away again: its rules go and outbound traffic is allowed by default as before. */
|
|
16
27
|
export declare function removeKillSwitchCommands(): string[][];
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
// The kill switch as netsh argument lists (pure, so it is tested without a firewall).
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// The kill switch as netsh argument lists (pure, so it is tested without a firewall). Windows Sandbox has its own
|
|
2
|
+
// "Container: allow outbound" rule (any program, any address), so blocking outbound by default alone stops nothing:
|
|
3
|
+
// the kill switch is made of BLOCK rules, which beat every allow rule. Phase 1 runs BEFORE the tunnel starts: every
|
|
4
|
+
// public IPv4 address except the VPN servers, global IPv6 and DNS are blocked (private ranges are the LAN block's).
|
|
5
|
+
// Phase 2 runs once the tunnel is up: the same block rules are narrowed in place (`set rule`, never a moment without
|
|
6
|
+
// them) to every local address except the tunnel's own, so what goes through the tunnel (DNS included) passes.
|
|
6
7
|
import { isIPv4 } from '../network/firewall-rules.js';
|
|
7
8
|
export const VPN_RULE_PREFIX = 'AgentSandbox-VPN-';
|
|
8
9
|
const rule = (name, extra) => [
|
|
@@ -24,9 +25,24 @@ const drop = (name) => [
|
|
|
24
25
|
'rule',
|
|
25
26
|
'name=' + VPN_RULE_PREFIX + name,
|
|
26
27
|
];
|
|
28
|
+
const block = (name, extra) => [
|
|
29
|
+
'advfirewall',
|
|
30
|
+
'firewall',
|
|
31
|
+
'add',
|
|
32
|
+
'rule',
|
|
33
|
+
'name=' + VPN_RULE_PREFIX + name,
|
|
34
|
+
'dir=out',
|
|
35
|
+
'action=block',
|
|
36
|
+
'enable=yes',
|
|
37
|
+
'profile=any',
|
|
38
|
+
...extra,
|
|
39
|
+
];
|
|
40
|
+
/** The block rules: IPv4 to the internet, global IPv6, and DNS anywhere (over udp and tcp). */
|
|
41
|
+
const BLOCK_RULES = ['Block-Internet', 'Block-IPv6', 'Block-DNS-UDP', 'Block-DNS-TCP'];
|
|
27
42
|
/** The rule names phase 1 and 2 may create (the servers get a number each). */
|
|
28
43
|
export function ruleNames(serverCount) {
|
|
29
44
|
return [
|
|
45
|
+
...BLOCK_RULES,
|
|
30
46
|
'Loopback',
|
|
31
47
|
'DHCP',
|
|
32
48
|
'Host',
|
|
@@ -34,6 +50,45 @@ export function ruleNames(serverCount) {
|
|
|
34
50
|
...Array.from({ length: Math.max(serverCount, 0) }, (_v, i) => 'Server-' + (i + 1)),
|
|
35
51
|
];
|
|
36
52
|
}
|
|
53
|
+
/** IPv4 ranges that are not the internet (this host, private, shared, link-local, multicast, reserved, broadcast). */
|
|
54
|
+
const NOT_INTERNET = [
|
|
55
|
+
['0.0.0.0', '0.255.255.255'],
|
|
56
|
+
['10.0.0.0', '10.255.255.255'],
|
|
57
|
+
['100.64.0.0', '100.127.255.255'],
|
|
58
|
+
['127.0.0.0', '127.255.255.255'],
|
|
59
|
+
['169.254.0.0', '169.254.255.255'],
|
|
60
|
+
['172.16.0.0', '172.31.255.255'],
|
|
61
|
+
['192.168.0.0', '192.168.255.255'],
|
|
62
|
+
['224.0.0.0', '255.255.255.255'],
|
|
63
|
+
];
|
|
64
|
+
const LAST_IPV4 = 0xffffffff;
|
|
65
|
+
function ipNumber(ip) {
|
|
66
|
+
return ip.split('.').reduce((n, part) => n * 256 + Number(part), 0);
|
|
67
|
+
}
|
|
68
|
+
function ipText(n) {
|
|
69
|
+
return [24, 16, 8, 0].map((shift) => Math.floor(n / 2 ** shift) % 256).join('.');
|
|
70
|
+
}
|
|
71
|
+
/** Every IPv4 address except the given ranges, as a netsh address list ("a-b,c-d"). */
|
|
72
|
+
export function ipv4Except(excluded) {
|
|
73
|
+
const sorted = [...excluded].sort((a, b) => a[0] - b[0]);
|
|
74
|
+
const out = [];
|
|
75
|
+
let next = 0;
|
|
76
|
+
for (const [from, to] of sorted) {
|
|
77
|
+
if (from > next)
|
|
78
|
+
out.push(ipText(next) + '-' + ipText(from - 1));
|
|
79
|
+
next = Math.max(next, to + 1);
|
|
80
|
+
}
|
|
81
|
+
if (next <= LAST_IPV4)
|
|
82
|
+
out.push(ipText(next) + '-' + ipText(LAST_IPV4));
|
|
83
|
+
return out.join(',');
|
|
84
|
+
}
|
|
85
|
+
/** The internet's IPv4 addresses without the VPN servers: what the kill switch blocks. */
|
|
86
|
+
export function internetExcept(servers) {
|
|
87
|
+
const ranges = NOT_INTERNET.map(([a, b]) => [ipNumber(a), ipNumber(b)]);
|
|
88
|
+
for (const s of cleanServers(servers))
|
|
89
|
+
ranges.push([ipNumber(s.ip), ipNumber(s.ip)]);
|
|
90
|
+
return ipv4Except(ranges);
|
|
91
|
+
}
|
|
37
92
|
/** Servers worth a rule: valid IPv4 addresses and ports, each endpoint once. */
|
|
38
93
|
export function cleanServers(servers) {
|
|
39
94
|
const seen = new Set();
|
|
@@ -45,12 +100,19 @@ export function cleanServers(servers) {
|
|
|
45
100
|
return true;
|
|
46
101
|
});
|
|
47
102
|
}
|
|
48
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Phase 1: the block rules first (they hold whatever else allows), then outbound blocked by default, then what the
|
|
105
|
+
* tunnel and the attach channel need. `ptyHostExe` must be the long form of the path (netsh refuses 8.3 names).
|
|
106
|
+
*/
|
|
49
107
|
export function killSwitchCommands(servers, ptyHostExe) {
|
|
50
108
|
const list = cleanServers(servers);
|
|
51
109
|
return [
|
|
52
110
|
...ruleNames(Math.max(list.length, 8)).map(drop),
|
|
53
111
|
['advfirewall', 'set', 'allprofiles', 'state', 'on'],
|
|
112
|
+
block('Block-Internet', ['protocol=any', 'remoteip=' + internetExcept(list)]),
|
|
113
|
+
block('Block-IPv6', ['protocol=any', 'remoteip=2000::/3']),
|
|
114
|
+
block('Block-DNS-UDP', ['protocol=udp', 'remoteport=53']),
|
|
115
|
+
block('Block-DNS-TCP', ['protocol=tcp', 'remoteport=53']),
|
|
54
116
|
['advfirewall', 'set', 'allprofiles', 'firewallpolicy', 'blockinbound,blockoutbound'],
|
|
55
117
|
rule('Loopback', ['protocol=any', 'remoteip=127.0.0.0/8']),
|
|
56
118
|
rule('DHCP', ['protocol=udp', 'localport=68', 'remoteport=67']),
|
|
@@ -58,11 +120,29 @@ export function killSwitchCommands(servers, ptyHostExe) {
|
|
|
58
120
|
...list.map((s, i) => rule('Server-' + (i + 1), ['protocol=' + s.proto, 'remoteip=' + s.ip, 'remoteport=' + s.port])),
|
|
59
121
|
];
|
|
60
122
|
}
|
|
61
|
-
/**
|
|
123
|
+
/**
|
|
124
|
+
* Phase 2: everything that leaves from the tunnel's own address goes (it is inside the tunnel). The IPv4 block rules
|
|
125
|
+
* are changed in place to every other local address, so they never stop applying to the normal connection. Global
|
|
126
|
+
* IPv6 stays blocked (the tunnel is IPv4).
|
|
127
|
+
*/
|
|
62
128
|
export function tunnelCommands(tunnelIp) {
|
|
63
129
|
if (!isIPv4(tunnelIp))
|
|
64
130
|
throw new Error('Not an IPv4 address: ' + tunnelIp);
|
|
65
|
-
|
|
131
|
+
const n = ipNumber(tunnelIp);
|
|
132
|
+
const notTunnel = ipv4Except([[n, n]]);
|
|
133
|
+
return [
|
|
134
|
+
...['Block-Internet', 'Block-DNS-UDP', 'Block-DNS-TCP'].map((name) => [
|
|
135
|
+
'advfirewall',
|
|
136
|
+
'firewall',
|
|
137
|
+
'set',
|
|
138
|
+
'rule',
|
|
139
|
+
'name=' + VPN_RULE_PREFIX + name,
|
|
140
|
+
'new',
|
|
141
|
+
'localip=' + notTunnel,
|
|
142
|
+
]),
|
|
143
|
+
drop('Tunnel'),
|
|
144
|
+
rule('Tunnel', ['protocol=any', 'localip=' + tunnelIp]),
|
|
145
|
+
];
|
|
66
146
|
}
|
|
67
147
|
/** Takes the kill switch away again: its rules go and outbound traffic is allowed by default as before. */
|
|
68
148
|
export function removeKillSwitchCommands() {
|
|
@@ -29,10 +29,6 @@ export interface WebInfo {
|
|
|
29
29
|
readonly defaultHarness: string;
|
|
30
30
|
readonly projects: readonly WebProject[];
|
|
31
31
|
}
|
|
32
|
-
export interface NewSessionRequest {
|
|
33
|
-
readonly harness: string;
|
|
34
|
-
readonly project: string;
|
|
35
|
-
}
|
|
36
32
|
/** Browser -> server on the terminal socket: binary messages are keystrokes; text messages are these (JSON). */
|
|
37
33
|
export type ClientMessage = {
|
|
38
34
|
readonly t: 'resize';
|
package/dist/sync/watcher.js
CHANGED
|
@@ -243,7 +243,7 @@ export class Watcher {
|
|
|
243
243
|
? 'this PC is low (' + step.reason + '): asking the sandbox to slow its builds down'
|
|
244
244
|
: 'this PC has recovered: no longer asking the sandbox to slow down');
|
|
245
245
|
if (step.send)
|
|
246
|
-
new SandboxChannel(this.dataPath).pressure(step.reason, REQUEST_SECONDS);
|
|
246
|
+
new SandboxChannel(this.dataPath).pressure(step.reason, REQUEST_SECONDS, step.severe ? 'severe' : 'slow');
|
|
247
247
|
}
|
|
248
248
|
catch (e) {
|
|
249
249
|
this.note('host watchdog: ' + errMsg(e));
|
package/dist/web/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>Sandbox</title>
|
|
7
7
|
<link rel="icon" href="data:," />
|
|
8
|
-
<link rel="stylesheet" href="/main-
|
|
9
|
-
<script type="module" src="/main-
|
|
8
|
+
<link rel="stylesheet" href="/main-6JF3ASB5.css" />
|
|
9
|
+
<script type="module" src="/main-Z645W45E.js"></script>
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|