windows-development-sandbox 1.10.0 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +64 -17
  2. package/config.example.json +5 -1
  3. package/dist/app/features/accounts/accounts.def.d.ts +122 -0
  4. package/dist/app/features/accounts/accounts.def.js +243 -0
  5. package/dist/app/features/accounts/accounts.run.d.ts +51 -0
  6. package/dist/app/features/accounts/accounts.run.js +125 -0
  7. package/dist/app/features/accounts/index.d.ts +2 -0
  8. package/dist/app/features/accounts/index.js +3 -0
  9. package/dist/app/features/agents/agent-entry.d.ts +17 -0
  10. package/dist/app/features/agents/agent-entry.js +50 -0
  11. package/dist/app/features/agents/agents.def.d.ts +65 -0
  12. package/dist/app/features/agents/agents.def.js +142 -0
  13. package/dist/app/features/agents/agents.run.d.ts +31 -0
  14. package/dist/app/features/agents/agents.run.js +189 -0
  15. package/dist/app/features/agents/index.d.ts +3 -0
  16. package/dist/app/features/agents/index.js +4 -0
  17. package/dist/app/features/apps/apps-rows.d.ts +31 -0
  18. package/dist/app/features/apps/apps-rows.js +73 -0
  19. package/dist/app/features/apps/apps.def.d.ts +181 -0
  20. package/dist/app/features/apps/apps.def.js +264 -0
  21. package/dist/app/features/apps/apps.run.d.ts +58 -0
  22. package/dist/app/features/apps/apps.run.js +76 -0
  23. package/dist/app/features/apps/index.d.ts +3 -0
  24. package/dist/app/features/apps/index.js +4 -0
  25. package/dist/app/features/data/data.def.d.ts +154 -0
  26. package/dist/app/features/data/data.def.js +201 -0
  27. package/dist/app/features/data/data.run.d.ts +46 -0
  28. package/dist/app/features/data/data.run.js +141 -0
  29. package/dist/app/features/data/index.d.ts +2 -0
  30. package/dist/app/features/data/index.js +3 -0
  31. package/dist/app/features/defs.d.ts +952 -4
  32. package/dist/app/features/defs.js +147 -10
  33. package/dist/app/features/engine/engine.def.d.ts +228 -0
  34. package/dist/app/features/engine/engine.def.js +194 -0
  35. package/dist/app/features/engine/engine.run.d.ts +72 -0
  36. package/dist/app/features/engine/engine.run.js +77 -0
  37. package/dist/app/features/engine/index.d.ts +2 -0
  38. package/dist/app/features/engine/index.js +4 -0
  39. package/dist/app/features/files/files.def.d.ts +51 -0
  40. package/dist/app/features/files/files.def.js +38 -0
  41. package/dist/app/features/files/files.run.d.ts +20 -0
  42. package/dist/app/features/files/files.run.js +59 -0
  43. package/dist/app/features/files/index.d.ts +2 -0
  44. package/dist/app/features/files/index.js +3 -0
  45. package/dist/app/features/github/github.def.d.ts +80 -0
  46. package/dist/app/features/github/github.def.js +142 -0
  47. package/dist/app/features/github/github.run.d.ts +36 -0
  48. package/dist/app/features/github/github.run.js +59 -0
  49. package/dist/app/features/github/index.d.ts +2 -0
  50. package/dist/app/features/github/index.js +3 -0
  51. package/dist/app/features/health/health.def.d.ts +275 -0
  52. package/dist/app/features/health/health.def.js +281 -0
  53. package/dist/app/features/health/health.run.d.ts +125 -0
  54. package/dist/app/features/health/health.run.js +204 -0
  55. package/dist/app/features/health/index.d.ts +2 -0
  56. package/dist/app/features/health/index.js +3 -0
  57. package/dist/app/features/logs/index.d.ts +2 -0
  58. package/dist/app/features/logs/index.js +3 -0
  59. package/dist/app/features/logs/logs.def.d.ts +78 -0
  60. package/dist/app/features/logs/logs.def.js +115 -0
  61. package/dist/app/features/logs/logs.run.d.ts +20 -0
  62. package/dist/app/features/logs/logs.run.js +42 -0
  63. package/dist/app/features/projects/index.d.ts +2 -0
  64. package/dist/app/features/projects/index.js +3 -0
  65. package/dist/app/features/projects/projects.def.d.ts +101 -0
  66. package/dist/app/features/projects/projects.def.js +208 -0
  67. package/dist/app/features/projects/projects.run.d.ts +56 -0
  68. package/dist/app/features/projects/projects.run.js +155 -0
  69. package/dist/app/features/sandbox/sandbox.def.js +11 -5
  70. package/dist/app/features/sessions/sessions.def.js +3 -0
  71. package/dist/app/features/settings/categories.def.js +3 -2
  72. package/dist/{cli/menu/settings/share.d.ts → app/features/settings/settings-share.d.ts} +1 -1
  73. package/dist/{cli/menu/settings/share.js → app/features/settings/settings-share.js} +3 -2
  74. package/dist/app/features/settings/settings.def.d.ts +22 -5
  75. package/dist/app/features/settings/settings.def.js +81 -6
  76. package/dist/app/features/settings/settings.run.d.ts +17 -0
  77. package/dist/app/features/settings/settings.run.js +89 -4
  78. package/dist/app/features/storage/index.d.ts +2 -0
  79. package/dist/app/features/storage/index.js +3 -0
  80. package/dist/app/features/storage/storage.def.d.ts +133 -0
  81. package/dist/app/features/storage/storage.def.js +225 -0
  82. package/dist/app/features/storage/storage.run.d.ts +62 -0
  83. package/dist/app/features/storage/storage.run.js +370 -0
  84. package/dist/app/features/updates/index.d.ts +3 -0
  85. package/dist/app/features/updates/index.js +4 -0
  86. package/dist/app/features/updates/update-lines.d.ts +13 -0
  87. package/dist/app/features/updates/update-lines.js +61 -0
  88. package/dist/app/features/updates/updates.def.d.ts +89 -0
  89. package/dist/app/features/updates/updates.def.js +225 -0
  90. package/dist/app/features/updates/updates.run.d.ts +48 -0
  91. package/dist/app/features/updates/updates.run.js +154 -0
  92. package/dist/app/features/vpn/index.d.ts +2 -0
  93. package/dist/app/features/vpn/index.js +3 -0
  94. package/dist/app/features/vpn/vpn.def.d.ts +112 -0
  95. package/dist/app/features/vpn/vpn.def.js +174 -0
  96. package/dist/app/features/vpn/vpn.run.d.ts +37 -0
  97. package/dist/app/features/vpn/vpn.run.js +54 -0
  98. package/dist/app/features/web/index.d.ts +2 -0
  99. package/dist/app/features/web/index.js +3 -0
  100. package/dist/app/features/web/web.def.d.ts +33 -0
  101. package/dist/app/features/web/web.def.js +90 -0
  102. package/dist/app/features/web/web.run.d.ts +24 -0
  103. package/dist/app/features/web/web.run.js +93 -0
  104. package/dist/app/kernel/define.d.ts +10 -1
  105. package/dist/app/kernel/io.d.ts +34 -0
  106. package/dist/app/kernel/io.js +9 -0
  107. package/dist/app/kernel/rpc.d.ts +17 -0
  108. package/dist/app/kernel/text.d.ts +2 -0
  109. package/dist/app/kernel/text.js +7 -0
  110. package/dist/app/kernel/view.d.ts +24 -1
  111. package/dist/app/kernel/view.js +1 -1
  112. package/dist/app/registry.js +74 -1
  113. package/dist/cli/args.js +1 -1
  114. package/dist/cli/commands/context.d.ts +7 -0
  115. package/dist/cli/commands/context.js +29 -2
  116. package/dist/cli/commands/engine.js +5 -58
  117. package/dist/cli/commands/github.d.ts +2 -0
  118. package/dist/cli/commands/github.js +11 -0
  119. package/dist/cli/commands/index.d.ts +3 -5
  120. package/dist/cli/commands/index.js +3 -5
  121. package/dist/cli/commands/launch/launch.js +21 -4
  122. package/dist/cli/commands/launch/running.js +4 -1
  123. package/dist/cli/commands/maintenance/config.js +1 -6
  124. package/dist/cli/commands/maintenance/index.d.ts +0 -1
  125. package/dist/cli/commands/maintenance/index.js +1 -2
  126. package/dist/cli/commands/maintenance/logs.js +27 -32
  127. package/dist/cli/commands/maintenance/migrate.d.ts +0 -8
  128. package/dist/cli/commands/maintenance/migrate.js +2 -44
  129. package/dist/cli/commands/maintenance/update.d.ts +0 -19
  130. package/dist/cli/commands/maintenance/update.js +1 -99
  131. package/dist/cli/commands/projects/index.d.ts +0 -1
  132. package/dist/cli/commands/projects/index.js +0 -1
  133. package/dist/cli/commands/registry.d.ts +1 -1
  134. package/dist/cli/commands/registry.js +29 -11
  135. package/dist/cli/commands/repair/checks/data.js +1 -1
  136. package/dist/cli/commands/repair/checks/hcs.js +28 -1
  137. package/dist/cli/commands/repair/checks/sandbox.js +1 -1
  138. package/dist/cli/commands/repair/health-run.d.ts +30 -0
  139. package/dist/cli/commands/repair/health-run.js +32 -0
  140. package/dist/cli/commands/repair/printer.d.ts +2 -2
  141. package/dist/cli/commands/repair/printer.js +2 -11
  142. package/dist/cli/commands/repair/run.d.ts +1 -21
  143. package/dist/cli/commands/repair/run.js +13 -70
  144. package/dist/cli/commands/storage/index.d.ts +0 -1
  145. package/dist/cli/commands/storage/index.js +0 -1
  146. package/dist/cli/commands/storage/offer.js +6 -2
  147. package/dist/cli/commands/vpn.d.ts +1 -3
  148. package/dist/cli/commands/vpn.js +8 -89
  149. package/dist/cli/commands/web.d.ts +2 -1
  150. package/dist/cli/commands/web.js +14 -78
  151. package/dist/cli/index.js +3 -2
  152. package/dist/cli/manifest.d.ts +16 -153
  153. package/dist/cli/manifest.js +20 -50
  154. package/dist/cli/menu/command-form.js +1 -2
  155. package/dist/cli/menu/io-menu.d.ts +2 -2
  156. package/dist/cli/menu/io-menu.js +6 -4
  157. package/dist/cli/menu/menu.js +1 -1
  158. package/dist/cli/menu/pages/accounts-page.d.ts +5 -17
  159. package/dist/cli/menu/pages/accounts-page.js +28 -170
  160. package/dist/cli/menu/pages/agents-page.d.ts +17 -18
  161. package/dist/cli/menu/pages/agents-page.js +67 -124
  162. package/dist/cli/menu/pages/apps-page.d.ts +15 -8
  163. package/dist/cli/menu/pages/apps-page.js +121 -29
  164. package/dist/cli/menu/pages/list-page.js +10 -1
  165. package/dist/cli/menu/pages/maintenance-page.d.ts +51 -52
  166. package/dist/cli/menu/pages/maintenance-page.js +246 -427
  167. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -5
  168. package/dist/cli/menu/pages/sandbox-page.js +34 -112
  169. package/dist/cli/menu/pages/settings-page.d.ts +21 -3
  170. package/dist/cli/menu/pages/settings-page.js +89 -17
  171. package/dist/cli/menu/render-view.js +2 -1
  172. package/dist/cli/menu/settings/index.d.ts +0 -1
  173. package/dist/cli/menu/settings/index.js +3 -3
  174. package/dist/cli/menu/views.js +28 -0
  175. package/dist/cli/operations/handler.js +7 -3
  176. package/dist/cli/operations/input.d.ts +1 -1
  177. package/dist/cli/operations/input.js +29 -5
  178. package/dist/cli/operations/io-cli.js +9 -1
  179. package/dist/cli/operations/spec.js +8 -2
  180. package/dist/cli/output/render-view.js +2 -0
  181. package/dist/cli/{commands/data/collect.js → services/data-collect.js} +2 -2
  182. package/dist/cli/{commands/data/remove.js → services/data-remove.js} +2 -2
  183. package/dist/cli/services/data-service.d.ts +1 -1
  184. package/dist/cli/services/data-service.js +2 -2
  185. package/dist/cli/services/databases-service.d.ts +5 -0
  186. package/dist/cli/services/databases-service.js +15 -0
  187. package/dist/cli/services/health-service.d.ts +8 -4
  188. package/dist/cli/services/health-service.js +10 -8
  189. package/dist/cli/services/index.d.ts +4 -1
  190. package/dist/cli/services/index.js +4 -1
  191. package/dist/cli/services/logs-service.d.ts +7 -0
  192. package/dist/cli/services/logs-service.js +13 -0
  193. package/dist/cli/services/storage-service.d.ts +19 -0
  194. package/dist/cli/services/storage-service.js +71 -0
  195. package/dist/cli/services/vpn-service.d.ts +6 -4
  196. package/dist/cli/services/vpn-service.js +5 -11
  197. package/dist/cli/services/web-service.d.ts +4 -3
  198. package/dist/cli/services/web-service.js +12 -32
  199. package/dist/core/config/defaults.js +2 -1
  200. package/dist/core/schema/config.d.ts +5 -0
  201. package/dist/core/schema/config.js +2 -0
  202. package/dist/core/schema/github.d.ts +4 -0
  203. package/dist/core/schema/github.js +7 -0
  204. package/dist/core/schema/index.d.ts +1 -0
  205. package/dist/core/schema/index.js +1 -0
  206. package/dist/core/schema/profile.d.ts +1 -0
  207. package/dist/core/schema/profile.js +3 -0
  208. package/dist/core/schema/sandbox.js +3 -3
  209. package/dist/core/schema/toolchains.js +2 -2
  210. package/dist/core/types.d.ts +6 -3
  211. package/dist/guest/boot/boot.js +8 -0
  212. package/dist/guest/daemon/daemon.js +1 -1
  213. package/dist/guest/daemon/sessions.d.ts +3 -2
  214. package/dist/guest/daemon/sessions.js +38 -7
  215. package/dist/guest/governor/core.d.ts +44 -0
  216. package/dist/guest/governor/core.js +124 -0
  217. package/dist/guest/governor/decide.d.ts +46 -18
  218. package/dist/guest/governor/decide.js +136 -82
  219. package/dist/guest/governor/governor.d.ts +2 -38
  220. package/dist/guest/governor/governor.js +33 -113
  221. package/dist/guest/governor/index.d.ts +1 -0
  222. package/dist/guest/governor/index.js +1 -0
  223. package/dist/guest/network/firewall.d.ts +2 -0
  224. package/dist/guest/network/firewall.js +3 -3
  225. package/dist/guest/sessions/viewer.js +5 -1
  226. package/dist/guest/setup/github-token.d.ts +7 -0
  227. package/dist/guest/setup/github-token.js +65 -0
  228. package/dist/guest/toolchains/languages/node.js +11 -1
  229. package/dist/guest/toolchains/native/rust-extras.js +2 -2
  230. package/dist/guest/toolchains/tools/cli.d.ts +8 -0
  231. package/dist/guest/toolchains/tools/cli.js +16 -2
  232. package/dist/guest/vpn/openvpn.d.ts +5 -0
  233. package/dist/guest/vpn/openvpn.js +14 -1
  234. package/dist/guest/vpn/vpn.js +55 -16
  235. package/dist/guest/vpn/wireguard.js +2 -0
  236. package/dist/host/channel/attach.d.ts +1 -0
  237. package/dist/host/channel/attach.js +1 -0
  238. package/dist/host/channel/channel.d.ts +1 -1
  239. package/dist/host/channel/channel.js +2 -2
  240. package/dist/host/engines/hcs/check.d.ts +1 -0
  241. package/dist/host/engines/hcs/check.js +1 -1
  242. package/dist/host/engines/hcs/engine.d.ts +1 -1
  243. package/dist/host/engines/hcs/engine.js +6 -4
  244. package/dist/host/engines/hcs/helper.d.ts +11 -0
  245. package/dist/host/engines/hcs/helper.js +31 -2
  246. package/dist/host/engines/hcs/leftovers.d.ts +42 -0
  247. package/dist/host/engines/hcs/leftovers.js +101 -0
  248. package/dist/host/engines/index.d.ts +1 -0
  249. package/dist/host/engines/index.js +1 -0
  250. package/dist/host/github/deliver.d.ts +13 -0
  251. package/dist/host/github/deliver.js +51 -0
  252. package/dist/host/github/index.d.ts +2 -0
  253. package/dist/host/github/index.js +3 -0
  254. package/dist/host/github/token.d.ts +21 -0
  255. package/dist/host/github/token.js +74 -0
  256. package/dist/host/launch/generate.js +11 -5
  257. package/dist/host/launch/index.d.ts +1 -1
  258. package/dist/host/launch/index.js +1 -1
  259. package/dist/host/launch/session-file.js +1 -2
  260. package/dist/host/launch/wsb-file.d.ts +11 -7
  261. package/dist/host/launch/wsb-file.js +30 -12
  262. package/dist/host/life/watchdog.d.ts +9 -0
  263. package/dist/host/life/watchdog.js +17 -1
  264. package/dist/host/sandbox/tasklist.d.ts +6 -0
  265. package/dist/host/sandbox/tasklist.js +37 -0
  266. package/dist/host/secrets/launch-secrets.d.ts +2 -1
  267. package/dist/host/secrets/launch-secrets.js +4 -2
  268. package/dist/host/vpn/status.js +13 -3
  269. package/dist/host/web/backend.d.ts +1 -3
  270. package/dist/host/web/index.d.ts +2 -1
  271. package/dist/host/web/index.js +2 -1
  272. package/dist/host/web/live.d.ts +23 -0
  273. package/dist/host/web/live.js +107 -0
  274. package/dist/host/web/rpc.d.ts +6 -1
  275. package/dist/host/web/rpc.js +23 -31
  276. package/dist/host/web/runner.d.ts +4 -0
  277. package/dist/host/web/runner.js +12 -1
  278. package/dist/host/web/server.d.ts +30 -2
  279. package/dist/host/web/server.js +87 -29
  280. package/dist/host/web/state.d.ts +1 -0
  281. package/dist/host/web/state.js +2 -0
  282. package/dist/runtime/agent.js +30 -6
  283. package/dist/runtime/daemon.js +323 -176
  284. package/dist/runtime/db.js +30 -6
  285. package/dist/runtime/main.js +375 -76
  286. package/dist/runtime/netproxy.js +30 -6
  287. package/dist/runtime/view.js +495 -146
  288. package/dist/selftest/app.test.js +620 -12
  289. package/dist/selftest/channel.test.js +18 -1
  290. package/dist/selftest/cli.test.js +1 -1
  291. package/dist/selftest/config.test.js +1 -1
  292. package/dist/selftest/contained.test.js +1 -1
  293. package/dist/selftest/data.test.js +1 -2
  294. package/dist/selftest/engine.test.js +3 -1
  295. package/dist/selftest/github.test.d.ts +2 -0
  296. package/dist/selftest/github.test.js +243 -0
  297. package/dist/selftest/hcs.test.js +105 -8
  298. package/dist/selftest/health.test.js +71 -0
  299. package/dist/selftest/heavy-load.test.js +132 -72
  300. package/dist/selftest/index.js +4 -0
  301. package/dist/selftest/layout.test.js +8 -0
  302. package/dist/selftest/live-terminal.test.js +74 -0
  303. package/dist/selftest/menu-screens.js +171 -56
  304. package/dist/selftest/menu.test.js +54 -37
  305. package/dist/selftest/migrate.test.js +14 -12
  306. package/dist/selftest/powershell-variables.test.d.ts +2 -0
  307. package/dist/selftest/powershell-variables.test.js +61 -0
  308. package/dist/selftest/support/engine-golden.js +1 -0
  309. package/dist/selftest/support/fixtures.d.ts +4 -0
  310. package/dist/selftest/support/web-preview.d.ts +1 -0
  311. package/dist/selftest/support/web-preview.js +856 -0
  312. package/dist/selftest/update-service.test.js +15 -8
  313. package/dist/selftest/vpn.test.js +86 -2
  314. package/dist/selftest/web.test.js +58 -11
  315. package/dist/shared/channel/run-dir.d.ts +2 -0
  316. package/dist/shared/channel/run-dir.js +3 -0
  317. package/dist/shared/channel/schema.d.ts +7 -0
  318. package/dist/shared/channel/schema.js +9 -1
  319. package/dist/shared/channel/secrets.d.ts +1 -0
  320. package/dist/shared/channel/secrets.js +3 -0
  321. package/dist/shared/github/index.d.ts +1 -0
  322. package/dist/shared/github/index.js +2 -0
  323. package/dist/shared/github/token.d.ts +29 -0
  324. package/dist/shared/github/token.js +89 -0
  325. package/dist/shared/memory/policy.d.ts +33 -12
  326. package/dist/shared/memory/policy.js +50 -19
  327. package/dist/shared/pty/ctrl-c.d.ts +18 -0
  328. package/dist/shared/pty/ctrl-c.js +36 -0
  329. package/dist/shared/pty/index.d.ts +1 -0
  330. package/dist/shared/pty/index.js +1 -0
  331. package/dist/shared/pty/terminal.d.ts +2 -0
  332. package/dist/shared/pty/terminal.js +21 -2
  333. package/dist/shared/vpn/kill-switch.d.ts +13 -2
  334. package/dist/shared/vpn/kill-switch.js +88 -8
  335. package/dist/shared/web/protocol.d.ts +0 -4
  336. package/dist/sync/watcher.js +1 -1
  337. package/dist/web/index.html +2 -2
  338. package/dist/web/{main-T5DMCHYV.css → main-6JF3ASB5.css} +1 -1
  339. package/dist/web/main-Z645W45E.js +219 -0
  340. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  341. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  342. package/package.json +10 -3
  343. package/sandbox/csharp/MemGov.cs +240 -38
  344. package/sandbox/csharp/PtyHost.cs +104 -15
  345. package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
  346. package/sandbox/csharp/SandboxTools/Program.cs +1 -1
  347. package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
  348. package/schemas/config.schema.json +19 -5
  349. package/schemas/sandbox-config.schema.json +7 -3
  350. package/dist/cli/commands/accounts.d.ts +0 -2
  351. package/dist/cli/commands/accounts.js +0 -96
  352. package/dist/cli/commands/data/clean.d.ts +0 -3
  353. package/dist/cli/commands/data/clean.js +0 -60
  354. package/dist/cli/commands/data/index.d.ts +0 -4
  355. package/dist/cli/commands/data/index.js +0 -62
  356. package/dist/cli/commands/maintenance/clean.d.ts +0 -2
  357. package/dist/cli/commands/maintenance/clean.js +0 -24
  358. package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
  359. package/dist/cli/commands/maintenance/config-share.js +0 -80
  360. package/dist/cli/commands/projects/projects.d.ts +0 -2
  361. package/dist/cli/commands/projects/projects.js +0 -162
  362. package/dist/cli/commands/storage/contained.d.ts +0 -3
  363. package/dist/cli/commands/storage/contained.js +0 -179
  364. package/dist/cli/commands/storage/storage.d.ts +0 -8
  365. package/dist/cli/commands/storage/storage.js +0 -179
  366. package/dist/cli/menu/add-agent.d.ts +0 -47
  367. package/dist/cli/menu/add-agent.js +0 -168
  368. package/dist/cli/menu/apps.d.ts +0 -69
  369. package/dist/cli/menu/apps.js +0 -214
  370. package/dist/cli/menu/data-folder.d.ts +0 -18
  371. package/dist/cli/menu/data-folder.js +0 -99
  372. package/dist/cli/menu/share-settings.d.ts +0 -21
  373. package/dist/cli/menu/share-settings.js +0 -112
  374. package/dist/cli/menu/vpn-login.d.ts +0 -16
  375. package/dist/cli/menu/vpn-login.js +0 -74
  376. package/dist/web/main-NRRS5O6Z.js +0 -157
  377. /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
  378. /package/dist/cli/{commands/data/remove.d.ts → services/data-remove.d.ts} +0 -0
