windows-development-sandbox 1.27.3 → 1.29.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 (125) hide show
  1. package/README.md +5 -4
  2. package/dist/app/features/sandbox/sandbox.run.js +1 -1
  3. package/dist/bin/{chunk-FA5VWLP4.js → chunk-O4EL32TM.js} +1 -1
  4. package/dist/bin/{chunk-RU7XRN62.js → chunk-QYRRWGFY.js} +1637 -1354
  5. package/dist/bin/sandbox.js +10772 -3
  6. package/dist/cli/commands/launch/launch.js +1 -1
  7. package/dist/cli/commands/launch/running.js +2 -2
  8. package/dist/cli/index.js +1 -1
  9. package/dist/cli/menu/pages/agents-page.js +1 -1
  10. package/dist/cli/services/sandbox-service.js +1 -1
  11. package/dist/core/schema/sandbox.js +2 -2
  12. package/dist/guest/apps/app-installer.js +1 -1
  13. package/dist/guest/apps/store-check.d.ts +2 -0
  14. package/dist/guest/apps/store-check.js +3 -1
  15. package/dist/guest/boot/guide-lines.d.ts +2 -0
  16. package/dist/guest/boot/guide-lines.js +7 -0
  17. package/dist/guest/boot/guide.js +2 -1
  18. package/dist/guest/daemon/heartbeat.js +1 -0
  19. package/dist/guest/governor/core.d.ts +53 -1
  20. package/dist/guest/governor/core.js +95 -1
  21. package/dist/guest/governor/decide.d.ts +4 -0
  22. package/dist/guest/governor/decide.js +2 -0
  23. package/dist/guest/governor/governor.js +23 -9
  24. package/dist/guest/toolchains/runtimes.js +7 -6
  25. package/dist/host/accounts/deliver.js +16 -2
  26. package/dist/host/apps/store-package.d.ts +2 -0
  27. package/dist/host/apps/store-package.js +16 -15
  28. package/dist/host/channel/attach.js +1 -1
  29. package/dist/host/channel/channel.js +3 -3
  30. package/dist/host/guard/commands.js +1 -0
  31. package/dist/host/health/path-copies.d.ts +1 -1
  32. package/dist/host/health/path-copies.js +2 -2
  33. package/dist/host/install/index.d.ts +1 -1
  34. package/dist/host/install/index.js +1 -1
  35. package/dist/host/install/shims.d.ts +8 -1
  36. package/dist/host/install/shims.js +39 -1
  37. package/dist/host/launch/generate.js +4 -0
  38. package/dist/host/launch/index.d.ts +1 -0
  39. package/dist/host/launch/index.js +1 -0
  40. package/dist/host/launch/pc-logs.d.ts +6 -0
  41. package/dist/host/launch/pc-logs.js +129 -0
  42. package/dist/host/life/crash-report.d.ts +4 -0
  43. package/dist/host/life/crash-report.js +30 -1
  44. package/dist/host/life/last-end.js +1 -0
  45. package/dist/host/sandbox/platform.js +1 -1
  46. package/dist/host/sandbox/window.js +1 -1
  47. package/dist/host/tools/windows-terminal.d.ts +4 -1
  48. package/dist/host/tools/windows-terminal.js +25 -9
  49. package/dist/runtime/agent.js +6 -2
  50. package/dist/runtime/daemon.js +111 -16
  51. package/dist/runtime/db.js +6 -2
  52. package/dist/runtime/main.js +199 -35
  53. package/dist/runtime/netproxy.js +6 -2
  54. package/dist/runtime/tool.js +6 -2
  55. package/dist/runtime/view.js +126 -28
  56. package/dist/selftest/agent-paths.test.js +3 -1
  57. package/dist/selftest/channel.test.js +33 -0
  58. package/dist/selftest/cli.test.js +5 -5
  59. package/dist/selftest/config.test.js +1 -1
  60. package/dist/selftest/credentials.test.js +1 -1
  61. package/dist/selftest/engine.test.js +1 -1
  62. package/dist/selftest/generate.test.js +66 -1
  63. package/dist/selftest/hcs.test.js +1 -1
  64. package/dist/selftest/health.test.js +21 -10
  65. package/dist/selftest/heavy-load.test.js +112 -4
  66. package/dist/selftest/host-sim.test.js +13 -14
  67. package/dist/selftest/install.test.js +6 -2
  68. package/dist/selftest/live-terminal.test.js +103 -0
  69. package/dist/selftest/personalization.test.js +2 -1
  70. package/dist/selftest/store-app.test.js +62 -4
  71. package/dist/selftest/support/engine-golden.js +2 -0
  72. package/dist/selftest/support/web-preview.js +2 -2
  73. package/dist/shared/accounts/kinds.d.ts +5 -0
  74. package/dist/shared/accounts/kinds.js +8 -0
  75. package/dist/shared/apps/index.d.ts +1 -1
  76. package/dist/shared/apps/index.js +1 -1
  77. package/dist/shared/apps/selection.d.ts +1 -0
  78. package/dist/shared/apps/selection.js +4 -3
  79. package/dist/shared/apps/store-package.d.ts +13 -0
  80. package/dist/shared/apps/store-package.js +24 -0
  81. package/dist/shared/channel/schema.d.ts +2 -0
  82. package/dist/shared/channel/schema.js +4 -0
  83. package/dist/shared/memory/policy.d.ts +12 -0
  84. package/dist/shared/memory/policy.js +4 -0
  85. package/dist/shared/pty/clipboard-watch.d.ts +4 -0
  86. package/dist/shared/pty/clipboard-watch.js +40 -0
  87. package/dist/shared/pty/ctrl-c.d.ts +13 -7
  88. package/dist/shared/pty/ctrl-c.js +35 -19
  89. package/dist/shared/pty/index.d.ts +1 -0
  90. package/dist/shared/pty/index.js +1 -0
  91. package/dist/shared/pty/terminal.d.ts +1 -1
  92. package/dist/shared/pty/terminal.js +16 -13
  93. package/dist/shared/web/ctrl-c.d.ts +26 -0
  94. package/dist/shared/web/ctrl-c.js +64 -0
  95. package/dist/shared/web/index.d.ts +1 -0
  96. package/dist/shared/web/index.js +1 -0
  97. package/dist/web/index.html +1 -1
  98. package/dist/web/{main-NKM7ECSB.js → main-7NY4X6YU.js} +67 -67
  99. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  100. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  101. package/native/csharp/HostTools/Window.cs +1 -1
  102. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  103. package/native/scripts/get-store-package.ps1 +24 -13
  104. package/package.json +4 -14
  105. package/sandbox/csharp/ClipboardWatch.cs +59 -0
  106. package/sandbox/csharp/MemGov.cs +752 -7
  107. package/sandbox/scripts/install-store-package.ps1 +11 -4
  108. package/sandbox/scripts/watch-clipboard.ps1 +8 -0
  109. package/schemas/config.schema.json +2 -2
  110. package/schemas/sandbox-config.schema.json +1 -1
  111. package/dist/bin/agent-sandbox.d.ts +0 -2
  112. package/dist/bin/agent-sandbox.js +0 -9
  113. package/dist/bin/chunk-4M5SZZ5P.js +0 -10778
  114. package/dist/bin/claude-host.d.ts +0 -2
  115. package/dist/bin/claude-host.js +0 -11
  116. package/dist/bin/claude-sbx.d.ts +0 -2
  117. package/dist/bin/claude-sbx.js +0 -9
  118. package/dist/bin/codex-sbx.d.ts +0 -2
  119. package/dist/bin/codex-sbx.js +0 -9
  120. package/dist/bin/gemini-sbx.d.ts +0 -2
  121. package/dist/bin/gemini-sbx.js +0 -9
  122. package/dist/bin/sbx-hide.d.ts +0 -2
  123. package/dist/bin/sbx-hide.js +0 -9
  124. package/dist/bin/sbx-show.d.ts +0 -2
  125. package/dist/bin/sbx-show.js +0 -9
