windows-development-sandbox 1.7.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/config.example.json +12 -1
  2. package/dist/app/context.d.ts +8 -0
  3. package/dist/app/context.js +12 -0
  4. package/dist/app/features/defs.d.ts +322 -0
  5. package/dist/app/features/defs.js +28 -0
  6. package/dist/app/features/sandbox/index.d.ts +2 -0
  7. package/dist/app/features/sandbox/index.js +3 -0
  8. package/dist/app/features/sandbox/sandbox.def.d.ts +193 -0
  9. package/dist/app/features/sandbox/sandbox.def.js +245 -0
  10. package/dist/app/features/sandbox/sandbox.run.d.ts +72 -0
  11. package/dist/app/features/sandbox/sandbox.run.js +98 -0
  12. package/dist/app/features/sessions/index.d.ts +2 -0
  13. package/dist/app/features/sessions/index.js +3 -0
  14. package/dist/app/features/sessions/sessions.def.d.ts +141 -0
  15. package/dist/app/features/sessions/sessions.def.js +176 -0
  16. package/dist/app/features/sessions/sessions.run.d.ts +39 -0
  17. package/dist/app/features/sessions/sessions.run.js +58 -0
  18. package/dist/{cli/menu/settings/categories.d.ts → app/features/settings/categories.def.d.ts} +2 -0
  19. package/dist/{cli/menu/settings/categories.js → app/features/settings/categories.def.js} +24 -5
  20. package/dist/app/features/settings/index.d.ts +5 -0
  21. package/dist/app/features/settings/index.js +6 -0
  22. package/dist/{cli/menu/settings/config-file.d.ts → app/features/settings/settings-file.d.ts} +1 -1
  23. package/dist/{cli/menu/settings/config-file.js → app/features/settings/settings-file.js} +1 -1
  24. package/dist/app/features/settings/settings-rows.d.ts +35 -0
  25. package/dist/app/features/settings/settings-rows.js +94 -0
  26. package/dist/app/features/settings/settings.def.d.ts +157 -0
  27. package/dist/app/features/settings/settings.def.js +179 -0
  28. package/dist/app/features/settings/settings.run.d.ts +67 -0
  29. package/dist/app/features/settings/settings.run.js +84 -0
  30. package/dist/app/kernel/define.d.ts +143 -0
  31. package/dist/app/kernel/define.js +42 -0
  32. package/dist/app/kernel/errors.d.ts +34 -0
  33. package/dist/app/kernel/errors.js +45 -0
  34. package/dist/app/kernel/fields.d.ts +70 -0
  35. package/dist/app/kernel/fields.js +243 -0
  36. package/dist/app/kernel/index.d.ts +8 -0
  37. package/dist/app/kernel/index.js +10 -0
  38. package/dist/app/kernel/io.d.ts +193 -0
  39. package/dist/app/kernel/io.js +126 -0
  40. package/dist/app/kernel/rpc.d.ts +156 -0
  41. package/dist/app/kernel/rpc.js +47 -0
  42. package/dist/app/kernel/text.d.ts +6 -0
  43. package/dist/app/kernel/text.js +57 -0
  44. package/dist/app/kernel/view.d.ts +146 -0
  45. package/dist/app/kernel/view.js +28 -0
  46. package/dist/app/registry.d.ts +10 -0
  47. package/dist/app/registry.js +50 -0
  48. package/dist/cli/args.d.ts +5 -0
  49. package/dist/cli/args.js +6 -0
  50. package/dist/cli/commands/engine.d.ts +2 -0
  51. package/dist/cli/commands/engine.js +60 -0
  52. package/dist/cli/commands/index.d.ts +1 -1
  53. package/dist/cli/commands/index.js +1 -1
  54. package/dist/cli/commands/launch/launch.js +49 -7
  55. package/dist/cli/commands/launch/prepare.js +3 -3
  56. package/dist/cli/commands/launch/running.js +2 -1
  57. package/dist/cli/commands/launch/summary.d.ts +2 -0
  58. package/dist/cli/commands/maintenance/config-share.d.ts +12 -0
  59. package/dist/cli/commands/maintenance/config-share.js +80 -0
  60. package/dist/cli/commands/maintenance/config.js +8 -82
  61. package/dist/cli/commands/maintenance/logs.js +14 -0
  62. package/dist/cli/commands/registry.js +3 -7
  63. package/dist/cli/commands/repair/checks/contained.d.ts +2 -0
  64. package/dist/cli/commands/repair/checks/contained.js +139 -0
  65. package/dist/cli/commands/repair/checks/hcs.d.ts +7 -0
  66. package/dist/cli/commands/repair/checks/hcs.js +28 -0
  67. package/dist/cli/commands/repair/checks/index.js +4 -0
  68. package/dist/cli/commands/repair/checks/pc.js +32 -1
  69. package/dist/cli/commands/repair/checks/sandbox.js +16 -1
  70. package/dist/cli/commands/repair/checks/vpn.js +34 -9
  71. package/dist/cli/commands/repair/env.js +2 -1
  72. package/dist/cli/commands/sessions/index.d.ts +0 -4
  73. package/dist/cli/commands/sessions/index.js +3 -7
  74. package/dist/cli/commands/shared-use.d.ts +5 -2
  75. package/dist/cli/commands/shared-use.js +11 -8
  76. package/dist/cli/commands/storage/contained.d.ts +3 -0
  77. package/dist/cli/commands/storage/contained.js +179 -0
  78. package/dist/cli/commands/storage/offer.js +7 -1
  79. package/dist/cli/commands/storage/storage.js +10 -2
  80. package/dist/cli/commands/user-config.js +1 -1
  81. package/dist/cli/commands/vpn.js +20 -3
  82. package/dist/cli/commands/web.d.ts +5 -0
  83. package/dist/cli/commands/web.js +40 -0
  84. package/dist/cli/index.js +2 -1
  85. package/dist/cli/manifest.d.ts +72 -104
  86. package/dist/cli/manifest.js +64 -39
  87. package/dist/cli/menu/add-agent.d.ts +1 -1
  88. package/dist/cli/menu/add-agent.js +1 -1
  89. package/dist/cli/menu/apps.d.ts +7 -1
  90. package/dist/cli/menu/apps.js +36 -0
  91. package/dist/cli/menu/command-fields.d.ts +1 -1
  92. package/dist/cli/menu/command-form.js +2 -2
  93. package/dist/cli/menu/io-menu.d.ts +29 -0
  94. package/dist/cli/menu/io-menu.js +126 -0
  95. package/dist/cli/menu/live.d.ts +27 -0
  96. package/dist/cli/menu/live.js +69 -0
  97. package/dist/cli/menu/memory.d.ts +19 -0
  98. package/dist/cli/menu/memory.js +53 -0
  99. package/dist/cli/menu/menu.d.ts +10 -1
  100. package/dist/cli/menu/menu.js +27 -9
  101. package/dist/cli/menu/pages/agents-page.d.ts +3 -1
  102. package/dist/cli/menu/pages/agents-page.js +12 -5
  103. package/dist/cli/menu/pages/apps-page.d.ts +3 -1
  104. package/dist/cli/menu/pages/apps-page.js +19 -2
  105. package/dist/cli/menu/pages/list-page.d.ts +27 -0
  106. package/dist/cli/menu/pages/list-page.js +109 -7
  107. package/dist/cli/menu/pages/maintenance-page.d.ts +0 -5
  108. package/dist/cli/menu/pages/maintenance-page.js +17 -19
  109. package/dist/cli/menu/pages/sandbox-page.d.ts +4 -6
  110. package/dist/cli/menu/pages/sandbox-page.js +26 -118
  111. package/dist/cli/menu/pages/scopes.d.ts +1 -1
  112. package/dist/cli/menu/pages/sessions-page.d.ts +5 -11
  113. package/dist/cli/menu/pages/sessions-page.js +19 -88
  114. package/dist/cli/menu/pages/settings-page.d.ts +2 -10
  115. package/dist/cli/menu/pages/settings-page.js +64 -94
  116. package/dist/cli/menu/render-view.d.ts +28 -0
  117. package/dist/cli/menu/render-view.js +112 -0
  118. package/dist/cli/menu/settings/{path-kind.d.ts → ask-path.d.ts} +1 -7
  119. package/dist/cli/menu/settings/ask-path.js +14 -0
  120. package/dist/cli/menu/settings/collections/collection-editor.d.ts +1 -1
  121. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +1 -2
  122. package/dist/cli/menu/settings/collections/string-list-editor.js +1 -1
  123. package/dist/cli/menu/settings/draft.d.ts +1 -1
  124. package/dist/cli/menu/settings/format.d.ts +1 -3
  125. package/dist/cli/menu/settings/format.js +6 -36
  126. package/dist/cli/menu/settings/index.d.ts +1 -3
  127. package/dist/cli/menu/settings/index.js +3 -3
  128. package/dist/cli/menu/settings/object-editor.d.ts +1 -1
  129. package/dist/cli/menu/settings/share.d.ts +36 -0
  130. package/dist/cli/menu/settings/share.js +131 -0
  131. package/dist/cli/menu/settings/value-editor.d.ts +5 -1
  132. package/dist/cli/menu/settings/value-editor.js +57 -54
  133. package/dist/cli/menu/several.js +1 -1
  134. package/dist/cli/menu/share-settings.d.ts +21 -0
  135. package/dist/cli/menu/share-settings.js +112 -0
  136. package/dist/cli/menu/shell.d.ts +21 -5
  137. package/dist/cli/menu/shell.js +31 -6
  138. package/dist/cli/menu/views.d.ts +7 -0
  139. package/dist/cli/menu/views.js +11 -0
  140. package/dist/cli/menu/vpn-login.js +8 -0
  141. package/dist/cli/operations/handler.d.ts +6 -0
  142. package/dist/cli/operations/handler.js +61 -0
  143. package/dist/cli/operations/index.d.ts +4 -0
  144. package/dist/cli/operations/index.js +5 -0
  145. package/dist/cli/operations/input.d.ts +6 -0
  146. package/dist/cli/operations/input.js +37 -0
  147. package/dist/cli/operations/io-cli.d.ts +7 -0
  148. package/dist/cli/operations/io-cli.js +62 -0
  149. package/dist/cli/operations/spec.d.ts +18 -0
  150. package/dist/cli/operations/spec.js +108 -0
  151. package/dist/cli/output/colors.d.ts +2 -2
  152. package/dist/cli/output/colors.js +2 -11
  153. package/dist/cli/output/index.d.ts +1 -0
  154. package/dist/cli/output/index.js +1 -0
  155. package/dist/cli/output/print.d.ts +3 -1
  156. package/dist/cli/output/print.js +7 -3
  157. package/dist/cli/output/progress.d.ts +15 -0
  158. package/dist/cli/output/progress.js +44 -0
  159. package/dist/cli/output/render-view.d.ts +4 -0
  160. package/dist/cli/output/render-view.js +63 -0
  161. package/dist/cli/services/agent-commands-service.d.ts +2 -0
  162. package/dist/cli/services/agent-commands-service.js +11 -2
  163. package/dist/cli/services/logs-service.js +4 -3
  164. package/dist/cli/tui/app.d.ts +6 -1
  165. package/dist/cli/tui/app.js +26 -4
  166. package/dist/cli/tui/list/list-screen.d.ts +14 -0
  167. package/dist/cli/tui/list/list-screen.js +64 -36
  168. package/dist/cli/tui/list/list-types.d.ts +2 -0
  169. package/dist/cli/tui/terminal.d.ts +7 -0
  170. package/dist/cli/tui/terminal.js +30 -10
  171. package/dist/core/config/defaults.js +9 -1
  172. package/dist/core/schema/config.d.ts +14 -0
  173. package/dist/core/schema/config.js +16 -1
  174. package/dist/core/schema/harness.d.ts +1 -0
  175. package/dist/core/schema/harness.js +5 -0
  176. package/dist/core/schema/sandbox.d.ts +6 -0
  177. package/dist/core/schema/sandbox.js +20 -3
  178. package/dist/core/schema/vpn.d.ts +2 -1
  179. package/dist/core/schema/vpn.js +4 -4
  180. package/dist/core/schema/web.d.ts +1 -0
  181. package/dist/core/schema/web.js +4 -1
  182. package/dist/core/types.d.ts +23 -5
  183. package/dist/core/util/fs.d.ts +2 -0
  184. package/dist/core/util/fs.js +9 -0
  185. package/dist/core/util/index.d.ts +1 -1
  186. package/dist/core/util/index.js +1 -1
  187. package/dist/guest/agents/agent-files.d.ts +5 -0
  188. package/dist/guest/agents/agent-files.js +4 -0
  189. package/dist/guest/agents/local-state.d.ts +2 -0
  190. package/dist/guest/agents/local-state.js +21 -1
  191. package/dist/guest/boot/boot.js +5 -2
  192. package/dist/guest/daemon/daemon.js +4 -0
  193. package/dist/guest/daemon/sessions.d.ts +5 -0
  194. package/dist/guest/daemon/sessions.js +17 -3
  195. package/dist/guest/entries/daemon.js +3 -0
  196. package/dist/guest/governor/decide.d.ts +71 -0
  197. package/dist/guest/governor/decide.js +211 -0
  198. package/dist/guest/governor/governor.d.ts +45 -0
  199. package/dist/guest/governor/governor.js +230 -0
  200. package/dist/guest/governor/index.d.ts +2 -0
  201. package/dist/guest/governor/index.js +2 -0
  202. package/dist/guest/network/firewall.d.ts +1 -0
  203. package/dist/guest/network/firewall.js +65 -23
  204. package/dist/guest/runtime/csc.d.ts +1 -0
  205. package/dist/guest/runtime/csc.js +1 -0
  206. package/dist/guest/runtime/process.js +53 -5
  207. package/dist/guest/sessions/viewer.js +3 -1
  208. package/dist/guest/setup/claude-mem.js +12 -4
  209. package/dist/guest/toolchains/languages/node.js +29 -3
  210. package/dist/guest/toolchains/native/rust-extras.js +4 -2
  211. package/dist/guest/vpn/vpn.js +69 -21
  212. package/dist/guest/vpn/wireguard.d.ts +32 -0
  213. package/dist/guest/vpn/wireguard.js +132 -0
  214. package/dist/host/agent-commands/commands.d.ts +4 -0
  215. package/dist/host/agent-commands/commands.js +31 -7
  216. package/dist/host/audit/log.d.ts +1 -1
  217. package/dist/host/channel/attach.d.ts +3 -1
  218. package/dist/host/channel/attach.js +5 -2
  219. package/dist/host/channel/channel.d.ts +2 -0
  220. package/dist/host/channel/channel.js +4 -0
  221. package/dist/host/engines/engine.d.ts +12 -0
  222. package/dist/host/engines/engine.js +1 -0
  223. package/dist/host/engines/hcs/check.d.ts +25 -0
  224. package/dist/host/engines/hcs/check.js +95 -0
  225. package/dist/host/engines/hcs/documents.d.ts +44 -0
  226. package/dist/host/engines/hcs/documents.js +155 -0
  227. package/dist/host/engines/hcs/engine.d.ts +39 -0
  228. package/dist/host/engines/hcs/engine.js +171 -0
  229. package/dist/host/engines/hcs/helper.d.ts +43 -0
  230. package/dist/host/engines/hcs/helper.js +173 -0
  231. package/dist/host/engines/hcs/images.d.ts +37 -0
  232. package/dist/host/engines/hcs/images.js +152 -0
  233. package/dist/host/engines/index.d.ts +7 -0
  234. package/dist/host/engines/index.js +5 -0
  235. package/dist/host/engines/registry.d.ts +16 -0
  236. package/dist/host/engines/registry.js +30 -0
  237. package/dist/host/engines/types.d.ts +58 -0
  238. package/dist/host/engines/types.js +1 -0
  239. package/dist/host/engines/windows-sandbox/engine.d.ts +16 -0
  240. package/dist/host/engines/windows-sandbox/engine.js +63 -0
  241. package/dist/host/engines/windows-sandbox/wsb-text.d.ts +2 -0
  242. package/dist/host/engines/windows-sandbox/wsb-text.js +29 -0
  243. package/dist/host/launch/generate.d.ts +5 -1
  244. package/dist/host/launch/generate.js +50 -8
  245. package/dist/host/launch/index.d.ts +3 -1
  246. package/dist/host/launch/index.js +3 -1
  247. package/dist/host/launch/launch-plan.d.ts +13 -0
  248. package/dist/host/launch/launch-plan.js +26 -0
  249. package/dist/host/launch/mappings.js +2 -1
  250. package/dist/host/launch/risk-notes.d.ts +10 -0
  251. package/dist/host/launch/risk-notes.js +18 -0
  252. package/dist/host/launch/session-file.d.ts +2 -0
  253. package/dist/host/launch/session-file.js +7 -1
  254. package/dist/host/launch/wsb-file.d.ts +28 -4
  255. package/dist/host/launch/wsb-file.js +61 -42
  256. package/dist/host/life/crash-report.d.ts +27 -1
  257. package/dist/host/life/crash-report.js +173 -7
  258. package/dist/host/life/host-memory.d.ts +41 -0
  259. package/dist/host/life/host-memory.js +140 -0
  260. package/dist/host/life/index.d.ts +2 -0
  261. package/dist/host/life/index.js +2 -0
  262. package/dist/host/life/stop-events.d.ts +2 -0
  263. package/dist/host/life/stop-events.js +20 -3
  264. package/dist/host/life/stop-warning.js +1 -1
  265. package/dist/host/life/watchdog.d.ts +56 -0
  266. package/dist/host/life/watchdog.js +124 -0
  267. package/dist/host/native.d.ts +3 -2
  268. package/dist/host/native.js +22 -3
  269. package/dist/host/profile/claude-login.js +3 -2
  270. package/dist/host/sandbox/contained-deps.d.ts +2 -0
  271. package/dist/host/sandbox/contained-deps.js +17 -0
  272. package/dist/host/sandbox/index.d.ts +2 -0
  273. package/dist/host/sandbox/index.js +2 -0
  274. package/dist/host/sandbox/platform.d.ts +2 -0
  275. package/dist/host/sandbox/platform.js +7 -7
  276. package/dist/host/sandbox/tasklist.d.ts +13 -0
  277. package/dist/host/sandbox/tasklist.js +47 -0
  278. package/dist/host/secrets/launch-secrets.js +2 -1
  279. package/dist/host/sharing/current.js +2 -6
  280. package/dist/host/storage/contained/check.d.ts +9 -0
  281. package/dist/host/storage/contained/check.js +37 -0
  282. package/dist/host/storage/contained/contained-storage.d.ts +66 -0
  283. package/dist/host/storage/contained/contained-storage.js +168 -0
  284. package/dist/host/storage/contained/disk-port.d.ts +43 -0
  285. package/dist/host/storage/contained/disk-port.js +122 -0
  286. package/dist/host/storage/contained/index.d.ts +9 -0
  287. package/dist/host/storage/contained/index.js +8 -0
  288. package/dist/host/storage/contained/layout.d.ts +28 -0
  289. package/dist/host/storage/contained/layout.js +45 -0
  290. package/dist/host/storage/contained/resolve.d.ts +4 -0
  291. package/dist/host/storage/contained/resolve.js +30 -0
  292. package/dist/host/storage/contained/setting.d.ts +1 -0
  293. package/dist/host/storage/contained/setting.js +5 -0
  294. package/dist/host/storage/contained/state.d.ts +89 -0
  295. package/dist/host/storage/contained/state.js +166 -0
  296. package/dist/host/storage/contained/transfer.d.ts +24 -0
  297. package/dist/host/storage/contained/transfer.js +121 -0
  298. package/dist/host/storage/index.d.ts +2 -0
  299. package/dist/host/storage/index.js +2 -0
  300. package/dist/host/storage/providers/contained.d.ts +15 -0
  301. package/dist/host/storage/providers/contained.js +39 -0
  302. package/dist/host/storage/providers/folder.d.ts +12 -0
  303. package/dist/host/storage/providers/folder.js +20 -0
  304. package/dist/host/storage/providers/index.d.ts +4 -0
  305. package/dist/host/storage/providers/index.js +3 -0
  306. package/dist/host/storage/providers/registry.d.ts +9 -0
  307. package/dist/host/storage/providers/registry.js +14 -0
  308. package/dist/host/storage/providers/types.d.ts +33 -0
  309. package/dist/host/storage/providers/types.js +1 -0
  310. package/dist/host/tools/conpty.js +3 -2
  311. package/dist/host/tools/windows-terminal.js +8 -7
  312. package/dist/host/vpn/index.d.ts +1 -1
  313. package/dist/host/vpn/index.js +1 -1
  314. package/dist/host/vpn/prepare.d.ts +2 -0
  315. package/dist/host/vpn/prepare.js +63 -2
  316. package/dist/host/web/browser.d.ts +2 -0
  317. package/dist/host/web/browser.js +14 -1
  318. package/dist/host/web/index.d.ts +3 -2
  319. package/dist/host/web/index.js +3 -2
  320. package/dist/host/web/rpc.d.ts +24 -0
  321. package/dist/host/web/rpc.js +149 -0
  322. package/dist/host/web/runner.d.ts +2 -0
  323. package/dist/host/web/runner.js +1 -2
  324. package/dist/host/web/server.d.ts +7 -0
  325. package/dist/host/web/server.js +23 -3
  326. package/dist/runtime/agent.js +83 -18
  327. package/dist/runtime/daemon.js +1805 -1221
  328. package/dist/runtime/db.js +83 -18
  329. package/dist/runtime/main.js +779 -219
  330. package/dist/runtime/netproxy.js +73 -11
  331. package/dist/runtime/view.js +91 -16
  332. package/dist/selftest/agent-paths.test.js +11 -1
  333. package/dist/selftest/app.test.d.ts +2 -0
  334. package/dist/selftest/app.test.js +324 -0
  335. package/dist/selftest/channel.test.js +13 -0
  336. package/dist/selftest/cli.test.js +2 -1
  337. package/dist/selftest/config.test.js +59 -0
  338. package/dist/selftest/contained.test.d.ts +2 -0
  339. package/dist/selftest/contained.test.js +544 -0
  340. package/dist/selftest/credentials.test.js +1 -1
  341. package/dist/selftest/engine.test.d.ts +2 -0
  342. package/dist/selftest/engine.test.js +127 -0
  343. package/dist/selftest/guest-boot.test.js +47 -1
  344. package/dist/selftest/hcs.test.d.ts +2 -0
  345. package/dist/selftest/hcs.test.js +482 -0
  346. package/dist/selftest/heavy-load.test.d.ts +2 -0
  347. package/dist/selftest/heavy-load.test.js +355 -0
  348. package/dist/selftest/index.js +12 -0
  349. package/dist/selftest/layout.test.js +12 -0
  350. package/dist/selftest/menu-perf.test.d.ts +2 -0
  351. package/dist/selftest/menu-perf.test.js +248 -0
  352. package/dist/selftest/menu-screens.js +4 -2
  353. package/dist/selftest/menu.test.js +36 -8
  354. package/dist/selftest/network.test.js +20 -1
  355. package/dist/selftest/support/engine-cases.d.ts +8 -0
  356. package/dist/selftest/support/engine-cases.js +65 -0
  357. package/dist/selftest/support/engine-golden.d.ts +3 -0
  358. package/dist/selftest/support/engine-golden.js +66 -0
  359. package/dist/selftest/support/fixtures.d.ts +8 -1
  360. package/dist/selftest/support/hcs-probes.d.ts +17 -0
  361. package/dist/selftest/support/hcs-probes.js +41 -0
  362. package/dist/selftest/vpn.test.js +136 -3
  363. package/dist/selftest/web.test.js +101 -3
  364. package/dist/shared/channel/run-dir.d.ts +4 -1
  365. package/dist/shared/channel/run-dir.js +7 -1
  366. package/dist/shared/channel/schema.d.ts +35 -1
  367. package/dist/shared/channel/schema.js +27 -0
  368. package/dist/shared/channel/secrets.d.ts +1 -0
  369. package/dist/shared/channel/secrets.js +6 -0
  370. package/dist/shared/io/copy-tree.d.ts +7 -0
  371. package/dist/shared/io/copy-tree.js +45 -0
  372. package/dist/shared/io/index.d.ts +2 -0
  373. package/dist/shared/io/index.js +2 -0
  374. package/dist/shared/io/robocopy-result.d.ts +6 -0
  375. package/dist/shared/io/robocopy-result.js +23 -0
  376. package/dist/shared/memory/index.d.ts +1 -0
  377. package/dist/shared/memory/index.js +1 -0
  378. package/dist/shared/memory/policy.d.ts +38 -0
  379. package/dist/shared/memory/policy.js +63 -0
  380. package/dist/shared/network/firewall-rules.d.ts +8 -0
  381. package/dist/shared/network/firewall-rules.js +28 -0
  382. package/dist/shared/pty/output-filter.d.ts +14 -1
  383. package/dist/shared/pty/output-filter.js +22 -4
  384. package/dist/shared/pty/terminal.d.ts +4 -1
  385. package/dist/shared/pty/terminal.js +4 -2
  386. package/dist/shared/system.d.ts +1 -0
  387. package/dist/shared/system.js +1 -0
  388. package/dist/shared/vpn/download.d.ts +16 -0
  389. package/dist/shared/vpn/download.js +16 -0
  390. package/dist/shared/vpn/wireguard.d.ts +51 -0
  391. package/dist/shared/vpn/wireguard.js +227 -0
  392. package/dist/sync/sync-cycle.js +5 -5
  393. package/dist/sync/watcher.d.ts +13 -0
  394. package/dist/sync/watcher.js +92 -3
  395. package/dist/web/index.html +4 -3
  396. package/dist/web/main-NRRS5O6Z.js +157 -0
  397. package/dist/web/main-T5DMCHYV.css +1 -0
  398. package/native/csharp/HcsHost/AssemblyInfo.cs +14 -0
  399. package/native/csharp/HcsHost/Guard.cs +100 -0
  400. package/native/csharp/HcsHost/Hcs.cs +256 -0
  401. package/native/csharp/HcsHost/Json.cs +78 -0
  402. package/native/csharp/HcsHost/Program.cs +185 -0
  403. package/native/csharp/HcsHost/VirtualDisk.cs +95 -0
  404. package/native/csharp/HostTools/AssemblyInfo.cs +14 -0
  405. package/native/csharp/HostTools/MemoryStatus.cs +128 -0
  406. package/native/csharp/HostTools/Program.cs +58 -17
  407. package/native/scripts/check-contained.ps1 +28 -0
  408. package/native/scripts/contained-common.ps1 +241 -0
  409. package/native/scripts/dismount-contained.ps1 +66 -0
  410. package/native/scripts/memory-status.ps1 +42 -0
  411. package/native/scripts/mount-contained.ps1 +139 -0
  412. package/native/scripts/run-elevated.ps1 +17 -4
  413. package/native/scripts/stop-events.ps1 +23 -8
  414. package/package.json +9 -2
  415. package/sandbox/csharp/MemGov.cs +466 -0
  416. package/sandbox/csharp/PtyHost.cs +111 -5
  417. package/sandbox/scripts/new-shortcuts.ps1 +3 -1
  418. package/schemas/config.schema.json +66 -8
  419. package/schemas/sandbox-config.schema.json +3 -3
  420. package/dist/cli/commands/sessions/control.d.ts +0 -4
  421. package/dist/cli/commands/sessions/control.js +0 -66
  422. package/dist/cli/commands/sessions/list.d.ts +0 -2
  423. package/dist/cli/commands/sessions/list.js +0 -48
  424. package/dist/cli/commands/sessions/status.d.ts +0 -4
  425. package/dist/cli/commands/sessions/status.js +0 -114
  426. package/dist/cli/commands/sessions/window.d.ts +0 -3
  427. package/dist/cli/commands/sessions/window.js +0 -18
  428. package/dist/cli/menu/settings/path-kind.js +0 -44
  429. package/dist/web/main-CXESL347.js +0 -45
  430. package/dist/web/main-VLR7DVQ4.css +0 -1
  431. /package/dist/{cli/menu/settings → app/kernel}/schema-node.d.ts +0 -0
  432. /package/dist/{cli/menu/settings → app/kernel}/schema-node.js +0 -0