@@ -5532,7 +5532,7 @@ var require_lodash = __commonJS({
5532
5532
  });
5533
5533
 
5534
5534
  // src/guest/entries/main.ts
5535
- import fs60 from "node:fs";
5535
+ import fs61 from "node:fs";
5536
5536
  import path74 from "node:path";
5537
5537
 
5538
5538
  // src/guest/runtime/paths.ts
@@ -25411,6 +25411,9 @@ var AttachSchema = external_exports.strictObject({
25411
25411
  ),
25412
25412
  autoHide: external_exports.boolean().describe(
25413
25413
  "Hide the Windows Sandbox window whenever this terminal attaches; it keeps running (sandbox show brings it back)."
25414
+ ),
25415
+ confirmCtrlC: external_exports.boolean().describe(
25416
+ 'In an attached terminal and the sandbox window, a single Ctrl+C is held back (the title says so) and only a second one within 1.5 seconds reaches the agent: a Ctrl+C meant as "copy" no longer stops it. Esc still stops an agent.'
25414
25417
  )
25415
25418
  });
25416
25419
  var AgentCommandsSchema = external_exports.strictObject({
@@ -25455,7 +25458,9 @@ var SandboxSchema = external_exports.strictObject({
25455
25458
  engine: external_exports.enum(["windows-sandbox", "hcs"]).describe(
25456
25459
  '(alpha) What runs the sandbox. "windows-sandbox" = Windows Sandbox (the default: desktop, Windows Terminal, GPU, clipboard, audio, printers). "hcs" = a headless Hyper-V isolated Server Core container for agents (no desktop, GPU or clipboard); it needs Windows features and an image on this PC (sandbox engine check hcs lists what is missing), and starting it is not enabled yet in this alpha. sandbox engine shows what each engine can do. Yours only: a project file (.sandbox-config.json) cannot set it.'
25457
25460
  ),
25458
- memoryMb: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(2048)]).describe('Sandbox RAM in MB (>= 2048), or "auto": free RAM minus reserveHostMb, capped at maxMemoryMb.'),
25461
+ memoryMb: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(2048)]).describe(
25462
+ 'Sandbox RAM in MB (>= 2048), or "auto": free RAM minus reserveHostMb, capped at maxMemoryMb. Never more than this PC can keep in RAM for it (its RAM minus the larger of reserveHostMb and 25 %, 2 GB more with vGPU): a bigger value is lowered.'
25463
+ ),
25459
25464
  maxMemoryMb: external_exports.number().int().positive().describe('Upper limit for memoryMb "auto".'),
