windows-development-sandbox 1.9.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 (398) hide show
  1. package/README.md +64 -17
  2. package/config.example.json +7 -2
  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 +23 -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 -88
  149. package/dist/cli/commands/web.d.ts +7 -1
  150. package/dist/cli/commands/web.js +45 -71
  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 +3 -2
  200. package/dist/core/schema/config.d.ts +6 -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/schema/vpn.js +1 -1
  211. package/dist/core/schema/web.d.ts +1 -0
  212. package/dist/core/schema/web.js +4 -1
  213. package/dist/core/types.d.ts +6 -3
  214. package/dist/guest/boot/boot.js +11 -1
  215. package/dist/guest/daemon/daemon.js +1 -1
  216. package/dist/guest/daemon/sessions.d.ts +3 -2
  217. package/dist/guest/daemon/sessions.js +38 -7
  218. package/dist/guest/governor/core.d.ts +44 -0
  219. package/dist/guest/governor/core.js +124 -0
  220. package/dist/guest/governor/decide.d.ts +53 -15
  221. package/dist/guest/governor/decide.js +155 -72
  222. package/dist/guest/governor/governor.d.ts +2 -35
  223. package/dist/guest/governor/governor.js +35 -99
  224. package/dist/guest/governor/index.d.ts +1 -0
  225. package/dist/guest/governor/index.js +1 -0
  226. package/dist/guest/network/firewall.d.ts +3 -0
  227. package/dist/guest/network/firewall.js +65 -23
  228. package/dist/guest/runtime/process.js +53 -5
  229. package/dist/guest/sessions/viewer.js +5 -1
  230. package/dist/guest/setup/claude-mem.js +12 -4
  231. package/dist/guest/setup/github-token.d.ts +7 -0
  232. package/dist/guest/setup/github-token.js +65 -0
  233. package/dist/guest/toolchains/languages/node.js +40 -4
  234. package/dist/guest/toolchains/native/rust-extras.js +2 -2
  235. package/dist/guest/toolchains/tools/cli.d.ts +8 -0
  236. package/dist/guest/toolchains/tools/cli.js +16 -2
  237. package/dist/guest/vpn/openvpn.d.ts +5 -0
  238. package/dist/guest/vpn/openvpn.js +14 -1
  239. package/dist/guest/vpn/vpn.js +55 -16
  240. package/dist/guest/vpn/wireguard.js +2 -0
  241. package/dist/host/channel/attach.d.ts +1 -0
  242. package/dist/host/channel/attach.js +1 -0
  243. package/dist/host/channel/channel.d.ts +1 -1
  244. package/dist/host/channel/channel.js +2 -2
  245. package/dist/host/engines/hcs/check.d.ts +1 -0
  246. package/dist/host/engines/hcs/check.js +1 -1
  247. package/dist/host/engines/hcs/engine.d.ts +1 -1
  248. package/dist/host/engines/hcs/engine.js +6 -4
  249. package/dist/host/engines/hcs/helper.d.ts +11 -0
  250. package/dist/host/engines/hcs/helper.js +31 -2
  251. package/dist/host/engines/hcs/leftovers.d.ts +42 -0
  252. package/dist/host/engines/hcs/leftovers.js +101 -0
  253. package/dist/host/engines/index.d.ts +1 -0
  254. package/dist/host/engines/index.js +1 -0
  255. package/dist/host/github/deliver.d.ts +13 -0
  256. package/dist/host/github/deliver.js +51 -0
  257. package/dist/host/github/index.d.ts +2 -0
  258. package/dist/host/github/index.js +3 -0
  259. package/dist/host/github/token.d.ts +21 -0
  260. package/dist/host/github/token.js +74 -0
  261. package/dist/host/launch/generate.js +11 -5
  262. package/dist/host/launch/index.d.ts +1 -1
  263. package/dist/host/launch/index.js +1 -1
  264. package/dist/host/launch/session-file.js +1 -2
  265. package/dist/host/launch/wsb-file.d.ts +11 -7
  266. package/dist/host/launch/wsb-file.js +30 -12
  267. package/dist/host/life/host-memory.d.ts +1 -0
  268. package/dist/host/life/host-memory.js +4 -1
  269. package/dist/host/life/watchdog.d.ts +11 -0
  270. package/dist/host/life/watchdog.js +36 -4
  271. package/dist/host/sandbox/tasklist.d.ts +6 -0
  272. package/dist/host/sandbox/tasklist.js +37 -0
  273. package/dist/host/secrets/launch-secrets.d.ts +2 -1
  274. package/dist/host/secrets/launch-secrets.js +4 -2
  275. package/dist/host/vpn/status.js +13 -3
  276. package/dist/host/web/backend.d.ts +1 -3
  277. package/dist/host/web/index.d.ts +2 -1
  278. package/dist/host/web/index.js +2 -1
  279. package/dist/host/web/live.d.ts +23 -0
  280. package/dist/host/web/live.js +107 -0
  281. package/dist/host/web/rpc.d.ts +6 -1
  282. package/dist/host/web/rpc.js +23 -31
  283. package/dist/host/web/runner.d.ts +4 -0
  284. package/dist/host/web/runner.js +12 -1
  285. package/dist/host/web/server.d.ts +30 -2
  286. package/dist/host/web/server.js +87 -29
  287. package/dist/host/web/state.d.ts +1 -0
  288. package/dist/host/web/state.js +2 -0
  289. package/dist/runtime/agent.js +44 -16
  290. package/dist/runtime/daemon.js +1154 -857
  291. package/dist/runtime/db.js +44 -16
  292. package/dist/runtime/main.js +532 -115
  293. package/dist/runtime/netproxy.js +34 -9
  294. package/dist/runtime/view.js +499 -149
  295. package/dist/selftest/app.test.js +620 -12
  296. package/dist/selftest/channel.test.js +18 -1
  297. package/dist/selftest/cli.test.js +1 -1
  298. package/dist/selftest/config.test.js +1 -1
  299. package/dist/selftest/contained.test.js +1 -1
  300. package/dist/selftest/data.test.js +1 -2
  301. package/dist/selftest/engine.test.js +3 -1
  302. package/dist/selftest/github.test.d.ts +2 -0
  303. package/dist/selftest/github.test.js +243 -0
  304. package/dist/selftest/guest-boot.test.js +47 -1
  305. package/dist/selftest/hcs.test.js +105 -8
  306. package/dist/selftest/health.test.js +71 -0
  307. package/dist/selftest/heavy-load.test.js +152 -66
  308. package/dist/selftest/index.js +4 -0
  309. package/dist/selftest/layout.test.js +8 -0
  310. package/dist/selftest/live-terminal.test.js +74 -0
  311. package/dist/selftest/menu-screens.js +171 -56
  312. package/dist/selftest/menu.test.js +54 -37
  313. package/dist/selftest/migrate.test.js +14 -12
  314. package/dist/selftest/network.test.js +20 -1
  315. package/dist/selftest/powershell-variables.test.d.ts +2 -0
  316. package/dist/selftest/powershell-variables.test.js +61 -0
  317. package/dist/selftest/support/engine-golden.js +1 -0
  318. package/dist/selftest/support/fixtures.d.ts +5 -0
  319. package/dist/selftest/support/web-preview.d.ts +1 -0
  320. package/dist/selftest/support/web-preview.js +856 -0
  321. package/dist/selftest/update-service.test.js +15 -8
  322. package/dist/selftest/vpn.test.js +86 -2
  323. package/dist/selftest/web.test.js +58 -11
  324. package/dist/shared/channel/run-dir.d.ts +2 -0
  325. package/dist/shared/channel/run-dir.js +3 -0
  326. package/dist/shared/channel/schema.d.ts +7 -0
  327. package/dist/shared/channel/schema.js +9 -1
  328. package/dist/shared/channel/secrets.d.ts +1 -0
  329. package/dist/shared/channel/secrets.js +3 -0
  330. package/dist/shared/github/index.d.ts +1 -0
  331. package/dist/shared/github/index.js +2 -0
  332. package/dist/shared/github/token.d.ts +29 -0
  333. package/dist/shared/github/token.js +89 -0
  334. package/dist/shared/io/copy-tree.d.ts +7 -0
  335. package/dist/shared/io/copy-tree.js +45 -0
  336. package/dist/shared/io/index.d.ts +2 -0
  337. package/dist/shared/io/index.js +2 -0
  338. package/dist/shared/io/robocopy-result.d.ts +6 -0
  339. package/dist/shared/io/robocopy-result.js +23 -0
  340. package/dist/shared/memory/policy.d.ts +38 -12
  341. package/dist/shared/memory/policy.js +58 -19
  342. package/dist/shared/network/firewall-rules.d.ts +8 -0
  343. package/dist/shared/network/firewall-rules.js +28 -0
  344. package/dist/shared/pty/ctrl-c.d.ts +18 -0
  345. package/dist/shared/pty/ctrl-c.js +36 -0
  346. package/dist/shared/pty/index.d.ts +1 -0
  347. package/dist/shared/pty/index.js +1 -0
  348. package/dist/shared/pty/terminal.d.ts +2 -0
  349. package/dist/shared/pty/terminal.js +21 -2
  350. package/dist/shared/vpn/kill-switch.d.ts +13 -2
  351. package/dist/shared/vpn/kill-switch.js +88 -8
  352. package/dist/shared/web/protocol.d.ts +0 -4
  353. package/dist/sync/watcher.js +1 -1
  354. package/dist/web/index.html +2 -2
  355. package/dist/web/{main-T5DMCHYV.css → main-6JF3ASB5.css} +1 -1
  356. package/dist/web/main-Z645W45E.js +219 -0
  357. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  358. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  359. package/native/csharp/HostTools/MemoryStatus.cs +128 -107
  360. package/native/scripts/memory-status.ps1 +10 -2
  361. package/package.json +10 -3
  362. package/sandbox/csharp/MemGov.cs +668 -398
  363. package/sandbox/csharp/PtyHost.cs +104 -15
  364. package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
  365. package/sandbox/csharp/SandboxTools/Program.cs +1 -1
  366. package/sandbox/scripts/new-shortcuts.ps1 +3 -1
  367. package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
  368. package/schemas/config.schema.json +25 -7
  369. package/schemas/sandbox-config.schema.json +7 -3
  370. package/dist/cli/commands/accounts.d.ts +0 -2
  371. package/dist/cli/commands/accounts.js +0 -96
  372. package/dist/cli/commands/data/clean.d.ts +0 -3
  373. package/dist/cli/commands/data/clean.js +0 -60
  374. package/dist/cli/commands/data/index.d.ts +0 -4
  375. package/dist/cli/commands/data/index.js +0 -62
  376. package/dist/cli/commands/maintenance/clean.d.ts +0 -2
  377. package/dist/cli/commands/maintenance/clean.js +0 -24
  378. package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
  379. package/dist/cli/commands/maintenance/config-share.js +0 -80
  380. package/dist/cli/commands/projects/projects.d.ts +0 -2
  381. package/dist/cli/commands/projects/projects.js +0 -162
  382. package/dist/cli/commands/storage/contained.d.ts +0 -3
  383. package/dist/cli/commands/storage/contained.js +0 -179
  384. package/dist/cli/commands/storage/storage.d.ts +0 -8
  385. package/dist/cli/commands/storage/storage.js +0 -179
  386. package/dist/cli/menu/add-agent.d.ts +0 -47
  387. package/dist/cli/menu/add-agent.js +0 -168
  388. package/dist/cli/menu/apps.d.ts +0 -69
  389. package/dist/cli/menu/apps.js +0 -214
  390. package/dist/cli/menu/data-folder.d.ts +0 -18
  391. package/dist/cli/menu/data-folder.js +0 -99
  392. package/dist/cli/menu/share-settings.d.ts +0 -21
  393. package/dist/cli/menu/share-settings.js +0 -112
  394. package/dist/cli/menu/vpn-login.d.ts +0 -16
  395. package/dist/cli/menu/vpn-login.js +0 -74
  396. package/dist/web/main-NRRS5O6Z.js +0 -157
  397. /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
  398. /package/dist/cli/{commands/data/remove.d.ts → services/data-remove.d.ts} +0 -0
