windows-development-sandbox 1.9.0 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/README.md +64 -17
  2. package/config.example.json +7 -2
  3. package/dist/app/features/accounts/accounts.def.d.ts +122 -0
  4. package/dist/app/features/accounts/accounts.def.js +243 -0
  5. package/dist/app/features/accounts/accounts.run.d.ts +51 -0
  6. package/dist/app/features/accounts/accounts.run.js +125 -0
  7. package/dist/app/features/accounts/index.d.ts +2 -0
  8. package/dist/app/features/accounts/index.js +3 -0
  9. package/dist/app/features/agents/agent-entry.d.ts +17 -0
  10. package/dist/app/features/agents/agent-entry.js +50 -0
  11. package/dist/app/features/agents/agents.def.d.ts +65 -0
  12. package/dist/app/features/agents/agents.def.js +142 -0
  13. package/dist/app/features/agents/agents.run.d.ts +31 -0
  14. package/dist/app/features/agents/agents.run.js +189 -0
  15. package/dist/app/features/agents/index.d.ts +3 -0
  16. package/dist/app/features/agents/index.js +4 -0
  17. package/dist/app/features/apps/apps-rows.d.ts +31 -0
  18. package/dist/app/features/apps/apps-rows.js +73 -0
  19. package/dist/app/features/apps/apps.def.d.ts +181 -0
  20. package/dist/app/features/apps/apps.def.js +264 -0
  21. package/dist/app/features/apps/apps.run.d.ts +58 -0
  22. package/dist/app/features/apps/apps.run.js +76 -0
  23. package/dist/app/features/apps/index.d.ts +3 -0
  24. package/dist/app/features/apps/index.js +4 -0
  25. package/dist/app/features/data/data.def.d.ts +154 -0
  26. package/dist/app/features/data/data.def.js +201 -0
  27. package/dist/app/features/data/data.run.d.ts +46 -0
  28. package/dist/app/features/data/data.run.js +141 -0
  29. package/dist/app/features/data/index.d.ts +2 -0
  30. package/dist/app/features/data/index.js +3 -0
  31. package/dist/app/features/defs.d.ts +952 -4
  32. package/dist/app/features/defs.js +147 -10
  33. package/dist/app/features/engine/engine.def.d.ts +228 -0
  34. package/dist/app/features/engine/engine.def.js +194 -0
  35. package/dist/app/features/engine/engine.run.d.ts +72 -0
  36. package/dist/app/features/engine/engine.run.js +77 -0
  37. package/dist/app/features/engine/index.d.ts +2 -0
  38. package/dist/app/features/engine/index.js +4 -0
  39. package/dist/app/features/files/files.def.d.ts +51 -0
  40. package/dist/app/features/files/files.def.js +38 -0
  41. package/dist/app/features/files/files.run.d.ts +20 -0
  42. package/dist/app/features/files/files.run.js +59 -0
  43. package/dist/app/features/files/index.d.ts +2 -0
  44. package/dist/app/features/files/index.js +3 -0
  45. package/dist/app/features/github/github.def.d.ts +80 -0
  46. package/dist/app/features/github/github.def.js +142 -0
  47. package/dist/app/features/github/github.run.d.ts +36 -0
  48. package/dist/app/features/github/github.run.js +59 -0
  49. package/dist/app/features/github/index.d.ts +2 -0
  50. package/dist/app/features/github/index.js +3 -0
  51. package/dist/app/features/health/health.def.d.ts +275 -0
  52. package/dist/app/features/health/health.def.js +281 -0
  53. package/dist/app/features/health/health.run.d.ts +125 -0
  54. package/dist/app/features/health/health.run.js +204 -0
  55. package/dist/app/features/health/index.d.ts +2 -0
  56. package/dist/app/features/health/index.js +3 -0
  57. package/dist/app/features/logs/index.d.ts +2 -0
  58. package/dist/app/features/logs/index.js +3 -0
  59. package/dist/app/features/logs/logs.def.d.ts +78 -0
  60. package/dist/app/features/logs/logs.def.js +115 -0
  61. package/dist/app/features/logs/logs.run.d.ts +20 -0
  62. package/dist/app/features/logs/logs.run.js +42 -0
  63. package/dist/app/features/projects/index.d.ts +2 -0
  64. package/dist/app/features/projects/index.js +3 -0
  65. package/dist/app/features/projects/projects.def.d.ts +101 -0
  66. package/dist/app/features/projects/projects.def.js +208 -0
  67. package/dist/app/features/projects/projects.run.d.ts +56 -0
  68. package/dist/app/features/projects/projects.run.js +155 -0
  69. package/dist/app/features/sandbox/sandbox.def.js +11 -5
  70. package/dist/app/features/sessions/sessions.def.js +3 -0
  71. package/dist/app/features/settings/categories.def.js +3 -2
  72. package/dist/{cli/menu/settings/share.d.ts → app/features/settings/settings-share.d.ts} +1 -1
  73. package/dist/{cli/menu/settings/share.js → app/features/settings/settings-share.js} +3 -2
  74. package/dist/app/features/settings/settings.def.d.ts +22 -5
  75. package/dist/app/features/settings/settings.def.js +81 -6
  76. package/dist/app/features/settings/settings.run.d.ts +17 -0
  77. package/dist/app/features/settings/settings.run.js +89 -4
  78. package/dist/app/features/storage/index.d.ts +2 -0
  79. package/dist/app/features/storage/index.js +3 -0
  80. package/dist/app/features/storage/storage.def.d.ts +133 -0
  81. package/dist/app/features/storage/storage.def.js +225 -0
  82. package/dist/app/features/storage/storage.run.d.ts +62 -0
  83. package/dist/app/features/storage/storage.run.js +370 -0
  84. package/dist/app/features/updates/index.d.ts +3 -0
  85. package/dist/app/features/updates/index.js +4 -0
  86. package/dist/app/features/updates/update-lines.d.ts +13 -0
  87. package/dist/app/features/updates/update-lines.js +61 -0
  88. package/dist/app/features/updates/updates.def.d.ts +89 -0
  89. package/dist/app/features/updates/updates.def.js +225 -0
  90. package/dist/app/features/updates/updates.run.d.ts +48 -0
  91. package/dist/app/features/updates/updates.run.js +154 -0
  92. package/dist/app/features/vpn/index.d.ts +2 -0
  93. package/dist/app/features/vpn/index.js +3 -0
  94. package/dist/app/features/vpn/vpn.def.d.ts +112 -0
  95. package/dist/app/features/vpn/vpn.def.js +174 -0
  96. package/dist/app/features/vpn/vpn.run.d.ts +37 -0
  97. package/dist/app/features/vpn/vpn.run.js +54 -0
  98. package/dist/app/features/web/index.d.ts +2 -0
  99. package/dist/app/features/web/index.js +3 -0
  100. package/dist/app/features/web/web.def.d.ts +33 -0
  101. package/dist/app/features/web/web.def.js +90 -0
  102. package/dist/app/features/web/web.run.d.ts +24 -0
  103. package/dist/app/features/web/web.run.js +93 -0
  104. package/dist/app/kernel/define.d.ts +10 -1
  105. package/dist/app/kernel/io.d.ts +34 -0
  106. package/dist/app/kernel/io.js +9 -0
  107. package/dist/app/kernel/rpc.d.ts +17 -0
  108. package/dist/app/kernel/text.d.ts +2 -0
  109. package/dist/app/kernel/text.js +7 -0
  110. package/dist/app/kernel/view.d.ts +24 -1
  111. package/dist/app/kernel/view.js +1 -1
  112. package/dist/app/registry.js +74 -1
  113. package/dist/cli/args.js +1 -1
  114. package/dist/cli/commands/context.d.ts +7 -0
  115. package/dist/cli/commands/context.js +29 -2
  116. package/dist/cli/commands/engine.js +5 -58
  117. package/dist/cli/commands/github.d.ts +2 -0
  118. package/dist/cli/commands/github.js +11 -0
  119. package/dist/cli/commands/index.d.ts +3 -5
  120. package/dist/cli/commands/index.js +3 -5
  121. package/dist/cli/commands/launch/launch.js +23 -4
  122. package/dist/cli/commands/launch/running.js +4 -1
  123. package/dist/cli/commands/maintenance/config.js +1 -6
  124. package/dist/cli/commands/maintenance/index.d.ts +0 -1
  125. package/dist/cli/commands/maintenance/index.js +1 -2
  126. package/dist/cli/commands/maintenance/logs.js +27 -32
  127. package/dist/cli/commands/maintenance/migrate.d.ts +0 -8
  128. package/dist/cli/commands/maintenance/migrate.js +2 -44
  129. package/dist/cli/commands/maintenance/update.d.ts +0 -19
  130. package/dist/cli/commands/maintenance/update.js +1 -99
  131. package/dist/cli/commands/projects/index.d.ts +0 -1
  132. package/dist/cli/commands/projects/index.js +0 -1
  133. package/dist/cli/commands/registry.d.ts +1 -1
  134. package/dist/cli/commands/registry.js +29 -11
  135. package/dist/cli/commands/repair/checks/data.js +1 -1
  136. package/dist/cli/commands/repair/checks/hcs.js +28 -1
  137. package/dist/cli/commands/repair/checks/sandbox.js +1 -1
  138. package/dist/cli/commands/repair/health-run.d.ts +30 -0
  139. package/dist/cli/commands/repair/health-run.js +32 -0
  140. package/dist/cli/commands/repair/printer.d.ts +2 -2
  141. package/dist/cli/commands/repair/printer.js +2 -11
  142. package/dist/cli/commands/repair/run.d.ts +1 -21
  143. package/dist/cli/commands/repair/run.js +13 -70
  144. package/dist/cli/commands/storage/index.d.ts +0 -1
  145. package/dist/cli/commands/storage/index.js +0 -1
  146. package/dist/cli/commands/storage/offer.js +6 -2
  147. package/dist/cli/commands/vpn.d.ts +1 -3
  148. package/dist/cli/commands/vpn.js +8 -88
  149. package/dist/cli/commands/web.d.ts +7 -1
  150. package/dist/cli/commands/web.js +45 -71
  151. package/dist/cli/index.js +3 -2
  152. package/dist/cli/manifest.d.ts +16 -153
  153. package/dist/cli/manifest.js +20 -50
  154. package/dist/cli/menu/command-form.js +1 -2
  155. package/dist/cli/menu/io-menu.d.ts +2 -2
  156. package/dist/cli/menu/io-menu.js +6 -4
  157. package/dist/cli/menu/menu.js +1 -1
  158. package/dist/cli/menu/pages/accounts-page.d.ts +5 -17
  159. package/dist/cli/menu/pages/accounts-page.js +28 -170
  160. package/dist/cli/menu/pages/agents-page.d.ts +17 -18
  161. package/dist/cli/menu/pages/agents-page.js +67 -124
  162. package/dist/cli/menu/pages/apps-page.d.ts +15 -8
  163. package/dist/cli/menu/pages/apps-page.js +121 -29
  164. package/dist/cli/menu/pages/list-page.js +10 -1
  165. package/dist/cli/menu/pages/maintenance-page.d.ts +51 -52
  166. package/dist/cli/menu/pages/maintenance-page.js +246 -427
  167. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -5
  168. package/dist/cli/menu/pages/sandbox-page.js +34 -112
  169. package/dist/cli/menu/pages/settings-page.d.ts +21 -3
  170. package/dist/cli/menu/pages/settings-page.js +89 -17
  171. package/dist/cli/menu/render-view.js +2 -1
  172. package/dist/cli/menu/settings/index.d.ts +0 -1
  173. package/dist/cli/menu/settings/index.js +3 -3
  174. package/dist/cli/menu/views.js +28 -0
  175. package/dist/cli/operations/handler.js +7 -3
  176. package/dist/cli/operations/input.d.ts +1 -1
  177. package/dist/cli/operations/input.js +29 -5
  178. package/dist/cli/operations/io-cli.js +9 -1
  179. package/dist/cli/operations/spec.js +8 -2
  180. package/dist/cli/output/render-view.js +2 -0
  181. package/dist/cli/{commands/data/collect.js → services/data-collect.js} +2 -2
  182. package/dist/cli/{commands/data/remove.js → services/data-remove.js} +2 -2
  183. package/dist/cli/services/data-service.d.ts +1 -1
  184. package/dist/cli/services/data-service.js +2 -2
  185. package/dist/cli/services/databases-service.d.ts +5 -0
  186. package/dist/cli/services/databases-service.js +15 -0
  187. package/dist/cli/services/health-service.d.ts +8 -4
  188. package/dist/cli/services/health-service.js +10 -8
  189. package/dist/cli/services/index.d.ts +4 -1
  190. package/dist/cli/services/index.js +4 -1
  191. package/dist/cli/services/logs-service.d.ts +7 -0
  192. package/dist/cli/services/logs-service.js +13 -0
  193. package/dist/cli/services/storage-service.d.ts +19 -0
  194. package/dist/cli/services/storage-service.js +71 -0
  195. package/dist/cli/services/vpn-service.d.ts +6 -4
  196. package/dist/cli/services/vpn-service.js +5 -11
  197. package/dist/cli/services/web-service.d.ts +4 -3
  198. package/dist/cli/services/web-service.js +12 -32
  199. package/dist/core/config/defaults.js +3 -2
  200. package/dist/core/schema/config.d.ts +6 -0
  201. package/dist/core/schema/config.js +2 -0
  202. package/dist/core/schema/github.d.ts +4 -0
  203. package/dist/core/schema/github.js +7 -0
  204. package/dist/core/schema/index.d.ts +1 -0
  205. package/dist/core/schema/index.js +1 -0
  206. package/dist/core/schema/profile.d.ts +1 -0
  207. package/dist/core/schema/profile.js +3 -0
  208. package/dist/core/schema/sandbox.js +3 -3
  209. package/dist/core/schema/toolchains.js +2 -2
  210. package/dist/core/schema/vpn.js +1 -1
  211. package/dist/core/schema/web.d.ts +1 -0
  212. package/dist/core/schema/web.js +4 -1
  213. package/dist/core/types.d.ts +6 -3
  214. package/dist/guest/boot/boot.js +11 -1
  215. package/dist/guest/daemon/daemon.js +1 -1
  216. package/dist/guest/daemon/sessions.d.ts +3 -2
  217. package/dist/guest/daemon/sessions.js +38 -7
  218. package/dist/guest/governor/core.d.ts +44 -0
  219. package/dist/guest/governor/core.js +124 -0
  220. package/dist/guest/governor/decide.d.ts +53 -15
  221. package/dist/guest/governor/decide.js +155 -72
  222. package/dist/guest/governor/governor.d.ts +2 -35
  223. package/dist/guest/governor/governor.js +35 -99
  224. package/dist/guest/governor/index.d.ts +1 -0
  225. package/dist/guest/governor/index.js +1 -0
  226. package/dist/guest/network/firewall.d.ts +3 -0
  227. package/dist/guest/network/firewall.js +65 -23
  228. package/dist/guest/runtime/process.js +53 -5
  229. package/dist/guest/sessions/viewer.js +5 -1
  230. package/dist/guest/setup/claude-mem.js +12 -4
  231. package/dist/guest/setup/github-token.d.ts +7 -0
  232. package/dist/guest/setup/github-token.js +65 -0
  233. package/dist/guest/toolchains/languages/node.js +40 -4
  234. package/dist/guest/toolchains/native/rust-extras.js +2 -2
  235. package/dist/guest/toolchains/tools/cli.d.ts +8 -0
  236. package/dist/guest/toolchains/tools/cli.js +16 -2
  237. package/dist/guest/vpn/openvpn.d.ts +5 -0
  238. package/dist/guest/vpn/openvpn.js +14 -1
  239. package/dist/guest/vpn/vpn.js +55 -16
  240. package/dist/guest/vpn/wireguard.js +2 -0
  241. package/dist/host/channel/attach.d.ts +1 -0
  242. package/dist/host/channel/attach.js +1 -0
  243. package/dist/host/channel/channel.d.ts +1 -1
  244. package/dist/host/channel/channel.js +2 -2
  245. package/dist/host/engines/hcs/check.d.ts +1 -0
  246. package/dist/host/engines/hcs/check.js +1 -1
  247. package/dist/host/engines/hcs/engine.d.ts +1 -1
  248. package/dist/host/engines/hcs/engine.js +6 -4
  249. package/dist/host/engines/hcs/helper.d.ts +11 -0
  250. package/dist/host/engines/hcs/helper.js +31 -2
  251. package/dist/host/engines/hcs/leftovers.d.ts +42 -0
  252. package/dist/host/engines/hcs/leftovers.js +101 -0
  253. package/dist/host/engines/index.d.ts +1 -0
  254. package/dist/host/engines/index.js +1 -0
  255. package/dist/host/github/deliver.d.ts +13 -0
  256. package/dist/host/github/deliver.js +51 -0
  257. package/dist/host/github/index.d.ts +2 -0
  258. package/dist/host/github/index.js +3 -0
  259. package/dist/host/github/token.d.ts +21 -0
  260. package/dist/host/github/token.js +74 -0
  261. package/dist/host/launch/generate.js +11 -5
  262. package/dist/host/launch/index.d.ts +1 -1
  263. package/dist/host/launch/index.js +1 -1
  264. package/dist/host/launch/session-file.js +1 -2
  265. package/dist/host/launch/wsb-file.d.ts +11 -7
  266. package/dist/host/launch/wsb-file.js +30 -12
  267. package/dist/host/life/host-memory.d.ts +1 -0
  268. package/dist/host/life/host-memory.js +4 -1
  269. package/dist/host/life/watchdog.d.ts +11 -0
  270. package/dist/host/life/watchdog.js +36 -4
  271. package/dist/host/sandbox/tasklist.d.ts +6 -0
  272. package/dist/host/sandbox/tasklist.js +37 -0
  273. package/dist/host/secrets/launch-secrets.d.ts +2 -1
  274. package/dist/host/secrets/launch-secrets.js +4 -2
  275. package/dist/host/vpn/status.js +13 -3
  276. package/dist/host/web/backend.d.ts +1 -3
  277. package/dist/host/web/index.d.ts +2 -1
  278. package/dist/host/web/index.js +2 -1
  279. package/dist/host/web/live.d.ts +23 -0
  280. package/dist/host/web/live.js +107 -0
  281. package/dist/host/web/rpc.d.ts +6 -1
  282. package/dist/host/web/rpc.js +23 -31
  283. package/dist/host/web/runner.d.ts +4 -0
  284. package/dist/host/web/runner.js +12 -1
  285. package/dist/host/web/server.d.ts +30 -2
  286. package/dist/host/web/server.js +87 -29
  287. package/dist/host/web/state.d.ts +1 -0
  288. package/dist/host/web/state.js +2 -0
  289. package/dist/runtime/agent.js +44 -16
  290. package/dist/runtime/daemon.js +1154 -857
  291. package/dist/runtime/db.js +44 -16
  292. package/dist/runtime/main.js +532 -115
  293. package/dist/runtime/netproxy.js +34 -9
  294. package/dist/runtime/view.js +499 -149
  295. package/dist/selftest/app.test.js +620 -12
  296. package/dist/selftest/channel.test.js +18 -1
  297. package/dist/selftest/cli.test.js +1 -1
  298. package/dist/selftest/config.test.js +1 -1
  299. package/dist/selftest/contained.test.js +1 -1
  300. package/dist/selftest/data.test.js +1 -2
  301. package/dist/selftest/engine.test.js +3 -1
  302. package/dist/selftest/github.test.d.ts +2 -0
  303. package/dist/selftest/github.test.js +243 -0
  304. package/dist/selftest/guest-boot.test.js +47 -1
  305. package/dist/selftest/hcs.test.js +105 -8
  306. package/dist/selftest/health.test.js +71 -0
  307. package/dist/selftest/heavy-load.test.js +152 -66
  308. package/dist/selftest/index.js +4 -0
  309. package/dist/selftest/layout.test.js +8 -0
  310. package/dist/selftest/live-terminal.test.js +74 -0
  311. package/dist/selftest/menu-screens.js +171 -56
  312. package/dist/selftest/menu.test.js +54 -37
  313. package/dist/selftest/migrate.test.js +14 -12
  314. package/dist/selftest/network.test.js +20 -1
  315. package/dist/selftest/powershell-variables.test.d.ts +2 -0
  316. package/dist/selftest/powershell-variables.test.js +61 -0
  317. package/dist/selftest/support/engine-golden.js +1 -0
  318. package/dist/selftest/support/fixtures.d.ts +5 -0
  319. package/dist/selftest/support/web-preview.d.ts +1 -0
  320. package/dist/selftest/support/web-preview.js +856 -0
  321. package/dist/selftest/update-service.test.js +15 -8
  322. package/dist/selftest/vpn.test.js +86 -2
  323. package/dist/selftest/web.test.js +58 -11
  324. package/dist/shared/channel/run-dir.d.ts +2 -0
  325. package/dist/shared/channel/run-dir.js +3 -0
  326. package/dist/shared/channel/schema.d.ts +7 -0
  327. package/dist/shared/channel/schema.js +9 -1
  328. package/dist/shared/channel/secrets.d.ts +1 -0
  329. package/dist/shared/channel/secrets.js +3 -0
  330. package/dist/shared/github/index.d.ts +1 -0
  331. package/dist/shared/github/index.js +2 -0
  332. package/dist/shared/github/token.d.ts +29 -0
  333. package/dist/shared/github/token.js +89 -0
  334. package/dist/shared/io/copy-tree.d.ts +7 -0
  335. package/dist/shared/io/copy-tree.js +45 -0
  336. package/dist/shared/io/index.d.ts +2 -0
  337. package/dist/shared/io/index.js +2 -0
  338. package/dist/shared/io/robocopy-result.d.ts +6 -0
  339. package/dist/shared/io/robocopy-result.js +23 -0
  340. package/dist/shared/memory/policy.d.ts +38 -12
  341. package/dist/shared/memory/policy.js +58 -19
  342. package/dist/shared/network/firewall-rules.d.ts +8 -0
  343. package/dist/shared/network/firewall-rules.js +28 -0
  344. package/dist/shared/pty/ctrl-c.d.ts +18 -0
  345. package/dist/shared/pty/ctrl-c.js +36 -0
  346. package/dist/shared/pty/index.d.ts +1 -0
  347. package/dist/shared/pty/index.js +1 -0
  348. package/dist/shared/pty/terminal.d.ts +2 -0
  349. package/dist/shared/pty/terminal.js +21 -2
  350. package/dist/shared/vpn/kill-switch.d.ts +13 -2
  351. package/dist/shared/vpn/kill-switch.js +88 -8
  352. package/dist/shared/web/protocol.d.ts +0 -4
  353. package/dist/sync/watcher.js +1 -1
  354. package/dist/web/index.html +2 -2
  355. package/dist/web/{main-T5DMCHYV.css → main-6JF3ASB5.css} +1 -1
  356. package/dist/web/main-Z645W45E.js +219 -0
  357. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  358. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  359. package/native/csharp/HostTools/MemoryStatus.cs +128 -107
  360. package/native/scripts/memory-status.ps1 +10 -2
  361. package/package.json +10 -3
  362. package/sandbox/csharp/MemGov.cs +668 -398
  363. package/sandbox/csharp/PtyHost.cs +104 -15
  364. package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
  365. package/sandbox/csharp/SandboxTools/Program.cs +1 -1
  366. package/sandbox/scripts/new-shortcuts.ps1 +3 -1
  367. package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
  368. package/schemas/config.schema.json +25 -7
  369. package/schemas/sandbox-config.schema.json +7 -3
  370. package/dist/cli/commands/accounts.d.ts +0 -2
  371. package/dist/cli/commands/accounts.js +0 -96
  372. package/dist/cli/commands/data/clean.d.ts +0 -3
  373. package/dist/cli/commands/data/clean.js +0 -60
  374. package/dist/cli/commands/data/index.d.ts +0 -4
  375. package/dist/cli/commands/data/index.js +0 -62
  376. package/dist/cli/commands/maintenance/clean.d.ts +0 -2
  377. package/dist/cli/commands/maintenance/clean.js +0 -24
  378. package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
  379. package/dist/cli/commands/maintenance/config-share.js +0 -80
  380. package/dist/cli/commands/projects/projects.d.ts +0 -2
  381. package/dist/cli/commands/projects/projects.js +0 -162
  382. package/dist/cli/commands/storage/contained.d.ts +0 -3
  383. package/dist/cli/commands/storage/contained.js +0 -179
  384. package/dist/cli/commands/storage/storage.d.ts +0 -8
  385. package/dist/cli/commands/storage/storage.js +0 -179
  386. package/dist/cli/menu/add-agent.d.ts +0 -47
  387. package/dist/cli/menu/add-agent.js +0 -168
  388. package/dist/cli/menu/apps.d.ts +0 -69
  389. package/dist/cli/menu/apps.js +0 -214
  390. package/dist/cli/menu/data-folder.d.ts +0 -18
  391. package/dist/cli/menu/data-folder.js +0 -99
  392. package/dist/cli/menu/share-settings.d.ts +0 -21
  393. package/dist/cli/menu/share-settings.js +0 -112
  394. package/dist/cli/menu/vpn-login.d.ts +0 -16
  395. package/dist/cli/menu/vpn-login.js +0 -74
  396. package/dist/web/main-NRRS5O6Z.js +0 -157
  397. /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
  398. /package/dist/cli/{commands/data/remove.d.ts → services/data-remove.d.ts} +0 -0