25460
25465
  maxMemoryPercent: external_exports.number().int().min(10).max(100).describe(`memoryMb "auto" never takes more than this share of this PC's total RAM (percent).`),
25461
25466
  cpuLimit: external_exports.union([external_exports.literal("none"), external_exports.number().int().min(5).max(100)]).describe(
@@ -25468,10 +25473,10 @@ var SandboxSchema = external_exports.strictObject({
25468
25473
  'Memory always left for this PC when memoryMb is "auto": the sandbox gets at most (free RAM, and RAM plus paging file still unused) minus this.'
25469
25474
  ),
25470
25475
  agentMemoryHeadroomMb: external_exports.union([external_exports.literal("auto"), external_exports.literal("none"), external_exports.number().int().min(0)]).describe(
25471
- 'Memory kept out of the agents reach inside the sandbox, in MB: everything the agents start (their builds, tests, tools) together may use at most the sandbox memory minus this; a runaway parallel build then gets out-of-memory errors in its own session instead of freezing or crashing the whole sandbox. "auto" = the larger of 2048 MB and 10 % of the sandbox memory; "none" = no limit. Yours only: a project file cannot change it.'
25476
+ 'The last resort that keeps the sandbox up, in MB below its commit limit (RAM plus paging file): builds are slowed down long before (sandbox.pressureResponse); only if everything the agents start together would take the sandbox to the very edge of its memory, where Windows inside it would start failing, is a build refused memory instead of Windows. "auto" = the larger of 1536 MB and 3 % of the commit limit; "none" = no backstop. Yours only: a project file cannot change it.'
25472
25477
  ),
25473
25478
  pressureResponse: external_exports.boolean().describe(
25474
- "When the sandbox (or this PC) runs low on memory, slow the heaviest build programs down (lower priority) and, if that is not enough, pause the biggest compiler for a few seconds at a time, so heavy parallel builds slow down instead of closing the sandbox. Never touches the agents themselves. Yours only: a project file cannot change it."
25479
+ "When the sandbox (or this PC) runs low on memory, slow builds down in steps, like a PC that gets slower instead of failing: build programs get lower CPU and memory priority, then less CPU, then compilers take turns (the waiting ones briefly suspended and trimmed to the paging file). Nothing is stopped or killed, and the agents themselves are never touched. Yours only: a project file cannot change it."
25475
25480
  ),
25476
25481
  vGpu: external_exports.boolean().describe(
25477
25482
  "Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface. The sandbox then uses this PC's graphics card, and with some graphics drivers heavy use can freeze the whole PC: turn it on only when a program in the sandbox needs the GPU (the mesa toolchain gives software OpenGL without it)."
@@ -25617,7 +25622,7 @@ var ToolchainsSchema = external_exports.strictObject({
25617
25622
  `GNU host: "lld" links with Rust's own lld through MinGW's gcc (much less memory than GNU ld), "gnu" with GNU ld.`
25618
25623
  ),
25619
25624
  linkSlots: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(1).max(32)]).describe(
25620
- 'GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per 8 GB of sandbox memory, 2 to 4. Several agents linking big programs at once can take Windows down.'
25625
+ 'GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per 3 GB of sandbox memory after 6 GB, 2 to 8 (the memory governor slows links down too when memory runs short).'
25621
25626
  )
25622
25627
  }),
