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
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// The memory governor's decisions (pure): given a memory sample and what it did before, how far to turn the dial and
|
|
2
|
+
// what that means for the build programs in the agents' job. Like a PC that gets slower instead of failing: lower
|
|
3
|
+
// priority, lower memory priority (their pages are trimmed first), less CPU, fewer compilers at a time (the others wait
|
|
4
|
+
// their turn, suspended and always resumed), waiting compilers trimmed to the paging file. Agents, shells and Windows
|
|
5
|
+
// are never touched. Nothing here touches Windows; governor.ts carries the actions out through a port.
|
|
6
|
+
import { compilersAllowed, DIAL_CALM_SAMPLES, DIAL_CPU_RATE, DIAL_EXIT_MARGIN, DIAL_STEPS, } from '../../shared/memory/index.js';
|
|
1
7
|
/** Programs that compile or link: they may be slowed down and, as the last resort, paused for a few seconds. */
|
|
2
8
|
const COMPILERS = new Set([
|
|
3
9
|
'rustc',
|
|
@@ -25,8 +31,8 @@ const COMPILERS = new Set([
|
|
|
25
31
|
'javac',
|
|
26
32
|
]);
|
|
27
33
|
/** Build tools and workers: slowed down but never paused (a node process may be a dev server or an agent). */
|
|
34
|
+
// Not node: agents such as Codex and Gemini run as node.exe, and the agents are never slowed down.
|
|
28
35
|
const BUILD_TOOLS = new Set([
|
|
29
|
-
'node',
|
|
30
36
|
'dotnet',
|
|
31
37
|
'msbuild',
|
|
32
38
|
'vbcscompiler',
|
|
@@ -77,103 +83,180 @@ const NEVER = new Set([
|
|
|
77
83
|
const key = (name) => name.toLowerCase().replace(/\.exe$/, '');
|
|
78
84
|
export const isNeverTouched = (name) => NEVER.has(key(name));
|
|
79
85
|
export const canLower = (name) => !isNeverTouched(name) && (COMPILERS.has(key(name)) || BUILD_TOOLS.has(key(name)));
|
|
86
|
+
/** The heavy ones the concurrency cap counts (drivers like gcc and collect2 only wait for these). */
|
|
87
|
+
const HEAVY = new Set([
|
|
88
|
+
'rustc',
|
|
89
|
+
'clippy-driver',
|
|
90
|
+
'rustdoc',
|
|
91
|
+
'cc1',
|
|
92
|
+
'cc1plus',
|
|
93
|
+
'clang',
|
|
94
|
+
'clang++',
|
|
95
|
+
'clang-cl',
|
|
96
|
+
'cl',
|
|
97
|
+
'link',
|
|
98
|
+
'lld',
|
|
99
|
+
'lld-link',
|
|
100
|
+
'ld',
|
|
101
|
+
'ld.lld',
|
|
102
|
+
]);
|
|
103
|
+
export const isHeavyCompiler = (name) => !isNeverTouched(name) && HEAVY.has(key(name));
|
|
80
104
|
export const canPause = (name) => !isNeverTouched(name) && COMPILERS.has(key(name));
|
|
81
105
|
export const INITIAL_STATE = {
|
|
82
|
-
|
|
106
|
+
step: 0,
|
|
83
107
|
calm: 0,
|
|
84
|
-
samples: 0,
|
|
85
108
|
lowered: {},
|
|
86
|
-
|
|
87
|
-
|
|
109
|
+
memLow: [],
|
|
110
|
+
throttled: [],
|
|
111
|
+
trimmed: [],
|
|
112
|
+
cpuRate: 100,
|
|
113
|
+
lastCommitMb: 0,
|
|
114
|
+
lastAt: 0,
|
|
115
|
+
growth: 0,
|
|
88
116
|
hostUntil: 0,
|
|
117
|
+
hostStep: 0,
|
|
89
118
|
};
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
/**
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
119
|
+
/** How much the newest sample counts in the smoothed commit growth. */
|
|
120
|
+
const GROWTH_WEIGHT = 0.3;
|
|
121
|
+
/** How long a held compiler waits before it may get a turn again (the governor repeats the hold while it waits). */
|
|
122
|
+
export const HOLD_MS = 3000;
|
|
123
|
+
/** Which compilers wait their turn changes this often, so none waits for ever. */
|
|
124
|
+
export const ROTATE_MS = 20000;
|
|
125
|
+
/**
|
|
126
|
+
* "Full soon" only counts this close (in commit percent) to a step's own threshold: a build that grabs a few GB in a
|
|
127
|
+
* burst while most of the memory is free is normal, not a reason to pause compilers.
|
|
128
|
+
*/
|
|
129
|
+
const SOON_WITHIN_PERCENT = 12;
|
|
130
|
+
/** The step a sample calls for on its own: the highest step whose threshold it crosses. */
|
|
131
|
+
export function stepFor(ramFree, commit, secondsToLimit, profile) {
|
|
132
|
+
let step = 0;
|
|
133
|
+
DIAL_STEPS[profile].forEach((t, i) => {
|
|
134
|
+
const near = commit > t.commitPercent - SOON_WITHIN_PERCENT;
|
|
135
|
+
const soon = near && t.secondsToLimit !== undefined && secondsToLimit < t.secondsToLimit;
|
|
136
|
+
if (ramFree < t.availablePercent || commit > t.commitPercent || soon)
|
|
137
|
+
step = i + 1;
|
|
138
|
+
});
|
|
139
|
+
return step;
|
|
140
|
+
}
|
|
141
|
+
/** Is the sample clear of `step` by the exit margins (so the dial may turn down from it)? */
|
|
142
|
+
function clearOf(step, ramFree, commit, profile) {
|
|
143
|
+
if (step === 0)
|
|
144
|
+
return true;
|
|
145
|
+
const t = DIAL_STEPS[profile][step - 1];
|
|
146
|
+
return (ramFree > t.availablePercent + DIAL_EXIT_MARGIN.availablePercent &&
|
|
147
|
+
commit < t.commitPercent - DIAL_EXIT_MARGIN.commitPercent);
|
|
148
|
+
}
|
|
97
149
|
/**
|
|
98
|
-
* One step.
|
|
99
|
-
* priority
|
|
150
|
+
* One step of the governor. The dial turns up at once and down one step at a time after calm samples. `gentle` (vGPU
|
|
151
|
+
* on): compilers rest below normal priority, and `maxCompilers` caps how many heavy compilers run at any step.
|
|
100
152
|
*/
|
|
101
|
-
export function decide(prev, sample, nowMs,
|
|
153
|
+
export function decide(prev, sample, nowMs, profile, maxCompilers = null) {
|
|
102
154
|
const ramFree = (sample.ramAvailMb / Math.max(1, sample.ramTotalMb)) * 100;
|
|
103
|
-
const
|
|
155
|
+
const usedMb = sample.commitLimitMb - sample.commitAvailMb;
|
|
156
|
+
const commit = (usedMb / Math.max(1, sample.commitLimitMb)) * 100;
|
|
157
|
+
const seconds = (nowMs - prev.lastAt) / 1000;
|
|
158
|
+
const instant = prev.lastAt > 0 && seconds > 0 ? (usedMb - prev.lastCommitMb) / seconds : 0;
|
|
159
|
+
// Smoothed over the last samples, so one burst between two samples is not read as a trend.
|
|
160
|
+
const growth = prev.lastAt > 0 ? prev.growth * (1 - GROWTH_WEIGHT) + instant * GROWTH_WEIGHT : 0;
|
|
161
|
+
const secondsToLimit = growth > 0 ? sample.commitAvailMb / growth : Number.POSITIVE_INFINITY;
|
|
104
162
|
const pcLow = nowMs < prev.hostUntil;
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
let
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
calm
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
else if (prev.pressure) {
|
|
116
|
-
calm = recovered ? prev.calm + 1 : 0;
|
|
117
|
-
if (calm >= thresholds.calmSamples) {
|
|
118
|
-
pressure = false;
|
|
163
|
+
const wanted = Math.max(stepFor(ramFree, commit, secondsToLimit, profile), pcLow ? prev.hostStep : 0);
|
|
164
|
+
let step = prev.step;
|
|
165
|
+
let calm = 0;
|
|
166
|
+
if (wanted > prev.step)
|
|
167
|
+
step = wanted;
|
|
168
|
+
else if (prev.step > 0 && wanted < prev.step && clearOf(prev.step, ramFree, commit, profile)) {
|
|
169
|
+
calm = prev.calm + 1;
|
|
170
|
+
if (calm >= DIAL_CALM_SAMPLES) {
|
|
171
|
+
step = prev.step - 1;
|
|
119
172
|
calm = 0;
|
|
120
|
-
samples = 0;
|
|
121
173
|
}
|
|
122
174
|
}
|
|
123
175
|
const actions = [];
|
|
124
176
|
const present = new Set(sample.procs.map((p) => p.pid));
|
|
177
|
+
const keep = (pids) => pids.filter((pid) => present.has(pid));
|
|
125
178
|
const lowered = {};
|
|
126
179
|
for (const [pid, to] of Object.entries(prev.lowered))
|
|
127
180
|
if (present.has(Number(pid)))
|
|
128
181
|
lowered[Number(pid)] = to;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
182
|
+
const memLow = new Set(keep(prev.memLow));
|
|
183
|
+
const throttled = new Set(keep(prev.throttled));
|
|
184
|
+
const trimmed = new Set(keep(prev.trimmed));
|
|
185
|
+
// CPU priority: where a program rests (normal; compilers below in the gentle profile), below from step 1, idle
|
|
186
|
+
// from step 2. Only changes are sent.
|
|
187
|
+
for (const p of sample.procs) {
|
|
188
|
+
if (!canLower(p.name))
|
|
189
|
+
continue;
|
|
190
|
+
const rest = profile === 'gentle' && canPause(p.name) ? 'below' : 'normal';
|
|
191
|
+
const target = step >= 2 ? 'idle' : step === 1 ? 'below' : rest;
|
|
192
|
+
const was = lowered[p.pid];
|
|
193
|
+
const touched = was !== undefined || target !== 'normal';
|
|
194
|
+
if (touched && was !== target && p.prio !== target)
|
|
195
|
+
actions.push({ kind: 'priority', pid: p.pid, name: p.name, to: target });
|
|
196
|
+
if (target === 'normal')
|
|
197
|
+
delete lowered[p.pid];
|
|
198
|
+
else
|
|
137
199
|
lowered[p.pid] = target;
|
|
138
|
-
}
|
|
139
200
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
201
|
+
// Memory priority: low from step 1, so Windows trims the builds' pages before the agents'.
|
|
202
|
+
const lowMemory = step >= 1;
|
|
203
|
+
for (const p of sample.procs) {
|
|
204
|
+
if (!canLower(p.name) || lowMemory === memLow.has(p.pid))
|
|
205
|
+
continue;
|
|
206
|
+
actions.push({ kind: 'memory', pid: p.pid, name: p.name, low: lowMemory });
|
|
207
|
+
if (lowMemory)
|
|
208
|
+
memLow.add(p.pid);
|
|
209
|
+
else
|
|
210
|
+
memLow.delete(p.pid);
|
|
211
|
+
}
|
|
212
|
+
// CPU share of the compilers: they join the throttle job once (from step 2); its cap follows the dial.
|
|
213
|
+
if (step >= 2)
|
|
214
|
+
for (const p of sample.procs)
|
|
215
|
+
if (canPause(p.name) && !throttled.has(p.pid)) {
|
|
216
|
+
actions.push({ kind: 'throttle', pid: p.pid, name: p.name });
|
|
217
|
+
throttled.add(p.pid);
|
|
154
218
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
219
|
+
const cpuRate = DIAL_CPU_RATE[step] ?? 100;
|
|
220
|
+
if (cpuRate !== prev.cpuRate)
|
|
221
|
+
actions.push({ kind: 'cpu', percent: cpuRate });
|
|
222
|
+
// Turns: of the heavy compilers only so many go on; the rest wait, and who waits changes every ROTATE_MS.
|
|
223
|
+
const heavy = sample.procs.filter((p) => isHeavyCompiler(p.name)).sort((a, b) => a.pid - b.pid);
|
|
224
|
+
let allowed = compilersAllowed(step, heavy.length);
|
|
225
|
+
// The cap is a memory measure: with memory to spare, Windows shares the CPU (the priorities above) and no compiler
|
|
226
|
+
// waits. A waiting rustc also holds cargo's job tokens, which stalls the whole build.
|
|
227
|
+
if (maxCompilers !== null && step >= 2)
|
|
228
|
+
allowed = Math.min(allowed, Math.max(1, maxCompilers));
|
|
229
|
+
if (allowed < heavy.length) {
|
|
230
|
+
const turn = Math.floor(nowMs / ROTATE_MS) % heavy.length;
|
|
231
|
+
const order = [...heavy.slice(turn), ...heavy.slice(0, turn)];
|
|
232
|
+
for (const p of order.slice(allowed)) {
|
|
233
|
+
actions.push({ kind: 'hold', pid: p.pid, name: p.name, ms: HOLD_MS });
|
|
234
|
+
if (step >= 3 && !trimmed.has(p.pid)) {
|
|
235
|
+
actions.push({ kind: 'trim', pid: p.pid, name: p.name });
|
|
236
|
+
trimmed.add(p.pid);
|
|
159
237
|
}
|
|
160
238
|
}
|
|
239
|
+
for (const p of order.slice(0, allowed))
|
|
240
|
+
trimmed.delete(p.pid);
|
|
161
241
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const victim = [...sample.procs]
|
|
166
|
-
.filter((p) => canPause(p.name) && p.mb >= PAUSE_MIN_MB)
|
|
167
|
-
.sort((a, b) => b.mb - a.mb)[0];
|
|
168
|
-
if (victim) {
|
|
169
|
-
actions.push({ kind: 'pause', pid: victim.pid, name: victim.name, ms: PAUSE_MS });
|
|
170
|
-
pausedUntil = nowMs + PAUSE_MS;
|
|
171
|
-
nextPauseAt = pausedUntil + PAUSE_COOLDOWN_MS;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const level = nowMs < pausedUntil ? 'suspending' : pressure ? 'throttled' : 'ok';
|
|
242
|
+
else
|
|
243
|
+
trimmed.clear();
|
|
244
|
+
const level = step >= 3 ? 'suspending' : step >= 1 ? 'throttled' : 'ok';
|
|
175
245
|
return {
|
|
176
|
-
state: {
|
|
246
|
+
state: {
|
|
247
|
+
step,
|
|
248
|
+
calm,
|
|
249
|
+
lowered,
|
|
250
|
+
memLow: [...memLow],
|
|
251
|
+
throttled: [...throttled],
|
|
252
|
+
trimmed: [...trimmed],
|
|
253
|
+
cpuRate,
|
|
254
|
+
lastCommitMb: usedMb,
|
|
255
|
+
lastAt: nowMs,
|
|
256
|
+
growth,
|
|
257
|
+
hostUntil: prev.hostUntil,
|
|
258
|
+
hostStep: prev.hostStep,
|
|
259
|
+
},
|
|
177
260
|
actions,
|
|
178
261
|
level,
|
|
179
262
|
ramFreePercent: Math.round(ramFree),
|
|
@@ -1,42 +1,9 @@
|
|
|
1
|
-
import type { PressureStatus } from '../../shared/channel/schema.js';
|
|
2
|
-
import { type LoadProfile } from '../../shared/memory/index.js';
|
|
3
|
-
import { type GovernorState, type MemSample } from './decide.js';
|
|
4
|
-
/** What the governor needs from Windows (injectable: the tests use a fake). */
|
|
5
|
-
export interface GovernorPort {
|
|
6
|
-
setPriority(pid: number, to: 'idle' | 'below' | 'normal'): void;
|
|
7
|
-
pause(pid: number, ms: number): void;
|
|
8
|
-
}
|
|
9
|
-
/** Everything a step changes outside the decision, behind injectable functions. */
|
|
10
|
-
export interface GovernorDeps {
|
|
11
|
-
readonly port: GovernorPort;
|
|
12
|
-
readonly profile: LoadProfile;
|
|
13
|
-
readonly now: () => number;
|
|
14
|
-
/** A line in the memory log. */
|
|
15
|
-
readonly logLine: (line: string) => void;
|
|
16
|
-
/** run\pressure.json. */
|
|
17
|
-
readonly saveStatus: (status: PressureStatus) => void;
|
|
18
|
-
}
|
|
19
|
-
/** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
|
|
20
|
-
export declare class GovernorCore {
|
|
21
|
-
private readonly deps;
|
|
22
|
-
private state;
|
|
23
|
-
private lastAction;
|
|
24
|
-
private lastWrite;
|
|
25
|
-
private lastWriteAt;
|
|
26
|
-
private pausedName;
|
|
27
|
-
private pausedPid;
|
|
28
|
-
constructor(deps: GovernorDeps);
|
|
29
|
-
hostPressure(seconds: number, reason: string): void;
|
|
30
|
-
get current(): GovernorState;
|
|
31
|
-
onSample(sample: MemSample): void;
|
|
32
|
-
private apply;
|
|
33
|
-
}
|
|
34
1
|
/** The daemon's governor: on unless sandbox.pressureResponse is off. */
|
|
35
2
|
export declare class Governor {
|
|
36
3
|
private core;
|
|
37
4
|
describe(): string;
|
|
38
5
|
start(): void;
|
|
39
|
-
/** The host's watchdog: this PC is low for a while. */
|
|
40
|
-
hostPressure(seconds: number, reason: string): void;
|
|
6
|
+
/** The host's watchdog: this PC is low (or nearly out of memory) for a while. */
|
|
7
|
+
hostPressure(seconds: number, reason: string, level?: 'slow' | 'severe'): void;
|
|
41
8
|
}
|
|
42
9
|
export declare const governor: Governor;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
// The memory governor: samples the sandbox's memory every 2 seconds (memgov.exe, sandbox/csharp/MemGov.cs) and
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// The memory governor: samples the sandbox's memory every 2 seconds (memgov.exe, sandbox/csharp/MemGov.cs) and turns
|
|
2
|
+
// a dial as it fills: the build programs the agents started get lower priority, lower memory priority, less CPU, and
|
|
3
|
+
// take turns (decide.ts). Builds slow down; nothing fails. What it does goes to the memory log and run\pressure.json.
|
|
4
4
|
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
5
6
|
import path from 'node:path';
|
|
6
7
|
import { spawn } from 'node:child_process';
|
|
7
8
|
import { createInterface } from 'node:readline';
|
|
8
9
|
import { z } from 'zod';
|
|
9
|
-
import { now } from '../../shared/channel/run-dir.js';
|
|
10
10
|
import { writeJsonAtomic } from '../../shared/io/json.js';
|
|
11
|
-
import {
|
|
11
|
+
import { DIAL_STEPS, maxCompilers } from '../../shared/memory/index.js';
|
|
12
12
|
import { ensureCompiled } from '../runtime/csc.js';
|
|
13
13
|
import { dataDir } from '../runtime/paths.js';
|
|
14
14
|
import { warn } from '../runtime/log.js';
|
|
15
15
|
import { run } from '../runtime/paths.js';
|
|
16
16
|
import { session } from '../runtime/session.js';
|
|
17
17
|
import { errMsg } from '../../core/util/errors.js';
|
|
18
|
-
import {
|
|
18
|
+
import { GovernorCore } from './core.js';
|
|
19
19
|
const SampleSchema = z.object({
|
|
20
20
|
ramTotalMb: z.number(),
|
|
21
21
|
ramAvailMb: z.number(),
|
|
@@ -30,87 +30,6 @@ const SampleSchema = z.object({
|
|
|
30
30
|
}))
|
|
31
31
|
.max(1024),
|
|
32
32
|
});
|
|
33
|
-
/** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
|
|
34
|
-
export class GovernorCore {
|
|
35
|
-
deps;
|
|
36
|
-
state = INITIAL_STATE;
|
|
37
|
-
lastAction = '';
|
|
38
|
-
lastWrite = '';
|
|
39
|
-
lastWriteAt = 0;
|
|
40
|
-
pausedName = '';
|
|
41
|
-
pausedPid = 0;
|
|
42
|
-
constructor(deps) {
|
|
43
|
-
this.deps = deps;
|
|
44
|
-
}
|
|
45
|
-
hostPressure(seconds, reason) {
|
|
46
|
-
const until = this.deps.now() + seconds * 1000;
|
|
47
|
-
if (until > this.state.hostUntil) {
|
|
48
|
-
if (this.state.hostUntil <= this.deps.now())
|
|
49
|
-
this.deps.logLine('governor: this PC is low (' + reason + '); slowing builds down');
|
|
50
|
-
this.state = { ...this.state, hostUntil: until };
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
get current() {
|
|
54
|
-
return this.state;
|
|
55
|
-
}
|
|
56
|
-
onSample(sample) {
|
|
57
|
-
const nowMs = this.deps.now();
|
|
58
|
-
const before = this.state.pressure;
|
|
59
|
-
const d = decide(this.state, sample, nowMs, GUEST_THRESHOLDS[this.deps.profile], this.deps.profile);
|
|
60
|
-
this.state = d.state;
|
|
61
|
-
for (const action of d.actions)
|
|
62
|
-
this.apply(action);
|
|
63
|
-
if (d.state.pressure !== before)
|
|
64
|
-
this.deps.logLine(d.state.pressure
|
|
65
|
-
? 'governor: memory is low (' +
|
|
66
|
-
d.ramFreePercent +
|
|
67
|
-
'% RAM free, commit ' +
|
|
68
|
-
d.commitPercent +
|
|
69
|
-
'% used): slowing builds down'
|
|
70
|
-
: 'governor: memory is fine again: builds back to normal');
|
|
71
|
-
const paused = nowMs < d.state.pausedUntil && this.pausedPid
|
|
72
|
-
? [{ name: this.pausedName, pid: this.pausedPid, seconds: Math.ceil((d.state.pausedUntil - nowMs) / 1000) }]
|
|
73
|
-
: [];
|
|
74
|
-
const status = {
|
|
75
|
-
level: d.level,
|
|
76
|
-
profile: this.deps.profile,
|
|
77
|
-
ramFreePercent: Math.max(0, Math.min(100, d.ramFreePercent)),
|
|
78
|
-
commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
|
|
79
|
-
lowered: Object.keys(d.state.lowered).length,
|
|
80
|
-
paused,
|
|
81
|
-
pcLow: nowMs < d.state.hostUntil,
|
|
82
|
-
lastAction: this.lastAction,
|
|
83
|
-
updatedAt: now(),
|
|
84
|
-
};
|
|
85
|
-
// Written when something changed, else once a minute (the host reads it, never polls it hard).
|
|
86
|
-
const shape = JSON.stringify({ ...status, updatedAt: '', paused: paused.map((p) => p.pid) });
|
|
87
|
-
if (shape !== this.lastWrite || nowMs - this.lastWriteAt > 60000) {
|
|
88
|
-
this.lastWrite = shape;
|
|
89
|
-
this.lastWriteAt = nowMs;
|
|
90
|
-
this.deps.saveStatus(status);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
apply(action) {
|
|
94
|
-
try {
|
|
95
|
-
if (action.kind === 'priority') {
|
|
96
|
-
this.deps.port.setPriority(action.pid, action.to);
|
|
97
|
-
this.lastAction = action.name + ' (' + action.pid + ') priority ' + action.to;
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
this.deps.port.pause(action.pid, action.ms);
|
|
101
|
-
this.pausedName = action.name;
|
|
102
|
-
this.pausedPid = action.pid;
|
|
103
|
-
this.lastAction = 'paused ' + action.name + ' (' + action.pid + ') for ' + action.ms / 1000 + ' s';
|
|
104
|
-
this.deps.logLine('governor: ' + this.lastAction);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
this.deps.logLine('governor: ' + this.lastAction);
|
|
108
|
-
}
|
|
109
|
-
catch (e) {
|
|
110
|
-
warn('governor: ' + errMsg(e));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
33
|
/** memgov.exe as a child process: samples come out of its stdout, commands go into its stdin. */
|
|
115
34
|
class MemGovProcess {
|
|
116
35
|
onSample;
|
|
@@ -145,10 +64,25 @@ class MemGovProcess {
|
|
|
145
64
|
}
|
|
146
65
|
}
|
|
147
66
|
setPriority(pid, to) {
|
|
148
|
-
this.
|
|
67
|
+
this.send('priority ' + pid + ' ' + to);
|
|
68
|
+
}
|
|
69
|
+
hold(pid, ms) {
|
|
70
|
+
this.send('suspend ' + pid + ' ' + ms);
|
|
71
|
+
}
|
|
72
|
+
setMemoryPriority(pid, low) {
|
|
73
|
+
this.send('memprio ' + pid + ' ' + (low ? 'low' : 'normal'));
|
|
74
|
+
}
|
|
75
|
+
throttle(pid) {
|
|
76
|
+
this.send('throttle ' + pid);
|
|
77
|
+
}
|
|
78
|
+
setCpuRate(percent) {
|
|
79
|
+
this.send('cpurate ' + Math.round(percent));
|
|
80
|
+
}
|
|
81
|
+
trim(pid) {
|
|
82
|
+
this.send('trim ' + pid);
|
|
149
83
|
}
|
|
150
|
-
|
|
151
|
-
this.child?.stdin?.write(
|
|
84
|
+
send(line) {
|
|
85
|
+
this.child?.stdin?.write(line + '\n');
|
|
152
86
|
}
|
|
153
87
|
}
|
|
154
88
|
/** The newest memory log SandboxTools writes, to add the governor's lines to it. */
|
|
@@ -175,15 +109,15 @@ export class Governor {
|
|
|
175
109
|
core = null;
|
|
176
110
|
describe() {
|
|
177
111
|
const profile = session.loadProfile === 'gentle' ? 'gentle' : 'normal';
|
|
178
|
-
const
|
|
112
|
+
const first = DIAL_STEPS[profile][0];
|
|
179
113
|
return session.pressureResponse === false
|
|
180
114
|
? 'off (sandbox.pressureResponse)'
|
|
181
115
|
: profile +
|
|
182
|
-
' profile: slows builds down
|
|
183
|
-
|
|
184
|
-
'% free RAM or
|
|
185
|
-
|
|
186
|
-
'% commit';
|
|
116
|
+
' profile: slows builds down from ' +
|
|
117
|
+
first.availablePercent +
|
|
118
|
+
'% free RAM or ' +
|
|
119
|
+
first.commitPercent +
|
|
120
|
+
'% commit, in steps';
|
|
187
121
|
}
|
|
188
122
|
start() {
|
|
189
123
|
if (session.pressureResponse === false)
|
|
@@ -193,8 +127,10 @@ export class Governor {
|
|
|
193
127
|
this.core = new GovernorCore({
|
|
194
128
|
port: proc,
|
|
195
129
|
profile,
|
|
130
|
+
maxCompilers: maxCompilers(os.cpus().length, profile),
|
|
196
131
|
now: () => Date.now(),
|
|
197
132
|
logLine: appendToMemoryLog,
|
|
133
|
+
warn,
|
|
198
134
|
saveStatus: (status) => {
|
|
199
135
|
try {
|
|
200
136
|
writeJsonAtomic(run.pressureFile, status);
|
|
@@ -206,9 +142,9 @@ export class Governor {
|
|
|
206
142
|
});
|
|
207
143
|
proc.start();
|
|
208
144
|
}
|
|
209
|
-
/** The host's watchdog: this PC is low for a while. */
|
|
210
|
-
hostPressure(seconds, reason) {
|
|
211
|
-
this.core?.hostPressure(seconds, reason);
|
|
145
|
+
/** The host's watchdog: this PC is low (or nearly out of memory) for a while. */
|
|
146
|
+
hostPressure(seconds, reason, level = 'slow') {
|
|
147
|
+
this.core?.hostPressure(seconds, reason, level);
|
|
212
148
|
}
|
|
213
149
|
}
|
|
214
150
|
export const governor = new Governor();
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** What the agent's manifest says about the LAN. */
|
|
2
2
|
export type LanState = 'blocked' | 'open' | 'offline';
|
|
3
|
+
export declare function networkProblems(): readonly string[];
|
|
4
|
+
/** netsh needs the long form of a path: the sandbox's TEMP is an 8.3 short path (WDAGUT~1). */
|
|
5
|
+
export declare function longPath(file: string): string;
|
|
3
6
|
export declare function run(commands: string[][]): void;
|
|
4
7
|
/**
|
|
5
8
|
* Applies the LAN block. Internet is checked first; if it works before the rules but not after, the rules (not the
|
|
@@ -4,14 +4,13 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import { relayPort, withBlockedHosts } from '../../shared/network/policy.js';
|
|
7
|
-
import { buildFirewallCommands, ipv4DnsServers, isIPv4, parseDefaultGateways, parseDnsServers, } from '../../shared/network/firewall-rules.js';
|
|
7
|
+
import { attachRuleCommands, buildFirewallCommands, hasShortName, ipv4DnsServers, isIPv4, parseDefaultGateways, parseDnsServers, } from '../../shared/network/firewall-rules.js';
|
|
8
8
|
import { SYSTEM } from '../../shared/system.js';
|
|
9
9
|
import { scriptArgs } from '../../shared/scripts.js';
|
|
10
10
|
import { dryRun, isWin } from '../runtime/paths.js';
|
|
11
11
|
import { log, warn } from '../runtime/log.js';
|
|
12
12
|
import { session } from '../runtime/session.js';
|
|
13
13
|
import { errMsg } from '../../core/util/errors.js';
|
|
14
|
-
const ATTACH_RULE = 'AgentSandbox-Attach';
|
|
15
14
|
const netsh = (args) => {
|
|
16
15
|
const r = spawnSync(SYSTEM.netsh(), args, { encoding: 'utf8', windowsHide: true });
|
|
17
16
|
return { status: r.status, out: (r.stdout ?? '') + (r.stderr ?? '') };
|
|
@@ -51,24 +50,49 @@ const waitForInternet = async (seconds) => {
|
|
|
51
50
|
}
|
|
52
51
|
return false;
|
|
53
52
|
};
|
|
54
|
-
/**
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
53
|
+
/** Protections that could not be put in place this boot (shown in the boot summary and the log, never silent). */
|
|
54
|
+
const problems = [];
|
|
55
|
+
export function networkProblems() {
|
|
56
|
+
return problems;
|
|
57
|
+
}
|
|
58
|
+
/** netsh needs the long form of a path: the sandbox's TEMP is an 8.3 short path (WDAGUT~1). */
|
|
59
|
+
export function longPath(file) {
|
|
60
|
+
if (!hasShortName(file))
|
|
61
|
+
return file;
|
|
62
|
+
try {
|
|
63
|
+
return fs.realpathSync.native(file);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return file; // netsh then says the program cannot be found, which is reported where the rule was wanted
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The inbound rule for ptyhost (the attach channel). A rule that cannot be added is a missing protection, so it is
|
|
71
|
+
* tried again a few times and then reported loudly instead of being skipped.
|
|
72
|
+
*/
|
|
73
|
+
async function applyAttachRule(ptyHostExe) {
|
|
74
|
+
if (!session.attach.enabled)
|
|
75
|
+
return;
|
|
76
|
+
if (!ptyHostExe) {
|
|
77
|
+
problems.push('attach: the session host was not built, so the firewall rule for it was not created');
|
|
78
|
+
warn(problems[problems.length - 1]);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
let last = '';
|
|
82
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
83
|
+
try {
|
|
84
|
+
run(attachRuleCommands(longPath(ptyHostExe)));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
last = errMsg(e);
|
|
89
|
+
if (attempt < 3)
|
|
90
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
problems.push('attach: the firewall rule for the session host could not be created (' + last + ')');
|
|
94
|
+
warn('PROTECTION MISSING: ' + problems[problems.length - 1]);
|
|
95
|
+
}
|
|
72
96
|
export function run(commands) {
|
|
73
97
|
for (const c of commands) {
|
|
74
98
|
const r = netsh(c);
|
|
@@ -89,10 +113,11 @@ export async function applyNetworkPolicy(ptyHostExe) {
|
|
|
89
113
|
const block = session.network.blockPrivateRanges;
|
|
90
114
|
const exempt = block ? discoverExemptIps() : [];
|
|
91
115
|
const lanRules = block ? buildFirewallCommands(exempt) : [];
|
|
116
|
+
const forwardRules = forwardRule();
|
|
92
117
|
const commands = [
|
|
93
118
|
...lanRules,
|
|
94
|
-
...(ptyHostExe && session.attach.enabled ?
|
|
95
|
-
...
|
|
119
|
+
...(ptyHostExe && session.attach.enabled ? attachRuleCommands(ptyHostExe) : []),
|
|
120
|
+
...forwardRules,
|
|
96
121
|
];
|
|
97
122
|
if (isWin && !dryRun) {
|
|
98
123
|
try {
|
|
@@ -122,7 +147,24 @@ export async function applyNetworkPolicy(ptyHostExe) {
|
|
|
122
147
|
if (commands.length === 0)
|
|
123
148
|
return 'open';
|
|
124
149
|
const online = block ? await waitForInternet(30) : true;
|
|
125
|
-
|
|
150
|
+
// Each group on its own: one failing must not skip the others (or the internet check below).
|
|
151
|
+
const failures = [];
|
|
152
|
+
try {
|
|
153
|
+
run(lanRules);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
failures.push(errMsg(e));
|
|
157
|
+
}
|
|
158
|
+
await applyAttachRule(ptyHostExe);
|
|
159
|
+
try {
|
|
160
|
+
run(forwardRules);
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
problems.push('forwardPorts: the firewall rule for the relays could not be created (' + errMsg(e) + ')');
|
|
164
|
+
warn('PROTECTION MISSING: ' + problems[problems.length - 1]);
|
|
165
|
+
}
|
|
166
|
+
if (failures.length)
|
|
167
|
+
throw new Error(failures[0]);
|
|
126
168
|
if (!block)
|
|
127
169
|
return 'open';
|
|
128
170
|
if (online && !(await waitForInternet(15))) {
|