@@ -1,3 +1,5 @@
1
1
  export * from './json.js';
2
2
  export * from './json-file.js';
3
3
  export * from './safe-remove.js';
4
+ export * from './robocopy-result.js';
5
+ export * from './copy-tree.js';
@@ -0,0 +1,6 @@
1
+ /** Exit code 8 and up means something could not be copied; below that every file is in place. */
2
+ export declare function robocopyFailed(code: number | null): boolean;
3
+ /** The exit code in plain words (it is a bit field: 1 copied, 2 extras, 4 mismatches, 8 failures, 16 fatal). */
4
+ export declare function robocopyMeaning(code: number | null): string;
5
+ /** The first few ERROR lines of robocopy's output (what went wrong and on which file), one line each. */
6
+ export declare function robocopyErrors(output: string, max?: number): string[];
@@ -0,0 +1,23 @@
1
+ // Reading robocopy's exit code and output (pure; the guest and the tests share it).
2
+ /** Exit code 8 and up means something could not be copied; below that every file is in place. */
3
+ export function robocopyFailed(code) {
4
+ return code === null || code >= 8;
5
+ }
6
+ /** The exit code in plain words (it is a bit field: 1 copied, 2 extras, 4 mismatches, 8 failures, 16 fatal). */
7
+ export function robocopyMeaning(code) {
8
+ if (code === null)
9
+ return 'robocopy did not finish';
10
+ if (code >= 16)
11
+ return 'robocopy stopped with a fatal error (bad path or no access)';
12
+ if (code >= 8)
13
+ return code & 1 ? 'some files were copied and some could not be' : 'files could not be copied';
14
+ return code === 0 ? 'nothing to copy' : 'copied';
15
+ }
16
+ /** The first few ERROR lines of robocopy's output (what went wrong and on which file), one line each. */
17
+ export function robocopyErrors(output, max = 3) {
18
+ const lines = output
19
+ .split(/\r?\n/)
20
+ .map((l) => l.trim())
21
+ .filter((l) => /\bERROR\b/.test(l) || /^The (process|system) cannot/i.test(l));
22
+ return lines.slice(0, max).map((l) => (l.length > 220 ? l.slice(0, 217) + '...' : l));
23
+ }
@@ -1,16 +1,27 @@
1
1
  export type LoadProfile = 'normal' | 'gentle';