@@ -0,0 +1,466 @@
1
+ // memgov.exe: the Windows side of the sandbox's memory governor (src/guest/governor). One long-running process the
2
+ // daemon talks to over stdin/stdout, so the decisions stay in TypeScript and only the Win32 calls live here. C# 5.
3
+ //
4
+ // stdout, a JSON line every --interval seconds (default 2):
5
+ // {"ramTotalMb":..,"ramAvailMb":..,"commitLimitMb":..,"commitAvailMb":..,"procs":[{"pid":..,"name":"rustc","mb":..,"prio":"normal"}]}
6
+ // procs = the processes in the agents' job (the job ptyhost makes for everything the agents start), nothing else.
7
+ // stdin, one command per line:
8
+ // priority <pid> <idle|below|normal> lowers (or restores) the priority of a process in that job
9
+ // suspend <pid> <ms> pauses a process in that job, resumes it after ms (at most 30000)
10
+ // exit
11
+ //
12
+ // It only ever touches processes that are in the agents' job, never itself, and resumes everything it paused when it
13
+ // ends or when the daemon goes away (stdin closes).
14
+ using System;
15
+ using System.Collections.Generic;
16
+ using System.ComponentModel;
17
+ using System.Diagnostics;
18
+ using System.Globalization;
19
+ using System.IO;
20
+ using System.Runtime.InteropServices;
21
+ using System.Text;
22
+ using System.Threading;
23
+
24
+ static class MemGov
25
+ {
26
+ private const string AgentJobName = "Local\\AgentSandboxAgentsJob";
27
+ private const double BytesPerMb = 1024.0 * 1024.0;
28
+ private const int MaxProcesses = 1024;
29
+ private const int MaxSuspendMs = 30000;
30
+ private const uint JobObjectQuery = 0x0004;
31
+ private const int JobObjectBasicProcessIdList = 3;
32
+ private const uint ProcessQueryLimited = 0x1000;
33
+ private const uint ProcessSetInformation = 0x0200;
34
+ private const uint ProcessSuspendResume = 0x0800;
35
+ private const uint IdleClass = 0x00000040;
36
+ private const uint BelowNormalClass = 0x00004000;
37
+ private const uint NormalClass = 0x00000020;
38
+
39
+ // MEMORYSTATUSEX.
40
+ [StructLayout(LayoutKind.Sequential)]
41
+ private struct MemoryStatus
42
+ {
43
+ public uint Length;
44
+ public uint MemoryLoad;
45
+ public ulong TotalPhys;
46
+ public ulong AvailPhys;
47
+ public ulong TotalPageFile;
48
+ public ulong AvailPageFile;
49
+ public ulong TotalVirtual;
50
+ public ulong AvailVirtual;
51
+ public ulong AvailExtendedVirtual;
52
+ }
53
+
54
+ private static class NativeMethods
55
+ {
56
+ [DllImport("kernel32.dll", SetLastError = true)]
57
+ public static extern bool GlobalMemoryStatusEx(ref MemoryStatus status);
58
+
59
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
60
+ public static extern IntPtr OpenJobObjectW(uint access, bool inherit, string name);
61
+
62
+ [DllImport("kernel32.dll", SetLastError = true)]
63
+ public static extern bool QueryInformationJobObject(IntPtr job, int infoClass, IntPtr info, int length, IntPtr returnLength);
64
+
65
+ [DllImport("kernel32.dll", SetLastError = true)]
66
+ public static extern bool IsProcessInJob(IntPtr process, IntPtr job, out bool result);
67
+
68
+ [DllImport("kernel32.dll", SetLastError = true)]
69
+ public static extern IntPtr OpenProcess(uint access, bool inherit, int pid);
70
+
71
+ [DllImport("kernel32.dll", SetLastError = true)]
72
+ public static extern bool SetPriorityClass(IntPtr process, uint priorityClass);
73
+
74
+ [DllImport("kernel32.dll", SetLastError = true)]
75
+ public static extern uint GetPriorityClass(IntPtr process);
76
+
77
+ [DllImport("kernel32.dll", SetLastError = true)]
78
+ public static extern bool CloseHandle(IntPtr handle);
79
+
80
+ [DllImport("ntdll.dll")]
81
+ public static extern int NtSuspendProcess(IntPtr process);
82
+
83
+ [DllImport("ntdll.dll")]
84
+ public static extern int NtResumeProcess(IntPtr process);
85
+ }
86
+
87
+ private static readonly object Gate = new object();
88
+ private static readonly Dictionary<int, DateTime> Paused = new Dictionary<int, DateTime>();
89
+
90
+ /// <summary>The paused process ids on disk, so a memgov that is killed mid-pause is undone by the next one.</summary>
91
+ private static readonly string HeldFile = Path.Combine(Path.GetTempPath(), "agent-sandbox-memgov-held.txt");
92
+ private static IntPtr job = IntPtr.Zero;
93
+ private static volatile bool stop;
94
+
95
+ static int Main(string[] args)
96
+ {
97
+ if (args.Length == 0 || args[0] != "serve")
98
+ {
99
+ Console.Error.WriteLine("usage: memgov serve [--interval seconds]");
100
+ return 2;
101
+ }
102
+ int interval = 2;
103
+ for (int i = 1; i + 1 < args.Length; i++)
104
+ {
105
+ if (args[i] == "--interval")
106
+ {
107
+ int.TryParse(args[i + 1], NumberStyles.Integer, CultureInfo.InvariantCulture, out interval);
108
+ }
109
+ }
110
+ if (interval < 1)
111
+ {
112
+ interval = 2;
113
+ }
114
+ // A memgov that ended without resuming (killed, crashed) left its pauses in the file: undo them first.
115
+ RecoverHeld();
116
+ Thread commands = new Thread(ReadCommands);
117
+ commands.IsBackground = true;
118
+ commands.Start();
119
+ Thread resumer = new Thread(ResumeWhenDue);
120
+ resumer.IsBackground = true;
121
+ resumer.Start();
122
+ while (!stop)
123
+ {
124
+ try
125
+ {
126
+ Console.Out.WriteLine(Sample());
127
+ Console.Out.Flush();
128
+ }
129
+ catch (Exception)
130
+ {
131
+ // A sample that fails (a process ended while it was read) is skipped; the next one tries again.
132
+ }
133
+ for (int waited = 0; waited < interval * 10 && !stop; waited++)
134
+ {
135
+ Thread.Sleep(100);
136
+ }
137
+ }
138
+ ResumeAll();
139
+ return 0;
140
+ }
141
+
142
+ /// <summary>The job, opened once it exists (ptyhost makes it when the first agent starts).</summary>
143
+ private static IntPtr Job()
144
+ {
145
+ if (job == IntPtr.Zero)
146
+ {
147
+ job = NativeMethods.OpenJobObjectW(JobObjectQuery, false, AgentJobName);
148
+ }
149
+ return job;
150
+ }
151
+
152
+ private static string Sample()
153
+ {
154
+ MemoryStatus status = new MemoryStatus();
155
+ status.Length = (uint)Marshal.SizeOf(typeof(MemoryStatus));
156
+ if (!NativeMethods.GlobalMemoryStatusEx(ref status))
157
+ {
158
+ throw new Win32Exception(Marshal.GetLastWin32Error());
159
+ }
160
+ StringBuilder sb = new StringBuilder();
161
+ sb.Append("{\"ramTotalMb\":").Append(Mb(status.TotalPhys));
162
+ sb.Append(",\"ramAvailMb\":").Append(Mb(status.AvailPhys));
163
+ sb.Append(",\"commitLimitMb\":").Append(Mb(status.TotalPageFile));
164
+ sb.Append(",\"commitAvailMb\":").Append(Mb(status.AvailPageFile));
165
+ sb.Append(",\"procs\":[");
166
+ bool first = true;
167
+ int self = Process.GetCurrentProcess().Id;
168
+ foreach (int pid in JobProcessIds())
169
+ {
170
+ if (pid == self)
171
+ {
172
+ continue;
173
+ }
174
+ try
175
+ {
176
+ using (Process p = Process.GetProcessById(pid))
177
+ {
178
+ if (!first)
179
+ {
180
+ sb.Append(',');
181
+ }
182
+ first = false;
183
+ sb.Append("{\"pid\":").Append(pid.ToString(CultureInfo.InvariantCulture));
184
+ sb.Append(",\"name\":").Append(Json(p.ProcessName));
185
+ sb.Append(",\"mb\":").Append(Mb((ulong)p.PrivateMemorySize64));
186
+ sb.Append(",\"prio\":\"").Append(PriorityName(pid)).Append("\"}");
187
+ }
188
+ }
189
+ catch (Exception)
190
+ {
191
+ // The process ended while it was read.
192
+ }
193
+ }
194
+ return sb.Append("]}").ToString();
195
+ }
196
+
197
+ private static List<int> JobProcessIds()
198
+ {
199
+ List<int> ids = new List<int>();
200
+ IntPtr handle = Job();
201
+ if (handle == IntPtr.Zero)
202
+ {
203
+ return ids;
204
+ }
205
+ // JOBOBJECT_BASIC_PROCESS_ID_LIST: two counts, then the ids (pointer-sized).
206
+ int length = 8 + IntPtr.Size * MaxProcesses;
207
+ IntPtr buffer = Marshal.AllocHGlobal(length);
208
+ try
209
+ {
210
+ if (!NativeMethods.QueryInformationJobObject(handle, JobObjectBasicProcessIdList, buffer, length, IntPtr.Zero))
211
+ {
212
+ return ids;
213
+ }
214
+ int count = Marshal.ReadInt32(buffer, 4);
215
+ for (int i = 0; i < count && i < MaxProcesses; i++)
216
+ {
217
+ ids.Add((int)Marshal.ReadIntPtr(buffer, 8 + i * IntPtr.Size).ToInt64());
218
+ }
219
+ }
220
+ finally
221
+ {
222
+ Marshal.FreeHGlobal(buffer);
223
+ }
224
+ return ids;
225
+ }
226
+
227
+ private static string PriorityName(int pid)
228
+ {
229
+ IntPtr process = NativeMethods.OpenProcess(ProcessQueryLimited, false, pid);
230
+ if (process == IntPtr.Zero)
231
+ {
232
+ return "normal";
233
+ }
234
+ try
235
+ {
236
+ uint c = NativeMethods.GetPriorityClass(process);
237
+ return c == IdleClass ? "idle" : c == BelowNormalClass ? "below" : "normal";
238
+ }
239
+ finally
240
+ {
241
+ NativeMethods.CloseHandle(process);
242
+ }
243
+ }
244
+
245
+ /// <summary>Whether pid is a process of the agents' job and not this one: the only ones this program touches.</summary>
246
+ private static bool Allowed(int pid)
247
+ {
248
+ return pid != Process.GetCurrentProcess().Id && JobProcessIds().Contains(pid);
249
+ }
250
+
251
+ private static void ReadCommands()
252
+ {
253
+ string line;
254
+ while ((line = Console.In.ReadLine()) != null)
255
+ {
256
+ try
257
+ {
258
+ Run(line.Trim().Split(' '));
259
+ }
260
+ catch (Exception)
261
+ {
262
+ // A bad command is ignored.
263
+ }
264
+ if (stop)
265
+ {
266
+ return;
267
+ }
268
+ }
269
+ // The daemon is gone: put everything back and end.
270
+ stop = true;
271
+ }
272
+
273
+ private static void Run(string[] parts)
274
+ {
275
+ if (parts.Length == 1 && parts[0] == "exit")
276
+ {
277
+ stop = true;
278
+ return;
279
+ }
280
+ int pid;
281
+ if (parts.Length < 3 || !int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out pid) || !Allowed(pid))
282
+ {
283
+ return;
284
+ }
285
+ if (parts[0] == "priority")
286
+ {
287
+ uint cls = parts[2] == "idle" ? IdleClass : parts[2] == "below" ? BelowNormalClass : NormalClass;
288
+ IntPtr process = NativeMethods.OpenProcess(ProcessSetInformation, false, pid);
289
+ if (process != IntPtr.Zero)
290
+ {
291
+ NativeMethods.SetPriorityClass(process, cls);
292
+ NativeMethods.CloseHandle(process);
293
+ }
294
+ }
295
+ else if (parts[0] == "suspend")
296
+ {
297
+ int ms;
298
+ if (!int.TryParse(parts[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out ms) || ms < 1)
299
+ {
300
+ return;
301
+ }
302
+ Suspend(pid, Math.Min(ms, MaxSuspendMs));
303
+ }
304
+ }
305
+
306
+ private static void Suspend(int pid, int ms)
307
+ {
308
+ lock (Gate)
309
+ {
310
+ if (Paused.ContainsKey(pid))
311
+ {
312
+ return;
313
+ }
314
+ IntPtr process = NativeMethods.OpenProcess(ProcessSuspendResume, false, pid);
315
+ if (process == IntPtr.Zero)
316
+ {
317
+ return;
318
+ }
319
+ try
320
+ {
321
+ // Recorded before the pause, so a memgov that dies right after still lets the next one resume it.
322
+ Paused[pid] = DateTime.UtcNow.AddMilliseconds(ms);
323
+ SaveHeld();
324
+ NativeMethods.NtSuspendProcess(process);
325
+ }
326
+ finally
327
+ {
328
+ NativeMethods.CloseHandle(process);
329
+ }
330
+ }
331
+ }
332
+
333
+ private static void Resume(int pid)
334
+ {
335
+ IntPtr process = NativeMethods.OpenProcess(ProcessSuspendResume, false, pid);
336
+ if (process != IntPtr.Zero)
337
+ {
338
+ NativeMethods.NtResumeProcess(process);
339
+ NativeMethods.CloseHandle(process);
340
+ }
341
+ }
342
+
343
+ /// <summary>A paused process always comes back: when its time is up (checked every 100 ms).</summary>
344
+ private static void ResumeWhenDue()
345
+ {
346
+ while (true)
347
+ {
348
+ Thread.Sleep(100);
349
+ lock (Gate)
350
+ {
351
+ List<int> due = new List<int>();
352
+ foreach (KeyValuePair<int, DateTime> p in Paused)
353
+ {
354
+ if (p.Value <= DateTime.UtcNow)
355
+ {
356
+ due.Add(p.Key);
357
+ }
358
+ }
359
+ foreach (int pid in due)
360
+ {
361
+ Resume(pid);
362
+ Paused.Remove(pid);
363
+ }
364
+ if (due.Count > 0)
365
+ {
366
+ SaveHeld();
367
+ }
368
+ }
369
+ }
370
+ }
371
+
372
+ private static void ResumeAll()
373
+ {
374
+ lock (Gate)
375
+ {
376
+ foreach (int pid in new List<int>(Paused.Keys))
377
+ {
378
+ Resume(pid);
379
+ }
380
+ Paused.Clear();
381
+ SaveHeld();
382
+ }
383
+ }
384
+
385
+ /// <summary>The processes paused right now, one id per line (empty: the file goes). Called with Gate held.</summary>
386
+ private static void SaveHeld()
387
+ {
388
+ try
389
+ {
390
+ if (Paused.Count == 0)
391
+ {
392
+ File.Delete(HeldFile);
393
+ return;
394
+ }
395
+ List<string> lines = new List<string>();
396
+ foreach (int pid in Paused.Keys)
397
+ {
398
+ lines.Add(pid.ToString(CultureInfo.InvariantCulture));
399
+ }
400
+ File.WriteAllLines(HeldFile, lines.ToArray());
401
+ }
402
+ catch (IOException)
403
+ {
404
+ // Best effort: the in-memory list still resumes every pause while this memgov runs.
405
+ }
406
+ catch (UnauthorizedAccessException)
407
+ {
408
+ // Same as above.
409
+ }
410
+ }
411
+
412
+ /// <summary>Resumes what an earlier memgov paused and never resumed. Resuming a running process changes nothing.</summary>
413
+ private static void RecoverHeld()
414
+ {
415
+ try
416
+ {
417
+ if (!File.Exists(HeldFile))
418
+ {
419
+ return;
420
+ }
421
+ foreach (string line in File.ReadAllLines(HeldFile))
422
+ {
423
+ int pid;
424
+ if (int.TryParse(line.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out pid) && pid > 0)
425
+ {
426
+ Resume(pid);
427
+ }
428
+ }
429
+ File.Delete(HeldFile);
430
+ }
431
+ catch (IOException)
432
+ {
433
+ // Nothing more to do: the file stays and the next start tries again.
434
+ }
435
+ catch (UnauthorizedAccessException)
436
+ {
437
+ // Same as above.
438
+ }
439
+ }
440
+
441
+ private static string Mb(ulong bytes)
442
+ {
443
+ return Math.Floor(bytes / BytesPerMb).ToString("0", CultureInfo.InvariantCulture);
444
+ }
445
+
446
+ private static string Json(string value)
447
+ {
448
+ StringBuilder sb = new StringBuilder("\"");
449
+ foreach (char c in value)
450
+ {
451
+ if (c == '"' || c == '\\')
452
+ {
453
+ sb.Append('\\').Append(c);
454
+ }
455
+ else if (c < 0x20)
456
+ {
457
+ sb.Append("\\u").Append(((int)c).ToString("x4", CultureInfo.InvariantCulture));
458
+ }
459
+ else
460
+ {
461
+ sb.Append(c);
462
+ }
463
+ }
464
+ return sb.Append('"').ToString();
465
+ }
466
+ }
@@ -79,7 +79,7 @@ sealed class SessionHost
79
79
  log.Write("starting: " + command);
