windows-development-sandbox 1.27.1 → 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 (121) hide show
  1. package/dist/app/context.d.ts +5 -0
  2. package/dist/app/context.js +13 -0
  3. package/dist/app/features/accounts/accounts.def.d.ts +16 -0
  4. package/dist/app/features/accounts/accounts.run.d.ts +4 -0
  5. package/dist/app/features/accounts/services.def.d.ts +15 -1
  6. package/dist/app/features/accounts/services.def.js +67 -31
  7. package/dist/app/features/accounts/services.run.d.ts +7 -2
  8. package/dist/app/features/accounts/services.run.js +25 -6
  9. package/dist/app/features/defs.d.ts +17 -0
  10. package/dist/app/registry.d.ts +1 -1
  11. package/dist/app/registry.js +15 -2
  12. package/dist/bin/agent-sandbox.js +2 -2
  13. package/dist/bin/{chunk-RSIX7C6D.js → chunk-CB44HTTN.js} +444 -175
  14. package/dist/bin/{chunk-4TLSWPG7.js → chunk-UZ5S3EMB.js} +1 -1
  15. package/dist/bin/{chunk-QUHNXHVG.js → chunk-ZMZI3625.js} +46 -41
  16. package/dist/bin/claude-host.js +2 -2
  17. package/dist/bin/claude-sbx.js +2 -2
  18. package/dist/bin/codex-sbx.js +2 -2
  19. package/dist/bin/gemini-sbx.js +2 -2
  20. package/dist/bin/sandbox.js +2 -2
  21. package/dist/bin/sbx-hide.js +2 -2
  22. package/dist/bin/sbx-show.js +2 -2
  23. package/dist/cli/menu/menu.js +6 -1
  24. package/dist/cli/menu/pages/accounts-page.js +9 -5
  25. package/dist/core/schema/sandbox.js +1 -1
  26. package/dist/guest/apps/app-installer.js +7 -5
  27. package/dist/guest/apps/comet-unpack.js +2 -2
  28. package/dist/guest/daemon/heartbeat.js +1 -0
  29. package/dist/guest/governor/core.d.ts +53 -1
  30. package/dist/guest/governor/core.js +95 -1
  31. package/dist/guest/governor/decide.d.ts +4 -0
  32. package/dist/guest/governor/decide.js +2 -0
  33. package/dist/guest/governor/governor.js +23 -9
  34. package/dist/guest/runtime/pools.d.ts +4 -4
  35. package/dist/guest/runtime/pools.js +4 -15
  36. package/dist/guest/runtime/process.d.ts +5 -2
  37. package/dist/guest/runtime/process.js +23 -3
  38. package/dist/guest/toolchains/engines/epic-launcher.d.ts +6 -0
  39. package/dist/guest/toolchains/engines/epic-launcher.js +19 -1
  40. package/dist/guest/toolchains/engines/unreal-engines.js +2 -1
  41. package/dist/guest/toolchains/installers.d.ts +3 -3
  42. package/dist/guest/toolchains/installers.js +5 -5
  43. package/dist/guest/toolchains/native/unreal.js +22 -3
  44. package/dist/guest/toolchains/native/vcruntime.js +2 -2
  45. package/dist/guest/toolchains/native/vs-persist.d.ts +2 -2
  46. package/dist/guest/toolchains/runtimes.js +7 -6
  47. package/dist/guest/toolchains/signature.d.ts +2 -0
  48. package/dist/guest/toolchains/signature.js +9 -2
  49. package/dist/guest/toolchains/step-scheduler.js +1 -1
  50. package/dist/host/accounts/deliver.js +15 -7
  51. package/dist/host/life/crash-report.d.ts +4 -0
  52. package/dist/host/life/crash-report.js +30 -1
  53. package/dist/host/life/last-end.js +1 -0
  54. package/dist/host/pc-installs/discover.js +5 -2
  55. package/dist/host/pc-installs/unreal.d.ts +3 -1
  56. package/dist/host/pc-installs/unreal.js +27 -1
  57. package/dist/host/tools/windows-terminal.d.ts +4 -1
  58. package/dist/host/tools/windows-terminal.js +25 -9
  59. package/dist/runtime/agent.js +39 -23
  60. package/dist/runtime/daemon.js +279 -121
  61. package/dist/runtime/db.js +37 -17
  62. package/dist/runtime/main.js +340 -109
  63. package/dist/runtime/netproxy.js +31 -13
  64. package/dist/runtime/tool.js +37 -16
  65. package/dist/runtime/view.js +150 -38
  66. package/dist/selftest/agent-paths.test.js +3 -1
  67. package/dist/selftest/app.test.js +20 -2
  68. package/dist/selftest/boot-runner.test.js +15 -1
  69. package/dist/selftest/channel.test.js +33 -0
  70. package/dist/selftest/engines.test.js +22 -1
  71. package/dist/selftest/heavy-load.test.js +116 -4
  72. package/dist/selftest/live-terminal.test.js +103 -0
  73. package/dist/selftest/menu-screens.js +52 -1
  74. package/dist/selftest/menu.test.js +29 -3
  75. package/dist/selftest/personalization.test.js +2 -1
  76. package/dist/selftest/service-accounts.test.js +77 -2
  77. package/dist/selftest/support/engine-golden.js +2 -0
  78. package/dist/selftest/ui-text.test.js +4 -0
  79. package/dist/shared/accounts/kinds.js +9 -9
  80. package/dist/shared/apps/catalogue-gamedev.js +1 -0
  81. package/dist/shared/apps/catalogue.d.ts +2 -0
  82. package/dist/shared/channel/schema.d.ts +2 -0
  83. package/dist/shared/channel/schema.js +4 -0
  84. package/dist/shared/concurrency/pools.js +1 -1
  85. package/dist/shared/download/archive.js +4 -2
  86. package/dist/shared/download/index.d.ts +1 -1
  87. package/dist/shared/download/index.js +1 -1
  88. package/dist/shared/download/spawn.d.ts +7 -1
  89. package/dist/shared/download/spawn.js +16 -1
  90. package/dist/shared/memory/index.d.ts +1 -0
  91. package/dist/shared/memory/index.js +1 -0
  92. package/dist/shared/memory/policy.d.ts +12 -0
  93. package/dist/shared/memory/policy.js +4 -0
  94. package/dist/shared/memory/unreal-build.d.ts +2 -0
  95. package/dist/shared/memory/unreal-build.js +21 -0
  96. package/dist/shared/paths/pc-installs.d.ts +8 -0
  97. package/dist/shared/pty/clipboard-watch.d.ts +4 -0
  98. package/dist/shared/pty/clipboard-watch.js +40 -0
  99. package/dist/shared/pty/ctrl-c.d.ts +13 -7
  100. package/dist/shared/pty/ctrl-c.js +35 -19
  101. package/dist/shared/pty/index.d.ts +1 -0
  102. package/dist/shared/pty/index.js +1 -0
  103. package/dist/shared/pty/terminal.d.ts +1 -1
  104. package/dist/shared/pty/terminal.js +16 -13
  105. package/dist/shared/unreal/launcher-files.d.ts +7 -0
  106. package/dist/shared/unreal/launcher-files.js +32 -1
  107. package/dist/shared/web/ctrl-c.d.ts +26 -0
  108. package/dist/shared/web/ctrl-c.js +64 -0
  109. package/dist/shared/web/index.d.ts +1 -0
  110. package/dist/shared/web/index.js +1 -0
  111. package/dist/web/index.html +1 -1
  112. package/dist/web/{main-VPMYTSUL.js → main-7NY4X6YU.js} +67 -67
  113. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  114. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  115. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  116. package/package.json +1 -1
  117. package/sandbox/csharp/ClipboardWatch.cs +59 -0
  118. package/sandbox/csharp/MemGov.cs +752 -7
  119. package/sandbox/scripts/watch-clipboard.ps1 +8 -0
  120. package/schemas/config.schema.json +10 -10
  121. package/schemas/sandbox-config.schema.json +9 -9
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  attach
4
- } from "./chunk-RSIX7C6D.js";
4
+ } from "./chunk-CB44HTTN.js";
5
5
  export {
6
6
  attach
7
7
  };