2
- /** The guest governor: when memory inside the sandbox counts as under pressure, and when it has recovered. */
3
- export interface GuestThresholds {
4
- /** Pressure starts when available RAM is below this share of the sandbox's RAM (percent)... */
5
- readonly enterAvailablePercent: number;
6
- /** ...or commit is above this share of its limit. */
7
- readonly enterCommitPercent: number;
8
- /** Pressure ends only when available RAM is above this and commit is below the next, for `calmSamples` in a row. */
9
- readonly exitAvailablePercent: number;
10
- readonly exitCommitPercent: number;
11
- readonly calmSamples: number;
2
+ /**
3
+ * One step of the guest governor's dial. It turns up when available RAM falls below `availablePercent` of the
4
+ * sandbox's RAM, commit rises above `commitPercent` of its limit, or (from step 3) the commit would reach its limit
5
+ * within `secondsToLimit` at the rate it is growing. It turns down one step after `calmSamples` samples in a row that
6
+ * are clear of the step by the margins below.
7
+ */
8
+ export interface DialStep {
9
+ readonly availablePercent: number;
10
+ readonly commitPercent: number;
11
+ readonly secondsToLimit?: number;
12
12
  }
13
- export declare const GUEST_THRESHOLDS: Readonly<Record<LoadProfile, GuestThresholds>>;
13
+ /** Steps 1 to 4 of the dial, per profile (index 0 is step 1). The gentle profile (vGPU on) turns earlier. */
14
+ export declare const DIAL_STEPS: Readonly<Record<LoadProfile, readonly DialStep[]>>;
15
+ /** How clear of a step a sample must be to count as calm: this much more RAM free and this much less commit. */
16
+ export declare const DIAL_EXIT_MARGIN: {
17
+ readonly availablePercent: 5;
18
+ readonly commitPercent: 4;
19
+ };
20
+ export declare const DIAL_CALM_SAMPLES = 3;
21
+ /** The CPU share (percent of the sandbox) the compilers get together at each step; 100 = no cap. */
22
+ export declare const DIAL_CPU_RATE: readonly number[];
23
+ /** How many of the compilers running may go on at each step (the rest wait their turn), as a share of them. */
24
+ export declare function compilersAllowed(step: number, running: number): number;
14
25
  /** The PC watchdog: when this PC itself is low. */
15
26
  export interface HostThresholds {
16
27
  /** Low when available RAM is below max(this, availableShare of total RAM)... */
@@ -23,11 +34,26 @@ export interface HostThresholds {
23
34
  /** Total CPU above this (percent) for cpuSeconds. */
24
35
  readonly cpuPercent: number;
25
36
  readonly cpuSeconds: number;
37
+ /** The disks' queue length (all together) at or above this for diskSeconds: builds writing through mapped folders. */
38
+ readonly diskQueue: number;
39
+ readonly diskSeconds: number;
26
40
  }
27
41
  export declare const HOST_THRESHOLDS: Readonly<Record<LoadProfile, HostThresholds>>;
28
42
  /** The CPU cap (percent of the PC) the gentle profile uses: 15 points lower, never below 50. "none" = 100. */
29
43
  export declare function gentleCpuLimit(cpuLimit: 'none' | number): number;
30
44
  /** The CPU cap the sandbox runs with (percent; null = none) for a profile. */
31
45
  export declare function effectiveCpuLimit(cpuLimit: 'none' | number, profile: LoadProfile): number | null;
32
- /** Cargo jobs that fit the memory (about 4 GB per rustc) and the CPUs, fewer when several agent sessions build. */
46
+ /**
47
+ * The build budget of the whole sandbox: how many compile jobs fit together (about 3 GB each after 6 GB for Windows,
48
+ * the agents and their tools), never more than the processors the sandbox may use. The governor slows them down when
49
+ * memory runs short anyway; this keeps builds from starting far more than fits.
50
+ */
51
+ export declare function buildJobs(cpus: number, memoryGb: number): number;
52
+ /** Links that may run at once in the whole sandbox ("auto"): one per 3 GB after 6 GB, 2 to 8. */
53
+ export declare function linkSlotsFor(memoryGb: number): number;
54
+ /** The processors the sandbox's programs may use with a CPU cap of `percent` (affinity): at least 2. */
55
+ export declare function usableCpus(cpus: number, percent: number | null): number;
56
+ /** Cargo jobs for one more agent session: what fits the memory and CPUs, shared with the sessions already building. */
33
57
  export declare function cargoJobs(cpus: number, memoryGb: number, sessions: number): number;
58
+ /** The most heavy compilers (rustc, clippy-driver, link ...) that run at once in the agents' job: only with vGPU on. */
59
+ export declare function maxCompilers(cpus: number, profile: LoadProfile): number | null;
@@ -1,22 +1,36 @@
1
1
  // What "heavy load" means, decided once for the host watchdog and the guest governor (pure, no I/O). Every
2
2
  // protection is on by default; the gentle profile (vGPU on: a graphics driver hang can freeze the whole PC) triggers
3
3
  // earlier and runs the sandbox with less CPU.
4
- export const GUEST_THRESHOLDS = {
5
- normal: {
6
- enterAvailablePercent: 8,
7
- enterCommitPercent: 92,
8
- exitAvailablePercent: 12,
9
- exitCommitPercent: 88,
10
- calmSamples: 3,
11
- },
12
- gentle: {
13
- enterAvailablePercent: 15,
14
- enterCommitPercent: 85,
15
- exitAvailablePercent: 20,
16
- exitCommitPercent: 80,
17
- calmSamples: 3,
18
- },
4
+ /** Steps 1 to 4 of the dial, per profile (index 0 is step 1). The gentle profile (vGPU on) turns earlier. */
5
+ export const DIAL_STEPS = {
6
+ normal: [
7
+ { availablePercent: 15, commitPercent: 80 },
8
+ { availablePercent: 10, commitPercent: 88 },
9
+ { availablePercent: 6, commitPercent: 94, secondsToLimit: 20 },
10
+ { availablePercent: 4, commitPercent: 97, secondsToLimit: 8 },
11
+ ],
12
+ gentle: [
13
+ { availablePercent: 20, commitPercent: 75 },
14
+ { availablePercent: 15, commitPercent: 85 },
15
+ { availablePercent: 8, commitPercent: 92, secondsToLimit: 25 },
16
+ { availablePercent: 5, commitPercent: 96, secondsToLimit: 10 },
17
+ ],
19
18
  };
19
+ /** How clear of a step a sample must be to count as calm: this much more RAM free and this much less commit. */
20
+ export const DIAL_EXIT_MARGIN = { availablePercent: 5, commitPercent: 4 };
21
+ export const DIAL_CALM_SAMPLES = 3;
22
+ /** The CPU share (percent of the sandbox) the compilers get together at each step; 100 = no cap. */
23
+ export const DIAL_CPU_RATE = [100, 100, 60, 35, 15];
24
+ /** How many of the compilers running may go on at each step (the rest wait their turn), as a share of them. */
25
+ export function compilersAllowed(step, running) {
26
+ if (step <= 1 || running <= 1)
27
+ return running;
28
+ if (step === 2)
29
+ return Math.max(1, Math.ceil(running * 0.6));
30
+ if (step === 3)
31
+ return Math.max(1, Math.ceil(running / 3));
32
+ return 1;
33
+ }
20
34
  export const HOST_THRESHOLDS = {
21
35
  normal: {
22
36
  availableMinMb: 4096,
@@ -25,6 +39,8 @@ export const HOST_THRESHOLDS = {
25
39
  calmSamples: 3,
26
40
  cpuPercent: 95,
27
41
  cpuSeconds: 60,
42
+ diskQueue: 32,
43
+ diskSeconds: 40,
28
44
  },
29
45
  gentle: {
30
46
  availableMinMb: 6144,
@@ -33,6 +49,8 @@ export const HOST_THRESHOLDS = {
33
49
  calmSamples: 3,
34
50
  cpuPercent: 90,
35
51
  cpuSeconds: 45,
52
+ diskQueue: 16,
53
+ diskSeconds: 30,
36
54
  },
37
55
  };
38
56
  /** The CPU cap (percent of the PC) the gentle profile uses: 15 points lower, never below 50. "none" = 100. */
@@ -45,11 +63,32 @@ export function effectiveCpuLimit(cpuLimit, profile) {
45
63
  return Math.min(gentleCpuLimit(cpuLimit), cpuLimit === 'none' ? 100 : cpuLimit);
46
64
  return cpuLimit === 'none' ? null : cpuLimit;
47
65
  }
48
- /** Cargo jobs that fit the memory (about 4 GB per rustc) and the CPUs, fewer when several agent sessions build. */
66
+ /**
67
+ * The build budget of the whole sandbox: how many compile jobs fit together (about 3 GB each after 6 GB for Windows,
68
+ * the agents and their tools), never more than the processors the sandbox may use. The governor slows them down when
69
+ * memory runs short anyway; this keeps builds from starting far more than fits.
70
+ */
71
+ export function buildJobs(cpus, memoryGb) {
72
+ return Math.max(2, Math.min(cpus, Math.floor((memoryGb - 6) / 3)));
73
+ }
74
+ /** Links that may run at once in the whole sandbox ("auto"): one per 3 GB after 6 GB, 2 to 8. */
75
+ export function linkSlotsFor(memoryGb) {
76
+ return Math.max(2, Math.min(8, Math.floor((memoryGb - 6) / 3)));
77
+ }
78
+ /** The processors the sandbox's programs may use with a CPU cap of `percent` (affinity): at least 2. */
79
+ export function usableCpus(cpus, percent) {
80
+ if (percent === null || percent >= 100)
81
+ return cpus;
82
+ return Math.max(2, Math.min(cpus, Math.floor((cpus * percent) / 100)));
83
+ }
84
+ /** Cargo jobs for one more agent session: what fits the memory and CPUs, shared with the sessions already building. */
49
85
  export function cargoJobs(cpus, memoryGb, sessions) {
50
- const byCpu = Math.max(2, Math.min(4, Math.floor(cpus / 4)));
86
+ const byCpu = Math.max(2, Math.min(8, Math.floor(cpus / 4)));
51
87
  const byMemory = Math.max(1, Math.floor(memoryGb / 4));
52
88
  const jobs = Math.min(byCpu, byMemory);
53
- // All the agents' builds share the sandbox: about 8 jobs in total however many sessions there are.
54
- return Math.max(1, Math.min(jobs, Math.floor(8 / Math.max(1, sessions))));
89
+ return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions))));
90
+ }
91
+ /** The most heavy compilers (rustc, clippy-driver, link ...) that run at once in the agents' job: only with vGPU on. */
92
+ export function maxCompilers(cpus, profile) {
93
+ return profile === 'gentle' ? Math.max(2, Math.floor(cpus / 4)) : null;
55
94
  }
@@ -22,3 +22,11 @@ export declare function parseDnsServers(ipconfigAll: string): string[];
22
22
  * keeps working.
23
23
  */
24
24
  export declare function buildFirewallCommands(exemptIps: string[]): string[][];
25
+ export declare const ATTACH_RULE = "AgentSandbox-Attach";
26
+ /**
27
+ * True when a Windows path has an 8.3 short name in it (`C:\Users\WDAGUT~1\...`). netsh refuses `program=` paths
28
+ * like that ("The application name could not be resolved"), so they are expanded first.
29
+ */
30
+ export declare function hasShortName(file: string): boolean;
31
+ /** Inbound rule for ptyhost only, and only from the sandbox's own subnet (where the host's Hyper-V adapter is). */
32
+ export declare function attachRuleCommands(ptyHostExe: string): string[][];
@@ -135,3 +135,31 @@ export function buildFirewallCommands(exemptIps) {
135
135
  }
136
136
  return commands;
137
137
  }