25623
25628
  msvc: external_exports.strictObject({
@@ -25692,7 +25697,7 @@ var ToolchainsSchema = external_exports.strictObject({
25692
25697
  }),
25693
25698
  cli: external_exports.strictObject({
25694
25699
  gh: EnabledSchema.describe(
25695
- 'GitHub CLI (gh). Only with provisioning.git.access "full": gh can push and merge through the GitHub API, past a read-only git. Your PC\'s gh login is never copied; `gh auth login` inside persists (GH_CONFIG_DIR). "auto" = when the project has a .github folder.'
25700
+ 'GitHub CLI (gh). Only with provisioning.git.access "full": gh can push and merge through the GitHub API, past a read-only git. Your PC\'s gh login is never copied; `gh auth login` inside persists (GH_CONFIG_DIR), unless a token you saved for sandboxes is handed over (github.shareToken). "auto" = when the project has a .github folder.'
25696
25701
  ),
25697
25702
  zstd: EnabledSchema.describe('Zstandard (zstd). "auto" = off; set true to get it.'),
25698
25703
  openssl: EnabledSchema.describe(
@@ -26620,6 +26625,13 @@ var VpnSchema = external_exports.strictObject({
26620
26625
  )
26621
26626
  });
26622
26627
 
26628
+ // src/core/schema/github.ts
26629
+ var GithubSchema = external_exports.strictObject({
26630
+ shareToken: external_exports.boolean().describe(
26631
+ 'Give each sandbox the GitHub token you saved with `sandbox github login` (best a fine-grained token limited to some repositories and permissions), so gh and https git work there without logging in. Only with provisioning.git.access "full". The agent in the sandbox can read the token and use it for whatever it allows. A project file (.sandbox-config.json) cannot turn this on.'
26632
+ )
26633
+ });
26634
+
26623
26635
  // src/core/schema/config.ts
26624
26636
  var ConfigSchema = external_exports.strictObject({
26625
26637
  $schema: SchemaRefSchema.optional(),
@@ -26650,6 +26662,7 @@ var ConfigSchema = external_exports.strictObject({
26650
26662
  }),
26651
26663
  network: NetworkSchema,
26652
26664
  vpn: VpnSchema,
26665
+ github: GithubSchema,
26653
26666
  provisioning: ProvisioningSchema,
26654
26667
  downloads: DownloadsSchema,
26655
26668
  toolchains: ToolchainsSchema,
@@ -26812,19 +26825,25 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
26812
26825
  id: IdSchema,
26813
26826
  reason: Text(300),
26814
26827
  seconds: external_exports.number().int().min(10).max(300),
26828
+ /** "severe": the PC is nearly out of memory; builds go to the governor's last step at once. */
26829
+ level: external_exports.enum(["slow", "severe"]).optional(),
26815
26830
  createdAt: TimeSchema
26816
26831
  })
26817
26832
  ]);
26818
26833
  var PressureStatusSchema = external_exports.object({
26819
26834
  level: external_exports.enum(["ok", "throttled", "suspending"]),
26835
+ /** The governor's dial, 0 (nothing wrong) to 4 (one compiler at a time). */
26836
+ step: external_exports.number().int().min(0).max(4).optional(),
26820
26837
  profile: external_exports.enum(["normal", "gentle"]),
26821
26838
  /** Share of the sandbox's RAM still free and of its commit limit in use (percent). */
26822
26839
  ramFreePercent: external_exports.number().int().min(0).max(100),
26823
26840
  commitPercent: external_exports.number().int().min(0).max(100),
26824
26841
  /** Programs running at lower priority because of it. */
26825
26842
  lowered: external_exports.number().int().min(0).max(1024),
26826
- /** Programs paused right now (name, process id, seconds left). */
26843
+ /** Compilers waiting their turn right now (name, process id, seconds until they may go on). */
26827
26844
  paused: external_exports.array(external_exports.object({ name: Text(64), pid: external_exports.number().int(), seconds: external_exports.number().int().min(0).max(60) })).max(8),
26845
+ /** The CPU share the compilers get together (percent; 100 = no cap). */
26846
+ cpuPercent: external_exports.number().int().min(0).max(100).optional(),
26828
26847
  /** The PC itself asked for slowing down (its memory or CPU is low). */
26829
26848
  pcLow: external_exports.boolean(),
26830
26849
  lastAction: Text(300),
@@ -26868,6 +26887,8 @@ var VpnStatusSchema = external_exports.object({
26868
26887
  state: external_exports.enum(["off", "starting", "up", "failed"]),
26869
26888
  message: Text(2e3),
26870
26889
  killSwitch: external_exports.boolean(),
26890
+ /** A direct connection was tried after the kill switch was applied: false = it still got out. */
26891
+ killSwitchHeld: external_exports.boolean().optional(),
26871
26892
  /** The server's name, e.g. uk2201.nordvpn.com. */
26872
26893
  server: Text(128).optional(),
26873
26894
  /** What the sandbox's traffic looks like from outside, once the tunnel is up. */
@@ -27055,6 +27076,8 @@ var RunDir = class {
27055
27076
  vpnFile;
27056
27077
  /** What the memory governor in the sandbox is doing (pressure.json). */
27057
27078
  pressureFile;
27079
+ /** What the sandbox's programs may really use (budget.json): processors, memory, build jobs, link slots. */
27080
+ budgetFile;
27058
27081
  requestsDir;
27059
27082
  responsesDir;
27060
27083
  sessionsDir;
@@ -27068,6 +27091,7 @@ var RunDir = class {
27068
27091
  this.sandboxFile = path6.join(this.root, "sandbox.json");
27069
27092
  this.vpnFile = path6.join(this.root, "vpn.json");
27070
27093
  this.pressureFile = path6.join(this.root, "pressure.json");
27094
+ this.budgetFile = path6.join(this.root, "budget.json");
27071
27095
  this.requestsDir = path6.join(this.root, "requests");
27072
27096
  this.responsesDir = path6.join(this.root, "responses");
27073
27097
  this.sessionsDir = path6.join(this.root, "sessions");
@@ -27507,7 +27531,7 @@ function writeStatus(phase, message) {
27507
27531
  }
27508
27532
 
27509
27533
  // src/guest/boot/boot.ts
27510
- import fs59 from "node:fs";
27534
+ import fs60 from "node:fs";
27511
27535
  import path73 from "node:path";
27512
27536
  import { spawn as spawn9 } from "node:child_process";
27513
27537
 
@@ -29234,9 +29258,17 @@ async function setupUv(env) {
29234
29258
  function ghConfigDir() {
29235
29259
  return path34.join(stateDir, "gh");
29236
29260
  }
29261
+ function deliveredGhConfigDir() {
29262
+ return path34.join(localDir, "gh-token");
29263
+ }
29264
+ function ghExePath() {
29265
+ const entry = CLI_TOOLS.find((t) => t.name === "gh");
29266
+ const dir = tool("cli", "gh");
29267
+ return path34.join(entry?.subdir ? path34.join(dir, entry.subdir) : dir, entry?.exe ?? "gh.exe");
29268
+ }
29237
29269
  var toolVars = {
29238
29270
  gh: () => ({
29239
- GH_CONFIG_DIR: mkdirp(ghConfigDir()),
29271
+ GH_CONFIG_DIR: exists(deliveredGhConfigDir()) ? deliveredGhConfigDir() : mkdirp(ghConfigDir()),
29240
29272
  GH_NO_UPDATE_NOTIFIER: "1",
29241
29273
  GH_NO_EXTENSION_UPDATE_NOTIFIER: "1"
29242
29274
  })
@@ -30082,6 +30114,10 @@ var activate = async (version2) => {
30082
30114
  fs36.rmSync(NVM_SYMLINK, { recursive: true, force: true });
30083
30115
  fs36.symlinkSync(path45.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
30084
30116
  };
30117
+ var PLAYWRIGHT_VARS = () => ({
30118
+ PLAYWRIGHT_BROWSERS_PATH: tool("ms-playwright"),
30119
+ PLAYWRIGHT_MCP_BROWSER: "msedge"
30120
+ });
30085
30121
  async function setupNode(env, versions, config2) {
30086
30122
  if (dryRun) {
30087
30123
  log("(dry run) would provision nvm and Node " + versions.node.spec + " (from " + versions.node.source + ")");
@@ -30115,13 +30151,14 @@ async function setupNode(env, versions, config2) {
30115
30151
  warn("Node " + version2 + " from this PC: " + errMsg(e));
30116
30152
  }
30117
30153
  }
30118
- Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK });
30154
+ Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK, ...PLAYWRIGHT_VARS() });
30119
30155
  if (duringSession()) env.prepend.push(path45.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
30120
30156
  else {
30121
30157
  await activate(main);
30122
30158
  env.prepend.push(NVM_HOME, NVM_SYMLINK);
30123
30159
  }
30124
30160
  env.summary.push("node: " + main + " (from " + versions.node.source + ", switch with nvm use)");
30161
+ env.summary.push("playwright: ready (Edge; browsers it downloads are kept; in tests use channel: 'msedge')");
30125
30162
  await packageManagers(env, config2, main);
30126
30163
  }
30127
30164
  var packageManagers = async (env, config2, version2) => {
@@ -32032,11 +32069,17 @@ import os8 from "node:os";
32032
32069
  import path51 from "node:path";
32033
32070
 
32034
32071
  // src/shared/memory/policy.ts
32072
+ function buildJobs(cpus, memoryGb) {
32073
+ return Math.max(2, Math.min(cpus, Math.floor((memoryGb - 6) / 3)));
32074
+ }
32075
+ function linkSlotsFor(memoryGb) {
32076
+ return Math.max(2, Math.min(8, Math.floor((memoryGb - 6) / 3)));
32077
+ }
32035
32078
  function cargoJobs(cpus, memoryGb, sessions) {
32036
- const byCpu = Math.max(2, Math.min(4, Math.floor(cpus / 4)));
32079
+ const byCpu = Math.max(2, Math.min(8, Math.floor(cpus / 4)));
32037
32080
  const byMemory = Math.max(1, Math.floor(memoryGb / 4));
32038
32081
  const jobs = Math.min(byCpu, byMemory);
32039
- return Math.max(1, Math.min(jobs, Math.floor(8 / Math.max(1, sessions))));
32082
+ return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions))));
32040
32083
  }
32041
32084
 
32042
32085
  // src/guest/toolchains/native/rust-extras.ts
@@ -32059,7 +32102,7 @@ function linkGate(env, rust, host) {
32059
32102
  const gate = path51.join(mkdirp(tool("shims")), "linkgate.exe");
32060
32103
  fs41.copyFileSync(ensureCompiled("linkgate"), gate);
32061
32104
  const memoryGb = os8.totalmem() / 1024 ** 3;
32062
- const slots = rust.linkSlots === "auto" ? Math.max(2, Math.min(4, Math.floor(memoryGb / 8))) : rust.linkSlots;
32105
+ const slots = rust.linkSlots === "auto" ? linkSlotsFor(memoryGb) : rust.linkSlots;
32063
32106
  env.vars.AGENT_LINK_SLOTS = String(slots);
32064
32107
  env.vars.AGENT_REAL_LINKER = gcc;
32065
32108
  env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gate;
@@ -33170,14 +33213,14 @@ var problems = [];
33170
33213
  function networkProblems() {
33171
33214
  return problems;
33172
33215
  }
33173
- var longPath = (file3) => {
33216
+ function longPath(file3) {
33174
33217
  if (!hasShortName(file3)) return file3;
33175
33218
  try {
33176
33219
  return fs48.realpathSync.native(file3);
33177
33220
  } catch {
33178
33221
  return file3;
33179
33222
  }
33180
- };
33223
+ }
33181
33224
  async function applyAttachRule(ptyHostExe) {
33182
33225
  if (!session.attach.enabled) return;
33183
33226
  if (!ptyHostExe) {
@@ -33210,9 +33253,9 @@ async function applyNetworkPolicy(ptyHostExe) {
33210
33253
  log("Networking is disabled for this sandbox.");
33211
33254
  return "offline";
33212
33255
  }
33213
- const block = session.network.blockPrivateRanges;
33214
- const exempt = block ? discoverExemptIps() : [];
33215
- const lanRules = block ? buildFirewallCommands(exempt) : [];
33256
+ const block2 = session.network.blockPrivateRanges;
33257
+ const exempt = block2 ? discoverExemptIps() : [];
33258
+ const lanRules = block2 ? buildFirewallCommands(exempt) : [];
33216
33259
  const forwardRules = forwardRule();
33217
33260
  const commands = [
33218
33261
  ...lanRules,
@@ -33231,18 +33274,18 @@ async function applyNetworkPolicy(ptyHostExe) {
33231
33274
  warn("network.dns could not be applied: " + errMsg(e));
33232
33275
  }
33233
33276
  }
33234
- if (!block) log("Private-range blocking disabled by config.");
33235
- if (block)
33277
+ if (!block2) log("Private-range blocking disabled by config.");
33278
+ if (block2)
33236
33279
  log(
33237
33280
  "Gateway/DNS addresses kept reachable for DNS only: " + (exempt.length ? [...new Set(exempt)].join(", ") : "(none found)")
33238
33281
  );
33239
33282
  if (!isWin || dryRun) {
33240
33283
  log("(dry run) firewall plan:");
33241
33284
  for (const c of commands) log(" netsh " + c.join(" "));
33242
- return block ? "blocked" : "open";
33285
+ return block2 ? "blocked" : "open";
33243
33286
  }
33244
33287
  if (commands.length === 0) return "open";
33245
- const online = block ? await waitForInternet(30) : true;
33288
+ const online = block2 ? await waitForInternet(30) : true;
33246
33289
  const failures = [];
33247
33290
  try {
33248
33291
  run2(lanRules);
@@ -33257,7 +33300,7 @@ async function applyNetworkPolicy(ptyHostExe) {
33257
33300
  warn("PROTECTION MISSING: " + problems[problems.length - 1]);
33258
33301
  }
33259
33302
  if (failures.length) throw new Error(failures[0]);
33260
- if (!block) return "open";
33303
+ if (!block2) return "open";
33261
33304
  if (online && !await waitForInternet(15)) {
33262
33305
  run2(lanRules.filter((c) => c[2] === "delete"));
33263
33306
  warn(
@@ -33487,18 +33530,109 @@ function setupGitConfig(env) {
33487
33530
  spawnSync7(git, ["config", "--global", "core.autocrlf", "input"], { env: rest, windowsHide: true, stdio: "ignore" });
33488
33531
  }
33489
33532
 
33533
+ // src/guest/setup/github-token.ts
33534
+ import fs53 from "node:fs";
33535
+ import { spawnSync as spawnSync8 } from "node:child_process";
33536
+
33537
+ // src/shared/github/token.ts
33538
+ var MIN_LENGTH = 20;
33539
+ var MAX_LENGTH = 255;
33540
+ var PRINTABLE = /^[\x21-\x7e]+$/;
33541
+ var GithubTokenSchema = external_exports.string().min(MIN_LENGTH).max(MAX_LENGTH).regex(PRINTABLE);
33542
+ var TOKEN_VARIABLES = /^(GH_TOKEN|GITHUB_TOKEN|GH_ENTERPRISE_TOKEN|GITHUB_ENTERPRISE_TOKEN)$/i;
33543
+ var ghEnv = (base, configDir) => ({
33544
+ ...Object.fromEntries(
33545
+ Object.entries(base).filter((e) => e[1] !== void 0 && !TOKEN_VARIABLES.test(e[0]))
33546
+ ),
33547
+ GH_CONFIG_DIR: configDir,
33548
+ GH_PROMPT_DISABLED: "1",
33549
+ GH_NO_UPDATE_NOTIFIER: "1"
33550
+ });
33551
+ function ghLoginCommand(ghExe, configDir, token, base) {
33552
+ return {
33553
+ file: ghExe,
33554
+ args: [
33555
+ "auth",
33556
+ "login",
33557
+ "--hostname",
33558
+ "github.com",
33559
+ "--git-protocol",
33560
+ "https",
33561
+ "--insecure-storage",
33562
+ "--with-token"
33563
+ ],
33564
+ input: token + "\n",
33565
+ env: ghEnv(base, configDir)
33566
+ };
33567
+ }
33568
+ function ghSetupGitCommand(ghExe, configDir, base) {
33569
+ return { file: ghExe, args: ["auth", "setup-git", "--hostname", "github.com"], env: ghEnv(base, configDir) };
33570
+ }
33571
+ function ghOutputText(text, token) {
33572
+ const clean = token ? text.split(token).join("***") : text;
33573
+ return clean.replace(/\s+/g, " ").trim().slice(0, 300);
33574
+ }
33575
+
33576
+ // src/guest/setup/github-token.ts
33577
+ var GH_TIMEOUT_MS = 6e4;
33578
+ function prepareGithubFolder(token) {
33579
+ const dir = deliveredGhConfigDir();
33580
+ fs53.rmSync(dir, { recursive: true, force: true });
33581
+ if (!token) return false;
33582
+ mkdirp(dir);
33583
+ return true;
33584
+ }
33585
+ function runGh(command, token, what) {
33586
+ const result = spawnSync8(command.file, [...command.args], {
33587
+ env: command.env,
33588
+ encoding: "utf8",
33589
+ windowsHide: true,
33590
+ timeout: GH_TIMEOUT_MS,
33591
+ stdio: ["pipe", "pipe", "pipe"],
33592
+ ...command.input !== void 0 ? { input: command.input } : {}
33593
+ });
33594
+ if (result.error) throw new Error(what + " could not run: " + ghOutputText(result.error.message, token));
33595
+ if (result.status !== 0)
33596
+ throw new Error(
33597
+ what + " failed: " + ghOutputText(String(result.stderr ?? "") || String(result.stdout ?? ""), token)
33598
+ );
33599
+ }
33600
+ function loginGithub(token, env) {
33601
+ if (dryRun) {
33602
+ log("(dry run) would log gh in with the GitHub token from your PC");
33603
+ return;
33604
+ }
33605
+ const gh2 = ghExePath();
33606
+ const dir = deliveredGhConfigDir();
33607
+ if (!exists(gh2) || env.GH_CONFIG_DIR !== dir) {
33608
+ fs53.rmSync(dir, { recursive: true, force: true });
33609
+ log("A GitHub token arrived, but gh is not set up in this sandbox (toolchains.cli.gh), so it is not used.");
33610
+ return;
33611
+ }
33612
+ try {
33613
+ runGh(ghLoginCommand(gh2, dir, token, env), token, "gh auth login");
33614
+ runGh(ghSetupGitCommand(gh2, dir, env), token, "gh auth setup-git");
33615
+ } catch (e) {
33616
+ fs53.rmSync(dir, { recursive: true, force: true });
33617
+ env.GH_CONFIG_DIR = mkdirp(ghConfigDir());
33618
+ addMachineEnvironment({ GH_CONFIG_DIR: env.GH_CONFIG_DIR }, []);
33619
+ throw e;
33620
+ }
33621
+ log("gh and https git to github.com use the GitHub token from your PC (github.shareToken); the agent can read it.");
33622
+ }
33623
+
33490
33624
  // src/guest/sessions/pty-host.ts
33491
33625
  function ensurePtyHost() {
33492
33626
  return ensureCompiled("ptyhost");
33493
33627
  }
33494
33628
 
33495
33629
  // src/guest/toolchains/leftovers.ts
33496
- import fs53 from "node:fs";
33630
+ import fs54 from "node:fs";
33497
33631
  import path66 from "node:path";
33498
33632
  var STAGING = /\.staging-[0-9a-f]+$/i;
33499
33633
  var entries2 = (dir) => {
33500
33634
  try {
33501
- return fs53.readdirSync(dir, { withFileTypes: true });
33635
+ return fs54.readdirSync(dir, { withFileTypes: true });
33502
33636
  } catch {
33503
33637
  return [];
33504
33638
  }
@@ -33515,17 +33649,17 @@ function pruneToolLeftovers() {
33515
33649
 
33516
33650
  // src/guest/audit/process-audit.ts
33517
33651
  import path67 from "node:path";
33518
- import { spawnSync as spawnSync8 } from "node:child_process";
33652
+ import { spawnSync as spawnSync9 } from "node:child_process";
33519
33653
  var PROCESS_CREATION = "{0CCE922B-69AE-11D9-BED3-505054503030}";
33520
33654
  var auditOn = () => Boolean(session.auditProcesses) && isWin && !dryRun;
33521
33655
  function enableProcessAudit() {
33522
33656
  if (!auditOn()) return;
33523
- spawnSync8(
33657
+ spawnSync9(
33524
33658
  path67.join(process.env.WINDIR ?? "C:\\Windows", "System32", "auditpol.exe"),
33525
33659
  ["/set", "/subcategory:" + PROCESS_CREATION, "/success:enable"],
33526
33660
  { windowsHide: true, stdio: "ignore" }
33527
33661
  );
33528
- spawnSync8(
33662
+ spawnSync9(
33529
33663
  SYSTEM.reg(),
33530
33664
  [
33531
33665
  "add",
@@ -33545,7 +33679,8 @@ function enableProcessAudit() {
33545
33679
 
33546
33680
  // src/guest/vpn/vpn.ts
33547
33681
  import dns2 from "node:dns";
33548
- import fs57 from "node:fs";
33682
+ import fs58 from "node:fs";
33683
+ import net3 from "node:net";
33549
33684
  import os14 from "node:os";
33550
33685
  import path71 from "node:path";
33551
33686
 
@@ -33710,13 +33845,13 @@ function inspectOvpn(text) {
33710
33845
  if (text.includes("\0")) return { ok: false, problems: ["the file is not text"] };
33711
33846
  const lines = text.split(/\r?\n/);
33712
33847
  if (lines.length > MAX_LINES) return { ok: false, problems: ["the file has too many lines"] };
33713
- let block = null;
33848
+ let block2 = null;
33714
33849
  let defaultProto = "udp";
33715
33850
  lines.forEach((line, i) => {
33716
33851
  const at = "line " + (i + 1) + ": ";
33717
33852
  const trimmed = line.trim();
33718
- if (block) {
33719
- if (trimmed.toLowerCase() === "</" + block + ">") block = null;
33853
+ if (block2) {
33854
+ if (trimmed.toLowerCase() === "</" + block2 + ">") block2 = null;
33720
33855
  else if (/^<\/?[A-Za-z-]+>$/.test(trimmed)) refuse(at + "a section inside a section");
33721
33856
  return;
33722
33857
  }
@@ -33724,7 +33859,7 @@ function inspectOvpn(text) {
33724
33859
  if (open2) {
33725
33860
  const tag = open2[1].toLowerCase();
33726
33861
  if (!BLOCKS.has(tag)) refuse(at + "<" + tag + "> is not allowed");
33727
- block = tag;
33862
+ block2 = tag;
33728
33863
  return;
33729
33864
  }
33730
33865
  const d = directiveOf(line);
@@ -33749,7 +33884,7 @@ function inspectOvpn(text) {
33749
33884
  }
33750
33885
  });
33751
33886
  const remotes = found.map((r) => ({ host: r.host, port: r.port, proto: r.proto ?? defaultProto }));
33752
- if (block) refuse("a <" + block + "> section is never closed");
33887
+ if (block2) refuse("a <" + block2 + "> section is never closed");
33753
33888
  if (remotes.length === 0) refuse("it names no remote server");
33754
33889
  if (remotes.length > 64) refuse("it names too many servers");
33755
33890
  return problems2.length ? { ok: false, problems: problems2 } : { ok: true, remotes };
@@ -33958,8 +34093,22 @@ var drop = (name) => [
33958
34093
  "rule",
33959
34094
  "name=" + VPN_RULE_PREFIX + name
33960
34095
  ];
34096
+ var block = (name, extra) => [
34097
+ "advfirewall",
34098
+ "firewall",
34099
+ "add",
34100
+ "rule",
34101
+ "name=" + VPN_RULE_PREFIX + name,
34102
+ "dir=out",
34103
+ "action=block",
34104
+ "enable=yes",
34105
+ "profile=any",
34106
+ ...extra
34107
+ ];
34108
+ var BLOCK_RULES = ["Block-Internet", "Block-IPv6", "Block-DNS-UDP", "Block-DNS-TCP"];
33961
34109
  function ruleNames(serverCount) {
33962
34110
  return [
34111
+ ...BLOCK_RULES,
33963
34112
  "Loopback",
33964
34113
  "DHCP",
33965
34114
  "Host",
@@ -33967,6 +34116,39 @@ function ruleNames(serverCount) {
33967
34116
  ...Array.from({ length: Math.max(serverCount, 0) }, (_v, i) => "Server-" + (i + 1))
33968
34117
  ];
33969
34118
  }
34119
+ var NOT_INTERNET = [
34120
+ ["0.0.0.0", "0.255.255.255"],
34121
+ ["10.0.0.0", "10.255.255.255"],
34122
+ ["100.64.0.0", "100.127.255.255"],
34123
+ ["127.0.0.0", "127.255.255.255"],
34124
+ ["169.254.0.0", "169.254.255.255"],
34125
+ ["172.16.0.0", "172.31.255.255"],
34126
+ ["192.168.0.0", "192.168.255.255"],
34127
+ ["224.0.0.0", "255.255.255.255"]
34128
+ ];
34129
+ var LAST_IPV4 = 4294967295;
34130
+ function ipNumber(ip) {
34131
+ return ip.split(".").reduce((n, part) => n * 256 + Number(part), 0);
34132
+ }
34133
+ function ipText(n) {
34134
+ return [24, 16, 8, 0].map((shift) => Math.floor(n / 2 ** shift) % 256).join(".");
34135
+ }
34136
+ function ipv4Except(excluded) {
34137
+ const sorted = [...excluded].sort((a, b) => a[0] - b[0]);
34138
+ const out = [];
34139
+ let next = 0;
34140
+ for (const [from, to] of sorted) {
34141
+ if (from > next) out.push(ipText(next) + "-" + ipText(from - 1));
34142
+ next = Math.max(next, to + 1);
34143
+ }
34144
+ if (next <= LAST_IPV4) out.push(ipText(next) + "-" + ipText(LAST_IPV4));
34145
+ return out.join(",");
34146
+ }
34147
+ function internetExcept(servers) {
34148
+ const ranges = NOT_INTERNET.map(([a, b]) => [ipNumber(a), ipNumber(b)]);
34149
+ for (const s of cleanServers(servers)) ranges.push([ipNumber(s.ip), ipNumber(s.ip)]);
34150
+ return ipv4Except(ranges);
34151
+ }
33970
34152
  function cleanServers(servers) {
33971
34153
  const seen = /* @__PURE__ */ new Set();
33972
34154
  return servers.filter((s) => {
@@ -33981,6 +34163,10 @@ function killSwitchCommands(servers, ptyHostExe) {
33981
34163
  return [
33982
34164
  ...ruleNames(Math.max(list.length, 8)).map(drop),
33983
34165
  ["advfirewall", "set", "allprofiles", "state", "on"],
34166
+ block("Block-Internet", ["protocol=any", "remoteip=" + internetExcept(list)]),
34167
+ block("Block-IPv6", ["protocol=any", "remoteip=2000::/3"]),
34168
+ block("Block-DNS-UDP", ["protocol=udp", "remoteport=53"]),
34169
+ block("Block-DNS-TCP", ["protocol=tcp", "remoteport=53"]),
33984
34170
  ["advfirewall", "set", "allprofiles", "firewallpolicy", "blockinbound,blockoutbound"],
33985
34171
  rule("Loopback", ["protocol=any", "remoteip=127.0.0.0/8"]),
33986
34172
  rule("DHCP", ["protocol=udp", "localport=68", "remoteport=67"]),
@@ -33992,7 +34178,21 @@ function killSwitchCommands(servers, ptyHostExe) {
33992
34178
  }
33993
34179
  function tunnelCommands(tunnelIp) {
33994
34180
  if (!isIPv4(tunnelIp)) throw new Error("Not an IPv4 address: " + tunnelIp);
33995
- return [drop("Tunnel"), rule("Tunnel", ["protocol=any", "localip=" + tunnelIp])];
34181
+ const n = ipNumber(tunnelIp);
34182
+ const notTunnel = ipv4Except([[n, n]]);
34183
+ return [
34184
+ ...["Block-Internet", "Block-DNS-UDP", "Block-DNS-TCP"].map((name) => [
34185
+ "advfirewall",
34186
+ "firewall",
34187
+ "set",
34188
+ "rule",
34189
+ "name=" + VPN_RULE_PREFIX + name,
34190
+ "new",
34191
+ "localip=" + notTunnel
34192
+ ]),
34193
+ drop("Tunnel"),
34194
+ rule("Tunnel", ["protocol=any", "localip=" + tunnelIp])
34195
+ ];
33996
34196
  }
33997
34197
  function tunnelAddressFromLog(log2) {
33998
34198
  const add = /net_addr_v4_add:\s*(\d{1,3}(?:\.\d{1,3}){3})\/\d+/.exec(log2);
@@ -34005,7 +34205,7 @@ function tunnelAddressFromLog(log2) {
34005
34205
 
34006
34206
  // src/guest/vpn/openvpn.ts
34007
34207
  import crypto4 from "node:crypto";
34008
- import fs54 from "node:fs";
34208
+ import fs55 from "node:fs";
34009
34209
  import path68 from "node:path";
34010
34210
 
34011
34211
  // src/shared/vpn/download.ts
@@ -34042,7 +34242,12 @@ function openvpnDownload(arch2 = process.arch) {
34042
34242
  const entry = arch2 === "arm64" ? OPENVPN_MSI.arm64 : OPENVPN_MSI.x64;
34043
34243
  return { ...entry, url: OPENVPN_MSI.base + entry.file };
34044
34244
  }
34045
- var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs54.readFileSync(file3)).digest("hex") === sha256;
34245
+ function repairServiceQueries() {
34246
+ const did = scriptOutput("repair-wmi-services.ps1");
34247
+ if (did === "removed") log("VPN: repaired the Windows service queries installers use (a Windows Sandbox gap).");
34248
+ else if (did !== "absent" && did !== "kept") warn("VPN: could not check the Windows service queries installers use.");
34249
+ }
34250
+ var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs55.readFileSync(file3)).digest("hex") === sha256;
34046
34251
  async function ensureOpenVpn() {
34047
34252
  const exe = openvpnExe();
34048
34253
  if (!isWin || dryRun) return exe;
@@ -34053,6 +34258,7 @@ async function ensureOpenVpn() {
34053
34258
  log("VPN: downloading OpenVPN " + OPENVPN_MSI.version + " (about 6 MB)");
34054
34259
  await downloader.file(dl.url, msi, dl.sha256);
34055
34260
  }
34261
+ repairServiceQueries();
34056
34262
  log("VPN: installing OpenVPN");
34057
34263
  const logFile2 = path68.join(toolsDir, "downloads", "openvpn-install.log");
34058
34264
  const code = await spawnAsync(SYSTEM.msiexec(), ["/i", msi, "/qn", "/norestart", "/l*v", logFile2], {
@@ -34066,7 +34272,7 @@ async function ensureOpenVpn() {
34066
34272
 
34067
34273
  // src/guest/vpn/tunnel.ts
34068
34274
  import { spawn as spawn7 } from "node:child_process";
34069
- import fs55 from "node:fs";
34275
+ import fs56 from "node:fs";
34070
34276
  import os12 from "node:os";
34071
34277
  import path69 from "node:path";
34072
34278
  var DONE = "Initialization Sequence Completed";
@@ -34084,17 +34290,17 @@ function failureReason(text) {
34084
34290
  }
34085
34291
  var tail = (text, lines = 12) => text.trim().split(/\r?\n/).slice(-lines).join("\n");
34086
34292
  async function startTunnel(o) {
34087
- const dir = fs55.mkdtempSync(path69.join(os12.tmpdir(), "sbx-vpn-"));
34293
+ const dir = fs56.mkdtempSync(path69.join(os12.tmpdir(), "sbx-vpn-"));
34088
34294
  const auth = path69.join(dir, "login.txt");
34089
34295
  const logFile2 = path69.join(dir, "openvpn.log");
34090
34296
  const keepLog = () => {
34091
34297
  try {
34092
- fs55.mkdirSync(logsDir, { recursive: true });
34093
- fs55.copyFileSync(logFile2, path69.join(logsDir, "openvpn.log"));
34298
+ fs56.mkdirSync(logsDir, { recursive: true });
34299
+ fs56.copyFileSync(logFile2, path69.join(logsDir, "openvpn.log"));
34094
34300
  } catch {
34095
34301
  }
34096
34302
  };
34097
- fs55.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
34303
+ fs56.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
34098
34304
  try {
34099
34305
  const child = spawn7(
34100
34306
  o.exe,
@@ -34112,7 +34318,7 @@ async function startTunnel(o) {
34112
34318
  child.unref();
34113
34319
  const deadline = Date.now() + (o.timeoutMs ?? 9e4);
34114
34320
  for (; ; ) {
34115
- const text = fs55.existsSync(logFile2) ? fs55.readFileSync(logFile2, "utf8") : "";
34321
+ const text = fs56.existsSync(logFile2) ? fs56.readFileSync(logFile2, "utf8") : "";
34116
34322
  if (text.includes(DONE)) {
34117
34323
  keepLog();
34118
34324
  const tunnelIp = tunnelAddressFromLog(text) ?? void 0;
@@ -34132,14 +34338,14 @@ async function startTunnel(o) {
34132
34338
  await new Promise((r) => setTimeout(r, 500));
34133
34339
  }
34134
34340
  } finally {
34135
- fs55.rmSync(auth, { force: true });
34341
+ fs56.rmSync(auth, { force: true });
34136
34342
  }
34137
34343
  }
34138
34344
 
34139
34345
  // src/guest/vpn/wireguard.ts
34140
34346
  import { execFile } from "node:child_process";
34141
34347
  import crypto5 from "node:crypto";
34142
- import fs56 from "node:fs";
34348
+ import fs57 from "node:fs";
34143
34349
  import os13 from "node:os";
34144
34350
  import path70 from "node:path";
34145
34351
  var WIREGUARD_TUNNEL = "sandbox";
@@ -34153,7 +34359,7 @@ function wireguardDownload(arch2 = process.arch) {
34153
34359
  const entry = arch2 === "arm64" ? WIREGUARD_MSI.arm64 : WIREGUARD_MSI.x64;
34154
34360
  return { ...entry, url: WIREGUARD_MSI.base + entry.file };
34155
34361
  }
34156
- var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(fs56.readFileSync(file3)).digest("hex") === sha256;
34362
+ var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(fs57.readFileSync(file3)).digest("hex") === sha256;
34157
34363
  async function ensureWireguard() {
34158
34364
  const exe = wireguardExe();
34159
34365
  if (!isWin || dryRun) return exe;
@@ -34164,6 +34370,7 @@ async function ensureWireguard() {
34164
34370
  log("VPN: downloading WireGuard " + WIREGUARD_MSI.version + " (about 3 MB)");
34165
34371
  await downloader.file(dl.url, msi, dl.sha256);
34166
34372
  }
34373
+ repairServiceQueries();
34167
34374
  log("VPN: installing WireGuard");
34168
34375
  const logFile2 = path70.join(toolsDir, "downloads", "wireguard-install.log");
34169
34376
  const code = await spawnAsync(
@@ -34198,9 +34405,9 @@ async function removeWireguardTunnel(exe) {
34198
34405
  }
34199
34406
  async function startWireguardTunnel(o) {
34200
34407
  const root = path70.join(process.env.SystemRoot ?? "C:\\Windows", "Temp");
34201
- const dir = fs56.mkdtempSync(path70.join(fs56.existsSync(root) ? root : os13.tmpdir(), "sbx-wg-"));
34408
+ const dir = fs57.mkdtempSync(path70.join(fs57.existsSync(root) ? root : os13.tmpdir(), "sbx-wg-"));
34202
34409
  const file3 = path70.join(dir, WIREGUARD_TUNNEL + ".conf");
34203
- fs56.writeFileSync(file3, o.config, "utf8");
34410
+ fs57.writeFileSync(file3, o.config, "utf8");
34204
34411
  const fail = async (message) => {
34205
34412
  await removeWireguardTunnel(o.exe);
34206
34413
  return { ok: false, message };
@@ -34221,7 +34428,7 @@ async function startWireguardTunnel(o) {
34221
34428
  await sleep(500);
34222
34429
  }
34223
34430
  } finally {
34224
- fs56.rmSync(dir, { recursive: true, force: true });
34431
+ fs57.rmSync(dir, { recursive: true, force: true });
34225
34432
  }
34226
34433
  }
34227
34434
  async function waitForHandshake(exe, poke, timeoutMs = 3e4) {
@@ -34290,15 +34497,47 @@ async function publicAddress() {
34290
34497
  }
34291
34498
  }
34292
34499
  var hasAdapter2 = (ip) => Object.values(os14.networkInterfaces()).some((list) => (list ?? []).some((i) => i.address === ip));
34500
+ var PROBE_TARGETS = ["1.1.1.1", "8.8.8.8", "9.9.9.9"];
34501
+ var PROBE_TIMEOUT_MS = 3e3;
34502
+ function connects(ip, port) {
34503
+ return new Promise((resolve2) => {
34504
+ const socket = net3.connect({ host: ip, port });
34505
+ const done = (ok) => {
34506
+ socket.destroy();
34507
+ resolve2(ok);
34508
+ };
34509
+ socket.setTimeout(PROBE_TIMEOUT_MS, () => done(false));
34510
+ socket.once("connect", () => done(true));
34511
+ socket.once("error", () => done(false));
34512
+ });
34513
+ }
34514
+ async function directConnectionBlocked(servers) {
34515
+ const targets = PROBE_TARGETS.filter((ip) => !servers.some((s) => s.ip === ip));
34516
+ const results = await Promise.all(targets.map((ip) => connects(ip, 443)));
34517
+ return !results.some(Boolean);
34518
+ }
34293
34519
  async function setupVpn(secrets, ptyHostExe) {
34294
34520
  const vpn = session.vpn;
34295
34521
  if (!vpn) return true;
34296
34522
  const killSwitch = vpn.killSwitch;
34297
34523
  let blocked = false;
34298
- const block = (servers) => {
34299
- if (isWin && !dryRun) run2(killSwitchCommands(servers, ptyHostExe));
34300
- blocked = true;
34301
- log("VPN: kill switch on: nothing leaves the sandbox except through the tunnel.");
34524
+ let held = false;
34525
+ const block2 = async (servers) => {
34526
+ if (!isWin || dryRun) {
34527
+ blocked = held = true;
34528
+ return;
34529
+ }
34530
+ try {
34531
+ run2(killSwitchCommands(servers, ptyHostExe ? longPath(ptyHostExe) : null));
34532
+ } finally {
34533
+ blocked = true;
34534
+ held = await directConnectionBlocked(servers);
34535
+ }
34536
+ if (held) log("VPN: kill switch on: nothing leaves the sandbox except through the tunnel (checked).");
34537
+ else
34538
+ warn(
34539
+ "VPN: the kill switch did not hold: a direct connection still got out. If the tunnel drops, traffic leaves through your normal connection."
34540
+ );
34302
34541
  };
34303
34542
  setVpnStatus("starting", "Starting the VPN");
34304
34543
  try {
@@ -34314,7 +34553,7 @@ async function setupVpn(secrets, ptyHostExe) {
34314
34553
  warn(
34315
34554
  "VPN: AllowedIPs does not include 0.0.0.0/0: with the kill switch on, only the tunnel traffic can leave the sandbox."
34316
34555
  );
34317
- if (killSwitch) block(servers);
34556
+ if (killSwitch) await block2(servers);
34318
34557
  if (dryRun || !isWin) {
34319
34558
  log("(dry run) would start the WireGuard tunnel " + vpn.server);
34320
34559
  setVpnStatus("off", "dry run");
@@ -34329,11 +34568,11 @@ async function setupVpn(secrets, ptyHostExe) {
34329
34568
  const credentials = secrets.vpn;
34330
34569
  if (!credentials) throw new Error("the VPN login did not arrive (start the sandbox again)");
34331
34570
  const profile = path71.join(launchDir, "vpn", "server.ovpn");
34332
- const remotes = assertSafeOvpn(fs57.readFileSync(profile, "utf8"), vpn.server);
34571
+ const remotes = assertSafeOvpn(fs58.readFileSync(profile, "utf8"), vpn.server);
34333
34572
  const exe = await ensureOpenVpn();
34334
34573
  const servers = await serverAddresses(remotes);
34335
34574
  if (servers.length === 0) throw new Error("the VPN server addresses could not be found");
34336
- if (killSwitch) block(servers);
34575
+ if (killSwitch) await block2(servers);
34337
34576
  if (dryRun || !isWin) {
34338
34577
  log("(dry run) would start the VPN tunnel to " + vpn.server);
34339
34578
  setVpnStatus("off", "dry run");
@@ -34352,18 +34591,21 @@ async function setupVpn(secrets, ptyHostExe) {
34352
34591
  throw new Error("the tunnel reported it was up, but no network adapter with its address appeared");
34353
34592
  const publicIp = await publicAddress();
34354
34593
  log("VPN: up" + (publicIp ? " (the sandbox appears as " + publicIp + ")" : "") + ".");
34355
- setVpnStatus("up", "The tunnel is up", publicIp ? { publicIp } : {});
34594
+ setVpnStatus("up", "The tunnel is up", {
34595
+ ...publicIp ? { publicIp } : {},
34596
+ ...killSwitch ? { killSwitchHeld: held } : {}
34597
+ });
34356
34598
  return true;
34357
34599
  } catch (e) {
34358
34600
  const reason = errMsg(e);
34359
34601
  try {
34360
- if (killSwitch && !blocked) block([]);
34602
+ if (killSwitch && !blocked) await block2([]);
34361
34603
  } catch (blockError) {
34362
34604
  warn("VPN: could not close the network after the failure: " + errMsg(blockError));
34363
34605
  }
34364
- const text = "VPN failed: " + reason + (killSwitch ? " The kill switch is on, so this sandbox has NO internet access." : " The kill switch is off, so this sandbox is using your normal connection.");
34365
- warn(text);
34366
- setVpnStatus("failed", reason);
34606
+ const after = !killSwitch ? " The kill switch is off, so this sandbox is using your normal connection." : held ? " The kill switch is on, so this sandbox has NO internet access." : " The kill switch could NOT close the network, so this sandbox is ONLINE through your normal connection, without the VPN.";
34607
+ warn("VPN failed: " + reason + after);
34608
+ setVpnStatus("failed", reason, killSwitch ? { killSwitchHeld: held } : {});
34367
34609
  return false;
34368
34610
  }
34369
34611
  }
@@ -34420,10 +34662,10 @@ var FrameReader = class {
34420
34662
  };
34421
34663
 
34422
34664
  // src/shared/pty/client.ts
34423
- import net3 from "node:net";
34665
+ import net4 from "node:net";
34424
34666
  var connectOnce = (host, port, timeoutMs) => {
34425
34667
  return new Promise((resolve2, reject) => {
34426
- const socket = net3.connect({ host, port });
34668
+ const socket = net4.connect({ host, port });
34427
34669
  const timer = setTimeout(() => {
34428
34670
  socket.destroy();
34429
34671
  reject(new Error("timed out connecting to " + host + ":" + port));
@@ -34644,6 +34886,36 @@ function unfinishedSequence(data) {
34644
34886
  return data.length;
34645
34887
  }
34646
34888
 
34889
+ // src/shared/pty/ctrl-c.ts
34890
+ var CTRL_C_CONFIRM_MS = 1500;
34891
+ var CTRL_C_HINT = "Ctrl+C again to send it to the program (Esc stops an agent)";
34892
+ var OSC_TITLE = /\x1b\][02];([^\x07\x1b]{0,256})(?:\x07|\x1b\\)/g;
34893
+ var CtrlCGuard = class {
34894
+ armedAt = Number.NEGATIVE_INFINITY;
34895
+ lastTitle = "";
34896
+ /** What to send for one read from the keyboard: a lone Ctrl+C only when another came just before. */
34897
+ push(chunk, nowMs) {
34898
+ if (chunk.length !== 1 || chunk[0] !== 3) return { send: chunk, held: false };
34899
+ if (nowMs - this.armedAt <= CTRL_C_CONFIRM_MS) {
34900
+ this.armedAt = Number.NEGATIVE_INFINITY;
34901
+ return { send: chunk, held: false };
34902
+ }
34903
+ this.armedAt = nowMs;
34904
+ return { send: Buffer.alloc(0), held: true };
34905
+ }
34906
+ /** Remembers the title the program last set (from its output), to put it back after the hint. */
34907
+ watchOutput(text) {
34908
+ for (const m of text.matchAll(OSC_TITLE)) this.lastTitle = m[1];
34909
+ }
34910
+ /** The escape sequence that shows the hint, and the one that puts the program's title back. */
34911
+ hintTitle() {
34912
+ return "\x1B]0;" + CTRL_C_HINT + "\x07";
34913
+ }
34914
+ restoreTitle() {
34915
+ return "\x1B]0;" + this.lastTitle.replace(/[\x00-\x1f\x7f]/g, "") + "\x07";
34916
+ }
34917
+ };
34918
+
34647
34919
  // src/shared/pty/terminal.ts
34648
34920
  var MOUSE_OFF = "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1005l\x1B[?1006l\x1B[?1015l";
34649
34921
  function fixWindowsKeys(chunk) {
@@ -34674,6 +34946,7 @@ function runTerminalClient(socket, token, options = {}) {
34674
34946
  clearInterval(heartbeat);
34675
34947
  clearInterval(sizeWatch);
34676
34948
  clearTimeout(joinTimer);
34949
+ clearTimeout(hintTimer);
34677
34950
  socket.destroy();
34678
34951
  stdout.write("\x1B[0m\x1B[?25h" + MOUSE_OFF + "\r\n");
34679
34952
  void (vtInput?.stop() ?? Promise.resolve()).then(() => {
@@ -34687,11 +34960,23 @@ function runTerminalClient(socket, token, options = {}) {
34687
34960
  const sendInput = (data) => {
34688
34961
  if (data.length && !done) socket.write(encodeFrame(FrameType.Input, swapKeys ? fixWindowsKeys(data) : data));
34689
34962
  };
34963
+ const guard = options.confirmCtrlC ? new CtrlCGuard() : null;
34964
+ let hintTimer;
34690
34965
  const onInput = (chunk) => {
34691
34966
  if (options.detachKey !== void 0 && chunk.includes(options.detachKey)) {
34692
34967
  finish({ reason: "detach" });
34693
34968
  return;
34694
34969
  }
34970
+ if (guard) {
34971
+ const decided = guard.push(chunk, Date.now());
34972
+ clearTimeout(hintTimer);
34973
+ if (decided.held) {
34974
+ stdout.write(guard.hintTitle());
34975
+ hintTimer = setTimeout(() => stdout.write(guard.restoreTitle()), CTRL_C_CONFIRM_MS);
34976
+ return;
34977
+ }
34978
+ if (decided.send.length === 1 && decided.send[0] === 3) stdout.write(guard.restoreTitle());
34979
+ }
34695
34980
  clearTimeout(joinTimer);
34696
34981
  sendInput(joiner.push(chunk));
34697
34982
  if (joiner.holding()) joinTimer = setTimeout(() => sendInput(joiner.flush()), JOIN_MS);
@@ -34724,8 +35009,11 @@ function runTerminalClient(socket, token, options = {}) {
34724
35009
  return;
34725
35010
  }
34726
35011
  for (const frame of frames) {
34727
- if (frame.type === FrameType.Output) stdout.write(filter.push(frame.payload));
34728
- else if (frame.type === FrameType.Console) passthrough = frame.payload.toString("latin1") === "conpty.dll";
35012
+ if (frame.type === FrameType.Output) {
35013
+ const out = filter.push(frame.payload);
35014
+ guard?.watchOutput(out.toString("latin1"));
35015
+ stdout.write(out);
35016
+ } else if (frame.type === FrameType.Console) passthrough = frame.payload.toString("latin1") === "conpty.dll";
34729
35017
  else if (frame.type === FrameType.Restarting) stdout.write(MOUSE_OFF + "\x1B[2J\x1B[3J\x1B[H");
34730
35018
  else if (frame.type === FrameType.Exit)
34731
35019
  finish({ reason: "exit", exitCode: frame.payload.length >= 4 ? frame.payload.readInt32LE(0) : 1 });
@@ -34778,7 +35066,10 @@ async function viewSession(id) {
34778
35066
  return 1;
34779
35067
  }
34780
35068
  const socket = await connect({ ...session2.attach, addresses: ["127.0.0.1"] });
34781
- const result = await runTerminalClient(socket, session2.attach.token, { clipboardWrites: true });
35069
+ const result = await runTerminalClient(socket, session2.attach.token, {
35070
+ clipboardWrites: true,
35071
+ confirmCtrlC: session.attach.confirmCtrlC !== false
35072
+ });
34782
35073
  if (result.reason === "exit") console.log(session2.harness + " exited with code " + result.exitCode + ".");
34783
35074
  else if (result.reason === "error") console.log("Session error: " + result.message);
34784
35075
  return result.reason === "exit" ? result.exitCode : 1;
@@ -34833,7 +35124,7 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
34833
35124
  }
34834
35125
 
34835
35126
  // src/guest/runtime/secrets.ts
34836
- import fs58 from "node:fs";
35127
+ import fs59 from "node:fs";
34837
35128
 
34838
35129
  // src/shared/channel/secrets.ts
34839
35130
  var Environment = external_exports.record(external_exports.string().max(256), external_exports.string().max(65536));
@@ -34849,7 +35140,9 @@ var SecretsFileSchema = external_exports.strictObject({
34849
35140
  /** VPN service credentials (vpn.provider's login), only for the launch's own sandbox. */
34850
35141
  vpn: external_exports.strictObject({ username: external_exports.string().min(1).max(256), password: external_exports.string().min(1).max(1024) }).optional(),
34851
35142
  /** The checked WireGuard config of vpn.provider wireguard-file (holds the private key). */
34852
- wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional()
35143
+ wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional(),
35144
+ /** The GitHub token you saved for sandboxes (github.shareToken), only with git access "full". */
35145
+ githubToken: GithubTokenSchema.optional()
34853
35146
  });
34854
35147
 
34855
35148
  // src/guest/runtime/secrets.ts
@@ -34859,12 +35152,12 @@ function takeSecrets(id) {
34859
35152
  const file3 = run.secretFile(id);
34860
35153
  let text;
34861
35154
  try {
34862
- if (fs58.statSync(file3).size > MAX_BYTES) throw new Error("too big");
34863
- text = fs58.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
35155
+ if (fs59.statSync(file3).size > MAX_BYTES) throw new Error("too big");
35156
+ text = fs59.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
34864
35157
  } catch {
34865
35158
  return {};
34866
35159
  } finally {
34867
- fs58.rmSync(file3, { force: true });
35160
+ fs59.rmSync(file3, { force: true });
34868
35161
  }
34869
35162
  try {
34870
35163
  const parsed = SecretsFileSchema.safeParse(JSON.parse(text));
@@ -34917,7 +35210,7 @@ function startDaemon(env, secrets) {
34917
35210
  function writeDbCommand() {
34918
35211
  const dir = mkdirp(path73.join(localDir, "bin"));
34919
35212
  const db = path73.join(path73.dirname(process.argv[1]), "db.js");
34920
- fs59.writeFileSync(
35213
+ fs60.writeFileSync(
34921
35214
  path73.join(dir, "sbx-db.cmd"),
34922
35215
  '@setlocal\r\n@set AGENT_LOG_PREFIX=db\r\n@"' + process.execPath + '" "' + db + '" %*\r\n'
34923
35216
  );
@@ -34927,8 +35220,8 @@ function writeDbCommand() {
34927
35220
  function writeAgentCommands(dir) {
34928
35221
  const install = { node: process.execPath, script: path73.join(path73.dirname(process.argv[1]), "agent.js") };
34929
35222
  for (const shim3 of agentShims(toolsDir, session.agents ?? {}))
34930
- fs59.writeFileSync(path73.join(dir, shim3.command + ".cmd"), shimText(shim3, install));
34931
- fs59.writeFileSync(path73.join(dir, "sbx-agent.cmd"), sbxAgentText(install));
35223
+ fs60.writeFileSync(path73.join(dir, shim3.command + ".cmd"), shimText(shim3, install));
35224
+ fs60.writeFileSync(path73.join(dir, "sbx-agent.cmd"), sbxAgentText(install));
34932
35225
  }
34933
35226
  async function waitForPrimary() {
34934
35227
  for (let i = 0; i < PRIMARY_POLLS; i++) {
@@ -34956,12 +35249,13 @@ var Boot = class {
34956
35249
  log(
34957
35250
  "Agent sandbox: " + session.project + " | workspace " + workspace + " | agent " + session.harnessName + " | log " + logPath
34958
35251
  );
34959
- if (!fs59.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
35252
+ if (!fs60.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
34960
35253
  throw new Error("Workspace folder is missing in the sandbox: " + workspace);
34961
35254
  mkdirp(toolsDir);
34962
35255
  mkdirp(run.root);
34963
35256
  this.secrets = takeSecrets(session.launchId);
34964
35257
  applyBootEnvironment(this.secrets.harnessEnvironment);
35258
+ prepareGithubFolder(this.secrets.githubToken);
34965
35259
  await this.networkAndSessionHost();
34966
35260
  await this.hooksAndDesktop();
34967
35261
  const { tools, env } = await this.developerTools();
@@ -35044,6 +35338,11 @@ var Boot = class {
35044
35338
  async gitIdentity(env) {
35045
35339
  step(5, "Git identity");
35046
35340
  await soft("Git config", () => setupGitConfig(env));
35341
+ const token = this.secrets.githubToken;
35342
+ if (token) {
35343
+ this.secrets = { ...this.secrets, githubToken: void 0 };
35344
+ await soft("GitHub token", () => loginGithub(token, env));
35345
+ }
35047
35346
  }
35048
35347
  async claude(tools) {
35049
35348
  step(6, "Claude settings, history and claude-mem");
@@ -35105,7 +35404,7 @@ runBoot().catch((e) => {
35105
35404
  const message = errMsg(e) + (e instanceof Error && e.stack ? "\n" + e.stack : "");
35106
35405
  try {
35107
35406
  setSandboxStatus("failed", errMsg(e));
35108
- fs60.writeFileSync(path74.join(logsDir, "guest-error.txt"), message);
35407
+ fs61.writeFileSync(path74.join(logsDir, "guest-error.txt"), message);
35109
35408
  } catch {
35110
35409
  }
35111
35410
  console.error(