windows-development-sandbox 1.27.3 → 1.28.0
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/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-RU7XRN62.js → chunk-CB44HTTN.js} +196 -75
- package/dist/bin/{chunk-FA5VWLP4.js → chunk-UZ5S3EMB.js} +1 -1
- package/dist/bin/{chunk-4M5SZZ5P.js → chunk-ZMZI3625.js} +1 -1
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/core/schema/sandbox.js +1 -1
- package/dist/guest/daemon/heartbeat.js +1 -0
- package/dist/guest/governor/core.d.ts +53 -1
- package/dist/guest/governor/core.js +95 -1
- package/dist/guest/governor/decide.d.ts +4 -0
- package/dist/guest/governor/decide.js +2 -0
- package/dist/guest/governor/governor.js +23 -9
- package/dist/guest/toolchains/native/unreal.js +22 -3
- package/dist/guest/toolchains/runtimes.js +7 -6
- package/dist/host/life/crash-report.d.ts +4 -0
- package/dist/host/life/crash-report.js +30 -1
- package/dist/host/life/last-end.js +1 -0
- package/dist/host/tools/windows-terminal.d.ts +4 -1
- package/dist/host/tools/windows-terminal.js +25 -9
- package/dist/runtime/agent.js +5 -1
- package/dist/runtime/daemon.js +183 -70
- package/dist/runtime/db.js +5 -1
- package/dist/runtime/main.js +242 -56
- package/dist/runtime/netproxy.js +5 -1
- package/dist/runtime/tool.js +5 -1
- package/dist/runtime/view.js +125 -27
- package/dist/selftest/agent-paths.test.js +3 -1
- package/dist/selftest/channel.test.js +33 -0
- package/dist/selftest/heavy-load.test.js +116 -4
- package/dist/selftest/live-terminal.test.js +103 -0
- package/dist/selftest/personalization.test.js +2 -1
- package/dist/selftest/support/engine-golden.js +2 -0
- package/dist/shared/channel/schema.d.ts +2 -0
- package/dist/shared/channel/schema.js +4 -0
- package/dist/shared/memory/index.d.ts +1 -0
- package/dist/shared/memory/index.js +1 -0
- package/dist/shared/memory/policy.d.ts +12 -0
- package/dist/shared/memory/policy.js +4 -0
- package/dist/shared/memory/unreal-build.d.ts +2 -0
- package/dist/shared/memory/unreal-build.js +21 -0
- package/dist/shared/pty/clipboard-watch.d.ts +4 -0
- package/dist/shared/pty/clipboard-watch.js +40 -0
- package/dist/shared/pty/ctrl-c.d.ts +13 -7
- package/dist/shared/pty/ctrl-c.js +35 -19
- package/dist/shared/pty/index.d.ts +1 -0
- package/dist/shared/pty/index.js +1 -0
- package/dist/shared/pty/terminal.d.ts +1 -1
- package/dist/shared/pty/terminal.js +16 -13
- package/dist/shared/web/ctrl-c.d.ts +26 -0
- package/dist/shared/web/ctrl-c.js +64 -0
- package/dist/shared/web/index.d.ts +1 -0
- package/dist/shared/web/index.js +1 -0
- package/dist/web/index.html +1 -1
- package/dist/web/{main-NKM7ECSB.js → main-7NY4X6YU.js} +67 -67
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/package.json +1 -1
- package/sandbox/csharp/ClipboardWatch.cs +59 -0
- package/sandbox/csharp/MemGov.cs +752 -7
- package/sandbox/scripts/watch-clipboard.ps1 +8 -0
- package/schemas/config.schema.json +1 -1
package/dist/runtime/daemon.js
CHANGED
|
@@ -25521,7 +25521,7 @@ var SandboxSchema = external_exports.strictObject({
|
|
|
25521
25521
|
'The last resort that keeps the sandbox up, in MB below its commit limit (RAM plus paging file): builds are slowed down long before (sandbox.pressureResponse); only if everything the agents start together would take the sandbox to the very edge of its memory, where Windows inside it would start failing, is a build refused memory instead of Windows. "auto" = the larger of 1536 MB and 3 % of the commit limit; "none" = no backstop. Yours only: a project file cannot change it.'
|
|
25522
25522
|
),
|
|
25523
25523
|
pressureResponse: external_exports.boolean().describe(
|
|
25524
|
-
"When the sandbox (or this PC) runs low on memory, slow builds down in steps, like a PC that gets slower instead of failing: build programs get lower CPU and memory priority, then less CPU, then compilers take turns (the waiting ones briefly suspended and trimmed to the paging file). Nothing is stopped or killed, and the agents themselves are never touched. Yours only: a project file cannot change it."
|
|
25524
|
+
"When the sandbox (or this PC) runs low on memory, slow builds down in steps, like a PC that gets slower instead of failing: build programs get lower CPU and memory priority, then less CPU, then compilers take turns (the waiting ones briefly suspended and trimmed to the paging file). Nothing is stopped or killed, and the agents themselves are never touched. A memory gate also holds new compilers and linkers for a moment when the memory of the build programs grows faster than 4 GB in 3 seconds (3 GB with vGPU), and lets them go one at a time. Yours only: a project file cannot change it."
|
|
25525
25525
|
),
|
|
25526
25526
|
vGpu: external_exports.boolean().describe(
|
|
25527
25527
|
"Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface. The sandbox then uses this PC's graphics card, and with some graphics drivers heavy use can freeze the whole PC: turn it on only when a program in the sandbox needs the GPU (the mesa toolchain gives software OpenGL without it). Browsers in the sandbox never use it (they draw in software)."
|
|
@@ -27922,6 +27922,8 @@ var PressureStatusSchema = external_exports.object({
|
|
|
27922
27922
|
lowered: external_exports.number().int().min(0).max(1024),
|
|
27923
27923
|
/** Compilers waiting their turn right now (name, process id, seconds until they may go on). */
|
|
27924
27924
|
paused: external_exports.array(external_exports.object({ name: Text(64), pid: external_exports.number().int(), seconds: external_exports.number().int().min(0).max(60) })).max(8),
|
|
27925
|
+
/** Build programs the memory gate holds right now (let go one at a time). */
|
|
27926
|
+
held: external_exports.number().int().min(0).max(1024).optional(),
|
|
27925
27927
|
/** The CPU share the compilers get together (percent; 100 = no cap). */
|
|
27926
27928
|
cpuPercent: external_exports.number().int().min(0).max(100).optional(),
|
|
27927
27929
|
/** The PC itself asked for slowing down (its memory or CPU is low). */
|
|
@@ -27942,6 +27944,8 @@ var HeartbeatSchema = external_exports.object({
|
|
|
27942
27944
|
topProcesses: external_exports.array(external_exports.object({ name: Text(64), privateMb: external_exports.number().int().min(0).max(1e7) })).max(5),
|
|
27943
27945
|
/** The disk queue this PC last reported while asking the sandbox to slow down. */
|
|
27944
27946
|
diskQueueReported: external_exports.number().min(0).max(1e5).optional(),
|
|
27947
|
+
/** Build programs the memory gate holds right now (let go one at a time). */
|
|
27948
|
+
held: external_exports.number().int().min(0).max(1024).optional(),
|
|
27945
27949
|
/** "ending": the sandbox is shutting down in order (idle shutdown, sandbox stop, Windows shutting down). */
|
|
27946
27950
|
phase: external_exports.enum(["ready", "working", "ending"])
|
|
27947
27951
|
});
|
|
@@ -32109,11 +32113,10 @@ async function setupBun(env) {
|
|
|
32109
32113
|
tool("bun", "bin"),
|
|
32110
32114
|
{ size: "35 MB" }
|
|
32111
32115
|
);
|
|
32112
|
-
|
|
32113
|
-
|
|
32114
|
-
|
|
32115
|
-
|
|
32116
|
-
});
|
|
32116
|
+
const cache = path48.join(localDir, "bun-cache");
|
|
32117
|
+
const temp = path48.join(localDir, "bun-tmp");
|
|
32118
|
+
if (!dryRun) [cache, temp].forEach((dir) => mkdirp(dir));
|
|
32119
|
+
Object.assign(env.vars, { BUN_INSTALL: tool("bun"), BUN_INSTALL_CACHE_DIR: cache, BUN_TMPDIR: temp });
|
|
32117
32120
|
}
|
|
32118
32121
|
async function setupDeno(env) {
|
|
32119
32122
|
await setupSingleExe(
|
|
@@ -34954,6 +34957,82 @@ import fs58 from "node:fs";
|
|
|
34954
34957
|
import os10 from "node:os";
|
|
34955
34958
|
import path83 from "node:path";
|
|
34956
34959
|
|
|
34960
|
+
// src/shared/memory/policy.ts
|
|
34961
|
+
var DIAL_STEPS = {
|
|
34962
|
+
normal: [
|
|
34963
|
+
{ availablePercent: 15, commitPercent: 80 },
|
|
34964
|
+
{ availablePercent: 10, commitPercent: 88 },
|
|
34965
|
+
{ availablePercent: 6, commitPercent: 94, secondsToLimit: 20 },
|
|
34966
|
+
{ availablePercent: 4, commitPercent: 97, secondsToLimit: 8 }
|
|
34967
|
+
],
|
|
34968
|
+
gentle: [
|
|
34969
|
+
{ availablePercent: 20, commitPercent: 75 },
|
|
34970
|
+
{ availablePercent: 15, commitPercent: 85 },
|
|
34971
|
+
{ availablePercent: 8, commitPercent: 92, secondsToLimit: 25 },
|
|
34972
|
+
{ availablePercent: 5, commitPercent: 96, secondsToLimit: 10 }
|
|
34973
|
+
]
|
|
34974
|
+
};
|
|
34975
|
+
var DIAL_EXIT_MARGIN = { availablePercent: 5, commitPercent: 4 };
|
|
34976
|
+
var DIAL_CALM_SAMPLES = 3;
|
|
34977
|
+
var DIAL_CPU_RATE = [100, 100, 60, 35, 15];
|
|
34978
|
+
function compilersAllowed(step, running) {
|
|
34979
|
+
if (step <= 1 || running <= 1) return running;
|
|
34980
|
+
if (step === 2) return Math.max(1, Math.ceil(running * 0.6));
|
|
34981
|
+
if (step === 3) return Math.max(1, Math.ceil(running / 3));
|
|
34982
|
+
return 1;
|
|
34983
|
+
}
|
|
34984
|
+
function buildJobs(cpus, memoryGb) {
|
|
34985
|
+
return Math.max(2, Math.min(cpus, Math.floor((memoryGb - 6) / 3)));
|
|
34986
|
+
}
|
|
34987
|
+
function linkSlotsFor(memoryGb) {
|
|
34988
|
+
return Math.max(2, Math.min(8, Math.floor((memoryGb - 6) / 3)));
|
|
34989
|
+
}
|
|
34990
|
+
function usableCpus(cpus, percent) {
|
|
34991
|
+
if (percent === null || percent >= 100) return cpus;
|
|
34992
|
+
return Math.max(2, Math.min(cpus, Math.floor(cpus * percent / 100)));
|
|
34993
|
+
}
|
|
34994
|
+
function cargoJobs(cpus, memoryGb, sessions2) {
|
|
34995
|
+
const byCpu = Math.max(2, Math.min(8, Math.floor(cpus / 4)));
|
|
34996
|
+
const byMemory = Math.max(1, Math.floor(memoryGb / 4));
|
|
34997
|
+
const jobs = Math.min(byCpu, byMemory);
|
|
34998
|
+
return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions2))));
|
|
34999
|
+
}
|
|
35000
|
+
var LOCAL_TARGET_MIN_BYTES = 25 * 1024 ** 3;
|
|
35001
|
+
function chooseTargetDir(targetDir, freeBytes2) {
|
|
35002
|
+
if (targetDir !== "auto") return { targetDir };
|
|
35003
|
+
if (freeBytes2 >= LOCAL_TARGET_MIN_BYTES) return { targetDir: "local" };
|
|
35004
|
+
return {
|
|
35005
|
+
targetDir: "separate",
|
|
35006
|
+
warning: "Rust builds write through the mapped workspace; this can overload your PC's disk (C: has less than 25 GB free for a local build folder)"
|
|
35007
|
+
};
|
|
35008
|
+
}
|
|
35009
|
+
function maxCompilers(cpus, profile) {
|
|
35010
|
+
return profile === "gentle" ? Math.min(4, Math.max(2, Math.floor(cpus / 4))) : null;
|
|
35011
|
+
}
|
|
35012
|
+
function cargoLinkerVar(host) {
|
|
35013
|
+
return "CARGO_TARGET_" + host.toUpperCase().replace(/[^A-Z0-9]/g, "_") + "_LINKER";
|
|
35014
|
+
}
|
|
35015
|
+
var BURST_GATE = {
|
|
35016
|
+
normal: { growthMb: 4096, windowMs: 3e3, releaseMs: 1500, maxHoldMs: 3e4 },
|
|
35017
|
+
gentle: { growthMb: 3072, windowMs: 3e3, releaseMs: 2e3, maxHoldMs: 3e4 }
|
|
35018
|
+
};
|
|
35019
|
+
|
|
35020
|
+
// src/shared/memory/unreal-build.ts
|
|
35021
|
+
var NAMESPACE = "https://www.unrealengine.com/BuildConfiguration";
|
|
35022
|
+
function ubtBuildConfiguration(jobs) {
|
|
35023
|
+
const max = Math.max(1, Math.floor(jobs));
|
|
35024
|
+
return [
|
|
35025
|
+
'<?xml version="1.0" encoding="utf-8"?>',
|
|
35026
|
+
"<!-- Written by the sandbox at boot: compiles at once from the build budget (run\\budget.json, buildJobs). -->",
|
|
35027
|
+
'<Configuration xmlns="' + NAMESPACE + '">',
|
|
35028
|
+
" <BuildConfiguration>",
|
|
35029
|
+
" <MaxParallelActions>" + max + "</MaxParallelActions>",
|
|
35030
|
+
" </BuildConfiguration>",
|
|
35031
|
+
"</Configuration>",
|
|
35032
|
+
""
|
|
35033
|
+
].join("\r\n");
|
|
35034
|
+
}
|
|
35035
|
+
|
|
34957
35036
|
// src/guest/toolchains/native/debuggers.ts
|
|
34958
35037
|
import path79 from "node:path";
|
|
34959
35038
|
var SDK_SETUP_URL = "https://go.microsoft.com/fwlink/?linkid=2311806";
|
|
@@ -35731,6 +35810,14 @@ async function checkVisualStudio() {
|
|
|
35731
35810
|
fs58.rmSync(dir, { recursive: true, force: true });
|
|
35732
35811
|
}
|
|
35733
35812
|
}
|
|
35813
|
+
function capUnrealBuilds() {
|
|
35814
|
+
const cpus = usableCpus(os10.cpus().length, session.cpuLimitPercent ?? null);
|
|
35815
|
+
const jobs = buildJobs(cpus, os10.totalmem() / 1024 ** 3);
|
|
35816
|
+
const appData = process.env.APPDATA ?? "C:\\Users\\WDAGUtilityAccount\\AppData\\Roaming";
|
|
35817
|
+
const dir = mkdirp(path83.join(appData, "Unreal Engine", "UnrealBuildTool"));
|
|
35818
|
+
fs58.writeFileSync(path83.join(dir, "BuildConfiguration.xml"), ubtBuildConfiguration(jobs), "utf8");
|
|
35819
|
+
return jobs;
|
|
35820
|
+
}
|
|
35734
35821
|
async function part(what, work, fallback) {
|
|
35735
35822
|
try {
|
|
35736
35823
|
return await work();
|
|
@@ -35749,6 +35836,8 @@ async function setupUnreal(env, config2, _ctx) {
|
|
|
35749
35836
|
return;
|
|
35750
35837
|
}
|
|
35751
35838
|
resetUnrealStatus();
|
|
35839
|
+
const jobs = await part("capping parallel compiles", async () => capUnrealBuilds(), 0);
|
|
35840
|
+
if (jobs) log("Unreal: UnrealBuildTool runs at most " + jobs + " compiles at once (the build budget)");
|
|
35752
35841
|
await part("the DirectX End-User Runtime", installDirectX, void 0);
|
|
35753
35842
|
const launcher = await part("the Epic Games Launcher", ensureLauncher, null);
|
|
35754
35843
|
const place = placeEngines(config2.persistEngines);
|
|
@@ -35784,7 +35873,7 @@ async function setupUnreal(env, config2, _ctx) {
|
|
|
35784
35873
|
debugger: debuggers ? path83.join(debuggers, "cdb.exe") : null
|
|
35785
35874
|
}));
|
|
35786
35875
|
env.summary.push(
|
|
35787
|
-
"unreal tools: " + (vs ? "Visual Studio " + vs.version + (check2.ok ? " (UnrealBuildTool finds it)" : " (UnrealBuildTool would NOT find it)") : "no Visual Studio") + ", DirectX End-User Runtime" + (launcher ? ", Epic Games Launcher" : "") + (debuggers ? ", cdb/windbg" : "")
|
|
35876
|
+
"unreal tools: " + (vs ? "Visual Studio " + vs.version + (check2.ok ? " (UnrealBuildTool finds it)" : " (UnrealBuildTool would NOT find it)") : "no Visual Studio") + (jobs ? ", at most " + jobs + " compiles at once" : "") + ", DirectX End-User Runtime" + (launcher ? ", Epic Games Launcher" : "") + (debuggers ? ", cdb/windbg" : "")
|
|
35788
35877
|
);
|
|
35789
35878
|
}
|
|
35790
35879
|
|
|
@@ -37631,62 +37720,6 @@ import fs72 from "node:fs";
|
|
|
37631
37720
|
import os12 from "node:os";
|
|
37632
37721
|
import path104 from "node:path";
|
|
37633
37722
|
|
|
37634
|
-
// src/shared/memory/policy.ts
|
|
37635
|
-
var DIAL_STEPS = {
|
|
37636
|
-
normal: [
|
|
37637
|
-
{ availablePercent: 15, commitPercent: 80 },
|
|
37638
|
-
{ availablePercent: 10, commitPercent: 88 },
|
|
37639
|
-
{ availablePercent: 6, commitPercent: 94, secondsToLimit: 20 },
|
|
37640
|
-
{ availablePercent: 4, commitPercent: 97, secondsToLimit: 8 }
|
|
37641
|
-
],
|
|
37642
|
-
gentle: [
|
|
37643
|
-
{ availablePercent: 20, commitPercent: 75 },
|
|
37644
|
-
{ availablePercent: 15, commitPercent: 85 },
|
|
37645
|
-
{ availablePercent: 8, commitPercent: 92, secondsToLimit: 25 },
|
|
37646
|
-
{ availablePercent: 5, commitPercent: 96, secondsToLimit: 10 }
|
|
37647
|
-
]
|
|
37648
|
-
};
|
|
37649
|
-
var DIAL_EXIT_MARGIN = { availablePercent: 5, commitPercent: 4 };
|
|
37650
|
-
var DIAL_CALM_SAMPLES = 3;
|
|
37651
|
-
var DIAL_CPU_RATE = [100, 100, 60, 35, 15];
|
|
37652
|
-
function compilersAllowed(step, running) {
|
|
37653
|
-
if (step <= 1 || running <= 1) return running;
|
|
37654
|
-
if (step === 2) return Math.max(1, Math.ceil(running * 0.6));
|
|
37655
|
-
if (step === 3) return Math.max(1, Math.ceil(running / 3));
|
|
37656
|
-
return 1;
|
|
37657
|
-
}
|
|
37658
|
-
function buildJobs(cpus, memoryGb) {
|
|
37659
|
-
return Math.max(2, Math.min(cpus, Math.floor((memoryGb - 6) / 3)));
|
|
37660
|
-
}
|
|
37661
|
-
function linkSlotsFor(memoryGb) {
|
|
37662
|
-
return Math.max(2, Math.min(8, Math.floor((memoryGb - 6) / 3)));
|
|
37663
|
-
}
|
|
37664
|
-
function usableCpus(cpus, percent) {
|
|
37665
|
-
if (percent === null || percent >= 100) return cpus;
|
|
37666
|
-
return Math.max(2, Math.min(cpus, Math.floor(cpus * percent / 100)));
|
|
37667
|
-
}
|
|
37668
|
-
function cargoJobs(cpus, memoryGb, sessions2) {
|
|
37669
|
-
const byCpu = Math.max(2, Math.min(8, Math.floor(cpus / 4)));
|
|
37670
|
-
const byMemory = Math.max(1, Math.floor(memoryGb / 4));
|
|
37671
|
-
const jobs = Math.min(byCpu, byMemory);
|
|
37672
|
-
return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions2))));
|
|
37673
|
-
}
|
|
37674
|
-
var LOCAL_TARGET_MIN_BYTES = 25 * 1024 ** 3;
|
|
37675
|
-
function chooseTargetDir(targetDir, freeBytes2) {
|
|
37676
|
-
if (targetDir !== "auto") return { targetDir };
|
|
37677
|
-
if (freeBytes2 >= LOCAL_TARGET_MIN_BYTES) return { targetDir: "local" };
|
|
37678
|
-
return {
|
|
37679
|
-
targetDir: "separate",
|
|
37680
|
-
warning: "Rust builds write through the mapped workspace; this can overload your PC's disk (C: has less than 25 GB free for a local build folder)"
|
|
37681
|
-
};
|
|
37682
|
-
}
|
|
37683
|
-
function maxCompilers(cpus, profile) {
|
|
37684
|
-
return profile === "gentle" ? Math.min(4, Math.max(2, Math.floor(cpus / 4))) : null;
|
|
37685
|
-
}
|
|
37686
|
-
function cargoLinkerVar(host) {
|
|
37687
|
-
return "CARGO_TARGET_" + host.toUpperCase().replace(/[^A-Z0-9]/g, "_") + "_LINKER";
|
|
37688
|
-
}
|
|
37689
|
-
|
|
37690
37723
|
// src/guest/governor/decide.ts
|
|
37691
37724
|
var COMPILERS = /* @__PURE__ */ new Set([
|
|
37692
37725
|
"rustc",
|
|
@@ -37786,6 +37819,7 @@ function linkerSlots(totalMb, cpus) {
|
|
|
37786
37819
|
}
|
|
37787
37820
|
var isHeavyCompiler = (name) => !isNeverTouched(name) && HEAVY.has(key(name));
|
|
37788
37821
|
var canPause = (name) => !isNeverTouched(name) && COMPILERS.has(key(name));
|
|
37822
|
+
var GATE_NAMES = [...COMPILERS, "shadercompileworker"].filter((n) => !NEVER2.has(n)).sort();
|
|
37789
37823
|
var INITIAL_STATE = {
|
|
37790
37824
|
step: 0,
|
|
37791
37825
|
calm: 0,
|
|
@@ -38748,6 +38782,9 @@ async function sendControl(endpoint, type) {
|
|
|
38748
38782
|
// src/shared/pty/output-filter.ts
|
|
38749
38783
|
var MAX_CLIPBOARD_STRING = 1024 * 1024;
|
|
38750
38784
|
|
|
38785
|
+
// src/shared/web/protocol.ts
|
|
38786
|
+
var MAX_CLIENT_MESSAGE_BYTES = 256 * 1024;
|
|
38787
|
+
|
|
38751
38788
|
// src/guest/sessions/cmdline.ts
|
|
38752
38789
|
import path106 from "node:path";
|
|
38753
38790
|
var quoted = (arg) => '"' + arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
|
|
@@ -39240,6 +39277,63 @@ async function flushAccounts(final = false) {
|
|
|
39240
39277
|
import os15 from "node:os";
|
|
39241
39278
|
|
|
39242
39279
|
// src/guest/governor/core.ts
|
|
39280
|
+
function memgovArgs(profile) {
|
|
39281
|
+
const g = BURST_GATE[profile];
|
|
39282
|
+
return [
|
|
39283
|
+
"serve",
|
|
39284
|
+
"--interval",
|
|
39285
|
+
"2",
|
|
39286
|
+
"--gate",
|
|
39287
|
+
[g.growthMb, g.windowMs, g.releaseMs, g.maxHoldMs].join(":"),
|
|
39288
|
+
"--gate-names",
|
|
39289
|
+
GATE_NAMES.join(",")
|
|
39290
|
+
];
|
|
39291
|
+
}
|
|
39292
|
+
var GateBase = { event: external_exports.literal("gate"), at: external_exports.number() };
|
|
39293
|
+
var GateName = external_exports.string().max(128);
|
|
39294
|
+
var GateCount = external_exports.number().int().min(0);
|
|
39295
|
+
var GateEventSchema = external_exports.discriminatedUnion("kind", [
|
|
39296
|
+
external_exports.strictObject({
|
|
39297
|
+
...GateBase,
|
|
39298
|
+
kind: external_exports.literal("ready"),
|
|
39299
|
+
mode: external_exports.enum(["notify", "poll"]),
|
|
39300
|
+
growthMb: GateCount,
|
|
39301
|
+
windowMs: GateCount
|
|
39302
|
+
}),
|
|
39303
|
+
external_exports.strictObject({ ...GateBase, kind: external_exports.literal("off"), reason: external_exports.string().max(200) }),
|
|
39304
|
+
external_exports.strictObject({
|
|
39305
|
+
...GateBase,
|
|
39306
|
+
kind: external_exports.literal("trip"),
|
|
39307
|
+
grewMb: GateCount,
|
|
39308
|
+
ms: GateCount,
|
|
39309
|
+
jobMb: GateCount,
|
|
39310
|
+
held: external_exports.array(external_exports.strictObject({ pid: external_exports.number().int(), name: GateName })).max(64)
|
|
39311
|
+
}),
|
|
39312
|
+
external_exports.strictObject({ ...GateBase, kind: external_exports.literal("hold"), pid: external_exports.number().int(), name: GateName }),
|
|
39313
|
+
external_exports.strictObject({
|
|
39314
|
+
...GateBase,
|
|
39315
|
+
kind: external_exports.literal("release"),
|
|
39316
|
+
pid: external_exports.number().int(),
|
|
39317
|
+
name: GateName,
|
|
39318
|
+
heldMs: GateCount,
|
|
39319
|
+
forced: external_exports.boolean()
|
|
39320
|
+
})
|
|
39321
|
+
]);
|
|
39322
|
+
function gateLine(e) {
|
|
39323
|
+
const cut = (s) => s.slice(0, 64);
|
|
39324
|
+
switch (e.kind) {
|
|
39325
|
+
case "ready":
|
|
39326
|
+
return "gate: on (" + e.mode + "): new compilers wait when the agents' programs grow by more than " + e.growthMb + " MB within " + e.windowMs / 1e3 + " s";
|
|
39327
|
+
case "off":
|
|
39328
|
+
return "gate: off (" + e.reason + "): builds are only slowed down by the dial";
|
|
39329
|
+
case "trip":
|
|
39330
|
+
return "gate: the agents' programs grew " + e.grewMb + " MB in " + (e.ms / 1e3).toFixed(1) + " s (now " + e.jobMb + " MB); holding " + e.held.length + ": " + e.held.slice(0, 8).map((p) => cut(p.name) + " (" + p.pid + ")").join(", ") + (e.held.length > 8 ? " \u2026" : "");
|
|
39331
|
+
case "hold":
|
|
39332
|
+
return "gate: " + cut(e.name) + " (" + e.pid + ") waits at start while a build burst goes through in turn";
|
|
39333
|
+
case "release":
|
|
39334
|
+
return "gate: " + cut(e.name) + " (" + e.pid + ") goes on after " + (e.heldMs / 1e3).toFixed(1) + " s" + (e.forced ? " (the longest it may wait)" : "");
|
|
39335
|
+
}
|
|
39336
|
+
}
|
|
39243
39337
|
var STEP_TEXT = [
|
|
39244
39338
|
"builds back to normal",
|
|
39245
39339
|
"build programs at lower priority",
|
|
@@ -39289,6 +39383,7 @@ var GovernorCore = class {
|
|
|
39289
39383
|
commitPercent: d.commitPercent,
|
|
39290
39384
|
step: d.state.step,
|
|
39291
39385
|
hostStep: nowMs < d.state.hostUntil ? d.state.hostStep : 0,
|
|
39386
|
+
held: sample.gateHeld ?? 0,
|
|
39292
39387
|
diskQueue: null,
|
|
39293
39388
|
top: [...sample.procs].sort((a, b) => b.mb - a.mb).slice(0, 5).map((p) => ({ name: p.name.slice(0, 64), mb: Math.round(p.mb) }))
|
|
39294
39389
|
};
|
|
@@ -39310,6 +39405,7 @@ var GovernorCore = class {
|
|
|
39310
39405
|
commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
|
|
39311
39406
|
lowered: Object.keys(d.state.lowered).length,
|
|
39312
39407
|
paused: [...this.held].slice(0, 8).map(([pid, name]) => ({ name: name.slice(0, 64), pid, seconds: HOLD_MS / 1e3 })),
|
|
39408
|
+
held: sample.gateHeld ?? 0,
|
|
39313
39409
|
cpuPercent: d.state.cpuRate,
|
|
39314
39410
|
pcLow: nowMs < d.state.hostUntil,
|
|
39315
39411
|
lastAction: this.lastAction.slice(0, 300),
|
|
@@ -39322,6 +39418,10 @@ var GovernorCore = class {
|
|
|
39322
39418
|
this.deps.saveStatus(status);
|
|
39323
39419
|
}
|
|
39324
39420
|
}
|
|
39421
|
+
/** An event from the memory gate in memgov: goes to the memory log. */
|
|
39422
|
+
onGate(event) {
|
|
39423
|
+
this.note(gateLine(event));
|
|
39424
|
+
}
|
|
39325
39425
|
apply(action) {
|
|
39326
39426
|
const port = this.deps.port;
|
|
39327
39427
|
try {
|
|
@@ -39382,26 +39482,34 @@ var SampleSchema = external_exports.object({
|
|
|
39382
39482
|
mb: external_exports.number(),
|
|
39383
39483
|
prio: external_exports.enum(["idle", "below", "normal"]).catch("normal")
|
|
39384
39484
|
})
|
|
39385
|
-
).max(1024)
|
|
39485
|
+
).max(1024),
|
|
39486
|
+
gateHeld: external_exports.number().int().min(0).max(1024).optional().catch(void 0)
|
|
39386
39487
|
});
|
|
39387
39488
|
var MemGovProcess = class {
|
|
39388
|
-
constructor(onSample) {
|
|
39489
|
+
constructor(args, onSample, onGate) {
|
|
39490
|
+
this.args = args;
|
|
39389
39491
|
this.onSample = onSample;
|
|
39492
|
+
this.onGate = onGate;
|
|
39390
39493
|
}
|
|
39494
|
+
args;
|
|
39391
39495
|
onSample;
|
|
39496
|
+
onGate;
|
|
39392
39497
|
child = null;
|
|
39393
39498
|
start() {
|
|
39394
39499
|
try {
|
|
39395
|
-
const child = spawn12(ensureCompiled("memgov"), [
|
|
39500
|
+
const child = spawn12(ensureCompiled("memgov"), [...this.args], {
|
|
39396
39501
|
stdio: ["pipe", "pipe", "ignore"],
|
|
39397
39502
|
windowsHide: true
|
|
39398
39503
|
});
|
|
39399
39504
|
this.child = child;
|
|
39400
39505
|
createInterface({ input: child.stdout }).on("line", (line) => {
|
|
39401
39506
|
try {
|
|
39402
|
-
|
|
39507
|
+
const raw = JSON.parse(line);
|
|
39508
|
+
if (typeof raw === "object" && raw !== null && raw.event === "gate")
|
|
39509
|
+
this.onGate(GateEventSchema.parse(raw));
|
|
39510
|
+
else this.onSample(SampleSchema.parse(raw));
|
|
39403
39511
|
} catch (e) {
|
|
39404
|
-
warn("governor: bad
|
|
39512
|
+
warn("governor: bad line from memgov: " + errMsg(e));
|
|
39405
39513
|
}
|
|
39406
39514
|
});
|
|
39407
39515
|
child.stdin.on("error", () => void 0);
|
|
@@ -39454,12 +39562,16 @@ var Governor = class {
|
|
|
39454
39562
|
describe() {
|
|
39455
39563
|
const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
|
|
39456
39564
|
const first = DIAL_STEPS[profile][0];
|
|
39457
|
-
return session.pressureResponse === false ? "off (sandbox.pressureResponse)" : profile + " profile: slows builds down from " + first.availablePercent + "% free RAM or " + first.commitPercent + "% commit, in steps";
|
|
39565
|
+
return session.pressureResponse === false ? "off (sandbox.pressureResponse)" : profile + " profile: slows builds down from " + first.availablePercent + "% free RAM or " + first.commitPercent + "% commit, in steps; holds new compilers when memory grows faster than " + BURST_GATE[profile].growthMb + " MB in " + BURST_GATE[profile].windowMs / 1e3 + " s";
|
|
39458
39566
|
}
|
|
39459
39567
|
start() {
|
|
39460
39568
|
if (session.pressureResponse === false) return;
|
|
39461
39569
|
const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
|
|
39462
|
-
const proc = new MemGovProcess(
|
|
39570
|
+
const proc = new MemGovProcess(
|
|
39571
|
+
memgovArgs(profile),
|
|
39572
|
+
(s) => this.core?.onSample(s),
|
|
39573
|
+
(e) => this.core?.onGate(e)
|
|
39574
|
+
);
|
|
39463
39575
|
this.core = new GovernorCore({
|
|
39464
39576
|
port: proc,
|
|
39465
39577
|
profile,
|
|
@@ -39502,6 +39614,7 @@ function buildHeartbeat(snapshot2, sessionCount, uptimeSeconds, freeBytes2, tota
|
|
|
39502
39614
|
hostStep: clamp(snapshot2?.hostStep ?? 0, 0, 4),
|
|
39503
39615
|
topProcesses: (snapshot2?.top ?? []).slice(0, 5).map((p) => ({ name: p.name.slice(0, 64), privateMb: p.mb })),
|
|
39504
39616
|
...snapshot2?.diskQueue !== null && snapshot2?.diskQueue !== void 0 ? { diskQueueReported: snapshot2.diskQueue } : {},
|
|
39617
|
+
...snapshot2 && snapshot2.held > 0 ? { held: Math.min(1024, snapshot2.held) } : {},
|
|
39505
39618
|
phase: ending ? "ending" : sessionCount > 0 ? "working" : "ready"
|
|
39506
39619
|
};
|
|
39507
39620
|
}
|
package/dist/runtime/db.js
CHANGED
|
@@ -25478,7 +25478,7 @@ var SandboxSchema = external_exports.strictObject({
|
|
|
25478
25478
|
'The last resort that keeps the sandbox up, in MB below its commit limit (RAM plus paging file): builds are slowed down long before (sandbox.pressureResponse); only if everything the agents start together would take the sandbox to the very edge of its memory, where Windows inside it would start failing, is a build refused memory instead of Windows. "auto" = the larger of 1536 MB and 3 % of the commit limit; "none" = no backstop. Yours only: a project file cannot change it.'
|
|
25479
25479
|
),
|
|
25480
25480
|
pressureResponse: external_exports.boolean().describe(
|
|
25481
|
-
"When the sandbox (or this PC) runs low on memory, slow builds down in steps, like a PC that gets slower instead of failing: build programs get lower CPU and memory priority, then less CPU, then compilers take turns (the waiting ones briefly suspended and trimmed to the paging file). Nothing is stopped or killed, and the agents themselves are never touched. Yours only: a project file cannot change it."
|
|
25481
|
+
"When the sandbox (or this PC) runs low on memory, slow builds down in steps, like a PC that gets slower instead of failing: build programs get lower CPU and memory priority, then less CPU, then compilers take turns (the waiting ones briefly suspended and trimmed to the paging file). Nothing is stopped or killed, and the agents themselves are never touched. A memory gate also holds new compilers and linkers for a moment when the memory of the build programs grows faster than 4 GB in 3 seconds (3 GB with vGPU), and lets them go one at a time. Yours only: a project file cannot change it."
|
|
25482
25482
|
),
|
|
25483
25483
|
vGpu: external_exports.boolean().describe(
|
|
25484
25484
|
"Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface. The sandbox then uses this PC's graphics card, and with some graphics drivers heavy use can freeze the whole PC: turn it on only when a program in the sandbox needs the GPU (the mesa toolchain gives software OpenGL without it). Browsers in the sandbox never use it (they draw in software)."
|
|
@@ -27676,6 +27676,8 @@ var PressureStatusSchema = external_exports.object({
|
|
|
27676
27676
|
lowered: external_exports.number().int().min(0).max(1024),
|
|
27677
27677
|
/** Compilers waiting their turn right now (name, process id, seconds until they may go on). */
|
|
27678
27678
|
paused: external_exports.array(external_exports.object({ name: Text(64), pid: external_exports.number().int(), seconds: external_exports.number().int().min(0).max(60) })).max(8),
|
|
27679
|
+
/** Build programs the memory gate holds right now (let go one at a time). */
|
|
27680
|
+
held: external_exports.number().int().min(0).max(1024).optional(),
|
|
27679
27681
|
/** The CPU share the compilers get together (percent; 100 = no cap). */
|
|
27680
27682
|
cpuPercent: external_exports.number().int().min(0).max(100).optional(),
|
|
27681
27683
|
/** The PC itself asked for slowing down (its memory or CPU is low). */
|
|
@@ -27696,6 +27698,8 @@ var HeartbeatSchema = external_exports.object({
|
|
|
27696
27698
|
topProcesses: external_exports.array(external_exports.object({ name: Text(64), privateMb: external_exports.number().int().min(0).max(1e7) })).max(5),
|
|
27697
27699
|
/** The disk queue this PC last reported while asking the sandbox to slow down. */
|
|
27698
27700
|
diskQueueReported: external_exports.number().min(0).max(1e5).optional(),
|
|
27701
|
+
/** Build programs the memory gate holds right now (let go one at a time). */
|
|
27702
|
+
held: external_exports.number().int().min(0).max(1024).optional(),
|
|
27699
27703
|
/** "ending": the sandbox is shutting down in order (idle shutdown, sandbox stop, Windows shutting down). */
|
|
27700
27704
|
phase: external_exports.enum(["ready", "working", "ending"])
|
|
27701
27705
|
});
|