138
+ export const ATTACH_RULE = 'AgentSandbox-Attach';
139
+ /**
140
+ * True when a Windows path has an 8.3 short name in it (`C:\Users\WDAGUT~1\...`). netsh refuses `program=` paths
141
+ * like that ("The application name could not be resolved"), so they are expanded first.
142
+ */
143
+ export function hasShortName(file) {
144
+ return file.split(/[/\\]/).some((part) => /~\d/.test(part));
145
+ }
146
+ /** Inbound rule for ptyhost only, and only from the sandbox's own subnet (where the host's Hyper-V adapter is). */
147
+ export function attachRuleCommands(ptyHostExe) {
148
+ return [
149
+ ['advfirewall', 'firewall', 'delete', 'rule', 'name=' + ATTACH_RULE],
150
+ [
151
+ 'advfirewall',
152
+ 'firewall',
153
+ 'add',
154
+ 'rule',
155
+ 'name=' + ATTACH_RULE,
156
+ 'dir=in',
157
+ 'action=allow',
158
+ 'enable=yes',
159
+ 'profile=any',
160
+ 'protocol=tcp',
161
+ 'remoteip=LocalSubnet',
162
+ 'program=' + ptyHostExe,
163
+ ],
164
+ ];
165
+ }
@@ -0,0 +1,18 @@
1
+ /** A second Ctrl+C within this long sends it. */
2
+ export declare const CTRL_C_CONFIRM_MS = 1500;
3
+ /** What the title shows while a Ctrl+C is held back. */
4
+ export declare const CTRL_C_HINT = "Ctrl+C again to send it to the program (Esc stops an agent)";
5
+ export declare class CtrlCGuard {
6
+ private armedAt;
7
+ private lastTitle;
8
+ /** What to send for one read from the keyboard: a lone Ctrl+C only when another came just before. */
9
+ push(chunk: Buffer, nowMs: number): {
10
+ send: Buffer;
11
+ held: boolean;
12
+ };
13
+ /** Remembers the title the program last set (from its output), to put it back after the hint. */
14
+ watchOutput(text: string): void;
15
+ /** The escape sequence that shows the hint, and the one that puts the program's title back. */
16
+ hintTitle(): string;
17
+ restoreTitle(): string;
18
+ }
@@ -0,0 +1,36 @@
1
+ // A lone Ctrl+C is easy to send by accident: it is "copy" everywhere else, and a terminal sends it to the program when
2
+ // the selection it was meant for has just been cleared by a redraw (an agent's spinner redraws all the time). With
3
+ // attach.confirmCtrlC the terminal client holds a lone Ctrl+C back until it is pressed again within a moment; Esc still
4
+ // stops an agent at once. Pure, so it is tested without a terminal.
5
+ /** A second Ctrl+C within this long sends it. */
6
+ export const CTRL_C_CONFIRM_MS = 1500;
7
+ /** What the title shows while a Ctrl+C is held back. */
8
+ export const CTRL_C_HINT = 'Ctrl+C again to send it to the program (Esc stops an agent)';
9
+ const OSC_TITLE = /\x1b\][02];([^\x07\x1b]{0,256})(?:\x07|\x1b\\)/g;
10
+ export class CtrlCGuard {
11
+ armedAt = Number.NEGATIVE_INFINITY;
12
+ lastTitle = '';
13
+ /** What to send for one read from the keyboard: a lone Ctrl+C only when another came just before. */
14
+ push(chunk, nowMs) {
15
+ if (chunk.length !== 1 || chunk[0] !== 0x03)
16
+ return { send: chunk, held: false };
17
+ if (nowMs - this.armedAt <= CTRL_C_CONFIRM_MS) {
18
+ this.armedAt = Number.NEGATIVE_INFINITY;
19
+ return { send: chunk, held: false };
20
+ }
21
+ this.armedAt = nowMs;
22
+ return { send: Buffer.alloc(0), held: true };
23
+ }
24
+ /** Remembers the title the program last set (from its output), to put it back after the hint. */
25
+ watchOutput(text) {
26
+ for (const m of text.matchAll(OSC_TITLE))
27
+ this.lastTitle = m[1];
28
+ }
29
+ /** The escape sequence that shows the hint, and the one that puts the program's title back. */
30
+ hintTitle() {
31
+ return '\x1b]0;' + CTRL_C_HINT + '\x07';
32
+ }
33
+ restoreTitle() {
34
+ return '\x1b]0;' + this.lastTitle.replace(/[\x00-\x1f\x7f]/g, '') + '\x07';
35
+ }
36
+ }
@@ -2,5 +2,6 @@ export { FrameType, HelloFlag, PING_INTERVAL_MS, type Frame, DETACH_KEY, encodeF
2
2
  export { type Endpoint, connect, sendControl, type Viewers, queryViewers } from './client.js';
3
3
  export { type ClientResult, MOUSE_OFF, fixWindowsKeys, runTerminalClient } from './terminal.js';
4
4
  export { JOIN_MS, InputJoiner } from './input-joiner.js';
5
+ export { CTRL_C_CONFIRM_MS, CTRL_C_HINT, CtrlCGuard } from './ctrl-c.js';
5
6
  export { type VtInput, enableVtInput } from './console-input.js';
6
7
  export { OutputFilter } from './output-filter.js';
@@ -2,5 +2,6 @@ export { FrameType, HelloFlag, PING_INTERVAL_MS, DETACH_KEY, encodeFrame, helloF
2
2
  export { connect, sendControl, queryViewers } from './client.js';
3
3
  export { MOUSE_OFF, fixWindowsKeys, runTerminalClient } from './terminal.js';
4
4
  export { JOIN_MS, InputJoiner } from './input-joiner.js';
5
+ export { CTRL_C_CONFIRM_MS, CTRL_C_HINT, CtrlCGuard } from './ctrl-c.js';
5
6
  export { enableVtInput } from './console-input.js';
6
7
  export { OutputFilter } from './output-filter.js';
@@ -24,7 +24,9 @@ export declare function fixWindowsKeys(chunk: Buffer): Buffer;
24
24
  */
25
25
  export declare function runTerminalClient(socket: net.Socket, token: string,
26
26
  /** clipboardWrites: the agent's "copy" (OSC 52) reaches the clipboard; see OutputFilterOptions. */
27
+ /** confirmCtrlC: a lone Ctrl+C is held back until it is pressed again (CtrlCGuard, attach.confirmCtrlC). */
27
28
  options?: {
28
29
  detachKey?: number;
29
30
  clipboardWrites?: boolean;
31
+ confirmCtrlC?: boolean;
30
32
  }): Promise<ClientResult>;
@@ -2,6 +2,7 @@ import { FrameReader, encodeFrame, FrameType, resizeFrame, PING_INTERVAL_MS, hel
2
2
  import { OutputFilter } from './output-filter.js';
3
3
  import { enableVtInput } from './console-input.js';
4
4
  import { InputJoiner, JOIN_MS } from './input-joiner.js';
5
+ import { CTRL_C_CONFIRM_MS, CtrlCGuard } from './ctrl-c.js';
5
6
  /**
6
7
  * Turns off every mouse tracking mode a program may have turned on in your terminal (normal, button, any, UTF-8, SGR,
7
8
  * urxvt).
@@ -22,6 +23,7 @@ export function fixWindowsKeys(chunk) {
22
23
  */
23
24
  export function runTerminalClient(socket, token,
24
25
  /** clipboardWrites: the agent's "copy" (OSC 52) reaches the clipboard; see OutputFilterOptions. */
26
+ /** confirmCtrlC: a lone Ctrl+C is held back until it is pressed again (CtrlCGuard, attach.confirmCtrlC). */
25
27
  options = {}) {
26
28
  const stdin = process.stdin;
27
29
  const stdout = process.stdout;
@@ -51,6 +53,7 @@ options = {}) {
51
53
  clearInterval(heartbeat);
52
54
  clearInterval(sizeWatch);
53
55
  clearTimeout(joinTimer);
56
+ clearTimeout(hintTimer);
54
57
  socket.destroy();
55
58
  // The agent's mouse tracking ends with it: your terminal's wheel scrolls again (and clicks select text).
56
59
  stdout.write('\x1b[0m\x1b[?25h' + MOUSE_OFF + '\r\n');
@@ -68,11 +71,24 @@ options = {}) {
68
71
  if (data.length && !done)
69
72
  socket.write(encodeFrame(FrameType.Input, swapKeys ? fixWindowsKeys(data) : data));
70
73
  };
74
+ const guard = options.confirmCtrlC ? new CtrlCGuard() : null;
75
+ let hintTimer;
71
76
  const onInput = (chunk) => {
72
77
  if (options.detachKey !== undefined && chunk.includes(options.detachKey)) {
73
78
  finish({ reason: 'detach' });
74
79
  return;
75
80
  }
81
+ if (guard) {
82
+ const decided = guard.push(chunk, Date.now());
83
+ clearTimeout(hintTimer);
84
+ if (decided.held) {
85
+ stdout.write(guard.hintTitle());
86
+ hintTimer = setTimeout(() => stdout.write(guard.restoreTitle()), CTRL_C_CONFIRM_MS);
87
+ return;
88
+ }
89
+ if (decided.send.length === 1 && decided.send[0] === 0x03)
90
+ stdout.write(guard.restoreTitle());
91
+ }
76
92
  clearTimeout(joinTimer);
77
93
  sendInput(joiner.push(chunk));
78
94
  // A lone Esc key press is a "sequence" that never completes: send it after a moment.
@@ -116,8 +132,11 @@ options = {}) {
116
132
  return;
117
133
  }
118
134
  for (const frame of frames) {
119
- if (frame.type === FrameType.Output)
120
- stdout.write(filter.push(frame.payload));
135
+ if (frame.type === FrameType.Output) {
136
+ const out = filter.push(frame.payload);
137
+ guard?.watchOutput(out.toString('latin1'));
138
+ stdout.write(out);
139
+ }
121
140
  else if (frame.type === FrameType.Console)
122
141
  passthrough = frame.payload.toString('latin1') === 'conpty.dll';
123
142
  else if (frame.type === FrameType.Restarting)
@@ -6,11 +6,22 @@ export interface KillSwitchServer {
6
6
  }
7
7
  /** The rule names phase 1 and 2 may create (the servers get a number each). */
8
8
  export declare function ruleNames(serverCount: number): string[];
9
+ /** Every IPv4 address except the given ranges, as a netsh address list ("a-b,c-d"). */
10
+ export declare function ipv4Except(excluded: readonly (readonly [number, number])[]): string;
11
+ /** The internet's IPv4 addresses without the VPN servers: what the kill switch blocks. */
12
+ export declare function internetExcept(servers: readonly KillSwitchServer[]): string;
9
13
  /** Servers worth a rule: valid IPv4 addresses and ports, each endpoint once. */
10
14
  export declare function cleanServers(servers: readonly KillSwitchServer[]): KillSwitchServer[];
11
- /** Phase 1: block everything that goes out, then allow only what the tunnel and the attach channel need. */
15
+ /**
16
+ * Phase 1: the block rules first (they hold whatever else allows), then outbound blocked by default, then what the
17
+ * tunnel and the attach channel need. `ptyHostExe` must be the long form of the path (netsh refuses 8.3 names).
18
+ */
12
19
  export declare function killSwitchCommands(servers: readonly KillSwitchServer[], ptyHostExe: string | null): string[][];
13
- /** Phase 2: everything that leaves from the tunnel's own address goes (it is inside the tunnel). */
20
+ /**
21
+ * Phase 2: everything that leaves from the tunnel's own address goes (it is inside the tunnel). The IPv4 block rules
22
+ * are changed in place to every other local address, so they never stop applying to the normal connection. Global
23
+ * IPv6 stays blocked (the tunnel is IPv4).
24
+ */
14
25
  export declare function tunnelCommands(tunnelIp: string): string[][];
15
26
  /** Takes the kill switch away again: its rules go and outbound traffic is allowed by default as before. */
16
27
  export declare function removeKillSwitchCommands(): string[][];
@@ -1,8 +1,9 @@
1
- // The kill switch as netsh argument lists (pure, so it is tested without a firewall). Phase 1 runs BEFORE the tunnel
2
- // starts: everything that goes out is blocked except loopback, the VPN servers themselves, DHCP and the host's attach
3
- // channel. Phase 2 runs once the tunnel is up: traffic from the tunnel's own address is allowed, which is everything
4
- // that goes through the tunnel (DNS included). Windows keeps the block rules for private ranges
5
- // (network.blockPrivateRanges) on top of this: a block rule always beats an allow rule.
1
+ // The kill switch as netsh argument lists (pure, so it is tested without a firewall). Windows Sandbox has its own
2
+ // "Container: allow outbound" rule (any program, any address), so blocking outbound by default alone stops nothing:
3
+ // the kill switch is made of BLOCK rules, which beat every allow rule. Phase 1 runs BEFORE the tunnel starts: every
4
+ // public IPv4 address except the VPN servers, global IPv6 and DNS are blocked (private ranges are the LAN block's).
5
+ // Phase 2 runs once the tunnel is up: the same block rules are narrowed in place (`set rule`, never a moment without
6
+ // them) to every local address except the tunnel's own, so what goes through the tunnel (DNS included) passes.
6
7
  import { isIPv4 } from '../network/firewall-rules.js';
7
8
  export const VPN_RULE_PREFIX = 'AgentSandbox-VPN-';
8
9
  const rule = (name, extra) => [
@@ -24,9 +25,24 @@ const drop = (name) => [
24
25
  'rule',
25
26
  'name=' + VPN_RULE_PREFIX + name,
26
27
  ];
28
+ const block = (name, extra) => [
29
+ 'advfirewall',
30
+ 'firewall',
31
+ 'add',
32
+ 'rule',
33
+ 'name=' + VPN_RULE_PREFIX + name,
34
+ 'dir=out',
35
+ 'action=block',
36
+ 'enable=yes',
37
+ 'profile=any',
38
+ ...extra,
39
+ ];
40
+ /** The block rules: IPv4 to the internet, global IPv6, and DNS anywhere (over udp and tcp). */
41
+ const BLOCK_RULES = ['Block-Internet', 'Block-IPv6', 'Block-DNS-UDP', 'Block-DNS-TCP'];
27
42
  /** The rule names phase 1 and 2 may create (the servers get a number each). */
28
43
  export function ruleNames(serverCount) {
29
44
  return [
45
+ ...BLOCK_RULES,
30
46
  'Loopback',
31
47
  'DHCP',
32
48
  'Host',
@@ -34,6 +50,45 @@ export function ruleNames(serverCount) {
34
50
  ...Array.from({ length: Math.max(serverCount, 0) }, (_v, i) => 'Server-' + (i + 1)),
35
51
  ];
36
52
  }
53
+ /** IPv4 ranges that are not the internet (this host, private, shared, link-local, multicast, reserved, broadcast). */
54
+ const NOT_INTERNET = [
55
+ ['0.0.0.0', '0.255.255.255'],
56
+ ['10.0.0.0', '10.255.255.255'],
57
+ ['100.64.0.0', '100.127.255.255'],
58
+ ['127.0.0.0', '127.255.255.255'],
59
+ ['169.254.0.0', '169.254.255.255'],
60
+ ['172.16.0.0', '172.31.255.255'],
61
+ ['192.168.0.0', '192.168.255.255'],
62
+ ['224.0.0.0', '255.255.255.255'],
63
+ ];
64
+ const LAST_IPV4 = 0xffffffff;
65
+ function ipNumber(ip) {
66
+ return ip.split('.').reduce((n, part) => n * 256 + Number(part), 0);
67
+ }
68
+ function ipText(n) {
69
+ return [24, 16, 8, 0].map((shift) => Math.floor(n / 2 ** shift) % 256).join('.');
70
+ }
71
+ /** Every IPv4 address except the given ranges, as a netsh address list ("a-b,c-d"). */
72
+ export function ipv4Except(excluded) {
73
+ const sorted = [...excluded].sort((a, b) => a[0] - b[0]);
74
+ const out = [];
75
+ let next = 0;
76
+ for (const [from, to] of sorted) {
77
+ if (from > next)
78
+ out.push(ipText(next) + '-' + ipText(from - 1));
79
+ next = Math.max(next, to + 1);
80
+ }
81
+ if (next <= LAST_IPV4)
82
+ out.push(ipText(next) + '-' + ipText(LAST_IPV4));
83
+ return out.join(',');
84
+ }
85
+ /** The internet's IPv4 addresses without the VPN servers: what the kill switch blocks. */
86
+ export function internetExcept(servers) {
87
+ const ranges = NOT_INTERNET.map(([a, b]) => [ipNumber(a), ipNumber(b)]);
88
+ for (const s of cleanServers(servers))
89
+ ranges.push([ipNumber(s.ip), ipNumber(s.ip)]);
90
+ return ipv4Except(ranges);
91
+ }
37
92
  /** Servers worth a rule: valid IPv4 addresses and ports, each endpoint once. */
38
93
  export function cleanServers(servers) {
39
94
  const seen = new Set();
@@ -45,12 +100,19 @@ export function cleanServers(servers) {
45
100
  return true;
46
101
  });
47
102
  }
48
- /** Phase 1: block everything that goes out, then allow only what the tunnel and the attach channel need. */
103
+ /**
104
+ * Phase 1: the block rules first (they hold whatever else allows), then outbound blocked by default, then what the
105
+ * tunnel and the attach channel need. `ptyHostExe` must be the long form of the path (netsh refuses 8.3 names).
106
+ */
49
107
  export function killSwitchCommands(servers, ptyHostExe) {
50
108
  const list = cleanServers(servers);
51
109
  return [
52
110
  ...ruleNames(Math.max(list.length, 8)).map(drop),
53
111
  ['advfirewall', 'set', 'allprofiles', 'state', 'on'],
112
+ block('Block-Internet', ['protocol=any', 'remoteip=' + internetExcept(list)]),
113
+ block('Block-IPv6', ['protocol=any', 'remoteip=2000::/3']),
114
+ block('Block-DNS-UDP', ['protocol=udp', 'remoteport=53']),
115
+ block('Block-DNS-TCP', ['protocol=tcp', 'remoteport=53']),
54
116
  ['advfirewall', 'set', 'allprofiles', 'firewallpolicy', 'blockinbound,blockoutbound'],
55
117
  rule('Loopback', ['protocol=any', 'remoteip=127.0.0.0/8']),
56
118
  rule('DHCP', ['protocol=udp', 'localport=68', 'remoteport=67']),
@@ -58,11 +120,29 @@ export function killSwitchCommands(servers, ptyHostExe) {
58
120
  ...list.map((s, i) => rule('Server-' + (i + 1), ['protocol=' + s.proto, 'remoteip=' + s.ip, 'remoteport=' + s.port])),
59
121
  ];
60
122
  }
61
- /** Phase 2: everything that leaves from the tunnel's own address goes (it is inside the tunnel). */
123
+ /**
124
+ * Phase 2: everything that leaves from the tunnel's own address goes (it is inside the tunnel). The IPv4 block rules
125
+ * are changed in place to every other local address, so they never stop applying to the normal connection. Global
126
+ * IPv6 stays blocked (the tunnel is IPv4).
127
+ */
62
128
  export function tunnelCommands(tunnelIp) {
63
129
  if (!isIPv4(tunnelIp))
64
130
  throw new Error('Not an IPv4 address: ' + tunnelIp);
65
- return [drop('Tunnel'), rule('Tunnel', ['protocol=any', 'localip=' + tunnelIp])];
131
+ const n = ipNumber(tunnelIp);
132
+ const notTunnel = ipv4Except([[n, n]]);
133
+ return [
134
+ ...['Block-Internet', 'Block-DNS-UDP', 'Block-DNS-TCP'].map((name) => [
135
+ 'advfirewall',
136
+ 'firewall',
137
+ 'set',
138
+ 'rule',
139
+ 'name=' + VPN_RULE_PREFIX + name,
140
+ 'new',
141
+ 'localip=' + notTunnel,
142
+ ]),
143
+ drop('Tunnel'),
144
+ rule('Tunnel', ['protocol=any', 'localip=' + tunnelIp]),
145
+ ];
66
146
  }
67
147
  /** Takes the kill switch away again: its rules go and outbound traffic is allowed by default as before. */
68
148
  export function removeKillSwitchCommands() {
@@ -29,10 +29,6 @@ export interface WebInfo {
29
29
  readonly defaultHarness: string;
30
30
  readonly projects: readonly WebProject[];
31
31
  }
32
- export interface NewSessionRequest {
33
- readonly harness: string;
34
- readonly project: string;
35
- }
36
32
  /** Browser -> server on the terminal socket: binary messages are keystrokes; text messages are these (JSON). */
37
33
  export type ClientMessage = {
38
34
  readonly t: 'resize';
@@ -243,7 +243,7 @@ export class Watcher {
243
243
  ? 'this PC is low (' + step.reason + '): asking the sandbox to slow its builds down'
244
244
  : 'this PC has recovered: no longer asking the sandbox to slow down');
245
245
  if (step.send)
246
- new SandboxChannel(this.dataPath).pressure(step.reason, REQUEST_SECONDS);
246
+ new SandboxChannel(this.dataPath).pressure(step.reason, REQUEST_SECONDS, step.severe ? 'severe' : 'slow');
247
247
  }
248
248
  catch (e) {
249
249
  this.note('host watchdog: ' + errMsg(e));
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>Sandbox</title>
7
7
  <link rel="icon" href="data:," />
8
- <link rel="stylesheet" href="/main-T5DMCHYV.css" />
9
- <script type="module" src="/main-NRRS5O6Z.js"></script>
8
+ <link rel="stylesheet" href="/main-6JF3ASB5.css" />
9
+ <script type="module" src="/main-Z645W45E.js"></script>
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>