@@ -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)."
@@ -25535,7 +25535,7 @@ var SandboxSchema = external_exports.strictObject({
25535
25535
  printerRedirection: external_exports.boolean().describe("Printers from this PC."),
25536
25536
  protectedClient: external_exports.boolean().describe("Run the sandbox window in Protected Client mode (recommended)."),
25537
25537
  headless: external_exports.boolean().describe(
25538
- "Hide the sandbox window (sbx-show brings it back). A headless sandbox shuts down when its last session ends."
25538
+ 'Hide the sandbox window ("Show the window" brings it back). A headless sandbox shuts down when its last session ends.'
25539
25539
  ),
25540
25540
  keepAwake: external_exports.boolean().describe(
25541
25541
  "Keep this PC from sleeping while a sandbox runs, so agents left working overnight keep going (the screen may still turn off; closing a laptop lid still sleeps it)."
@@ -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
  });
@@ -30036,6 +30040,10 @@ function toolLines(primaryName, toolSummary, projects) {
30036
30040
  "- Tools by project: each project gets the tools its own files ask for; python and rust already installed here are on every project's PATH."
30037
30041
  ];
30038
30042
  }
30043
+ function pcLogsGuideLine(launchDir2, exists2) {
30044
+ const dir = path31.win32.join(launchDir2, "pc-logs");
30045
+ return exists2(dir) ? ["- PC crash reports and logs (this project only, read-only, never commit them): `" + dir + "`"] : [];
30046
+ }
30039
30047
 