80
80
  while (true)
81
81
  {
82
- using (PseudoConsole console = PseudoConsole.Start(command, hub.Cols, hub.Rows, hub.Broadcast))
82
+ using (PseudoConsole console = PseudoConsole.Start(command, hub.Cols, hub.Rows, hub.Broadcast, log))
83
83
  {
84
84
  hub.Attach(console);
85
85
  log.Write("pseudo console: " + Native.ConsoleKind);
@@ -856,7 +856,7 @@ sealed class PseudoConsole : IDisposable
856
856
  this.pump = pump;
857
857
  }
858
858
 
859
- public static PseudoConsole Start(string commandLine, short cols, short rows, Action<byte[]> onOutput)
859
+ public static PseudoConsole Start(string commandLine, short cols, short rows, Action<byte[]> onOutput, Log log)
860
860
  {
861
861
  SafeFileHandle inRead;
862
862
  SafeFileHandle inWrite;
@@ -872,7 +872,7 @@ sealed class PseudoConsole : IDisposable
872
872
  }
873
873
  inRead.Dispose();
874
874
  outWrite.Dispose();
875
- IntPtr process = Native.Spawn(commandLine, handle);
875
+ IntPtr process = Native.Spawn(commandLine, handle, log);
876
876
  FileStream output = new FileStream(outRead, FileAccess.Read);
877
877
  Thread pump = new Thread(() => Pump(output, onOutput));
878
878
  pump.IsBackground = true;
@@ -1085,6 +1085,12 @@ sealed class Log
1085
1085
  static class Native
1086
1086
  {
1087
1087
  private const uint ExtendedStartupInfoPresent = 0x00080000;
1088
+ private const uint CreateSuspended = 0x00000004;
1089
+ // The shared job of everything the agents start (the memory governor in the daemon opens it by this name).
1090
+ private const string AgentJobName = "Local\\AgentSandboxAgentsJob";
1091
+ private const int JobObjectExtendedLimitInformation = 9;
1092
+ private const uint JobObjectLimitJobMemory = 0x00000200;
1093
+ private const long BytesPerMb = 1024L * 1024L;
1088
1094
  private const int UseStdHandles = 0x00000100;
1089
1095
  private static readonly IntPtr PseudoConsoleAttribute = (IntPtr)0x00020016;
1090
1096
 
@@ -1125,6 +1131,43 @@ static class Native
1125
1131
  public IntPtr lpAttributeList;
1126
1132
  }
1127
1133
 
1134
+ // JOBOBJECT_BASIC_LIMIT_INFORMATION, IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION.
1135
+ [StructLayout(LayoutKind.Sequential)]
1136
+ private struct JobBasicLimit
1137
+ {
1138
+ public long PerProcessUserTimeLimit;
1139
+ public long PerJobUserTimeLimit;
1140
+ public uint LimitFlags;
1141
+ public UIntPtr MinimumWorkingSetSize;
1142
+ public UIntPtr MaximumWorkingSetSize;
1143
+ public uint ActiveProcessLimit;
1144
+ public UIntPtr Affinity;
1145
+ public uint PriorityClass;
1146
+ public uint SchedulingClass;
1147
+ }
1148
+
1149
+ [StructLayout(LayoutKind.Sequential)]
1150
+ private struct IoCounters
1151
+ {
1152
+ public ulong ReadOperationCount;
1153
+ public ulong WriteOperationCount;
1154
+ public ulong OtherOperationCount;
1155
+ public ulong ReadTransferCount;
1156
+ public ulong WriteTransferCount;
1157
+ public ulong OtherTransferCount;
1158
+ }
1159
+
1160
+ [StructLayout(LayoutKind.Sequential)]
1161
+ private struct JobExtendedLimit
1162
+ {
1163
+ public JobBasicLimit BasicLimitInformation;
1164
+ public IoCounters IoInfo;
1165
+ public UIntPtr ProcessMemoryLimit;
1166
+ public UIntPtr JobMemoryLimit;
1167
+ public UIntPtr PeakProcessMemoryUsed;
1168
+ public UIntPtr PeakJobMemoryUsed;
1169
+ }
1170
+
1128
1171
  [StructLayout(LayoutKind.Sequential)]
1129
1172
  private struct ProcessInformation
1130
1173
  {
@@ -1182,6 +1225,18 @@ static class Native
1182
1225
  [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
1183
1226
  public static extern bool CreateProcessW(string lpApplicationName, StringBuilder lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref StartupInfoEx lpStartupInfo, out ProcessInformation lpProcessInformation);
1184
1227
 
1228
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
1229
+ public static extern IntPtr CreateJobObjectW(IntPtr attributes, string name);
1230
+
1231
+ [DllImport("kernel32.dll", SetLastError = true)]
1232
+ public static extern bool SetInformationJobObject(IntPtr job, int infoClass, ref JobExtendedLimit info, int length);
1233
+
1234
+ [DllImport("kernel32.dll", SetLastError = true)]
1235
+ public static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
1236
+
1237
+ [DllImport("kernel32.dll", SetLastError = true)]
1238
+ public static extern uint ResumeThread(IntPtr thread);
1239
+
1185
1240
  [DllImport("kernel32.dll", SetLastError = true)]
1186
1241
  public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
1187
1242
 
@@ -1241,9 +1296,51 @@ static class Native
1241
1296
  return NativeMethods.CreatePipe(out read, out write, IntPtr.Zero, 0);
1242
1297
  }
1243
1298
 
1299
+ private static IntPtr agentJob;
1300
+ private static bool agentJobTried;
1301
+
1302
+ /// <summary>
1303
+ /// The shared job of everything the agents start, with a memory limit for all of it together (PTYHOST_JOB_MB, set
1304
+ /// by the daemon from sandbox.agentMemoryHeadroomMb): a runaway build then gets out-of-memory errors in its own
1305
+ /// session instead of using up the whole sandbox. Zero when no limit is asked for or the job cannot be made; ptyhost
1306
+ /// itself is never in it. The handle stays open for ptyhost's whole life (the job lives while a handle is open).
1307
+ /// </summary>
1308
+ private static IntPtr AgentJob(Log log)
1309
+ {
1310
+ if (agentJobTried)
1311
+ {
1312
+ return agentJob;
1313
+ }
1314
+ agentJobTried = true;
1315
+ long limitMb;
1316
+ if (!long.TryParse(Environment.GetEnvironmentVariable("PTYHOST_JOB_MB"), out limitMb) || limitMb < 512)
1317
+ {
1318
+ return IntPtr.Zero;
1319
+ }
1320
+ IntPtr job = NativeMethods.CreateJobObjectW(IntPtr.Zero, AgentJobName);
1321
+ if (job == IntPtr.Zero)
1322
+ {
1323
+ log.Write("agent job: CreateJobObject failed (" + Marshal.GetLastWin32Error() + "); no memory limit");
1324
+ return IntPtr.Zero;
1325
+ }
1326
+ JobExtendedLimit info = new JobExtendedLimit();
1327
+ info.BasicLimitInformation.LimitFlags = JobObjectLimitJobMemory;
1328
+ info.JobMemoryLimit = new UIntPtr((ulong)(limitMb * BytesPerMb));
1329
+ if (!NativeMethods.SetInformationJobObject(job, JobObjectExtendedLimitInformation, ref info, Marshal.SizeOf(typeof(JobExtendedLimit))))
1330
+ {
1331
+ log.Write("agent job: setting the limit failed (" + Marshal.GetLastWin32Error() + "); no memory limit");
1332
+ NativeMethods.CloseHandle(job);
1333
+ return IntPtr.Zero;
1334
+ }
1335
+ log.Write("agent job: everything the agent starts may use " + limitMb + " MB together");
1336
+ agentJob = job;
1337
+ return job;
1338
+ }
1339
+
1244
1340
  /// <summary>Starts `commandLine` attached to the pseudo console. Null std handles: never leak our own stdio into the child.</summary>
1245
- public static IntPtr Spawn(string commandLine, IntPtr pseudoConsole)
1341
+ public static IntPtr Spawn(string commandLine, IntPtr pseudoConsole, Log log)
1246
1342
  {
1343
+ IntPtr job = AgentJob(log);
1247
1344
  IntPtr size = IntPtr.Zero;
1248
1345
  NativeMethods.InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref size);
1249
1346
  IntPtr attributes = Marshal.AllocHGlobal(size);
@@ -1256,10 +1353,19 @@ static class Native
1256
1353
  info.StartupInfo.dwFlags = UseStdHandles;
1257
1354
  info.lpAttributeList = attributes;
1258
1355
  ProcessInformation pi;
1259
- if (!NativeMethods.CreateProcessW(null, new StringBuilder(commandLine), IntPtr.Zero, IntPtr.Zero, false, ExtendedStartupInfoPresent, IntPtr.Zero, null, ref info, out pi))
1356
+ if (!NativeMethods.CreateProcessW(null, new StringBuilder(commandLine), IntPtr.Zero, IntPtr.Zero, false, ExtendedStartupInfoPresent | (job != IntPtr.Zero ? CreateSuspended : 0), IntPtr.Zero, null, ref info, out pi))
1260
1357
  {
1261
1358
  throw new IOException("CreateProcess failed (" + Marshal.GetLastWin32Error() + "): " + commandLine);
1262
1359
  }
1360
+ if (job != IntPtr.Zero)
1361
+ {
1362
+ // Suspended until it is in the job, so nothing it starts can be outside.
1363
+ if (!NativeMethods.AssignProcessToJobObject(job, pi.hProcess))
1364
+ {
1365
+ log.Write("agent job: could not add the agent (" + Marshal.GetLastWin32Error() + "); it runs without the memory limit");
1366
+ }
1367
+ NativeMethods.ResumeThread(pi.hThread);
1368
+ }
1263
1369
  NativeMethods.CloseHandle(pi.hThread);
1264
1370
  return pi.hProcess;
1265
1371
  }
@@ -5,7 +5,9 @@ param([Parameter(Mandatory = $true)][string]$ListFile)
5
5
  $ErrorActionPreference = 'Stop'
6
6
 
7
7
  $shell = New-Object -ComObject WScript.Shell
8
- foreach ($entry in @(Get-Content -LiteralPath $ListFile -Raw -Encoding UTF8 | ConvertFrom-Json)) {
8
+ # Windows PowerShell 5.1 hands a JSON array over as ONE object: pipe it through ForEach-Object to get its elements.
9
+ $entries = @(ConvertFrom-Json -InputObject (Get-Content -LiteralPath $ListFile -Raw -Encoding UTF8) | ForEach-Object { $_ })
10
+ foreach ($entry in $entries) {
9
11
  New-Item -ItemType Directory -Force -Path (Split-Path -Parent $entry.link) | Out-Null
10
12
  $shortcut = $shell.CreateShortcut($entry.link)
11
13
  $shortcut.TargetPath = $entry.target