windows-development-sandbox 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/README.md +1 -0
  2. package/config.example.json +17 -1
  3. package/dist/cli/args.d.ts +13 -2
  4. package/dist/cli/args.js +95 -24
  5. package/dist/cli/commands/accounts.js +45 -17
  6. package/dist/cli/commands/context.d.ts +2 -0
  7. package/dist/cli/commands/context.js +9 -2
  8. package/dist/cli/commands/data/clean.js +32 -9
  9. package/dist/cli/commands/index.d.ts +1 -0
  10. package/dist/cli/commands/index.js +1 -0
  11. package/dist/cli/commands/launch/add-root.d.ts +3 -2
  12. package/dist/cli/commands/launch/add-root.js +11 -10
  13. package/dist/cli/commands/launch/launch.js +57 -4
  14. package/dist/cli/commands/launch/prepare.js +3 -1
  15. package/dist/cli/commands/maintenance/audit.js +1 -1
  16. package/dist/cli/commands/maintenance/clean.d.ts +1 -1
  17. package/dist/cli/commands/maintenance/clean.js +17 -3
  18. package/dist/cli/commands/maintenance/config.d.ts +1 -1
  19. package/dist/cli/commands/maintenance/config.js +112 -10
  20. package/dist/cli/commands/maintenance/doctor.d.ts +1 -1
  21. package/dist/cli/commands/maintenance/doctor.js +2 -4
  22. package/dist/cli/commands/maintenance/migrate.d.ts +2 -1
  23. package/dist/cli/commands/maintenance/migrate.js +19 -4
  24. package/dist/cli/commands/maintenance/sync.js +2 -0
  25. package/dist/cli/commands/maintenance/update.d.ts +2 -0
  26. package/dist/cli/commands/maintenance/update.js +27 -4
  27. package/dist/cli/commands/projects/here.js +12 -7
  28. package/dist/cli/commands/projects/projects.js +26 -17
  29. package/dist/cli/commands/registry.js +7 -0
  30. package/dist/cli/commands/repair/checks/agents.d.ts +2 -0
  31. package/dist/cli/commands/repair/checks/agents.js +70 -0
  32. package/dist/cli/commands/repair/checks/common.d.ts +8 -0
  33. package/dist/cli/commands/repair/checks/common.js +22 -0
  34. package/dist/cli/commands/repair/checks/data.d.ts +2 -0
  35. package/dist/cli/commands/repair/checks/data.js +241 -0
  36. package/dist/cli/commands/repair/checks/index.d.ts +2 -0
  37. package/dist/cli/commands/repair/checks/index.js +20 -0
  38. package/dist/cli/commands/repair/checks/install.d.ts +5 -0
  39. package/dist/cli/commands/repair/checks/install.js +318 -0
  40. package/dist/cli/commands/repair/checks/machine.d.ts +2 -0
  41. package/dist/cli/commands/repair/checks/machine.js +232 -0
  42. package/dist/cli/commands/repair/checks/network.d.ts +6 -0
  43. package/dist/cli/commands/repair/checks/network.js +60 -0
  44. package/dist/cli/commands/repair/checks/pc.d.ts +4 -0
  45. package/dist/cli/commands/repair/checks/pc.js +55 -0
  46. package/dist/cli/commands/repair/checks/sandbox.d.ts +2 -0
  47. package/dist/cli/commands/repair/checks/sandbox.js +267 -0
  48. package/dist/cli/commands/repair/checks/settings.d.ts +2 -0
  49. package/dist/cli/commands/repair/checks/settings.js +169 -0
  50. package/dist/cli/commands/repair/checks/vpn.d.ts +2 -0
  51. package/dist/cli/commands/repair/checks/vpn.js +53 -0
  52. package/dist/cli/commands/repair/engine.d.ts +32 -0
  53. package/dist/cli/commands/repair/engine.js +127 -0
  54. package/dist/cli/commands/repair/env.d.ts +7 -0
  55. package/dist/cli/commands/repair/env.js +49 -0
  56. package/dist/cli/commands/repair/index.d.ts +1 -9
  57. package/dist/cli/commands/repair/index.js +2 -54
  58. package/dist/cli/commands/repair/log.d.ts +17 -0
  59. package/dist/cli/commands/repair/log.js +82 -0
  60. package/dist/cli/commands/repair/printer.d.ts +32 -0
  61. package/dist/cli/commands/repair/printer.js +132 -0
  62. package/dist/cli/commands/repair/run.d.ts +33 -0
  63. package/dist/cli/commands/repair/run.js +133 -0
  64. package/dist/cli/commands/repair/types.d.ts +97 -9
  65. package/dist/cli/commands/repair/types.js +11 -7
  66. package/dist/cli/commands/resume.js +2 -2
  67. package/dist/cli/commands/sessions/list.js +5 -2
  68. package/dist/cli/commands/sessions/status.d.ts +2 -0
  69. package/dist/cli/commands/sessions/status.js +27 -6
  70. package/dist/cli/commands/setup/index.d.ts +5 -0
  71. package/dist/cli/commands/setup/index.js +25 -1
  72. package/dist/cli/commands/storage/index.d.ts +2 -0
  73. package/dist/cli/commands/storage/index.js +2 -0
  74. package/dist/cli/commands/storage/offer.d.ts +3 -0
  75. package/dist/cli/commands/storage/offer.js +85 -0
  76. package/dist/cli/commands/storage/storage.d.ts +8 -0
  77. package/dist/cli/commands/storage/storage.js +171 -0
  78. package/dist/cli/commands/user-config.js +1 -1
  79. package/dist/cli/commands/vpn.d.ts +4 -0
  80. package/dist/cli/commands/vpn.js +75 -0
  81. package/dist/cli/commands/web.d.ts +4 -0
  82. package/dist/cli/commands/web.js +95 -0
  83. package/dist/cli/history.js +1 -1
  84. package/dist/cli/index.js +46 -3
  85. package/dist/cli/manifest.d.ts +303 -29
  86. package/dist/cli/manifest.js +173 -43
  87. package/dist/cli/menu/add-agent.d.ts +47 -0
  88. package/dist/cli/menu/add-agent.js +168 -0
  89. package/dist/cli/menu/apps.d.ts +31 -2
  90. package/dist/cli/menu/apps.js +44 -5
  91. package/dist/cli/menu/command-fields.d.ts +18 -0
  92. package/dist/cli/menu/command-fields.js +61 -0
  93. package/dist/cli/menu/command-form.d.ts +22 -0
  94. package/dist/cli/menu/command-form.js +169 -46
  95. package/dist/cli/menu/data-folder.d.ts +18 -0
  96. package/dist/cli/menu/data-folder.js +99 -0
  97. package/dist/cli/menu/menu.d.ts +1 -1
  98. package/dist/cli/menu/menu.js +11 -8
  99. package/dist/cli/menu/pages/accounts-page.js +55 -24
  100. package/dist/cli/menu/pages/agents-page.d.ts +66 -0
  101. package/dist/cli/menu/pages/agents-page.js +338 -0
  102. package/dist/cli/menu/pages/apps-page.js +1 -2
  103. package/dist/cli/menu/pages/list-page.d.ts +16 -3
  104. package/dist/cli/menu/pages/list-page.js +40 -8
  105. package/dist/cli/menu/pages/maintenance-page.d.ts +9 -0
  106. package/dist/cli/menu/pages/maintenance-page.js +161 -72
  107. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -0
  108. package/dist/cli/menu/pages/sandbox-page.js +132 -43
  109. package/dist/cli/menu/pages/sessions-page.d.ts +4 -0
  110. package/dist/cli/menu/pages/sessions-page.js +41 -25
  111. package/dist/cli/menu/pages/settings-page.d.ts +8 -4
  112. package/dist/cli/menu/pages/settings-page.js +36 -13
  113. package/dist/cli/menu/settings/categories.d.ts +2 -0
  114. package/dist/cli/menu/settings/categories.js +19 -44
  115. package/dist/cli/menu/settings/collections/collection-editor.d.ts +7 -1
  116. package/dist/cli/menu/settings/collections/collection-editor.js +12 -8
  117. package/dist/cli/menu/settings/collections/map-editor.js +5 -1
  118. package/dist/cli/menu/settings/collections/object-list-editor.js +2 -2
  119. package/dist/cli/menu/settings/collections/object-map-editor.js +2 -2
  120. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +11 -1
  121. package/dist/cli/menu/settings/collections/string-list-editor.js +23 -0
  122. package/dist/cli/menu/settings/index.d.ts +1 -1
  123. package/dist/cli/menu/settings/index.js +1 -1
  124. package/dist/cli/menu/settings/object-editor.d.ts +5 -1
  125. package/dist/cli/menu/settings/object-editor.js +15 -4
  126. package/dist/cli/menu/settings/path-kind.d.ts +20 -0
  127. package/dist/cli/menu/settings/path-kind.js +44 -0
  128. package/dist/cli/menu/settings/schema-node.d.ts +9 -0
  129. package/dist/cli/menu/settings/schema-node.js +26 -0
  130. package/dist/cli/menu/settings/value-editor.d.ts +5 -0
  131. package/dist/cli/menu/settings/value-editor.js +51 -18
  132. package/dist/cli/menu/several.js +7 -5
  133. package/dist/cli/menu/shell.d.ts +37 -10
  134. package/dist/cli/menu/shell.js +90 -10
  135. package/dist/cli/menu/vpn-login.d.ts +16 -0
  136. package/dist/cli/menu/vpn-login.js +66 -0
  137. package/dist/cli/output/print.d.ts +2 -0
  138. package/dist/cli/output/print.js +8 -1
  139. package/dist/cli/services/accounts-service.d.ts +2 -0
  140. package/dist/cli/services/accounts-service.js +2 -2
  141. package/dist/cli/services/health-service.d.ts +0 -6
  142. package/dist/cli/services/health-service.js +5 -42
  143. package/dist/cli/services/index.d.ts +3 -1
  144. package/dist/cli/services/index.js +3 -1
  145. package/dist/cli/services/migrate-service.js +1 -1
  146. package/dist/cli/services/update-service.d.ts +2 -0
  147. package/dist/cli/services/update-service.js +13 -6
  148. package/dist/cli/services/vpn-service.d.ts +28 -0
  149. package/dist/cli/services/vpn-service.js +46 -0
  150. package/dist/cli/services/web-service.d.ts +22 -0
  151. package/dist/cli/services/web-service.js +111 -0
  152. package/dist/cli/tui/app.d.ts +6 -3
  153. package/dist/cli/tui/app.js +12 -5
  154. package/dist/cli/tui/dialogs/path-listing.d.ts +43 -0
  155. package/dist/cli/tui/dialogs/path-listing.js +127 -0
  156. package/dist/cli/tui/dialogs/path-picker.d.ts +67 -0
  157. package/dist/cli/tui/dialogs/path-picker.js +423 -0
  158. package/dist/cli/tui/dialogs/text-screen.d.ts +6 -0
  159. package/dist/cli/tui/dialogs/text-screen.js +10 -3
  160. package/dist/cli/tui/frame.d.ts +7 -10
  161. package/dist/cli/tui/frame.js +19 -10
  162. package/dist/cli/tui/index.d.ts +4 -3
  163. package/dist/cli/tui/index.js +2 -1
  164. package/dist/cli/tui/list/list-screen.d.ts +14 -2
  165. package/dist/cli/tui/list/list-screen.js +68 -32
  166. package/dist/cli/tui/list/list-types.d.ts +8 -4
  167. package/dist/cli/tui/nav.d.ts +29 -0
  168. package/dist/cli/tui/nav.js +67 -0
  169. package/dist/cli/validate.d.ts +1 -1
  170. package/dist/cli/validate.js +3 -3
  171. package/dist/cli/version.d.ts +2 -0
  172. package/dist/cli/version.js +11 -0
  173. package/dist/core/config/defaults.js +5 -1
  174. package/dist/core/config/loader.js +12 -2
  175. package/dist/core/local-config/overrides.js +1 -0
  176. package/dist/core/prompt.d.ts +19 -0
  177. package/dist/core/prompt.js +43 -3
  178. package/dist/core/schema/common.d.ts +6 -0
  179. package/dist/core/schema/common.js +8 -0
  180. package/dist/core/schema/config.d.ts +23 -0
  181. package/dist/core/schema/config.js +10 -1
  182. package/dist/core/schema/harness.d.ts +1 -0
  183. package/dist/core/schema/harness.js +8 -2
  184. package/dist/core/schema/index.d.ts +3 -1
  185. package/dist/core/schema/index.js +3 -1
  186. package/dist/core/schema/profile.d.ts +1 -0
  187. package/dist/core/schema/profile.js +3 -0
  188. package/dist/core/schema/redact.d.ts +13 -0
  189. package/dist/core/schema/redact.js +75 -0
  190. package/dist/core/schema/sandbox.js +1 -0
  191. package/dist/core/schema/vpn.d.ts +17 -0
  192. package/dist/core/schema/vpn.js +22 -0
  193. package/dist/core/schema/web.d.ts +6 -0
  194. package/dist/core/schema/web.js +14 -0
  195. package/dist/core/types.d.ts +26 -0
  196. package/dist/guest/agents/agent-files.d.ts +49 -0
  197. package/dist/guest/agents/agent-files.js +63 -0
  198. package/dist/guest/agents/agent-installer.js +2 -9
  199. package/dist/guest/agents/local-state.d.ts +12 -0
  200. package/dist/guest/agents/local-state.js +198 -0
  201. package/dist/guest/agents/sbx-agent.d.ts +2 -0
  202. package/dist/guest/agents/sbx-agent.js +35 -0
  203. package/dist/guest/boot/boot.d.ts +4 -0
  204. package/dist/guest/boot/boot.js +50 -11
  205. package/dist/guest/daemon/daemon.js +4 -1
  206. package/dist/guest/daemon/exec.js +2 -1
  207. package/dist/guest/daemon/idle-shutdown.js +2 -0
  208. package/dist/guest/daemon/sessions.js +4 -1
  209. package/dist/guest/entries/agent.d.ts +1 -0
  210. package/dist/guest/entries/agent.js +10 -0
  211. package/dist/guest/entries/daemon.js +2 -0
  212. package/dist/guest/runtime/csc.d.ts +1 -0
  213. package/dist/guest/runtime/csc.js +1 -0
  214. package/dist/guest/runtime/secrets.d.ts +12 -0
  215. package/dist/guest/runtime/secrets.js +63 -0
  216. package/dist/guest/setup/claude-profile.d.ts +2 -1
  217. package/dist/guest/setup/claude-profile.js +12 -1
  218. package/dist/guest/setup/environment.d.ts +6 -0
  219. package/dist/guest/setup/environment.js +56 -6
  220. package/dist/guest/setup/path-plan.d.ts +32 -0
  221. package/dist/guest/setup/path-plan.js +67 -0
  222. package/dist/guest/setup/shell-path.d.ts +1 -0
  223. package/dist/guest/setup/shell-path.js +22 -0
  224. package/dist/guest/toolchains/languages/python.js +1 -1
  225. package/dist/guest/toolchains/runtimes.js +2 -2
  226. package/dist/guest/vpn/index.d.ts +1 -0
  227. package/dist/guest/vpn/index.js +1 -0
  228. package/dist/guest/vpn/openvpn.d.ts +9 -0
  229. package/dist/guest/vpn/openvpn.js +47 -0
  230. package/dist/guest/vpn/tunnel.d.ts +17 -0
  231. package/dist/guest/vpn/tunnel.js +78 -0
  232. package/dist/guest/vpn/vpn.d.ts +6 -0
  233. package/dist/guest/vpn/vpn.js +126 -0
  234. package/dist/host/channel/attach.d.ts +3 -1
  235. package/dist/host/channel/attach.js +1 -1
  236. package/dist/host/channel/channel.d.ts +7 -0
  237. package/dist/host/channel/channel.js +26 -2
  238. package/dist/host/health/acl-read.d.ts +17 -0
  239. package/dist/host/health/acl-read.js +45 -0
  240. package/dist/host/health/config-backup.d.ts +11 -0
  241. package/dist/host/health/config-backup.js +73 -0
  242. package/dist/host/health/index.d.ts +6 -0
  243. package/dist/host/health/index.js +7 -0
  244. package/dist/host/health/install-state.d.ts +33 -0
  245. package/dist/host/health/install-state.js +110 -0
  246. package/dist/host/health/path-copies.d.ts +32 -0
  247. package/dist/host/health/path-copies.js +82 -0
  248. package/dist/host/health/stale.d.ts +45 -0
  249. package/dist/host/health/stale.js +120 -0
  250. package/dist/host/health/system.d.ts +37 -0
  251. package/dist/host/health/system.js +87 -0
  252. package/dist/host/install/copies.d.ts +13 -0
  253. package/dist/host/install/copies.js +63 -0
  254. package/dist/host/install/index.d.ts +1 -0
  255. package/dist/host/install/index.js +1 -0
  256. package/dist/host/launch/generate.js +25 -1
  257. package/dist/host/launch/session-file.js +4 -1
  258. package/dist/host/launch/stage.js +1 -1
  259. package/dist/host/migrate/backup.js +3 -0
  260. package/dist/host/migrate/migrations/config-file.d.ts +2 -0
  261. package/dist/host/migrate/migrations/config-file.js +7 -0
  262. package/dist/host/migrate/migrations/follow-machine-storage.js +9 -1
  263. package/dist/host/migrate/migrations/pin-storage-root.d.ts +4 -0
  264. package/dist/host/migrate/migrations/pin-storage-root.js +46 -0
  265. package/dist/host/migrate/migrations/unpin-config-defaults.js +4 -1
  266. package/dist/host/migrate/registry.js +2 -1
  267. package/dist/host/profile/accounts.d.ts +25 -1
  268. package/dist/host/profile/accounts.js +96 -13
  269. package/dist/host/profile/agent-accounts.d.ts +5 -1
  270. package/dist/host/profile/agent-accounts.js +35 -5
  271. package/dist/host/profile/index.d.ts +2 -1
  272. package/dist/host/profile/index.js +1 -0
  273. package/dist/host/profile/plugin-share.d.ts +26 -0
  274. package/dist/host/profile/plugin-share.js +146 -0
  275. package/dist/host/projects/join.d.ts +7 -1
  276. package/dist/host/projects/join.js +21 -4
  277. package/dist/host/projects/registry.d.ts +16 -10
  278. package/dist/host/projects/registry.js +74 -6
  279. package/dist/host/sandbox/platform.d.ts +2 -0
  280. package/dist/host/sandbox/platform.js +21 -2
  281. package/dist/host/secrets/index.d.ts +2 -0
  282. package/dist/host/secrets/index.js +2 -0
  283. package/dist/host/secrets/launch-secrets.d.ts +17 -0
  284. package/dist/host/secrets/launch-secrets.js +93 -0
  285. package/dist/host/secrets/secret-store.d.ts +25 -0
  286. package/dist/host/secrets/secret-store.js +89 -0
  287. package/dist/host/sharing/acl.d.ts +16 -2
  288. package/dist/host/sharing/acl.js +35 -10
  289. package/dist/host/sharing/current.js +11 -2
  290. package/dist/host/sharing/doctor.d.ts +2 -0
  291. package/dist/host/sharing/doctor.js +44 -0
  292. package/dist/host/sharing/group-access.d.ts +6 -0
  293. package/dist/host/sharing/group-access.js +24 -0
  294. package/dist/host/sharing/index.d.ts +2 -1
  295. package/dist/host/sharing/index.js +2 -1
  296. package/dist/host/sharing/lifecycle.d.ts +8 -2
  297. package/dist/host/sharing/lifecycle.js +16 -7
  298. package/dist/host/storage/cleanup.d.ts +2 -0
  299. package/dist/host/storage/cleanup.js +2 -1
  300. package/dist/host/storage/history.d.ts +21 -0
  301. package/dist/host/storage/history.js +49 -0
  302. package/dist/host/storage/index.d.ts +4 -0
  303. package/dist/host/storage/index.js +4 -0
  304. package/dist/host/storage/move.d.ts +95 -0
  305. package/dist/host/storage/move.js +384 -0
  306. package/dist/host/storage/offer.d.ts +11 -0
  307. package/dist/host/storage/offer.js +36 -0
  308. package/dist/host/storage/root.d.ts +18 -0
  309. package/dist/host/storage/root.js +77 -0
  310. package/dist/host/tools/windows-terminal.d.ts +2 -0
  311. package/dist/host/tools/windows-terminal.js +23 -5
  312. package/dist/host/update/index.d.ts +1 -1
  313. package/dist/host/update/index.js +1 -1
  314. package/dist/host/update/notice.d.ts +2 -0
  315. package/dist/host/update/notice.js +13 -1
  316. package/dist/host/update/update-state.d.ts +6 -0
  317. package/dist/host/update/update-state.js +2 -0
  318. package/dist/host/update/updater.d.ts +19 -0
  319. package/dist/host/update/updater.js +88 -12
  320. package/dist/host/vpn/index.d.ts +4 -0
  321. package/dist/host/vpn/index.js +4 -0
  322. package/dist/host/vpn/login.d.ts +24 -0
  323. package/dist/host/vpn/login.js +79 -0
  324. package/dist/host/vpn/nordvpn.d.ts +21 -0
  325. package/dist/host/vpn/nordvpn.js +77 -0
  326. package/dist/host/vpn/prepare.d.ts +17 -0
  327. package/dist/host/vpn/prepare.js +77 -0
  328. package/dist/host/vpn/status.d.ts +12 -0
  329. package/dist/host/vpn/status.js +53 -0
  330. package/dist/host/web/auth.d.ts +38 -0
  331. package/dist/host/web/auth.js +96 -0
  332. package/dist/host/web/backend.d.ts +14 -0
  333. package/dist/host/web/backend.js +1 -0
  334. package/dist/host/web/bridge.d.ts +27 -0
  335. package/dist/host/web/bridge.js +144 -0
  336. package/dist/host/web/browser.d.ts +1 -0
  337. package/dist/host/web/browser.js +10 -0
  338. package/dist/host/web/control.d.ts +17 -0
  339. package/dist/host/web/control.js +67 -0
  340. package/dist/host/web/index.d.ts +9 -0
  341. package/dist/host/web/index.js +8 -0
  342. package/dist/host/web/runner.d.ts +14 -0
  343. package/dist/host/web/runner.js +45 -0
  344. package/dist/host/web/server.d.ts +40 -0
  345. package/dist/host/web/server.js +218 -0
  346. package/dist/host/web/state.d.ts +20 -0
  347. package/dist/host/web/state.js +41 -0
  348. package/dist/host/web/static-files.d.ts +13 -0
  349. package/dist/host/web/static-files.js +57 -0
  350. package/dist/runtime/agent.js +27614 -0
  351. package/dist/runtime/daemon.js +1012 -618
  352. package/dist/runtime/db.js +236 -106
  353. package/dist/runtime/main.js +1093 -250
  354. package/dist/runtime/netproxy.js +102 -3
  355. package/dist/runtime/view.js +102 -3
  356. package/dist/selftest/accounts.test.js +40 -0
  357. package/dist/selftest/agent-paths.test.d.ts +2 -0
  358. package/dist/selftest/agent-paths.test.js +115 -0
  359. package/dist/selftest/channel.test.js +5 -0
  360. package/dist/selftest/cli.test.js +34 -4
  361. package/dist/selftest/credentials.test.d.ts +2 -0
  362. package/dist/selftest/credentials.test.js +198 -0
  363. package/dist/selftest/generate.test.js +1 -1
  364. package/dist/selftest/health.test.d.ts +2 -0
  365. package/dist/selftest/health.test.js +470 -0
  366. package/dist/selftest/host-sim.test.js +2 -0
  367. package/dist/selftest/index.js +19 -0
  368. package/dist/selftest/layout.test.js +2 -0
  369. package/dist/selftest/menu-screens.d.ts +7 -0
  370. package/dist/selftest/menu-screens.js +65 -16
  371. package/dist/selftest/menu.test.js +574 -21
  372. package/dist/selftest/migrate.test.js +1 -1
  373. package/dist/selftest/personalization.test.js +3 -1
  374. package/dist/selftest/projects.test.js +39 -1
  375. package/dist/selftest/shared-use.test.js +64 -2
  376. package/dist/selftest/sharing.test.js +50 -1
  377. package/dist/selftest/storage.test.d.ts +2 -0
  378. package/dist/selftest/storage.test.js +363 -0
  379. package/dist/selftest/support/fixtures.d.ts +14 -0
  380. package/dist/selftest/support/releases.js +1 -1
  381. package/dist/selftest/toolchains.test.js +21 -0
  382. package/dist/selftest/update-service.test.js +87 -3
  383. package/dist/selftest/vpn.test.d.ts +2 -0
  384. package/dist/selftest/vpn.test.js +279 -0
  385. package/dist/selftest/web.test.d.ts +2 -0
  386. package/dist/selftest/web.test.js +304 -0
  387. package/dist/shared/apps/catalogue.js +31 -0
  388. package/dist/shared/channel/index.d.ts +1 -0
  389. package/dist/shared/channel/index.js +1 -0
  390. package/dist/shared/channel/run-dir.d.ts +6 -1
  391. package/dist/shared/channel/run-dir.js +12 -1
  392. package/dist/shared/channel/schema.d.ts +19 -0
  393. package/dist/shared/channel/schema.js +11 -0
  394. package/dist/shared/channel/secrets.d.ts +28 -0
  395. package/dist/shared/channel/secrets.js +44 -0
  396. package/dist/shared/vpn/download.d.ts +13 -0
  397. package/dist/shared/vpn/download.js +14 -0
  398. package/dist/shared/vpn/kill-switch.d.ts +18 -0
  399. package/dist/shared/vpn/kill-switch.js +81 -0
  400. package/dist/shared/vpn/ovpn.d.ts +23 -0
  401. package/dist/shared/vpn/ovpn.js +244 -0
  402. package/dist/shared/web/index.d.ts +1 -0
  403. package/dist/shared/web/index.js +1 -0
  404. package/dist/shared/web/protocol.d.ts +61 -0
  405. package/dist/shared/web/protocol.js +35 -0
  406. package/dist/sync/sync-cycle.js +5 -1
  407. package/dist/sync/sync-state.d.ts +1 -0
  408. package/dist/sync/sync-state.js +1 -0
  409. package/dist/sync/watcher.js +10 -0
  410. package/dist/web/index.html +13 -0
  411. package/dist/web/main-CXESL347.js +45 -0
  412. package/dist/web/main-VLR7DVQ4.css +1 -0
  413. package/native/csharp/FolderSecurity.cs +29 -0
  414. package/native/scripts/protect-data.ps1 +29 -0
  415. package/native/scripts/read-folder-sddl.ps1 +10 -0
  416. package/native/scripts/set-folder-access.ps1 +49 -7
  417. package/node_modules/ws/LICENSE +20 -0
  418. package/node_modules/ws/README.md +548 -0
  419. package/node_modules/ws/browser.js +8 -0
  420. package/node_modules/ws/index.js +22 -0
  421. package/node_modules/ws/lib/buffer-util.js +131 -0
  422. package/node_modules/ws/lib/constants.js +19 -0
  423. package/node_modules/ws/lib/event-target.js +292 -0
  424. package/node_modules/ws/lib/extension.js +203 -0
  425. package/node_modules/ws/lib/limiter.js +55 -0
  426. package/node_modules/ws/lib/permessage-deflate.js +530 -0
  427. package/node_modules/ws/lib/receiver.js +743 -0
  428. package/node_modules/ws/lib/sender.js +607 -0
  429. package/node_modules/ws/lib/stream.js +161 -0
  430. package/node_modules/ws/lib/subprotocol.js +62 -0
  431. package/node_modules/ws/lib/validation.js +152 -0
  432. package/node_modules/ws/lib/websocket-server.js +562 -0
  433. package/node_modules/ws/lib/websocket.js +1421 -0
  434. package/node_modules/ws/package.json +74 -0
  435. package/node_modules/ws/wrapper.mjs +21 -0
  436. package/package.json +15 -5
  437. package/sandbox/csharp/EnvBroadcast.cs +33 -0
  438. package/sandbox/csharp/PathSync.cs +90 -0
  439. package/sandbox/scripts/install-shell-path.ps1 +73 -0
  440. package/sandbox/scripts/set-machine-environment.ps1 +37 -4
  441. package/schemas/config.schema.json +79 -4
  442. package/schemas/sandbox-config.schema.json +14 -1
  443. package/dist/cli/commands/repair/checks.d.ts +0 -2
  444. package/dist/cli/commands/repair/checks.js +0 -246
  445. package/dist/cli/menu/pages/start-page.d.ts +0 -43
  446. package/dist/cli/menu/pages/start-page.js +0 -192
  447. package/dist/cli/tui/tab-bar.d.ts +0 -9
  448. package/dist/cli/tui/tab-bar.js +0 -33