30040
30048
  // src/shared/unreal/engines.ts
30041
30049
  import crypto3 from "node:crypto";
@@ -31911,6 +31919,7 @@ function sandboxGuide(toolSummary, lan = "blocked", projects = [], addons = [])
31911
31919
  "- RW, persists: `" + stateDir + "` (agent config/history; do not edit logins) \xB7 logs: `" + path46.join(dataDir, "logs") + "`",
31912
31920
  "- RO: `" + launchDir + "` (this boot's scripts) \xB7 lost on close: everything else, incl. `C:\\nvm` (Node symlink)",
31913
31921
  ...mirrorLine(),
31922
+ ...pcLogsGuideLine(launchDir, fs28.existsSync),
31914
31923
  ...toolLines(session.project, toolSummary, projects),
31915
31924
  ...unrealLines(projects),
31916
31925
  ...unityLines(projects),
@@ -32109,11 +32118,10 @@ async function setupBun(env) {
32109
32118
  tool("bun", "bin"),
32110
32119
  { size: "35 MB" }
32111
32120
  );
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
- });
32121
+ const cache = path48.join(localDir, "bun-cache");
32122
+ const temp = path48.join(localDir, "bun-tmp");
32123
+ if (!dryRun) [cache, temp].forEach((dir) => mkdirp(dir));
32124
+ Object.assign(env.vars, { BUN_INSTALL: tool("bun"), BUN_INSTALL_CACHE_DIR: cache, BUN_TMPDIR: temp });
32117
32125
  }
32118
32126
  async function setupDeno(env) {
32119
32127
  await setupSingleExe(
@@ -32687,9 +32695,10 @@ function fileSha256(file3) {
32687
32695
  stream.on("end", () => resolve2(hash2.digest("hex")));
32688
32696
  });
32689
32697
  }
