windows-development-sandbox 1.10.0 → 1.11.4

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 (383) 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 +194 -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 +959 -4
  32. package/dist/app/features/defs.js +151 -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 +297 -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 +220 -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 +224 -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 +35 -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/host-memory.d.ts +18 -0
  263. package/dist/host/life/host-memory.js +66 -0
  264. package/dist/host/life/watchdog.d.ts +9 -0
  265. package/dist/host/life/watchdog.js +17 -1
  266. package/dist/host/sandbox/tasklist.d.ts +6 -0
  267. package/dist/host/sandbox/tasklist.js +37 -0
  268. package/dist/host/secrets/launch-secrets.d.ts +2 -1
  269. package/dist/host/secrets/launch-secrets.js +4 -2
  270. package/dist/host/vpn/status.js +13 -3
  271. package/dist/host/web/backend.d.ts +1 -3
  272. package/dist/host/web/index.d.ts +2 -1
  273. package/dist/host/web/index.js +2 -1
  274. package/dist/host/web/live.d.ts +23 -0
  275. package/dist/host/web/live.js +107 -0
  276. package/dist/host/web/rpc.d.ts +6 -1
  277. package/dist/host/web/rpc.js +23 -31
  278. package/dist/host/web/runner.d.ts +4 -0
  279. package/dist/host/web/runner.js +12 -1
  280. package/dist/host/web/server.d.ts +30 -2
  281. package/dist/host/web/server.js +87 -29
  282. package/dist/host/web/state.d.ts +1 -0
  283. package/dist/host/web/state.js +2 -0
  284. package/dist/runtime/agent.js +30 -6
  285. package/dist/runtime/daemon.js +337 -177
  286. package/dist/runtime/db.js +30 -6
  287. package/dist/runtime/main.js +389 -77
  288. package/dist/runtime/netproxy.js +30 -6
  289. package/dist/runtime/view.js +495 -146
  290. package/dist/selftest/app.test.js +632 -12
  291. package/dist/selftest/channel.test.js +18 -1
  292. package/dist/selftest/cli.test.js +1 -1
  293. package/dist/selftest/config.test.js +1 -1
  294. package/dist/selftest/contained.test.js +1 -1
  295. package/dist/selftest/data.test.js +1 -2
  296. package/dist/selftest/engine.test.js +3 -1
  297. package/dist/selftest/github.test.d.ts +2 -0
  298. package/dist/selftest/github.test.js +243 -0
  299. package/dist/selftest/hcs.test.js +105 -8
  300. package/dist/selftest/health.test.js +71 -0
  301. package/dist/selftest/heavy-load.test.js +132 -72
  302. package/dist/selftest/index.js +4 -0
  303. package/dist/selftest/layout.test.js +8 -0
  304. package/dist/selftest/live-terminal.test.js +74 -0
  305. package/dist/selftest/menu-screens.js +171 -56
  306. package/dist/selftest/menu.test.js +54 -37
  307. package/dist/selftest/migrate.test.js +14 -12
  308. package/dist/selftest/powershell-variables.test.d.ts +2 -0
  309. package/dist/selftest/powershell-variables.test.js +61 -0
  310. package/dist/selftest/support/engine-golden.js +1 -0
  311. package/dist/selftest/support/fixtures.d.ts +4 -0
  312. package/dist/selftest/support/web-preview.d.ts +1 -0
  313. package/dist/selftest/support/web-preview.js +856 -0
  314. package/dist/selftest/update-service.test.js +15 -8
  315. package/dist/selftest/vpn.test.js +86 -2
  316. package/dist/selftest/web.test.js +58 -11
  317. package/dist/shared/channel/run-dir.d.ts +2 -0
  318. package/dist/shared/channel/run-dir.js +3 -0
  319. package/dist/shared/channel/schema.d.ts +7 -0
  320. package/dist/shared/channel/schema.js +9 -1
  321. package/dist/shared/channel/secrets.d.ts +1 -0
  322. package/dist/shared/channel/secrets.js +3 -0
  323. package/dist/shared/github/index.d.ts +1 -0
  324. package/dist/shared/github/index.js +2 -0
  325. package/dist/shared/github/token.d.ts +29 -0
  326. package/dist/shared/github/token.js +89 -0
  327. package/dist/shared/memory/policy.d.ts +33 -12
  328. package/dist/shared/memory/policy.js +50 -19
  329. package/dist/shared/pty/ctrl-c.d.ts +18 -0
  330. package/dist/shared/pty/ctrl-c.js +36 -0
  331. package/dist/shared/pty/index.d.ts +1 -0
  332. package/dist/shared/pty/index.js +1 -0
  333. package/dist/shared/pty/terminal.d.ts +2 -0
  334. package/dist/shared/pty/terminal.js +21 -2
  335. package/dist/shared/vpn/kill-switch.d.ts +13 -2
  336. package/dist/shared/vpn/kill-switch.js +88 -8
  337. package/dist/shared/web/protocol.d.ts +0 -4
  338. package/dist/sync/watcher.d.ts +2 -0
  339. package/dist/sync/watcher.js +8 -3
  340. package/dist/web/index.html +2 -2
  341. package/dist/web/{main-T5DMCHYV.css → main-MU5XWZMS.css} +1 -1
  342. package/dist/web/main-SLQNJRXD.js +219 -0
  343. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  344. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  345. package/native/csharp/HostTools/MemoryStatus.cs +58 -2
  346. package/native/csharp/HostTools/Program.cs +7 -1
  347. package/package.json +10 -3
  348. package/sandbox/csharp/MemGov.cs +240 -38
  349. package/sandbox/csharp/PtyHost.cs +104 -15
  350. package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
  351. package/sandbox/csharp/SandboxTools/Program.cs +1 -1
  352. package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
  353. package/schemas/config.schema.json +19 -5
  354. package/schemas/sandbox-config.schema.json +7 -3
  355. package/dist/cli/commands/accounts.d.ts +0 -2
  356. package/dist/cli/commands/accounts.js +0 -96
  357. package/dist/cli/commands/data/clean.d.ts +0 -3
  358. package/dist/cli/commands/data/clean.js +0 -60
  359. package/dist/cli/commands/data/index.d.ts +0 -4
  360. package/dist/cli/commands/data/index.js +0 -62
  361. package/dist/cli/commands/maintenance/clean.d.ts +0 -2
  362. package/dist/cli/commands/maintenance/clean.js +0 -24
  363. package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
  364. package/dist/cli/commands/maintenance/config-share.js +0 -80
  365. package/dist/cli/commands/projects/projects.d.ts +0 -2
  366. package/dist/cli/commands/projects/projects.js +0 -162
  367. package/dist/cli/commands/storage/contained.d.ts +0 -3
  368. package/dist/cli/commands/storage/contained.js +0 -179
  369. package/dist/cli/commands/storage/storage.d.ts +0 -8
  370. package/dist/cli/commands/storage/storage.js +0 -179
  371. package/dist/cli/menu/add-agent.d.ts +0 -47
  372. package/dist/cli/menu/add-agent.js +0 -168
  373. package/dist/cli/menu/apps.d.ts +0 -69
  374. package/dist/cli/menu/apps.js +0 -214
  375. package/dist/cli/menu/data-folder.d.ts +0 -18
  376. package/dist/cli/menu/data-folder.js +0 -99
  377. package/dist/cli/menu/share-settings.d.ts +0 -21
  378. package/dist/cli/menu/share-settings.js +0 -112
  379. package/dist/cli/menu/vpn-login.d.ts +0 -16
  380. package/dist/cli/menu/vpn-login.js +0 -74
  381. package/dist/web/main-NRRS5O6Z.js +0 -157
  382. /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
  383. /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,28 @@ 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
