windows-development-sandbox 1.10.0 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +64 -17
  2. package/config.example.json +5 -1
  3. package/dist/app/features/accounts/accounts.def.d.ts +122 -0
  4. package/dist/app/features/accounts/accounts.def.js +243 -0
  5. package/dist/app/features/accounts/accounts.run.d.ts +51 -0
  6. package/dist/app/features/accounts/accounts.run.js +125 -0
  7. package/dist/app/features/accounts/index.d.ts +2 -0
  8. package/dist/app/features/accounts/index.js +3 -0
  9. package/dist/app/features/agents/agent-entry.d.ts +17 -0
  10. package/dist/app/features/agents/agent-entry.js +50 -0
  11. package/dist/app/features/agents/agents.def.d.ts +65 -0
  12. package/dist/app/features/agents/agents.def.js +142 -0
  13. package/dist/app/features/agents/agents.run.d.ts +31 -0
  14. package/dist/app/features/agents/agents.run.js +189 -0
  15. package/dist/app/features/agents/index.d.ts +3 -0
  16. package/dist/app/features/agents/index.js +4 -0
  17. package/dist/app/features/apps/apps-rows.d.ts +31 -0
  18. package/dist/app/features/apps/apps-rows.js +73 -0
  19. package/dist/app/features/apps/apps.def.d.ts +181 -0
  20. package/dist/app/features/apps/apps.def.js +264 -0
  21. package/dist/app/features/apps/apps.run.d.ts +58 -0
  22. package/dist/app/features/apps/apps.run.js +76 -0
  23. package/dist/app/features/apps/index.d.ts +3 -0
  24. package/dist/app/features/apps/index.js +4 -0
  25. package/dist/app/features/data/data.def.d.ts +154 -0
  26. package/dist/app/features/data/data.def.js +201 -0
  27. package/dist/app/features/data/data.run.d.ts +46 -0
  28. package/dist/app/features/data/data.run.js +141 -0
  29. package/dist/app/features/data/index.d.ts +2 -0
  30. package/dist/app/features/data/index.js +3 -0
  31. package/dist/app/features/defs.d.ts +952 -4
  32. package/dist/app/features/defs.js +147 -10
  33. package/dist/app/features/engine/engine.def.d.ts +228 -0
  34. package/dist/app/features/engine/engine.def.js +194 -0
  35. package/dist/app/features/engine/engine.run.d.ts +72 -0
  36. package/dist/app/features/engine/engine.run.js +77 -0
  37. package/dist/app/features/engine/index.d.ts +2 -0
  38. package/dist/app/features/engine/index.js +4 -0
  39. package/dist/app/features/files/files.def.d.ts +51 -0
  40. package/dist/app/features/files/files.def.js +38 -0
  41. package/dist/app/features/files/files.run.d.ts +20 -0
  42. package/dist/app/features/files/files.run.js +59 -0
  43. package/dist/app/features/files/index.d.ts +2 -0
  44. package/dist/app/features/files/index.js +3 -0
  45. package/dist/app/features/github/github.def.d.ts +80 -0
  46. package/dist/app/features/github/github.def.js +142 -0
  47. package/dist/app/features/github/github.run.d.ts +36 -0
  48. package/dist/app/features/github/github.run.js +59 -0
  49. package/dist/app/features/github/index.d.ts +2 -0
  50. package/dist/app/features/github/index.js +3 -0
  51. package/dist/app/features/health/health.def.d.ts +275 -0
  52. package/dist/app/features/health/health.def.js +281 -0
  53. package/dist/app/features/health/health.run.d.ts +125 -0
  54. package/dist/app/features/health/health.run.js +204 -0
  55. package/dist/app/features/health/index.d.ts +2 -0
  56. package/dist/app/features/health/index.js +3 -0
  57. package/dist/app/features/logs/index.d.ts +2 -0
  58. package/dist/app/features/logs/index.js +3 -0
  59. package/dist/app/features/logs/logs.def.d.ts +78 -0
  60. package/dist/app/features/logs/logs.def.js +115 -0
  61. package/dist/app/features/logs/logs.run.d.ts +20 -0
  62. package/dist/app/features/logs/logs.run.js +42 -0
  63. package/dist/app/features/projects/index.d.ts +2 -0
  64. package/dist/app/features/projects/index.js +3 -0
  65. package/dist/app/features/projects/projects.def.d.ts +101 -0
  66. package/dist/app/features/projects/projects.def.js +208 -0
  67. package/dist/app/features/projects/projects.run.d.ts +56 -0
  68. package/dist/app/features/projects/projects.run.js +155 -0
  69. package/dist/app/features/sandbox/sandbox.def.js +11 -5
  70. package/dist/app/features/sessions/sessions.def.js +3 -0
  71. package/dist/app/features/settings/categories.def.js +3 -2
  72. package/dist/{cli/menu/settings/share.d.ts → app/features/settings/settings-share.d.ts} +1 -1
  73. package/dist/{cli/menu/settings/share.js → app/features/settings/settings-share.js} +3 -2
  74. package/dist/app/features/settings/settings.def.d.ts +22 -5
  75. package/dist/app/features/settings/settings.def.js +81 -6
  76. package/dist/app/features/settings/settings.run.d.ts +17 -0
  77. package/dist/app/features/settings/settings.run.js +89 -4
  78. package/dist/app/features/storage/index.d.ts +2 -0
  79. package/dist/app/features/storage/index.js +3 -0
  80. package/dist/app/features/storage/storage.def.d.ts +133 -0
  81. package/dist/app/features/storage/storage.def.js +225 -0
  82. package/dist/app/features/storage/storage.run.d.ts +62 -0
  83. package/dist/app/features/storage/storage.run.js +370 -0
  84. package/dist/app/features/updates/index.d.ts +3 -0
  85. package/dist/app/features/updates/index.js +4 -0
  86. package/dist/app/features/updates/update-lines.d.ts +13 -0
  87. package/dist/app/features/updates/update-lines.js +61 -0
  88. package/dist/app/features/updates/updates.def.d.ts +89 -0
  89. package/dist/app/features/updates/updates.def.js +225 -0
  90. package/dist/app/features/updates/updates.run.d.ts +48 -0
  91. package/dist/app/features/updates/updates.run.js +154 -0
  92. package/dist/app/features/vpn/index.d.ts +2 -0
  93. package/dist/app/features/vpn/index.js +3 -0
  94. package/dist/app/features/vpn/vpn.def.d.ts +112 -0
  95. package/dist/app/features/vpn/vpn.def.js +174 -0
  96. package/dist/app/features/vpn/vpn.run.d.ts +37 -0
  97. package/dist/app/features/vpn/vpn.run.js +54 -0
  98. package/dist/app/features/web/index.d.ts +2 -0
  99. package/dist/app/features/web/index.js +3 -0
  100. package/dist/app/features/web/web.def.d.ts +33 -0
  101. package/dist/app/features/web/web.def.js +90 -0
  102. package/dist/app/features/web/web.run.d.ts +24 -0
  103. package/dist/app/features/web/web.run.js +93 -0
  104. package/dist/app/kernel/define.d.ts +10 -1
  105. package/dist/app/kernel/io.d.ts +34 -0
  106. package/dist/app/kernel/io.js +9 -0
  107. package/dist/app/kernel/rpc.d.ts +17 -0
  108. package/dist/app/kernel/text.d.ts +2 -0
  109. package/dist/app/kernel/text.js +7 -0
  110. package/dist/app/kernel/view.d.ts +24 -1
  111. package/dist/app/kernel/view.js +1 -1
  112. package/dist/app/registry.js +74 -1
  113. package/dist/cli/args.js +1 -1
  114. package/dist/cli/commands/context.d.ts +7 -0
  115. package/dist/cli/commands/context.js +29 -2
  116. package/dist/cli/commands/engine.js +5 -58
  117. package/dist/cli/commands/github.d.ts +2 -0
  118. package/dist/cli/commands/github.js +11 -0
  119. package/dist/cli/commands/index.d.ts +3 -5
  120. package/dist/cli/commands/index.js +3 -5
  121. package/dist/cli/commands/launch/launch.js +21 -4
  122. package/dist/cli/commands/launch/running.js +4 -1
  123. package/dist/cli/commands/maintenance/config.js +1 -6
  124. package/dist/cli/commands/maintenance/index.d.ts +0 -1
  125. package/dist/cli/commands/maintenance/index.js +1 -2
  126. package/dist/cli/commands/maintenance/logs.js +27 -32
  127. package/dist/cli/commands/maintenance/migrate.d.ts +0 -8
  128. package/dist/cli/commands/maintenance/migrate.js +2 -44
  129. package/dist/cli/commands/maintenance/update.d.ts +0 -19
  130. package/dist/cli/commands/maintenance/update.js +1 -99
  131. package/dist/cli/commands/projects/index.d.ts +0 -1
  132. package/dist/cli/commands/projects/index.js +0 -1
  133. package/dist/cli/commands/registry.d.ts +1 -1
  134. package/dist/cli/commands/registry.js +29 -11
  135. package/dist/cli/commands/repair/checks/data.js +1 -1
  136. package/dist/cli/commands/repair/checks/hcs.js +28 -1
  137. package/dist/cli/commands/repair/checks/sandbox.js +1 -1
  138. package/dist/cli/commands/repair/health-run.d.ts +30 -0
  139. package/dist/cli/commands/repair/health-run.js +32 -0
  140. package/dist/cli/commands/repair/printer.d.ts +2 -2
  141. package/dist/cli/commands/repair/printer.js +2 -11
  142. package/dist/cli/commands/repair/run.d.ts +1 -21
  143. package/dist/cli/commands/repair/run.js +13 -70
  144. package/dist/cli/commands/storage/index.d.ts +0 -1
  145. package/dist/cli/commands/storage/index.js +0 -1
  146. package/dist/cli/commands/storage/offer.js +6 -2
  147. package/dist/cli/commands/vpn.d.ts +1 -3
  148. package/dist/cli/commands/vpn.js +8 -89
  149. package/dist/cli/commands/web.d.ts +2 -1
  150. package/dist/cli/commands/web.js +14 -78
  151. package/dist/cli/index.js +3 -2
  152. package/dist/cli/manifest.d.ts +16 -153
  153. package/dist/cli/manifest.js +20 -50
  154. package/dist/cli/menu/command-form.js +1 -2
  155. package/dist/cli/menu/io-menu.d.ts +2 -2
  156. package/dist/cli/menu/io-menu.js +6 -4
  157. package/dist/cli/menu/menu.js +1 -1
  158. package/dist/cli/menu/pages/accounts-page.d.ts +5 -17
  159. package/dist/cli/menu/pages/accounts-page.js +28 -170
  160. package/dist/cli/menu/pages/agents-page.d.ts +17 -18
  161. package/dist/cli/menu/pages/agents-page.js +67 -124
  162. package/dist/cli/menu/pages/apps-page.d.ts +15 -8
  163. package/dist/cli/menu/pages/apps-page.js +121 -29
  164. package/dist/cli/menu/pages/list-page.js +10 -1
  165. package/dist/cli/menu/pages/maintenance-page.d.ts +51 -52
  166. package/dist/cli/menu/pages/maintenance-page.js +246 -427
  167. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -5
  168. package/dist/cli/menu/pages/sandbox-page.js +34 -112
  169. package/dist/cli/menu/pages/settings-page.d.ts +21 -3
  170. package/dist/cli/menu/pages/settings-page.js +89 -17
  171. package/dist/cli/menu/render-view.js +2 -1
  172. package/dist/cli/menu/settings/index.d.ts +0 -1
  173. package/dist/cli/menu/settings/index.js +3 -3
  174. package/dist/cli/menu/views.js +28 -0
  175. package/dist/cli/operations/handler.js +7 -3
  176. package/dist/cli/operations/input.d.ts +1 -1
  177. package/dist/cli/operations/input.js +29 -5
  178. package/dist/cli/operations/io-cli.js +9 -1
  179. package/dist/cli/operations/spec.js +8 -2
  180. package/dist/cli/output/render-view.js +2 -0
  181. package/dist/cli/{commands/data/collect.js → services/data-collect.js} +2 -2
  182. package/dist/cli/{commands/data/remove.js → services/data-remove.js} +2 -2
  183. package/dist/cli/services/data-service.d.ts +1 -1
  184. package/dist/cli/services/data-service.js +2 -2
  185. package/dist/cli/services/databases-service.d.ts +5 -0
  186. package/dist/cli/services/databases-service.js +15 -0
  187. package/dist/cli/services/health-service.d.ts +8 -4
  188. package/dist/cli/services/health-service.js +10 -8
  189. package/dist/cli/services/index.d.ts +4 -1
  190. package/dist/cli/services/index.js +4 -1
  191. package/dist/cli/services/logs-service.d.ts +7 -0
  192. package/dist/cli/services/logs-service.js +13 -0
  193. package/dist/cli/services/storage-service.d.ts +19 -0
  194. package/dist/cli/services/storage-service.js +71 -0
  195. package/dist/cli/services/vpn-service.d.ts +6 -4
  196. package/dist/cli/services/vpn-service.js +5 -11
  197. package/dist/cli/services/web-service.d.ts +4 -3
  198. package/dist/cli/services/web-service.js +12 -32
  199. package/dist/core/config/defaults.js +2 -1
  200. package/dist/core/schema/config.d.ts +5 -0
  201. package/dist/core/schema/config.js +2 -0
  202. package/dist/core/schema/github.d.ts +4 -0
  203. package/dist/core/schema/github.js +7 -0
  204. package/dist/core/schema/index.d.ts +1 -0
  205. package/dist/core/schema/index.js +1 -0
  206. package/dist/core/schema/profile.d.ts +1 -0
  207. package/dist/core/schema/profile.js +3 -0
  208. package/dist/core/schema/sandbox.js +3 -3
  209. package/dist/core/schema/toolchains.js +2 -2
  210. package/dist/core/types.d.ts +6 -3
  211. package/dist/guest/boot/boot.js +8 -0
  212. package/dist/guest/daemon/daemon.js +1 -1
  213. package/dist/guest/daemon/sessions.d.ts +3 -2
  214. package/dist/guest/daemon/sessions.js +38 -7
  215. package/dist/guest/governor/core.d.ts +44 -0
  216. package/dist/guest/governor/core.js +124 -0
  217. package/dist/guest/governor/decide.d.ts +46 -18
  218. package/dist/guest/governor/decide.js +136 -82
  219. package/dist/guest/governor/governor.d.ts +2 -38
  220. package/dist/guest/governor/governor.js +33 -113
  221. package/dist/guest/governor/index.d.ts +1 -0
  222. package/dist/guest/governor/index.js +1 -0
  223. package/dist/guest/network/firewall.d.ts +2 -0
  224. package/dist/guest/network/firewall.js +3 -3
  225. package/dist/guest/sessions/viewer.js +5 -1
  226. package/dist/guest/setup/github-token.d.ts +7 -0
  227. package/dist/guest/setup/github-token.js +65 -0
  228. package/dist/guest/toolchains/languages/node.js +11 -1
  229. package/dist/guest/toolchains/native/rust-extras.js +2 -2
  230. package/dist/guest/toolchains/tools/cli.d.ts +8 -0
  231. package/dist/guest/toolchains/tools/cli.js +16 -2
  232. package/dist/guest/vpn/openvpn.d.ts +5 -0
  233. package/dist/guest/vpn/openvpn.js +14 -1
  234. package/dist/guest/vpn/vpn.js +55 -16
  235. package/dist/guest/vpn/wireguard.js +2 -0
  236. package/dist/host/channel/attach.d.ts +1 -0
  237. package/dist/host/channel/attach.js +1 -0
  238. package/dist/host/channel/channel.d.ts +1 -1
  239. package/dist/host/channel/channel.js +2 -2
  240. package/dist/host/engines/hcs/check.d.ts +1 -0
  241. package/dist/host/engines/hcs/check.js +1 -1
  242. package/dist/host/engines/hcs/engine.d.ts +1 -1
  243. package/dist/host/engines/hcs/engine.js +6 -4
  244. package/dist/host/engines/hcs/helper.d.ts +11 -0
  245. package/dist/host/engines/hcs/helper.js +31 -2
  246. package/dist/host/engines/hcs/leftovers.d.ts +42 -0
  247. package/dist/host/engines/hcs/leftovers.js +101 -0
  248. package/dist/host/engines/index.d.ts +1 -0
  249. package/dist/host/engines/index.js +1 -0
  250. package/dist/host/github/deliver.d.ts +13 -0
  251. package/dist/host/github/deliver.js +51 -0
  252. package/dist/host/github/index.d.ts +2 -0
  253. package/dist/host/github/index.js +3 -0
  254. package/dist/host/github/token.d.ts +21 -0
  255. package/dist/host/github/token.js +74 -0
  256. package/dist/host/launch/generate.js +11 -5
  257. package/dist/host/launch/index.d.ts +1 -1
  258. package/dist/host/launch/index.js +1 -1
  259. package/dist/host/launch/session-file.js +1 -2
  260. package/dist/host/launch/wsb-file.d.ts +11 -7
  261. package/dist/host/launch/wsb-file.js +30 -12
  262. package/dist/host/life/watchdog.d.ts +9 -0
  263. package/dist/host/life/watchdog.js +17 -1
  264. package/dist/host/sandbox/tasklist.d.ts +6 -0
  265. package/dist/host/sandbox/tasklist.js +37 -0
  266. package/dist/host/secrets/launch-secrets.d.ts +2 -1
  267. package/dist/host/secrets/launch-secrets.js +4 -2
  268. package/dist/host/vpn/status.js +13 -3
  269. package/dist/host/web/backend.d.ts +1 -3
  270. package/dist/host/web/index.d.ts +2 -1
  271. package/dist/host/web/index.js +2 -1
  272. package/dist/host/web/live.d.ts +23 -0
  273. package/dist/host/web/live.js +107 -0
  274. package/dist/host/web/rpc.d.ts +6 -1
  275. package/dist/host/web/rpc.js +23 -31
  276. package/dist/host/web/runner.d.ts +4 -0
  277. package/dist/host/web/runner.js +12 -1
  278. package/dist/host/web/server.d.ts +30 -2
  279. package/dist/host/web/server.js +87 -29
  280. package/dist/host/web/state.d.ts +1 -0
  281. package/dist/host/web/state.js +2 -0
  282. package/dist/runtime/agent.js +30 -6
  283. package/dist/runtime/daemon.js +323 -176
  284. package/dist/runtime/db.js +30 -6
  285. package/dist/runtime/main.js +375 -76
  286. package/dist/runtime/netproxy.js +30 -6
  287. package/dist/runtime/view.js +495 -146
  288. package/dist/selftest/app.test.js +620 -12
  289. package/dist/selftest/channel.test.js +18 -1
  290. package/dist/selftest/cli.test.js +1 -1
  291. package/dist/selftest/config.test.js +1 -1
  292. package/dist/selftest/contained.test.js +1 -1
  293. package/dist/selftest/data.test.js +1 -2
  294. package/dist/selftest/engine.test.js +3 -1
  295. package/dist/selftest/github.test.d.ts +2 -0
  296. package/dist/selftest/github.test.js +243 -0
  297. package/dist/selftest/hcs.test.js +105 -8
  298. package/dist/selftest/health.test.js +71 -0
  299. package/dist/selftest/heavy-load.test.js +132 -72
  300. package/dist/selftest/index.js +4 -0
  301. package/dist/selftest/layout.test.js +8 -0
  302. package/dist/selftest/live-terminal.test.js +74 -0
  303. package/dist/selftest/menu-screens.js +171 -56
  304. package/dist/selftest/menu.test.js +54 -37
  305. package/dist/selftest/migrate.test.js +14 -12
  306. package/dist/selftest/powershell-variables.test.d.ts +2 -0
  307. package/dist/selftest/powershell-variables.test.js +61 -0
  308. package/dist/selftest/support/engine-golden.js +1 -0
  309. package/dist/selftest/support/fixtures.d.ts +4 -0
  310. package/dist/selftest/support/web-preview.d.ts +1 -0
  311. package/dist/selftest/support/web-preview.js +856 -0
  312. package/dist/selftest/update-service.test.js +15 -8
  313. package/dist/selftest/vpn.test.js +86 -2
  314. package/dist/selftest/web.test.js +58 -11
  315. package/dist/shared/channel/run-dir.d.ts +2 -0
  316. package/dist/shared/channel/run-dir.js +3 -0
  317. package/dist/shared/channel/schema.d.ts +7 -0
  318. package/dist/shared/channel/schema.js +9 -1
  319. package/dist/shared/channel/secrets.d.ts +1 -0
  320. package/dist/shared/channel/secrets.js +3 -0
  321. package/dist/shared/github/index.d.ts +1 -0
  322. package/dist/shared/github/index.js +2 -0
  323. package/dist/shared/github/token.d.ts +29 -0
  324. package/dist/shared/github/token.js +89 -0
  325. package/dist/shared/memory/policy.d.ts +33 -12
  326. package/dist/shared/memory/policy.js +50 -19
  327. package/dist/shared/pty/ctrl-c.d.ts +18 -0
  328. package/dist/shared/pty/ctrl-c.js +36 -0
  329. package/dist/shared/pty/index.d.ts +1 -0
  330. package/dist/shared/pty/index.js +1 -0
  331. package/dist/shared/pty/terminal.d.ts +2 -0
  332. package/dist/shared/pty/terminal.js +21 -2
  333. package/dist/shared/vpn/kill-switch.d.ts +13 -2
  334. package/dist/shared/vpn/kill-switch.js +88 -8
  335. package/dist/shared/web/protocol.d.ts +0 -4
  336. package/dist/sync/watcher.js +1 -1
  337. package/dist/web/index.html +2 -2
  338. package/dist/web/{main-T5DMCHYV.css → main-6JF3ASB5.css} +1 -1
  339. package/dist/web/main-Z645W45E.js +219 -0
  340. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  341. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  342. package/package.json +10 -3
  343. package/sandbox/csharp/MemGov.cs +240 -38
  344. package/sandbox/csharp/PtyHost.cs +104 -15
  345. package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
  346. package/sandbox/csharp/SandboxTools/Program.cs +1 -1
  347. package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
  348. package/schemas/config.schema.json +19 -5
  349. package/schemas/sandbox-config.schema.json +7 -3
  350. package/dist/cli/commands/accounts.d.ts +0 -2
  351. package/dist/cli/commands/accounts.js +0 -96
  352. package/dist/cli/commands/data/clean.d.ts +0 -3
  353. package/dist/cli/commands/data/clean.js +0 -60
  354. package/dist/cli/commands/data/index.d.ts +0 -4
  355. package/dist/cli/commands/data/index.js +0 -62
  356. package/dist/cli/commands/maintenance/clean.d.ts +0 -2
  357. package/dist/cli/commands/maintenance/clean.js +0 -24
  358. package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
  359. package/dist/cli/commands/maintenance/config-share.js +0 -80
  360. package/dist/cli/commands/projects/projects.d.ts +0 -2
  361. package/dist/cli/commands/projects/projects.js +0 -162
  362. package/dist/cli/commands/storage/contained.d.ts +0 -3
  363. package/dist/cli/commands/storage/contained.js +0 -179
  364. package/dist/cli/commands/storage/storage.d.ts +0 -8
  365. package/dist/cli/commands/storage/storage.js +0 -179
  366. package/dist/cli/menu/add-agent.d.ts +0 -47
  367. package/dist/cli/menu/add-agent.js +0 -168
  368. package/dist/cli/menu/apps.d.ts +0 -69
  369. package/dist/cli/menu/apps.js +0 -214
  370. package/dist/cli/menu/data-folder.d.ts +0 -18
  371. package/dist/cli/menu/data-folder.js +0 -99
  372. package/dist/cli/menu/share-settings.d.ts +0 -21
  373. package/dist/cli/menu/share-settings.js +0 -112
  374. package/dist/cli/menu/vpn-login.d.ts +0 -16
  375. package/dist/cli/menu/vpn-login.js +0 -74
  376. package/dist/web/main-NRRS5O6Z.js +0 -157
  377. /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
  378. /package/dist/cli/{commands/data/remove.d.ts → services/data-remove.d.ts} +0 -0
