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.
Files changed (68) hide show
  1. package/dist/bin/agent-sandbox.js +2 -2
  2. package/dist/bin/{chunk-RU7XRN62.js → chunk-CB44HTTN.js} +196 -75
  3. package/dist/bin/{chunk-FA5VWLP4.js → chunk-UZ5S3EMB.js} +1 -1
  4. package/dist/bin/{chunk-4M5SZZ5P.js → chunk-ZMZI3625.js} +1 -1
  5. package/dist/bin/claude-host.js +2 -2
  6. package/dist/bin/claude-sbx.js +2 -2
  7. package/dist/bin/codex-sbx.js +2 -2
  8. package/dist/bin/gemini-sbx.js +2 -2
  9. package/dist/bin/sandbox.js +2 -2
  10. package/dist/bin/sbx-hide.js +2 -2
  11. package/dist/bin/sbx-show.js +2 -2
  12. package/dist/core/schema/sandbox.js +1 -1
  13. package/dist/guest/daemon/heartbeat.js +1 -0
  14. package/dist/guest/governor/core.d.ts +53 -1
  15. package/dist/guest/governor/core.js +95 -1
  16. package/dist/guest/governor/decide.d.ts +4 -0
  17. package/dist/guest/governor/decide.js +2 -0
  18. package/dist/guest/governor/governor.js +23 -9
  19. package/dist/guest/toolchains/native/unreal.js +22 -3
  20. package/dist/guest/toolchains/runtimes.js +7 -6
  21. package/dist/host/life/crash-report.d.ts +4 -0
  22. package/dist/host/life/crash-report.js +30 -1
  23. package/dist/host/life/last-end.js +1 -0
  24. package/dist/host/tools/windows-terminal.d.ts +4 -1
  25. package/dist/host/tools/windows-terminal.js +25 -9
  26. package/dist/runtime/agent.js +5 -1
  27. package/dist/runtime/daemon.js +183 -70
  28. package/dist/runtime/db.js +5 -1
  29. package/dist/runtime/main.js +242 -56
  30. package/dist/runtime/netproxy.js +5 -1
  31. package/dist/runtime/tool.js +5 -1
  32. package/dist/runtime/view.js +125 -27
  33. package/dist/selftest/agent-paths.test.js +3 -1
  34. package/dist/selftest/channel.test.js +33 -0
  35. package/dist/selftest/heavy-load.test.js +116 -4
  36. package/dist/selftest/live-terminal.test.js +103 -0
  37. package/dist/selftest/personalization.test.js +2 -1
  38. package/dist/selftest/support/engine-golden.js +2 -0
  39. package/dist/shared/channel/schema.d.ts +2 -0
  40. package/dist/shared/channel/schema.js +4 -0
  41. package/dist/shared/memory/index.d.ts +1 -0
  42. package/dist/shared/memory/index.js +1 -0
  43. package/dist/shared/memory/policy.d.ts +12 -0
  44. package/dist/shared/memory/policy.js +4 -0
  45. package/dist/shared/memory/unreal-build.d.ts +2 -0
  46. package/dist/shared/memory/unreal-build.js +21 -0
  47. package/dist/shared/pty/clipboard-watch.d.ts +4 -0
  48. package/dist/shared/pty/clipboard-watch.js +40 -0
  49. package/dist/shared/pty/ctrl-c.d.ts +13 -7
  50. package/dist/shared/pty/ctrl-c.js +35 -19
  51. package/dist/shared/pty/index.d.ts +1 -0
  52. package/dist/shared/pty/index.js +1 -0
  53. package/dist/shared/pty/terminal.d.ts +1 -1
  54. package/dist/shared/pty/terminal.js +16 -13
  55. package/dist/shared/web/ctrl-c.d.ts +26 -0
  56. package/dist/shared/web/ctrl-c.js +64 -0
  57. package/dist/shared/web/index.d.ts +1 -0
  58. package/dist/shared/web/index.js +1 -0
  59. package/dist/web/index.html +1 -1
  60. package/dist/web/{main-NKM7ECSB.js → main-7NY4X6YU.js} +67 -67
  61. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  62. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  63. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  64. package/package.json +1 -1
  65. package/sandbox/csharp/ClipboardWatch.cs +59 -0
  66. package/sandbox/csharp/MemGov.cs +752 -7
  67. package/sandbox/scripts/watch-clipboard.ps1 +8 -0
  68. package/schemas/config.schema.json +1 -1
@@ -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
- Object.assign(env.vars, {
32113
- BUN_INSTALL: tool("bun"),
32114
- BUN_INSTALL_CACHE_DIR: path48.join(localDir, "bun-cache"),
32115
- BUN_TMPDIR: path48.join(localDir, "bun-tmp")
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"), ["serve", "--interval", "2"], {
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
- this.onSample(SampleSchema.parse(JSON.parse(line)));
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 sample: " + errMsg(e));
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((s) => this.core?.onSample(s));
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
  }
@@ -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
  });