windows-development-sandbox 1.7.0 → 1.9.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 (413) hide show
  1. package/config.example.json +10 -0
  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 +47 -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 +19 -3
  82. package/dist/cli/commands/web.js +2 -0
  83. package/dist/cli/index.js +2 -1
  84. package/dist/cli/manifest.d.ts +72 -104
  85. package/dist/cli/manifest.js +64 -39
  86. package/dist/cli/menu/add-agent.d.ts +1 -1
  87. package/dist/cli/menu/add-agent.js +1 -1
  88. package/dist/cli/menu/apps.d.ts +7 -1
  89. package/dist/cli/menu/apps.js +36 -0
  90. package/dist/cli/menu/command-fields.d.ts +1 -1
  91. package/dist/cli/menu/command-form.js +2 -2
  92. package/dist/cli/menu/io-menu.d.ts +29 -0
  93. package/dist/cli/menu/io-menu.js +126 -0
  94. package/dist/cli/menu/live.d.ts +27 -0
  95. package/dist/cli/menu/live.js +69 -0
  96. package/dist/cli/menu/memory.d.ts +19 -0
  97. package/dist/cli/menu/memory.js +53 -0
  98. package/dist/cli/menu/menu.d.ts +10 -1
  99. package/dist/cli/menu/menu.js +27 -9
  100. package/dist/cli/menu/pages/agents-page.d.ts +3 -1
  101. package/dist/cli/menu/pages/agents-page.js +12 -5
  102. package/dist/cli/menu/pages/apps-page.d.ts +3 -1
  103. package/dist/cli/menu/pages/apps-page.js +19 -2
  104. package/dist/cli/menu/pages/list-page.d.ts +27 -0
  105. package/dist/cli/menu/pages/list-page.js +109 -7
  106. package/dist/cli/menu/pages/maintenance-page.d.ts +0 -5
  107. package/dist/cli/menu/pages/maintenance-page.js +17 -19
  108. package/dist/cli/menu/pages/sandbox-page.d.ts +4 -6
  109. package/dist/cli/menu/pages/sandbox-page.js +26 -118
  110. package/dist/cli/menu/pages/scopes.d.ts +1 -1
  111. package/dist/cli/menu/pages/sessions-page.d.ts +5 -11
  112. package/dist/cli/menu/pages/sessions-page.js +19 -88
  113. package/dist/cli/menu/pages/settings-page.d.ts +2 -10
  114. package/dist/cli/menu/pages/settings-page.js +64 -94
  115. package/dist/cli/menu/render-view.d.ts +28 -0
  116. package/dist/cli/menu/render-view.js +112 -0
  117. package/dist/cli/menu/settings/{path-kind.d.ts → ask-path.d.ts} +1 -7
  118. package/dist/cli/menu/settings/ask-path.js +14 -0
  119. package/dist/cli/menu/settings/collections/collection-editor.d.ts +1 -1
  120. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +1 -2
  121. package/dist/cli/menu/settings/collections/string-list-editor.js +1 -1
  122. package/dist/cli/menu/settings/draft.d.ts +1 -1
  123. package/dist/cli/menu/settings/format.d.ts +1 -3
  124. package/dist/cli/menu/settings/format.js +6 -36
  125. package/dist/cli/menu/settings/index.d.ts +1 -3
  126. package/dist/cli/menu/settings/index.js +3 -3
  127. package/dist/cli/menu/settings/object-editor.d.ts +1 -1
  128. package/dist/cli/menu/settings/share.d.ts +36 -0
  129. package/dist/cli/menu/settings/share.js +131 -0
  130. package/dist/cli/menu/settings/value-editor.d.ts +5 -1
  131. package/dist/cli/menu/settings/value-editor.js +57 -54
  132. package/dist/cli/menu/several.js +1 -1
  133. package/dist/cli/menu/share-settings.d.ts +21 -0
  134. package/dist/cli/menu/share-settings.js +112 -0
  135. package/dist/cli/menu/shell.d.ts +21 -5
  136. package/dist/cli/menu/shell.js +31 -6
  137. package/dist/cli/menu/views.d.ts +7 -0
  138. package/dist/cli/menu/views.js +11 -0
  139. package/dist/cli/menu/vpn-login.js +8 -0
  140. package/dist/cli/operations/handler.d.ts +6 -0
  141. package/dist/cli/operations/handler.js +61 -0
  142. package/dist/cli/operations/index.d.ts +4 -0
  143. package/dist/cli/operations/index.js +5 -0
  144. package/dist/cli/operations/input.d.ts +6 -0
  145. package/dist/cli/operations/input.js +37 -0
  146. package/dist/cli/operations/io-cli.d.ts +7 -0
  147. package/dist/cli/operations/io-cli.js +62 -0
  148. package/dist/cli/operations/spec.d.ts +18 -0
  149. package/dist/cli/operations/spec.js +108 -0
  150. package/dist/cli/output/colors.d.ts +2 -2
  151. package/dist/cli/output/colors.js +2 -11
  152. package/dist/cli/output/index.d.ts +1 -0
  153. package/dist/cli/output/index.js +1 -0
  154. package/dist/cli/output/print.d.ts +3 -1
  155. package/dist/cli/output/print.js +7 -3
  156. package/dist/cli/output/progress.d.ts +15 -0
  157. package/dist/cli/output/progress.js +44 -0
  158. package/dist/cli/output/render-view.d.ts +4 -0
  159. package/dist/cli/output/render-view.js +63 -0
  160. package/dist/cli/services/agent-commands-service.d.ts +2 -0
  161. package/dist/cli/services/agent-commands-service.js +11 -2
  162. package/dist/cli/services/logs-service.js +4 -3
  163. package/dist/cli/tui/app.d.ts +6 -1
  164. package/dist/cli/tui/app.js +26 -4
  165. package/dist/cli/tui/list/list-screen.d.ts +14 -0
  166. package/dist/cli/tui/list/list-screen.js +64 -36
  167. package/dist/cli/tui/list/list-types.d.ts +2 -0
  168. package/dist/cli/tui/terminal.d.ts +7 -0
  169. package/dist/cli/tui/terminal.js +30 -10
  170. package/dist/core/config/defaults.js +8 -0
  171. package/dist/core/schema/config.d.ts +13 -0
  172. package/dist/core/schema/config.js +16 -1
  173. package/dist/core/schema/harness.d.ts +1 -0
  174. package/dist/core/schema/harness.js +5 -0
  175. package/dist/core/schema/sandbox.d.ts +6 -0
  176. package/dist/core/schema/sandbox.js +20 -3
  177. package/dist/core/schema/vpn.d.ts +2 -1
  178. package/dist/core/schema/vpn.js +3 -3
  179. package/dist/core/types.d.ts +23 -5
  180. package/dist/core/util/fs.d.ts +2 -0
  181. package/dist/core/util/fs.js +9 -0
  182. package/dist/core/util/index.d.ts +1 -1
  183. package/dist/core/util/index.js +1 -1
  184. package/dist/guest/agents/agent-files.d.ts +5 -0
  185. package/dist/guest/agents/agent-files.js +4 -0
  186. package/dist/guest/agents/local-state.d.ts +2 -0
  187. package/dist/guest/agents/local-state.js +21 -1
  188. package/dist/guest/boot/boot.js +2 -1
  189. package/dist/guest/daemon/daemon.js +4 -0
  190. package/dist/guest/daemon/sessions.d.ts +5 -0
  191. package/dist/guest/daemon/sessions.js +17 -3
  192. package/dist/guest/entries/daemon.js +3 -0
  193. package/dist/guest/governor/decide.d.ts +61 -0
  194. package/dist/guest/governor/decide.js +182 -0
  195. package/dist/guest/governor/governor.d.ts +42 -0
  196. package/dist/guest/governor/governor.js +214 -0
  197. package/dist/guest/governor/index.d.ts +2 -0
  198. package/dist/guest/governor/index.js +2 -0
  199. package/dist/guest/runtime/csc.d.ts +1 -0
  200. package/dist/guest/runtime/csc.js +1 -0
  201. package/dist/guest/sessions/viewer.js +3 -1
  202. package/dist/guest/toolchains/native/rust-extras.js +4 -2
  203. package/dist/guest/vpn/vpn.js +69 -21
  204. package/dist/guest/vpn/wireguard.d.ts +32 -0
  205. package/dist/guest/vpn/wireguard.js +132 -0
  206. package/dist/host/agent-commands/commands.d.ts +4 -0
  207. package/dist/host/agent-commands/commands.js +31 -7
  208. package/dist/host/audit/log.d.ts +1 -1
  209. package/dist/host/channel/attach.d.ts +3 -1
  210. package/dist/host/channel/attach.js +5 -2
  211. package/dist/host/channel/channel.d.ts +2 -0
  212. package/dist/host/channel/channel.js +4 -0
  213. package/dist/host/engines/engine.d.ts +12 -0
  214. package/dist/host/engines/engine.js +1 -0
  215. package/dist/host/engines/hcs/check.d.ts +25 -0
  216. package/dist/host/engines/hcs/check.js +95 -0
  217. package/dist/host/engines/hcs/documents.d.ts +44 -0
  218. package/dist/host/engines/hcs/documents.js +155 -0
  219. package/dist/host/engines/hcs/engine.d.ts +39 -0
  220. package/dist/host/engines/hcs/engine.js +171 -0
  221. package/dist/host/engines/hcs/helper.d.ts +43 -0
  222. package/dist/host/engines/hcs/helper.js +173 -0
  223. package/dist/host/engines/hcs/images.d.ts +37 -0
  224. package/dist/host/engines/hcs/images.js +152 -0
  225. package/dist/host/engines/index.d.ts +7 -0
  226. package/dist/host/engines/index.js +5 -0
  227. package/dist/host/engines/registry.d.ts +16 -0
  228. package/dist/host/engines/registry.js +30 -0
  229. package/dist/host/engines/types.d.ts +58 -0
  230. package/dist/host/engines/types.js +1 -0
  231. package/dist/host/engines/windows-sandbox/engine.d.ts +16 -0
  232. package/dist/host/engines/windows-sandbox/engine.js +63 -0
  233. package/dist/host/engines/windows-sandbox/wsb-text.d.ts +2 -0
  234. package/dist/host/engines/windows-sandbox/wsb-text.js +29 -0
  235. package/dist/host/launch/generate.d.ts +5 -1
  236. package/dist/host/launch/generate.js +50 -8
  237. package/dist/host/launch/index.d.ts +3 -1
  238. package/dist/host/launch/index.js +3 -1
  239. package/dist/host/launch/launch-plan.d.ts +13 -0
  240. package/dist/host/launch/launch-plan.js +26 -0
  241. package/dist/host/launch/mappings.js +2 -1
  242. package/dist/host/launch/risk-notes.d.ts +10 -0
  243. package/dist/host/launch/risk-notes.js +18 -0
  244. package/dist/host/launch/session-file.d.ts +2 -0
  245. package/dist/host/launch/session-file.js +7 -1
  246. package/dist/host/launch/wsb-file.d.ts +28 -4
  247. package/dist/host/launch/wsb-file.js +61 -42
  248. package/dist/host/life/crash-report.d.ts +27 -1
  249. package/dist/host/life/crash-report.js +173 -7
  250. package/dist/host/life/host-memory.d.ts +40 -0
  251. package/dist/host/life/host-memory.js +137 -0
  252. package/dist/host/life/index.d.ts +2 -0
  253. package/dist/host/life/index.js +2 -0
  254. package/dist/host/life/stop-events.d.ts +2 -0
  255. package/dist/host/life/stop-events.js +20 -3
  256. package/dist/host/life/stop-warning.js +1 -1
  257. package/dist/host/life/watchdog.d.ts +54 -0
  258. package/dist/host/life/watchdog.js +108 -0
  259. package/dist/host/native.d.ts +3 -2
  260. package/dist/host/native.js +22 -3
  261. package/dist/host/profile/claude-login.js +3 -2
  262. package/dist/host/sandbox/contained-deps.d.ts +2 -0
  263. package/dist/host/sandbox/contained-deps.js +17 -0
  264. package/dist/host/sandbox/index.d.ts +2 -0
  265. package/dist/host/sandbox/index.js +2 -0
  266. package/dist/host/sandbox/platform.d.ts +2 -0
  267. package/dist/host/sandbox/platform.js +7 -7
  268. package/dist/host/sandbox/tasklist.d.ts +13 -0
  269. package/dist/host/sandbox/tasklist.js +47 -0
  270. package/dist/host/secrets/launch-secrets.js +2 -1
  271. package/dist/host/sharing/current.js +2 -6
  272. package/dist/host/storage/contained/check.d.ts +9 -0
  273. package/dist/host/storage/contained/check.js +37 -0
  274. package/dist/host/storage/contained/contained-storage.d.ts +66 -0
  275. package/dist/host/storage/contained/contained-storage.js +168 -0
  276. package/dist/host/storage/contained/disk-port.d.ts +43 -0
  277. package/dist/host/storage/contained/disk-port.js +122 -0
  278. package/dist/host/storage/contained/index.d.ts +9 -0
  279. package/dist/host/storage/contained/index.js +8 -0
  280. package/dist/host/storage/contained/layout.d.ts +28 -0
  281. package/dist/host/storage/contained/layout.js +45 -0
  282. package/dist/host/storage/contained/resolve.d.ts +4 -0
  283. package/dist/host/storage/contained/resolve.js +30 -0
  284. package/dist/host/storage/contained/setting.d.ts +1 -0
  285. package/dist/host/storage/contained/setting.js +5 -0
  286. package/dist/host/storage/contained/state.d.ts +89 -0
  287. package/dist/host/storage/contained/state.js +166 -0
  288. package/dist/host/storage/contained/transfer.d.ts +24 -0
  289. package/dist/host/storage/contained/transfer.js +121 -0
  290. package/dist/host/storage/index.d.ts +2 -0
  291. package/dist/host/storage/index.js +2 -0
  292. package/dist/host/storage/providers/contained.d.ts +15 -0
  293. package/dist/host/storage/providers/contained.js +39 -0
  294. package/dist/host/storage/providers/folder.d.ts +12 -0
  295. package/dist/host/storage/providers/folder.js +20 -0
  296. package/dist/host/storage/providers/index.d.ts +4 -0
  297. package/dist/host/storage/providers/index.js +3 -0
  298. package/dist/host/storage/providers/registry.d.ts +9 -0
  299. package/dist/host/storage/providers/registry.js +14 -0
  300. package/dist/host/storage/providers/types.d.ts +33 -0
  301. package/dist/host/storage/providers/types.js +1 -0
  302. package/dist/host/tools/conpty.js +3 -2
  303. package/dist/host/tools/windows-terminal.js +8 -7
  304. package/dist/host/vpn/index.d.ts +1 -1
  305. package/dist/host/vpn/index.js +1 -1
  306. package/dist/host/vpn/prepare.d.ts +2 -0
  307. package/dist/host/vpn/prepare.js +63 -2
  308. package/dist/host/web/browser.d.ts +2 -0
  309. package/dist/host/web/browser.js +14 -1
  310. package/dist/host/web/index.d.ts +3 -2
  311. package/dist/host/web/index.js +3 -2
  312. package/dist/host/web/rpc.d.ts +24 -0
  313. package/dist/host/web/rpc.js +149 -0
  314. package/dist/host/web/runner.d.ts +2 -0
  315. package/dist/host/web/runner.js +1 -2
  316. package/dist/host/web/server.d.ts +7 -0
  317. package/dist/host/web/server.js +23 -3
  318. package/dist/runtime/agent.js +69 -8
  319. package/dist/runtime/daemon.js +1058 -624
  320. package/dist/runtime/db.js +69 -8
  321. package/dist/runtime/main.js +624 -182
  322. package/dist/runtime/netproxy.js +69 -8
  323. package/dist/runtime/view.js +87 -13
  324. package/dist/selftest/agent-paths.test.js +11 -1
  325. package/dist/selftest/app.test.d.ts +2 -0
  326. package/dist/selftest/app.test.js +324 -0
  327. package/dist/selftest/channel.test.js +13 -0
  328. package/dist/selftest/cli.test.js +2 -1
  329. package/dist/selftest/config.test.js +59 -0
  330. package/dist/selftest/contained.test.d.ts +2 -0
  331. package/dist/selftest/contained.test.js +544 -0
  332. package/dist/selftest/credentials.test.js +1 -1
  333. package/dist/selftest/engine.test.d.ts +2 -0
  334. package/dist/selftest/engine.test.js +127 -0
  335. package/dist/selftest/hcs.test.d.ts +2 -0
  336. package/dist/selftest/hcs.test.js +482 -0
  337. package/dist/selftest/heavy-load.test.d.ts +2 -0
  338. package/dist/selftest/heavy-load.test.js +329 -0
  339. package/dist/selftest/index.js +12 -0
  340. package/dist/selftest/layout.test.js +12 -0
  341. package/dist/selftest/menu-perf.test.d.ts +2 -0
  342. package/dist/selftest/menu-perf.test.js +248 -0
  343. package/dist/selftest/menu-screens.js +4 -2
  344. package/dist/selftest/menu.test.js +36 -8
  345. package/dist/selftest/support/engine-cases.d.ts +8 -0
  346. package/dist/selftest/support/engine-cases.js +65 -0
  347. package/dist/selftest/support/engine-golden.d.ts +3 -0
  348. package/dist/selftest/support/engine-golden.js +66 -0
  349. package/dist/selftest/support/fixtures.d.ts +7 -1
  350. package/dist/selftest/support/hcs-probes.d.ts +17 -0
  351. package/dist/selftest/support/hcs-probes.js +41 -0
  352. package/dist/selftest/vpn.test.js +136 -3
  353. package/dist/selftest/web.test.js +101 -3
  354. package/dist/shared/channel/run-dir.d.ts +4 -1
  355. package/dist/shared/channel/run-dir.js +7 -1
  356. package/dist/shared/channel/schema.d.ts +35 -1
  357. package/dist/shared/channel/schema.js +27 -0
  358. package/dist/shared/channel/secrets.d.ts +1 -0
  359. package/dist/shared/channel/secrets.js +6 -0
  360. package/dist/shared/memory/index.d.ts +1 -0
  361. package/dist/shared/memory/index.js +1 -0
  362. package/dist/shared/memory/policy.d.ts +33 -0
  363. package/dist/shared/memory/policy.js +55 -0
  364. package/dist/shared/pty/output-filter.d.ts +14 -1
  365. package/dist/shared/pty/output-filter.js +22 -4
  366. package/dist/shared/pty/terminal.d.ts +4 -1
  367. package/dist/shared/pty/terminal.js +4 -2
  368. package/dist/shared/system.d.ts +1 -0
  369. package/dist/shared/system.js +1 -0
  370. package/dist/shared/vpn/download.d.ts +16 -0
  371. package/dist/shared/vpn/download.js +16 -0
  372. package/dist/shared/vpn/wireguard.d.ts +51 -0
  373. package/dist/shared/vpn/wireguard.js +227 -0
  374. package/dist/sync/sync-cycle.js +5 -5
  375. package/dist/sync/watcher.d.ts +13 -0
  376. package/dist/sync/watcher.js +92 -3
  377. package/dist/web/index.html +4 -3
  378. package/dist/web/main-NRRS5O6Z.js +157 -0
  379. package/dist/web/main-T5DMCHYV.css +1 -0
  380. package/native/csharp/HcsHost/AssemblyInfo.cs +14 -0
  381. package/native/csharp/HcsHost/Guard.cs +100 -0
  382. package/native/csharp/HcsHost/Hcs.cs +256 -0
  383. package/native/csharp/HcsHost/Json.cs +78 -0
  384. package/native/csharp/HcsHost/Program.cs +185 -0
  385. package/native/csharp/HcsHost/VirtualDisk.cs +95 -0
  386. package/native/csharp/HostTools/AssemblyInfo.cs +14 -0
  387. package/native/csharp/HostTools/MemoryStatus.cs +107 -0
  388. package/native/csharp/HostTools/Program.cs +58 -17
  389. package/native/scripts/check-contained.ps1 +28 -0
  390. package/native/scripts/contained-common.ps1 +241 -0
  391. package/native/scripts/dismount-contained.ps1 +66 -0
  392. package/native/scripts/memory-status.ps1 +34 -0
  393. package/native/scripts/mount-contained.ps1 +139 -0
  394. package/native/scripts/run-elevated.ps1 +17 -4
  395. package/native/scripts/stop-events.ps1 +23 -8
  396. package/package.json +9 -2
  397. package/sandbox/csharp/MemGov.cs +398 -0
  398. package/sandbox/csharp/PtyHost.cs +111 -5
  399. package/schemas/config.schema.json +60 -6
  400. package/schemas/sandbox-config.schema.json +3 -3
  401. package/dist/cli/commands/sessions/control.d.ts +0 -4
  402. package/dist/cli/commands/sessions/control.js +0 -66
  403. package/dist/cli/commands/sessions/list.d.ts +0 -2
  404. package/dist/cli/commands/sessions/list.js +0 -48
  405. package/dist/cli/commands/sessions/status.d.ts +0 -4
  406. package/dist/cli/commands/sessions/status.js +0 -114
  407. package/dist/cli/commands/sessions/window.d.ts +0 -3
  408. package/dist/cli/commands/sessions/window.js +0 -18
  409. package/dist/cli/menu/settings/path-kind.js +0 -44
  410. package/dist/web/main-CXESL347.js +0 -45
  411. package/dist/web/main-VLR7DVQ4.css +0 -1
  412. /package/dist/{cli/menu/settings → app/kernel}/schema-node.d.ts +0 -0
  413. /package/dist/{cli/menu/settings → app/kernel}/schema-node.js +0 -0