32698
+ var MISSING_PACKAGE = 'this PC did not hand over its package (it could not fetch it: see the launch notes). Fix: on this PC run "winget download --id <product id> --source msstore", then launch again';
32690
32699
  async function checkedPackage(dir) {
32691
32700
  const manifest2 = readValid(StorePackageManifestSchema, path55.join(dir, STORE_PACKAGE_MANIFEST));
32692
- if (!manifest2) throw new Error("the package was not handed over (this PC could not fetch it: see the launch notes)");
32701
+ if (!manifest2) throw new Error(MISSING_PACKAGE);
32693
32702
  for (const f of manifest2.files) {
32694
32703
  if (await fileSha256(path55.join(dir, f.name)).catch(() => "") !== f.sha256)
32695
32704
  throw new Error(f.name + " is missing or changed");
@@ -33069,7 +33078,9 @@ var AppInstaller = class {
33069
33078
  warn(
33070
33079
  entry.name + " could not be installed and is skipped; the other apps are not affected. Reason: " + errMsg(e)
33071
33080
  );
33072
- this.env.summary.push(entry.name + ": FAILED");
33081
+ this.env.summary.push(
33082
+ "store" in entry.source ? entry.name + ": not installed - " + errMsg(e).slice(0, 300) : entry.name + ": FAILED"
33083
+ );
33073
33084
  }
33074
33085
  }
33075
33086
  /** The command line an app's shortcut starts it with (Comet: its own profile, DevTools on 127.0.0.1). */
@@ -37686,6 +37697,10 @@ function maxCompilers(cpus, profile) {
37686
37697
  function cargoLinkerVar(host) {
37687
37698
  return "CARGO_TARGET_" + host.toUpperCase().replace(/[^A-Z0-9]/g, "_") + "_LINKER";
37688
37699
  }
37700
+ var BURST_GATE = {
37701
+ normal: { growthMb: 4096, windowMs: 3e3, releaseMs: 1500, maxHoldMs: 3e4 },
37702
+ gentle: { growthMb: 3072, windowMs: 3e3, releaseMs: 2e3, maxHoldMs: 3e4 }
37703
+ };
37689
37704
 
37690
37705
  // src/guest/governor/decide.ts
37691
37706
  var COMPILERS = /* @__PURE__ */ new Set([
@@ -37786,6 +37801,7 @@ function linkerSlots(totalMb, cpus) {
37786
37801
  }
37787
37802
  var isHeavyCompiler = (name) => !isNeverTouched(name) && HEAVY.has(key(name));
37788
37803
  var canPause = (name) => !isNeverTouched(name) && COMPILERS.has(key(name));
37804
+ var GATE_NAMES = [...COMPILERS, "shadercompileworker"].filter((n) => !NEVER2.has(n)).sort();
37789
37805
  var INITIAL_STATE = {
37790
37806
  step: 0,
37791
37807
  calm: 0,
@@ -38748,6 +38764,9 @@ async function sendControl(endpoint, type) {
38748
38764
  // src/shared/pty/output-filter.ts
38749
38765
  var MAX_CLIPBOARD_STRING = 1024 * 1024;
38750
38766
 
38767
+ // src/shared/web/protocol.ts
38768
+ var MAX_CLIENT_MESSAGE_BYTES = 256 * 1024;
38769
+
38751
38770
  // src/guest/sessions/cmdline.ts
38752
38771
  import path106 from "node:path";
38753
38772
  var quoted = (arg) => '"' + arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/, "$1$1") + '"';
@@ -39240,6 +39259,63 @@ async function flushAccounts(final = false) {
39240
39259
  import os15 from "node:os";
39241
39260
 
39242
39261
  // src/guest/governor/core.ts
39262
+ function memgovArgs(profile) {
39263
+ const g = BURST_GATE[profile];
39264
+ return [
39265
+ "serve",
39266
+ "--interval",
39267
+ "2",
39268
+ "--gate",
39269
+ [g.growthMb, g.windowMs, g.releaseMs, g.maxHoldMs].join(":"),
39270
+ "--gate-names",
39271
+ GATE_NAMES.join(",")
39272
+ ];
39273
+ }
39274
+ var GateBase = { event: external_exports.literal("gate"), at: external_exports.number() };
39275
+ var GateName = external_exports.string().max(128);
39276
+ var GateCount = external_exports.number().int().min(0);
39277
+ var GateEventSchema = external_exports.discriminatedUnion("kind", [
39278
+ external_exports.strictObject({
39279
+ ...GateBase,
39280
+ kind: external_exports.literal("ready"),
39281
+ mode: external_exports.enum(["notify", "poll"]),
39282
+ growthMb: GateCount,
39283
+ windowMs: GateCount
39284
+ }),
39285
+ external_exports.strictObject({ ...GateBase, kind: external_exports.literal("off"), reason: external_exports.string().max(200) }),
39286
+ external_exports.strictObject({
39287
+ ...GateBase,
39288
+ kind: external_exports.literal("trip"),
39289
+ grewMb: GateCount,
39290
+ ms: GateCount,
39291
+ jobMb: GateCount,
39292
+ held: external_exports.array(external_exports.strictObject({ pid: external_exports.number().int(), name: GateName })).max(64)
39293
+ }),
39294
+ external_exports.strictObject({ ...GateBase, kind: external_exports.literal("hold"), pid: external_exports.number().int(), name: GateName }),
39295
+ external_exports.strictObject({
39296
+ ...GateBase,
39297
+ kind: external_exports.literal("release"),
39298
+ pid: external_exports.number().int(),
39299
+ name: GateName,
39300
+ heldMs: GateCount,
39301
+ forced: external_exports.boolean()
39302
+ })
39303
+ ]);
39304
+ function gateLine(e) {
39305
+ const cut = (s) => s.slice(0, 64);
39306
+ switch (e.kind) {
39307
+ case "ready":
39308
+ return "gate: on (" + e.mode + "): new compilers wait when the agents' programs grow by more than " + e.growthMb + " MB within " + e.windowMs / 1e3 + " s";
39309
+ case "off":
39310
+ return "gate: off (" + e.reason + "): builds are only slowed down by the dial";
39311
+ case "trip":
39312
+ 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" : "");
39313
+ case "hold":
39314
+ return "gate: " + cut(e.name) + " (" + e.pid + ") waits at start while a build burst goes through in turn";
39315
+ case "release":
39316
+ return "gate: " + cut(e.name) + " (" + e.pid + ") goes on after " + (e.heldMs / 1e3).toFixed(1) + " s" + (e.forced ? " (the longest it may wait)" : "");
39317
+ }
39318
+ }
39243
39319
  var STEP_TEXT = [
39244
39320
  "builds back to normal",
39245
39321
  "build programs at lower priority",
@@ -39289,6 +39365,7 @@ var GovernorCore = class {
39289
39365
  commitPercent: d.commitPercent,
39290
39366
  step: d.state.step,
39291
39367
  hostStep: nowMs < d.state.hostUntil ? d.state.hostStep : 0,
39368
+ held: sample.gateHeld ?? 0,
39292
39369
  diskQueue: null,
39293
39370
  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
39371
  };
@@ -39310,6 +39387,7 @@ var GovernorCore = class {
39310
39387
  commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
39311
39388
  lowered: Object.keys(d.state.lowered).length,
39312
39389
  paused: [...this.held].slice(0, 8).map(([pid, name]) => ({ name: name.slice(0, 64), pid, seconds: HOLD_MS / 1e3 })),
39390
+ held: sample.gateHeld ?? 0,
39313
39391
  cpuPercent: d.state.cpuRate,
39314
39392
  pcLow: nowMs < d.state.hostUntil,
39315
39393
  lastAction: this.lastAction.slice(0, 300),
@@ -39322,6 +39400,10 @@ var GovernorCore = class {
39322
39400
  this.deps.saveStatus(status);
39323
39401
  }
39324
39402
  }
39403
+ /** An event from the memory gate in memgov: goes to the memory log. */
39404
+ onGate(event) {
39405
+ this.note(gateLine(event));
39406
+ }
39325
39407
  apply(action) {
39326
39408
  const port = this.deps.port;
39327
39409
  try {
@@ -39382,26 +39464,34 @@ var SampleSchema = external_exports.object({
39382
39464
  mb: external_exports.number(),
39383
39465
  prio: external_exports.enum(["idle", "below", "normal"]).catch("normal")
39384
39466
  })
39385
- ).max(1024)
39467
+ ).max(1024),
39468
+ gateHeld: external_exports.number().int().min(0).max(1024).optional().catch(void 0)
39386
39469
  });
39387
39470
  var MemGovProcess = class {
39388
- constructor(onSample) {
39471
+ constructor(args, onSample, onGate) {
39472
+ this.args = args;
39389
39473
  this.onSample = onSample;
39474
+ this.onGate = onGate;
39390
39475
  }
39476
+ args;
39391
39477
  onSample;
39478
+ onGate;
39392
39479
  child = null;
39393
39480
  start() {
39394
39481
  try {
39395
- const child = spawn12(ensureCompiled("memgov"), ["serve", "--interval", "2"], {
39482
+ const child = spawn12(ensureCompiled("memgov"), [...this.args], {
39396
39483
  stdio: ["pipe", "pipe", "ignore"],
39397
39484
  windowsHide: true
39398
39485
  });
39399
39486
  this.child = child;
39400
39487
  createInterface({ input: child.stdout }).on("line", (line) => {
39401
39488
  try {
39402
- this.onSample(SampleSchema.parse(JSON.parse(line)));
39489
+ const raw = JSON.parse(line);
39490
+ if (typeof raw === "object" && raw !== null && raw.event === "gate")
39491
+ this.onGate(GateEventSchema.parse(raw));
39492
+ else this.onSample(SampleSchema.parse(raw));
39403
39493
  } catch (e) {
39404
- warn("governor: bad sample: " + errMsg(e));
39494
+ warn("governor: bad line from memgov: " + errMsg(e));
39405
39495
  }
39406
39496
  });
39407
39497
  child.stdin.on("error", () => void 0);
@@ -39454,12 +39544,16 @@ var Governor = class {
39454
39544
  describe() {
39455
39545
  const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
39456
39546
  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";
39547
+ 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
39548
  }
39459
39549
  start() {
39460
39550
  if (session.pressureResponse === false) return;
39461
39551
  const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
39462
- const proc = new MemGovProcess((s) => this.core?.onSample(s));
39552
+ const proc = new MemGovProcess(
39553
+ memgovArgs(profile),
39554
+ (s) => this.core?.onSample(s),
39555
+ (e) => this.core?.onGate(e)
39556
+ );
39463
39557
  this.core = new GovernorCore({
39464
39558
  port: proc,
39465
39559
  profile,
@@ -39502,6 +39596,7 @@ function buildHeartbeat(snapshot2, sessionCount, uptimeSeconds, freeBytes2, tota
39502
39596
  hostStep: clamp(snapshot2?.hostStep ?? 0, 0, 4),
39503
39597
  topProcesses: (snapshot2?.top ?? []).slice(0, 5).map((p) => ({ name: p.name.slice(0, 64), privateMb: p.mb })),
39504
39598
  ...snapshot2?.diskQueue !== null && snapshot2?.diskQueue !== void 0 ? { diskQueueReported: snapshot2.diskQueue } : {},
39599
+ ...snapshot2 && snapshot2.held > 0 ? { held: Math.min(1024, snapshot2.held) } : {},
39505
39600
  phase: ending ? "ending" : sessionCount > 0 ? "working" : "ready"
39506
39601
  };
39507
39602
  }
@@ -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)."
@@ -25492,7 +25492,7 @@ var SandboxSchema = external_exports.strictObject({
25492
25492
  printerRedirection: external_exports.boolean().describe("Printers from this PC."),
25493
25493
  protectedClient: external_exports.boolean().describe("Run the sandbox window in Protected Client mode (recommended)."),
25494
25494
  headless: external_exports.boolean().describe(
25495
- "Hide the sandbox window (sbx-show brings it back). A headless sandbox shuts down when its last session ends."
25495
+ 'Hide the sandbox window ("Show the window" brings it back). A headless sandbox shuts down when its last session ends.'
25496
25496
  ),
25497
25497
  keepAwake: external_exports.boolean().describe(
25498
25498
  "Keep this PC from sleeping while a sandbox runs, so agents left working overnight keep going (the screen may still turn off; closing a laptop lid still sleeps it)."
@@ -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
  });