@@ -1,3 +1,9 @@
1
+ // The memory governor's decisions (pure): given a memory sample and what it did before, how far to turn the dial and
2
+ // what that means for the build programs in the agents' job. Like a PC that gets slower instead of failing: lower
3
+ // priority, lower memory priority (their pages are trimmed first), less CPU, fewer compilers at a time (the others wait
4
+ // their turn, suspended and always resumed), waiting compilers trimmed to the paging file. Agents, shells and Windows
5
+ // are never touched. Nothing here touches Windows; governor.ts carries the actions out through a port.
6
+ import { compilersAllowed, DIAL_CALM_SAMPLES, DIAL_CPU_RATE, DIAL_EXIT_MARGIN, DIAL_STEPS, } from '../../shared/memory/index.js';
1
7
  /** Programs that compile or link: they may be slowed down and, as the last resort, paused for a few seconds. */
2
8
  const COMPILERS = new Set([
3
9
  'rustc',
@@ -25,8 +31,8 @@ const COMPILERS = new Set([
25
31
  'javac',
26
32
  ]);
27
33
  /** Build tools and workers: slowed down but never paused (a node process may be a dev server or an agent). */
34
+ // Not node: agents such as Codex and Gemini run as node.exe, and the agents are never slowed down.
28
35
  const BUILD_TOOLS = new Set([
29
- 'node',
30
36
  'dotnet',
31
37
  'msbuild',
32
38
  'vbcscompiler',
@@ -77,103 +83,180 @@ const NEVER = new Set([
77
83
  const key = (name) => name.toLowerCase().replace(/\.exe$/, '');
78
84
  export const isNeverTouched = (name) => NEVER.has(key(name));
79
85
  export const canLower = (name) => !isNeverTouched(name) && (COMPILERS.has(key(name)) || BUILD_TOOLS.has(key(name)));
86
+ /** The heavy ones the concurrency cap counts (drivers like gcc and collect2 only wait for these). */
87
+ const HEAVY = new Set([
88
+ 'rustc',
89
+ 'clippy-driver',
90
+ 'rustdoc',
91
+ 'cc1',
92
+ 'cc1plus',
93
+ 'clang',
94
+ 'clang++',
95
+ 'clang-cl',
96
+ 'cl',
97
+ 'link',
98
+ 'lld',
99
+ 'lld-link',
100
+ 'ld',
101
+ 'ld.lld',
102
+ ]);
103
+ export const isHeavyCompiler = (name) => !isNeverTouched(name) && HEAVY.has(key(name));
80
104
  export const canPause = (name) => !isNeverTouched(name) && COMPILERS.has(key(name));
81
105
  export const INITIAL_STATE = {
82
- pressure: false,
106
+ step: 0,
83
107
  calm: 0,
84
- samples: 0,
85
108
  lowered: {},
86
- pausedUntil: 0,
87
- nextPauseAt: 0,
109
+ memLow: [],
110
+ throttled: [],
111
+ trimmed: [],
112
+ cpuRate: 100,
113
+ lastCommitMb: 0,
114
+ lastAt: 0,
115
+ growth: 0,
88
116
  hostUntil: 0,
117
+ hostStep: 0,
89
118
  };
90
- export const PAUSE_MS = 5000;
91
- const PAUSE_COOLDOWN_MS = 10000;
92
- /** Samples under pressure before programs go from below-normal to idle, and before one is paused. */
93
- const IDLE_AFTER = 3;
94
- const PAUSE_AFTER = 4;
95
- /** Only a program this big is worth pausing. */
96
- const PAUSE_MIN_MB = 300;
119
+ /** How much the newest sample counts in the smoothed commit growth. */
120
+ const GROWTH_WEIGHT = 0.3;
121
+ /** How long a held compiler waits before it may get a turn again (the governor repeats the hold while it waits). */
122
+ export const HOLD_MS = 3000;
123
+ /** Which compilers wait their turn changes this often, so none waits for ever. */
124
+ export const ROTATE_MS = 20000;
125
+ /**
126
+ * "Full soon" only counts this close (in commit percent) to a step's own threshold: a build that grabs a few GB in a
127
+ * burst while most of the memory is free is normal, not a reason to pause compilers.
128
+ */
129
+ const SOON_WITHIN_PERCENT = 12;
130
+ /** The step a sample calls for on its own: the highest step whose threshold it crosses. */
131
+ export function stepFor(ramFree, commit, secondsToLimit, profile) {
132
+ let step = 0;
133
+ DIAL_STEPS[profile].forEach((t, i) => {
134
+ const near = commit > t.commitPercent - SOON_WITHIN_PERCENT;
135
+ const soon = near && t.secondsToLimit !== undefined && secondsToLimit < t.secondsToLimit;
136
+ if (ramFree < t.availablePercent || commit > t.commitPercent || soon)
137
+ step = i + 1;
138
+ });
139
+ return step;
140
+ }
141
+ /** Is the sample clear of `step` by the exit margins (so the dial may turn down from it)? */
142
+ function clearOf(step, ramFree, commit, profile) {
143
+ if (step === 0)
144
+ return true;
145
+ const t = DIAL_STEPS[profile][step - 1];
146
+ return (ramFree > t.availablePercent + DIAL_EXIT_MARGIN.availablePercent &&
147
+ commit < t.commitPercent - DIAL_EXIT_MARGIN.commitPercent);
148
+ }
97
149
  /**
98
- * One step. `gentle` (vGPU on): compilers start below normal even without pressure. Programs go back to their normal
99
- * priority only when pressure ends (several calm samples in a row).
150
+ * One step of the governor. The dial turns up at once and down one step at a time after calm samples. `gentle` (vGPU
151
+ * on): compilers rest below normal priority, and `maxCompilers` caps how many heavy compilers run at any step.
100
152
  */
101
- export function decide(prev, sample, nowMs, thresholds, profile) {
153
+ export function decide(prev, sample, nowMs, profile, maxCompilers = null) {
102
154
  const ramFree = (sample.ramAvailMb / Math.max(1, sample.ramTotalMb)) * 100;
103
- const commit = ((sample.commitLimitMb - sample.commitAvailMb) / Math.max(1, sample.commitLimitMb)) * 100;
155
+ const usedMb = sample.commitLimitMb - sample.commitAvailMb;
156
+ const commit = (usedMb / Math.max(1, sample.commitLimitMb)) * 100;
157
+ const seconds = (nowMs - prev.lastAt) / 1000;
158
+ const instant = prev.lastAt > 0 && seconds > 0 ? (usedMb - prev.lastCommitMb) / seconds : 0;
159
+ // Smoothed over the last samples, so one burst between two samples is not read as a trend.
160
+ const growth = prev.lastAt > 0 ? prev.growth * (1 - GROWTH_WEIGHT) + instant * GROWTH_WEIGHT : 0;
161
+ const secondsToLimit = growth > 0 ? sample.commitAvailMb / growth : Number.POSITIVE_INFINITY;
104
162
  const pcLow = nowMs < prev.hostUntil;
105
- const low = ramFree < thresholds.enterAvailablePercent || commit > thresholds.enterCommitPercent || pcLow;
106
- const recovered = ramFree > thresholds.exitAvailablePercent && commit < thresholds.exitCommitPercent && !pcLow;
107
- let pressure = prev.pressure;
108
- let calm = prev.calm;
109
- let samples = prev.samples;
110
- if (low) {
111
- pressure = true;
112
- calm = 0;
113
- samples = prev.samples + 1;
114
- }
115
- else if (prev.pressure) {
116
- calm = recovered ? prev.calm + 1 : 0;
117
- if (calm >= thresholds.calmSamples) {
118
- pressure = false;
163
+ const wanted = Math.max(stepFor(ramFree, commit, secondsToLimit, profile), pcLow ? prev.hostStep : 0);
164
+ let step = prev.step;
165
+ let calm = 0;
166
+ if (wanted > prev.step)
167
+ step = wanted;
168
+ else if (prev.step > 0 && wanted < prev.step && clearOf(prev.step, ramFree, commit, profile)) {
169
+ calm = prev.calm + 1;
170
+ if (calm >= DIAL_CALM_SAMPLES) {
171
+ step = prev.step - 1;
119
172
  calm = 0;
120
- samples = 0;
121
173
  }
122
174
  }
123
175
  const actions = [];
124
176
  const present = new Set(sample.procs.map((p) => p.pid));
177
+ const keep = (pids) => pids.filter((pid) => present.has(pid));
125
178
  const lowered = {};
126
179
  for (const [pid, to] of Object.entries(prev.lowered))
127
180
  if (present.has(Number(pid)))
128
181
  lowered[Number(pid)] = to;
129
- if (pressure) {
130
- const target = samples > IDLE_AFTER ? 'idle' : 'below';
131
- for (const p of sample.procs) {
132
- if (!canLower(p.name) || lowered[p.pid] === target)
133
- continue;
134
- // Already as low as asked (or lower): only remember it.
135
- if (p.prio !== target && !(target === 'below' && p.prio === 'idle'))
136
- actions.push({ kind: 'priority', pid: p.pid, name: p.name, to: target });
182
+ const memLow = new Set(keep(prev.memLow));
183
+ const throttled = new Set(keep(prev.throttled));
184
+ const trimmed = new Set(keep(prev.trimmed));
185
+ // CPU priority: where a program rests (normal; compilers below in the gentle profile), below from step 1, idle
186
+ // from step 2. Only changes are sent.
187
+ for (const p of sample.procs) {
188
+ if (!canLower(p.name))
189
+ continue;
190
+ const rest = profile === 'gentle' && canPause(p.name) ? 'below' : 'normal';
191
+ const target = step >= 2 ? 'idle' : step === 1 ? 'below' : rest;
192
+ const was = lowered[p.pid];
193
+ const touched = was !== undefined || target !== 'normal';
194
+ if (touched && was !== target && p.prio !== target)
195
+ actions.push({ kind: 'priority', pid: p.pid, name: p.name, to: target });
196
+ if (target === 'normal')
197
+ delete lowered[p.pid];
198
+ else
137
199
  lowered[p.pid] = target;
138
- }
139
200
  }
140
- else {
141
- for (const p of sample.procs) {
142
- if (!canLower(p.name))
143
- continue;
144
- // Where a program rests when nothing is wrong: compilers below normal in the gentle profile.
145
- const base = profile === 'gentle' && canPause(p.name) ? 'below' : 'normal';
146
- const was = lowered[p.pid];
147
- if (prev.pressure && was !== undefined && was !== base) {
148
- if (p.prio !== base)
149
- actions.push({ kind: 'priority', pid: p.pid, name: p.name, to: base });
150
- if (base === 'normal')
151
- delete lowered[p.pid];
152
- else
153
- lowered[p.pid] = base;
201
+ // Memory priority: low from step 1, so Windows trims the builds' pages before the agents'.
202
+ const lowMemory = step >= 1;
203
+ for (const p of sample.procs) {
204
+ if (!canLower(p.name) || lowMemory === memLow.has(p.pid))
205
+ continue;
206
+ actions.push({ kind: 'memory', pid: p.pid, name: p.name, low: lowMemory });
207
+ if (lowMemory)
208
+ memLow.add(p.pid);
209
+ else
210
+ memLow.delete(p.pid);
211
+ }
212
+ // CPU share of the compilers: they join the throttle job once (from step 2); its cap follows the dial.
213
+ if (step >= 2)
214
+ for (const p of sample.procs)
215
+ if (canPause(p.name) && !throttled.has(p.pid)) {
216
+ actions.push({ kind: 'throttle', pid: p.pid, name: p.name });
217
+ throttled.add(p.pid);
154
218
  }
155
- else if (!prev.pressure && base === 'below' && was === undefined) {
156
- if (p.prio === 'normal')
157
- actions.push({ kind: 'priority', pid: p.pid, name: p.name, to: 'below' });
158
- lowered[p.pid] = 'below';
219
+ const cpuRate = DIAL_CPU_RATE[step] ?? 100;
220
+ if (cpuRate !== prev.cpuRate)
221
+ actions.push({ kind: 'cpu', percent: cpuRate });
222
+ // Turns: of the heavy compilers only so many go on; the rest wait, and who waits changes every ROTATE_MS.
223
+ const heavy = sample.procs.filter((p) => isHeavyCompiler(p.name)).sort((a, b) => a.pid - b.pid);
224
+ let allowed = compilersAllowed(step, heavy.length);
225
+ // The cap is a memory measure: with memory to spare, Windows shares the CPU (the priorities above) and no compiler
226
+ // waits. A waiting rustc also holds cargo's job tokens, which stalls the whole build.
227
+ if (maxCompilers !== null && step >= 2)
228
+ allowed = Math.min(allowed, Math.max(1, maxCompilers));
229
+ if (allowed < heavy.length) {
230
+ const turn = Math.floor(nowMs / ROTATE_MS) % heavy.length;
231
+ const order = [...heavy.slice(turn), ...heavy.slice(0, turn)];
232
+ for (const p of order.slice(allowed)) {
233
+ actions.push({ kind: 'hold', pid: p.pid, name: p.name, ms: HOLD_MS });
234
+ if (step >= 3 && !trimmed.has(p.pid)) {
235
+ actions.push({ kind: 'trim', pid: p.pid, name: p.name });
236
+ trimmed.add(p.pid);
159
237
  }
160
238
  }
239
+ for (const p of order.slice(0, allowed))
240
+ trimmed.delete(p.pid);
161
241
  }
162
- let pausedUntil = prev.pausedUntil;
163
- let nextPauseAt = prev.nextPauseAt;
164
- if (pressure && samples >= PAUSE_AFTER && nowMs >= prev.nextPauseAt && nowMs >= prev.pausedUntil) {
165
- const victim = [...sample.procs]
166
- .filter((p) => canPause(p.name) && p.mb >= PAUSE_MIN_MB)
167
- .sort((a, b) => b.mb - a.mb)[0];
168
- if (victim) {
169
- actions.push({ kind: 'pause', pid: victim.pid, name: victim.name, ms: PAUSE_MS });
170
- pausedUntil = nowMs + PAUSE_MS;
171
- nextPauseAt = pausedUntil + PAUSE_COOLDOWN_MS;
172
- }
173
- }
174
- const level = nowMs < pausedUntil ? 'suspending' : pressure ? 'throttled' : 'ok';
242
+ else
243
+ trimmed.clear();
244
+ const level = step >= 3 ? 'suspending' : step >= 1 ? 'throttled' : 'ok';
175
245
  return {
176
- state: { pressure, calm, samples, lowered, pausedUntil, nextPauseAt, hostUntil: prev.hostUntil },
246
+ state: {
247
+ step,
248
+ calm,
249
+ lowered,
250
+ memLow: [...memLow],
251
+ throttled: [...throttled],
252
+ trimmed: [...trimmed],
253
+ cpuRate,
254
+ lastCommitMb: usedMb,
255
+ lastAt: nowMs,
256
+ growth,
257
+ hostUntil: prev.hostUntil,
258
+ hostStep: prev.hostStep,
259
+ },
177
260
  actions,
178
261
  level,
179
262
  ramFreePercent: Math.round(ramFree),
@@ -1,42 +1,9 @@
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
- pause(pid: number, ms: number): void;
8
- }
9
- /** Everything a step changes outside the decision, behind injectable functions. */
10
- export interface GovernorDeps {
11
- readonly port: GovernorPort;
12
- readonly profile: LoadProfile;
13
- readonly now: () => number;
14
- /** A line in the memory log. */
15
- readonly logLine: (line: string) => void;
16
- /** run\pressure.json. */
17
- readonly saveStatus: (status: PressureStatus) => void;
18
- }
19
- /** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
20
- export declare class GovernorCore {
21
- private readonly deps;
22
- private state;
23
- private lastAction;
24
- private lastWrite;
25
- private lastWriteAt;
26
- private pausedName;
27
- private pausedPid;
28
- constructor(deps: GovernorDeps);
29
- hostPressure(seconds: number, reason: string): void;
30
- get current(): GovernorState;
31
- onSample(sample: MemSample): void;
32
- private apply;
33
- }
34
1
  /** The daemon's governor: on unless sandbox.pressureResponse is off. */
35
2
  export declare class Governor {
36
3
  private core;
37
4
  describe(): string;
38
5
  start(): void;
39
- /** The host's watchdog: this PC is low for a while. */
40
- hostPressure(seconds: number, reason: string): void;
6
+ /** The host's watchdog: this PC is low (or nearly out of memory) for a while. */
7
+ hostPressure(seconds: number, reason: string, level?: 'slow' | 'severe'): void;
41
8
  }
42
9
  export declare const governor: Governor;
@@ -1,21 +1,21 @@
1
- // The memory governor: samples the sandbox's memory every 2 seconds (memgov.exe, sandbox/csharp/MemGov.cs) and, when it
2
- // runs low, slows the heaviest build programs the agents started down and, as a last resort, pauses the biggest
3
- // compiler for a few seconds (decide.ts). What it does goes to the memory log and run\pressure.json, for the host.
1
+ // The memory governor: samples the sandbox's memory every 2 seconds (memgov.exe, sandbox/csharp/MemGov.cs) and turns
2
+ // a dial as it fills: the build programs the agents started get lower priority, lower memory priority, less CPU, and
3
+ // take turns (decide.ts). Builds slow down; nothing fails. What it does goes to the memory log and run\pressure.json.
4
4
  import fs from 'node:fs';
5
+ import os from 'node:os';
5
6
  import path from 'node:path';
6
7
  import { spawn } from 'node:child_process';
7
8
  import { createInterface } from 'node:readline';
8
9
  import { z } from 'zod';
9
- import { now } from '../../shared/channel/run-dir.js';
10
10
  import { writeJsonAtomic } from '../../shared/io/json.js';
11
- import { GUEST_THRESHOLDS } from '../../shared/memory/index.js';
11
+ import { DIAL_STEPS, maxCompilers } from '../../shared/memory/index.js';
12
12
  import { ensureCompiled } from '../runtime/csc.js';
13
13
  import { dataDir } from '../runtime/paths.js';
14
14
  import { warn } from '../runtime/log.js';
15
15
  import { run } from '../runtime/paths.js';
16
16
  import { session } from '../runtime/session.js';
17
17
  import { errMsg } from '../../core/util/errors.js';
18
- import { decide, INITIAL_STATE } from './decide.js';
18
+ import { GovernorCore } from './core.js';
19
19
  const SampleSchema = z.object({
20
20
  ramTotalMb: z.number(),
21
21
  ramAvailMb: z.number(),
@@ -30,87 +30,6 @@ const SampleSchema = z.object({
30
30
  }))
31
31
  .max(1024),
32
32
  });
33
- /** The governor's logic over a port: feed it samples; the host's "slow down" requests go to hostPressure. */
34
- export class GovernorCore {
35
- deps;
36
- state = INITIAL_STATE;
37
- lastAction = '';
38
- lastWrite = '';
39
- lastWriteAt = 0;
40
- pausedName = '';
41
- pausedPid = 0;
42
- constructor(deps) {
43
- this.deps = deps;
44
- }
45
- hostPressure(seconds, reason) {
46
- const until = this.deps.now() + seconds * 1000;
47
- if (until > this.state.hostUntil) {
48
- if (this.state.hostUntil <= this.deps.now())
49
- this.deps.logLine('governor: this PC is low (' + reason + '); slowing builds down');
50
- this.state = { ...this.state, hostUntil: until };
51
- }
52
- }
53
- get current() {
54
- return this.state;
55
- }
56
- onSample(sample) {
57
- const nowMs = this.deps.now();
58
- const before = this.state.pressure;
59
- const d = decide(this.state, sample, nowMs, GUEST_THRESHOLDS[this.deps.profile], this.deps.profile);
60
- this.state = d.state;
61
- for (const action of d.actions)
62
- this.apply(action);
63
- if (d.state.pressure !== before)
64
- this.deps.logLine(d.state.pressure
65
- ? 'governor: memory is low (' +
66
- d.ramFreePercent +
67
- '% RAM free, commit ' +
68
- d.commitPercent +
69
- '% used): slowing builds down'
70
- : 'governor: memory is fine again: builds back to normal');
71
- const paused = nowMs < d.state.pausedUntil && this.pausedPid
72
- ? [{ name: this.pausedName, pid: this.pausedPid, seconds: Math.ceil((d.state.pausedUntil - nowMs) / 1000) }]
73
- : [];
74
- const status = {
75
- level: d.level,
76
- profile: this.deps.profile,
77
- ramFreePercent: Math.max(0, Math.min(100, d.ramFreePercent)),
78
- commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
79
- lowered: Object.keys(d.state.lowered).length,
80
- paused,
81
- pcLow: nowMs < d.state.hostUntil,
82
- lastAction: this.lastAction,
83
- updatedAt: now(),
84
- };
85
- // Written when something changed, else once a minute (the host reads it, never polls it hard).
86
- const shape = JSON.stringify({ ...status, updatedAt: '', paused: paused.map((p) => p.pid) });
87
- if (shape !== this.lastWrite || nowMs - this.lastWriteAt > 60000) {
88
- this.lastWrite = shape;
89
- this.lastWriteAt = nowMs;
90
- this.deps.saveStatus(status);
91
- }
92
- }
93
- apply(action) {
94
- try {
95
- if (action.kind === 'priority') {
96
- this.deps.port.setPriority(action.pid, action.to);
97
- this.lastAction = action.name + ' (' + action.pid + ') priority ' + action.to;
98
- }
99
- else {
100
- this.deps.port.pause(action.pid, action.ms);
101
- this.pausedName = action.name;
102
- this.pausedPid = action.pid;
103
- this.lastAction = 'paused ' + action.name + ' (' + action.pid + ') for ' + action.ms / 1000 + ' s';
104
- this.deps.logLine('governor: ' + this.lastAction);
105
- return;
106
- }
107
- this.deps.logLine('governor: ' + this.lastAction);
108
- }
109
- catch (e) {
110
- warn('governor: ' + errMsg(e));
111
- }
112
- }
113
- }
114
33
  /** memgov.exe as a child process: samples come out of its stdout, commands go into its stdin. */
115
34
  class MemGovProcess {
116
35
  onSample;
@@ -145,10 +64,25 @@ class MemGovProcess {
145
64
  }
146
65
  }
147
66
  setPriority(pid, to) {
148
- this.child?.stdin?.write('priority ' + pid + ' ' + to + '\n');
67
+ this.send('priority ' + pid + ' ' + to);
68
+ }
69
+ hold(pid, ms) {
70
+ this.send('suspend ' + pid + ' ' + ms);
71
+ }
72
+ setMemoryPriority(pid, low) {
73
+ this.send('memprio ' + pid + ' ' + (low ? 'low' : 'normal'));
74
+ }
75
+ throttle(pid) {
76
+ this.send('throttle ' + pid);
77
+ }
78
+ setCpuRate(percent) {
79
+ this.send('cpurate ' + Math.round(percent));
80
+ }
81
+ trim(pid) {
82
+ this.send('trim ' + pid);
149
83
  }
150
- pause(pid, ms) {
151
- this.child?.stdin?.write('suspend ' + pid + ' ' + ms + '\n');
84
+ send(line) {
85
+ this.child?.stdin?.write(line + '\n');
152
86
  }
153
87
  }
154
88
  /** The newest memory log SandboxTools writes, to add the governor's lines to it. */
@@ -175,15 +109,15 @@ export class Governor {
175
109
  core = null;
176
110
  describe() {
177
111
  const profile = session.loadProfile === 'gentle' ? 'gentle' : 'normal';
178
- const t = GUEST_THRESHOLDS[profile];
112
+ const first = DIAL_STEPS[profile][0];
179
113
  return session.pressureResponse === false
180
114
  ? 'off (sandbox.pressureResponse)'
181
115
  : profile +
182
- ' profile: slows builds down below ' +
183
- t.enterAvailablePercent +
184
- '% free RAM or above ' +
185
- t.enterCommitPercent +
186
- '% commit';
116
+ ' profile: slows builds down from ' +
117
+ first.availablePercent +
118
+ '% free RAM or ' +
119
+ first.commitPercent +
120
+ '% commit, in steps';
187
121
  }
188
122
  start() {
189
123
  if (session.pressureResponse === false)
@@ -193,8 +127,10 @@ export class Governor {
193
127
  this.core = new GovernorCore({
194
128
  port: proc,
195
129
  profile,
130
+ maxCompilers: maxCompilers(os.cpus().length, profile),
196
131
  now: () => Date.now(),
197
132
  logLine: appendToMemoryLog,
133
+ warn,
198
134
  saveStatus: (status) => {
199
135
  try {
200
136
  writeJsonAtomic(run.pressureFile, status);
@@ -206,9 +142,9 @@ export class Governor {
206
142
  });
207
143
  proc.start();
208
144
  }
209
- /** The host's watchdog: this PC is low for a while. */
210
- hostPressure(seconds, reason) {
211
- this.core?.hostPressure(seconds, reason);
145
+ /** The host's watchdog: this PC is low (or nearly out of memory) for a while. */
146
+ hostPressure(seconds, reason, level = 'slow') {
147
+ this.core?.hostPressure(seconds, reason, level);
212
148
  }
213
149
  }
214
150
  export const governor = new Governor();
@@ -1,2 +1,3 @@
1
1
  export * from './decide.js';
2
+ export * from './core.js';
2
3
  export * from './governor.js';
@@ -1,2 +1,3 @@
1
1
  export * from './decide.js';
2
+ export * from './core.js';
2
3
  export * from './governor.js';
@@ -1,5 +1,8 @@
1
1
  /** What the agent's manifest says about the LAN. */
2
2
  export type LanState = 'blocked' | 'open' | 'offline';
3
+ export declare function networkProblems(): readonly string[];
4
+ /** netsh needs the long form of a path: the sandbox's TEMP is an 8.3 short path (WDAGUT~1). */
5
+ export declare function longPath(file: string): string;
3
6
  export declare function run(commands: string[][]): void;
4
7
  /**
5
8
  * Applies the LAN block. Internet is checked first; if it works before the rules but not after, the rules (not the
@@ -4,14 +4,13 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import { relayPort, withBlockedHosts } from '../../shared/network/policy.js';
7
- import { buildFirewallCommands, ipv4DnsServers, isIPv4, parseDefaultGateways, parseDnsServers, } from '../../shared/network/firewall-rules.js';
7
+ import { attachRuleCommands, buildFirewallCommands, hasShortName, ipv4DnsServers, isIPv4, parseDefaultGateways, parseDnsServers, } from '../../shared/network/firewall-rules.js';
8
8
  import { SYSTEM } from '../../shared/system.js';
9
9
  import { scriptArgs } from '../../shared/scripts.js';
10
10
  import { dryRun, isWin } from '../runtime/paths.js';
11
11
  import { log, warn } from '../runtime/log.js';
12
12
  import { session } from '../runtime/session.js';
13
13
  import { errMsg } from '../../core/util/errors.js';
14
- const ATTACH_RULE = 'AgentSandbox-Attach';
15
14
  const netsh = (args) => {
16
15
  const r = spawnSync(SYSTEM.netsh(), args, { encoding: 'utf8', windowsHide: true });
17
16
  return { status: r.status, out: (r.stdout ?? '') + (r.stderr ?? '') };
@@ -51,24 +50,49 @@ const waitForInternet = async (seconds) => {
51
50
  }
52
51
  return false;
53
52
  };
54
- /** Inbound rule for ptyhost only, and only from the sandbox's own subnet (where the host's Hyper-V adapter is). */
55
- const attachRule = (ptyHostExe) => [
56
- ['advfirewall', 'firewall', 'delete', 'rule', 'name=' + ATTACH_RULE],
57
- [
58
- 'advfirewall',
59
- 'firewall',
60
- 'add',
61
- 'rule',
62
- 'name=' + ATTACH_RULE,
63
- 'dir=in',
64
- 'action=allow',
65
- 'enable=yes',
66
- 'profile=any',
67
- 'protocol=tcp',
68
- 'remoteip=LocalSubnet',
69
- 'program=' + ptyHostExe,
70
- ],
71
- ];
53
+ /** Protections that could not be put in place this boot (shown in the boot summary and the log, never silent). */
54
+ const problems = [];
55
+ export function networkProblems() {
56
+ return problems;
57
+ }
58
+ /** netsh needs the long form of a path: the sandbox's TEMP is an 8.3 short path (WDAGUT~1). */
59
+ export function longPath(file) {
60
+ if (!hasShortName(file))
61
+ return file;
62
+ try {
63
+ return fs.realpathSync.native(file);
64
+ }
65
+ catch {
66
+ return file; // netsh then says the program cannot be found, which is reported where the rule was wanted
67
+ }
68
+ }
69
+ /**
70
+ * The inbound rule for ptyhost (the attach channel). A rule that cannot be added is a missing protection, so it is
71
+ * tried again a few times and then reported loudly instead of being skipped.
72
+ */
73
+ async function applyAttachRule(ptyHostExe) {
74
+ if (!session.attach.enabled)
75
+ return;
76
+ if (!ptyHostExe) {
77
+ problems.push('attach: the session host was not built, so the firewall rule for it was not created');
78
+ warn(problems[problems.length - 1]);
79
+ return;
80
+ }
81
+ let last = '';
82
+ for (let attempt = 1; attempt <= 3; attempt++) {
83
+ try {
84
+ run(attachRuleCommands(longPath(ptyHostExe)));
85
+ return;
86
+ }
87
+ catch (e) {
88
+ last = errMsg(e);
89
+ if (attempt < 3)
90
+ await new Promise((r) => setTimeout(r, 1000));
91
+ }
92
+ }
93
+ problems.push('attach: the firewall rule for the session host could not be created (' + last + ')');
94
+ warn('PROTECTION MISSING: ' + problems[problems.length - 1]);
95
+ }
72
96
  export function run(commands) {
73
97
  for (const c of commands) {
74
98
  const r = netsh(c);
@@ -89,10 +113,11 @@ export async function applyNetworkPolicy(ptyHostExe) {
89
113
  const block = session.network.blockPrivateRanges;
90
114
  const exempt = block ? discoverExemptIps() : [];
91
115
  const lanRules = block ? buildFirewallCommands(exempt) : [];
116
+ const forwardRules = forwardRule();
92
117
  const commands = [
93
118
  ...lanRules,
94
- ...(ptyHostExe && session.attach.enabled ? attachRule(ptyHostExe) : []),
95
- ...forwardRule(),
119
+ ...(ptyHostExe && session.attach.enabled ? attachRuleCommands(ptyHostExe) : []),
120
+ ...forwardRules,
96
121
  ];
97
122
  if (isWin && !dryRun) {
98
123
  try {
@@ -122,7 +147,24 @@ export async function applyNetworkPolicy(ptyHostExe) {
122
147
  if (commands.length === 0)
123
148
  return 'open';
124
149
  const online = block ? await waitForInternet(30) : true;
125
- run(commands);
150
+ // Each group on its own: one failing must not skip the others (or the internet check below).
151
+ const failures = [];
152
+ try {
153
+ run(lanRules);
154
+ }
155
+ catch (e) {
156
+ failures.push(errMsg(e));
157
+ }
158
+ await applyAttachRule(ptyHostExe);
159
+ try {
160
+ run(forwardRules);
161
+ }
162
+ catch (e) {
163
+ problems.push('forwardPorts: the firewall rule for the relays could not be created (' + errMsg(e) + ')');
164
+ warn('PROTECTION MISSING: ' + problems[problems.length - 1]);
165
+ }
166
+ if (failures.length)
167
+ throw new Error(failures[0]);
126
168
  if (!block)
127
169
  return 'open';
128
170
  if (online && !(await waitForInternet(15))) {