windows-development-sandbox 1.10.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 +5 -1
- 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 +21 -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 -89
- package/dist/cli/commands/web.d.ts +2 -1
- package/dist/cli/commands/web.js +14 -78
- 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 +2 -1
- package/dist/core/schema/config.d.ts +5 -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/types.d.ts +6 -3
- package/dist/guest/boot/boot.js +8 -0
- 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 +46 -18
- package/dist/guest/governor/decide.js +136 -82
- package/dist/guest/governor/governor.d.ts +2 -38
- package/dist/guest/governor/governor.js +33 -113
- package/dist/guest/governor/index.d.ts +1 -0
- package/dist/guest/governor/index.js +1 -0
- package/dist/guest/network/firewall.d.ts +2 -0
- package/dist/guest/network/firewall.js +3 -3
- package/dist/guest/sessions/viewer.js +5 -1
- 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 +11 -1
- 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/watchdog.d.ts +9 -0
- package/dist/host/life/watchdog.js +17 -1
- 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 +30 -6
- package/dist/runtime/daemon.js +323 -176
- package/dist/runtime/db.js +30 -6
- package/dist/runtime/main.js +375 -76
- package/dist/runtime/netproxy.js +30 -6
- package/dist/runtime/view.js +495 -146
- 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/hcs.test.js +105 -8
- package/dist/selftest/health.test.js +71 -0
- package/dist/selftest/heavy-load.test.js +132 -72
- 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/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 +4 -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/memory/policy.d.ts +33 -12
- package/dist/shared/memory/policy.js +50 -19
- 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/package.json +10 -3
- package/sandbox/csharp/MemGov.cs +240 -38
- 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/repair-wmi-services.ps1 +26 -0
- package/schemas/config.schema.json +19 -5
- 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',
|
|
@@ -97,112 +103,160 @@ const HEAVY = new Set([
|
|
|
97
103
|
export const isHeavyCompiler = (name) => !isNeverTouched(name) && HEAVY.has(key(name));
|
|
98
104
|
export const canPause = (name) => !isNeverTouched(name) && COMPILERS.has(key(name));
|
|
99
105
|
export const INITIAL_STATE = {
|
|
100
|
-
|
|
106
|
+
step: 0,
|
|
101
107
|
calm: 0,
|
|
102
|
-
samples: 0,
|
|
103
108
|
lowered: {},
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
memLow: [],
|
|
110
|
+
throttled: [],
|
|
111
|
+
trimmed: [],
|
|
112
|
+
cpuRate: 100,
|
|
113
|
+
lastCommitMb: 0,
|
|
114
|
+
lastAt: 0,
|
|
115
|
+
growth: 0,
|
|
106
116
|
hostUntil: 0,
|
|
117
|
+
hostStep: 0,
|
|
107
118
|
};
|
|
108
|
-
/** How
|
|
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). */
|
|
109
122
|
export const HOLD_MS = 3000;
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
/** Samples under pressure before programs go from below-normal to idle, and before one is paused. */
|
|
113
|
-
const IDLE_AFTER = 3;
|
|
114
|
-
const PAUSE_AFTER = 4;
|
|
115
|
-
/** Only a program this big is worth pausing. */
|
|
116
|
-
const PAUSE_MIN_MB = 300;
|
|
123
|
+
/** Which compilers wait their turn changes this often, so none waits for ever. */
|
|
124
|
+
export const ROTATE_MS = 20000;
|
|
117
125
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
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.
|
|
120
128
|
*/
|
|
121
|
-
|
|
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
|
+
}
|
|
149
|
+
/**
|
|
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.
|
|
152
|
+
*/
|
|
153
|
+
export function decide(prev, sample, nowMs, profile, maxCompilers = null) {
|
|
122
154
|
const ramFree = (sample.ramAvailMb / Math.max(1, sample.ramTotalMb)) * 100;
|
|
123
|
-
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;
|
|
124
162
|
const pcLow = nowMs < prev.hostUntil;
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
let
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
calm
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
else if (prev.pressure) {
|
|
136
|
-
calm = recovered ? prev.calm + 1 : 0;
|
|
137
|
-
if (calm >= thresholds.calmSamples) {
|
|
138
|
-
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;
|
|
139
172
|
calm = 0;
|
|
140
|
-
samples = 0;
|
|
141
173
|
}
|
|
142
174
|
}
|
|
143
175
|
const actions = [];
|
|
144
176
|
const present = new Set(sample.procs.map((p) => p.pid));
|
|
177
|
+
const keep = (pids) => pids.filter((pid) => present.has(pid));
|
|
145
178
|
const lowered = {};
|
|
146
179
|
for (const [pid, to] of Object.entries(prev.lowered))
|
|
147
180
|
if (present.has(Number(pid)))
|
|
148
181
|
lowered[Number(pid)] = to;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
|
157
199
|
lowered[p.pid] = target;
|
|
158
|
-
}
|
|
159
200
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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);
|
|
174
218
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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);
|
|
179
237
|
}
|
|
180
238
|
}
|
|
239
|
+
for (const p of order.slice(0, allowed))
|
|
240
|
+
trimmed.delete(p.pid);
|
|
181
241
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const victim = [...sample.procs]
|
|
186
|
-
.filter((p) => canPause(p.name) && p.mb >= PAUSE_MIN_MB)
|
|
187
|
-
.sort((a, b) => b.mb - a.mb)[0];
|
|
188
|
-
if (victim) {
|
|
189
|
-
actions.push({ kind: 'pause', pid: victim.pid, name: victim.name, ms: PAUSE_MS });
|
|
190
|
-
pausedUntil = nowMs + PAUSE_MS;
|
|
191
|
-
nextPauseAt = pausedUntil + PAUSE_COOLDOWN_MS;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
// Concurrency cap (vGPU profile): the oldest N heavy compilers run, the newer ones wait a few seconds at a time.
|
|
195
|
-
if (maxCompilers !== null) {
|
|
196
|
-
const heavy = sample.procs
|
|
197
|
-
.filter((p) => isHeavyCompiler(p.name) &&
|
|
198
|
-
!(nowMs < pausedUntil && actions.some((a) => a.kind === 'pause' && a.pid === p.pid)))
|
|
199
|
-
.sort((a, b) => a.pid - b.pid);
|
|
200
|
-
for (const p of heavy.slice(Math.max(1, maxCompilers)))
|
|
201
|
-
actions.push({ kind: 'hold', pid: p.pid, name: p.name, ms: HOLD_MS });
|
|
202
|
-
}
|
|
203
|
-
const level = nowMs < pausedUntil ? 'suspending' : pressure ? 'throttled' : 'ok';
|
|
242
|
+
else
|
|
243
|
+
trimmed.clear();
|
|
244
|
+
const level = step >= 3 ? 'suspending' : step >= 1 ? 'throttled' : 'ok';
|
|
204
245
|
return {
|
|
205
|
-
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
|
+
},
|
|
206
260
|
actions,
|
|
207
261
|
level,
|
|
208
262
|
ramFreePercent: Math.round(ramFree),
|
|
@@ -1,45 +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
|
-
/** At most this many heavy compilers run at once (null = no cap). */
|
|
14
|
-
readonly maxCompilers?: number | null;
|
|
15
|
-
readonly now: () => number;
|
|
16
|
-
/** A line in the memory log. */
|
|
17
|
-
readonly logLine: (line: string) => void;
|
|
18
|
-
/** run\pressure.json. */
|
|
19
|
-
readonly saveStatus: (status: PressureStatus) => void;
|
|
20
|
-
}
|
|
21
|
-
/** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
|
|
22
|
-
export declare class GovernorCore {
|
|
23
|
-
private readonly deps;
|
|
24
|
-
private state;
|
|
25
|
-
private lastAction;
|
|
26
|
-
private lastWrite;
|
|
27
|
-
private lastWriteAt;
|
|
28
|
-
private pausedName;
|
|
29
|
-
private pausedPid;
|
|
30
|
-
private held;
|
|
31
|
-
constructor(deps: GovernorDeps);
|
|
32
|
-
hostPressure(seconds: number, reason: string): void;
|
|
33
|
-
get current(): GovernorState;
|
|
34
|
-
onSample(sample: MemSample): void;
|
|
35
|
-
private apply;
|
|
36
|
-
}
|
|
37
1
|
/** The daemon's governor: on unless sandbox.pressureResponse is off. */
|
|
38
2
|
export declare class Governor {
|
|
39
3
|
private core;
|
|
40
4
|
describe(): string;
|
|
41
5
|
start(): void;
|
|
42
|
-
/** The host's watchdog: this PC is low for a while. */
|
|
43
|
-
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;
|
|
44
8
|
}
|
|
45
9
|
export declare const governor: Governor;
|
|
@@ -1,22 +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
5
|
import os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
-
import { now } from '../../shared/channel/run-dir.js';
|
|
11
10
|
import { writeJsonAtomic } from '../../shared/io/json.js';
|
|
12
|
-
import {
|
|
11
|
+
import { DIAL_STEPS, maxCompilers } from '../../shared/memory/index.js';
|
|
13
12
|
import { ensureCompiled } from '../runtime/csc.js';
|
|
14
13
|
import { dataDir } from '../runtime/paths.js';
|
|
15
14
|
import { warn } from '../runtime/log.js';
|
|
16
15
|
import { run } from '../runtime/paths.js';
|
|
17
16
|
import { session } from '../runtime/session.js';
|
|
18
17
|
import { errMsg } from '../../core/util/errors.js';
|
|
19
|
-
import {
|
|
18
|
+
import { GovernorCore } from './core.js';
|
|
20
19
|
const SampleSchema = z.object({
|
|
21
20
|
ramTotalMb: z.number(),
|
|
22
21
|
ramAvailMb: z.number(),
|
|
@@ -31,101 +30,6 @@ const SampleSchema = z.object({
|
|
|
31
30
|
}))
|
|
32
31
|
.max(1024),
|
|
33
32
|
});
|
|
34
|
-
/** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
|
|
35
|
-
export class GovernorCore {
|
|
36
|
-
deps;
|
|
37
|
-
state = INITIAL_STATE;
|
|
38
|
-
lastAction = '';
|
|
39
|
-
lastWrite = '';
|
|
40
|
-
lastWriteAt = 0;
|
|
41
|
-
pausedName = '';
|
|
42
|
-
pausedPid = 0;
|
|
43
|
-
held = new Set();
|
|
44
|
-
constructor(deps) {
|
|
45
|
-
this.deps = deps;
|
|
46
|
-
}
|
|
47
|
-
hostPressure(seconds, reason) {
|
|
48
|
-
const until = this.deps.now() + seconds * 1000;
|
|
49
|
-
if (until > this.state.hostUntil) {
|
|
50
|
-
if (this.state.hostUntil <= this.deps.now())
|
|
51
|
-
this.deps.logLine('governor: this PC is low (' + reason + '); slowing builds down');
|
|
52
|
-
this.state = { ...this.state, hostUntil: until };
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
get current() {
|
|
56
|
-
return this.state;
|
|
57
|
-
}
|
|
58
|
-
onSample(sample) {
|
|
59
|
-
const nowMs = this.deps.now();
|
|
60
|
-
const before = this.state.pressure;
|
|
61
|
-
const seen = new Set(sample.procs.map((p) => p.pid));
|
|
62
|
-
for (const pid of this.held)
|
|
63
|
-
if (!seen.has(pid))
|
|
64
|
-
this.held.delete(pid);
|
|
65
|
-
const d = decide(this.state, sample, nowMs, GUEST_THRESHOLDS[this.deps.profile], this.deps.profile, this.deps.maxCompilers ?? null);
|
|
66
|
-
this.state = d.state;
|
|
67
|
-
for (const action of d.actions)
|
|
68
|
-
this.apply(action);
|
|
69
|
-
if (d.state.pressure !== before)
|
|
70
|
-
this.deps.logLine(d.state.pressure
|
|
71
|
-
? 'governor: memory is low (' +
|
|
72
|
-
d.ramFreePercent +
|
|
73
|
-
'% RAM free, commit ' +
|
|
74
|
-
d.commitPercent +
|
|
75
|
-
'% used): slowing builds down'
|
|
76
|
-
: 'governor: memory is fine again: builds back to normal');
|
|
77
|
-
const paused = nowMs < d.state.pausedUntil && this.pausedPid
|
|
78
|
-
? [{ name: this.pausedName, pid: this.pausedPid, seconds: Math.ceil((d.state.pausedUntil - nowMs) / 1000) }]
|
|
79
|
-
: [];
|
|
80
|
-
const status = {
|
|
81
|
-
level: d.level,
|
|
82
|
-
profile: this.deps.profile,
|
|
83
|
-
ramFreePercent: Math.max(0, Math.min(100, d.ramFreePercent)),
|
|
84
|
-
commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
|
|
85
|
-
lowered: Object.keys(d.state.lowered).length,
|
|
86
|
-
paused,
|
|
87
|
-
pcLow: nowMs < d.state.hostUntil,
|
|
88
|
-
lastAction: this.lastAction,
|
|
89
|
-
updatedAt: now(),
|
|
90
|
-
};
|
|
91
|
-
// Written when something changed, else once a minute (the host reads it, never polls it hard).
|
|
92
|
-
const shape = JSON.stringify({ ...status, updatedAt: '', paused: paused.map((p) => p.pid) });
|
|
93
|
-
if (shape !== this.lastWrite || nowMs - this.lastWriteAt > 60000) {
|
|
94
|
-
this.lastWrite = shape;
|
|
95
|
-
this.lastWriteAt = nowMs;
|
|
96
|
-
this.deps.saveStatus(status);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
apply(action) {
|
|
100
|
-
try {
|
|
101
|
-
if (action.kind === 'hold') {
|
|
102
|
-
this.deps.port.pause(action.pid, action.ms);
|
|
103
|
-
if (!this.held.has(action.pid)) {
|
|
104
|
-
this.held.add(action.pid);
|
|
105
|
-
this.lastAction = 'holding ' + action.name + ' (' + action.pid + ') until another compiler ends';
|
|
106
|
-
this.deps.logLine('governor: ' + this.lastAction);
|
|
107
|
-
}
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
if (action.kind === 'priority') {
|
|
111
|
-
this.deps.port.setPriority(action.pid, action.to);
|
|
112
|
-
this.lastAction = action.name + ' (' + action.pid + ') priority ' + action.to;
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
this.deps.port.pause(action.pid, action.ms);
|
|
116
|
-
this.pausedName = action.name;
|
|
117
|
-
this.pausedPid = action.pid;
|
|
118
|
-
this.lastAction = 'paused ' + action.name + ' (' + action.pid + ') for ' + action.ms / 1000 + ' s';
|
|
119
|
-
this.deps.logLine('governor: ' + this.lastAction);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
this.deps.logLine('governor: ' + this.lastAction);
|
|
123
|
-
}
|
|
124
|
-
catch (e) {
|
|
125
|
-
warn('governor: ' + errMsg(e));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
33
|
/** memgov.exe as a child process: samples come out of its stdout, commands go into its stdin. */
|
|
130
34
|
class MemGovProcess {
|
|
131
35
|
onSample;
|
|
@@ -160,10 +64,25 @@ class MemGovProcess {
|
|
|
160
64
|
}
|
|
161
65
|
}
|
|
162
66
|
setPriority(pid, to) {
|
|
163
|
-
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);
|
|
164
83
|
}
|
|
165
|
-
|
|
166
|
-
this.child?.stdin?.write(
|
|
84
|
+
send(line) {
|
|
85
|
+
this.child?.stdin?.write(line + '\n');
|
|
167
86
|
}
|
|
168
87
|
}
|
|
169
88
|
/** The newest memory log SandboxTools writes, to add the governor's lines to it. */
|
|
@@ -190,15 +109,15 @@ export class Governor {
|
|
|
190
109
|
core = null;
|
|
191
110
|
describe() {
|
|
192
111
|
const profile = session.loadProfile === 'gentle' ? 'gentle' : 'normal';
|
|
193
|
-
const
|
|
112
|
+
const first = DIAL_STEPS[profile][0];
|
|
194
113
|
return session.pressureResponse === false
|
|
195
114
|
? 'off (sandbox.pressureResponse)'
|
|
196
115
|
: profile +
|
|
197
|
-
' profile: slows builds down
|
|
198
|
-
|
|
199
|
-
'% free RAM or
|
|
200
|
-
|
|
201
|
-
'% commit';
|
|
116
|
+
' profile: slows builds down from ' +
|
|
117
|
+
first.availablePercent +
|
|
118
|
+
'% free RAM or ' +
|
|
119
|
+
first.commitPercent +
|
|
120
|
+
'% commit, in steps';
|
|
202
121
|
}
|
|
203
122
|
start() {
|
|
204
123
|
if (session.pressureResponse === false)
|
|
@@ -211,6 +130,7 @@ export class Governor {
|
|
|
211
130
|
maxCompilers: maxCompilers(os.cpus().length, profile),
|
|
212
131
|
now: () => Date.now(),
|
|
213
132
|
logLine: appendToMemoryLog,
|
|
133
|
+
warn,
|
|
214
134
|
saveStatus: (status) => {
|
|
215
135
|
try {
|
|
216
136
|
writeJsonAtomic(run.pressureFile, status);
|
|
@@ -222,9 +142,9 @@ export class Governor {
|
|
|
222
142
|
});
|
|
223
143
|
proc.start();
|
|
224
144
|
}
|
|
225
|
-
/** The host's watchdog: this PC is low for a while. */
|
|
226
|
-
hostPressure(seconds, reason) {
|
|
227
|
-
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);
|
|
228
148
|
}
|
|
229
149
|
}
|
|
230
150
|
export const governor = new Governor();
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** What the agent's manifest says about the LAN. */
|
|
2
2
|
export type LanState = 'blocked' | 'open' | 'offline';
|
|
3
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;
|
|
4
6
|
export declare function run(commands: string[][]): void;
|
|
5
7
|
/**
|
|
6
8
|
* Applies the LAN block. Internet is checked first; if it works before the rules but not after, the rules (not the
|
|
@@ -56,16 +56,16 @@ export function networkProblems() {
|
|
|
56
56
|
return problems;
|
|
57
57
|
}
|
|
58
58
|
/** netsh needs the long form of a path: the sandbox's TEMP is an 8.3 short path (WDAGUT~1). */
|
|
59
|
-
|
|
59
|
+
export function longPath(file) {
|
|
60
60
|
if (!hasShortName(file))
|
|
61
61
|
return file;
|
|
62
62
|
try {
|
|
63
63
|
return fs.realpathSync.native(file);
|
|
64
64
|
}
|
|
65
65
|
catch {
|
|
66
|
-
return file;
|
|
66
|
+
return file; // netsh then says the program cannot be found, which is reported where the rule was wanted
|
|
67
67
|
}
|
|
68
|
-
}
|
|
68
|
+
}
|
|
69
69
|
/**
|
|
70
70
|
* The inbound rule for ptyhost (the attach channel). A rule that cannot be added is a missing protection, so it is
|
|
71
71
|
* tried again a few times and then reported loudly instead of being skipped.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { connect, runTerminalClient } from '../../shared/pty/index.js';
|
|
2
2
|
import { run } from '../runtime/paths.js';
|
|
3
|
+
import { session as sandboxSession } from '../runtime/session.js';
|
|
3
4
|
/**
|
|
4
5
|
* A session that is still being set up (its project provisioning, its agent installing): show the progress until it
|
|
5
6
|
* runs.
|
|
@@ -32,7 +33,10 @@ export async function viewSession(id) {
|
|
|
32
33
|
const socket = await connect({ ...session.attach, addresses: ['127.0.0.1'] });
|
|
33
34
|
// The sandbox's own terminal: a copy in the agent reaches the sandbox's clipboard (and yours only through
|
|
34
35
|
// sandbox.clipboard, which already shares it).
|
|
35
|
-
const result = await runTerminalClient(socket, session.attach.token, {
|
|
36
|
+
const result = await runTerminalClient(socket, session.attach.token, {
|
|
37
|
+
clipboardWrites: true,
|
|
38
|
+
confirmCtrlC: sandboxSession.attach.confirmCtrlC !== false,
|
|
39
|
+
});
|
|
36
40
|
if (result.reason === 'exit')
|
|
37
41
|
console.log(session.harness + ' exited with code ' + result.exitCode + '.');
|
|
38
42
|
else if (result.reason === 'error')
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Before the tools are set up: the folder gh uses for a handed-over token exists only when one arrived (gh's setup
|
|
3
|
+
* points GH_CONFIG_DIR at it while it exists). Without one, gh keeps the login you made in the sandbox.
|
|
4
|
+
*/
|
|
5
|
+
export declare function prepareGithubFolder(token: string | undefined): boolean;
|
|
6
|
+
/** gh logs in with the token (stdin) in the sandbox-only folder, then https git to github.com asks gh. */
|
|
7
|
+
export declare function loginGithub(token: string, env: NodeJS.ProcessEnv): void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// The GitHub token the host handed over (github.shareToken, only with git access "full"): gh logs in with it in a
|
|
2
|
+
// folder on the sandbox's own disk (gone with the sandbox, never in the persistent state), and https git asks gh. The
|
|
3
|
+
// token goes to gh on stdin, never in an argument, a file of ours or a log line.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { ghLoginCommand, ghOutputText, ghSetupGitCommand } from '../../shared/github/index.js';
|
|
7
|
+
import { deliveredGhConfigDir, ghConfigDir, ghExePath } from '../toolchains/tools/cli.js';
|
|
8
|
+
import { addMachineEnvironment } from './environment.js';
|
|
9
|
+
import { dryRun } from '../runtime/paths.js';
|
|
10
|
+
import { exists, mkdirp } from '../runtime/fs.js';
|
|
11
|
+
import { log } from '../runtime/log.js';
|
|
12
|
+
const GH_TIMEOUT_MS = 60_000;
|
|
13
|
+
/**
|
|
14
|
+
* Before the tools are set up: the folder gh uses for a handed-over token exists only when one arrived (gh's setup
|
|
15
|
+
* points GH_CONFIG_DIR at it while it exists). Without one, gh keeps the login you made in the sandbox.
|
|
16
|
+
*/
|
|
17
|
+
export function prepareGithubFolder(token) {
|
|
18
|
+
const dir = deliveredGhConfigDir();
|
|
19
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
20
|
+
if (!token)
|
|
21
|
+
return false;
|
|
22
|
+
mkdirp(dir);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
function runGh(command, token, what) {
|
|
26
|
+
const result = spawnSync(command.file, [...command.args], {
|
|
27
|
+
env: command.env,
|
|
28
|
+
encoding: 'utf8',
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
timeout: GH_TIMEOUT_MS,
|
|
31
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
32
|
+
...(command.input !== undefined ? { input: command.input } : {}),
|
|
33
|
+
});
|
|
34
|
+
if (result.error)
|
|
35
|
+
throw new Error(what + ' could not run: ' + ghOutputText(result.error.message, token));
|
|
36
|
+
if (result.status !== 0)
|
|
37
|
+
throw new Error(what + ' failed: ' + ghOutputText(String(result.stderr ?? '') || String(result.stdout ?? ''), token));
|
|
38
|
+
}
|
|
39
|
+
/** gh logs in with the token (stdin) in the sandbox-only folder, then https git to github.com asks gh. */
|
|
40
|
+
export function loginGithub(token, env) {
|
|
41
|
+
if (dryRun) {
|
|
42
|
+
log('(dry run) would log gh in with the GitHub token from your PC');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const gh = ghExePath();
|
|
46
|
+
const dir = deliveredGhConfigDir();
|
|
47
|
+
if (!exists(gh) || env.GH_CONFIG_DIR !== dir) {
|
|
48
|
+
// Gone again, so gh set up later (a project added afterwards) keeps the login you make in the sandbox.
|
|
49
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
50
|
+
log('A GitHub token arrived, but gh is not set up in this sandbox (toolchains.cli.gh), so it is not used.');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
runGh(ghLoginCommand(gh, dir, token, env), token, 'gh auth login');
|
|
55
|
+
runGh(ghSetupGitCommand(gh, dir, env), token, 'gh auth setup-git');
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
// gh goes back to the persistent folder (and a `gh auth login` you make inside is kept), for every session.
|
|
59
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
60
|
+
env.GH_CONFIG_DIR = mkdirp(ghConfigDir());
|
|
61
|
+
addMachineEnvironment({ GH_CONFIG_DIR: env.GH_CONFIG_DIR }, []);
|
|
62
|
+
throw e;
|
|
63
|
+
}
|
|
64
|
+
log('gh and https git to github.com use the GitHub token from your PC (github.shareToken); the agent can read it.');
|
|
65
|
+
}
|