@@ -182,6 +182,7 @@ import {
182
182
  redactSecrets,
183
183
  refreshStorage,
184
184
  refuseInSelfTest,
185
+ reloadSettings,
185
186
  reopenSessions,
186
187
  reopenedText,
187
188
  requestApp,
@@ -257,7 +258,7 @@ import {
257
258
  withOperationCommands,
258
259
  working,
259
260
  writeJson
260
- } from "./chunk-RSIX7C6D.js";
261
+ } from "./chunk-CB44HTTN.js";
261
262
 
262
263
  // node_modules/commander/lib/error.js
263
264
  var require_error = __commonJS({
@@ -4410,7 +4411,7 @@ function helpOrdered() {
4410
4411
  return [...COMMANDS].sort((x, y) => rank(x.name) - rank(y.name));
4411
4412
  }
4412
4413
  function toOptions(o, wrapper) {
4413
- const shown2 = o.shownAs && !wrapper ? o.shownAs : o.flag;
4414
+ const shown3 = o.shownAs && !wrapper ? o.shownAs : o.flag;
4414
4415
  const placeholder = o.type === "boolean" ? "" : " <" + (o.value ?? "value") + ">";
4415
4416
  const make = (flag) => {
4416
4417
  const option = new Option((o.short ? o.short + ", " : "") + flag + placeholder, o.description);
@@ -4420,8 +4421,8 @@ function toOptions(o, wrapper) {
4420
4421
  if (o.group) option.helpGroup(o.group + ":");
4421
4422
  return option;
4422
4423
  };
4423
- const visible = make(shown2);
4424
- return shown2 === o.flag ? [visible] : [visible, make(o.flag).hideHelp()];
4424
+ const visible = make(shown3);
4425
+ return shown3 === o.flag ? [visible] : [visible, make(o.flag).hideHelp()];
4425
4426
  }
4426
4427
  function toArgument(arg) {
4427
4428
  const name = (arg.required ? "<" : "[") + arg.name + (arg.variadic ? "..." : "") + (arg.required ? ">" : "]");
@@ -4901,10 +4902,10 @@ var TextScreen = class {
4901
4902
  const chars = [...this.value].map((ch) => this.o.masked ? "*" : ch);
4902
4903
  const inner = width - 4;
4903
4904
  const start = Math.max(0, this.cursor - inner + 1);
4904
- const shown2 = chars.slice(start, start + inner);
4905
- const before = shown2.slice(0, this.cursor - start).join("");
4906
- const at = shown2[this.cursor - start] ?? " ";
4907
- const after = shown2.slice(this.cursor - start + 1).join("");
4905
+ const shown3 = chars.slice(start, start + inner);
4906
+ const before = shown3.slice(0, this.cursor - start).join("");
4907
+ const at = shown3[this.cursor - start] ?? " ";
4908
+ const after = shown3.slice(this.cursor - start + 1).join("");
4908
4909
  const text2 = this.value === "" && this.o.placeholder ? Theme.muted(this.o.placeholder) : before + (Theme.colour ? "\x1B[7m" + at + "\x1B[27m" : "_") + after;
4909
4910
  const body = [
4910
4911
  "",
@@ -5114,10 +5115,10 @@ var PathPickerScreen = class {
5114
5115
  const typing = this.mode === "input";
5115
5116
  const frame = (t) => typing ? Theme.accent(t) : Theme.muted(t);
5116
5117
  const start = Math.max(0, this.cursor - inner + 1);
5117
- const shown2 = this.input.slice(start, start + inner);
5118
- const before = shown2.slice(0, this.cursor - start);
5119
- const at = shown2[this.cursor - start] ?? " ";
5120
- const after = shown2.slice(this.cursor - start + 1);
5118
+ const shown3 = this.input.slice(start, start + inner);
5119
+ const before = shown3.slice(0, this.cursor - start);
5120
+ const at = shown3[this.cursor - start] ?? " ";
5121
+ const after = shown3.slice(this.cursor - start + 1);
5121
5122
  const cursor = typing ? Theme.colour ? "\x1B[7m" + at + "\x1B[27m" : "_" : at;
5122
5123
  const field = this.input === "" && !typing ? Theme.muted("type a path or pick below") : before + cursor + after;
5123
5124
  const verdict = this.verdict();
@@ -5540,17 +5541,17 @@ var OverlayScreen = class {
5540
5541
  var KeyBar = class {
5541
5542
  static render(keys, width) {
5542
5543
  const line = (list) => " " + list.map(([k, what]) => Theme.key(k) + " " + Theme.muted(what)).join(" ");
5543
- const shown2 = [...keys];
5544
+ const shown3 = [...keys];
5544
5545
  const importance = (k) => k[2] ?? 5;
5545
- while (Text.width(line(shown2)) > width - 1) {
5546
+ while (Text.width(line(shown3)) > width - 1) {
5546
5547
  let drop = -1;
5547
- shown2.forEach((k, i) => {
5548
- if (importance(k) > 0 && (drop < 0 || importance(k) >= importance(shown2[drop]))) drop = i;
5548
+ shown3.forEach((k, i) => {
5549
+ if (importance(k) > 0 && (drop < 0 || importance(k) >= importance(shown3[drop]))) drop = i;
5549
5550
  });
5550
5551
  if (drop < 0) break;
5551
- shown2.splice(drop, 1);
5552
+ shown3.splice(drop, 1);
5552
5553
  }
5553
- return Text.truncate(line(shown2), width - 1);
5554
+ return Text.truncate(line(shown3), width - 1);
5554
5555
  }
5555
5556
  };
5556
5557
 
@@ -5584,9 +5585,9 @@ var SideNav = class _SideNav {
5584
5585
  lines.findIndex((l) => l.stop)
5585
5586
  );
5586
5587
  const start = lines.length > height ? Math.min(Math.max(0, at - Math.floor(height / 2)), lines.length - height) : 0;
5587
- const shown2 = lines.slice(start, start + height).map((l) => l.text);
5588
- while (shown2.length < height) shown2.push(" ".repeat(width));
5589
- return shown2;
5588
+ const shown3 = lines.slice(start, start + height).map((l) => l.text);
5589
+ while (shown3.length < height) shown3.push(" ".repeat(width));
5590
+ return shown3;
5590
5591
  }
5591
5592
  static section(nav, section, index, width, slim, standing) {
5592
5593
  const open = index === nav.active;
@@ -6435,8 +6436,8 @@ var StringListEditor = class extends CollectionEditor {
6435
6436
 
6436
6437
  // src/cli/menu/settings/format.ts
6437
6438
  function formatValue(value, max = 60) {
6438
- const shown2 = valueText(value, void 0, max);
6439
- return shown2.tone === "ok" ? Theme.ok(shown2.text) : shown2.tone === "muted" ? Theme.muted(shown2.text) : shown2.text;
6439
+ const shown3 = valueText(value, void 0, max);
6440
+ return shown3.tone === "ok" ? Theme.ok(shown3.text) : shown3.tone === "muted" ? Theme.muted(shown3.text) : shown3.text;
6440
6441
  }
6441
6442
 
6442
6443
  // src/cli/menu/settings/collections/map-editor.ts
@@ -7266,34 +7267,35 @@ var ListPage = class {
7266
7267
  };
7267
7268
 
7268
7269
  // src/cli/menu/pages/accounts-page.ts
7270
+ function shown(m) {
7271
+ return m.services.filter((s) => s.ready);
7272
+ }
7269
7273
  function viewOf(m, category) {
7270
7274
  const agent = m.agents.find((a) => a.name === category);
7271
7275
  if (agent) return menuView(agentPage(agent), { category: agent.name, refresh: false });
7272
- const service = m.services.find((s) => serviceCategory(s.kind) === category);
7276
+ const service = shown(m).find((s) => serviceCategory(s.kind) === category);
7273
7277
  if (service) return menuView(servicePage(service), { category: serviceCategory(service.kind), refresh: false });
7274
7278
  return menuView({ title: "Accounts", sections: [] }, { refresh: false });
7275
7279
  }
7276
7280
  function accountsOptions(m) {
7277
7281
  return {
7278
7282
  path: [],
7279
- intro: "Logins saved on this PC, per agent (Use puts one into the sandbox; new launches start with the default), and the service sign-ins sandboxes may get.",
7283
+ intro: "Logins saved on this PC, per agent, and the service sign-ins sandboxes may get.",
7280
7284
  categories: [
7281
7285
  ...m.agents.map((a) => ({
7282
7286
  id: a.name,
7283
7287
  label: a.name,
7284
7288
  description: a.kept ? "Saved " + a.name + " logins." : "This agent's login is not kept between sandboxes: it cannot be pointed at a folder we control."
7285
7289
  })),
7286
- ...m.services.map((s) => ({
7290
+ ...shown(m).map((s) => ({
7287
7291
  id: serviceCategory(s.kind),
7288
7292
  label: s.label,
7289
- description: "Your " + s.label + " sign-in for sandboxes that use " + s.usedFor + "."
7293
+ description: "For " + s.usedFor + "."
7290
7294
  }))
7291
7295
  ],
7292
7296
  items: [
7293
7297
  ...m.agents.flatMap((a) => menuView(agentPage(a), { category: a.name, refresh: false }).items),
7294
- ...m.services.flatMap(
7295
- (s) => menuView(servicePage(s), { category: serviceCategory(s.kind), refresh: false }).items
7296
- )
7298
+ ...shown(m).flatMap((s) => menuView(servicePage(s), { category: serviceCategory(s.kind), refresh: false }).items)
7297
7299
  ],
7298
7300
  empty: "No agents.",
7299
7301
  actions: (category) => viewOf(m, category).actions,
@@ -7481,7 +7483,7 @@ var CommandForm = class {
7481
7483
  }
7482
7484
  item(f) {
7483
7485
  const v = this.values.get(this.id(f));
7484
- const shown2 = v === true ? Theme.ok("On") : v === false || v === void 0 ? Theme.muted(
7486
+ const shown3 = v === true ? Theme.ok("On") : v === false || v === void 0 ? Theme.muted(
7485
7487
  f.kind === "option" && f.spec.type === "boolean" || f.kind === "json" ? "Off" : f.kind === "option" && f.spec.default !== void 0 ? "default " + f.spec.default : f.kind === "arg" && f.spec.required ? "required" : "not set"
7486
7488
  ) : Array.isArray(v) && v.length ? v.join(" ") : Theme.muted("not set");
7487
7489
  const actions = this.actions();
@@ -7489,7 +7491,7 @@ var CommandForm = class {
7489
7491
  return {
7490
7492
  value: this.id(f),
7491
7493
  label: argLabel(f.spec),
7492
- hint: shown2,
7494
+ hint: shown3,
7493
7495
  description: plainDescription(f.spec.description, actions),
7494
7496
  section: "What",
7495
7497
  keywords: f.spec.name
@@ -7498,7 +7500,7 @@ var CommandForm = class {
7498
7500
  return {
7499
7501
  value: "json",
7500
7502
  label: "Machine-readable output",
7501
- hint: shown2,
7503
+ hint: shown3,
7502
7504
  description: "Print JSON instead of a table.",
7503
7505
  section: "Output",
7504
7506
  flip: true
@@ -7507,14 +7509,14 @@ var CommandForm = class {
7507
7509
  return {
7508
7510
  value: "extra",
7509
7511
  label: this.spec.passthrough === "agent" ? "Extra arguments for the agent" : "Arguments for the command",
7510
- hint: shown2,
7512
+ hint: shown3,
7511
7513
  description: this.spec.passthrough === "agent" ? "Passed on to the agent, e.g. --continue." : "The rest of the command line.",
7512
7514
  section: "Output"
7513
7515
  };
7514
7516
  return {
7515
7517
  value: this.id(f),
7516
7518
  label: optionLabel(f.spec),
7517
- hint: shown2,
7519
+ hint: shown3,
7518
7520
  description: plainDescription(f.spec.description, actions),
7519
7521
  section: f.spec.advanced ? "Advanced" : "Options",
7520
7522
  keywords: f.spec.flag,
@@ -8941,19 +8943,19 @@ function draftSource2(draft) {
8941
8943
  effective: (file, key, config2) => file.isProject ? written(file, key) : draft.has(file, key) ? draft.value(file, key) ?? file.defaultOf(key) : import_lodash5.default.get(config2, key)
8942
8944
  };
8943
8945
  }
8944
- function shown(row, value, max = 60) {
8946
+ function shown2(row, value, max = 60) {
8945
8947
  const v = valueText(value, row.field, max);
8946
8948
  return v.tone === "ok" ? Theme.ok(v.text) : v.tone === "muted" ? Theme.muted(v.text) : v.text;
8947
8949
  }
8948
8950
  function item(row, file, draft) {
8949
8951
  const unsaved = draft.has(file, row.key);
8950
8952
  const paint2 = file.isProject ? Theme.project : Theme.changed;
8951
- const value = file.isProject && !row.set ? Theme.muted("all projects: ") + shown(row, row.yours, 40) : shown(row, row.value);
8953
+ const value = file.isProject && !row.set ? Theme.muted("all projects: ") + shown2(row, row.yours, 40) : shown2(row, row.value);
8952
8954
  const details = [
8953
8955
  Theme.muted("Setting ") + row.id,
8954
- Theme.muted("All projects ") + shown(row, row.yours, 40) + Theme.muted(row.yoursSet ? " (your file)" : " (built-in default)"),
8955
- Theme.muted("This project ") + (row.inProject === void 0 ? Theme.muted("not set") : Theme.project(Text.strip(shown(row, row.inProject, 40)))),
8956
- ...!file.isProject ? [Theme.muted("Default ") + shown(row, row.default, 40)] : [],
8956
+ Theme.muted("All projects ") + shown2(row, row.yours, 40) + Theme.muted(row.yoursSet ? " (your file)" : " (built-in default)"),
8957
+ Theme.muted("This project ") + (row.inProject === void 0 ? Theme.muted("not set") : Theme.project(Text.strip(shown2(row, row.inProject, 40)))),
8958
+ ...!file.isProject ? [Theme.muted("Default ") + shown2(row, row.default, 40)] : [],
8957
8959
  ...unsaved ? [Theme.warn("Unsaved: Ctrl+S saves, z undoes this change.")] : [],
8958
8960
  ...file.isProject && row.locked ? [Theme.warn(Theme.glyph.lock + " A project can only make this stricter than your own setting.")] : []
8959
8961
  ];
@@ -9620,7 +9622,10 @@ var Menu = class {
9620
9622
  new MaintenancePage(app, ctx)
9621
9623
  ],
9622
9624
  draft,
9623
- (saved) => this.applyAgentCommands(saved)
9625
+ (saved) => {
9626
+ reloadSettings(this.ctx);
9627
+ return this.applyAgentCommands(saved);
9628
+ }
9624
9629
  );
9625
9630
  }
9626
9631
  /** Runs the menu until you leave it, or until a command that takes over the terminal (attach) has run. */
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-QUHNXHVG.js";
6
- import "./chunk-RSIX7C6D.js";
5
+ } from "./chunk-ZMZI3625.js";
6
+ import "./chunk-CB44HTTN.js";
7
7
 
8
8
  // src/bin/claude-host.ts
9
9
  var args = process.argv.slice(2);
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-QUHNXHVG.js";
6
- import "./chunk-RSIX7C6D.js";
5
+ } from "./chunk-ZMZI3625.js";
6
+ import "./chunk-CB44HTTN.js";
7
7
 
8
8
  // src/bin/claude-sbx.ts
9
9
  run(process.argv.slice(2), { harness: "claude" });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-QUHNXHVG.js";
6
- import "./chunk-RSIX7C6D.js";
5
+ } from "./chunk-ZMZI3625.js";
6
+ import "./chunk-CB44HTTN.js";
7
7
 
8
8
  // src/bin/codex-sbx.ts
9
9
  run(process.argv.slice(2), { harness: "codex" });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-QUHNXHVG.js";
6
- import "./chunk-RSIX7C6D.js";
5
+ } from "./chunk-ZMZI3625.js";
6
+ import "./chunk-CB44HTTN.js";
7
7
 
8
8
  // src/bin/gemini-sbx.ts
9
9
  run(process.argv.slice(2), { harness: "gemini" });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-QUHNXHVG.js";
6
- import "./chunk-RSIX7C6D.js";
5
+ } from "./chunk-ZMZI3625.js";
6
+ import "./chunk-CB44HTTN.js";
7
7
 
8
8
  // src/bin/sandbox.ts
9
9
  run(process.argv.slice(2));
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-QUHNXHVG.js";
6
- import "./chunk-RSIX7C6D.js";
5
+ } from "./chunk-ZMZI3625.js";
6
+ import "./chunk-CB44HTTN.js";
7
7
 
8
8
  // src/bin/sbx-hide.ts
9
9
  run(process.argv.slice(2), { command: "hide" });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-QUHNXHVG.js";
6
- import "./chunk-RSIX7C6D.js";
5
+ } from "./chunk-ZMZI3625.js";
6
+ import "./chunk-CB44HTTN.js";
7
7
 
8
8
  // src/bin/sbx-show.ts
9
9
  run(process.argv.slice(2), { command: "show" });
@@ -8,6 +8,7 @@ import { errMsg } from '../../core/util/index.js';
8
8
  import { SandboxChannel } from '../../host/channel/index.js';
9
9
  import { RunDir } from '../../shared/channel/index.js';
10
10
  import { isSandboxRunning } from '../../host/sandbox/index.js';
11
+ import { reloadSettings } from '../../app/context.js';
11
12
  import { lookAtSandbox } from '../commands/shared-use.js';
12
13
  import { commandLine } from '../history.js';
13
14
  import { commandSpec } from '../manifest.js';
@@ -98,7 +99,11 @@ export class Menu {
98
99
  new SettingsPage(app, files, draft, ctx),
99
100
  new AccountsPage(app, ctx),
100
101
  new MaintenancePage(app, ctx),
101
- ], draft, (saved) => this.applyAgentCommands(saved));
102
+ ], draft, (saved) => {
103
+ // Ctrl+S wrote the file: every page and operation reads the new settings from here on.
104
+ reloadSettings(this.ctx);
105
+ return this.applyAgentCommands(saved);
106
+ });
102
107
  }
103
108
  /** Runs the menu until you leave it, or until a command that takes over the terminal (attach) has run. */
104
109
  async start() {
@@ -7,12 +7,16 @@ import { readQuery } from '../../../app/registry.js';
7
7
  import { MenuOperations } from '../io-menu.js';
8
8
  import { menuView } from '../render-view.js';
9
9
  import { ListPage } from './list-page.js';
10
+ /** The services the menu lists: those whose sign-in is written (the others would offer actions that cannot work). */
11
+ function shown(m) {
12
+ return m.services.filter((s) => s.ready);
13
+ }
10
14
  /** The menu's rows, keys and Enter labels of one agent's category. */
11
15
  function viewOf(m, category) {
12
16
  const agent = m.agents.find((a) => a.name === category);
13
17
  if (agent)
14
18
  return menuView(agentPage(agent), { category: agent.name, refresh: false });
15
- const service = m.services.find((s) => serviceCategory(s.kind) === category);
19
+ const service = shown(m).find((s) => serviceCategory(s.kind) === category);
16
20
  if (service)
17
21
  return menuView(servicePage(service), { category: serviceCategory(service.kind), refresh: false });
18
22
  return menuView({ title: 'Accounts', sections: [] }, { refresh: false });
@@ -21,7 +25,7 @@ function viewOf(m, category) {
21
25
  export function accountsOptions(m) {
22
26
  return {
23
27
  path: [],
24
- intro: 'Logins saved on this PC, per agent (Use puts one into the sandbox; new launches start with the default), and the service sign-ins sandboxes may get.',
28
+ intro: 'Logins saved on this PC, per agent, and the service sign-ins sandboxes may get.',
25
29
  categories: [
26
30
  ...m.agents.map((a) => ({
27
31
  id: a.name,
@@ -30,15 +34,15 @@ export function accountsOptions(m) {
30
34
  ? 'Saved ' + a.name + ' logins.'
31
35
  : "This agent's login is not kept between sandboxes: it cannot be pointed at a folder we control.",
32
36
  })),
33
- ...m.services.map((s) => ({
37
+ ...shown(m).map((s) => ({
34
38
  id: serviceCategory(s.kind),
35
39
  label: s.label,
36
- description: 'Your ' + s.label + ' sign-in for sandboxes that use ' + s.usedFor + '.',
40
+ description: 'For ' + s.usedFor + '.',
37
41
  })),
38
42
  ],
39
43
  items: [
40
44
  ...m.agents.flatMap((a) => menuView(agentPage(a), { category: a.name, refresh: false }).items),
41
- ...m.services.flatMap((s) => menuView(servicePage(s), { category: serviceCategory(s.kind), refresh: false }).items),
45
+ ...shown(m).flatMap((s) => menuView(servicePage(s), { category: serviceCategory(s.kind), refresh: false }).items),
42
46
  ],
43
47
  empty: 'No agents.',
44
48
  actions: (category) => viewOf(m, category).actions,
@@ -48,7 +48,7 @@ export const SandboxSchema = z.strictObject({
48
48
  .describe('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.'),
49
49
  pressureResponse: z
50
50
  .boolean()
51
- .describe('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.'),
51
+ .describe('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.'),
52
52
  vGpu: z
53
53
  .boolean()
54
54
  .describe("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)."),
@@ -3,6 +3,7 @@
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { appsToInstall, previewGuideLine } from '../../shared/apps/index.js';
6
+ import { asBackground } from '../../shared/concurrency/index.js';
6
7
  import { downloader, moveIntoPlace, stagingFolder } from '../../shared/download/index.js';
7
8
  import { safeRemove } from '../../shared/io/safe-remove.js';
8
9
  import { dryRun, launchDir } from '../runtime/paths.js';
@@ -28,8 +29,8 @@ const MARKER = '.agent-sandbox-app';
28
29
  function prefetchedFile(entry, fileName) {
29
30
  return path.join(tool('apps', ...entry.id.split('/')) + '.download', fileName.replace(/[\\/:*?"<>|]/g, '_'));
30
31
  }
31
- /** How many apps download and unpack at once (they are big: a few at a time keeps the disk and network busy). */
32
- const PARALLEL = 3;
32
+ /** How many apps unpack at once (as many as the heavy pool holds: more would only queue up behind it). */
33
+ const PARALLEL = 2;
33
34
  export class AppInstaller {
34
35
  env;
35
36
  options;
@@ -53,7 +54,8 @@ export class AppInstaller {
53
54
  !('npm' in e.source) &&
54
55
  e.id !== '7zip' &&
55
56
  (this.options.refresh || !exists(path.join(tool('apps', ...e.id.split('/')), MARKER))));
56
- await Promise.all(todo.map(async (entry) => {
57
+ // Behind the downloads other steps need now (the runtimes, Visual Studio): these only save time for the install.
58
+ await asBackground(() => Promise.all(todo.map(async (entry) => {
57
59
  try {
58
60
  const d = await resolve(entry);
59
61
  const file = prefetchedFile(entry, d.fileName);
@@ -67,7 +69,7 @@ export class AppInstaller {
67
69
  catch {
68
70
  /* the install resolves and downloads again, and reports the reason if it fails too */
69
71
  }
70
- }));
72
+ })));
71
73
  }
72
74
  /** Installs the entries (7-Zip first: the NSIS apps need it to unpack), then their shortcuts. */
73
75
  async installAll(entries) {
@@ -124,7 +126,7 @@ export class AppInstaller {
124
126
  throw new Error(entry.exe + ' not found in the download');
125
127
  await afterInstall(entry, exe);
126
128
  // A proxy or MCP server (agent add-ons) is started by the sandbox or the agent: no PATH entry, no shortcut.
127
- if (!entry.service && (entry.cli || entry.id === 'sysinternals')) {
129
+ if (!entry.service && (entry.cli || entry.onPath || entry.id === 'sysinternals')) {
128
130
  // rustup's rust-analyzer proxy (in cargo's bin folder) only errors until its component is added.
129
131
  if (entry.id === 'rust-analyzer')
130
132
  this.env.prepend.unshift(path.dirname(exe));
@@ -9,7 +9,7 @@ import { installedCometExe } from '../browser/comet.js';
9
9
  import { execAsync } from '../runtime/process.js';
10
10
  import { heavy } from '../../shared/concurrency/index.js';
11
11
  import { mkdirp } from '../runtime/fs.js';
12
- import { signedBy } from '../toolchains/signature.js';
12
+ import { signedByAsync } from '../toolchains/signature.js';
13
13
  /** The archives inside, last stage first: the first one found is opened next. */
14
14
  const INNER = [
15
15
  /^chrome\.7z$/i,
@@ -118,7 +118,7 @@ export async function installFromKept(dest, signer, what) {
118
118
  const installed = installedCometExe();
119
119
  if (fs.existsSync(installed))
120
120
  return installed;
121
- if (!signedBy(installer, signer)) {
121
+ if (!(await signedByAsync(installer, signer))) {
122
122
  fs.rmSync(path.join(dest, '.agent-sandbox-app'), { force: true });
123
123
  fs.rmSync(installer, { force: true });
124
124
  throw new Error(what + "'s installer is not signed by its vendor; deleted it (it is downloaded again next boot)");
@@ -23,6 +23,7 @@ export function buildHeartbeat(snapshot, sessionCount, uptimeSeconds, freeBytes,
23
23
  ...(snapshot?.diskQueue !== null && snapshot?.diskQueue !== undefined
24
24
  ? { diskQueueReported: snapshot.diskQueue }
25
25
  : {}),
26
+ ...(snapshot && snapshot.held > 0 ? { held: Math.min(1024, snapshot.held) } : {}),
26
27
  phase: ending ? 'ending' : sessionCount > 0 ? 'working' : 'ready',
27
28
  };
28
29
  }
@@ -1,12 +1,62 @@
1
1
  import type { PressureStatus } from '../../shared/channel/schema.js';
2
- import type { LoadProfile } from '../../shared/memory/index.js';
2
+ import { z } from 'zod';
3
+ import { type LoadProfile } from '../../shared/memory/index.js';
3
4
  import { type GovernorState, type MemSample } from './decide.js';
5
+ /** memgov.exe's arguments: samples every 2 s and the memory gate for this profile. */
6
+ export declare function memgovArgs(profile: LoadProfile): string[];
7
+ /** What the memory gate in memgov reports on its stdout (one JSON line each). */
8
+ export declare const GateEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
9
+ kind: z.ZodLiteral<"ready">;
10
+ mode: z.ZodEnum<{
11
+ notify: "notify";
12
+ poll: "poll";
13
+ }>;
14
+ growthMb: z.ZodNumber;
15
+ windowMs: z.ZodNumber;
16
+ event: z.ZodLiteral<"gate">;
17
+ at: z.ZodNumber;
18
+ }, z.core.$strict>, z.ZodObject<{
19
+ kind: z.ZodLiteral<"off">;
20
+ reason: z.ZodString;
21
+ event: z.ZodLiteral<"gate">;
22
+ at: z.ZodNumber;
23
+ }, z.core.$strict>, z.ZodObject<{
24
+ kind: z.ZodLiteral<"trip">;
25
+ grewMb: z.ZodNumber;
26
+ ms: z.ZodNumber;
27
+ jobMb: z.ZodNumber;
28
+ held: z.ZodArray<z.ZodObject<{
29
+ pid: z.ZodNumber;
30
+ name: z.ZodString;
31
+ }, z.core.$strict>>;
32
+ event: z.ZodLiteral<"gate">;
33
+ at: z.ZodNumber;
34
+ }, z.core.$strict>, z.ZodObject<{
35
+ kind: z.ZodLiteral<"hold">;
36
+ pid: z.ZodNumber;
37
+ name: z.ZodString;
38
+ event: z.ZodLiteral<"gate">;
39
+ at: z.ZodNumber;
40
+ }, z.core.$strict>, z.ZodObject<{
41
+ kind: z.ZodLiteral<"release">;
42
+ pid: z.ZodNumber;
43
+ name: z.ZodString;
44
+ heldMs: z.ZodNumber;
45
+ forced: z.ZodBoolean;
46
+ event: z.ZodLiteral<"gate">;
47
+ at: z.ZodNumber;
48
+ }, z.core.$strict>], "kind">;
49
+ export type GateEvent = z.output<typeof GateEventSchema>;
50
+ /** One memory-log line for a gate event (names cut to 64 characters). */
51
+ export declare function gateLine(e: GateEvent): string;
4
52
  /** The newest numbers the governor saw (for the heartbeat file). */
5
53
  export interface GovernorSnapshot {
6
54
  readonly ramFreePercent: number;
7
55
  readonly commitPercent: number;
8
56
  readonly step: number;
9
57
  readonly hostStep: number;
58
+ /** Build programs the memory gate holds now. */
59
+ readonly held: number;
10
60
  readonly diskQueue: number | null;
11
61
  readonly top: readonly {
12
62
  readonly name: string;
@@ -57,6 +107,8 @@ export declare class GovernorCore {
57
107
  get snapshot(): GovernorSnapshot | null;
58
108
  get current(): GovernorState;
59
109
  onSample(sample: MemSample): void;
110
+ /** An event from the memory gate in memgov: goes to the memory log. */
111
+ onGate(event: GateEvent): void;
60
112
  private apply;
61
113
  private note;
62
114
  }