+ }
29269
+ var GH_NOTE = " (log in once with: gh auth login --web --insecure-storage; it is kept between sandboxes)";
29270
+ function warnKeyringLogin() {
29271
+ try {
29272
+ const hosts = fs28.readFileSync(path34.join(ghConfigDir(), "hosts.yml"), "utf8");
29273
+ if (/^\s*user:/m.test(hosts) && !/oauth_token:/.test(hosts))
29274
+ warn(
29275
+ "gh: the GitHub login from an earlier sandbox was kept in Windows Credential Manager, which is wiped with each sandbox. Log in again with: gh auth login --web --insecure-storage (then it lasts)."
29276
+ );
29277
+ } catch {
29278
+ }
29279
+ }
29237
29280
  var toolVars = {
29238
29281
  gh: () => ({
29239
- GH_CONFIG_DIR: mkdirp(ghConfigDir()),
29282
+ GH_CONFIG_DIR: exists(deliveredGhConfigDir()) ? deliveredGhConfigDir() : mkdirp(ghConfigDir()),
29240
29283
  GH_NO_UPDATE_NOTIFIER: "1",
29241
29284
  GH_NO_EXTENSION_UPDATE_NOTIFIER: "1"
29242
29285
  })
@@ -29274,9 +29317,11 @@ async function setupCli(env, settings, gitAccess, refresh = false) {
29274
29317
  await setupSingleExe(env, name, entry.repo, entry.asset(arch), entry.exe, tool("cli", name), {
29275
29318
  refresh,
29276
29319
  subdir: entry.subdir,
29277
- size: entry.size
29320
+ size: entry.size,
29321
+ ...name === "gh" ? { note: GH_NOTE } : {}
29278
29322
  });
29279
29323
  Object.assign(env.vars, toolVars[name]?.() ?? {});
29324
+ if (name === "gh") warnKeyringLogin();
29280
29325
  } catch (e) {
29281
29326
  warn(name + " could not be set up and is skipped; the other tools are not affected. Reason: " + errMsg(e));
29282
29327
  env.summary.push(entry.name + ": FAILED");
@@ -30082,6 +30127,10 @@ var activate = async (version2) => {
30082
30127
  fs36.rmSync(NVM_SYMLINK, { recursive: true, force: true });
30083
30128
  fs36.symlinkSync(path45.join(NVM_HOME, "v" + version2), NVM_SYMLINK, "junction");
30084
30129
  };
30130
+ var PLAYWRIGHT_VARS = () => ({
30131
+ PLAYWRIGHT_BROWSERS_PATH: tool("ms-playwright"),
30132
+ PLAYWRIGHT_MCP_BROWSER: "msedge"
30133
+ });
30085
30134
  async function setupNode(env, versions, config2) {
30086
30135
  if (dryRun) {
30087
30136
  log("(dry run) would provision nvm and Node " + versions.node.spec + " (from " + versions.node.source + ")");
@@ -30115,13 +30164,14 @@ async function setupNode(env, versions, config2) {
30115
30164
  warn("Node " + version2 + " from this PC: " + errMsg(e));
30116
30165
  }
30117
30166
  }
30118
- Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK });
30167
+ Object.assign(env.vars, { NVM_HOME, NVM_SYMLINK, ...PLAYWRIGHT_VARS() });
30119
30168
  if (duringSession()) env.prepend.push(path45.join(NVM_HOME, "v" + main), NVM_HOME, NVM_SYMLINK);
30120
30169
  else {
30121
30170
  await activate(main);
30122
30171
  env.prepend.push(NVM_HOME, NVM_SYMLINK);
30123
30172
  }
30124
30173
  env.summary.push("node: " + main + " (from " + versions.node.source + ", switch with nvm use)");
30174
+ env.summary.push("playwright: ready (Edge; browsers it downloads are kept; in tests use channel: 'msedge')");
30125
30175
  await packageManagers(env, config2, main);
30126
30176
  }
30127
30177
  var packageManagers = async (env, config2, version2) => {
@@ -32032,11 +32082,17 @@ import os8 from "node:os";
32032
32082
  import path51 from "node:path";
32033
32083
 
32034
32084
  // src/shared/memory/policy.ts
32085
+ function buildJobs(cpus, memoryGb) {
32086
+ return Math.max(2, Math.min(cpus, Math.floor((memoryGb - 6) / 3)));
32087
+ }
32088
+ function linkSlotsFor(memoryGb) {
32089
+ return Math.max(2, Math.min(8, Math.floor((memoryGb - 6) / 3)));
32090
+ }
32035
32091
  function cargoJobs(cpus, memoryGb, sessions) {
32036
- const byCpu = Math.max(2, Math.min(4, Math.floor(cpus / 4)));
32092
+ const byCpu = Math.max(2, Math.min(8, Math.floor(cpus / 4)));
32037
32093
  const byMemory = Math.max(1, Math.floor(memoryGb / 4));
32038
32094
  const jobs = Math.min(byCpu, byMemory);
32039
- return Math.max(1, Math.min(jobs, Math.floor(8 / Math.max(1, sessions))));
32095
+ return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions))));
32040
32096
  }
32041
32097
 
32042
32098
  // src/guest/toolchains/native/rust-extras.ts