@@ -1363,11 +1363,11 @@ var require_lodash = __commonJS({
1363
1363
  return isFunction(object2[key]);
1364
1364
  });
1365
1365
  }
1366
- function baseGet(object2, path67) {
1367
- path67 = castPath(path67, object2);
1368
- var index = 0, length = path67.length;
1366
+ function baseGet(object2, path74) {
1367
+ path74 = castPath(path74, object2);
1368
+ var index = 0, length = path74.length;
1369
1369
  while (object2 != null && index < length) {
1370
- object2 = object2[toKey(path67[index++])];
1370
+ object2 = object2[toKey(path74[index++])];
1371
1371
  }
1372
1372
  return index && index == length ? object2 : undefined2;
1373
1373
  }
@@ -1431,10 +1431,10 @@ var require_lodash = __commonJS({
1431
1431
  });
1432
1432
  return accumulator;
1433
1433
  }
1434
- function baseInvoke(object2, path67, args) {
1435
- path67 = castPath(path67, object2);
1436
- object2 = parent(object2, path67);
1437
- var func = object2 == null ? object2 : object2[toKey(last(path67))];
1434
+ function baseInvoke(object2, path74, args) {
1435
+ path74 = castPath(path74, object2);
1436
+ object2 = parent(object2, path74);
1437
+ var func = object2 == null ? object2 : object2[toKey(last(path74))];
1438
1438
  return func == null ? undefined2 : apply(func, object2, args);
1439
1439
  }
1440
1440
  function baseIsArguments(value) {
@@ -1590,13 +1590,13 @@ var require_lodash = __commonJS({
1590
1590
  return object2 === source || baseIsMatch(object2, source, matchData);
1591
1591
  };
1592
1592
  }
1593
- function baseMatchesProperty(path67, srcValue) {
1594
- if (isKey(path67) && isStrictComparable(srcValue)) {
1595
- return matchesStrictComparable(toKey(path67), srcValue);
1593
+ function baseMatchesProperty(path74, srcValue) {
1594
+ if (isKey(path74) && isStrictComparable(srcValue)) {
1595
+ return matchesStrictComparable(toKey(path74), srcValue);
1596
1596
  }
1597
1597
  return function(object2) {
1598
- var objValue = get(object2, path67);
1599
- return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path67) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1598
+ var objValue = get(object2, path74);
1599
+ return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path74) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1600
1600
  };
1601
1601
  }
1602
1602
  function baseMerge(object2, source, srcIndex, customizer, stack) {
@@ -1693,23 +1693,23 @@ var require_lodash = __commonJS({
1693
1693
  });
1694
1694
  }
1695
1695
  function basePick(object2, paths) {
1696
- return basePickBy(object2, paths, function(value, path67) {
1697
- return hasIn(object2, path67);
1696
+ return basePickBy(object2, paths, function(value, path74) {
1697
+ return hasIn(object2, path74);
1698
1698
  });
1699
1699
  }
1700
1700
  function basePickBy(object2, paths, predicate) {
1701
1701
  var index = -1, length = paths.length, result2 = {};
1702
1702
  while (++index < length) {
1703
- var path67 = paths[index], value = baseGet(object2, path67);
1704
- if (predicate(value, path67)) {
1705
- baseSet(result2, castPath(path67, object2), value);
1703
+ var path74 = paths[index], value = baseGet(object2, path74);
1704
+ if (predicate(value, path74)) {
1705
+ baseSet(result2, castPath(path74, object2), value);
1706
1706
  }
1707
1707
  }
1708
1708
  return result2;
1709
1709
  }
1710
- function basePropertyDeep(path67) {
1710
+ function basePropertyDeep(path74) {
1711
1711
  return function(object2) {
1712
- return baseGet(object2, path67);
1712
+ return baseGet(object2, path74);
1713
1713
  };
1714
1714
  }
1715
1715
  function basePullAll(array2, values2, iteratee2, comparator) {
@@ -1783,14 +1783,14 @@ var require_lodash = __commonJS({
1783
1783
  var array2 = values(collection);
1784
1784
  return shuffleSelf(array2, baseClamp(n, 0, array2.length));
1785
1785
  }
1786
- function baseSet(object2, path67, value, customizer) {
1786
+ function baseSet(object2, path74, value, customizer) {
1787
1787
  if (!isObject2(object2)) {
1788
1788
  return object2;
1789
1789
  }
1790
- path67 = castPath(path67, object2);
1791
- var index = -1, length = path67.length, lastIndex = length - 1, nested = object2;
1790
+ path74 = castPath(path74, object2);
1791
+ var index = -1, length = path74.length, lastIndex = length - 1, nested = object2;
1792
1792
  while (nested != null && ++index < length) {
1793
- var key = toKey(path67[index]), newValue = value;
1793
+ var key = toKey(path74[index]), newValue = value;
1794
1794
  if (key === "__proto__" || key === "constructor" || key === "prototype") {
1795
1795
  return object2;
1796
1796
  }
@@ -1798,7 +1798,7 @@ var require_lodash = __commonJS({
1798
1798
  var objValue = nested[key];
1799
1799
  newValue = customizer ? customizer(objValue, key, nested) : undefined2;
1800
1800
  if (newValue === undefined2) {
1801
- newValue = isObject2(objValue) ? objValue : isIndex(path67[index + 1]) ? [] : {};
1801
+ newValue = isObject2(objValue) ? objValue : isIndex(path74[index + 1]) ? [] : {};
1802
1802
  }
1803
1803
  }
1804
1804
  assignValue(nested, key, newValue);
@@ -1964,14 +1964,14 @@ var require_lodash = __commonJS({
1964
1964
  }
1965
1965
  return result2;
1966
1966
  }
1967
- function baseUnset(object2, path67) {
1968
- path67 = castPath(path67, object2);
1969
- var index = -1, length = path67.length;
1967
+ function baseUnset(object2, path74) {
1968
+ path74 = castPath(path74, object2);
1969
+ var index = -1, length = path74.length;
1970
1970
  if (!length) {
1971
1971
  return true;
1972
1972
  }
1973
1973
  while (++index < length) {
1974
- var key = toKey(path67[index]);
1974
+ var key = toKey(path74[index]);
1975
1975
  if (key === "__proto__" && !hasOwnProperty.call(object2, "__proto__")) {
1976
1976
  return false;
1977
1977
  }
@@ -1979,11 +1979,11 @@ var require_lodash = __commonJS({
1979
1979
  return false;
1980
1980
  }
1981
1981
  }
1982
- var obj = parent(object2, path67);
1983
- return obj == null || delete obj[toKey(last(path67))];
1982
+ var obj = parent(object2, path74);
1983
+ return obj == null || delete obj[toKey(last(path74))];
1984
1984
  }
1985
- function baseUpdate(object2, path67, updater, customizer) {
1986
- return baseSet(object2, path67, updater(baseGet(object2, path67)), customizer);
1985
+ function baseUpdate(object2, path74, updater, customizer) {
1986
+ return baseSet(object2, path74, updater(baseGet(object2, path74)), customizer);
1987
1987
  }
1988
1988
  function baseWhile(array2, predicate, isDrop, fromRight) {
1989
1989
  var length = array2.length, index = fromRight ? length : -1;
@@ -2866,11 +2866,11 @@ var require_lodash = __commonJS({
2866
2866
  var match = source.match(reWrapDetails);
2867
2867
  return match ? match[1].split(reSplitDetails) : [];
2868
2868
  }
2869
- function hasPath(object2, path67, hasFunc) {
2870
- path67 = castPath(path67, object2);
2871
- var index = -1, length = path67.length, result2 = false;
2869
+ function hasPath(object2, path74, hasFunc) {
2870
+ path74 = castPath(path74, object2);
2871
+ var index = -1, length = path74.length, result2 = false;
2872
2872
  while (++index < length) {
2873
- var key = toKey(path67[index]);
2873
+ var key = toKey(path74[index]);
2874
2874
  if (!(result2 = object2 != null && hasFunc(object2, key))) {
2875
2875
  break;
2876
2876
  }
@@ -3072,8 +3072,8 @@ var require_lodash = __commonJS({
3072
3072
  return apply(func, this, otherArgs);
3073
3073
  };
3074
3074
  }
3075
- function parent(object2, path67) {
3076
- return path67.length < 2 ? object2 : baseGet(object2, baseSlice(path67, 0, -1));
3075
+ function parent(object2, path74) {
3076
+ return path74.length < 2 ? object2 : baseGet(object2, baseSlice(path74, 0, -1));
3077
3077
  }
3078
3078
  function reorder(array2, indexes) {
3079
3079
  var arrLength = array2.length, length = nativeMin(indexes.length, arrLength), oldArray = copyArray(array2);
@@ -3230,7 +3230,7 @@ var require_lodash = __commonJS({
3230
3230
  }
3231
3231
  return isArrayLikeObject(array2) ? baseDifference(array2, baseFlatten(values2, 1, isArrayLikeObject, true), undefined2, comparator) : [];
3232
3232
  });
3233
- function drop(array2, n, guard) {
3233
+ function drop2(array2, n, guard) {
3234
3234
  var length = array2 == null ? 0 : array2.length;
3235
3235
  if (!length) {
3236
3236
  return [];
@@ -3461,7 +3461,7 @@ var require_lodash = __commonJS({
3461
3461
  function sortedUniqBy(array2, iteratee2) {
3462
3462
  return array2 && array2.length ? baseSortedUniq(array2, getIteratee(iteratee2, 2)) : [];
3463
3463
  }
3464
- function tail(array2) {
3464
+ function tail2(array2) {
3465
3465
  var length = array2 == null ? 0 : array2.length;
3466
3466
  return length ? baseSlice(array2, 1, length) : [];
3467
3467
  }
@@ -3708,10 +3708,10 @@ var require_lodash = __commonJS({
3708
3708
  }
3709
3709
  return isString(collection) ? fromIndex <= length && collection.indexOf(value, fromIndex) > -1 : !!length && baseIndexOf(collection, value, fromIndex) > -1;
3710
3710
  }
3711
- var invokeMap = baseRest(function(collection, path67, args) {
3712
- var index = -1, isFunc = typeof path67 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3711
+ var invokeMap = baseRest(function(collection, path74, args) {
3712
+ var index = -1, isFunc = typeof path74 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3713
3713
  baseEach(collection, function(value) {
3714
- result2[++index] = isFunc ? apply(path67, value, args) : baseInvoke(value, path67, args);
3714
+ result2[++index] = isFunc ? apply(path74, value, args) : baseInvoke(value, path74, args);
3715
3715
  });
3716
3716
  return result2;
3717
3717
  });
@@ -4363,15 +4363,15 @@ var require_lodash = __commonJS({
4363
4363
  function functionsIn(object2) {
4364
4364
  return object2 == null ? [] : baseFunctions(object2, keysIn(object2));
4365
4365
  }
4366
- function get(object2, path67, defaultValue) {
4367
- var result2 = object2 == null ? undefined2 : baseGet(object2, path67);
4366
+ function get(object2, path74, defaultValue) {
4367
+ var result2 = object2 == null ? undefined2 : baseGet(object2, path74);
4368
4368
  return result2 === undefined2 ? defaultValue : result2;
4369
4369
  }
4370
- function has(object2, path67) {
4371
- return object2 != null && hasPath(object2, path67, baseHas);
4370
+ function has(object2, path74) {
4371
+ return object2 != null && hasPath(object2, path74, baseHas);
4372
4372
  }
4373
- function hasIn(object2, path67) {
4374
- return object2 != null && hasPath(object2, path67, baseHasIn);
4373
+ function hasIn(object2, path74) {
4374
+ return object2 != null && hasPath(object2, path74, baseHasIn);
4375
4375
  }
4376
4376
  var invert = createInverter(function(result2, value, key) {
4377
4377
  if (value != null && typeof value.toString != "function") {
@@ -4424,10 +4424,10 @@ var require_lodash = __commonJS({
4424
4424
  return result2;
4425
4425
  }
4426
4426
  var isDeep = false;
4427
- paths = arrayMap(paths, function(path67) {
4428
- path67 = castPath(path67, object2);
4429
- isDeep || (isDeep = path67.length > 1);
4430
- return path67;
4427
+ paths = arrayMap(paths, function(path74) {
4428
+ path74 = castPath(path74, object2);
4429
+ isDeep || (isDeep = path74.length > 1);
4430
+ return path74;
4431
4431
  });
4432
4432
  copyObject(object2, getAllKeysIn(object2), result2);
4433
4433
  if (isDeep) {
@@ -4453,19 +4453,19 @@ var require_lodash = __commonJS({
4453
4453
  return [prop];
4454
4454
  });
4455
4455
  predicate = getIteratee(predicate);
4456
- return basePickBy(object2, props, function(value, path67) {
4457
- return predicate(value, path67[0]);
4456
+ return basePickBy(object2, props, function(value, path74) {
4457
+ return predicate(value, path74[0]);
4458
4458
  });
4459
4459
  }
4460
- function result(object2, path67, defaultValue) {
4461
- path67 = castPath(path67, object2);
4462
- var index = -1, length = path67.length;
4460
+ function result(object2, path74, defaultValue) {
4461
+ path74 = castPath(path74, object2);
4462
+ var index = -1, length = path74.length;
4463
4463
  if (!length) {
4464
4464
  length = 1;
4465
4465
  object2 = undefined2;
4466
4466
  }
4467
4467
  while (++index < length) {
4468
- var value = object2 == null ? undefined2 : object2[toKey(path67[index])];
4468
+ var value = object2 == null ? undefined2 : object2[toKey(path74[index])];
4469
4469
  if (value === undefined2) {
4470
4470
  index = length;
4471
4471
  value = defaultValue;
@@ -4474,12 +4474,12 @@ var require_lodash = __commonJS({
4474
4474
  }
4475
4475
  return object2;
4476
4476
  }
4477
- function set2(object2, path67, value) {
4478
- return object2 == null ? object2 : baseSet(object2, path67, value);
4477
+ function set2(object2, path74, value) {
4478
+ return object2 == null ? object2 : baseSet(object2, path74, value);
4479
4479
  }
4480
- function setWith(object2, path67, value, customizer) {
4480
+ function setWith(object2, path74, value, customizer) {
4481
4481
  customizer = typeof customizer == "function" ? customizer : undefined2;
4482
- return object2 == null ? object2 : baseSet(object2, path67, value, customizer);
4482
+ return object2 == null ? object2 : baseSet(object2, path74, value, customizer);
4483
4483
  }
4484
4484
  var toPairs = createToPairs(keys);
4485
4485
  var toPairsIn = createToPairs(keysIn);
@@ -4501,15 +4501,15 @@ var require_lodash = __commonJS({
4501
4501
  });
4502
4502
  return accumulator;
4503
4503
  }
4504
- function unset(object2, path67) {
4505
- return object2 == null ? true : baseUnset(object2, path67);
4504
+ function unset(object2, path74) {
4505
+ return object2 == null ? true : baseUnset(object2, path74);
4506
4506
  }
4507
- function update(object2, path67, updater) {
4508
- return object2 == null ? object2 : baseUpdate(object2, path67, castFunction(updater));
4507
+ function update(object2, path74, updater) {
4508
+ return object2 == null ? object2 : baseUpdate(object2, path74, castFunction(updater));
4509
4509
  }
4510
- function updateWith(object2, path67, updater, customizer) {
4510
+ function updateWith(object2, path74, updater, customizer) {
4511
4511
  customizer = typeof customizer == "function" ? customizer : undefined2;
4512
- return object2 == null ? object2 : baseUpdate(object2, path67, castFunction(updater), customizer);
4512
+ return object2 == null ? object2 : baseUpdate(object2, path74, castFunction(updater), customizer);
4513
4513
  }
4514
4514
  function values(object2) {
4515
4515
  return object2 == null ? [] : baseValues(object2, keys(object2));
@@ -4895,17 +4895,17 @@ var require_lodash = __commonJS({
4895
4895
  function matches(source) {
4896
4896
  return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
4897
4897
  }
4898
- function matchesProperty(path67, srcValue) {
4899
- return baseMatchesProperty(path67, baseClone(srcValue, CLONE_DEEP_FLAG));
4898
+ function matchesProperty(path74, srcValue) {
4899
+ return baseMatchesProperty(path74, baseClone(srcValue, CLONE_DEEP_FLAG));
4900
4900
  }
4901
- var method = baseRest(function(path67, args) {
4901
+ var method = baseRest(function(path74, args) {
4902
4902
  return function(object2) {
4903
- return baseInvoke(object2, path67, args);
4903
+ return baseInvoke(object2, path74, args);
4904
4904
  };
4905
4905
  });
4906
4906
  var methodOf = baseRest(function(object2, args) {
4907
- return function(path67) {
4908
- return baseInvoke(object2, path67, args);
4907
+ return function(path74) {
4908
+ return baseInvoke(object2, path74, args);
4909
4909
  };
4910
4910
  });
4911
4911
  function mixin(object2, source, options) {
@@ -4952,12 +4952,12 @@ var require_lodash = __commonJS({
4952
4952
  var over = createOver(arrayMap);
4953
4953
  var overEvery = createOver(arrayEvery);
4954
4954
  var overSome = createOver(arraySome);
4955
- function property(path67) {
4956
- return isKey(path67) ? baseProperty(toKey(path67)) : basePropertyDeep(path67);
4955
+ function property(path74) {
4956
+ return isKey(path74) ? baseProperty(toKey(path74)) : basePropertyDeep(path74);
4957
4957
  }
4958
4958
  function propertyOf(object2) {
4959
- return function(path67) {
4960
- return object2 == null ? undefined2 : baseGet(object2, path67);
4959
+ return function(path74) {
4960
+ return object2 == null ? undefined2 : baseGet(object2, path74);
4961
4961
  };
4962
4962
  }
4963
4963
  var range = createRange();
@@ -5071,7 +5071,7 @@ var require_lodash = __commonJS({
5071
5071
  lodash.difference = difference;
5072
5072
  lodash.differenceBy = differenceBy;
5073
5073
  lodash.differenceWith = differenceWith;
5074
- lodash.drop = drop;
5074
+ lodash.drop = drop2;
5075
5075
  lodash.dropRight = dropRight;
5076
5076
  lodash.dropRightWhile = dropRightWhile;
5077
5077
  lodash.dropWhile = dropWhile;
@@ -5151,7 +5151,7 @@ var require_lodash = __commonJS({
5151
5151
  lodash.sortedUniqBy = sortedUniqBy;
5152
5152
  lodash.split = split;
5153
5153
  lodash.spread = spread;
5154
- lodash.tail = tail;
5154
+ lodash.tail = tail2;
5155
5155
  lodash.take = take;
5156
5156
  lodash.takeRight = takeRight;
5157
5157
  lodash.takeRightWhile = takeRightWhile;
@@ -5410,12 +5410,12 @@ var require_lodash = __commonJS({
5410
5410
  LazyWrapper.prototype.findLast = function(predicate) {
5411
5411
  return this.reverse().find(predicate);
5412
5412
  };
5413
- LazyWrapper.prototype.invokeMap = baseRest(function(path67, args) {
5414
- if (typeof path67 == "function") {
5413
+ LazyWrapper.prototype.invokeMap = baseRest(function(path74, args) {
5414
+ if (typeof path74 == "function") {
5415
5415
  return new LazyWrapper(this);
5416
5416
  }
5417
5417
  return this.map(function(value) {
5418
- return baseInvoke(value, path67, args);
5418
+ return baseInvoke(value, path74, args);
5419
5419
  });
5420
5420
  });
5421
5421
  LazyWrapper.prototype.reject = function(predicate) {
@@ -5532,8 +5532,8 @@ var require_lodash = __commonJS({
5532
5532
  });
5533
5533
 
5534
5534
  // src/guest/entries/main.ts
5535
- import fs53 from "node:fs";
5536
- import path66 from "node:path";
5535
+ import fs59 from "node:fs";
5536
+ import path73 from "node:path";
5537
5537
 
5538
5538
  // src/guest/runtime/paths.ts
5539
5539
  import path7 from "node:path";
@@ -6358,10 +6358,10 @@ function mergeDefs(...defs) {
6358
6358
  function cloneDef(schema) {
6359
6359
  return mergeDefs(schema._zod.def);
6360
6360
  }
6361
- function getElementAtPath(obj, path67) {
6362
- if (!path67)
6361
+ function getElementAtPath(obj, path74) {
6362
+ if (!path74)
6363
6363
  return obj;
6364
- return path67.reduce((acc, key) => acc?.[key], obj);
6364
+ return path74.reduce((acc, key) => acc?.[key], obj);
6365
6365
  }
6366
6366
  function promiseAllObject(promisesObj) {
6367
6367
  const keys = Object.keys(promisesObj);
@@ -6701,11 +6701,11 @@ function explicitlyAborted(x, startIndex = 0) {
6701
6701
  }
6702
6702
  return false;
6703
6703
  }
6704
- function prefixIssues(path67, issues) {
6704
+ function prefixIssues(path74, issues) {
6705
6705
  return issues.map((iss) => {
6706
6706
  var _a3;
6707
6707
  (_a3 = iss).path ?? (_a3.path = []);
6708
- iss.path.unshift(path67);
6708
+ iss.path.unshift(path74);
6709
6709
  return iss;
6710
6710
  });
6711
6711
  }
@@ -7155,16 +7155,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
7155
7155
  }
7156
7156
  function formatError(error62, mapper = (issue2) => issue2.message) {
7157
7157
  const fieldErrors = { _errors: [] };
7158
- const processError = (error63, path67 = []) => {
7158
+ const processError = (error63, path74 = []) => {
7159
7159
  for (const issue2 of error63.issues) {
7160
7160
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7161
- issue2.errors.map((issues) => processError({ issues }, [...path67, ...issue2.path]));
7161
+ issue2.errors.map((issues) => processError({ issues }, [...path74, ...issue2.path]));
7162
7162
  } else if (issue2.code === "invalid_key") {
7163
- processError({ issues: issue2.issues }, [...path67, ...issue2.path]);
7163
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
7164
7164
  } else if (issue2.code === "invalid_element") {
7165
- processError({ issues: issue2.issues }, [...path67, ...issue2.path]);
7165
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
7166
7166
  } else {
7167
- const fullpath = [...path67, ...issue2.path];
7167
+ const fullpath = [...path74, ...issue2.path];
7168
7168
  if (fullpath.length === 0) {
7169
7169
  fieldErrors._errors.push(mapper(issue2));
7170
7170
  } else {
@@ -7203,17 +7203,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
7203
7203
  }
7204
7204
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
7205
7205
  const result = { errors: [] };
7206
- const processError = (error63, path67 = []) => {
7206
+ const processError = (error63, path74 = []) => {
7207
7207
  var _a3;
7208
7208
  for (const issue2 of error63.issues) {
7209
7209
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7210
- issue2.errors.map((issues) => processError({ issues }, [...path67, ...issue2.path]));
7210
+ issue2.errors.map((issues) => processError({ issues }, [...path74, ...issue2.path]));
7211
7211
  } else if (issue2.code === "invalid_key") {
7212
- processError({ issues: issue2.issues }, [...path67, ...issue2.path]);
7212
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
7213
7213
  } else if (issue2.code === "invalid_element") {
7214
- processError({ issues: issue2.issues }, [...path67, ...issue2.path]);
7214
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
7215
7215
  } else {
7216
- const fullpath = [...path67, ...issue2.path];
7216
+ const fullpath = [...path74, ...issue2.path];
7217
7217
  if (fullpath.length === 0) {
7218
7218
  result.errors.push(mapper(issue2));
7219
7219
  continue;
@@ -7252,8 +7252,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
7252
7252
  }
7253
7253
  function toDotPath(_path) {
7254
7254
  const segs = [];
7255
- const path67 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7256
- for (const seg of path67) {
7255
+ const path74 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7256
+ for (const seg of path74) {
7257
7257
  if (typeof seg === "number")
7258
7258
  segs.push(`[${seg}]`);
7259
7259
  else if (typeof seg === "symbol")
@@ -24355,13 +24355,13 @@ function resolveRef(ref, ctx) {
24355
24355
  if (!ref.startsWith("#")) {
24356
24356
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24357
24357
  }
24358
- const path67 = ref.slice(1).split("/").filter(Boolean);
24359
- if (path67.length === 0) {
24358
+ const path74 = ref.slice(1).split("/").filter(Boolean);
24359
+ if (path74.length === 0) {
24360
24360
  return ctx.rootSchema;
24361
24361
  }
24362
24362
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
24363
- if (path67[0] === defsKey) {
24364
- const key = path67[1] === void 0 ? void 0 : decodeJSONPointerSegment(path67[1]);
24363
+ if (path74[0] === defsKey) {
24364
+ const key = path74[1] === void 0 ? void 0 : decodeJSONPointerSegment(path74[1]);
24365
24365
  if (!key || !ctx.defs[key]) {
24366
24366
  throw new Error(`Reference not found: ${ref}`);
24367
24367
  }
@@ -25292,6 +25292,9 @@ function enabled(what, markers) {
25292
25292
  function Packages(what, example) {
25293
25293
  return StringsSchema.describe(what + ", installed once and kept (e.g. " + example + ").");
25294
25294
  }
25295
+ function secret(schema) {
25296
+ return schema.meta({ secret: true });
25297
+ }
25295
25298
 
25296
25299
  // src/core/schema/config.ts
25297
25300
  var import_lodash = __toESM(require_lodash(), 1);
@@ -25360,10 +25363,15 @@ var HarnessSchema = external_exports.strictObject({
25360
25363
  uvPackage: external_exports.string().optional().describe("Python package installed with `uv tool install` inside the sandbox (e.g. aider-chat)."),
25361
25364
  uvBin: external_exports.string().optional().describe("Command the uv package provides."),
25362
25365
  arguments: StringsSchema.describe("Arguments always passed to the agent."),
25363
- environment: external_exports.record(external_exports.string(), external_exports.string()).describe("Environment variables for the agent."),
25366
+ environment: external_exports.record(external_exports.string(), secret(external_exports.string())).describe(
25367
+ "Environment variables for the agent (API keys go here). Their values are shown as *** and are handed to the sandbox in a one-shot file, never kept in the launch folder. The agent can read its own environment."
25368
+ ),
25364
25369
  home: HarnessHomeSchema.optional().describe(
25365
25370
  "Where its login lives inside the sandbox; leave out when the agent cannot be pointed at a folder (then its login is not kept between sandboxes)."
25366
25371
  ),
25372
+ localState: external_exports.record(external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/), SubfolderSchema).optional().describe(
25373
+ "Environment variable -> folder below the agent's own state folder (state\\<agent>) for SQLite databases. SQLite cannot run in a mapped folder, so the agent runs from a copy on the sandbox's disk (the variable points to it) that is copied from and back to that folder."
25374
+ ),
25367
25375
  resumeArguments: StringsSchema.optional().describe(
25368
25376
  "Arguments used when the agent is restarted in place (e.g. after an account switch) so it resumes the conversation."
25369
25377
  ),
@@ -25415,6 +25423,9 @@ var ClaudeProfileSchema = external_exports.strictObject({
25415
25423
  globalStateFile: external_exports.string().describe('Your .claude.json, or "auto". Empty string = do not copy.'),
25416
25424
  copyCredentials: external_exports.boolean().describe("Copy your Claude LOGIN into the sandbox. Prefer sandbox account instead."),
25417
25425
  overwrite: external_exports.boolean().describe("Refresh these settings from this PC on every launch."),
25426
+ sharePluginsAcrossAccounts: external_exports.boolean().describe(
25427
+ "When you switch Claude accounts, copy your Claude plugins (and which ones are enabled) into a data set that has none yet. Off by default: plugins are code that runs in your sessions."
25428
+ ),
25418
25429
  syncHistory: external_exports.boolean().describe("Bring conversation history in, and sync new history back (path-translated)."),
25419
25430
  historyScope: external_exports.enum(["project", "all"]).describe(
25420
25431
  `Which history comes in: "project" = only the projects in this sandbox (other projects' conversations, file backups and prompts stay on this PC), "all" = everything. Only this sandbox's projects ever sync back.`
@@ -25491,7 +25502,10 @@ var NetworkSchema = external_exports.strictObject({
25491
25502
  "Reach servers in the sandbox from this PC: http://localhost:<pc> here goes to <sandbox> inside, while it runs. Nothing else on your network can use them."
25492
25503
  ),
25493
25504
  dns: external_exports.array(external_exports.string().regex(/^\d{1,3}(\.\d{1,3}){3}$/, "an IPv4 address like 1.1.1.1")).describe("DNS servers for the sandbox instead of your network's, e.g. 1.1.1.1 and 9.9.9.9."),
25494
- proxy: external_exports.string().regex(/^(https?:\/\/[^\s]+)?$/, "http://host:port").describe(
25505
+ proxy: external_exports.string().regex(/^(https?:\/\/[^\s]+)?$/, "http://host:port").refine(
25506
+ (v) => !/^https?:\/\/[^/?#]*@/i.test(v),
25507
+ "no user name or password in the address (it would be stored in plain text and visible to the agent): use a proxy that needs no login"
25508
+ ).describe(
25495
25509
  "An HTTP proxy the sandbox uses to reach the internet (HTTP_PROXY / HTTPS_PROXY for everything in it), e.g. http://proxy.corp:8080. Empty = none."
25496
25510
  )
25497
25511
  });
@@ -25893,6 +25907,17 @@ var APPS = [
25893
25907
  exe: "lazygit.exe",
25894
25908
  cli: true
25895
25909
  },
25910
+ {
25911
+ id: "jj",
25912
+ name: "Jujutsu (jj)",
25913
+ category: "git",
25914
+ about: "Git-compatible version control; conflicts do not block a rebase. Pilot, untested with worktrees.",
25915
+ size: "10 MB",
25916
+ source: gh("jj-vcs/jj", "^jj-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$"),
25917
+ exe: "jj.exe",
25918
+ cli: true,
25919
+ fullGitOnly: true
25920
+ },
25896
25921
  // ---- utilities
25897
25922
  {
25898
25923
  id: "7zip",
@@ -26421,6 +26446,26 @@ var APPS = [
26421
26446
  source: gh("gitleaks/gitleaks", "^gitleaks_[\\d.]+_windows_x64\\.zip$"),
26422
26447
  exe: "gitleaks.exe",
26423
26448
  cli: true
26449
+ },
26450
+ {
26451
+ id: "ast-grep",
26452
+ name: "ast-grep",
26453
+ category: "cli",
26454
+ about: "Search and rewrite code by its syntax tree (ast-grep, sg); prints only the matches.",
26455
+ size: "15 MB",
26456
+ source: gh("ast-grep/ast-grep", "^app-x86_64-pc-windows-msvc\\.zip$"),
26457
+ exe: "ast-grep.exe",
26458
+ cli: true
26459
+ },
26460
+ {
26461
+ id: "rust-analyzer",
26462
+ name: "rust-analyzer",
26463
+ category: "cli",
26464
+ about: "Rust language server: type errors and go-to-definition without cargo (for editors and the Claude LSP plugin).",
26465
+ size: "18 MB",
26466
+ source: gh("rust-lang/rust-analyzer", "^rust-analyzer-x86_64-pc-windows-msvc\\.zip$"),
26467
+ exe: "rust-analyzer.exe",
26468
+ cli: true
26424
26469
  }
26425
26470
  ];
26426
26471
  function appById(id) {
@@ -26529,6 +26574,33 @@ var ResumeSchema = external_exports.strictObject({
26529
26574
  )
26530
26575
  });
26531
26576
 
26577
+ // src/core/schema/web.ts
26578
+ var WebSchema = external_exports.strictObject({
26579
+ enabled: external_exports.boolean().describe(
26580
+ "(Beta) Allow the web UI: your sandbox sessions in a browser on this PC. Off by default, and nothing starts it by itself yet: sandbox web start works either way and runs it until sandbox web stop (or a restart of the PC)."
26581
+ ),
26582
+ port: external_exports.number().int().min(1024).max(65535).describe("Port of the web UI on 127.0.0.1 (this PC only). Pick another when it is taken.")
26583
+ });
26584
+
26585
+ // src/core/schema/vpn.ts
26586
+ var VPN_PROVIDERS = ["nordvpn", "openvpn-file"];
26587
+ var VpnSchema = external_exports.strictObject({
26588
+ enabled: external_exports.boolean().describe(
26589
+ "Send the sandbox's traffic through a VPN. Only the sandbox: your PC's own connection is untouched. Needs a saved login first (sandbox vpn login). The agent in the sandbox can read that login and can turn the tunnel off (it is the administrator there)."
26590
+ ),
26591
+ provider: external_exports.enum(VPN_PROVIDERS).describe(
26592
+ "nordvpn: a recommended NordVPN server is picked at every launch. openvpn-file: your own .ovpn file (configFile)."
26593
+ ),
26594
+ protocol: external_exports.enum(["udp", "tcp"]).describe("udp is faster; tcp gets through networks that block udp."),
26595
+ country: external_exports.string().regex(/^([A-Za-z][A-Za-z .'-]{0,39})?$/, "a country name or code like uk or Germany").describe("nordvpn: the country of the server, e.g. uk, us or Germany. Empty = the best server anywhere."),
26596
+ configFile: external_exports.string().describe(
26597
+ "openvpn-file: the .ovpn file on this PC (its certificates inside it). Files that run programs (script-security, up, down, plugin ...) are refused. A project's file can never set this."
26598
+ ),
26599
+ killSwitch: external_exports.boolean().describe(
26600
+ "Block all traffic that does not go through the tunnel: when the tunnel cannot start, the sandbox stays offline instead of using your normal connection. A project can only turn this on, never off."
26601
+ )
26602
+ });
26603
+
26532
26604
  // src/core/schema/config.ts
26533
26605
  var ConfigSchema = external_exports.strictObject({
26534
26606
  $schema: SchemaRefSchema.optional(),
@@ -26541,7 +26613,9 @@ var ConfigSchema = external_exports.strictObject({
26541
26613
  sandbox: SandboxSchema,
26542
26614
  sharing: SharingSchema,
26543
26615
  storage: external_exports.strictObject({
26544
- root: external_exports.string().min(1).describe("Where everything is kept on this PC (tools, databases, logins, launches)."),
26616
+ root: external_exports.string().min(1).describe(
26617
+ "Where everything is kept on this PC (tools, databases, logins, launches). The default is a private folder for you under %ProgramData%\\AgentSandbox\\users, which works for installs for one user and for everyone. sandbox storage move <folder> moves it."
26618
+ ),
26545
26619
  persistAgentState: external_exports.boolean().describe("Keep agent logins and history between sandboxes."),
26546
26620
  dataName: NameSchema.describe("Name of the persistent data set (C:\\AgentData) shared by all workspaces."),
26547
26621
  markSandboxFiles: external_exports.boolean().describe(
@@ -26552,6 +26626,7 @@ var ConfigSchema = external_exports.strictObject({
26552
26626
  )
26553
26627
  }),
26554
26628
  network: NetworkSchema,
26629
+ vpn: VpnSchema,
26555
26630
  provisioning: ProvisioningSchema,
26556
26631
  downloads: DownloadsSchema,
26557
26632
  toolchains: ToolchainsSchema,
@@ -26559,6 +26634,7 @@ var ConfigSchema = external_exports.strictObject({
26559
26634
  "Databases running inside the sandbox. Data persists in C:\\AgentData\\databases; each one starts at boot."
26560
26635
  ),
26561
26636
  attach: AttachSchema,
26637
+ web: WebSchema,
26562
26638
  agentCommands: AgentCommandsSchema,
26563
26639
  secrets: SecretsSchema,
26564
26640
  personalization: toggle("Copy your desktop look (theme, accent, taskbar, wallpaper, ...) into the sandbox."),
@@ -26591,6 +26667,8 @@ var LocalOverridesSchema = external_exports.strictObject({
26591
26667
  sandbox: SandboxSchema.omit({ cpuLimit: true, pageFileMb: true }).partial(),
26592
26668
  // A project may block more (the LAN, hosts); it never opens hosts, ports, DNS or a proxy.
26593
26669
  network: NetworkSchema.pick({ blockPrivateRanges: true, blockHosts: true }).partial(),
26670
+ // A project may turn the kill switch on, never off, and never choose a VPN, a server, a file or a login.
26671
+ vpn: VpnSchema.pick({ killSwitch: true }).partial(),
26594
26672
  provisioning: ProvisioningSchema.pick({ copyFromHost: true, fallbackToInstall: true, refresh: true }).extend({ git: GitSchema.partial(), terminal: toggle("Windows Terminal as the sandbox window.").partial() }).partial(),
26595
26673
  downloads: DownloadsSchema.partial(),
26596
26674
  // Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
@@ -26731,6 +26809,16 @@ var ProjectStatusSchema = external_exports.object({
26731
26809
  databases: external_exports.array(external_exports.object({ database: Text(32), port: external_exports.number().int() })).max(16),
26732
26810
  summary: external_exports.array(Text(512)).max(64)
26733
26811
  });
26812
+ var VpnStatusSchema = external_exports.object({
26813
+ state: external_exports.enum(["off", "starting", "up", "failed"]),
26814
+ message: Text(2e3),
26815
+ killSwitch: external_exports.boolean(),
26816
+ /** The server's name, e.g. uk2201.nordvpn.com. */
26817
+ server: Text(128).optional(),
26818
+ /** What the sandbox's traffic looks like from outside, once the tunnel is up. */
26819
+ publicIp: Text(64).optional(),
26820
+ updatedAt: TimeSchema
26821
+ });
26734
26822
 
26735
26823
  // src/shared/io/json.ts
26736
26824
  import fs2 from "node:fs";
@@ -26894,20 +26982,25 @@ var scan = (schema, dir) => {
26894
26982
  var RunDir = class {
26895
26983
  root;
26896
26984
  sandboxFile;
26985
+ vpnFile;
26897
26986
  requestsDir;
26898
26987
  responsesDir;
26899
26988
  sessionsDir;
26900
26989
  projectsDir;
26901
26990
  /** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
26902
26991
  auditDir;
26992
+ /** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
26993
+ secretsDir;
26903
26994
  constructor(dataDir2) {
26904
26995
  this.root = path6.join(dataDir2, "run");
26905
26996
  this.sandboxFile = path6.join(this.root, "sandbox.json");
26997
+ this.vpnFile = path6.join(this.root, "vpn.json");
26906
26998
  this.requestsDir = path6.join(this.root, "requests");
26907
26999
  this.responsesDir = path6.join(this.root, "responses");
26908
27000
  this.sessionsDir = path6.join(this.root, "sessions");
26909
27001
  this.projectsDir = path6.join(this.root, "projects");
26910
27002
  this.auditDir = path6.join(this.root, "audit");
27003
+ this.secretsDir = path6.join(dataDir2, "secrets");
26911
27004
  }
26912
27005
  requestFile(id) {
26913
27006
  return path6.join(this.requestsDir, safeId(id) + ".json");
@@ -26921,9 +27014,15 @@ var RunDir = class {
26921
27014
  projectFile(name) {
26922
27015
  return path6.join(this.projectsDir, safeId(name) + ".json");
26923
27016
  }
27017
+ secretFile(id) {
27018
+ return path6.join(this.secretsDir, safeId(id) + ".json");
27019
+ }
26924
27020
  readSandboxStatus() {
26925
27021
  return readValid(SandboxStatusSchema, this.sandboxFile);
26926
27022
  }
27023
+ readVpnStatus() {
27024
+ return readValid(VpnStatusSchema, this.vpnFile);
27025
+ }
26927
27026
  readSession(id) {
26928
27027
  return readValid(SessionStatusSchema, this.sessionFile(id));
26929
27028
  }
@@ -27331,9 +27430,9 @@ function writeStatus(phase, message) {
27331
27430
  }
27332
27431
 
27333
27432
  // src/guest/boot/boot.ts
27334
- import fs52 from "node:fs";
27335
- import path65 from "node:path";
27336
- import { spawn as spawn8 } from "node:child_process";
27433
+ import fs58 from "node:fs";
27434
+ import path72 from "node:path";
27435
+ import { spawn as spawn9 } from "node:child_process";
27337
27436
 
27338
27437
  // src/guest/boot/guide.ts
27339
27438
  import fs10 from "node:fs";
@@ -28664,7 +28763,8 @@ var SOURCES = {
28664
28763
  vswhere: "VsWhere.cs",
28665
28764
  openssl: "OpenSsl.cs",
28666
28765
  cargoshim: "CargoShim.cs",
28667
- linkgate: "LinkGate.cs"
28766
+ linkgate: "LinkGate.cs",
28767
+ pathsync: "PathSync.cs"
28668
28768
  };
28669
28769
  function sourceOf(name) {
28670
28770
  return path30.join(launchDir, "sandbox", "csharp", SOURCES[name]);
@@ -29014,7 +29114,7 @@ async function setupUv(env) {
29014
29114
  { size: "20 MB" }
29015
29115
  );
29016
29116
  Object.assign(env.vars, uvVars());
29017
- env.prepend.push(tool("uv-bin"));
29117
+ env.prepend.push(mkdirp(tool("uv-bin")));
29018
29118
  }
29019
29119
 
29020
29120
  // src/guest/toolchains/tools/cli.ts
@@ -30015,7 +30115,7 @@ async function setupPython(env, config2, versions) {
30015
30115
  const py3 = await installPython("python", versions.python.spec);
30016
30116
  const shims = shimDir(py3);
30017
30117
  shimPair(shims, "3", py3);
30018
- env.prepend.push(py3, path46.join(py3, "Scripts"), shims);
30118
+ env.prepend.push(py3, mkdirp(path46.join(py3, "Scripts")), shims);
30019
30119
  env.vars.PYTHONIOENCODING = "utf-8";
30020
30120
  env.summary.push(
30021
30121
  "python: " + path46.basename(py3).replace("python-", "") + " (from " + versions.python.source + "; py works too)"
@@ -31008,12 +31108,12 @@ function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
31008
31108
  }
31009
31109
  return result;
31010
31110
  }
31011
- function findNodeAtLocation(root, path67) {
31111
+ function findNodeAtLocation(root, path74) {
31012
31112
  if (!root) {
31013
31113
  return void 0;
31014
31114
  }
31015
31115
  let node2 = root;
31016
- for (let segment of path67) {
31116
+ for (let segment of path74) {
31017
31117
  if (typeof segment === "string") {
31018
31118
  if (node2.type !== "object" || !Array.isArray(node2.children)) {
31019
31119
  return void 0;
@@ -31367,14 +31467,14 @@ function getNodeType(value) {
31367
31467
 
31368
31468
  // node_modules/jsonc-parser/lib/esm/impl/edit.js
31369
31469
  function setProperty(text, originalPath, value, options) {
31370
- const path67 = originalPath.slice();
31470
+ const path74 = originalPath.slice();
31371
31471
  const errors = [];
31372
31472
  const root = parseTree(text, errors);
31373
31473
  let parent = void 0;
31374
31474
  let lastSegment = void 0;
31375
- while (path67.length > 0) {
31376
- lastSegment = path67.pop();
31377
- parent = findNodeAtLocation(root, path67);
31475
+ while (path74.length > 0) {
31476
+ lastSegment = path74.pop();
31477
+ parent = findNodeAtLocation(root, path74);
31378
31478
  if (parent === void 0 && value !== void 0) {
31379
31479
  if (typeof lastSegment === "string") {
31380
31480
  value = { [lastSegment]: value };
@@ -31560,8 +31660,8 @@ var ParseErrorCode;
31560
31660
  ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
31561
31661
  ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
31562
31662
  })(ParseErrorCode || (ParseErrorCode = {}));
31563
- function modify(text, path67, value, options) {
31564
- return setProperty(text, path67, value, options);
31663
+ function modify(text, path74, value, options) {
31664
+ return setProperty(text, path74, value, options);
31565
31665
  }
31566
31666
  function applyEdits(text, edits) {
31567
31667
  let sortedEdits = edits.slice(0).sort((a, b) => {
@@ -32110,14 +32210,159 @@ async function setupToolchains(config2, versions, options, run3 = {}) {
32110
32210
  }
32111
32211
 
32112
32212
  // src/guest/agents/agent-installer.ts
32213
+ import fs43 from "node:fs";
32214
+ import path56 from "node:path";
32215
+
32216
+ // src/guest/setup/environment.ts
32217
+ import path55 from "node:path";
32218
+
32219
+ // src/guest/agents/local-state.ts
32113
32220
  import fs42 from "node:fs";
32114
32221
  import path53 from "node:path";
32115
32222
 
32116
- // src/guest/setup/environment.ts
32223
+ // src/guest/agents/agent-files.ts
32117
32224
  import path52 from "node:path";
32225
+ function agentPaths(toolsDir2, name, harness) {
32226
+ const dir = path52.join(toolsDir2, "agents", name);
32227
+ const exe = harness.hostExecutable ?? (harness.uvBin ? harness.uvBin + ".exe" : null);
32228
+ return {
32229
+ dir,
32230
+ exe: exe ? path52.join(dir, exe) : null,
32231
+ cmd: harness.npmBin ? path52.join(dir, harness.npmBin + ".cmd") : null
32232
+ };
32233
+ }
32234
+ function agentCommand(name, harness) {
32235
+ return harness.npmBin ?? harness.uvBin ?? (harness.hostExecutable ?? name).replace(/\.exe$/i, "");
32236
+ }
32237
+ function agentShims(toolsDir2, agents2) {
32238
+ return Object.entries(agents2).flatMap(([name, harness]) => {
32239
+ const p = agentPaths(toolsDir2, name, harness);
32240
+ const target = p.exe ?? p.cmd;
32241
+ const command = agentCommand(name, harness);
32242
+ return target && /^[A-Za-z0-9_-]+$/.test(command) && /^[A-Za-z0-9_-]+$/.test(name) ? [{ name, command, target }] : [];
32243
+ });
32244
+ }
32245
+ function shimText(shim3, install) {
32246
+ return [
32247
+ "@echo off",
32248
+ "setlocal",
32249
+ 'set "SBX_REAL=' + shim3.target + '"',
32250
+ 'if exist "%SBX_REAL%" goto run',
32251
+ "echo " + shim3.command + " is not installed in this sandbox yet. Installing it now (one time)...",
32252
+ '"' + install.node + '" "' + install.script + '" install ' + shim3.name,
32253
+ "if errorlevel 1 exit /b 1",
32254
+ ":run",
32255
+ 'endlocal & "%SBX_REAL%" %*',
32256
+ ""
32257
+ ].join("\r\n");
32258
+ }
32259
+ function sbxAgentText(install) {
32260
+ return '@"' + install.node + '" "' + install.script + '" %*\r\n';
32261
+ }
32262
+ function localStateEntries(agents2, stateDir2, localRoot2) {
32263
+ return Object.entries(agents2).flatMap(
32264
+ ([agent, harness]) => Object.entries(harness.localState ?? {}).map(([env, folder]) => ({
32265
+ agent,
32266
+ env,
32267
+ store: path52.join(stateDir2, agent, folder),
32268
+ local: path52.join(localRoot2, agent, folder),
32269
+ processes: [agentCommand(agent, harness) + ".exe"],
32270
+ legacy: path52.join(stateDir2, agent)
32271
+ }))
32272
+ );
32273
+ }
32274
+ var isDatabaseFile = (name) => /\.(sqlite3?|db)(-wal|-shm)?$/i.test(name);
32275
+ var isCopyableDatabaseFile = (name) => isDatabaseFile(name) && !/-shm$/i.test(name);
32276
+
32277
+ // src/guest/agents/local-state.ts
32278
+ var localRoot = () => path53.join(localDir, "agent-state");
32279
+ function agentLocalStates() {
32280
+ return localStateEntries(session.agents ?? {}, stateDir, localRoot());
32281
+ }
32282
+ function localStateVars() {
32283
+ return Object.fromEntries(agentLocalStates().map((s) => [s.env, s.local]));
32284
+ }
32285
+ var databaseFiles = (dir, keep) => exists(dir) ? fs42.readdirSync(dir, { withFileTypes: true }).flatMap((e) => e.isFile() && keep(e.name) ? [e.name] : []) : [];
32286
+ var copyFiles = (from, to, names) => {
32287
+ fs42.rmSync(to, { recursive: true, force: true });
32288
+ mkdirp(to);
32289
+ for (const name of names) fs42.copyFileSync(path53.join(from, name), path53.join(to, name));
32290
+ };
32291
+ var swapIn = (incoming, store2) => {
32292
+ const previous = store2 + ".previous";
32293
+ fs42.rmSync(previous, { recursive: true, force: true });
32294
+ if (exists(store2)) fs42.renameSync(store2, previous);
32295
+ try {
32296
+ fs42.renameSync(incoming, store2);
32297
+ } catch (e) {
32298
+ if (exists(previous)) fs42.renameSync(previous, store2);
32299
+ throw e;
32300
+ }
32301
+ fs42.rmSync(previous, { recursive: true, force: true });
32302
+ };
32303
+ function adoptLegacy(s) {
32304
+ if (exists(s.store)) return;
32305
+ const names = databaseFiles(s.legacy, isDatabaseFile);
32306
+ if (!names.length) return;
32307
+ const copyable = names.filter(isCopyableDatabaseFile);
32308
+ const incoming = s.store + ".incoming";
32309
+ copyFiles(s.legacy, incoming, copyable);
32310
+ swapIn(incoming, s.store);
32311
+ const same = copyable.every(
32312
+ (n) => fs42.statSync(path53.join(s.store, n)).size === fs42.statSync(path53.join(s.legacy, n)).size
32313
+ );
32314
+ if (!same) {
32315
+ warn(s.agent + ": the copied databases differ in size from the originals; the originals were kept.");
32316
+ return;
32317
+ }
32318
+ for (const n of names) fs42.rmSync(path53.join(s.legacy, n), { force: true });
32319
+ log(s.agent + ": moved " + copyable.length + " database file(s) to " + s.store + ".");
32320
+ }
32321
+ function restoreLocalState() {
32322
+ if (dryRun) return;
32323
+ for (const s of agentLocalStates()) {
32324
+ try {
32325
+ adoptLegacy(s);
32326
+ mkdirp(s.local);
32327
+ const names = databaseFiles(s.store, isCopyableDatabaseFile);
32328
+ for (const n of names) fs42.copyFileSync(path53.join(s.store, n), path53.join(s.local, n));
32329
+ if (names.length) log(s.agent + ": databases restored to " + s.local + ".");
32330
+ } catch (e) {
32331
+ warn(s.agent + ": could not restore its databases (" + errMsg(e) + "); it starts with empty ones.");
32332
+ }
32333
+ }
32334
+ }
32335
+
32336
+ // src/guest/setup/path-plan.ts
32337
+ import path54 from "node:path";
32338
+ function pathKey(folder) {
32339
+ const slashes = folder.trim().replace(/^"|"$/g, "").replace(/\//g, "\\");
32340
+ return (slashes.length > 3 ? slashes.replace(/\\+$/, "") : slashes).toLowerCase();
32341
+ }
32342
+ function splitPath(value) {
32343
+ return value.split(";").map((part) => part.trim().replace(/^"|"$/g, "")).filter(Boolean);
32344
+ }
32345
+ function planPath(input2) {
32346
+ const seen = /* @__PURE__ */ new Set();
32347
+ const result = [];
32348
+ for (const entry of input2.entries.flatMap(splitPath)) {
32349
+ const key = pathKey(entry);
32350
+ if (seen.has(key) || input2.drop?.(entry) || !input2.exists(entry)) continue;
32351
+ seen.add(key);
32352
+ result.push(entry);
32353
+ }
32354
+ return result;
32355
+ }
32356
+ function isPinnedNodeDir(folder, nvmHome2) {
32357
+ const key = pathKey(folder);
32358
+ const home = pathKey(nvmHome2);
32359
+ return key.startsWith(home + "\\") && /^v\d/.test(path54.win32.basename(key));
32360
+ }
32361
+
32362
+ // src/guest/setup/environment.ts
32118
32363
  var LEGACY_HOMES = { CODEX_HOME: "codex", GEMINI_CLI_HOME: "gemini" };
32119
32364
  var agentHomes = () => Object.fromEntries(
32120
- Object.entries(session.agentHomes ?? LEGACY_HOMES).filter(([name]) => name !== "CLAUDE_CONFIG_DIR").map(([name, sub]) => [name, path52.join(stateDir, sub)])
32365
+ Object.entries(session.agentHomes ?? LEGACY_HOMES).filter(([name]) => name !== "CLAUDE_CONFIG_DIR").map(([name, sub]) => [name, path55.join(stateDir, sub)])
32121
32366
  );
32122
32367
  var AGENT_VARS = [
32123
32368
  "CLAUDE_CONFIG_DIR",
@@ -32137,7 +32382,8 @@ function agentEnv(tools, target = { workspace, project: session.project, base: p
32137
32382
  ...tools.vars,
32138
32383
  CLAUDE_CONFIG_DIR: claudeDir,
32139
32384
  ...homes,
32140
- npm_config_cache: path52.join(toolsDir, "npm-cache"),
32385
+ ...localStateVars(),
32386
+ npm_config_cache: path55.join(toolsDir, "npm-cache"),
32141
32387
  npm_config_update_notifier: "false",
32142
32388
  AGENT_WORKSPACE: target.workspace,
32143
32389
  AGENT_DATA: dataDir,
@@ -32147,22 +32393,32 @@ function agentEnv(tools, target = { workspace, project: session.project, base: p
32147
32393
  AGENT_SANDBOX: "1",
32148
32394
  AGENT_SANDBOX_WORKSPACE: target.workspace
32149
32395
  };
32150
- for (const dir of [env.CLAUDE_CONFIG_DIR, ...Object.keys(homes).map((n) => env[n]), env.npm_config_cache])
32396
+ const local = Object.keys(localStateVars());
32397
+ for (const dir of [
32398
+ env.CLAUDE_CONFIG_DIR,
32399
+ ...Object.keys(homes).map((n) => env[n]),
32400
+ env.npm_config_cache,
32401
+ ...local.map((n) => env[n])
32402
+ ])
32151
32403
  mkdirp(dir);
32152
- const runners = [path52.join(toolsDir, "node"), path52.dirname(process.execPath)].map((d) => d.toLowerCase());
32153
- const base = (target.base.PATH ?? "").split(path52.delimiter).filter((d) => d && !runners.includes(d.toLowerCase()));
32154
- env.PATH = [.../* @__PURE__ */ new Set([...tools.prepend, ...base, ...tools.append])].join(path52.delimiter);
32404
+ const runners = [path55.join(toolsDir, "node"), path55.dirname(process.execPath)].map((d) => d.toLowerCase());
32405
+ const base = (target.base.PATH ?? "").split(path55.delimiter).filter((d) => d && !runners.includes(d.toLowerCase()));
32406
+ env.PATH = [.../* @__PURE__ */ new Set([...tools.prepend, ...base, ...tools.append])].join(path55.delimiter);
32155
32407
  return env;
32156
32408
  }
32157
32409
  function persistEnvironment(env, toolVars2) {
32158
32410
  if (!isWin || dryRun || testMode) return;
32159
32411
  const vars = Object.fromEntries(
32160
- [...toolVars2, ...AGENT_VARS, ...Object.keys(agentHomes())].filter((n) => env[n] !== void 0).map((n) => [n, env[n]])
32412
+ [...toolVars2, ...AGENT_VARS, ...Object.keys(agentHomes()), ...Object.keys(localStateVars())].filter((n) => env[n] !== void 0).map((n) => [n, env[n]])
32161
32413
  );
32162
32414
  try {
32163
32415
  runScriptWithJson("set-machine-environment.ps1", "SettingsFile", {
32164
32416
  vars,
32165
- path: env.PATH ?? "",
32417
+ path: planPath({
32418
+ entries: [env.PATH ?? "", ...installedAgentDirs()],
32419
+ exists,
32420
+ drop: (dir) => isPinnedNodeDir(dir, nvmHome())
32421
+ }).join(path55.delimiter),
32166
32422
  add: [],
32167
32423
  additive: false
32168
32424
  });
@@ -32172,12 +32428,20 @@ function persistEnvironment(env, toolVars2) {
32172
32428
  }
32173
32429
  function addMachineEnvironment(vars, dirs, additive = false) {
32174
32430
  if (!isWin || dryRun || testMode) return;
32431
+ const planned = planPath({ entries: dirs, exists, drop: (dir) => isPinnedNodeDir(dir, nvmHome()) });
32175
32432
  try {
32176
- runScriptWithJson("set-machine-environment.ps1", "SettingsFile", { vars, path: null, add: dirs, additive });
32433
+ runScriptWithJson("set-machine-environment.ps1", "SettingsFile", { vars, path: null, add: planned, additive });
32177
32434
  } catch (e) {
32178
32435
  warn("Could not add to the environment: " + errMsg(e));
32179
32436
  }
32180
32437
  }
32438
+ var nvmHome = () => path55.join(toolsDir, "nvm");
32439
+ function installedAgentDirs() {
32440
+ return Object.entries(session.agents ?? {}).flatMap(([name, harness]) => {
32441
+ const p = agentPaths(toolsDir, name, harness);
32442
+ return p.exe && exists(p.exe) || p.cmd && exists(p.cmd) ? [p.dir] : [];
32443
+ });
32444
+ }
32181
32445
 
32182
32446
  // src/guest/agents/profile-links.ts
32183
32447
  var profileRoot = () => process.env.USERPROFILE ?? "";
@@ -32199,19 +32463,11 @@ function linkHarnessProfile(name, harness) {
32199
32463
  }
32200
32464
 
32201
32465
  // src/guest/agents/agent-installer.ts
32202
- function agentPaths(name, harness) {
32203
- const dir = path53.join(toolsDir, "agents", name);
32204
- const exe = harness.hostExecutable ?? (harness.uvBin ? harness.uvBin + ".exe" : null);
32205
- return {
32206
- dir,
32207
- exe: exe ? path53.join(dir, exe) : null,
32208
- cmd: harness.npmBin ? path53.join(dir, harness.npmBin + ".cmd") : null
32209
- };
32210
- }
32466
+ var agentPaths2 = (name, harness) => agentPaths(toolsDir, name, harness);
32211
32467
  async function installViaNpm(name, harness, dir, env) {
32212
32468
  if (!harness.npmPackage)
32213
32469
  throw new Error("No npmPackage configured for " + name + " and no host executable was available.");
32214
- const npmCli = path53.join(path53.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
32470
+ const npmCli = path56.join(path56.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
32215
32471
  const args = [npmCli, "install", "--global", "--prefix", dir, harness.npmPackage, "--no-fund", "--no-audit"];
32216
32472
  log("Installing " + harness.npmPackage + " (this can take a minute)...");
32217
32473
  if (dryRun) {
@@ -32222,7 +32478,7 @@ async function installViaNpm(name, harness, dir, env) {
32222
32478
  await execAsync(process.execPath, args, { env });
32223
32479
  }
32224
32480
  async function installViaUv(name, harness, dir, env) {
32225
- const uv = path53.join(toolsDir, "uv", "uv.exe");
32481
+ const uv = path56.join(toolsDir, "uv", "uv.exe");
32226
32482
  log("Installing " + harness.uvPackage + " with uv (this can take a minute)...");
32227
32483
  if (dryRun) {
32228
32484
  log("(dry run) uv tool install " + harness.uvPackage);
@@ -32237,8 +32493,8 @@ async function installViaUv(name, harness, dir, env) {
32237
32493
  });
32238
32494
  }
32239
32495
  function putOnPath(dir, env) {
32240
- const parts2 = (env.PATH ?? "").split(path53.delimiter);
32241
- if (!parts2.some((p) => p.toLowerCase() === dir.toLowerCase())) env.PATH = [...parts2, dir].join(path53.delimiter);
32496
+ const parts2 = (env.PATH ?? "").split(path56.delimiter);
32497
+ if (!parts2.some((p) => p.toLowerCase() === dir.toLowerCase())) env.PATH = [...parts2, dir].join(path56.delimiter);
32242
32498
  addMachineEnvironment({}, [dir], true);
32243
32499
  }
32244
32500
  var AgentInstaller = class {
@@ -32252,13 +32508,13 @@ var AgentInstaller = class {
32252
32508
  const current = this.installing.get(name);
32253
32509
  if (current) return current;
32254
32510
  linkHarnessProfile(name, harness);
32255
- const work = this.install(name, harness, env, refresh).then(() => putOnPath(agentPaths(name, harness).dir, env)).finally(() => this.installing.delete(name));
32511
+ const work = this.install(name, harness, env, refresh).then(() => putOnPath(agentPaths2(name, harness).dir, env)).finally(() => this.installing.delete(name));
32256
32512
  this.installing.set(name, work);
32257
32513
  return work;
32258
32514
  }
32259
32515
  /** Program + arguments that start the agent (an npm .cmd shim has to go through cmd.exe). */
32260
32516
  resolveLaunch(name, harness) {
32261
- const p = agentPaths(name, harness);
32517
+ const p = agentPaths2(name, harness);
32262
32518
  if (p.exe && exists(p.exe)) return { file: p.exe, args: [] };
32263
32519
  if (p.cmd && exists(p.cmd))
32264
32520
  return isWin ? { file: SYSTEM.cmd(), args: ["/d", "/c", p.cmd] } : { file: p.cmd, args: [] };
@@ -32271,7 +32527,7 @@ var AgentInstaller = class {
32271
32527
  return harness.uvPackage && !harness.npmPackage ? "uv" : "npm";
32272
32528
  }
32273
32529
  async install(name, harness, env, refresh) {
32274
- const p = agentPaths(name, harness);
32530
+ const p = agentPaths2(name, harness);
32275
32531
  const cached2 = p.exe !== null && exists(p.exe) || p.cmd !== null && exists(p.cmd);
32276
32532
  if (cached2 && !refresh) {
32277
32533
  log(name + " already cached in persistent storage.");
@@ -32279,9 +32535,9 @@ var AgentInstaller = class {
32279
32535
  }
32280
32536
  mkdirp(p.dir);
32281
32537
  if (this.sourceOf(name, harness) === "host") {
32282
- const source = path53.join(hostToolsDir, "agents", name, harness.hostExecutable);
32538
+ const source = path56.join(hostToolsDir, "agents", name, harness.hostExecutable);
32283
32539
  if (exists(source) && p.exe) {
32284
- fs42.copyFileSync(source, p.exe);
32540
+ fs43.copyFileSync(source, p.exe);
32285
32541
  log("Copied " + name + " from this PC: " + source);
32286
32542
  return;
32287
32543
  }
@@ -32295,28 +32551,45 @@ var AgentInstaller = class {
32295
32551
  };
32296
32552
  var agents = new AgentInstaller();
32297
32553
 
32554
+ // src/guest/setup/shell-path.ts
32555
+ import fs44 from "node:fs";
32556
+ import path57 from "node:path";
32557
+ function installShellPath() {
32558
+ if (!isWin || dryRun || testMode) return;
32559
+ const helper = path57.join(mkdirp(path57.join(localDir, "bin")), "pathsync.exe");
32560
+ fs44.copyFileSync(ensureCompiled("pathsync"), helper);
32561
+ runScript("install-shell-path.ps1", [
32562
+ "-Helper",
32563
+ helper,
32564
+ "-PwshDir",
32565
+ path57.join(toolsDir, "pwsh"),
32566
+ "-GitRoot",
32567
+ path57.join(toolsDir, "git")
32568
+ ]);
32569
+ }
32570
+
32298
32571
  // src/guest/setup/claude-mem.ts
32299
- import fs43 from "node:fs";
32572
+ import fs45 from "node:fs";
32300
32573
  import os9 from "node:os";
32301
- import path54 from "node:path";
32574
+ import path58 from "node:path";
32302
32575
  var claudeMemPaths = {
32303
- store: path54.join(stateDir, "claude-mem"),
32304
- local: path54.join(os9.homedir(), ".claude-mem")
32576
+ store: path58.join(stateDir, "claude-mem"),
32577
+ local: path58.join(os9.homedir(), ".claude-mem")
32305
32578
  };
32306
32579
  var claudeMemEnabled = () => session.claudeProfile.syncClaudeMem && !dryRun;
32307
32580
  function restoreClaudeMem() {
32308
32581
  if (!claudeMemEnabled()) return;
32309
32582
  const previous = claudeMemPaths.store + ".previous";
32310
- if (!exists(claudeMemPaths.store) && exists(previous)) fs43.renameSync(previous, claudeMemPaths.store);
32583
+ if (!exists(claudeMemPaths.store) && exists(previous)) fs45.renameSync(previous, claudeMemPaths.store);
32311
32584
  const backups = claudeMemPaths.store + ".backups";
32312
- if (!looksLikeSqlite(path54.join(claudeMemPaths.store, "claude-mem.db")) || !exists(claudeMemPaths.store)) {
32313
- const good = (exists(backups) ? fs43.readdirSync(backups).sort().reverse() : []).find(
32314
- (b) => exists(path54.join(backups, b, "claude-mem.db")) && looksLikeSqlite(path54.join(backups, b, "claude-mem.db"))
32585
+ if (!looksLikeSqlite(path58.join(claudeMemPaths.store, "claude-mem.db")) || !exists(claudeMemPaths.store)) {
32586
+ const good = (exists(backups) ? fs45.readdirSync(backups).sort().reverse() : []).find(
32587
+ (b) => exists(path58.join(backups, b, "claude-mem.db")) && looksLikeSqlite(path58.join(backups, b, "claude-mem.db"))
32315
32588
  );
32316
32589
  if (good) {
32317
32590
  if (exists(claudeMemPaths.store))
32318
- fs43.renameSync(claudeMemPaths.store, claudeMemPaths.store + ".damaged-" + Date.now());
32319
- fs43.cpSync(path54.join(backups, good), claudeMemPaths.store, { recursive: true });
32591
+ fs45.renameSync(claudeMemPaths.store, claudeMemPaths.store + ".damaged-" + Date.now());
32592
+ fs45.cpSync(path58.join(backups, good), claudeMemPaths.store, { recursive: true });
32320
32593
  warn(
32321
32594
  "claude-mem: the stored database was missing or damaged; restored the backup from " + new Date(Number(good)).toISOString() + "."
32322
32595
  );
@@ -32329,33 +32602,33 @@ function restoreClaudeMem() {
32329
32602
  var SQLITE_HEADER = "SQLite format 3\0";
32330
32603
  var looksLikeSqlite = (file3) => {
32331
32604
  if (!exists(file3)) return true;
32332
- const fd = fs43.openSync(file3, "r");
32605
+ const fd = fs45.openSync(file3, "r");
32333
32606
  try {
32334
32607
  const head = Buffer.alloc(16);
32335
- return fs43.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER;
32608
+ return fs45.readSync(fd, head, 0, 16, 0) === 16 && head.toString("latin1") === SQLITE_HEADER;
32336
32609
  } finally {
32337
- fs43.closeSync(fd);
32610
+ fs45.closeSync(fd);
32338
32611
  }
32339
32612
  };
32340
32613
  var BACKUP_EVERY_MS = 6 * 3600 * 1e3;
32341
32614
 
32342
32615
  // src/guest/setup/claude-profile.ts
32343
- import fs44 from "node:fs";
32344
- import path55 from "node:path";
32616
+ import fs46 from "node:fs";
32617
+ import path59 from "node:path";
32345
32618
  var KEEP_SANDBOX_COPY = [".claude.json", ".credentials.json"];
32346
32619
  var fixPluginPaths = (hostConfigDir) => {
32347
- const plugins = path55.join(claudeDir, "plugins");
32620
+ const plugins = path59.join(claudeDir, "plugins");
32348
32621
  if (!hostConfigDir || !exists(plugins)) return;
32349
- for (const name of fs44.readdirSync(plugins).filter((f) => f.endsWith(".json"))) {
32350
- const file3 = path55.join(plugins, name);
32351
- const text = fs44.readFileSync(file3, "utf8");
32622
+ for (const name of fs46.readdirSync(plugins).filter((f) => f.endsWith(".json"))) {
32623
+ const file3 = path59.join(plugins, name);
32624
+ const text = fs46.readFileSync(file3, "utf8");
32352
32625
  const fixed = translatePaths(text, hostConfigDir, claudeDir);
32353
- if (fixed !== text) fs44.writeFileSync(file3, fixed, "utf8");
32626
+ if (fixed !== text) fs46.writeFileSync(file3, fixed, "utf8");
32354
32627
  }
32355
32628
  };
32356
32629
  var readState2 = (file3) => {
32357
32630
  try {
32358
- return JSON.parse(fs44.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""));
32631
+ return JSON.parse(fs46.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""));
32359
32632
  } catch {
32360
32633
  return null;
32361
32634
  }
@@ -32380,30 +32653,37 @@ function mergeMcpServers(hostFile, guestFile, hostWorkspace, guestWorkspace) {
32380
32653
  writeJsonAtomic(guestFile, merged);
32381
32654
  return Object.keys(host.mcpServers ?? {}).length + Object.keys(hostProject).length;
32382
32655
  }
32383
- function syncClaudeProfile() {
32656
+ function syncClaudeProfile(credentials) {
32384
32657
  const profile = session.claudeProfile;
32385
32658
  if (profile.items.length === 0) {
32386
32659
  log("No Claude settings were staged from this PC.");
32387
32660
  return;
32388
32661
  }
32389
- const source = path55.join(launchDir, "claude-profile");
32662
+ const source = path59.join(launchDir, "claude-profile");
32390
32663
  mkdirp(claudeDir);
32391
32664
  for (const name of profile.items) {
32392
- const from = path55.join(source, name);
32393
- const to = path55.join(claudeDir, name);
32665
+ const from = path59.join(source, name);
32666
+ const to = path59.join(claudeDir, name);
32667
+ if (name === ".credentials.json") {
32668
+ if (credentials && !exists(to)) {
32669
+ fs46.writeFileSync(to, credentials, "utf8");
32670
+ log("Claude settings: copied " + name + " from this PC");
32671
+ } else log("Claude settings: kept the sandbox's " + name);
32672
+ continue;
32673
+ }
32394
32674
  if (!exists(from)) continue;
32395
32675
  if ((KEEP_SANDBOX_COPY.includes(name) || !profile.overwrite) && exists(to)) {
32396
32676
  log("Claude settings: kept the sandbox's " + name);
32397
32677
  continue;
32398
32678
  }
32399
- if (fs44.statSync(from).isDirectory()) safeRemove(to, claudeDir);
32400
- fs44.cpSync(from, to, { recursive: true, force: true });
32679
+ if (fs46.statSync(from).isDirectory()) safeRemove(to, claudeDir);
32680
+ fs46.cpSync(from, to, { recursive: true, force: true });
32401
32681
  log("Claude settings: copied " + name + " from this PC");
32402
32682
  }
32403
32683
  fixPluginPaths(profile.hostConfigDir);
32404
32684
  const mcp = mergeMcpServers(
32405
- path55.join(source, ".claude.json"),
32406
- path55.join(claudeDir, ".claude.json"),
32685
+ path59.join(source, ".claude.json"),
32686
+ path59.join(claudeDir, ".claude.json"),
32407
32687
  session.workspaceHost,
32408
32688
  workspace
32409
32689
  );
@@ -32412,11 +32692,11 @@ function syncClaudeProfile() {
32412
32692
  }
32413
32693
 
32414
32694
  // src/guest/setup/hooks.ts
32415
- import fs45 from "node:fs";
32416
- import path56 from "node:path";
32695
+ import fs47 from "node:fs";
32696
+ import path60 from "node:path";
32417
32697
  import { spawnSync as spawnSync4 } from "node:child_process";
32418
32698
  var commandFor = (file3) => {
32419
- const ext = path56.extname(file3).toLowerCase();
32699
+ const ext = path60.extname(file3).toLowerCase();
32420
32700
  if (ext === ".mjs" || ext === ".js") return [process.execPath, [file3]];
32421
32701
  if (!isWin) return null;
32422
32702
  if (ext === ".ps1")
@@ -32424,12 +32704,12 @@ var commandFor = (file3) => {
32424
32704
  if (ext === ".cmd" || ext === ".bat") return [SYSTEM.cmd(), ["/d", "/c", file3]];
32425
32705
  return null;
32426
32706
  };
32427
- var BOOT = { root: path56.join(launchDir, "hooks"), cwd: workspace };
32707
+ var BOOT = { root: path60.join(launchDir, "hooks"), cwd: workspace };
32428
32708
  var hooksOf = (stage, target) => {
32429
- const dir = path56.join(target.root, stage);
32709
+ const dir = path60.join(target.root, stage);
32430
32710
  if (!exists(dir)) return [];
32431
- return fs45.readdirSync(dir).sort().flatMap((name) => {
32432
- const command = commandFor(path56.join(dir, name));
32711
+ return fs47.readdirSync(dir).sort().flatMap((name) => {
32712
+ const command = commandFor(path60.join(dir, name));
32433
32713
  return command ? [{ name, command }] : [];
32434
32714
  });
32435
32715
  };
@@ -32447,8 +32727,8 @@ function runHooks(stage, env, target = BOOT) {
32447
32727
  }
32448
32728
 
32449
32729
  // src/guest/network/allow-only.ts
32450
- import fs47 from "node:fs";
32451
- import path58 from "node:path";
32730
+ import fs49 from "node:fs";
32731
+ import path62 from "node:path";
32452
32732
  import { spawn as spawn6, spawnSync as spawnSync6 } from "node:child_process";
32453
32733
 
32454
32734
  // src/shared/network/policy.ts
@@ -32543,8 +32823,8 @@ var PROXY_PORT = 38080;
32543
32823
 
32544
32824
  // src/guest/network/firewall.ts
32545
32825
  import dns from "node:dns";
32546
- import fs46 from "node:fs";
32547
- import path57 from "node:path";
32826
+ import fs48 from "node:fs";
32827
+ import path61 from "node:path";
32548
32828
  import { spawnSync as spawnSync5 } from "node:child_process";
32549
32829
 
32550
32830
  // src/shared/network/firewall-rules.ts
@@ -32783,12 +33063,12 @@ async function applyNetworkPolicy(ptyHostExe) {
32783
33063
  return "blocked";
32784
33064
  }
32785
33065
  var FORWARD_RULE = "AgentSandbox-Forward";
32786
- var HOSTS_FILE = path57.join(process.env.WINDIR ?? "C:\\Windows", "System32", "drivers", "etc", "hosts");
33066
+ var HOSTS_FILE = path61.join(process.env.WINDIR ?? "C:\\Windows", "System32", "drivers", "etc", "hosts");
32787
33067
  var applyBlockedHosts = () => {
32788
33068
  const hosts = session.network.blockHosts ?? [];
32789
33069
  if (!hosts.length) return;
32790
- const text = fs46.existsSync(HOSTS_FILE) ? fs46.readFileSync(HOSTS_FILE, "utf8") : "";
32791
- fs46.writeFileSync(HOSTS_FILE, withBlockedHosts(text, hosts));
33070
+ const text = fs48.existsSync(HOSTS_FILE) ? fs48.readFileSync(HOSTS_FILE, "utf8") : "";
33071
+ fs48.writeFileSync(HOSTS_FILE, withBlockedHosts(text, hosts));
32792
33072
  log("Blocked hosts (network.blockHosts): " + hosts.join(", "));
32793
33073
  };
32794
33074
  var applyDns = () => {
@@ -32843,11 +33123,11 @@ async function applyAllowOnly() {
32843
33123
  log("(dry run) would allow only: " + hosts.join(", "));
32844
33124
  return false;
32845
33125
  }
32846
- const exe = path58.join(toolsDir, "netproxy", "sbx-netproxy.exe");
32847
- fs47.mkdirSync(path58.dirname(exe), { recursive: true });
32848
- if (!fs47.existsSync(exe) || fs47.statSync(exe).size !== fs47.statSync(process.execPath).size)
32849
- fs47.copyFileSync(process.execPath, exe);
32850
- spawn6(exe, [path58.join(launchDir, "runtime", "netproxy.js")], {
33126
+ const exe = path62.join(toolsDir, "netproxy", "sbx-netproxy.exe");
33127
+ fs49.mkdirSync(path62.dirname(exe), { recursive: true });
33128
+ if (!fs49.existsSync(exe) || fs49.statSync(exe).size !== fs49.statSync(process.execPath).size)
33129
+ fs49.copyFileSync(process.execPath, exe);
33130
+ spawn6(exe, [path62.join(launchDir, "runtime", "netproxy.js")], {
32851
33131
  detached: true,
32852
33132
  stdio: "ignore",
32853
33133
  windowsHide: true
@@ -32891,8 +33171,8 @@ async function applyAllowOnly() {
32891
33171
  }
32892
33172
 
32893
33173
  // src/guest/setup/managed-policy.ts
32894
- import fs48 from "node:fs";
32895
- import path59 from "node:path";
33174
+ import fs50 from "node:fs";
33175
+ import path63 from "node:path";
32896
33176
 
32897
33177
  // src/guest/setup/git-rules.ts
32898
33178
  var SHELLS = ["Bash", "PowerShell"];
@@ -32949,44 +33229,44 @@ function gitDenyRules(access) {
32949
33229
 
32950
33230
  // src/guest/setup/managed-policy.ts
32951
33231
  function managedSettingsFile() {
32952
- return path59.join(path59.dirname(managedClaudeMd()), "managed-settings.json");
33232
+ return path63.join(path63.dirname(managedClaudeMd()), "managed-settings.json");
32953
33233
  }
32954
33234
  function writeManagedSettings2(access) {
32955
33235
  const file3 = managedSettingsFile();
32956
33236
  const deny = gitDenyRules(access);
32957
33237
  if (deny.length === 0) {
32958
- fs48.rmSync(file3, { force: true });
33238
+ fs50.rmSync(file3, { force: true });
32959
33239
  return;
32960
33240
  }
32961
- fs48.mkdirSync(path59.dirname(file3), { recursive: true });
32962
- fs48.writeFileSync(file3, JSON.stringify({ permissions: { deny } }, null, 2) + "\n", "utf8");
33241
+ fs50.mkdirSync(path63.dirname(file3), { recursive: true });
33242
+ fs50.writeFileSync(file3, JSON.stringify({ permissions: { deny } }, null, 2) + "\n", "utf8");
32963
33243
  }
32964
33244
 
32965
33245
  // src/guest/setup/desktop.ts
32966
- import fs49 from "node:fs";
33246
+ import fs51 from "node:fs";
32967
33247
  import os10 from "node:os";
32968
- import path60 from "node:path";
33248
+ import path64 from "node:path";
32969
33249
  function applyPersonalization() {
32970
- const dir = path60.join(launchDir, "personalize");
33250
+ const dir = path64.join(launchDir, "personalize");
32971
33251
  if (!session.personalization || !exists(dir) || dryRun || !isWin) return;
32972
- exec(SYSTEM.reg(), ["import", path60.join(dir, "personalize.reg")], { stdio: "ignore" });
32973
- const wallpaper = fs49.readdirSync(dir).find((f) => f.startsWith("wallpaper"));
32974
- const local = wallpaper ? path60.join(mkdirp(path60.join(os10.homedir(), "Pictures")), wallpaper) : null;
32975
- if (wallpaper && local) fs49.copyFileSync(path60.join(dir, wallpaper), local);
33252
+ exec(SYSTEM.reg(), ["import", path64.join(dir, "personalize.reg")], { stdio: "ignore" });
33253
+ const wallpaper = fs51.readdirSync(dir).find((f) => f.startsWith("wallpaper"));
33254
+ const local = wallpaper ? path64.join(mkdirp(path64.join(os10.homedir(), "Pictures")), wallpaper) : null;
33255
+ if (wallpaper && local) fs51.copyFileSync(path64.join(dir, wallpaper), local);
32976
33256
  runScript("set-desktop.ps1", local ? ["-Wallpaper", local] : []);
32977
33257
  log("Desktop personalisation applied from this PC.");
32978
33258
  }
32979
33259
 
32980
33260
  // src/guest/setup/git-identity.ts
32981
- import fs50 from "node:fs";
33261
+ import fs52 from "node:fs";
32982
33262
  import os11 from "node:os";
32983
- import path61 from "node:path";
33263
+ import path65 from "node:path";
32984
33264
  import { spawnSync as spawnSync7 } from "node:child_process";
32985
33265
  function setupGitConfig(env) {
32986
33266
  if (dryRun) return;
32987
- const source = path61.join(launchDir, "home", ".gitconfig");
32988
- if (exists(source)) fs50.copyFileSync(source, path61.join(os11.homedir(), ".gitconfig"));
32989
- const git = path61.join(toolsDir, "git", "cmd", "git.exe");
33267
+ const source = path65.join(launchDir, "home", ".gitconfig");
33268
+ if (exists(source)) fs52.copyFileSync(source, path65.join(os11.homedir(), ".gitconfig"));
33269
+ const git = path65.join(toolsDir, "git", "cmd", "git.exe");
32990
33270
  if (!exists(git)) return;
32991
33271
  const { GIT_DIR: _gitDir, ...rest } = env;
32992
33272
  spawnSync7(git, ["config", "--global", "--add", "safe.directory", "*"], {
@@ -33004,35 +33284,35 @@ function ensurePtyHost() {
33004
33284
  }
33005
33285
 
33006
33286
  // src/guest/toolchains/leftovers.ts
33007
- import fs51 from "node:fs";
33008
- import path62 from "node:path";
33287
+ import fs53 from "node:fs";
33288
+ import path66 from "node:path";
33009
33289
  var STAGING = /\.staging-[0-9a-f]+$/i;
33010
33290
  var entries2 = (dir) => {
33011
33291
  try {
33012
- return fs51.readdirSync(dir, { withFileTypes: true });
33292
+ return fs53.readdirSync(dir, { withFileTypes: true });
33013
33293
  } catch {
33014
33294
  return [];
33015
33295
  }
33016
33296
  };
33017
33297
  function pruneToolLeftovers() {
33018
- for (const legacy of ["ptyhost", "gitshim"]) safeRemove(path62.join(toolsDir, legacy), toolsDir);
33298
+ for (const legacy of ["ptyhost", "gitshim"]) safeRemove(path66.join(toolsDir, legacy), toolsDir);
33019
33299
  for (const top of entries2(toolsDir)) {
33020
- const dir = path62.join(toolsDir, top.name);
33300
+ const dir = path66.join(toolsDir, top.name);
33021
33301
  if (STAGING.test(top.name)) safeRemove(dir, toolsDir);
33022
33302
  else if (top.isDirectory())
33023
- for (const sub of entries2(dir).filter((e) => STAGING.test(e.name))) safeRemove(path62.join(dir, sub.name), dir);
33303
+ for (const sub of entries2(dir).filter((e) => STAGING.test(e.name))) safeRemove(path66.join(dir, sub.name), dir);
33024
33304
  }
33025
33305
  }
33026
33306
 
33027
33307
  // src/guest/audit/process-audit.ts
33028
- import path63 from "node:path";
33308
+ import path67 from "node:path";
33029
33309
  import { spawnSync as spawnSync8 } from "node:child_process";
33030
33310
  var PROCESS_CREATION = "{0CCE922B-69AE-11D9-BED3-505054503030}";
33031
33311
  var auditOn = () => Boolean(session.auditProcesses) && isWin && !dryRun;
33032
33312
  function enableProcessAudit() {
33033
33313
  if (!auditOn()) return;
33034
33314
  spawnSync8(
33035
- path63.join(process.env.WINDIR ?? "C:\\Windows", "System32", "auditpol.exe"),
33315
+ path67.join(process.env.WINDIR ?? "C:\\Windows", "System32", "auditpol.exe"),
33036
33316
  ["/set", "/subcategory:" + PROCESS_CREATION, "/success:enable"],
33037
33317
  { windowsHide: true, stdio: "ignore" }
33038
33318
  );
@@ -33054,6 +33334,497 @@ function enableProcessAudit() {
33054
33334
  log("Audit: programs started in the sandbox are recorded (audit.processes).");
33055
33335
  }
33056
33336
 
33337
+ // src/guest/vpn/vpn.ts
33338
+ import dns2 from "node:dns";
33339
+ import fs56 from "node:fs";
33340
+ import os13 from "node:os";
33341
+ import path70 from "node:path";
33342
+
33343
+ // src/shared/vpn/ovpn.ts
33344
+ var PROGRAM_DIRECTIVES = [
33345
+ "script-security",
33346
+ "up",
33347
+ "down",
33348
+ "up-restart",
33349
+ "down-pre",
33350
+ "route-up",
33351
+ "route-pre-down",
33352
+ "ipchange",
33353
+ "tls-verify",
33354
+ "plugin",
33355
+ "client-connect",
33356
+ "client-disconnect",
33357
+ "learn-address",
33358
+ "auth-user-pass-verify",
33359
+ "setenv-safe",
33360
+ "management",
33361
+ "management-client",
33362
+ "management-client-auth",
33363
+ "management-hold",
33364
+ "management-query-passwords",
33365
+ "config",
33366
+ "daemon",
33367
+ "service",
33368
+ "cd",
33369
+ "chroot",
33370
+ "setcon",
33371
+ "log",
33372
+ "log-append",
33373
+ "writepid",
33374
+ "status",
33375
+ "askpass",
33376
+ "engine",
33377
+ "bcast-dev",
33378
+ "dev-node",
33379
+ "cryptoapicert",
33380
+ "pkcs11-providers",
33381
+ "pkcs12",
33382
+ "http-proxy-user-pass",
33383
+ "tmp-dir"
33384
+ ];
33385
+ var ALLOWED = /* @__PURE__ */ new Set([
33386
+ "client",
33387
+ "tls-client",
33388
+ "dev",
33389
+ "dev-type",
33390
+ "proto",
33391
+ "remote",
33392
+ "remote-random",
33393
+ "remote-random-hostname",
33394
+ "resolv-retry",
33395
+ "nobind",
33396
+ "persist-key",
33397
+ "persist-tun",
33398
+ "remote-cert-tls",
33399
+ "remote-cert-eku",
33400
+ "ns-cert-type",
33401
+ "verify-x509-name",
33402
+ "cipher",
33403
+ "data-ciphers",
33404
+ "data-ciphers-fallback",
33405
+ "ncp-ciphers",
33406
+ "auth",
33407
+ "verb",
33408
+ "mute",
33409
+ "mute-replay-warnings",
33410
+ "reneg-sec",
33411
+ "reneg-bytes",
33412
+ "reneg-pkts",
33413
+ "tun-mtu",
33414
+ "tun-mtu-extra",
33415
+ "ping-timer-rem",
33416
+ "fast-io",
33417
+ "tls-timeout",
33418
+ "push-peer-info",
33419
+ "comp-noadapt",
33420
+ "link-mtu",
33421
+ "fragment",
33422
+ "mssfix",
33423
+ "sndbuf",
33424
+ "rcvbuf",
33425
+ "comp-lzo",
33426
+ "compress",
33427
+ "allow-compression",
33428
+ "key-direction",
33429
+ "auth-user-pass",
33430
+ "auth-nocache",
33431
+ "explicit-exit-notify",
33432
+ "pull",
33433
+ "pull-filter",
33434
+ "route-nopull",
33435
+ "route",
33436
+ "route-ipv6",
33437
+ "route-delay",
33438
+ "route-metric",
33439
+ "redirect-gateway",
33440
+ "redirect-private",
33441
+ "dhcp-option",
33442
+ "block-outside-dns",
33443
+ "register-dns",
33444
+ "topology",
33445
+ "tls-version-min",
33446
+ "tls-version-max",
33447
+ "tls-cipher",
33448
+ "tls-ciphersuites",
33449
+ "tls-groups",
33450
+ "tls-exit",
33451
+ "ping",
33452
+ "ping-restart",
33453
+ "ping-exit",
33454
+ "keepalive",
33455
+ "connect-retry",
33456
+ "connect-retry-max",
33457
+ "connect-timeout",
33458
+ "server-poll-timeout",
33459
+ "float",
33460
+ "ifconfig-nowarn",
33461
+ "tun-ipv6",
33462
+ "disable-dco",
33463
+ "windows-driver",
33464
+ "ignore-unknown-option",
33465
+ "opt-verify",
33466
+ "setenv",
33467
+ "key-method",
33468
+ "replay-window",
33469
+ "hand-window",
33470
+ "tran-window",
33471
+ "inactive",
33472
+ "socket-flags",
33473
+ "auth-retry",
33474
+ "ca",
33475
+ "cert",
33476
+ "key",
33477
+ "tls-auth",
33478
+ "tls-crypt",
33479
+ "tls-crypt-v2",
33480
+ "extra-certs",
33481
+ "dh"
33482
+ ]);
33483
+ var FILE_DIRECTIVES = /* @__PURE__ */ new Set(["ca", "cert", "key", "tls-auth", "tls-crypt", "tls-crypt-v2", "extra-certs", "dh"]);
33484
+ var BLOCKS = /* @__PURE__ */ new Set(["ca", "cert", "key", "tls-auth", "tls-crypt", "tls-crypt-v2", "extra-certs", "dh"]);
33485
+ var MAX_OVPN_BYTES = 256 * 1024;
33486
+ var MAX_LINES = 4e3;
33487
+ var HOST = /^(?:\d{1,3}(?:\.\d{1,3}){3}|[A-Za-z0-9](?:[A-Za-z0-9.-]{0,251}[A-Za-z0-9])?)$/;
33488
+ function directiveOf(line) {
33489
+ const text = line.replace(/^\uFEFF/, "").trim();
33490
+ if (text === "" || text.startsWith("#") || text.startsWith(";")) return null;
33491
+ const parts2 = text.replace(/^-+/, "").split(/\s+/);
33492
+ return { name: parts2[0].toLowerCase(), args: parts2.slice(1) };
33493
+ }
33494
+ function inspectOvpn(text) {
33495
+ const problems = [];
33496
+ const found = [];
33497
+ const refuse = (message) => {
33498
+ if (problems.length < 20 && !problems.includes(message)) problems.push(message);
33499
+ };
33500
+ if (Buffer.byteLength(text, "utf8") > MAX_OVPN_BYTES) return { ok: false, problems: ["the file is too big"] };
33501
+ if (text.includes("\0")) return { ok: false, problems: ["the file is not text"] };
33502
+ const lines = text.split(/\r?\n/);
33503
+ if (lines.length > MAX_LINES) return { ok: false, problems: ["the file has too many lines"] };
33504
+ let block = null;
33505
+ let defaultProto = "udp";
33506
+ lines.forEach((line, i) => {
33507
+ const at = "line " + (i + 1) + ": ";
33508
+ const trimmed = line.trim();
33509
+ if (block) {
33510
+ if (trimmed.toLowerCase() === "</" + block + ">") block = null;
33511
+ else if (/^<\/?[A-Za-z-]+>$/.test(trimmed)) refuse(at + "a section inside a section");
33512
+ return;
33513
+ }
33514
+ const open2 = /^<([A-Za-z0-9-]+)>$/.exec(trimmed);
33515
+ if (open2) {
33516
+ const tag = open2[1].toLowerCase();
33517
+ if (!BLOCKS.has(tag)) refuse(at + "<" + tag + "> is not allowed");
33518
+ block = tag;
33519
+ return;
33520
+ }
33521
+ const d = directiveOf(line);
33522
+ if (!d) return;
33523
+ if (!/^[a-z0-9-]{1,40}$/.test(d.name)) return refuse(at + "a directive name with odd characters");
33524
+ if (PROGRAM_DIRECTIVES.includes(d.name))
33525
+ return refuse(at + d.name + " runs a program or reads or writes a file on this machine");
33526
+ if (!ALLOWED.has(d.name)) return refuse(at + d.name + " is not on the list of settings that are safe to accept");
33527
+ if (FILE_DIRECTIVES.has(d.name))
33528
+ return refuse(at + d.name + " names a file: certificates must be inside the profile");
33529
+ if (d.name === "auth-user-pass" && d.args.length > 0)
33530
+ return refuse(at + "auth-user-pass names a file: the login is given separately");
33531
+ if (d.name === "setenv" && !(d.args[0] === "CLIENT_CERT" && d.args.length === 2))
33532
+ return refuse(at + "setenv may only be CLIENT_CERT");
33533
+ if (d.name === "proto") defaultProto = d.args[0]?.startsWith("tcp") ? "tcp" : "udp";
33534
+ if (d.name === "remote") {
33535
+ const [host, port = "1194", proto] = d.args;
33536
+ if (!host || !HOST.test(host)) return refuse(at + "remote needs a host name or an IPv4 address");
33537
+ const n = Number(port);
33538
+ if (!Number.isInteger(n) || n < 1 || n > 65535) return refuse(at + "remote has an invalid port");
33539
+ found.push({ host, port: n, ...proto ? { proto: proto.startsWith("tcp") ? "tcp" : "udp" } : {} });
33540
+ }
33541
+ });
33542
+ const remotes = found.map((r) => ({ host: r.host, port: r.port, proto: r.proto ?? defaultProto }));
33543
+ if (block) refuse("a <" + block + "> section is never closed");
33544
+ if (remotes.length === 0) refuse("it names no remote server");
33545
+ if (remotes.length > 64) refuse("it names too many servers");
33546
+ return problems.length ? { ok: false, problems } : { ok: true, remotes };
33547
+ }
33548
+ function assertSafeOvpn(text, what) {
33549
+ const report = inspectOvpn(text);
33550
+ if (report.ok) return report.remotes;
33551
+ throw new Error(
33552
+ what + " was refused because it could run programs or is not a plain profile:\n - " + report.problems.slice(0, 5).join("\n - ")
33553
+ );
33554
+ }
33555
+
33556
+ // src/shared/vpn/kill-switch.ts
33557
+ var VPN_RULE_PREFIX = "AgentSandbox-VPN-";
33558
+ var rule = (name, extra) => [
33559
+ "advfirewall",
33560
+ "firewall",
33561
+ "add",
33562
+ "rule",
33563
+ "name=" + VPN_RULE_PREFIX + name,
33564
+ "dir=out",
33565
+ "action=allow",
33566
+ "enable=yes",
33567
+ "profile=any",
33568
+ ...extra
33569
+ ];
33570
+ var drop = (name) => [
33571
+ "advfirewall",
33572
+ "firewall",
33573
+ "delete",
33574
+ "rule",
33575
+ "name=" + VPN_RULE_PREFIX + name
33576
+ ];
33577
+ function ruleNames(serverCount) {
33578
+ return [
33579
+ "Loopback",
33580
+ "DHCP",
33581
+ "Host",
33582
+ "Tunnel",
33583
+ ...Array.from({ length: Math.max(serverCount, 0) }, (_v, i) => "Server-" + (i + 1))
33584
+ ];
33585
+ }
33586
+ function cleanServers(servers) {
33587
+ const seen = /* @__PURE__ */ new Set();
33588
+ return servers.filter((s) => {
33589
+ const key = s.proto + ":" + s.ip + ":" + s.port;
33590
+ if (!isIPv4(s.ip) || !Number.isInteger(s.port) || s.port < 1 || s.port > 65535 || seen.has(key)) return false;
33591
+ seen.add(key);
33592
+ return true;
33593
+ });
33594
+ }
33595
+ function killSwitchCommands(servers, ptyHostExe) {
33596
+ const list = cleanServers(servers);
33597
+ return [
33598
+ ...ruleNames(Math.max(list.length, 8)).map(drop),
33599
+ ["advfirewall", "set", "allprofiles", "state", "on"],
33600
+ ["advfirewall", "set", "allprofiles", "firewallpolicy", "blockinbound,blockoutbound"],
33601
+ rule("Loopback", ["protocol=any", "remoteip=127.0.0.0/8"]),
33602
+ rule("DHCP", ["protocol=udp", "localport=68", "remoteport=67"]),
33603
+ ...ptyHostExe ? [rule("Host", ["protocol=any", "remoteip=LocalSubnet", "program=" + ptyHostExe])] : [],
33604
+ ...list.map(
33605
+ (s, i) => rule("Server-" + (i + 1), ["protocol=" + s.proto, "remoteip=" + s.ip, "remoteport=" + s.port])
33606
+ )
33607
+ ];
33608
+ }
33609
+ function tunnelCommands(tunnelIp) {
33610
+ if (!isIPv4(tunnelIp)) throw new Error("Not an IPv4 address: " + tunnelIp);
33611
+ return [drop("Tunnel"), rule("Tunnel", ["protocol=any", "localip=" + tunnelIp])];
33612
+ }
33613
+ function tunnelAddressFromLog(log2) {
33614
+ const add = /net_addr_v4_add:\s*(\d{1,3}(?:\.\d{1,3}){3})\/\d+/.exec(log2);
33615
+ if (add && isIPv4(add[1])) return add[1];
33616
+ const ifconfig = /(?:ifconfig|ip addr add|Notified TAP-Windows driver to set a DHCP IP\/netmask of)\s+(\d{1,3}(?:\.\d{1,3}){3})/i.exec(
33617
+ log2
33618
+ );
33619
+ return ifconfig && isIPv4(ifconfig[1]) ? ifconfig[1] : null;
33620
+ }
33621
+
33622
+ // src/guest/vpn/openvpn.ts
33623
+ import crypto4 from "node:crypto";
33624
+ import fs54 from "node:fs";
33625
+ import path68 from "node:path";
33626
+
33627
+ // src/shared/vpn/download.ts
33628
+ var OPENVPN_MSI = {
33629
+ version: "2.7.8",
33630
+ x64: {
33631
+ file: "OpenVPN-2.7.8-I001-amd64.msi",
33632
+ sha256: "1ea61a3056905b90607d4b0f084c04e5cf3043e07cf192d9cd44b0474f29cc49"
33633
+ },
33634
+ arm64: {
33635
+ file: "OpenVPN-2.7.8-I001-arm64.msi",
33636
+ sha256: "6fc0e8899cc5275ee297fb837bc84aa2bc49f8ef96d7ad93ee3fee1e7163a25c"
33637
+ },
33638
+ base: "https://swupdate.openvpn.org/community/releases/"
33639
+ };
33640
+
33641
+ // src/guest/vpn/openvpn.ts
33642
+ function openvpnExe(env = process.env) {
33643
+ return path68.join(env.ProgramFiles ?? "C:\\Program Files", "OpenVPN", "bin", "openvpn.exe");
33644
+ }
33645
+ function openvpnDownload(arch2 = process.arch) {
33646
+ const entry = arch2 === "arm64" ? OPENVPN_MSI.arm64 : OPENVPN_MSI.x64;
33647
+ return { ...entry, url: OPENVPN_MSI.base + entry.file };
33648
+ }
33649
+ var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs54.readFileSync(file3)).digest("hex") === sha256;
33650
+ async function ensureOpenVpn() {
33651
+ const exe = openvpnExe();
33652
+ if (!isWin || dryRun) return exe;
33653
+ if (exists(exe)) return exe;
33654
+ const dl = openvpnDownload();
33655
+ const msi = path68.join(mkdirp(path68.join(toolsDir, "downloads")), dl.file);
33656
+ if (!exists(msi) || !hasHash(msi, dl.sha256)) {
33657
+ log("VPN: downloading OpenVPN " + OPENVPN_MSI.version + " (about 6 MB)");
33658
+ await downloader.file(dl.url, msi, dl.sha256);
33659
+ }
33660
+ log("VPN: installing OpenVPN");
33661
+ const logFile2 = path68.join(toolsDir, "downloads", "openvpn-install.log");
33662
+ const code = await spawnAsync(SYSTEM.msiexec(), ["/i", msi, "/qn", "/norestart", "/l*v", logFile2], {
33663
+ stdio: "ignore"
33664
+ });
33665
+ if (code !== 0 && code !== 3010)
33666
+ throw new Error("The OpenVPN installer failed (exit " + code + "). Its log: " + logFile2);
33667
+ if (!exists(exe)) throw new Error("OpenVPN was installed but " + exe + " is missing. The installer log: " + logFile2);
33668
+ return exe;
33669
+ }
33670
+
33671
+ // src/guest/vpn/tunnel.ts
33672
+ import { spawn as spawn7 } from "node:child_process";
33673
+ import fs55 from "node:fs";
33674
+ import os12 from "node:os";
33675
+ import path69 from "node:path";
33676
+ var DONE = "Initialization Sequence Completed";
33677
+ function failureReason(text) {
33678
+ if (/AUTH_FAILED/i.test(text))
33679
+ return "the VPN refused the login (for NordVPN use the service credentials, not your account password)";
33680
+ if (/TLS Error: TLS key negotiation failed|TLS handshake failed/i.test(text))
33681
+ return "it could not reach the VPN server (the network blocks it, or the server is down)";
33682
+ if (/All wintun adapters on this system are in use|Cannot open TUN\/TAP|Could not create Wintun|ovpn-dco.*(error|failed)/i.test(
33683
+ text
33684
+ ))
33685
+ return "the network driver for the tunnel could not be used";
33686
+ if (/Exiting due to fatal error/i.test(text)) return "OpenVPN stopped with an error";
33687
+ return null;
33688
+ }
33689
+ var tail = (text, lines = 12) => text.trim().split(/\r?\n/).slice(-lines).join("\n");
33690
+ async function startTunnel(o) {
33691
+ const dir = fs55.mkdtempSync(path69.join(os12.tmpdir(), "sbx-vpn-"));
33692
+ const auth = path69.join(dir, "login.txt");
33693
+ const logFile2 = path69.join(dir, "openvpn.log");
33694
+ const keepLog = () => {
33695
+ try {
33696
+ fs55.mkdirSync(logsDir, { recursive: true });
33697
+ fs55.copyFileSync(logFile2, path69.join(logsDir, "openvpn.log"));
33698
+ } catch {
33699
+ }
33700
+ };
33701
+ fs55.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
33702
+ try {
33703
+ const child = spawn7(
33704
+ o.exe,
33705
+ ["--config", o.profile, "--auth-user-pass", auth, "--auth-nocache", "--verb", "3", "--log", logFile2],
33706
+ { detached: true, stdio: "ignore", windowsHide: true }
33707
+ );
33708
+ let exited = null;
33709
+ child.once("exit", (code) => {
33710
+ exited = code ?? -1;
33711
+ });
33712
+ child.once("error", (e) => {
33713
+ exited = -1;
33714
+ log("VPN: could not start OpenVPN: " + e.message);
33715
+ });
33716
+ child.unref();
33717
+ const deadline = Date.now() + (o.timeoutMs ?? 9e4);
33718
+ for (; ; ) {
33719
+ const text = fs55.existsSync(logFile2) ? fs55.readFileSync(logFile2, "utf8") : "";
33720
+ if (text.includes(DONE)) {
33721
+ keepLog();
33722
+ const tunnelIp = tunnelAddressFromLog(text) ?? void 0;
33723
+ return { ok: true, message: "the tunnel is up", ...tunnelIp ? { tunnelIp } : {} };
33724
+ }
33725
+ const reason = failureReason(text);
33726
+ if (exited !== null || reason) {
33727
+ if (exited === null) child.kill();
33728
+ keepLog();
33729
+ return { ok: false, message: (reason ?? "OpenVPN stopped") + ". " + tail(text, 4) };
33730
+ }
33731
+ if (Date.now() > deadline) {
33732
+ child.kill();
33733
+ keepLog();
33734
+ return { ok: false, message: "the tunnel did not come up in time. " + tail(text, 4) };
33735
+ }
33736
+ await new Promise((r) => setTimeout(r, 500));
33737
+ }
33738
+ } finally {
33739
+ fs55.rmSync(auth, { force: true });
33740
+ }
33741
+ }
33742
+
33743
+ // src/guest/vpn/vpn.ts
33744
+ function setVpnStatus(state, message, extra = {}) {
33745
+ try {
33746
+ writeJsonAtomic(run.vpnFile, {
33747
+ state,
33748
+ message: message.slice(0, 1900),
33749
+ killSwitch: session.vpn?.killSwitch ?? false,
33750
+ updatedAt: now(),
33751
+ ...session.vpn ? { server: session.vpn.server.slice(0, 120) } : {},
33752
+ ...extra
33753
+ });
33754
+ } catch (e) {
33755
+ warn("Could not write the VPN status: " + errMsg(e));
33756
+ }
33757
+ }
33758
+ async function serverAddresses(remotes) {
33759
+ const out = [];
33760
+ for (const r of remotes) {
33761
+ const ips = isIPv4(r.host) ? [r.host] : await dns2.promises.lookup(r.host, { all: true, family: 4 }).then(
33762
+ (all) => all.map((a) => a.address),
33763
+ () => []
33764
+ );
33765
+ for (const ip of ips) out.push({ ip, port: r.port, proto: r.proto });
33766
+ }
33767
+ return out;
33768
+ }
33769
+ async function publicAddress() {
33770
+ try {
33771
+ const text = (await (await fetch("https://api.ipify.org", { signal: AbortSignal.timeout(1e4) })).text()).trim();
33772
+ return /^[0-9a-fA-F.:]{3,45}$/.test(text) ? text : null;
33773
+ } catch {
33774
+ return null;
33775
+ }
33776
+ }
33777
+ var hasAdapter = (ip) => Object.values(os13.networkInterfaces()).some((list) => (list ?? []).some((i) => i.address === ip));
33778
+ async function setupVpn(secrets, ptyHostExe) {
33779
+ const vpn = session.vpn;
33780
+ if (!vpn) return true;
33781
+ const killSwitch = vpn.killSwitch;
33782
+ let blocked = false;
33783
+ const block = (servers) => {
33784
+ if (isWin && !dryRun) run2(killSwitchCommands(servers, ptyHostExe));
33785
+ blocked = true;
33786
+ log("VPN: kill switch on: nothing leaves the sandbox except through the tunnel.");
33787
+ };
33788
+ setVpnStatus("starting", "Starting the VPN");
33789
+ try {
33790
+ if (!session.networking) throw new Error("networking is off for this sandbox");
33791
+ const credentials = secrets.vpn;
33792
+ if (!credentials) throw new Error("the VPN login did not arrive (start the sandbox again)");
33793
+ const profile = path70.join(launchDir, "vpn", "server.ovpn");
33794
+ const remotes = assertSafeOvpn(fs56.readFileSync(profile, "utf8"), vpn.server);
33795
+ const exe = await ensureOpenVpn();
33796
+ const servers = await serverAddresses(remotes);
33797
+ if (servers.length === 0) throw new Error("the VPN server addresses could not be found");
33798
+ if (killSwitch) block(servers);
33799
+ if (dryRun || !isWin) {
33800
+ log("(dry run) would start the VPN tunnel to " + vpn.server);
33801
+ setVpnStatus("off", "dry run");
33802
+ return true;
33803
+ }
33804
+ log("VPN: connecting to " + vpn.server);
33805
+ const result = await startTunnel({ exe, profile, username: credentials.username, password: credentials.password });
33806
+ if (!result.ok) throw new Error(result.message);
33807
+ if (!result.tunnelIp || !hasAdapter(result.tunnelIp))
33808
+ throw new Error("the tunnel reported it was up, but no network adapter with its address appeared");
33809
+ if (killSwitch) run2(tunnelCommands(result.tunnelIp));
33810
+ const publicIp = await publicAddress();
33811
+ log("VPN: up" + (publicIp ? " (the sandbox appears as " + publicIp + ")" : "") + ".");
33812
+ setVpnStatus("up", "The tunnel is up", publicIp ? { publicIp } : {});
33813
+ return true;
33814
+ } catch (e) {
33815
+ const reason = errMsg(e);
33816
+ try {
33817
+ if (killSwitch && !blocked) block([]);
33818
+ } catch (blockError) {
33819
+ warn("VPN: could not close the network after the failure: " + errMsg(blockError));
33820
+ }
33821
+ 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.");
33822
+ warn(text);
33823
+ setVpnStatus("failed", reason);
33824
+ return false;
33825
+ }
33826
+ }
33827
+
33057
33828
  // src/shared/pty/protocol.ts
33058
33829
  var FrameType = {
33059
33830
  Hello: 1,
@@ -33250,7 +34021,7 @@ var OutputFilter = class {
33250
34021
  };
33251
34022
 
33252
34023
  // src/shared/pty/console-input.ts
33253
- import { spawn as spawn7 } from "node:child_process";
34024
+ import { spawn as spawn8 } from "node:child_process";
33254
34025
  function enableVtInput() {
33255
34026
  if (process.platform !== "win32" || !process.stdin.isTTY)
33256
34027
  return { ready: Promise.resolve(false), stop: () => Promise.resolve() };
@@ -33258,7 +34029,7 @@ function enableVtInput() {
33258
34029
  let exited = Promise.resolve();
33259
34030
  const ready = new Promise((resolve2) => {
33260
34031
  try {
33261
- child = spawn7(SYSTEM.powershell(), scriptArgs("enable-vt-input.ps1", ["-ProcessId", String(process.pid)]), {
34032
+ child = spawn8(SYSTEM.powershell(), scriptArgs("enable-vt-input.ps1", ["-ProcessId", String(process.pid)]), {
33262
34033
  stdio: "ignore",
33263
34034
  windowsHide: true
33264
34035
  });
@@ -33458,7 +34229,7 @@ async function viewSession(id) {
33458
34229
  }
33459
34230
 
33460
34231
  // src/guest/boot/boot-env.ts
33461
- import path64 from "node:path";
34232
+ import path71 from "node:path";
33462
34233
 
33463
34234
  // src/guest/boot/project-env.ts
33464
34235
  var EnvSchema = external_exports.object({
@@ -33477,7 +34248,7 @@ var BootEnvSchema = external_exports.object({
33477
34248
  });
33478
34249
 
33479
34250
  // src/guest/boot/boot-env.ts
33480
- var file2 = () => path64.join(localDir, "boot-env.json");
34251
+ var file2 = () => path71.join(localDir, "boot-env.json");
33481
34252
  function saveBootEnv(value) {
33482
34253
  try {
33483
34254
  writeJsonAtomic(file2(), value);
@@ -33505,8 +34276,52 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
33505
34276
  }
33506
34277
  }
33507
34278
 
34279
+ // src/guest/runtime/secrets.ts
34280
+ import fs57 from "node:fs";
34281
+
34282
+ // src/shared/channel/secrets.ts
34283
+ var Environment = external_exports.record(external_exports.string().max(256), external_exports.string().max(65536));
34284
+ var SecretsFileSchema = external_exports.strictObject({
34285
+ /** The agent the sandbox booted with: its harness environment. */
34286
+ harnessEnvironment: Environment.optional(),
34287
+ /** harnessSpec of a session request (an agent the sandbox did not boot with). */
34288
+ harnessSpecEnvironment: Environment.optional(),
34289
+ /** project.harnesses of a request, by agent name. */
34290
+ projectHarnessEnvironment: external_exports.record(external_exports.string().max(64), Environment).optional(),
34291
+ /** The login of this PC's Claude (claudeProfile.copyCredentials): the text of .credentials.json. */
34292
+ claudeCredentials: external_exports.string().max(1024 * 1024).optional(),
34293
+ /** VPN service credentials (vpn.provider's login), only for the launch's own sandbox. */
34294
+ vpn: external_exports.strictObject({ username: external_exports.string().min(1).max(256), password: external_exports.string().min(1).max(1024) }).optional()
34295
+ });
34296
+
34297
+ // src/guest/runtime/secrets.ts
34298
+ var BOOT_SECRETS_VARIABLE = "SBX_BOOT_SECRETS";
34299
+ var MAX_BYTES = 4 * 1024 * 1024;
34300
+ function takeSecrets(id) {
34301
+ const file3 = run.secretFile(id);
34302
+ let text;
34303
+ try {
34304
+ if (fs57.statSync(file3).size > MAX_BYTES) throw new Error("too big");
34305
+ text = fs57.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
34306
+ } catch {
34307
+ return {};
34308
+ } finally {
34309
+ fs57.rmSync(file3, { force: true });
34310
+ }
34311
+ try {
34312
+ const parsed = SecretsFileSchema.safeParse(JSON.parse(text));
34313
+ if (parsed.success) return parsed.data;
34314
+ } catch {
34315
+ }
34316
+ warn("The secrets file for " + id + " was not valid and was ignored.");
34317
+ return {};
34318
+ }
34319
+ function applyBootEnvironment(environment) {
34320
+ if (session.harness && environment) session.harness.environment = { ...environment };
34321
+ }
34322
+
33508
34323
  // src/guest/boot/boot.ts
33509
- var STEPS = 8;
34324
+ var STEPS = 9;
33510
34325
  var PRIMARY_POLLS = 600;
33511
34326
  var POLL_MS = 500;
33512
34327
  var VSCODE_LANGUAGES = ["python", "java", "go", "rust", "cpp", "msvc", "dotnet", "ruby", "php", "deno", "pwsh"];
@@ -33528,23 +34343,35 @@ async function soft(what, work) {
33528
34343
  warn(what + " failed (continuing): " + errMsg(e));
33529
34344
  }
33530
34345
  }
33531
- function startDaemon(env) {
33532
- spawn8(process.execPath, [path65.join(path65.dirname(process.argv[1]), "daemon.js")], {
34346
+ function startDaemon(env, secrets) {
34347
+ spawn9(process.execPath, [path72.join(path72.dirname(process.argv[1]), "daemon.js")], {
33533
34348
  detached: true,
33534
34349
  stdio: "ignore",
33535
34350
  windowsHide: true,
33536
- env: { ...env, AGENT_LOG_PREFIX: "daemon" }
34351
+ env: {
34352
+ ...env,
34353
+ AGENT_LOG_PREFIX: "daemon",
34354
+ // The agent's environment (it may hold API keys): the daemon moves it into memory and removes this at once.
34355
+ ...secrets.harnessEnvironment ? { [BOOT_SECRETS_VARIABLE]: JSON.stringify({ harnessEnvironment: secrets.harnessEnvironment }) } : {}
34356
+ }
33537
34357
  }).unref();
33538
34358
  }
33539
34359
  function writeDbCommand() {
33540
- const dir = mkdirp(path65.join(localDir, "bin"));
33541
- const db = path65.join(path65.dirname(process.argv[1]), "db.js");
33542
- fs52.writeFileSync(
33543
- path65.join(dir, "sbx-db.cmd"),
34360
+ const dir = mkdirp(path72.join(localDir, "bin"));
34361
+ const db = path72.join(path72.dirname(process.argv[1]), "db.js");
34362
+ fs58.writeFileSync(
34363
+ path72.join(dir, "sbx-db.cmd"),
33544
34364
  '@setlocal\r\n@set AGENT_LOG_PREFIX=db\r\n@"' + process.execPath + '" "' + db + '" %*\r\n'
33545
34365
  );
34366
+ writeAgentCommands(dir);
33546
34367
  return dir;
33547
34368
  }
34369
+ function writeAgentCommands(dir) {
34370
+ const install = { node: process.execPath, script: path72.join(path72.dirname(process.argv[1]), "agent.js") };
34371
+ for (const shim3 of agentShims(toolsDir, session.agents ?? {}))
34372
+ fs58.writeFileSync(path72.join(dir, shim3.command + ".cmd"), shimText(shim3, install));
34373
+ fs58.writeFileSync(path72.join(dir, "sbx-agent.cmd"), sbxAgentText(install));
34374
+ }
33548
34375
  async function waitForPrimary() {
33549
34376
  for (let i = 0; i < PRIMARY_POLLS; i++) {
33550
34377
  const s = run.readSession(session.launchId);
@@ -33565,17 +34392,22 @@ var Boot = class {
33565
34392
  ptyHost = null;
33566
34393
  lan = session.networking ? "open" : "offline";
33567
34394
  gitAccess = session.provisioning.git.access ?? "full";
34395
+ /** What the host handed over in its one-shot file (read and deleted at the start of run()). */
34396
+ secrets = {};
33568
34397
  async run() {
33569
34398
  log(
33570
34399
  "Agent sandbox: " + session.project + " | workspace " + workspace + " | agent " + session.harnessName + " | log " + logPath
33571
34400
  );
33572
- if (!fs52.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
34401
+ if (!fs58.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
33573
34402
  throw new Error("Workspace folder is missing in the sandbox: " + workspace);
33574
34403
  mkdirp(toolsDir);
33575
34404
  mkdirp(run.root);
34405
+ this.secrets = takeSecrets(session.launchId);
34406
+ applyBootEnvironment(this.secrets.harnessEnvironment);
33576
34407
  await this.networkAndSessionHost();
33577
34408
  await this.hooksAndDesktop();
33578
34409
  const { tools, env } = await this.developerTools();
34410
+ await this.vpn();
33579
34411
  await this.gitIdentity(env);
33580
34412
  await this.claude(tools);
33581
34413
  await this.agent(env);
@@ -33629,6 +34461,7 @@ var Boot = class {
33629
34461
  );
33630
34462
  const env = agentEnv(tools);
33631
34463
  persistEnvironment(env, Object.keys(tools.vars));
34464
+ await soft("Shell start-up PATH", installShellPath);
33632
34465
  saveBootEnv({
33633
34466
  basePath,
33634
34467
  toolVars: Object.keys(tools.vars),
@@ -33641,32 +34474,42 @@ var Boot = class {
33641
34474
  await soft("Cleaning old tool builds", () => pruneToolLeftovers());
33642
34475
  return { tools, env };
33643
34476
  }
34477
+ /** vpn.enabled: the tunnel and its kill switch, before anything else uses the network (git, the agent). */
34478
+ async vpn() {
34479
+ step(4, session.vpn ? "VPN (" + session.vpn.server + ")" : "VPN (off)");
34480
+ if (!session.vpn) return;
34481
+ await soft("VPN", async () => {
34482
+ await setupVpn(this.secrets, this.ptyHost);
34483
+ });
34484
+ }
33644
34485
  async gitIdentity(env) {
33645
- step(4, "Git identity");
34486
+ step(5, "Git identity");
33646
34487
  await soft("Git config", () => setupGitConfig(env));
33647
34488
  }
33648
34489
  async claude(tools) {
33649
- step(5, "Claude settings, history and claude-mem");
33650
- if (session.harnessName === "claude") await soft("Claude settings", syncClaudeProfile);
34490
+ step(6, "Claude settings, history and claude-mem");
34491
+ if (session.harnessName === "claude")
34492
+ await soft("Claude settings", () => syncClaudeProfile(this.secrets.claudeCredentials));
33651
34493
  await soft("claude-mem restore", restoreClaudeMem);
34494
+ await soft("Agent databases restore", restoreLocalState);
33652
34495
  await soft("Sandbox guide for the agent", () => writeGuides(tools.summary, this.lan));
33653
34496
  await soft("Claude managed settings", () => writeManagedSettings2(this.gitAccess));
33654
34497
  }
33655
34498
  async agent(env) {
33656
- step(6, "Agent: " + session.harnessName);
34499
+ step(7, "Agent: " + session.harnessName);
33657
34500
  linkProfileDirs(session.agentProfileDirs ?? {});
33658
34501
  if (session.harness) await agents.provision(session.harnessName, session.harness, env);
33659
34502
  }
33660
34503
  preAgentHooks(env) {
33661
- step(7, "Pre-agent hooks");
34504
+ step(8, "Pre-agent hooks");
33662
34505
  runHooks("pre-agent", env);
33663
34506
  }
33664
34507
  /** Ready: starts the session daemon and, with an agent, its first session, shown in this window. */
33665
34508
  async start(env) {
33666
- step(8, "Starting " + session.harnessName);
34509
+ step(9, "Starting " + session.harnessName);
33667
34510
  setSandboxStatus("ready", "Ready");
33668
34511
  if (!session.harness || session.autoSession === false) {
33669
- if (!dryRun) startDaemon(env);
34512
+ if (!dryRun) startDaemon(env, this.secrets);
33670
34513
  log("Ready" + (session.harness ? "" : " (no agent requested)") + ". Workspace: " + workspace);
33671
34514
  return;
33672
34515
  }
@@ -33678,7 +34521,7 @@ var Boot = class {
33678
34521
  runHooks("post-agent", env);
33679
34522
  return;
33680
34523
  }
33681
- startDaemon(env);
34524
+ startDaemon(env, this.secrets);
33682
34525
  writeJsonAtomic(run.requestFile(session.launchId), {
33683
34526
  kind: "session",
33684
34527
  id: session.launchId,
@@ -33702,11 +34545,11 @@ runBoot().catch((e) => {
33702
34545
  const message = errMsg(e) + (e instanceof Error && e.stack ? "\n" + e.stack : "");
33703
34546
  try {
33704
34547
  setSandboxStatus("failed", errMsg(e));
33705
- fs53.writeFileSync(path66.join(logsDir, "guest-error.txt"), message);
34548
+ fs59.writeFileSync(path73.join(logsDir, "guest-error.txt"), message);
33706
34549
  } catch {
33707
34550
  }
33708
34551
  console.error(
33709
- "\n\x1B[31mThe sandbox could not start: " + errMsg(e) + "\x1B[0m\nDetails: " + path66.join(logsDir, "guest-error.txt")
34552
+ "\n\x1B[31mThe sandbox could not start: " + errMsg(e) + "\x1B[0m\nDetails: " + path73.join(logsDir, "guest-error.txt")
33710
34553
  );
33711
34554
  process.exitCode = 1;
33712
34555
  });