@@ -86,6 +86,9 @@ export declare const ConfigSchema: z.ZodObject<{
86
86
  configFile: z.ZodString;
87
87
  killSwitch: z.ZodBoolean;
88
88
  }, z.core.$strict>;
89
+ github: z.ZodObject<{
90
+ shareToken: z.ZodBoolean;
91
+ }, z.core.$strict>;
89
92
  provisioning: z.ZodObject<{
90
93
  copyFromHost: z.ZodBoolean;
91
94
  fallbackToInstall: z.ZodBoolean;
@@ -243,6 +246,7 @@ export declare const ConfigSchema: z.ZodObject<{
243
246
  reuseSession: z.ZodBoolean;
244
247
  auto: z.ZodBoolean;
245
248
  autoHide: z.ZodBoolean;
249
+ confirmCtrlC: z.ZodBoolean;
246
250
  }, z.core.$strict>;
247
251
  web: z.ZodObject<{
248
252
  enabled: z.ZodBoolean;
@@ -699,6 +703,7 @@ export declare const LocalOverridesSchema: z.ZodObject<{
699
703
  reuseSession: z.ZodOptional<z.ZodBoolean>;
700
704
  auto: z.ZodOptional<z.ZodBoolean>;
701
705
  autoHide: z.ZodOptional<z.ZodBoolean>;
706
+ confirmCtrlC: z.ZodOptional<z.ZodBoolean>;
702
707
  }, z.core.$strict>>;
703
708
  personalization: z.ZodOptional<z.ZodObject<{
704
709
  enabled: z.ZodOptional<z.ZodBoolean>;
@@ -13,6 +13,7 @@ import { ProjectsSchema } from './projects.js';
13
13
  import { ResumeSchema } from './resume.js';
14
14
  import { WebSchema } from './web.js';
15
15
  import { VpnSchema } from './vpn.js';
16
+ import { GithubSchema } from './github.js';
16
17
  export const ConfigSchema = z
17
18
  .strictObject({
18
19
  $schema: SchemaRefSchema.optional(),
@@ -50,6 +51,7 @@ export const ConfigSchema = z
50
51
  }),
51
52
  network: NetworkSchema,
52
53
  vpn: VpnSchema,
54
+ github: GithubSchema,
53
55
  provisioning: ProvisioningSchema,
54
56
  downloads: DownloadsSchema,
55
57
  toolchains: ToolchainsSchema,
@@ -0,0 +1,4 @@
1
+ import { z } from 'zod';
2
+ export declare const GithubSchema: z.ZodObject<{
3
+ shareToken: z.ZodBoolean;
4
+ }, z.core.$strict>;
@@ -0,0 +1,7 @@
1
+ // The GitHub setting (the token itself is not a setting: it is kept encrypted by `sandbox github login`).
2
+ import { z } from 'zod';
3
+ export const GithubSchema = z.strictObject({
4
+ shareToken: z
5
+ .boolean()
6
+ .describe('Give each sandbox the GitHub token you saved with `sandbox github login` (best a fine-grained token limited to some repositories and permissions), so gh and https git work there without logging in. Only with provisioning.git.access "full". The agent in the sandbox can read the token and use it for whatever it allows. A project file (.sandbox-config.json) cannot turn this on.'),
7
+ });
@@ -5,4 +5,5 @@ export { HarnessSchema } from './harness.js';
5
5
  export { describeIssues, jsonSchemas } from './json-schema.js';
6
6
  export { MappingSchema } from './sandbox.js';
7
7
  export { ToolchainsSchema } from './toolchains.js';
8
+ export { GithubSchema } from './github.js';
8
9
  export { VpnSchema, VPN_PROVIDERS, type VpnProvider } from './vpn.js';
@@ -7,4 +7,5 @@ export { HarnessSchema } from './harness.js';
7
7
  export { describeIssues, jsonSchemas } from './json-schema.js';
8
8
  export { MappingSchema } from './sandbox.js';
9
9
  export { ToolchainsSchema } from './toolchains.js';
10
+ export { GithubSchema } from './github.js';
10
11
  export { VpnSchema, VPN_PROVIDERS } from './vpn.js';
@@ -10,6 +10,7 @@ export declare const AttachSchema: z.ZodObject<{
10
10
  reuseSession: z.ZodBoolean;
11
11
  auto: z.ZodBoolean;
12
12
  autoHide: z.ZodBoolean;
13
+ confirmCtrlC: z.ZodBoolean;
13
14
  }, z.core.$strict>;
14
15
  export declare const AgentCommandsSchema: z.ZodObject<{
15
16
  enabled: z.ZodBoolean;
@@ -22,6 +22,9 @@ export const AttachSchema = z.strictObject({
22
22
  autoHide: z
23
23
  .boolean()
24
24
  .describe('Hide the Windows Sandbox window whenever this terminal attaches; it keeps running (sandbox show brings it back).'),
25
+ confirmCtrlC: z
26
+ .boolean()
27
+ .describe('In an attached terminal and the sandbox window, a single Ctrl+C is held back (the title says so) and only a second one within 1.5 seconds reaches the agent: a Ctrl+C meant as "copy" no longer stops it. Esc still stops an agent.'),
25
28
  });
26
29
  export const AgentCommandsSchema = z.strictObject({
27
30
  enabled: z
@@ -21,7 +21,7 @@ export const SandboxSchema = z.strictObject({
21
21
  .describe('(alpha) What runs the sandbox. "windows-sandbox" = Windows Sandbox (the default: desktop, Windows Terminal, GPU, clipboard, audio, printers). "hcs" = a headless Hyper-V isolated Server Core container for agents (no desktop, GPU or clipboard); it needs Windows features and an image on this PC (sandbox engine check hcs lists what is missing), and starting it is not enabled yet in this alpha. sandbox engine shows what each engine can do. Yours only: a project file (.sandbox-config.json) cannot set it.'),
22
22
  memoryMb: z
23
23
  .union([z.literal('auto'), z.number().int().min(2048)])
24
- .describe('Sandbox RAM in MB (>= 2048), or "auto": free RAM minus reserveHostMb, capped at maxMemoryMb.'),
24
+ .describe('Sandbox RAM in MB (>= 2048), or "auto": free RAM minus reserveHostMb, capped at maxMemoryMb. Never more than this PC can keep in RAM for it (its RAM minus the larger of reserveHostMb and 25 %, 2 GB more with vGPU): a bigger value is lowered.'),
25
25
  maxMemoryMb: z.number().int().positive().describe('Upper limit for memoryMb "auto".'),
26
26
  maxMemoryPercent: z
27
27
  .number()
@@ -45,10 +45,10 @@ export const SandboxSchema = z.strictObject({
45
45
  .describe('Memory always left for this PC when memoryMb is "auto": the sandbox gets at most (free RAM, and RAM plus paging file still unused) minus this.'),
46
46
  agentMemoryHeadroomMb: z
47
47
  .union([z.literal('auto'), z.literal('none'), z.number().int().min(0)])
48
- .describe('Memory kept out of the agents reach inside the sandbox, in MB: everything the agents start (their builds, tests, tools) together may use at most the sandbox memory minus this; a runaway parallel build then gets out-of-memory errors in its own session instead of freezing or crashing the whole sandbox. "auto" = the larger of 2048 MB and 10 % of the sandbox memory; "none" = no limit. Yours only: a project file cannot change it.'),
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 the heaviest build programs down (lower priority) and, if that is not enough, pause the biggest compiler for a few seconds at a time, so heavy parallel builds slow down instead of closing the sandbox. Never touches the agents themselves. 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. 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)."),
@@ -43,7 +43,7 @@ export const ToolchainsSchema = z.strictObject({
43
43
  .describe('GNU host: "lld" links with Rust\'s own lld through MinGW\'s gcc (much less memory than GNU ld), "gnu" with GNU ld.'),
44
44
  linkSlots: z
45
45
  .union([z.literal('auto'), z.number().int().min(1).max(32)])
46
- .describe('GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per 8 GB of sandbox memory, 2 to 4. Several agents linking big programs at once can take Windows down.'),
46
+ .describe('GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per 3 GB of sandbox memory after 6 GB, 2 to 8 (the memory governor slows links down too when memory runs short).'),
47
47
  }),
48
48
  msvc: z.strictObject({
49
49
  enabled: enabled("MSVC (cl, link) and the Windows SDK, portable from Microsoft's Visual Studio manifest (~1-2 GB once), with vcvars64.bat and vswhere.", 'a .vcxproj, CMakePresets.json, a script calling vcvars/vswhere, or a Rust project when this PC builds Rust with MSVC'),
@@ -102,7 +102,7 @@ export const ToolchainsSchema = z.strictObject({
102
102
  }),
103
103
  cli: z
104
104
  .strictObject({
105
- gh: EnabledSchema.describe('GitHub CLI (gh). Only with provisioning.git.access "full": gh can push and merge through the GitHub API, past a read-only git. Your PC\'s gh login is never copied; `gh auth login` inside persists (GH_CONFIG_DIR). "auto" = when the project has a .github folder.'),
105
+ gh: EnabledSchema.describe('GitHub CLI (gh). Only with provisioning.git.access "full": gh can push and merge through the GitHub API, past a read-only git. Your PC\'s gh login is never copied; `gh auth login` inside persists (GH_CONFIG_DIR), unless a token you saved for sandboxes is handed over (github.shareToken). "auto" = when the project has a .github folder.'),
106
106
  zstd: EnabledSchema.describe('Zstandard (zstd). "auto" = off; set true to get it.'),
107
107
  openssl: EnabledSchema.describe('`openssl` on PATH, from the copy Git for Windows ships (its mingw64\\bin is not put on PATH, so it cannot shadow MinGW\'s gcc). "auto" = on.'),
108
108
  })
@@ -141,6 +141,8 @@ export interface GenerateOptions {
141
141
  };
142
142
  /** The VPN for this launch (vpn.enabled); its profile goes in the launch folder, its login in the one-shot file. */
143
143
  vpn?: PreparedVpn;
144
+ /** The saved GitHub token (github.shareToken, host/github/deliver.ts): only ever written to the one-shot file. */
145
+ githubToken?: string;
144
146
  /** The data set's mappings from a storage provider (contained storage); else the data folder is one mapping. */
145
147
  dataMappings?: ResolvedMapping[];
146
148
  }
@@ -263,10 +265,11 @@ export interface GuestSession {
263
265
  /** sandbox.pageFileMb (0 = Windows' own); sandbox\scripts\set-page-file.ps1 applies it at logon. */
264
266
  pageFileMb?: number;
265
267
  /**
266
- * sandbox.agentMemoryHeadroomMb as a limit: the most memory (MB) everything the agents start may use together
267
- * (the sandbox's memory minus the headroom); null = no limit. ptyhost puts each agent in a job object with it.
268
+ * sandbox.agentMemoryHeadroomMb: how far below the sandbox's commit limit the last-resort backstop of the agents'
269
+ * job sits ("auto", MB, or "none"). ptyhost reads the commit limit in the sandbox and sets it once, on the job it
270
+ * creates.
268
271
  */
269
- agentMemoryLimitMb?: number | null;
272
+ agentBackstop?: 'auto' | 'none' | number;
270
273
  /** "gentle" when vGPU is on: the governor and the watchdog act earlier, compilers run below normal. */
271
274
  loadProfile?: 'normal' | 'gentle';
272
275
  /** sandbox.pressureResponse: the daemon slows builds down when memory runs low. */
@@ -18,6 +18,7 @@ import { applyNetworkPolicy, networkProblems } from '../network/firewall.js';
18
18
  import { writeManagedSettings } from '../setup/managed-policy.js';
19
19
  import { applyPersonalization } from '../setup/desktop.js';
20
20
  import { setupGitConfig } from '../setup/git-identity.js';
21
+ import { loginGithub, prepareGithubFolder } from '../setup/github-token.js';
21
22
  import { ensurePtyHost } from '../sessions/pty-host.js';
22
23
  import { pruneToolLeftovers } from '../toolchains/leftovers.js';
23
24
  import { wanted } from '../toolchains/detect.js';
@@ -137,6 +138,7 @@ export class Boot {
137
138
  mkdirp(run.root);
138
139
  this.secrets = takeSecrets(session.launchId);
139
140
  applyBootEnvironment(this.secrets.harnessEnvironment);
141
+ prepareGithubFolder(this.secrets.githubToken);
140
142
  await this.networkAndSessionHost();
141
143
  await this.hooksAndDesktop();
142
144
  const { tools, env } = await this.developerTools();
@@ -221,6 +223,12 @@ export class Boot {
221
223
  async gitIdentity(env) {
222
224
  step(5, 'Git identity');
223
225
  await soft('Git config', () => setupGitConfig(env));
226
+ // After the VPN (gh checks the token with GitHub) and the git config (setup-git adds to it).
227
+ const token = this.secrets.githubToken;
228
+ if (token) {
229
+ this.secrets = { ...this.secrets, githubToken: undefined };
230
+ await soft('GitHub token', () => loginGithub(token, env));
231
+ }
224
232
  }
225
233
  async claude(tools) {
226
234
  step(6, 'Claude settings, history and claude-mem');
@@ -56,7 +56,7 @@ export class Daemon {
56
56
  return sessions.restart(req);
57
57
  case 'pressure':
58
58
  // No response: the host repeats it every few seconds while its memory stays low.
59
- return governor.hostPressure(req.seconds, req.reason);
59
+ return governor.hostPressure(req.seconds, req.reason, req.level ?? 'slow');
60
60
  case 'ping':
61
61
  return respond(req.id, { ok: true, message: 'pong (' + sessions.count + ' session(s) running)' });
62
62
  }
@@ -3,8 +3,9 @@ type SessionRequest = Extract<GuestRequest, {
3
3
  kind: 'session';
4
4
  }>;
5
5
  /**
6
- * What keeps heavy load from taking the sandbox down: the job object's memory limit for everything the agents start
7
- * (ptyhost reads PTYHOST_JOB_MB) and cargo's parallel jobs sized to the sandbox's memory and the sessions building.
6
+ * What keeps heavy load from taking the sandbox down: the agents' job with its last-resort backstop (ptyhost reads
7
+ * PTYHOST_BACKSTOP_MB and the commit limit) and cargo's parallel jobs sized to the sandbox's memory and the sessions
8
+ * building. Slowing builds down comes first (the governor); the backstop only ever picks a build over Windows.
8
9
  */
9
10
  export declare function memoryEnv(env: NodeJS.ProcessEnv, sessions: number): NodeJS.ProcessEnv;
10
11
  /** The agent sessions of this sandbox: the running ones, the ones starting, and what happens when one ends. */
@@ -9,7 +9,7 @@ import { FrameType, sendControl } from '../../shared/pty/index.js';
9
9
  import { isWithin } from '../../shared/paths/projects.js';
10
10
  import { now } from '../../shared/channel/run-dir.js';
11
11
  import { SYSTEM } from '../../shared/system.js';
12
- import { cargoJobs } from '../../shared/memory/index.js';
12
+ import { buildJobs, cargoJobs, linkSlotsFor, usableCpus } from '../../shared/memory/index.js';
13
13
  import { commandLine } from '../sessions/cmdline.js';
14
14
  import { freePort } from '../runtime/ports.js';
15
15
  import { primaryProject } from '../boot/project-status.js';
@@ -20,7 +20,8 @@ import { saveLocalState } from '../agents/local-state.js';
20
20
  import { projectHooks, runHooks, runHooksAsync } from '../setup/hooks.js';
21
21
  import { guestAddresses } from '../network/addresses.js';
22
22
  import { withRegistryPath } from '../setup/environment.js';
23
- import { dataDir, toolsDir } from '../runtime/paths.js';
23
+ import { dataDir, run, toolsDir } from '../runtime/paths.js';
24
+ import { writeJsonAtomic } from '../../shared/io/json.js';
24
25
  import { exists } from '../runtime/fs.js';
25
26
  import { log, warn } from '../runtime/log.js';
26
27
  import { claudeDir, session, workspace } from '../runtime/session.js';
@@ -51,17 +52,47 @@ const harnessFor = (req) => {
51
52
  throw new Error('Agent "' + req.harness + '" is not configured for this sandbox (it runs ' + session.harnessName + ').');
52
53
  };
53
54
  /**
54
- * What keeps heavy load from taking the sandbox down: the job object's memory limit for everything the agents start
55
- * (ptyhost reads PTYHOST_JOB_MB) and cargo's parallel jobs sized to the sandbox's memory and the sessions building.
55
+ * What keeps heavy load from taking the sandbox down: the agents' job with its last-resort backstop (ptyhost reads
56
+ * PTYHOST_BACKSTOP_MB and the commit limit) and cargo's parallel jobs sized to the sandbox's memory and the sessions
57
+ * building. Slowing builds down comes first (the governor); the backstop only ever picks a build over Windows.
56
58
  */
57
59
  export function memoryEnv(env, sessions) {
58
60
  const out = {};
59
- if (session.agentMemoryLimitMb)
60
- out.PTYHOST_JOB_MB = String(session.agentMemoryLimitMb);
61
+ out.PTYHOST_BACKSTOP_MB = String(session.agentBackstop ?? 'auto');
62
+ // What a program sees is what it may use: the processors of the CPU cap (the boot job's affinity), not every one.
63
+ const cpus = usableCpus(os.cpus().length, session.cpuLimitPercent ?? null);
64
+ const memoryGb = os.totalmem() / 1024 ** 3;
65
+ const jobs = cargoJobs(cpus, memoryGb, sessions);
66
+ out.NUMBER_OF_PROCESSORS = String(cpus);
61
67
  if (!env.CARGO_BUILD_JOBS)
62
- out.CARGO_BUILD_JOBS = String(cargoJobs(os.cpus().length, os.totalmem() / 1024 ** 3, sessions));
68
+ out.CARGO_BUILD_JOBS = String(jobs);
69
+ if (!env.CMAKE_BUILD_PARALLEL_LEVEL)
70
+ out.CMAKE_BUILD_PARALLEL_LEVEL = String(jobs);
71
+ out.SANDBOX_BUDGET_FILE = run.budgetFile;
72
+ writeBudget(cpus, memoryGb, jobs, env);
63
73
  return out;
64
74
  }
75
+ /**
76
+ * run\budget.json (SANDBOX_BUDGET_FILE): the numbers an agent should plan with, because a program in a sandbox sees
77
+ * the sandbox's maximum (all processors, the whole RAM) rather than what it may use. Never stops a session.
78
+ */
79
+ function writeBudget(cpus, memoryGb, jobs, env) {
80
+ try {
81
+ writeJsonAtomic(run.budgetFile, {
82
+ processors: cpus,
83
+ memoryMb: Math.round(memoryGb * 1024),
84
+ buildJobs: buildJobs(cpus, memoryGb),
85
+ cargoJobsPerSession: jobs,
86
+ linkSlots: Number(env.AGENT_LINK_SLOTS) || linkSlotsFor(memoryGb),
87
+ cpuLimitPercent: session.cpuLimitPercent ?? null,
88
+ governor: run.pressureFile,
89
+ note: 'Plan builds with these numbers. When memory runs short the sandbox slows builds down in steps (governor); nothing fails.',
90
+ });
91
+ }
92
+ catch (e) {
93
+ warn('budget.json could not be written: ' + errMsg(e));
94
+ }
95
+ }
65
96
  /** Starts ptyhost for the agent and waits until it listens; a failure carries the tail of ptyhost's own log. */
66
97
  const launchPtyHost = async (req, remote, env, say, sessions) => {
67
98
  const harness = harnessFor(req);
@@ -0,0 +1,44 @@
1
+ import type { PressureStatus } from '../../shared/channel/schema.js';
2
+ import type { LoadProfile } from '../../shared/memory/index.js';
3
+ import { type GovernorState, type MemSample } from './decide.js';
4
+ /** What the governor needs from Windows (injectable: the tests use a fake). */
5
+ export interface GovernorPort {
6
+ setPriority(pid: number, to: 'idle' | 'below' | 'normal'): void;
7
+ /** Suspends for `ms`, then resumes (memgov resumes it even if the daemon goes away). */
8
+ hold(pid: number, ms: number): void;
9
+ setMemoryPriority(pid: number, low: boolean): void;
10
+ /** Into the throttle job (whose CPU cap setCpuRate sets). */
11
+ throttle(pid: number): void;
12
+ setCpuRate(percent: number): void;
13
+ trim(pid: number): void;
14
+ }
15
+ /** Everything a step changes outside the decision, behind injectable functions. */
16
+ export interface GovernorDeps {
17
+ readonly port: GovernorPort;
18
+ readonly profile: LoadProfile;
19
+ /** At most this many heavy compilers run at once (null = no cap). */
20
+ readonly maxCompilers?: number | null;
21
+ readonly now: () => number;
22
+ /** A line in the memory log. */
23
+ readonly logLine: (line: string) => void;
24
+ /** run\pressure.json. */
25
+ readonly saveStatus: (status: PressureStatus) => void;
26
+ /** A problem worth the guest log (an action Windows refused). */
27
+ readonly warn: (text: string) => void;
28
+ }
29
+ /** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
30
+ export declare class GovernorCore {
31
+ private readonly deps;
32
+ private state;
33
+ private lastAction;
34
+ private lastWrite;
35
+ private lastWriteAt;
36
+ /** Compilers waiting their turn now, by pid (name), to log a hold once. */
37
+ private held;
38
+ constructor(deps: GovernorDeps);
39
+ hostPressure(seconds: number, reason: string, level?: 'slow' | 'severe'): void;
40
+ get current(): GovernorState;
41
+ onSample(sample: MemSample): void;
42
+ private apply;
43
+ private note;
44
+ }
@@ -0,0 +1,124 @@
1
+ import { now } from '../../shared/channel/run-dir.js';
2
+ import { errMsg } from '../../core/util/errors.js';
3
+ import { decide, HOLD_MS, INITIAL_STATE } from './decide.js';
4
+ const STEP_TEXT = [
5
+ 'builds back to normal',
6
+ 'build programs at lower priority',
7
+ 'builds get less CPU and take turns',
8
+ 'builds take turns, waiting ones go to the paging file',
9
+ 'one compiler at a time',
10
+ ];
11
+ /** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
12
+ export class GovernorCore {
13
+ deps;
14
+ state = INITIAL_STATE;
15
+ lastAction = '';
16
+ lastWrite = '';
17
+ lastWriteAt = 0;
18
+ /** Compilers waiting their turn now, by pid (name), to log a hold once. */
19
+ held = new Map();
20
+ constructor(deps) {
21
+ this.deps = deps;
22
+ }
23
+ hostPressure(seconds, reason, level = 'slow') {
24
+ const nowMs = this.deps.now();
25
+ const until = nowMs + seconds * 1000;
26
+ const active = this.state.hostUntil > nowMs;
27
+ const step = Math.max(level === 'severe' ? 4 : 2, active ? this.state.hostStep : 0);
28
+ if (!active || step > this.state.hostStep)
29
+ this.deps.logLine('governor: this PC is ' +
30
+ (level === 'severe' ? 'nearly out of memory' : 'low') +
31
+ ' (' +
32
+ reason +
33
+ '); builds to step ' +
34
+ step);
35
+ this.state = { ...this.state, hostUntil: Math.max(until, this.state.hostUntil), hostStep: step };
36
+ }
37
+ get current() {
38
+ return this.state;
39
+ }
40
+ onSample(sample) {
41
+ const nowMs = this.deps.now();
42
+ const before = this.state.step;
43
+ const d = decide(this.state, sample, nowMs, this.deps.profile, this.deps.maxCompilers ?? null);
44
+ this.state = d.state;
45
+ const holding = new Set();
46
+ for (const action of d.actions) {
47
+ if (action.kind === 'hold')
48
+ holding.add(action.pid);
49
+ this.apply(action);
50
+ }
51
+ for (const pid of [...this.held.keys()])
52
+ if (!holding.has(pid))
53
+ this.held.delete(pid);
54
+ if (d.state.step !== before)
55
+ this.deps.logLine('governor: step ' +
56
+ d.state.step +
57
+ ' (' +
58
+ d.ramFreePercent +
59
+ '% RAM free, commit ' +
60
+ d.commitPercent +
61
+ '% used): ' +
62
+ STEP_TEXT[d.state.step]);
63
+ const status = {
64
+ level: d.level,
65
+ step: d.state.step,
66
+ profile: this.deps.profile,
67
+ ramFreePercent: Math.max(0, Math.min(100, d.ramFreePercent)),
68
+ commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
69
+ lowered: Object.keys(d.state.lowered).length,
70
+ paused: [...this.held]
71
+ .slice(0, 8)
72
+ .map(([pid, name]) => ({ name: name.slice(0, 64), pid, seconds: HOLD_MS / 1000 })),
73
+ cpuPercent: d.state.cpuRate,
74
+ pcLow: nowMs < d.state.hostUntil,
75
+ lastAction: this.lastAction.slice(0, 300),
76
+ updatedAt: now(),
77
+ };
78
+ // Written when something changed, else once a minute (the host reads it, never polls it hard).
79
+ const shape = JSON.stringify({ ...status, updatedAt: '', paused: status.paused.map((p) => p.pid) });
80
+ if (shape !== this.lastWrite || nowMs - this.lastWriteAt > 60000) {
81
+ this.lastWrite = shape;
82
+ this.lastWriteAt = nowMs;
83
+ this.deps.saveStatus(status);
84
+ }
85
+ }
86
+ apply(action) {
87
+ const port = this.deps.port;
88
+ try {
89
+ switch (action.kind) {
90
+ case 'hold':
91
+ port.hold(action.pid, action.ms);
92
+ if (!this.held.has(action.pid)) {
93
+ this.held.set(action.pid, action.name);
94
+ this.note(action.name + ' (' + action.pid + ') waits its turn');
95
+ }
96
+ return;
97
+ case 'priority':
98
+ port.setPriority(action.pid, action.to);
99
+ this.note(action.name + ' (' + action.pid + ') priority ' + action.to);
100
+ return;
101
+ case 'memory':
102
+ port.setMemoryPriority(action.pid, action.low);
103
+ return;
104
+ case 'throttle':
105
+ port.throttle(action.pid);
106
+ return;
107
+ case 'cpu':
108
+ port.setCpuRate(action.percent);
109
+ this.note(action.percent >= 100 ? 'compilers: no CPU cap' : 'compilers: at most ' + action.percent + '% CPU');
110
+ return;
111
+ case 'trim':
112
+ port.trim(action.pid);
113
+ return;
114
+ }
115
+ }
116
+ catch (e) {
117
+ this.deps.warn('governor: ' + errMsg(e));
118
+ }
119
+ }
120
+ note(text) {
121
+ this.lastAction = text;
122
+ this.deps.logLine('governor: ' + text);
123
+ }
124
+ }
@@ -1,4 +1,4 @@
1
- import type { GuestThresholds, LoadProfile } from '../../shared/memory/index.js';
1
+ import { type LoadProfile } from '../../shared/memory/index.js';
2
2
  export type Priority = 'idle' | 'below' | 'normal';
3
3
  export interface ProcSample {
4
4
  readonly pid: number;
@@ -21,19 +21,29 @@ export declare const isHeavyCompiler: (name: string) => boolean;
21
21
  export declare const canPause: (name: string) => boolean;
22
22
  export type Level = 'ok' | 'throttled' | 'suspending';
23
23
  export interface GovernorState {
24
- /** Under pressure now (with hysteresis). */
25
- readonly pressure: boolean;
26
- /** Samples in a row that looked calm while under pressure. */
24
+ /** The dial: 0 nothing wrong, 1 lower priority, 2 less CPU and fewer compilers, 3 and 4 harder. */
25
+ readonly step: number;
26
+ /** Samples in a row clear of the current step (it turns down after DIAL_CALM_SAMPLES). */
27
27
  readonly calm: number;
28
- /** Samples under pressure so far (resets when it ends). */
29
- readonly samples: number;
30
28
  /** What was lowered and to what, by pid. */
31
29
  readonly lowered: Readonly<Record<number, Priority>>;
32
- /** Until when (ms) the last pause lasts, and when another may start. */
33
- readonly pausedUntil: number;
34
- readonly nextPauseAt: number;
35
- /** The PC asked for slowing down until this time (ms). */
30
+ /** Pids whose memory priority is low. */
31
+ readonly memLow: readonly number[];
32
+ /** Pids put in the throttle job (its CPU cap follows the step). */
33
+ readonly throttled: readonly number[];
34
+ /** Pids whose working set was trimmed while they waited. */
35
+ readonly trimmed: readonly number[];
36
+ /** The CPU cap last set on the throttle job (percent; 100 = none). */
37
+ readonly cpuRate: number;
38
+ /** Used commit (MB) and when, at the last sample: how fast it grows. */
39
+ readonly lastCommitMb: number;
40
+ readonly lastAt: number;
41
+ /** Commit growth in MB per second, smoothed over the samples. */
42
+ readonly growth: number;
43
+ /** The PC asked for slowing down until this time (ms): the dial is at least at `hostStep` until then. */
36
44
  readonly hostUntil: number;
45
+ /** 2 when the PC is low, 4 when it is nearly out of memory. */
46
+ readonly hostStep: number;
37
47
  }
38
48
  export declare const INITIAL_STATE: GovernorState;
39
49
  export type Action = {
@@ -42,20 +52,37 @@ export type Action = {
42
52
  readonly name: string;
43
53
  readonly to: Priority;
44
54
  } | {
45
- readonly kind: 'pause';
55
+ readonly kind: 'memory';
46
56
  readonly pid: number;
47
57
  readonly name: string;
48
- readonly ms: number;
58
+ readonly low: boolean;
59
+ }
60
+ /** Into the throttle job, whose CPU cap follows the dial. */
61
+ | {
62
+ readonly kind: 'throttle';
63
+ readonly pid: number;
64
+ readonly name: string;
65
+ } | {
66
+ readonly kind: 'cpu';
67
+ readonly percent: number;
49
68
  }
50
- /** Waits (suspended) because more compilers run than the cap allows; repeated while it is over, never killed. */
69
+ /** Waits (suspended) for its turn; repeated while it waits, always resumed, never killed. */
51
70
  | {
52
71
  readonly kind: 'hold';
53
72
  readonly pid: number;
54
73
  readonly name: string;
55
74
  readonly ms: number;
75
+ }
76
+ /** Its pages go to the paging file while it waits, so the compilers that run have the RAM. */
77
+ | {
78
+ readonly kind: 'trim';
79
+ readonly pid: number;
80
+ readonly name: string;
56
81
  };
57
- /** How long a held compiler waits before it gets a turn again (the governor repeats the hold while over the cap). */
82
+ /** How long a held compiler waits before it may get a turn again (the governor repeats the hold while it waits). */
58
83
  export declare const HOLD_MS = 3000;
84
+ /** Which compilers wait their turn changes this often, so none waits for ever. */
85
+ export declare const ROTATE_MS = 20000;
59
86
  export interface Decision {
60
87
  readonly state: GovernorState;
61
88
  readonly actions: readonly Action[];
@@ -63,9 +90,10 @@ export interface Decision {
63
90
  readonly ramFreePercent: number;
64
91
  readonly commitPercent: number;
65
92
  }
66
- export declare const PAUSE_MS = 5000;
93
+ /** The step a sample calls for on its own: the highest step whose threshold it crosses. */
94
+ export declare function stepFor(ramFree: number, commit: number, secondsToLimit: number, profile: LoadProfile): number;
67
95
  /**
68
- * One step. `gentle` (vGPU on): compilers start below normal even without pressure. Programs go back to their normal
69
- * priority only when pressure ends (several calm samples in a row).
96
+ * One step of the governor. The dial turns up at once and down one step at a time after calm samples. `gentle` (vGPU
97
+ * on): compilers rest below normal priority, and `maxCompilers` caps how many heavy compilers run at any step.
70
98
  */
71
- export declare function decide(prev: GovernorState, sample: MemSample, nowMs: number, thresholds: GuestThresholds, profile: LoadProfile, maxCompilers?: number | null): Decision;
99
+ export declare function decide(prev: GovernorState, sample: MemSample, nowMs: number, profile: LoadProfile, maxCompilers?: number | null): Decision;