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
|
@@ -8,11 +8,13 @@ import { DEFAULTS } from '../core/config/index.js';
|
|
|
8
8
|
import { isWin } from '../core/util/index.js';
|
|
9
9
|
import { SYSTEM } from '../shared/system.js';
|
|
10
10
|
import { GuestRequestSchema, PressureStatusSchema } from '../shared/channel/index.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { compilersAllowed, DIAL_CALM_SAMPLES, DIAL_STEPS, HOST_THRESHOLDS, buildJobs, cargoJobs, linkSlotsFor, usableCpus, effectiveCpuLimit, gentleCpuLimit, maxCompilers, } from '../shared/memory/index.js';
|
|
12
|
+
import { cappedMemoryMb, decideMemory, memoryNote, residentCapMb, residentNote, resolveMemoryMb, } from '../host/launch/index.js';
|
|
13
13
|
import { vgpuWarning, GENTLE_NOTE } from '../host/launch/risk-notes.js';
|
|
14
|
-
import { bugcheckCode, cpuPercentBetween, explainStop, findDumps, findingLines, freezeLine, hostPressure, lowReason, pageFileRisk, parseHostMemory, crashReportText, watchdogStep, WATCHDOG_START, } from '../host/life/index.js';
|
|
15
|
-
|
|
14
|
+
import { bugcheckCode, cpuPercentBetween, explainStop, findDumps, findingLines, freezeLine, hostPressure, lowReason, severeHost, pageFileRisk, parseHostMemory, crashReportText, watchdogStep, WATCHDOG_START, } from '../host/life/index.js';
|
|
15
|
+
// The pure governor files only: governor.ts loads the guest runtime (session.json), which exists only in a sandbox.
|
|
16
|
+
import { canLower, canPause, decide, INITIAL_STATE, ROTATE_MS, } from '../guest/governor/decide.js';
|
|
17
|
+
import { GovernorCore } from '../guest/governor/core.js';
|
|
16
18
|
const GB = 1024;
|
|
17
19
|
const MB_SANDBOX = DEFAULTS.sandbox;
|
|
18
20
|
const proc = (pid, name, mb, prio = 'normal') => ({
|
|
@@ -59,17 +61,22 @@ export const heavyLoadSuite = {
|
|
|
59
61
|
refused = String(e instanceof Error ? e.message : e);
|
|
60
62
|
}
|
|
61
63
|
t.check(refused.includes('RAM plus paging file'), 'too little commit refuses with the real reason', refused);
|
|
62
|
-
t.check(resolveMemoryMb({ ...MB_SANDBOX, memoryMb: 5000 }, 1, 1, 1) === 5000, 'a fixed memoryMb is
|
|
63
|
-
t.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
t.check(
|
|
67
|
-
|
|
64
|
+
t.check(resolveMemoryMb({ ...MB_SANDBOX, memoryMb: 5000 }, 1, 1, 1) === 5000, 'a fixed memoryMb is taken as asked (the resident cap below is the only limit on it)');
|
|
65
|
+
t.check(residentCapMb({ ...MB_SANDBOX, vGpu: false }, 32768) === 24576 &&
|
|
66
|
+
residentCapMb({ ...MB_SANDBOX, vGpu: true }, 32768) === 22528 &&
|
|
67
|
+
residentCapMb({ ...MB_SANDBOX, vGpu: false }, 65536) === 49152, 'what this PC can keep in RAM for the sandbox: its RAM minus max(reserve, 25 %), 2 GB more with vGPU');
|
|
68
|
+
t.check(cappedMemoryMb(32768, { ...MB_SANDBOX, vGpu: true }, 32768) === 22528 &&
|
|
69
|
+
cappedMemoryMb(16384, { ...MB_SANDBOX, vGpu: true }, 32768) === 16384 &&
|
|
70
|
+
cappedMemoryMb(8192, MB_SANDBOX, 6144) === 8192, 'a fixed memoryMb above it is lowered to it (never on a PC too small to keep 4 GB)');
|
|
71
|
+
t.check(residentNote(32768, 22528)?.includes('gets 22528 MB') === true && residentNote(16384, 16384) === null, 'and the launch says so');
|
|
72
|
+
t.check(decideMemory({ ...MB_SANDBOX, maxMemoryPercent: 100, maxMemoryMb: 65536, reserveHostMb: 1024 }, 32000, 32768, null).limitedBy === 'resident', '"auto" never goes above it either');
|
|
73
|
+
t.section("the agents' job backstop");
|
|
68
74
|
const gen = await f.launch({}, { args: ['--version'] });
|
|
69
75
|
const session = JSON.parse(fs.readFileSync(gen.sessionPath, 'utf8'));
|
|
70
|
-
t.check(session.
|
|
76
|
+
t.check(session.agentBackstop === 'auto' &&
|
|
77
|
+
session.agentMemoryLimitMb === undefined &&
|
|
71
78
|
session.pressureResponse === true &&
|
|
72
|
-
session.loadProfile === 'normal', 'session.json carries the limit, the governor switch and the profile
|
|
79
|
+
session.loadProfile === 'normal', 'session.json carries the backstop setting (no limit from RAM any more), the governor switch and the profile', JSON.stringify(session.agentBackstop));
|
|
73
80
|
const vgpuConfig = f.makeConfig();
|
|
74
81
|
vgpuConfig.sandbox.vGpu = true;
|
|
75
82
|
const gentle = await f.launch({}, { args: ['--version'], config: vgpuConfig });
|
|
@@ -82,9 +89,13 @@ export const heavyLoadSuite = {
|
|
|
82
89
|
t.check(cargoJobs(16, 32, 1) === 4, '16 CPUs, 32 GB: 4 jobs');
|
|
83
90
|
t.check(cargoJobs(16, 8, 1) === 2 && cargoJobs(16, 3, 1) === 1, 'about 4 GB per job');
|
|
84
91
|
t.check(cargoJobs(16, 32, 3) === 2 && cargoJobs(16, 32, 8) === 1, 'fewer when several sessions build');
|
|
92
|
+
t.check(cargoJobs(32, 32, 1) === 8, '32 processors, 32 GB: 8 jobs for one session');
|
|
93
|
+
t.check(buildJobs(32, 32) === 8 && buildJobs(32, 64) === 19 && buildJobs(4, 64) === 4 && buildJobs(16, 4) === 2, 'the build budget: 3 GB per job after 6 GB, never more than the processors, at least 2');
|
|
94
|
+
t.check(linkSlotsFor(32) === 8 && linkSlotsFor(16) === 3 && linkSlotsFor(8) === 2 && linkSlotsFor(128) === 8, 'links at once ("auto"): one per 3 GB after 6 GB, 2 to 8');
|
|
95
|
+
t.check(usableCpus(32, 80) === 25 && usableCpus(32, null) === 32 && usableCpus(4, 10) === 2 && usableCpus(8, 100) === 8, 'the processors programs see follow the CPU cap (at least 2)');
|
|
85
96
|
t.section('the governor: which programs');
|
|
86
97
|
t.check(canPause('rustc.exe') && canPause('link.exe') && canPause('ld.lld.exe'), 'compilers and linkers may be paused');
|
|
87
|
-
t.check(!canPause('node.exe') && canLower('node.exe') && canLower('MSBuild.exe'), 'build tools are only slowed down');
|
|
98
|
+
t.check(!canPause('node.exe') && !canLower('node.exe') && canLower('MSBuild.exe'), 'build tools are only slowed down');
|
|
88
99
|
t.check([
|
|
89
100
|
'claude.exe',
|
|
90
101
|
'codex.exe',
|
|
@@ -95,60 +106,78 @@ export const heavyLoadSuite = {
|
|
|
95
106
|
'svchost.exe',
|
|
96
107
|
'memgov.exe',
|
|
97
108
|
].every((n) => !canLower(n) && !canPause(n)), 'agents, shells, ptyhost, git and system programs are never touched');
|
|
98
|
-
t.section('the governor:
|
|
99
|
-
const normal = GUEST_THRESHOLDS.normal;
|
|
109
|
+
t.section('the governor: the dial turns up in steps, down slowly');
|
|
100
110
|
const procs = [
|
|
101
111
|
proc(1, 'rustc.exe', 2800),
|
|
102
112
|
proc(2, 'rustc.exe', 2000),
|
|
103
113
|
proc(3, 'claude.exe', 900),
|
|
104
114
|
proc(4, 'link.exe', 500),
|
|
105
115
|
];
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
116
|
+
const of = (d, kind) => d.actions.filter((a) => a.kind === kind);
|
|
117
|
+
const pids = (actions) => actions
|
|
118
|
+
.map((a) => ('pid' in a ? a.pid : 0))
|
|
119
|
+
.sort()
|
|
120
|
+
.join();
|
|
121
|
+
const calm = decide(INITIAL_STATE, sample(50, 50, procs), 1000, 'normal');
|
|
122
|
+
t.check(calm.state.step === 0 && calm.level === 'ok' && calm.actions.length === 0, '50 % free: nothing happens');
|
|
123
|
+
t.check(decide(INITIAL_STATE, sample(16, 79, procs), 1000, 'normal').state.step === 0, '16 % free and 79 % commit are fine (step 1 starts at 15 % and 80 %)');
|
|
124
|
+
const one = decide(INITIAL_STATE, sample(14, 50, procs), 1000, 'normal');
|
|
125
|
+
t.check(one.state.step === 1 &&
|
|
126
|
+
of(one, 'priority').every((a) => a.kind === 'priority' && a.to === 'below') &&
|
|
127
|
+
pids(of(one, 'priority')) === '1,2,4' &&
|
|
128
|
+
pids(of(one, 'memory')) === '1,2,4' &&
|
|
129
|
+
of(one, 'hold').length === 0 &&
|
|
130
|
+
of(one, 'cpu').length === 0, 'step 1: build programs get lower CPU and memory priority, nothing waits, the agent is untouched');
|
|
131
|
+
const two = decide(INITIAL_STATE, sample(9, 50, procs), 1000, 'normal');
|
|
132
|
+
t.check(two.state.step === 2 &&
|
|
133
|
+
of(two, 'priority').every((a) => a.kind === 'priority' && a.to === 'idle') &&
|
|
134
|
+
pids(of(two, 'throttle')) === '1,2,4' &&
|
|
135
|
+
of(two, 'cpu').some((a) => a.kind === 'cpu' && a.percent === 60) &&
|
|
136
|
+
of(two, 'hold').length === 1, 'step 2: idle priority, compilers share 60 % of the CPU, 2 of 3 compilers go on');
|
|
137
|
+
const three = decide(INITIAL_STATE, sample(5, 50, procs), 1000, 'normal');
|
|
138
|
+
t.check(three.state.step === 3 &&
|
|
139
|
+
three.level === 'suspending' &&
|
|
140
|
+
of(three, 'cpu').some((a) => a.kind === 'cpu' && a.percent === 35) &&
|
|
141
|
+
of(three, 'hold').length === 2 &&
|
|
142
|
+
pids(of(three, 'trim')) === pids(of(three, 'hold')), 'step 3: 35 % CPU, one compiler goes on, the waiting ones are trimmed to the paging file');
|
|
143
|
+
t.check(decide(INITIAL_STATE, sample(50, 98, procs), 1000, 'normal').state.step === 4, 'commit above 97 % is step 4');
|
|
144
|
+
// A build that grabs 2 GB in two seconds while most memory is free is normal: no false alarm (it paused compilers).
|
|
145
|
+
const burst = decide({ ...INITIAL_STATE, lastCommitMb: 4000, lastAt: 1000 }, sample(50, 60, procs), 3000, 'normal');
|
|
146
|
+
t.check(burst.state.step === 0, 'a burst of commit while most memory is free does not turn the dial', 'step ' + burst.state.step);
|
|
147
|
+
const growing = decide({ ...INITIAL_STATE, lastCommitMb: 8400, lastAt: 1000, growth: 200 }, sample(50, 88, procs), 3000, 'normal');
|
|
148
|
+
t.check(growing.state.step === 4, 'commit near its limit that keeps growing (about 6 s left) turns the dial up before it gets there', 'step ' + growing.state.step);
|
|
149
|
+
const everything = [one, two, three, growing].flatMap((d) => d.actions);
|
|
150
|
+
t.check(everything.every((a) => !('pid' in a) || a.pid !== 3), 'the agent is never slowed, held or trimmed at any step');
|
|
151
|
+
// Hysteresis: step 2 holds while memory is between its entry (10 %) and its exit (15 %).
|
|
152
|
+
let h = decide(INITIAL_STATE, sample(9, 50, procs), 0, 'normal').state;
|
|
153
|
+
h = decide(h, sample(12, 50, procs), 2000, 'normal').state;
|
|
154
|
+
t.check(h.step === 2, 'between the entry and the exit of a step it stays (no flapping)');
|
|
155
|
+
const steps = [];
|
|
156
|
+
for (let i = 0; i < 2 * DIAL_CALM_SAMPLES; i++) {
|
|
157
|
+
h = decide(h, sample(40, 40, procs), 4000 + i * 2000, 'normal').state;
|
|
158
|
+
steps.push(h.step);
|
|
124
159
|
}
|
|
125
|
-
t.check(
|
|
126
|
-
const
|
|
127
|
-
t.check(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
t.check(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
t.check(
|
|
137
|
-
|
|
138
|
-
back.actions[0].kind === 'priority' &&
|
|
139
|
-
back.actions[0].to === 'normal', 'when it ends the compilers get their normal priority back');
|
|
140
|
-
t.check(decide(INITIAL_STATE, sample(5, 50, [proc(1, 'rustc.exe', 100)]), 0, normal, 'normal').actions.length === 1 &&
|
|
141
|
-
!decide({ ...INITIAL_STATE, samples: 10 }, sample(5, 50, [proc(1, 'rustc.exe', 100)]), 99999, normal, 'normal').actions.some((a) => a.kind === 'pause'), 'a small compiler (under 300 MB) is never worth pausing');
|
|
142
|
-
const hostAsked = decide({ ...INITIAL_STATE, hostUntil: 5000 }, sample(60, 40, procs), 1000, normal, 'normal');
|
|
143
|
-
t.check(hostAsked.level === 'throttled', 'the PC asking for it counts as pressure while the request lasts');
|
|
160
|
+
t.check(steps.join() === '2,2,1,1,1,0', 'it turns down one step after ' + DIAL_CALM_SAMPLES + ' calm samples: ' + steps.join());
|
|
161
|
+
const back = decide({ ...INITIAL_STATE, step: 1, calm: DIAL_CALM_SAMPLES - 1, lowered: { 1: 'below' }, memLow: [1], cpuRate: 100 }, sample(40, 40, [proc(1, 'rustc.exe', 2800, 'below')]), 9000, 'normal');
|
|
162
|
+
t.check(back.state.step === 0 &&
|
|
163
|
+
of(back, 'priority').some((a) => a.kind === 'priority' && a.to === 'normal') &&
|
|
164
|
+
of(back, 'memory').some((a) => a.kind === 'memory' && !a.low), 'at step 0 the compilers get their normal CPU and memory priority back');
|
|
165
|
+
const uncapped = decide({ ...INITIAL_STATE, step: 2, calm: DIAL_CALM_SAMPLES - 1, cpuRate: 60 }, sample(40, 40, procs), 9000, 'normal');
|
|
166
|
+
t.check(uncapped.state.step === 1 && of(uncapped, 'cpu').some((a) => a.kind === 'cpu' && a.percent === 100), 'the CPU cap is lifted when the dial goes below step 2');
|
|
167
|
+
const hostAsked = decide({ ...INITIAL_STATE, hostUntil: 5000, hostStep: 2 }, sample(60, 40, procs), 1000, 'normal');
|
|
168
|
+
t.check(hostAsked.state.step >= 2, 'the PC asking for it turns the dial to at least step 2 while it lasts');
|
|
169
|
+
const turnA = of(decide(INITIAL_STATE, sample(5, 50, procs), 0, 'normal'), 'hold');
|
|
170
|
+
const turnB = of(decide(INITIAL_STATE, sample(5, 50, procs), ROTATE_MS, 'normal'), 'hold');
|
|
171
|
+
t.check(pids(turnA) !== pids(turnB), 'who waits changes over time, so no compiler waits for ever');
|
|
172
|
+
t.check(compilersAllowed(2, 10) === 6 && compilersAllowed(3, 10) === 4 && compilersAllowed(4, 10) === 1, 'how many compilers go on at steps 2, 3 and 4');
|
|
144
173
|
t.section('the gentle profile (vGPU on)');
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const g = decide(INITIAL_STATE, sample(50, 50, procs), 0,
|
|
148
|
-
t.check(g.
|
|
174
|
+
t.check(DIAL_STEPS.gentle[0].availablePercent > DIAL_STEPS.normal[0].availablePercent &&
|
|
175
|
+
DIAL_STEPS.gentle[0].commitPercent < DIAL_STEPS.normal[0].commitPercent, 'every step starts earlier');
|
|
176
|
+
const g = decide(INITIAL_STATE, sample(50, 50, procs), 0, 'gentle');
|
|
177
|
+
t.check(g.state.step === 0 &&
|
|
149
178
|
g.actions.length === 3 &&
|
|
150
|
-
g.actions.every((a) => a.kind === 'priority' && a.to === 'below' && a.pid !== 3), 'compilers
|
|
151
|
-
t.check(decide(INITIAL_STATE, sample(
|
|
179
|
+
g.actions.every((a) => a.kind === 'priority' && a.to === 'below' && a.pid !== 3), 'compilers rest below normal even with plenty of memory (the agent does not)');
|
|
180
|
+
t.check(decide(INITIAL_STATE, sample(19, 50, procs), 0, 'gentle').state.step === 1, '19 % free is step 1');
|
|
152
181
|
t.section('the compiler cap (vGPU on)');
|
|
153
182
|
t.check(maxCompilers(16, 'gentle') === 4 && maxCompilers(4, 'gentle') === 2 && maxCompilers(16, 'normal') === null, 'at most max(2, cores / 4) with vGPU, none otherwise');
|
|
154
183
|
const many = [
|
|
@@ -159,17 +188,24 @@ export const heavyLoadSuite = {
|
|
|
159
188
|
proc(3, 'claude.exe', 500),
|
|
160
189
|
proc(14, 'node.exe', 400),
|
|
161
190
|
];
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
t.check(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
t.check(
|
|
191
|
+
// The cap is a memory measure: with memory to spare no compiler waits (a waiting rustc stalls cargo's whole build).
|
|
192
|
+
const free = decide(INITIAL_STATE, sample(60, 40, many), 0, 'gentle', 2);
|
|
193
|
+
t.check(of(free, 'hold').length === 0, 'with memory to spare, nothing waits even beyond the cap');
|
|
194
|
+
const capped = decide(INITIAL_STATE, sample(14, 40, many), 0, 'gentle', 2);
|
|
195
|
+
const holds = of(capped, 'hold').map((a) => ('pid' in a ? a.pid : 0));
|
|
196
|
+
t.check(capped.state.step === 2 && holds.length === 2, 'under memory pressure (step 2), compilers beyond the cap wait their turn', holds.join(','));
|
|
197
|
+
t.check(!holds.includes(3) && !holds.includes(14), 'agents (claude, and codex or gemini as node) are never held');
|
|
198
|
+
t.check(of(decide(INITIAL_STATE, sample(60, 40, many), 0, 'gentle', null), 'hold').length === 0, 'no cap, no pressure: nothing waits');
|
|
199
|
+
t.check(of(decide(INITIAL_STATE, sample(60, 40, many.slice(0, 2)), 0, 'gentle', 2), 'hold').length === 0, 'under the cap nothing waits');
|
|
168
200
|
t.section('the governor over a port (fake Windows)');
|
|
169
201
|
const calls = [];
|
|
170
202
|
const port = {
|
|
171
203
|
setPriority: (pid, to) => calls.push('prio ' + pid + ' ' + to),
|
|
172
|
-
|
|
204
|
+
hold: (pid, ms) => calls.push('hold ' + pid + ' ' + ms),
|
|
205
|
+
setMemoryPriority: (pid, low) => calls.push('mem ' + pid + ' ' + (low ? 'low' : 'normal')),
|
|
206
|
+
throttle: (pid) => calls.push('throttle ' + pid),
|
|
207
|
+
setCpuRate: (percent) => calls.push('cpu ' + percent),
|
|
208
|
+
trim: (pid) => calls.push('trim ' + pid),
|
|
173
209
|
};
|
|
174
210
|
const logs = [];
|
|
175
211
|
const statuses = [];
|
|
@@ -180,15 +216,29 @@ export const heavyLoadSuite = {
|
|
|
180
216
|
now: () => clock,
|
|
181
217
|
logLine: (l) => logs.push(l),
|
|
182
218
|
saveStatus: (s) => statuses.push(s),
|
|
219
|
+
warn: (line) => logs.push(line),
|
|
183
220
|
});
|
|
184
|
-
for (let i = 0; i <
|
|
221
|
+
for (let i = 0; i < 4; i++) {
|
|
185
222
|
clock = i * 2000;
|
|
186
|
-
core.onSample(sample(
|
|
223
|
+
core.onSample(sample(5, 60, procs));
|
|
187
224
|
}
|
|
188
|
-
t.check(calls.includes('prio 1
|
|
189
|
-
|
|
190
|
-
|
|
225
|
+
t.check(calls.includes('prio 1 idle') &&
|
|
226
|
+
calls.includes('mem 1 low') &&
|
|
227
|
+
calls.includes('cpu 35') &&
|
|
228
|
+
calls.some((c) => c.startsWith('hold ')) &&
|
|
229
|
+
calls.some((c) => c.startsWith('trim ')) &&
|
|
230
|
+
!calls.some((c) => / 3( |$)/.test(c)), 'priority, memory priority, CPU cap, turns and trimming go through the port; the agent untouched', calls.join('; '));
|
|
231
|
+
t.check(logs.some((l) => l.includes('step 3')) && logs.some((l) => l.includes('waits its turn')), 'what it did goes to the memory log');
|
|
232
|
+
const lastStatus = statuses[statuses.length - 1];
|
|
233
|
+
t.check(statuses.length > 0 && PressureStatusSchema.safeParse(lastStatus).success, 'its status file matches the schema the host reads', JSON.stringify(lastStatus));
|
|
191
234
|
core.hostPressure(60, 'test');
|
|
235
|
+
t.check(core.current.hostStep === 2, 'the PC being low asks for step 2');
|
|
236
|
+
core.hostPressure(60, 'test', 'severe');
|
|
237
|
+
t.check(core.current.hostStep === 4, 'the PC nearly out of memory asks for step 4 at once');
|
|
238
|
+
core.hostPressure(60, 'test');
|
|
239
|
+
t.check(core.current.hostStep === 4, 'a later "low" does not lower a severe request while it lasts');
|
|
240
|
+
t.check(decide({ ...INITIAL_STATE, hostUntil: clock + 60000, hostStep: 4 }, sample(60, 40, procs), clock, 'normal').state
|
|
241
|
+
.step === 4, 'with plenty of memory in the sandbox, a severe PC still turns the dial to 4');
|
|
192
242
|
t.check(core.current.hostUntil === clock + 60000, 'a host request is remembered for its seconds');
|
|
193
243
|
t.section("the PC's watchdog");
|
|
194
244
|
const input = (memory, nowMs, cpu = 10, profile = 'normal') => ({
|
|
@@ -200,6 +250,12 @@ export const heavyLoadSuite = {
|
|
|
200
250
|
profile,
|
|
201
251
|
});
|
|
202
252
|
t.check(watchdogStep(WATCHDOG_START, input(pc(), 0)).state.low === false, 'plenty of memory: quiet');
|
|
253
|
+
t.check(severeHost(pc({ availableMb: 1200 })) &&
|
|
254
|
+
severeHost(pc({ commitAvailableMb: 1500 })) &&
|
|
255
|
+
!severeHost(pc({ availableMb: 3000 })), 'nearly out of memory: under 1.5 GB of RAM free, or commit within max(2 GB, 4 %) of its limit');
|
|
256
|
+
const lowState = watchdogStep(WATCHDOG_START, input(pc({ availableMb: 3000 }), 100000)).state;
|
|
257
|
+
const severeNow = watchdogStep(lowState, input(pc({ availableMb: 1200 }), 105000));
|
|
258
|
+
t.check(severeNow.severe && severeNow.send, 'getting severe is sent at once (not after the usual 30 seconds)');
|
|
203
259
|
t.check(lowReason(pc({ availableMb: 3000 }), 8192, HOST_THRESHOLDS.normal, 1) !== '', 'under 4 GB of RAM: low');
|
|
204
260
|
t.check(lowReason(pc({ availableMb: 5000 }), 8192, HOST_THRESHOLDS.normal, 1) === '', '5 GB free on a 32 GB PC is fine (limit max(4 GB, 12 % = 3.9 GB))');
|
|
205
261
|
t.check(lowReason(pc({ totalMb: 65536, availableMb: 7000 }), 8192, HOST_THRESHOLDS.normal, 1) !== '', '12 % of 64 GB = 7.7 GB: 7 GB is low');
|
|
@@ -340,13 +396,17 @@ export const heavyLoadSuite = {
|
|
|
340
396
|
const firstLine = (served.stdout ?? '').split(/\r?\n/)[0] ?? '';
|
|
341
397
|
let sampleOk = false;
|
|
342
398
|
try {
|
|
399
|
+
// In a sandbox started by 1.10 or later the real agents job exists, so the list may hold its processes.
|
|
343
400
|
const parsedSample = JSON.parse(firstLine);
|
|
344
|
-
sampleOk =
|
|
401
|
+
sampleOk =
|
|
402
|
+
Array.isArray(parsedSample.procs) &&
|
|
403
|
+
parsedSample.procs.every((p) => typeof p.pid === 'number' && typeof p.name === 'string') &&
|
|
404
|
+
parsedSample.ramTotalMb > 0;
|
|
345
405
|
}
|
|
346
406
|
catch {
|
|
347
407
|
// Not JSON: the check below fails.
|
|
348
408
|
}
|
|
349
|
-
t.check(sampleOk && served.status === 0, 'memgov serve prints a sample
|
|
409
|
+
t.check(sampleOk && served.status === 0, 'memgov serve prints a well-formed sample and ends when its input closes', firstLine);
|
|
350
410
|
for (const script of ['memory-status.ps1', 'stop-events.ps1']) {
|
|
351
411
|
const text = fs.readFileSync(path.join(t.packageRoot, 'native', 'scripts', script), 'utf8');
|
|
352
412
|
t.check(text.startsWith('#Requires -Version 5.1'), script + ' says its PowerShell version');
|
package/dist/selftest/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { liveTestsAvailable } from './support/live.js';
|
|
|
13
13
|
import { accountsSuite } from './accounts.test.js';
|
|
14
14
|
import { credentialsSuite } from './credentials.test.js';
|
|
15
15
|
import { vpnSuite } from './vpn.test.js';
|
|
16
|
+
import { githubSuite } from './github.test.js';
|
|
16
17
|
import { agentCommandsSuite } from './agent-commands.test.js';
|
|
17
18
|
import { channelSuite } from './channel.test.js';
|
|
18
19
|
import { heavyLoadSuite } from './heavy-load.test.js';
|
|
@@ -24,6 +25,7 @@ import { migrateSuite } from './migrate.test.js';
|
|
|
24
25
|
import { storageSuite } from './storage.test.js';
|
|
25
26
|
import { updateSuite } from './update.test.js';
|
|
26
27
|
import { installSuite } from './install.test.js';
|
|
28
|
+
import { powershellVariablesSuite } from './powershell-variables.test.js';
|
|
27
29
|
import { sharedUseSuite } from './shared-use.test.js';
|
|
28
30
|
import { updateServiceSuite } from './update-service.test.js';
|
|
29
31
|
import { sharingSuite } from './sharing.test.js';
|
|
@@ -74,6 +76,7 @@ export const SUITES = [
|
|
|
74
76
|
updateSuite,
|
|
75
77
|
updateServiceSuite,
|
|
76
78
|
installSuite,
|
|
79
|
+
powershellVariablesSuite,
|
|
77
80
|
sharingSuite,
|
|
78
81
|
sharedUseSuite,
|
|
79
82
|
workspaceSuite,
|
|
@@ -92,6 +95,7 @@ export const SUITES = [
|
|
|
92
95
|
accountsSuite,
|
|
93
96
|
credentialsSuite,
|
|
94
97
|
vpnSuite,
|
|
98
|
+
githubSuite,
|
|
95
99
|
workspaceViewSuite,
|
|
96
100
|
auditSuite,
|
|
97
101
|
// an untrusted sandbox: what the host refuses to do with what it finds
|
|
@@ -21,6 +21,8 @@ const PURE_GUEST = [
|
|
|
21
21
|
'guest/setup/path-plan.js',
|
|
22
22
|
'guest/toolchains/catalogue.js',
|
|
23
23
|
'guest/toolchains/tools/vscode-profile.js',
|
|
24
|
+
'guest/governor/decide.js',
|
|
25
|
+
'guest/governor/core.js',
|
|
24
26
|
];
|
|
25
27
|
const SIDE_EFFECTS = ['guest/runtime/session.js', 'guest/runtime/log.js'];
|
|
26
28
|
const readModules = (dist) => {
|
|
@@ -110,6 +112,12 @@ export const layoutSuite = {
|
|
|
110
112
|
.filter((d) => area(d) === 'guest')
|
|
111
113
|
.map((d) => f + ' -> ' + d));
|
|
112
114
|
t.check(!intoGuest.length, 'host, cli, core, sync and shared import no guest file', list(intoGuest));
|
|
115
|
+
// The self-test runs outside a sandbox too (GitHub Actions): no test may load the guest runtime, which reads
|
|
116
|
+
// C:\AgentLaunch\session.json and creates the log folder on import.
|
|
117
|
+
const testsIntoRuntime = files
|
|
118
|
+
.filter((f) => area(f) === 'selftest')
|
|
119
|
+
.flatMap((f) => [...closure(modules, f)].filter((d) => SIDE_EFFECTS.includes(d)).map((d) => f + ' -> ' + d));
|
|
120
|
+
t.check(!testsIntoRuntime.length, 'no test loads the guest runtime (session.json, log folder), so the self-test runs outside a sandbox', list(testsIntoRuntime));
|
|
113
121
|
t.section('pure guest files');
|
|
114
122
|
for (const pure of PURE_GUEST) {
|
|
115
123
|
t.check(modules.has(pure), pure + ' exists');
|
|
@@ -10,6 +10,7 @@ import path from 'node:path';
|
|
|
10
10
|
import { spawn, spawnSync } from 'node:child_process';
|
|
11
11
|
import { pathToFileURL } from 'node:url';
|
|
12
12
|
import { encodeFrame, FrameType } from '../shared/pty/index.js';
|
|
13
|
+
import { SYSTEM } from '../shared/system.js';
|
|
13
14
|
import { CSC, openViewer, tail, WAIT } from './support/live.js';
|
|
14
15
|
/**
|
|
15
16
|
* The stand-in agent: VT input and SGR mouse tracking on, echoes what it reads ("got <1b>[<0;10;5M"). L prints 500
|
|
@@ -89,6 +90,79 @@ export const liveTerminalSuite = {
|
|
|
89
90
|
t.check(!errors, 'ptyhost and the stand-in agent compile', errors);
|
|
90
91
|
if (errors)
|
|
91
92
|
return;
|
|
93
|
+
t.section("the agents' job: a last-resort backstop, set once");
|
|
94
|
+
{
|
|
95
|
+
// A job of the test's own (PTYHOST_JOB_NAME), never the agents' real one.
|
|
96
|
+
const jobName = 'Local\\AgentSandboxAgentsJobTest' + process.pid + '-' + Date.now();
|
|
97
|
+
const ping = path.join(process.env.SystemRoot ?? 'C:\\Windows', 'System32', 'PING.EXE');
|
|
98
|
+
const holder = '"' + SYSTEM.cmd() + '" /c "' + ping + '" -n 6 127.0.0.1 >nul';
|
|
99
|
+
const startHost = async (backstop, log) => spawn(ptyhost, [String(await freePort()), 'tok', '80', '24', t.at(log), holder], {
|
|
100
|
+
env: { ...process.env, PTYHOST_BIND: 'loopback', PTYHOST_BACKSTOP_MB: backstop, PTYHOST_JOB_NAME: jobName },
|
|
101
|
+
stdio: 'ignore',
|
|
102
|
+
windowsHide: true,
|
|
103
|
+
});
|
|
104
|
+
const read = (log) => (fs.existsSync(t.at(log)) ? fs.readFileSync(t.at(log), 'utf8') : '');
|
|
105
|
+
const first = await startHost('auto', 'job-first.log');
|
|
106
|
+
await t.waitFor(() => read('job-first.log').includes('agent job:'), WAIT.screen);
|
|
107
|
+
const second = await startHost('500000', 'job-second.log');
|
|
108
|
+
await t.waitFor(() => read('job-second.log').includes('agent job:'), WAIT.screen);
|
|
109
|
+
// The governor's hands on the same test job (MEMGOV_JOB_NAME): it sees the job's processes, and the dial's
|
|
110
|
+
// commands (memory priority, the throttle job and its CPU cap, trimming) leave them running.
|
|
111
|
+
const memgovExe = t.at('memgov.exe');
|
|
112
|
+
const memgovErrors = compile(path.join(t.packageRoot, 'sandbox', 'csharp', 'MemGov.cs'), memgovExe);
|
|
113
|
+
t.check(!memgovErrors, 'memgov compiles', memgovErrors);
|
|
114
|
+
if (!memgovErrors) {
|
|
115
|
+
const memgov = spawn(memgovExe, ['serve', '--interval', '1'], {
|
|
116
|
+
env: { ...process.env, MEMGOV_JOB_NAME: jobName },
|
|
117
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
118
|
+
windowsHide: true,
|
|
119
|
+
});
|
|
120
|
+
let lines = '';
|
|
121
|
+
memgov.stdout.on('data', (chunk) => (lines += chunk.toString('utf8')));
|
|
122
|
+
const procsSeen = () => {
|
|
123
|
+
const last = lines.trim().split(/\r?\n/).pop() ?? '';
|
|
124
|
+
try {
|
|
125
|
+
return JSON.parse(last).procs;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
await t.waitFor(() => procsSeen().length > 0, WAIT.screen);
|
|
132
|
+
const target = procsSeen().find((p) => /ping|cmd/i.test(p.name));
|
|
133
|
+
t.check(target !== undefined, "memgov sees the processes in the agents' job", lines.slice(-300));
|
|
134
|
+
if (target) {
|
|
135
|
+
for (const command of [
|
|
136
|
+
'memprio ' + target.pid + ' low',
|
|
137
|
+
'throttle ' + target.pid,
|
|
138
|
+
'cpurate 20',
|
|
139
|
+
'trim ' + target.pid,
|
|
140
|
+
])
|
|
141
|
+
memgov.stdin.write(command + '\n');
|
|
142
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
143
|
+
memgov.stdin.write('cpurate 100\n');
|
|
144
|
+
await new Promise((r) => setTimeout(r, 1200));
|
|
145
|
+
t.check(memgov.exitCode === null && procsSeen().some((p) => p.pid === target.pid), 'memory priority, the throttle job, a CPU cap and trimming leave the process running (and memgov too)');
|
|
146
|
+
}
|
|
147
|
+
memgov.stdin.end();
|
|
148
|
+
await t.waitFor(() => memgov.exitCode !== null, 5000);
|
|
149
|
+
t.check(memgov.exitCode === 0, 'memgov ends cleanly when the daemon goes away (and lifts the cap)');
|
|
150
|
+
}
|
|
151
|
+
for (const c of [first, second]) {
|
|
152
|
+
try {
|
|
153
|
+
if (c.exitCode === null)
|
|
154
|
+
c.kill();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
/* it ended between the check and the kill: nothing left to stop */
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const set = /backstop at (\d+) MB committed \(the sandbox's commit limit is (\d+) MB\)/.exec(read('job-first.log'));
|
|
161
|
+
const commit = Number(set?.[2] ?? 0);
|
|
162
|
+
t.check(set !== null &&
|
|
163
|
+
Number(set[1]) === Math.max(Math.floor(commit / 2), commit - Math.max(1536, Math.floor((commit * 3) / 100))), 'the ptyhost that creates the job sets the backstop just below the commit limit (auto: 3 %, at least 1.5 GB)', read('job-first.log'));
|
|
164
|
+
t.check(read('job-second.log').includes('joined the existing one'), 'a ptyhost that joins the job never changes its backstop', read('job-second.log'));
|
|
165
|
+
}
|
|
92
166
|
const client = t.at('client.mjs');
|
|
93
167
|
fs.writeFileSync(client, [
|
|
94
168
|
'import { connect, runTerminalClient } from ' +
|