@@ -32059,7 +32115,7 @@ function linkGate(env, rust, host) {
32059
32115
  const gate = path51.join(mkdirp(tool("shims")), "linkgate.exe");
32060
32116
  fs41.copyFileSync(ensureCompiled("linkgate"), gate);
32061
32117
  const memoryGb = os8.totalmem() / 1024 ** 3;
32062
- const slots = rust.linkSlots === "auto" ? Math.max(2, Math.min(4, Math.floor(memoryGb / 8))) : rust.linkSlots;
32118
+ const slots = rust.linkSlots === "auto" ? linkSlotsFor(memoryGb) : rust.linkSlots;
32063
32119
  env.vars.AGENT_LINK_SLOTS = String(slots);
32064
32120
  env.vars.AGENT_REAL_LINKER = gcc;
32065
32121
  env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gate;
@@ -33170,14 +33226,14 @@ var problems = [];
33170
33226
  function networkProblems() {
33171
33227
  return problems;
33172
33228
  }
33173
- var longPath = (file3) => {
33229
+ function longPath(file3) {
33174
33230
  if (!hasShortName(file3)) return file3;
33175
33231
  try {
33176
33232
  return fs48.realpathSync.native(file3);
33177
33233
  } catch {
33178
33234
  return file3;
33179
33235
  }
33180
- };
33236
+ }
33181
33237
  async function applyAttachRule(ptyHostExe) {
33182
33238
  if (!session.attach.enabled) return;
33183
33239
  if (!ptyHostExe) {
@@ -33210,9 +33266,9 @@ async function applyNetworkPolicy(ptyHostExe) {
33210
33266
  log("Networking is disabled for this sandbox.");
33211
33267
  return "offline";
33212
33268
  }
33213
- const block = session.network.blockPrivateRanges;
33214
- const exempt = block ? discoverExemptIps() : [];
33215
- const lanRules = block ? buildFirewallCommands(exempt) : [];
33269
+ const block2 = session.network.blockPrivateRanges;
33270
+ const exempt = block2 ? discoverExemptIps() : [];
33271
+ const lanRules = block2 ? buildFirewallCommands(exempt) : [];
33216
33272
  const forwardRules = forwardRule();
33217
33273
  const commands = [
33218
33274
  ...lanRules,
@@ -33231,18 +33287,18 @@ async function applyNetworkPolicy(ptyHostExe) {
33231
33287
  warn("network.dns could not be applied: " + errMsg(e));
33232
33288
  }
33233
33289
  }
33234
- if (!block) log("Private-range blocking disabled by config.");
33235
- if (block)
33290
+ if (!block2) log("Private-range blocking disabled by config.");
33291
+ if (block2)
33236
33292
  log(
33237
33293
  "Gateway/DNS addresses kept reachable for DNS only: " + (exempt.length ? [...new Set(exempt)].join(", ") : "(none found)")
33238
33294
  );
33239
33295
  if (!isWin || dryRun) {
33240
33296
  log("(dry run) firewall plan:");
33241
33297
  for (const c of commands) log(" netsh " + c.join(" "));
33242
- return block ? "blocked" : "open";
33298
+ return block2 ? "blocked" : "open";
33243
33299
  }
33244
33300
  if (commands.length === 0) return "open";
33245
- const online = block ? await waitForInternet(30) : true;
33301
+ const online = block2 ? await waitForInternet(30) : true;
33246
33302
  const failures = [];
33247
33303
  try {
33248
33304
  run2(lanRules);
@@ -33257,7 +33313,7 @@ async function applyNetworkPolicy(ptyHostExe) {
33257
33313
  warn("PROTECTION MISSING: " + problems[problems.length - 1]);
33258
33314
  }
33259
33315
  if (failures.length) throw new Error(failures[0]);
33260
- if (!block) return "open";
33316
+ if (!block2) return "open";
33261
33317
  if (online && !await waitForInternet(15)) {
33262
33318
  run2(lanRules.filter((c) => c[2] === "delete"));
33263
33319
  warn(
@@ -33487,18 +33543,109 @@ function setupGitConfig(env) {
33487
33543
  spawnSync7(git, ["config", "--global", "core.autocrlf", "input"], { env: rest, windowsHide: true, stdio: "ignore" });
33488
33544
  }
33489
33545
 
33546
+ // src/guest/setup/github-token.ts
33547
+ import fs53 from "node:fs";
33548
+ import { spawnSync as spawnSync8 } from "node:child_process";
33549
+
33550
+ // src/shared/github/token.ts
33551
+ var MIN_LENGTH = 20;
33552
+ var MAX_LENGTH = 255;
33553
+ var PRINTABLE = /^[\x21-\x7e]+$/;
33554
+ var GithubTokenSchema = external_exports.string().min(MIN_LENGTH).max(MAX_LENGTH).regex(PRINTABLE);
33555
+ var TOKEN_VARIABLES = /^(GH_TOKEN|GITHUB_TOKEN|GH_ENTERPRISE_TOKEN|GITHUB_ENTERPRISE_TOKEN)$/i;
33556
+ var ghEnv = (base, configDir) => ({
33557
+ ...Object.fromEntries(
33558
+ Object.entries(base).filter((e) => e[1] !== void 0 && !TOKEN_VARIABLES.test(e[0]))
33559
+ ),
33560
+ GH_CONFIG_DIR: configDir,
33561
+ GH_PROMPT_DISABLED: "1",
33562
+ GH_NO_UPDATE_NOTIFIER: "1"
33563
+ });
33564
+ function ghLoginCommand(ghExe, configDir, token, base) {
33565
+ return {
33566
+ file: ghExe,
33567
+ args: [
33568
+ "auth",
33569
+ "login",
33570
+ "--hostname",
33571
+ "github.com",
33572
+ "--git-protocol",
33573
+ "https",
33574
+ "--insecure-storage",
33575
+ "--with-token"
33576
+ ],
33577
+ input: token + "\n",
33578
+ env: ghEnv(base, configDir)
33579
+ };
33580
+ }
33581
+ function ghSetupGitCommand(ghExe, configDir, base) {
33582
+ return { file: ghExe, args: ["auth", "setup-git", "--hostname", "github.com"], env: ghEnv(base, configDir) };
33583
+ }
33584
+ function ghOutputText(text, token) {
33585
+ const clean = token ? text.split(token).join("***") : text;
33586
+ return clean.replace(/\s+/g, " ").trim().slice(0, 300);
33587
+ }
33588
+
33589
+ // src/guest/setup/github-token.ts
33590
+ var GH_TIMEOUT_MS = 6e4;
33591
+ function prepareGithubFolder(token) {
33592
+ const dir = deliveredGhConfigDir();
33593
+ fs53.rmSync(dir, { recursive: true, force: true });
33594
+ if (!token) return false;
33595
+ mkdirp(dir);
33596
+ return true;
33597
+ }
33598
+ function runGh(command, token, what) {
33599
+ const result = spawnSync8(command.file, [...command.args], {
33600
+ env: command.env,
33601
+ encoding: "utf8",
33602
+ windowsHide: true,
33603
+ timeout: GH_TIMEOUT_MS,
33604
+ stdio: ["pipe", "pipe", "pipe"],
33605
+ ...command.input !== void 0 ? { input: command.input } : {}
33606
+ });
33607
+ if (result.error) throw new Error(what + " could not run: " + ghOutputText(result.error.message, token));
33608
+ if (result.status !== 0)
33609
+ throw new Error(
33610
+ what + " failed: " + ghOutputText(String(result.stderr ?? "") || String(result.stdout ?? ""), token)
33611
+ );
33612
+ }
33613
+ function loginGithub(token, env) {
33614
+ if (dryRun) {
33615
+ log("(dry run) would log gh in with the GitHub token from your PC");
33616
+ return;
33617
+ }
33618
+ const gh2 = ghExePath();
33619
+ const dir = deliveredGhConfigDir();
33620
+ if (!exists(gh2) || env.GH_CONFIG_DIR !== dir) {
33621
+ fs53.rmSync(dir, { recursive: true, force: true });
33622
+ log("A GitHub token arrived, but gh is not set up in this sandbox (toolchains.cli.gh), so it is not used.");
33623
+ return;
33624
+ }
33625
+ try {
33626
+ runGh(ghLoginCommand(gh2, dir, token, env), token, "gh auth login");
33627
+ runGh(ghSetupGitCommand(gh2, dir, env), token, "gh auth setup-git");
33628
+ } catch (e) {
33629
+ fs53.rmSync(dir, { recursive: true, force: true });
33630
+ env.GH_CONFIG_DIR = mkdirp(ghConfigDir());
33631
+ addMachineEnvironment({ GH_CONFIG_DIR: env.GH_CONFIG_DIR }, []);
33632
+ throw e;
33633
+ }
33634
+ log("gh and https git to github.com use the GitHub token from your PC (github.shareToken); the agent can read it.");
33635
+ }
33636
+
33490
33637
  // src/guest/sessions/pty-host.ts
33491
33638
  function ensurePtyHost() {
33492
33639
  return ensureCompiled("ptyhost");
33493
33640
  }
33494
33641
 
33495
33642
  // src/guest/toolchains/leftovers.ts
33496
- import fs53 from "node:fs";
33643
+ import fs54 from "node:fs";
33497
33644
  import path66 from "node:path";
33498
33645
  var STAGING = /\.staging-[0-9a-f]+$/i;
33499
33646
  var entries2 = (dir) => {
33500
33647
  try {
33501
- return fs53.readdirSync(dir, { withFileTypes: true });
33648
+ return fs54.readdirSync(dir, { withFileTypes: true });
33502
33649
  } catch {
33503
33650
  return [];
33504
33651
  }
@@ -33515,17 +33662,17 @@ function pruneToolLeftovers() {
33515
33662
 
33516
33663
  // src/guest/audit/process-audit.ts
33517
33664
  import path67 from "node:path";
33518
- import { spawnSync as spawnSync8 } from "node:child_process";
33665
+ import { spawnSync as spawnSync9 } from "node:child_process";
33519
33666
  var PROCESS_CREATION = "{0CCE922B-69AE-11D9-BED3-505054503030}";
33520
33667
  var auditOn = () => Boolean(session.auditProcesses) && isWin && !dryRun;
33521
33668
  function enableProcessAudit() {
33522
33669
  if (!auditOn()) return;
33523
- spawnSync8(
33670
+ spawnSync9(
33524
33671
  path67.join(process.env.WINDIR ?? "C:\\Windows", "System32", "auditpol.exe"),
33525
33672
  ["/set", "/subcategory:" + PROCESS_CREATION, "/success:enable"],
33526
33673
  { windowsHide: true, stdio: "ignore" }
33527
33674
  );
33528
- spawnSync8(
33675
+ spawnSync9(
33529
33676
  SYSTEM.reg(),
33530
33677
  [
33531
33678
  "add",
@@ -33545,7 +33692,8 @@ function enableProcessAudit() {
33545
33692
 
33546
33693
  // src/guest/vpn/vpn.ts
33547
33694
  import dns2 from "node:dns";
33548
- import fs57 from "node:fs";
33695
+ import fs58 from "node:fs";
33696
+ import net3 from "node:net";
33549
33697
  import os14 from "node:os";
33550
33698
  import path71 from "node:path";
33551
33699
 
@@ -33710,13 +33858,13 @@ function inspectOvpn(text) {
33710
33858
  if (text.includes("\0")) return { ok: false, problems: ["the file is not text"] };
33711
33859
  const lines = text.split(/\r?\n/);
33712
33860
  if (lines.length > MAX_LINES) return { ok: false, problems: ["the file has too many lines"] };
33713
- let block = null;
33861
+ let block2 = null;
33714
33862
  let defaultProto = "udp";
33715
33863
  lines.forEach((line, i) => {
33716
33864
  const at = "line " + (i + 1) + ": ";
33717
33865
  const trimmed = line.trim();
33718
- if (block) {
33719
- if (trimmed.toLowerCase() === "</" + block + ">") block = null;
33866
+ if (block2) {
33867
+ if (trimmed.toLowerCase() === "</" + block2 + ">") block2 = null;
33720
33868
  else if (/^<\/?[A-Za-z-]+>$/.test(trimmed)) refuse(at + "a section inside a section");
33721
33869
  return;
33722
33870
  }
@@ -33724,7 +33872,7 @@ function inspectOvpn(text) {
33724
33872
  if (open2) {
33725
33873
  const tag = open2[1].toLowerCase();
33726
33874
  if (!BLOCKS.has(tag)) refuse(at + "<" + tag + "> is not allowed");
33727
- block = tag;
33875
+ block2 = tag;
33728
33876
  return;
33729
33877
  }
33730
33878
  const d = directiveOf(line);
@@ -33749,7 +33897,7 @@ function inspectOvpn(text) {
33749
33897
  }
33750
33898
  });
33751
33899
  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");
33900
+ if (block2) refuse("a <" + block2 + "> section is never closed");
33753
33901
  if (remotes.length === 0) refuse("it names no remote server");
33754
33902
  if (remotes.length > 64) refuse("it names too many servers");
33755
33903
  return problems2.length ? { ok: false, problems: problems2 } : { ok: true, remotes };
@@ -33958,8 +34106,22 @@ var drop = (name) => [
33958
34106
  "rule",
33959
34107
  "name=" + VPN_RULE_PREFIX + name
33960
34108
  ];
34109
+ var block = (name, extra) => [
34110
+ "advfirewall",
34111
+ "firewall",
34112
+ "add",
34113
+ "rule",
34114
+ "name=" + VPN_RULE_PREFIX + name,
34115
+ "dir=out",
34116
+ "action=block",
34117
+ "enable=yes",
34118
+ "profile=any",
34119
+ ...extra
34120
+ ];
34121
+ var BLOCK_RULES = ["Block-Internet", "Block-IPv6", "Block-DNS-UDP", "Block-DNS-TCP"];
33961
34122
  function ruleNames(serverCount) {
33962
34123
  return [
34124
+ ...BLOCK_RULES,
33963
34125
  "Loopback",
33964
34126
  "DHCP",
33965
34127
  "Host",
@@ -33967,6 +34129,39 @@ function ruleNames(serverCount) {
33967
34129
  ...Array.from({ length: Math.max(serverCount, 0) }, (_v, i) => "Server-" + (i + 1))
33968
34130
  ];
33969
34131
  }
34132
+ var NOT_INTERNET = [
34133
+ ["0.0.0.0", "0.255.255.255"],
34134
+ ["10.0.0.0", "10.255.255.255"],
34135
+ ["100.64.0.0", "100.127.255.255"],
34136
+ ["127.0.0.0", "127.255.255.255"],
34137
+ ["169.254.0.0", "169.254.255.255"],
34138
+ ["172.16.0.0", "172.31.255.255"],
34139
+ ["192.168.0.0", "192.168.255.255"],
34140
+ ["224.0.0.0", "255.255.255.255"]
34141
+ ];
34142
+ var LAST_IPV4 = 4294967295;
34143
+ function ipNumber(ip) {
34144
+ return ip.split(".").reduce((n, part) => n * 256 + Number(part), 0);
34145
+ }
34146
+ function ipText(n) {
34147
+ return [24, 16, 8, 0].map((shift) => Math.floor(n / 2 ** shift) % 256).join(".");
34148
+ }
34149
+ function ipv4Except(excluded) {
34150
+ const sorted = [...excluded].sort((a, b) => a[0] - b[0]);
34151
+ const out = [];
34152
+ let next = 0;
34153
+ for (const [from, to] of sorted) {
34154
+ if (from > next) out.push(ipText(next) + "-" + ipText(from - 1));
34155
+ next = Math.max(next, to + 1);
34156
+ }
34157
+ if (next <= LAST_IPV4) out.push(ipText(next) + "-" + ipText(LAST_IPV4));
34158
+ return out.join(",");
34159
+ }
34160
+ function internetExcept(servers) {
34161
+ const ranges = NOT_INTERNET.map(([a, b]) => [ipNumber(a), ipNumber(b)]);
34162
+ for (const s of cleanServers(servers)) ranges.push([ipNumber(s.ip), ipNumber(s.ip)]);
34163
+ return ipv4Except(ranges);
34164
+ }
33970
34165
  function cleanServers(servers) {
33971
34166
  const seen = /* @__PURE__ */ new Set();
33972
34167
  return servers.filter((s) => {
@@ -33981,6 +34176,10 @@ function killSwitchCommands(servers, ptyHostExe) {
33981
34176
  return [
33982
34177
  ...ruleNames(Math.max(list.length, 8)).map(drop),
33983
34178
  ["advfirewall", "set", "allprofiles", "state", "on"],
34179
+ block("Block-Internet", ["protocol=any", "remoteip=" + internetExcept(list)]),
34180
+ block("Block-IPv6", ["protocol=any", "remoteip=2000::/3"]),
34181
+ block("Block-DNS-UDP", ["protocol=udp", "remoteport=53"]),
34182
+ block("Block-DNS-TCP", ["protocol=tcp", "remoteport=53"]),
33984
34183
  ["advfirewall", "set", "allprofiles", "firewallpolicy", "blockinbound,blockoutbound"],
33985
34184
  rule("Loopback", ["protocol=any", "remoteip=127.0.0.0/8"]),
33986
34185
  rule("DHCP", ["protocol=udp", "localport=68", "remoteport=67"]),
@@ -33992,7 +34191,21 @@ function killSwitchCommands(servers, ptyHostExe) {
33992
34191
  }
33993
34192
  function tunnelCommands(tunnelIp) {
33994
34193
  if (!isIPv4(tunnelIp)) throw new Error("Not an IPv4 address: " + tunnelIp);
33995
- return [drop("Tunnel"), rule("Tunnel", ["protocol=any", "localip=" + tunnelIp])];
34194
+ const n = ipNumber(tunnelIp);
34195
+ const notTunnel = ipv4Except([[n, n]]);
34196
+ return [
34197
+ ...["Block-Internet", "Block-DNS-UDP", "Block-DNS-TCP"].map((name) => [
34198
+ "advfirewall",
34199
+ "firewall",
34200
+ "set",
34201
+ "rule",
34202
+ "name=" + VPN_RULE_PREFIX + name,
34203
+ "new",
34204
+ "localip=" + notTunnel
34205
+ ]),
34206
+ drop("Tunnel"),
34207
+ rule("Tunnel", ["protocol=any", "localip=" + tunnelIp])
34208
+ ];
33996
34209
  }
33997
34210
  function tunnelAddressFromLog(log2) {
33998
34211
  const add = /net_addr_v4_add:\s*(\d{1,3}(?:\.\d{1,3}){3})\/\d+/.exec(log2);
@@ -34005,7 +34218,7 @@ function tunnelAddressFromLog(log2) {
34005
34218
 
34006
34219
  // src/guest/vpn/openvpn.ts
34007
34220
  import crypto4 from "node:crypto";
34008
- import fs54 from "node:fs";
34221
+ import fs55 from "node:fs";
34009
34222
  import path68 from "node:path";
34010
34223
 
34011
34224
  // src/shared/vpn/download.ts
@@ -34042,7 +34255,12 @@ function openvpnDownload(arch2 = process.arch) {
34042
34255
  const entry = arch2 === "arm64" ? OPENVPN_MSI.arm64 : OPENVPN_MSI.x64;
34043
34256
  return { ...entry, url: OPENVPN_MSI.base + entry.file };
34044
34257
  }
34045
- var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs54.readFileSync(file3)).digest("hex") === sha256;
34258
+ function repairServiceQueries() {
34259
+ const did = scriptOutput("repair-wmi-services.ps1");
34260
+ if (did === "removed") log("VPN: repaired the Windows service queries installers use (a Windows Sandbox gap).");
34261
+ else if (did !== "absent" && did !== "kept") warn("VPN: could not check the Windows service queries installers use.");
34262
+ }
34263
+ var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs55.readFileSync(file3)).digest("hex") === sha256;
34046
34264
  async function ensureOpenVpn() {
34047
34265
  const exe = openvpnExe();
34048
34266
  if (!isWin || dryRun) return exe;
@@ -34053,6 +34271,7 @@ async function ensureOpenVpn() {
34053
34271
  log("VPN: downloading OpenVPN " + OPENVPN_MSI.version + " (about 6 MB)");
34054
34272
  await downloader.file(dl.url, msi, dl.sha256);
34055
34273
  }
34274
+ repairServiceQueries();
34056
34275
  log("VPN: installing OpenVPN");
34057
34276
  const logFile2 = path68.join(toolsDir, "downloads", "openvpn-install.log");
34058
34277
  const code = await spawnAsync(SYSTEM.msiexec(), ["/i", msi, "/qn", "/norestart", "/l*v", logFile2], {
@@ -34066,7 +34285,7 @@ async function ensureOpenVpn() {
34066
34285
 
34067
34286
  // src/guest/vpn/tunnel.ts
34068
34287
  import { spawn as spawn7 } from "node:child_process";
34069
- import fs55 from "node:fs";
34288
+ import fs56 from "node:fs";
34070
34289
  import os12 from "node:os";
34071
34290
  import path69 from "node:path";
34072
34291
  var DONE = "Initialization Sequence Completed";
@@ -34084,17 +34303,17 @@ function failureReason(text) {
34084
34303
  }
34085
34304
  var tail = (text, lines = 12) => text.trim().split(/\r?\n/).slice(-lines).join("\n");
34086
34305
  async function startTunnel(o) {
34087
- const dir = fs55.mkdtempSync(path69.join(os12.tmpdir(), "sbx-vpn-"));
34306
+ const dir = fs56.mkdtempSync(path69.join(os12.tmpdir(), "sbx-vpn-"));
34088
34307
  const auth = path69.join(dir, "login.txt");
34089
34308
  const logFile2 = path69.join(dir, "openvpn.log");
34090
34309
  const keepLog = () => {
34091
34310
  try {
34092
- fs55.mkdirSync(logsDir, { recursive: true });
34093
- fs55.copyFileSync(logFile2, path69.join(logsDir, "openvpn.log"));
34311
+ fs56.mkdirSync(logsDir, { recursive: true });
34312
+ fs56.copyFileSync(logFile2, path69.join(logsDir, "openvpn.log"));
34094
34313
  } catch {
34095
34314
  }
34096
34315
  };
34097
- fs55.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
34316
+ fs56.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
34098
34317
  try {
34099
34318
  const child = spawn7(
34100
34319
  o.exe,
@@ -34112,7 +34331,7 @@ async function startTunnel(o) {
34112
34331
  child.unref();
34113
34332
  const deadline = Date.now() + (o.timeoutMs ?? 9e4);
34114
34333
  for (; ; ) {
34115
- const text = fs55.existsSync(logFile2) ? fs55.readFileSync(logFile2, "utf8") : "";
34334
+ const text = fs56.existsSync(logFile2) ? fs56.readFileSync(logFile2, "utf8") : "";
34116
34335
  if (text.includes(DONE)) {
34117
34336
  keepLog();
34118
34337
  const tunnelIp = tunnelAddressFromLog(text) ?? void 0;
@@ -34132,14 +34351,14 @@ async function startTunnel(o) {
34132
34351
  await new Promise((r) => setTimeout(r, 500));
34133
34352
  }
34134
34353
  } finally {
34135
- fs55.rmSync(auth, { force: true });
34354
+ fs56.rmSync(auth, { force: true });
34136
34355
  }
34137
34356
  }
34138
34357
 
34139
34358
  // src/guest/vpn/wireguard.ts
34140
34359
  import { execFile } from "node:child_process";
34141
34360
  import crypto5 from "node:crypto";
34142
- import fs56 from "node:fs";
34361
+ import fs57 from "node:fs";
34143
34362
  import os13 from "node:os";
34144
34363
  import path70 from "node:path";
34145
34364
  var WIREGUARD_TUNNEL = "sandbox";
@@ -34153,7 +34372,7 @@ function wireguardDownload(arch2 = process.arch) {
34153
34372
  const entry = arch2 === "arm64" ? WIREGUARD_MSI.arm64 : WIREGUARD_MSI.x64;
34154
34373
  return { ...entry, url: WIREGUARD_MSI.base + entry.file };
34155
34374
  }
34156
- var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(fs56.readFileSync(file3)).digest("hex") === sha256;
34375
+ var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(fs57.readFileSync(file3)).digest("hex") === sha256;
34157
34376
  async function ensureWireguard() {
34158
34377
  const exe = wireguardExe();
34159
34378
  if (!isWin || dryRun) return exe;
@@ -34164,6 +34383,7 @@ async function ensureWireguard() {
34164
34383
  log("VPN: downloading WireGuard " + WIREGUARD_MSI.version + " (about 3 MB)");
34165
34384
  await downloader.file(dl.url, msi, dl.sha256);
34166
34385
  }
34386
+ repairServiceQueries();
34167
34387
  log("VPN: installing WireGuard");
34168
34388
  const logFile2 = path70.join(toolsDir, "downloads", "wireguard-install.log");
34169
34389
  const code = await spawnAsync(
@@ -34198,9 +34418,9 @@ async function removeWireguardTunnel(exe) {
34198
34418
  }
34199
34419
  async function startWireguardTunnel(o) {
34200
34420
  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-"));
34421
+ const dir = fs57.mkdtempSync(path70.join(fs57.existsSync(root) ? root : os13.tmpdir(), "sbx-wg-"));
34202
34422
  const file3 = path70.join(dir, WIREGUARD_TUNNEL + ".conf");
34203
- fs56.writeFileSync(file3, o.config, "utf8");
34423
+ fs57.writeFileSync(file3, o.config, "utf8");
34204
34424
  const fail = async (message) => {
34205
34425
  await removeWireguardTunnel(o.exe);
34206
34426
  return { ok: false, message };
@@ -34221,7 +34441,7 @@ async function startWireguardTunnel(o) {
34221
34441
  await sleep(500);
34222
34442
  }
34223
34443
  } finally {
34224
- fs56.rmSync(dir, { recursive: true, force: true });
34444
+ fs57.rmSync(dir, { recursive: true, force: true });
34225
34445
  }
34226
34446
  }
34227
34447
  async function waitForHandshake(exe, poke, timeoutMs = 3e4) {
@@ -34290,15 +34510,47 @@ async function publicAddress() {
34290
34510
  }
34291
34511
  }
34292
34512
  var hasAdapter2 = (ip) => Object.values(os14.networkInterfaces()).some((list) => (list ?? []).some((i) => i.address === ip));
34513
+ var PROBE_TARGETS = ["1.1.1.1", "8.8.8.8", "9.9.9.9"];
34514
+ var PROBE_TIMEOUT_MS = 3e3;
34515
+ function connects(ip, port) {
34516
+ return new Promise((resolve2) => {
34517
+ const socket = net3.connect({ host: ip, port });
34518
+ const done = (ok) => {
34519
+ socket.destroy();
34520
+ resolve2(ok);
34521
+ };
34522
+ socket.setTimeout(PROBE_TIMEOUT_MS, () => done(false));
34523
+ socket.once("connect", () => done(true));
34524
+ socket.once("error", () => done(false));
34525
+ });
34526
+ }
34527
+ async function directConnectionBlocked(servers) {
34528
+ const targets = PROBE_TARGETS.filter((ip) => !servers.some((s) => s.ip === ip));
34529
+ const results = await Promise.all(targets.map((ip) => connects(ip, 443)));
34530
+ return !results.some(Boolean);
34531
+ }
34293
34532
  async function setupVpn(secrets, ptyHostExe) {
34294
34533
  const vpn = session.vpn;
34295
34534
  if (!vpn) return true;
34296
34535
  const killSwitch = vpn.killSwitch;
34297
34536
  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.");
34537
+ let held = false;
34538
+ const block2 = async (servers) => {
34539
+ if (!isWin || dryRun) {
34540
+ blocked = held = true;
34541
+ return;
34542
+ }
34543
+ try {
34544
+ run2(killSwitchCommands(servers, ptyHostExe ? longPath(ptyHostExe) : null));
34545
+ } finally {
34546
+ blocked = true;
34547
+ held = await directConnectionBlocked(servers);
34548
+ }
34549
+ if (held) log("VPN: kill switch on: nothing leaves the sandbox except through the tunnel (checked).");
34550
+ else
34551
+ warn(
34552
+ "VPN: the kill switch did not hold: a direct connection still got out. If the tunnel drops, traffic leaves through your normal connection."
34553
+ );
34302
34554
  };
34303
34555
  setVpnStatus("starting", "Starting the VPN");
34304
34556
  try {
@@ -34314,7 +34566,7 @@ async function setupVpn(secrets, ptyHostExe) {
34314
34566
  warn(
34315
34567
  "VPN: AllowedIPs does not include 0.0.0.0/0: with the kill switch on, only the tunnel traffic can leave the sandbox."
34316
34568
  );
34317
- if (killSwitch) block(servers);
34569
+ if (killSwitch) await block2(servers);
34318
34570
  if (dryRun || !isWin) {
34319
34571
  log("(dry run) would start the WireGuard tunnel " + vpn.server);
34320
34572
  setVpnStatus("off", "dry run");
@@ -34329,11 +34581,11 @@ async function setupVpn(secrets, ptyHostExe) {
34329
34581
  const credentials = secrets.vpn;
34330
34582
  if (!credentials) throw new Error("the VPN login did not arrive (start the sandbox again)");
34331
34583
  const profile = path71.join(launchDir, "vpn", "server.ovpn");
34332
- const remotes = assertSafeOvpn(fs57.readFileSync(profile, "utf8"), vpn.server);
34584
+ const remotes = assertSafeOvpn(fs58.readFileSync(profile, "utf8"), vpn.server);
34333
34585
  const exe = await ensureOpenVpn();
34334
34586
  const servers = await serverAddresses(remotes);
34335
34587
  if (servers.length === 0) throw new Error("the VPN server addresses could not be found");
34336
- if (killSwitch) block(servers);
34588
+ if (killSwitch) await block2(servers);
34337
34589
  if (dryRun || !isWin) {
34338
34590
  log("(dry run) would start the VPN tunnel to " + vpn.server);
34339
34591
  setVpnStatus("off", "dry run");
@@ -34352,18 +34604,21 @@ async function setupVpn(secrets, ptyHostExe) {
34352
34604
  throw new Error("the tunnel reported it was up, but no network adapter with its address appeared");
34353
34605
  const publicIp = await publicAddress();
34354
34606
  log("VPN: up" + (publicIp ? " (the sandbox appears as " + publicIp + ")" : "") + ".");
34355
- setVpnStatus("up", "The tunnel is up", publicIp ? { publicIp } : {});
34607
+ setVpnStatus("up", "The tunnel is up", {
34608
+ ...publicIp ? { publicIp } : {},
34609
+ ...killSwitch ? { killSwitchHeld: held } : {}
34610
+ });
34356
34611
  return true;
34357
34612
  } catch (e) {
34358
34613
  const reason = errMsg(e);
34359
34614
  try {
34360
- if (killSwitch && !blocked) block([]);
34615
+ if (killSwitch && !blocked) await block2([]);
34361
34616
  } catch (blockError) {
34362
34617
  warn("VPN: could not close the network after the failure: " + errMsg(blockError));
34363
34618
  }
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);
34619
+ 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.";
34620
+ warn("VPN failed: " + reason + after);
34621
+ setVpnStatus("failed", reason, killSwitch ? { killSwitchHeld: held } : {});
34367
34622
  return false;
34368
34623
  }
34369
34624
  }
@@ -34420,10 +34675,10 @@ var FrameReader = class {
34420
34675
  };
34421
34676
 
34422
34677
  // src/shared/pty/client.ts
34423
- import net3 from "node:net";
34678
+ import net4 from "node:net";
34424
34679
  var connectOnce = (host, port, timeoutMs) => {
34425
34680
  return new Promise((resolve2, reject) => {
34426
- const socket = net3.connect({ host, port });
34681
+ const socket = net4.connect({ host, port });
34427
34682
  const timer = setTimeout(() => {
34428
34683
  socket.destroy();
34429
34684
  reject(new Error("timed out connecting to " + host + ":" + port));
@@ -34644,6 +34899,36 @@ function unfinishedSequence(data) {
34644
34899
  return data.length;
34645
34900
  }
34646
34901
 
34902
+ // src/shared/pty/ctrl-c.ts
34903
+ var CTRL_C_CONFIRM_MS = 1500;
34904
+ var CTRL_C_HINT = "Ctrl+C again to send it to the program (Esc stops an agent)";
34905
+ var OSC_TITLE = /\x1b\][02];([^\x07\x1b]{0,256})(?:\x07|\x1b\\)/g;
34906
+ var CtrlCGuard = class {
34907
+ armedAt = Number.NEGATIVE_INFINITY;
34908
+ lastTitle = "";
34909
+ /** What to send for one read from the keyboard: a lone Ctrl+C only when another came just before. */
34910
+ push(chunk, nowMs) {
34911
+ if (chunk.length !== 1 || chunk[0] !== 3) return { send: chunk, held: false };
34912
+ if (nowMs - this.armedAt <= CTRL_C_CONFIRM_MS) {
34913
+ this.armedAt = Number.NEGATIVE_INFINITY;
34914
+ return { send: chunk, held: false };
34915
+ }
34916
+ this.armedAt = nowMs;
34917
+ return { send: Buffer.alloc(0), held: true };
34918
+ }
34919
+ /** Remembers the title the program last set (from its output), to put it back after the hint. */
34920
+ watchOutput(text) {
34921
+ for (const m of text.matchAll(OSC_TITLE)) this.lastTitle = m[1];
34922
+ }
34923
+ /** The escape sequence that shows the hint, and the one that puts the program's title back. */
34924
+ hintTitle() {
34925
+ return "\x1B]0;" + CTRL_C_HINT + "\x07";
34926
+ }
34927
+ restoreTitle() {
34928
+ return "\x1B]0;" + this.lastTitle.replace(/[\x00-\x1f\x7f]/g, "") + "\x07";
34929
+ }
34930
+ };
34931
+
34647
34932
  // src/shared/pty/terminal.ts
34648
34933
  var MOUSE_OFF = "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1005l\x1B[?1006l\x1B[?1015l";
34649
34934
  function fixWindowsKeys(chunk) {
@@ -34674,6 +34959,7 @@ function runTerminalClient(socket, token, options = {}) {
34674
34959
  clearInterval(heartbeat);
34675
34960
  clearInterval(sizeWatch);
34676
34961
  clearTimeout(joinTimer);
34962
+ clearTimeout(hintTimer);
34677
34963
  socket.destroy();
34678
34964
  stdout.write("\x1B[0m\x1B[?25h" + MOUSE_OFF + "\r\n");
34679
34965
  void (vtInput?.stop() ?? Promise.resolve()).then(() => {
@@ -34687,11 +34973,23 @@ function runTerminalClient(socket, token, options = {}) {
34687
34973
  const sendInput = (data) => {
34688
34974
  if (data.length && !done) socket.write(encodeFrame(FrameType.Input, swapKeys ? fixWindowsKeys(data) : data));
34689
34975
  };
34976
+ const guard = options.confirmCtrlC ? new CtrlCGuard() : null;
34977
+ let hintTimer;
34690
34978
  const onInput = (chunk) => {
34691
34979
  if (options.detachKey !== void 0 && chunk.includes(options.detachKey)) {
34692
34980
  finish({ reason: "detach" });
34693
34981
  return;
34694
34982
  }
34983
+ if (guard) {
34984
+ const decided = guard.push(chunk, Date.now());
34985
+ clearTimeout(hintTimer);
34986
+ if (decided.held) {
34987
+ stdout.write(guard.hintTitle());
34988
+ hintTimer = setTimeout(() => stdout.write(guard.restoreTitle()), CTRL_C_CONFIRM_MS);
34989
+ return;
34990
+ }
34991
+ if (decided.send.length === 1 && decided.send[0] === 3) stdout.write(guard.restoreTitle());
34992
+ }
34695
34993
  clearTimeout(joinTimer);
34696
34994
  sendInput(joiner.push(chunk));
34697
34995
  if (joiner.holding()) joinTimer = setTimeout(() => sendInput(joiner.flush()), JOIN_MS);
@@ -34724,8 +35022,11 @@ function runTerminalClient(socket, token, options = {}) {
34724
35022
  return;
34725
35023
  }
34726
35024
  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";
35025
+ if (frame.type === FrameType.Output) {
35026
+ const out = filter.push(frame.payload);
35027
+ guard?.watchOutput(out.toString("latin1"));
35028
+ stdout.write(out);
35029
+ } else if (frame.type === FrameType.Console) passthrough = frame.payload.toString("latin1") === "conpty.dll";
34729
35030
  else if (frame.type === FrameType.Restarting) stdout.write(MOUSE_OFF + "\x1B[2J\x1B[3J\x1B[H");
34730
35031
  else if (frame.type === FrameType.Exit)
34731
35032
  finish({ reason: "exit", exitCode: frame.payload.length >= 4 ? frame.payload.readInt32LE(0) : 1 });
@@ -34778,7 +35079,10 @@ async function viewSession(id) {
34778
35079
  return 1;
34779
35080
  }
34780
35081
  const socket = await connect({ ...session2.attach, addresses: ["127.0.0.1"] });
34781
- const result = await runTerminalClient(socket, session2.attach.token, { clipboardWrites: true });
35082
+ const result = await runTerminalClient(socket, session2.attach.token, {
35083
+ clipboardWrites: true,
35084
+ confirmCtrlC: session.attach.confirmCtrlC !== false
35085
+ });
34782
35086
  if (result.reason === "exit") console.log(session2.harness + " exited with code " + result.exitCode + ".");
34783
35087
  else if (result.reason === "error") console.log("Session error: " + result.message);
34784
35088
  return result.reason === "exit" ? result.exitCode : 1;
@@ -34833,7 +35137,7 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
34833
35137
  }
34834
35138
 
34835
35139
  // src/guest/runtime/secrets.ts
34836
- import fs58 from "node:fs";
35140
+ import fs59 from "node:fs";
34837
35141
 
34838
35142
  // src/shared/channel/secrets.ts
34839
35143
  var Environment = external_exports.record(external_exports.string().max(256), external_exports.string().max(65536));
@@ -34849,7 +35153,9 @@ var SecretsFileSchema = external_exports.strictObject({
34849
35153
  /** VPN service credentials (vpn.provider's login), only for the launch's own sandbox. */
34850
35154
  vpn: external_exports.strictObject({ username: external_exports.string().min(1).max(256), password: external_exports.string().min(1).max(1024) }).optional(),
34851
35155
  /** The checked WireGuard config of vpn.provider wireguard-file (holds the private key). */
34852
- wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional()
35156
+ wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional(),
35157
+ /** The GitHub token you saved for sandboxes (github.shareToken), only with git access "full". */
35158
+ githubToken: GithubTokenSchema.optional()
34853
35159
  });
34854
35160
 
34855
35161
  // src/guest/runtime/secrets.ts
@@ -34859,12 +35165,12 @@ function takeSecrets(id) {
34859
35165
  const file3 = run.secretFile(id);
34860
35166
  let text;
34861
35167
  try {
34862
- if (fs58.statSync(file3).size > MAX_BYTES) throw new Error("too big");
34863
- text = fs58.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
35168
+ if (fs59.statSync(file3).size > MAX_BYTES) throw new Error("too big");
35169
+ text = fs59.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
34864
35170
  } catch {
34865
35171
  return {};
34866
35172
  } finally {
34867
- fs58.rmSync(file3, { force: true });
35173
+ fs59.rmSync(file3, { force: true });
34868
35174
  }
34869
35175
  try {
34870
35176
  const parsed = SecretsFileSchema.safeParse(JSON.parse(text));
@@ -34917,7 +35223,7 @@ function startDaemon(env, secrets) {
34917
35223
  function writeDbCommand() {
34918
35224
  const dir = mkdirp(path73.join(localDir, "bin"));
34919
35225
  const db = path73.join(path73.dirname(process.argv[1]), "db.js");
34920
- fs59.writeFileSync(
35226
+ fs60.writeFileSync(
34921
35227
  path73.join(dir, "sbx-db.cmd"),
34922
35228
  '@setlocal\r\n@set AGENT_LOG_PREFIX=db\r\n@"' + process.execPath + '" "' + db + '" %*\r\n'
34923
35229
  );
@@ -34927,8 +35233,8 @@ function writeDbCommand() {
34927
35233
  function writeAgentCommands(dir) {
34928
35234
  const install = { node: process.execPath, script: path73.join(path73.dirname(process.argv[1]), "agent.js") };
34929
35235
  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));
35236
+ fs60.writeFileSync(path73.join(dir, shim3.command + ".cmd"), shimText(shim3, install));
35237
+ fs60.writeFileSync(path73.join(dir, "sbx-agent.cmd"), sbxAgentText(install));
34932
35238
  }
34933
35239
  async function waitForPrimary() {
34934
35240
  for (let i = 0; i < PRIMARY_POLLS; i++) {
@@ -34956,12 +35262,13 @@ var Boot = class {
34956
35262
  log(
34957
35263
  "Agent sandbox: " + session.project + " | workspace " + workspace + " | agent " + session.harnessName + " | log " + logPath
34958
35264
  );
34959
- if (!fs59.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
35265
+ if (!fs60.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
34960
35266
  throw new Error("Workspace folder is missing in the sandbox: " + workspace);
34961
35267
  mkdirp(toolsDir);
34962
35268
  mkdirp(run.root);
34963
35269
  this.secrets = takeSecrets(session.launchId);
34964
35270
  applyBootEnvironment(this.secrets.harnessEnvironment);
35271
+ prepareGithubFolder(this.secrets.githubToken);
34965
35272
  await this.networkAndSessionHost();
34966
35273
  await this.hooksAndDesktop();
34967
35274
  const { tools, env } = await this.developerTools();
@@ -35044,6 +35351,11 @@ var Boot = class {
35044
35351
  async gitIdentity(env) {
35045
35352
  step(5, "Git identity");
35046
35353
  await soft("Git config", () => setupGitConfig(env));
35354
+ const token = this.secrets.githubToken;
35355
+ if (token) {
35356
+ this.secrets = { ...this.secrets, githubToken: void 0 };
35357
+ await soft("GitHub token", () => loginGithub(token, env));
35358
+ }
35047
35359
  }
35048
35360
  async claude(tools) {
35049
35361
  step(6, "Claude settings, history and claude-mem");
@@ -35105,7 +35417,7 @@ runBoot().catch((e) => {
35105
35417
  const message = errMsg(e) + (e instanceof Error && e.stack ? "\n" + e.stack : "");
35106
35418
  try {
35107
35419
  setSandboxStatus("failed", errMsg(e));
35108
- fs60.writeFileSync(path74.join(logsDir, "guest-error.txt"), message);
35420
+ fs61.writeFileSync(path74.join(logsDir, "guest-error.txt"), message);
35109
35421
  } catch {
35110
35422
  }
35111
35423
  console.error(