@@ -0,0 +1,173 @@
1
+ // Runs HcsHost.exe (native\csharp\HcsHost, built on first use) with JSON files in a private temp folder. The answer
2
+ // is a file too: size-bounded and checked with zod, never trusted as it is. HcsHost only talks to the Windows Host
3
+ // Compute Service and virtdisk; it takes no guest data.
4
+ import crypto from 'node:crypto';
5
+ import fs from 'node:fs';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
8
+ import { spawnSync } from 'node:child_process';
9
+ import { z } from 'zod';
10
+ import { fail, UserError } from '../../../core/util/index.js';
11
+ import { SYSTEM } from '../../../shared/system.js';
12
+ import { nativeFile } from '../../native.js';
13
+ import { refuseInSelfTest } from '../../test-guard.js';
14
+ const MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
15
+ const CALL_TIMEOUT_MS = 240000;
16
+ /** Only ids this tool gives its compute systems (HcsHost.exe refuses any other, and checks the Owner too). */
17
+ const SAFE_ID = /^agent-sandbox-[A-Za-z0-9._-]{1,100}$/;
18
+ export const HcsReplySchema = z.object({
19
+ ok: z.boolean(),
20
+ hresult: z.string().max(16),
21
+ message: z.string().max(4000),
22
+ json: z.string().max(MAX_RESPONSE_BYTES),
23
+ values: z.record(z.string().max(64), z.string().max(2000)),
24
+ });
25
+ export const spawnRunner = (exe, args, timeoutMs) => {
26
+ const r = spawnSync(exe, [...args], {
27
+ windowsHide: true,
28
+ timeout: timeoutMs,
29
+ maxBuffer: 1024 * 1024,
30
+ stdio: 'ignore',
31
+ });
32
+ return { status: r.status, error: r.error?.message };
33
+ };
34
+ /** Compiles the helper's sources to `exe` with the .NET Framework csc (C# 5). False when it cannot be built. */
35
+ export function buildHcsHostTo(exe) {
36
+ const dir = nativeFile('csharp', 'HcsHost');
37
+ let sources;
38
+ try {
39
+ sources = fs
40
+ .readdirSync(dir)
41
+ .filter((f) => f.endsWith('.cs'))
42
+ .sort()
43
+ .map((f) => path.join(dir, f));
44
+ }
45
+ catch {
46
+ return false; // no sources next to this package
47
+ }
48
+ if (!fs.existsSync(SYSTEM.csc()))
49
+ return false;
50
+ fs.mkdirSync(path.dirname(exe), { recursive: true });
51
+ const r = spawnSync(SYSTEM.csc(), ['/nologo', '/optimize', '/target:exe', '/r:System.Web.Extensions.dll', '/out:' + exe, ...sources], { windowsHide: true, timeout: 120000 });
52
+ return r.status === 0 && fs.existsSync(exe);
53
+ }
54
+ /**
55
+ * <storage>\bin\hcs\<hash of its sources>\HcsHost.exe, built the first time. Its own folder: HostTools' cleanup of old
56
+ * builds only touches twelve-digit hash folders directly in bin. Null when it cannot be built.
57
+ */
58
+ export function hcsHostExe(storageRoot) {
59
+ refuseInSelfTest('build HcsHost.exe');
60
+ const dir = nativeFile('csharp', 'HcsHost');
61
+ const hash = crypto.createHash('sha256');
62
+ try {
63
+ for (const f of fs
64
+ .readdirSync(dir)
65
+ .filter((n) => n.endsWith('.cs'))
66
+ .sort())
67
+ hash.update(fs.readFileSync(path.join(dir, f)));
68
+ }
69
+ catch {
70
+ return null; // no sources
71
+ }
72
+ const exe = path.join(storageRoot, 'bin', 'hcs', hash.digest('hex').slice(0, 12), 'HcsHost.exe');
73
+ return fs.existsSync(exe) || buildHcsHostTo(exe) ? exe : null;
74
+ }
75
+ /** A path argument: absolute, not an option. Nothing else reaches the helper's command line. */
76
+ function pathArg(value, what) {
77
+ if (!path.isAbsolute(value) || value.startsWith('-'))
78
+ fail('Not a full path for ' + what + ': ' + value);
79
+ return value;
80
+ }
81
+ function idArg(value) {
82
+ if (!SAFE_ID.test(value))
83
+ fail('Not a valid sandbox id: ' + value);
84
+ return value;
85
+ }
86
+ export class HcsHelper {
87
+ exe;
88
+ run;
89
+ tempRoot;
90
+ /** `exe`: where HcsHost.exe is (built when asked); `tempRoot`: where the private folders for one call go. */
91
+ constructor(exe, run = spawnRunner, tempRoot = os.tmpdir()) {
92
+ this.exe = exe;
93
+ this.run = run;
94
+ this.tempRoot = tempRoot;
95
+ }
96
+ /** One helper call: `args` then `--out <response>`. Returns the checked answer, whatever it says. */
97
+ call(args, request) {
98
+ const exe = this.exe();
99
+ if (!exe)
100
+ fail('HcsHost.exe could not be built.', 'It needs the .NET Framework compiler that ships with Windows.');
101
+ const dir = fs.mkdtempSync(path.join(this.tempRoot, 'agent-sandbox-hcs-'));
102
+ try {
103
+ const out = path.join(dir, 'response.json');
104
+ const full = [...args];
105
+ if (request !== undefined) {
106
+ const file = path.join(dir, 'request.json');
107
+ fs.writeFileSync(file, JSON.stringify(request), 'utf8');
108
+ full.push(file);
109
+ }
110
+ const result = this.run(exe, [...full, '--out', out], CALL_TIMEOUT_MS);
111
+ return readReply(out, result);
112
+ }
113
+ finally {
114
+ fs.rmSync(dir, { recursive: true, force: true });
115
+ }
116
+ }
117
+ /** The same, but a failed answer stops with the helper's own message. */
118
+ must(args, request) {
119
+ const reply = this.call(args, request);
120
+ if (!reply.ok)
121
+ fail('The Host Compute Service said: ' + reply.message + ' (' + reply.hresult + ')');
122
+ return reply;
123
+ }
124
+ check() {
125
+ return this.call(['check']);
126
+ }
127
+ enumerate() {
128
+ return this.must(['enumerate']);
129
+ }
130
+ properties(id) {
131
+ return this.must(['properties', idArg(id)]);
132
+ }
133
+ /** `document` is the HCS JSON text; it travels as a string inside the request file. */
134
+ create(id, document) {
135
+ return this.must(['create'], { id: idArg(id), document });
136
+ }
137
+ start(id) {
138
+ return this.must(['start', idArg(id)]);
139
+ }
140
+ terminate(id) {
141
+ return this.must(['terminate', idArg(id)]);
142
+ }
143
+ grantVmAccess(vmId, file) {
144
+ return this.must(['grant-vm-access', idArg(vmId), pathArg(file, 'the disk')]);
145
+ }
146
+ createVhdx(file, maxGb) {
147
+ if (!Number.isInteger(maxGb) || maxGb < 1 || maxGb > 4096)
148
+ fail('The disk size must be 1 to 4096 GB.');
149
+ return this.must(['create-vhdx', pathArg(file, 'the disk'), String(maxGb)]);
150
+ }
151
+ }
152
+ function readReply(file, result) {
153
+ let text;
154
+ try {
155
+ if (fs.statSync(file).size > MAX_RESPONSE_BYTES)
156
+ fail('HcsHost.exe answered with too much text.');
157
+ text = fs.readFileSync(file, 'utf8');
158
+ }
159
+ catch (e) {
160
+ if (e instanceof UserError)
161
+ throw e;
162
+ fail('HcsHost.exe gave no answer' + (result.error ? ': ' + result.error : '') + '.');
163
+ }
164
+ let json;
165
+ try {
166
+ json = JSON.parse(text);
167
+ }
168
+ catch {
169
+ return fail('HcsHost.exe answered with something that is not JSON.');
170
+ }
171
+ const parsed = HcsReplySchema.safeParse(json);
172
+ return parsed.success ? parsed.data : fail('HcsHost.exe answered in a form this version does not know.');
173
+ }
@@ -0,0 +1,37 @@
1
+ import type { HcsImage } from './documents.js';
2
+ /** What a store says when it has no image: said to the user in plain words. */
3
+ export interface ImageResult {
4
+ readonly image: HcsImage | null;
5
+ readonly reason: string;
6
+ }
7
+ export interface ImageStore {
8
+ readonly name: string;
9
+ find(): ImageResult;
10
+ }
11
+ /** The file reads a store does, so tests give it a fake disk. Every read is bounded and a miss is null. */
12
+ export interface ImageFiles {
13
+ readText(file: string): string | null;
14
+ isDir(folder: string): boolean;
15
+ }
16
+ export declare const REAL_IMAGE_FILES: ImageFiles;
17
+ /** Docker's chain ids: id(1) = diffId(1); id(n) = sha256(id(n-1) + " " + diffId(n)). */
18
+ export declare function chainIds(diffIds: readonly string[]): string[];
19
+ /** An image Docker Desktop (Windows containers) already pulled: found by reading its metadata, never changed. */
20
+ export declare class DockerImageStore implements ImageStore {
21
+ private readonly root;
22
+ private readonly files;
23
+ readonly name = "an image Docker already pulled";
24
+ constructor(root?: string, files?: ImageFiles);
25
+ find(): ImageResult;
26
+ }
27
+ /** Your own image folder (AGENT_SANDBOX_HCS_IMAGE): a folder with image.json {layers (base first), utilityVmFiles}. */
28
+ export declare class FolderImageStore implements ImageStore {
29
+ private readonly folder;
30
+ private readonly files;
31
+ readonly name = "an image folder you named";
32
+ constructor(folder?: string | undefined, files?: ImageFiles);
33
+ find(): ImageResult;
34
+ }
35
+ export declare function defaultImageStores(): ImageStore[];
36
+ /** The first image any store has, or every store's reason. */
37
+ export declare function findImage(stores: readonly ImageStore[]): ImageResult;
@@ -0,0 +1,152 @@
1
+ // Where the HCS engine gets its base image (Windows Server Core, ltsc2022). This phase never downloads one: it only
2
+ // finds an image that is already on this PC, read-only. The layout of Docker's image store is from memory of Docker's
3
+ // windowsfilter graph driver [U]; nothing here writes to it.
4
+ import crypto from 'node:crypto';
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { z } from 'zod';
8
+ const MAX_TEXT = 4 * 1024 * 1024;
9
+ export const REAL_IMAGE_FILES = {
10
+ readText: (file) => {
11
+ try {
12
+ if (fs.statSync(file).size > MAX_TEXT)
13
+ return null;
14
+ return fs.readFileSync(file, 'utf8');
15
+ }
16
+ catch {
17
+ return null; // missing or unreadable: the store reports "not found"
18
+ }
19
+ },
20
+ isDir: (folder) => {
21
+ try {
22
+ return fs.statSync(folder).isDirectory();
23
+ }
24
+ catch {
25
+ return false; // missing: not a folder
26
+ }
27
+ },
28
+ };
29
+ /** The repository and tag of the image we look for: Windows Server Core 2022, any registry spelling. */
30
+ const WANTED = /(^|\/)windows\/servercore:ltsc2022$/i;
31
+ const RepositoriesSchema = z.object({ Repositories: z.record(z.string(), z.record(z.string(), z.string())) });
32
+ const ImageConfigSchema = z.object({
33
+ rootfs: z.object({
34
+ diff_ids: z
35
+ .array(z.string().regex(/^sha256:[0-9a-f]{64}$/))
36
+ .min(1)
37
+ .max(200),
38
+ }),
39
+ });
40
+ const HEX64 = /^[0-9a-f]{64}$/;
41
+ const CACHE_ID = /^[0-9a-zA-Z]{1,128}$/;
42
+ /** Docker's chain ids: id(1) = diffId(1); id(n) = sha256(id(n-1) + " " + diffId(n)). */
43
+ export function chainIds(diffIds) {
44
+ const out = [];
45
+ for (const diff of diffIds) {
46
+ const prev = out[out.length - 1];
47
+ out.push(prev
48
+ ? 'sha256:' +
49
+ crypto
50
+ .createHash('sha256')
51
+ .update(prev + ' ' + diff)
52
+ .digest('hex')
53
+ : diff);
54
+ }
55
+ return out;
56
+ }
57
+ /** An image Docker Desktop (Windows containers) already pulled: found by reading its metadata, never changed. */
58
+ export class DockerImageStore {
59
+ root;
60
+ files;
61
+ name = 'an image Docker already pulled';
62
+ constructor(root = path.join(process.env.ProgramData ?? 'C:\\ProgramData', 'docker'), files = REAL_IMAGE_FILES) {
63
+ this.root = root;
64
+ this.files = files;
65
+ }
66
+ find() {
67
+ const meta = path.join(this.root, 'image', 'windowsfilter');
68
+ const repos = this.files.readText(path.join(meta, 'repositories.json'));
69
+ if (repos === null)
70
+ return { image: null, reason: 'Docker has no Windows images on this PC.' };
71
+ const parsed = RepositoriesSchema.safeParse(safeJson(repos));
72
+ if (!parsed.success)
73
+ return { image: null, reason: "Docker's image list could not be read." };
74
+ let imageId = null;
75
+ for (const tags of Object.values(parsed.data.Repositories))
76
+ for (const [name, id] of Object.entries(tags))
77
+ if (!imageId && WANTED.test(name) && /^sha256:[0-9a-f]{64}$/.test(id))
78
+ imageId = id;
79
+ if (!imageId)
80
+ return { image: null, reason: 'Docker has no windows/servercore:ltsc2022 image.' };
81
+ const config = ImageConfigSchema.safeParse(safeJson(this.files.readText(path.join(meta, 'imagedb', 'content', 'sha256', imageId.slice(7))) ?? ''));
82
+ if (!config.success)
83
+ return { image: null, reason: "Docker's record of the Server Core image could not be read." };
84
+ const layers = [];
85
+ for (const chain of chainIds(config.data.rootfs.diff_ids)) {
86
+ const hex = chain.slice(7);
87
+ if (!HEX64.test(hex))
88
+ return { image: null, reason: 'A layer id of the Server Core image is not valid.' };
89
+ const cacheId = (this.files.readText(path.join(meta, 'layerdb', 'sha256', hex, 'cache-id')) ?? '').trim();
90
+ if (!CACHE_ID.test(cacheId))
91
+ return { image: null, reason: 'A layer of the Server Core image is not on disk.' };
92
+ const folder = path.join(this.root, 'windowsfilter', cacheId);
93
+ if (!this.files.isDir(folder))
94
+ return { image: null, reason: 'A layer of the Server Core image is missing.' };
95
+ layers.push(folder);
96
+ }
97
+ const utilityVmFiles = path.join(layers[0], 'UtilityVM', 'Files');
98
+ if (!this.files.isDir(utilityVmFiles))
99
+ return { image: null, reason: 'The Server Core image has no UtilityVM folder (Hyper-V isolation needs it).' };
100
+ return { image: { id: imageId, layers, utilityVmFiles }, reason: '' };
101
+ }
102
+ }
103
+ const FolderImageSchema = z.object({
104
+ layers: z.array(z.string().min(3).max(260)).min(1).max(200),
105
+ utilityVmFiles: z.string().min(3).max(260),
106
+ });
107
+ /** Your own image folder (AGENT_SANDBOX_HCS_IMAGE): a folder with image.json {layers (base first), utilityVmFiles}. */
108
+ export class FolderImageStore {
109
+ folder;
110
+ files;
111
+ name = 'an image folder you named';
112
+ constructor(folder = process.env.AGENT_SANDBOX_HCS_IMAGE, files = REAL_IMAGE_FILES) {
113
+ this.folder = folder;
114
+ this.files = files;
115
+ }
116
+ find() {
117
+ if (!this.folder)
118
+ return { image: null, reason: 'No image folder is set (AGENT_SANDBOX_HCS_IMAGE).' };
119
+ const parsed = FolderImageSchema.safeParse(safeJson(this.files.readText(path.join(this.folder, 'image.json')) ?? ''));
120
+ if (!parsed.success)
121
+ return { image: null, reason: 'There is no valid image.json in ' + this.folder + '.' };
122
+ const all = [...parsed.data.layers, parsed.data.utilityVmFiles];
123
+ if (!all.every((p) => path.isAbsolute(p) && this.files.isDir(p)))
124
+ return { image: null, reason: 'A folder named in ' + path.join(this.folder, 'image.json') + ' is missing.' };
125
+ return {
126
+ image: { id: 'folder', layers: parsed.data.layers, utilityVmFiles: parsed.data.utilityVmFiles },
127
+ reason: '',
128
+ };
129
+ }
130
+ }
131
+ function safeJson(text) {
132
+ try {
133
+ return JSON.parse(text);
134
+ }
135
+ catch {
136
+ return null; // not JSON: the schema check then fails with a plain message
137
+ }
138
+ }
139
+ export function defaultImageStores() {
140
+ return [new FolderImageStore(), new DockerImageStore()];
141
+ }
142
+ /** The first image any store has, or every store's reason. */
143
+ export function findImage(stores) {
144
+ const reasons = [];
145
+ for (const store of stores) {
146
+ const result = store.find();
147
+ if (result.image)
148
+ return result;
149
+ reasons.push(result.reason);
150
+ }
151
+ return { image: null, reason: reasons.join(' ') };
152
+ }
@@ -0,0 +1,7 @@
1
+ export type { SandboxEngine } from './engine.js';
2
+ export type { EngineCapabilities, EngineCheck, EngineId, EnginePlan, LaunchDevices, LaunchPlan, RunningSandbox, } from './types.js';
3
+ export { engineFor, engineReports, openEngine, type EngineReport } from './registry.js';
4
+ export { WindowsSandboxEngine } from './windows-sandbox/engine.js';
5
+ export { wsbText } from './windows-sandbox/wsb-text.js';
6
+ export { HcsEngine, HCS_CAPABILITIES, hcsStartEnabled } from './hcs/engine.js';
7
+ export { checkHcs, realHcsProbes, type HcsProbes } from './hcs/check.js';
@@ -0,0 +1,5 @@
1
+ export { engineFor, engineReports, openEngine } from './registry.js';
2
+ export { WindowsSandboxEngine } from './windows-sandbox/engine.js';
3
+ export { wsbText } from './windows-sandbox/wsb-text.js';
4
+ export { HcsEngine, HCS_CAPABILITIES, hcsStartEnabled } from './hcs/engine.js';
5
+ export { checkHcs, realHcsProbes } from './hcs/check.js';
@@ -0,0 +1,16 @@
1
+ import type { Config } from '../../core/types.js';
2
+ import type { SandboxEngine } from './engine.js';
3
+ import { type HcsProbes } from './hcs/check.js';
4
+ import type { EngineCapabilities, EngineCheck, EngineId } from './types.js';
5
+ /** The engine for the settings when nothing is looked up first (Windows Sandbox); hcs is opened with openEngine. */
6
+ export declare function engineFor(config: Config): SandboxEngine;
7
+ /** The engine to launch with. HCS is returned only when its check passes; otherwise this stops with the reasons. */
8
+ export declare function openEngine(config: Config, hcsProbes?: HcsProbes): Promise<SandboxEngine>;
9
+ export interface EngineReport {
10
+ readonly id: EngineId;
11
+ readonly inUse: boolean;
12
+ readonly capabilities: EngineCapabilities;
13
+ readonly check: EngineCheck;
14
+ }
15
+ /** Every engine with its capabilities and whether it can be used on this PC. */
16
+ export declare function engineReports(config: Config, hcsProbes?: HcsProbes): Promise<EngineReport[]>;
@@ -0,0 +1,30 @@
1
+ import { fail } from '../../core/util/index.js';
2
+ import { checkHcs, realHcsProbes } from './hcs/check.js';
3
+ import { HCS_CAPABILITIES, HcsEngine } from './hcs/engine.js';
4
+ import { WindowsSandboxEngine } from './windows-sandbox/engine.js';
5
+ /** The engine for the settings when nothing is looked up first (Windows Sandbox); hcs is opened with openEngine. */
6
+ export function engineFor(config) {
7
+ if (config.sandbox.engine === 'hcs')
8
+ fail('The HCS engine has to be opened first (its check looks at this PC).', 'Run: sandbox engine check hcs');
9
+ return new WindowsSandboxEngine(config.sandbox);
10
+ }
11
+ /** The engine to launch with. HCS is returned only when its check passes; otherwise this stops with the reasons. */
12
+ export async function openEngine(config, hcsProbes) {
13
+ if (config.sandbox.engine === 'hcs')
14
+ return HcsEngine.open(config.storage.root, hcsProbes);
15
+ return engineFor(config);
16
+ }
17
+ /** Every engine with its capabilities and whether it can be used on this PC. */
18
+ export async function engineReports(config, hcsProbes = realHcsProbes()) {
19
+ const windows = new WindowsSandboxEngine(config.sandbox);
20
+ const inUse = config.sandbox.engine;
21
+ return [
22
+ {
23
+ id: 'windows-sandbox',
24
+ inUse: inUse === 'windows-sandbox',
25
+ capabilities: windows.capabilities(),
26
+ check: await windows.check(),
27
+ },
28
+ { id: 'hcs', inUse: inUse === 'hcs', capabilities: HCS_CAPABILITIES, check: checkHcs(hcsProbes) },
29
+ ];
30
+ }
@@ -0,0 +1,58 @@
1
+ import type { Config, ResolvedMapping } from '../../core/types.js';
2
+ import type { StorageAttachment } from '../storage/providers/index.js';
3
+ export type EngineId = Config['sandbox']['engine'];
4
+ export interface EngineCapabilities {
5
+ readonly desktop: boolean;
6
+ readonly gpu: boolean;
7
+ readonly clipboard: boolean;
8
+ readonly audio: boolean;
9
+ readonly video: boolean;
10
+ readonly printers: boolean;
11
+ /** Folders can be added to a running sandbox. */
12
+ readonly liveFolderAdd: boolean;
13
+ readonly attachedDisks: boolean;
14
+ readonly multipleInstances: boolean;
15
+ readonly hvsocket: boolean;
16
+ }
17
+ export interface EngineCheck {
18
+ readonly available: boolean;
19
+ readonly reasons: readonly string[];
20
+ readonly fixes: readonly string[];
21
+ }
22
+ export interface LaunchDevices {
23
+ readonly gpu: boolean;
24
+ readonly clipboard: boolean;
25
+ readonly audioInput: boolean;
26
+ readonly videoInput: boolean;
27
+ readonly printers: boolean;
28
+ readonly protectedClient: boolean;
29
+ }
30
+ /** One launch, whatever runs it. Pure data: nothing in it is engine-specific. */
31
+ export interface LaunchPlan {
32
+ /** The launch folder: where an engine writes its own files. */
33
+ readonly launchPath: string;
34
+ readonly memoryMb: number;
35
+ /** Percent of this PC's CPU, or 'none'. The guest applies it; an engine may use it as a hint. */
36
+ readonly cpuLimit: 'none' | number;
37
+ readonly networking: boolean;
38
+ readonly devices: LaunchDevices;
39
+ /** Every folder shared in, in order (the folder attachments of `storage` are among them). */
40
+ readonly mappings: readonly ResolvedMapping[];
41
+ /** The command the guest runs at logon. */
42
+ readonly logonCommand: string;
43
+ readonly storage: readonly StorageAttachment[];
44
+ }
45
+ /** What an engine made of a LaunchPlan: files to write and the one to start from. Callers do not look inside. */
46
+ export interface EnginePlan {
47
+ readonly engine: EngineId;
48
+ readonly files: readonly {
49
+ readonly path: string;
50
+ readonly text: string;
51
+ }[];
52
+ readonly entry: string;
53
+ }
54
+ export interface RunningSandbox {
55
+ readonly id: string;
56
+ readonly engine: EngineId;
57
+ readonly started: number;
58
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { Config } from '../../../core/types.js';
2
+ import type { SandboxEngine } from '../engine.js';
3
+ import type { EngineCapabilities, EngineCheck, EnginePlan, LaunchPlan, RunningSandbox } from '../types.js';
4
+ export declare class WindowsSandboxEngine implements SandboxEngine {
5
+ private readonly sandbox;
6
+ private readonly hasWsbCli;
7
+ readonly id = "windows-sandbox";
8
+ /** `hasWsbCli`: whether wsb.exe is on this PC (adding folders to a running sandbox needs it). */
9
+ constructor(sandbox: Config['sandbox'], hasWsbCli?: () => boolean);
10
+ capabilities(): EngineCapabilities;
11
+ check(): Promise<EngineCheck>;
12
+ plan(launch: LaunchPlan): EnginePlan;
13
+ start(plan: EnginePlan): Promise<RunningSandbox>;
14
+ running(): Promise<boolean>;
15
+ stop(): Promise<void>;
16
+ }
@@ -0,0 +1,63 @@
1
+ // Windows Sandbox behind the engine interface: the .wsb file, and the existing start / wait / running code.
2
+ import path from 'node:path';
3
+ import { fail, isWin } from '../../../core/util/index.js';
4
+ import { confirmSandboxStarted, findWsb, isSandboxRunning, sandboxFeatureInstalled, startSandbox, } from '../../sandbox/index.js';
5
+ import { wsbText } from './wsb-text.js';
6
+ const WSB_FILE = 'agent.wsb';
7
+ export class WindowsSandboxEngine {
8
+ sandbox;
9
+ hasWsbCli;
10
+ id = 'windows-sandbox';
11
+ /** `hasWsbCli`: whether wsb.exe is on this PC (adding folders to a running sandbox needs it). */
12
+ constructor(sandbox, hasWsbCli = () => findWsb() !== null) {
13
+ this.sandbox = sandbox;
14
+ this.hasWsbCli = hasWsbCli;
15
+ }
16
+ capabilities() {
17
+ return {
18
+ desktop: true,
19
+ gpu: this.sandbox.vGpu,
20
+ clipboard: this.sandbox.clipboard,
21
+ audio: this.sandbox.audioInput,
22
+ video: this.sandbox.videoInput,
23
+ printers: this.sandbox.printerRedirection,
24
+ liveFolderAdd: this.hasWsbCli(),
25
+ attachedDisks: false,
26
+ multipleInstances: false,
27
+ hvsocket: false,
28
+ };
29
+ }
30
+ check() {
31
+ if (!isWin)
32
+ return Promise.resolve({
33
+ available: false,
34
+ reasons: ['Windows Sandbox only runs on Windows.'],
35
+ fixes: ['Use sandbox generate to only write the files.'],
36
+ });
37
+ if (!sandboxFeatureInstalled())
38
+ return Promise.resolve({
39
+ available: false,
40
+ reasons: ['Windows Sandbox is not enabled on this PC.'],
41
+ fixes: [
42
+ 'Run in an admin PowerShell, then reboot: Enable-WindowsOptionalFeature -Online -FeatureName Containers-DisposableClientVM -All (needs Windows Pro, Enterprise or Education)',
43
+ ],
44
+ });
45
+ return Promise.resolve({ available: true, reasons: [], fixes: [] });
46
+ }
47
+ plan(launch) {
48
+ const entry = path.join(launch.launchPath, WSB_FILE);
49
+ return { engine: this.id, files: [{ path: entry, text: wsbText(launch) }], entry };
50
+ }
51
+ async start(plan) {
52
+ startSandbox(plan.entry);
53
+ await confirmSandboxStarted(plan.entry);
54
+ return { id: path.basename(path.dirname(plan.entry)), engine: this.id, started: Date.now() };
55
+ }
56
+ running() {
57
+ return Promise.resolve(isSandboxRunning());
58
+ }
59
+ stop() {
60
+ // Windows Sandbox shuts itself down from inside, through the session channel; it is never killed from outside.
61
+ return Promise.resolve().then(() => fail('Windows Sandbox is not stopped from outside.', 'Use sandbox stop (it shuts down from inside).'));
62
+ }
63
+ }
@@ -0,0 +1,2 @@
1
+ import type { LaunchPlan } from '../types.js';
2
+ export declare function wsbText(plan: LaunchPlan): string;
@@ -0,0 +1,29 @@
1
+ // The .wsb file Windows Sandbox starts from: memory, devices and the folders mapped in, written from a LaunchPlan.
2
+ import { xmlEscape } from '../../../core/util/index.js';
3
+ import { sandboxFolder } from '../../../shared/paths/index.js';
4
+ function element(name, value) {
5
+ return '<' + name + '>' + value + '</' + name + '>';
6
+ }
7
+ function toggle(value) {
8
+ return value ? 'Enable' : 'Disable';
9
+ }
10
+ export function wsbText(plan) {
11
+ const d = plan.devices;
12
+ // Guest paths on other drive letters (F:\x) really live under C:\Mirror\F; bootstrap.ps1 substs F: onto it at boot.
13
+ const folders = plan.mappings
14
+ .map((m) => element('MappedFolder', element('HostFolder', xmlEscape(m.host)) +
15
+ element('SandboxFolder', xmlEscape(sandboxFolder(m.guest))) +
16
+ element('ReadOnly', String(m.readOnly))))
17
+ .join('');
18
+ // The elements are in the order Windows Sandbox expects.
19
+ return element('Configuration', element('MemoryInMB', String(plan.memoryMb)) +
20
+ element('vGPU', toggle(d.gpu)) +
21
+ element('Networking', toggle(plan.networking)) +
22
+ element('ClipboardRedirection', toggle(d.clipboard)) +
23
+ element('AudioInput', toggle(d.audioInput)) +
24
+ element('VideoInput', toggle(d.videoInput)) +
25
+ element('PrinterRedirection', toggle(d.printers)) +
26
+ element('ProtectedClient', toggle(d.protectedClient)) +
27
+ element('MappedFolders', folders) +
28
+ element('LogonCommand', element('Command', xmlEscape(plan.logonCommand))));
29
+ }
@@ -1,4 +1,8 @@
1
1
  import type { GenerateOptions, Generated } from '../../core/types.js';
2
- export declare function generateSandbox(given: GenerateOptions): Generated & {
2
+ import { type EnginePlan, type SandboxEngine } from '../engines/index.js';
3
+ export declare function generateSandbox(given: GenerateOptions,
4
+ /** The engine launch.ts opened (hcs needs a look at this PC first); Windows Sandbox when left out. */
5
+ opened?: SandboxEngine): Generated & {
3
6
  personalization: string;
7
+ enginePlan: EnginePlan;
4
8
  };