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
package/README.md CHANGED
@@ -92,5 +92,6 @@ get `wsb`: [several projects](docs/projects.md#adding-folders-to-a-running-sandb
92
92
  - [Several projects](docs/projects.md): project roots, adding a project to a running sandbox, what each agent can see
93
93
  - [Changelog](CHANGELOG.md): what shipped in each version
94
94
  - [Security](docs/security.md): how your PC is protected, secrets, git access
95
+ - [VPN](docs/vpn.md): send the sandbox through NordVPN (or your own OpenVPN profile), with a kill switch
95
96
  - [Troubleshooting](docs/troubleshooting.md): common problems and fixes
96
97
  - [Development](docs/development.md): building, testing, releasing (code layout in [CLAUDE.md](CLAUDE.md))
@@ -37,7 +37,7 @@
37
37
  "otherUsers": false
38
38
  },
39
39
  "storage": {
40
- "root": "%LOCALAPPDATA%\\AgentSandbox",
40
+ "root": "%ProgramData%\\AgentSandbox\\users\\%USERNAME%",
41
41
  "persistAgentState": true,
42
42
  "dataName": "default",
43
43
  "markSandboxFiles": true,
@@ -51,6 +51,14 @@
51
51
  "dns": [],
52
52
  "proxy": ""
53
53
  },
54
+ "vpn": {
55
+ "enabled": false,
56
+ "provider": "nordvpn",
57
+ "protocol": "udp",
58
+ "country": "",
59
+ "configFile": "",
60
+ "killSwitch": true
61
+ },
54
62
  "provisioning": {
55
63
  "copyFromHost": true,
56
64
  "fallbackToInstall": true,
@@ -207,6 +215,10 @@
207
215
  "auto": false,
208
216
  "autoHide": false
209
217
  },
218
+ "web": {
219
+ "enabled": false,
220
+ "port": 47800
221
+ },
210
222
  "agentCommands": {
211
223
  "enabled": false,
212
224
  "agents": "auto"
@@ -238,6 +250,7 @@
238
250
  "globalStateFile": "auto",
239
251
  "copyCredentials": false,
240
252
  "overwrite": true,
253
+ "sharePluginsAcrossAccounts": false,
241
254
  "syncHistory": true,
242
255
  "historyScope": "project",
243
256
  "syncClaudeMem": true,
@@ -284,6 +297,9 @@
284
297
  ],
285
298
  "hostDir": "~/.codex"
286
299
  },
300
+ "localState": {
301
+ "CODEX_SQLITE_HOME": "sqlite"
302
+ },
287
303
  "resumeArguments": [
288
304
  "resume",
289
305
  "--last"
@@ -27,6 +27,10 @@ export interface CliOptions {
27
27
  follow: boolean;
28
28
  json: boolean;
29
29
  yes: boolean;
30
+ /** sessions --wide: also the folder column. */
31
+ wide: boolean;
32
+ /** storage move: keep the old folder (copy instead of rename). */
33
+ keepOld: boolean;
30
34
  timeout: number;
31
35
  days: number;
32
36
  /** restart: every session, not only this folder's project's. */
@@ -38,6 +42,8 @@ export interface CliOptions {
38
42
  grep?: string;
39
43
  /** migrate --dry-run, and --restore <backup folder>. */
40
44
  dryRun: boolean;
45
+ /** doctor --fix: repair what it finds without asking. */
46
+ fix: boolean;
41
47
  restore?: string;
42
48
  /** resume --auto: called by the background watcher after a crash. */
43
49
  auto: boolean;
@@ -62,7 +68,12 @@ export declare function splitArgs(text: string): string[];
62
68
  * `cwd`. Pure; validate.ts checks that the agent and folder exist.
63
69
  */
64
70
  export declare function parseSessionWant(input: string, cwd?: string): SessionWant;
65
- /** Every command, its options and help text, from manifest.ts. Actions only record what was parsed. */
66
- export declare function buildProgram(record: (name: string, cmd: Command) => void): Command;
71
+ /** "Unknown command" with the suggestion in our words; other commander errors only lose the lower-case start. */
72
+ export declare function friendlyError(text: string): string;
73
+ /**
74
+ * Every command, its options and help text, from manifest.ts. Actions only record what was parsed. `wrapper` = the
75
+ * sandbox <agent> spelling: --agent stays the agent's own flag there (Claude has one), only --harness is ours.
76
+ */
77
+ export declare function buildProgram(record: (name: string, cmd: Command) => void, wrapper?: boolean): Command;
67
78
  /** Parses argv into the command name and options. Throws commander errors for unknown commands/options. */
68
79
  export declare function parseCli(argv: string[], wrapper?: boolean): CliOptions;
package/dist/cli/args.js CHANGED
@@ -2,9 +2,10 @@
2
2
  // dispatches the result. sandbox claude & co parse as `launch`: every option launch does not own goes to the agent, in
3
3
  // order.
4
4
  import path from 'node:path';
5
- import { Command, InvalidArgumentError, Option } from 'commander';
5
+ import { Argument, Command, InvalidArgumentError, Option } from 'commander';
6
6
  import { fail } from '../core/util/index.js';
7
7
  import { c } from './output/index.js';
8
+ import { insideSandbox } from '../host/sandbox/index.js';
8
9
  import { COMMANDS } from './manifest.js';
9
10
  import { packageVersion } from '../core/package-info.js';
10
11
  /** Splits a command line like a shell: "quoted words" and 'quoted words' stay together. */
@@ -38,45 +39,109 @@ function positiveNumber(value) {
38
39
  function collect(value, previous = []) {
39
40
  return [...previous, value];
40
41
  }
41
- /** One commander option from its manifest entry. */
42
- function toOption(o) {
43
- const flags = (o.short ? o.short + ', ' : '') + o.flag + (o.type === 'boolean' ? '' : ' <' + (o.value ?? 'value') + '>');
44
- const option = new Option(flags, o.description);
45
- if (o.type === 'number')
46
- option.argParser(positiveNumber);
47
- if (o.type === 'list')
48
- option.argParser(collect);
49
- if (o.default !== undefined)
50
- option.default(o.default);
51
- return option;
42
+ /** Commands in --help, group by group, in this order (a command not listed comes last in its group). */
43
+ const HELP_ORDER = [
44
+ ['Agents', ['launch', 'start', 'resume', 'restart', 'stop', 'host']],
45
+ ['Sessions', ['sessions', 'attach', 'status', 'exec', 'show', 'hide', 'db']],
46
+ ['Projects & accounts', ['projects', 'account']],
47
+ ['Data', ['data', 'storage', 'clean', 'sync']],
48
+ ['Web', ['web']],
49
+ ['Health', ['setup', 'doctor', 'repair', 'logs', 'audit', 'update', 'migrate', 'config']],
50
+ ['Advanced', ['generate', 'agent-commands', 'vpn']],
51
+ ];
52
+ /** The commands in the order --help lists them. */
53
+ function helpOrdered() {
54
+ const flat = HELP_ORDER.flatMap(([, names]) => names);
55
+ const rank = (name) => {
56
+ const i = flat.indexOf(name);
57
+ return i < 0 ? flat.length : i;
58
+ };
59
+ return [...COMMANDS].sort((x, y) => rank(x.name) - rank(y.name));
60
+ }
61
+ /** The options of one manifest entry: the visible one, and a hidden old spelling when `shownAs` renames it. */
62
+ function toOptions(o, wrapper) {
63
+ const shown = o.shownAs && !wrapper ? o.shownAs : o.flag;
64
+ const placeholder = o.type === 'boolean' ? '' : ' <' + (o.value ?? 'value') + '>';
65
+ const make = (flag) => {
66
+ const option = new Option((o.short ? o.short + ', ' : '') + flag + placeholder, o.description);
67
+ if (o.type === 'number')
68
+ option.argParser(positiveNumber);
69
+ if (o.type === 'list')
70
+ option.argParser(collect);
71
+ if (o.default !== undefined)
72
+ option.default(o.default);
73
+ if (o.group)
74
+ option.helpGroup(o.group + ':');
75
+ return option;
76
+ };
77
+ const visible = make(shown);
78
+ return shown === o.flag ? [visible] : [visible, make(o.flag).hideHelp()];
52
79
  }
53
- /** Every command, its options and help text, from manifest.ts. Actions only record what was parsed. */
54
- export function buildProgram(record) {
80
+ /** A positional argument; fixed choices are checked by the parser and listed in --help. */
81
+ function toArgument(arg) {
82
+ const name = (arg.required ? '<' : '[') + arg.name + (arg.variadic ? '...' : '') + (arg.required ? '>' : ']');
83
+ const argument = new Argument(name, arg.description);
84
+ if (Array.isArray(arg.choices)) {
85
+ argument.choices(arg.choices);
86
+ const aliases = arg.aliases ?? [];
87
+ const check = argument.parseArg;
88
+ if (aliases.length && check)
89
+ argument.argParser((value, previous) => aliases.includes(value) ? value : check(value, previous));
90
+ }
91
+ return argument;
92
+ }
93
+ /** "Unknown command" with the suggestion in our words; other commander errors only lose the lower-case start. */
94
+ export function friendlyError(text) {
95
+ const m = /^error: unknown command '(.*)'\n\(Did you mean (.*)\?\)\n?$/.exec(text);
96
+ if (m) {
97
+ const names = m[2].replace(/^one of /, '').split(', ');
98
+ return 'Unknown command "' + m[1] + '". Did you mean: ' + names.map((n) => 'sandbox ' + n).join(' or ') + '?\n';
99
+ }
100
+ return text.replace(/^error: /, '').replace(/^./, (ch) => ch.toUpperCase());
101
+ }
102
+ function rootHelp() {
103
+ const lines = [
104
+ '',
105
+ 'Start an agent by name: sandbox claude, sandbox codex ... (the same as sandbox launch --agent <name>).',
106
+ 'Put --config <file> before or after the command to use another settings file.',
107
+ ];
108
+ if (insideSandbox())
109
+ lines.push('You are inside a sandbox: launch, resume, attach, restart, stop, exec, show, hide, storage and web control it from your PC and do not work here.');
110
+ lines.push('', 'Examples:', ' sandbox the menu', ' sandbox claude -t start Claude and attach this terminal', ' sandbox data clean logs delete the saved logs', ' sandbox exec -- npm test run a command in the running sandbox');
111
+ return lines.join('\n');
112
+ }
113
+ /**
114
+ * Every command, its options and help text, from manifest.ts. Actions only record what was parsed. `wrapper` = the
115
+ * sandbox <agent> spelling: --agent stays the agent's own flag there (Claude has one), only --harness is ours.
116
+ */
117
+ export function buildProgram(record, wrapper = false) {
55
118
  const program = new Command('sandbox')
56
119
  .description('A disposable Windows Sandbox for development, with or without an AI agent, for the folder you are in. Run it with no arguments for the menu.')
57
120
  .version(packageVersion(), '-v, --version', 'show the version')
58
121
  .enablePositionalOptions()
59
122
  .showHelpAfterError(' Fix: run the command with --help to see how to use it.')
60
- .configureOutput({
61
- outputError: (text, write) => write(c.red('Error: ') + text.replace(/^error: /, '').replace(/^./, (ch) => ch.toUpperCase())),
62
- })
63
- .addHelpText('after', '\nPut --config <file> before or after the command to use another settings file.\nExamples:\n sandbox the menu\n sandbox claude -t start Claude and attach this terminal\n sandbox data clean logs delete the saved logs\n sandbox exec -- npm test run a command in the running sandbox')
123
+ .configureOutput({ outputError: (text, write) => write(c.red('Error: ') + friendlyError(text)) })
124
+ .addHelpText('after', rootHelp)
64
125
  .exitOverride();
65
- for (const spec of COMMANDS) {
126
+ for (const spec of helpOrdered()) {
66
127
  const cmd = program
67
128
  .command(spec.name, { hidden: spec.hidden })
68
129
  .description(spec.summary)
69
- .option('--config <file>', 'config file (default: ~/.agent-sandbox/config.json)');
130
+ .helpGroup(spec.group + ':')
131
+ .addOption(new Option('--config <file>', 'config file (default: ~/.agent-sandbox/config.json)').hideHelp());
70
132
  for (const option of spec.options)
71
- cmd.addOption(toOption(option));
133
+ for (const o of toOptions(option, wrapper))
134
+ cmd.addOption(o);
72
135
  if (spec.json)
73
136
  cmd.option('--json', 'machine-readable output');
74
137
  for (const arg of spec.args)
75
- cmd.argument((arg.required ? '<' : '[') + arg.name + (arg.variadic ? '...' : '') + (arg.required ? '>' : ']'), arg.description);
138
+ cmd.addArgument(toArgument(arg));
76
139
  if (spec.passthrough === 'agent')
77
140
  cmd.argument('[agentArgs...]', 'passed to the agent').allowUnknownOption().allowExcessArguments();
78
141
  if (spec.passthrough === 'command')
79
142
  cmd.passThroughOptions();
143
+ if (spec.examples?.length)
144
+ cmd.addHelpText('after', '\nExamples:\n' + spec.examples.map((l) => ' ' + l).join('\n'));
80
145
  cmd.action((...args) => record(spec.name, args[args.length - 1]));
81
146
  }
82
147
  return program;
@@ -99,7 +164,7 @@ export function parseCli(argv, wrapper = false) {
99
164
  let parsed = null;
100
165
  const program = buildProgram((name, cmd) => {
101
166
  parsed = { name, cmd };
102
- });
167
+ }, wrapper);
103
168
  const launchFlags = new Set(program.commands
104
169
  .find((c) => c.name() === 'launch')
105
170
  .options.map((o) => o.long)
@@ -123,7 +188,7 @@ export function parseCli(argv, wrapper = false) {
123
188
  passthrough: forAgent || name === 'exec' ? operands : [],
124
189
  config: o.config,
125
190
  workspace: o.workspace,
126
- harness: o.harness,
191
+ harness: o.harness ?? (name !== 'account' && typeof o.agent === 'string' ? o.agent : undefined),
127
192
  account: o.account,
128
193
  node: o.node,
129
194
  python: o.python,
@@ -146,6 +211,8 @@ export function parseCli(argv, wrapper = false) {
146
211
  follow: Boolean(o.follow),
147
212
  json: Boolean(o.json),
148
213
  yes: Boolean(o.yes),
214
+ wide: Boolean(o.wide),
215
+ keepOld: Boolean(o.keepOld),
149
216
  all: Boolean(o.all),
150
217
  sessions: (o.session ?? []).map((s) => parseSessionWant(s)),
151
218
  timeout: o.timeout ?? 600,
@@ -153,6 +220,7 @@ export function parseCli(argv, wrapper = false) {
153
220
  kind: o.kind,
154
221
  grep: o.grep,
155
222
  dryRun: Boolean(o.dryRun),
223
+ fix: Boolean(o.fix),
156
224
  auto: o.auto === true,
157
225
  restore: o.restore,
158
226
  check: Boolean(o.check),
@@ -187,12 +255,15 @@ function defaults() {
187
255
  noRestart: false,
188
256
  follow: false,
189
257
  dryRun: false,
258
+ fix: false,
190
259
  auto: false,
191
260
  check: false,
192
261
  rollback: false,
193
262
  unattended: false,
194
263
  json: false,
195
264
  yes: false,
265
+ wide: false,
266
+ keepOld: false,
196
267
  all: false,
197
268
  sessions: [],
198
269
  timeout: 600,
@@ -1,6 +1,7 @@
1
1
  // `account list | save | use | default | rename | remove [--agent <name>]`
2
+ import { askChoice, askName, askRequired } from '../../core/prompt.js';
2
3
  import { fail, safeText } from '../../core/util/index.js';
3
- import { printJson, table } from '../output/index.js';
4
+ import { nextStep, printJson, table } from '../output/index.js';
4
5
  import { AccountsService } from '../services/index.js';
5
6
  function label(a) {
6
7
  return '"' + a.name + '"' + (a.email ? ' (' + a.email + ')' : '');
@@ -31,38 +32,65 @@ function list(ctx, accounts, agent) {
31
32
  return 0;
32
33
  }
33
34
  async function use(ctx, accounts, name, agent) {
34
- console.log('Sandbox now uses ' + label(accounts.activate(name, agent)) + '.');
35
+ const used = accounts.activate(name, agent);
36
+ console.log('Sandbox now uses ' + label(used) + '.');
37
+ if (used.note)
38
+ console.log(safeText(used.note));
35
39
  if (accounts.hasRunningSessions(agent) && !ctx.options.noRestart)
36
40
  console.log(safeText(await accounts.restart(agent)) + ' with --continue; the conversation carries on under the new account.');
37
41
  return 0;
38
42
  }
43
+ /** The account the command is about: the one typed, or one picked from the saved accounts. */
44
+ async function accountName(accounts, action, agent, given) {
45
+ if (given)
46
+ return given;
47
+ const usage = 'Usage: sandbox account ' + action + ' <name>';
48
+ if (action === 'save')
49
+ return askName('Name for this login:', usage, (v) => v.length > 0 || 'Type a name.');
50
+ const rows = accounts.list(agent);
51
+ if (!rows.length)
52
+ fail('No saved accounts.', 'Sign in inside the sandbox, then run: sandbox account save <name>');
53
+ return askChoice('Which account?', rows.map((a) => ({ name: safeText(label(a)), value: a.name })), usage);
54
+ }
55
+ async function remove(ctx, accounts, name, agent) {
56
+ const sure = ctx.options.yes ||
57
+ (await askRequired('Remove the saved account "' + name + '"? Its login cannot be recovered; you would sign in again.', 'Add --yes to remove it without asking.'));
58
+ if (!sure) {
59
+ console.log('Nothing removed.');
60
+ return 1;
61
+ }
62
+ accounts.remove(name, agent);
63
+ console.log('Removed account ' + name + '.');
64
+ return 0;
65
+ }
39
66
  export async function account(ctx) {
40
- const [action = 'list', name] = ctx.options.positionals;
41
- const newName = ctx.options.accountTo;
67
+ const [action = 'list', given] = ctx.options.positionals;
42
68
  const agent = ctx.options.accountAgent ?? 'claude';
43
69
  const accounts = new AccountsService(ctx);
44
- const needName = () => name ?? fail('Missing account name.', 'Usage: sandbox account ' + action + ' <name>');
70
+ if (action === 'list')
71
+ return list(ctx, accounts, agent);
72
+ const name = await accountName(accounts, action, agent, given);
45
73
  switch (action) {
46
- case 'list':
47
- return list(ctx, accounts, agent);
48
74
  case 'save':
49
- console.log('Saved account ' + label(accounts.save(needName(), Boolean(ctx.options.fromHost), agent)) + '.');
75
+ console.log('Saved account ' + label(accounts.save(name, Boolean(ctx.options.fromHost), agent)) + '.');
76
+ nextStep('sandbox account use ' + name + ' (the sandbox uses it)');
50
77
  return 0;
51
78
  case 'use':
52
- return use(ctx, accounts, needName(), agent);
79
+ return use(ctx, accounts, name, agent);
53
80
  case 'default':
54
- accounts.setDefault(needName(), agent);
81
+ accounts.setDefault(name, agent);
55
82
  console.log('Default account: ' + name);
56
83
  return 0;
57
- case 'rename':
58
- accounts.rename(needName(), newName ?? fail('Missing the new name.', 'Usage: sandbox account rename <name> --to <new-name>'), agent);
59
- console.log('Renamed account ' + name + ' to ' + newName);
84
+ case 'rename': {
85
+ const to = ctx.options.accountTo ??
86
+ (await askName('New name for "' + name + '":', 'Usage: sandbox account rename <name> --to <new-name>', (v) => v.length > 0 || 'Type a name.'));
87
+ accounts.rename(name, to, agent);
88
+ console.log('Renamed account ' + name + ' to ' + to + '.');
60
89
  return 0;
90
+ }
61
91
  case 'remove':
62
- accounts.remove(needName(), agent);
63
- console.log('Removed account ' + name);
64
- return 0;
92
+ return remove(ctx, accounts, name, agent);
65
93
  default:
66
- fail('Unknown account action "' + action + '".', 'Use one of: sandbox account list | save <name> | use <name> | default <name> | rename <name> --to <new-name> | remove <name>');
94
+ return fail('Unknown account action "' + action + '".', 'Use one of: sandbox account list | save <name> | use <name> | default <name> | rename <name> --to <new-name> | remove <name>');
67
95
  }
68
96
  }
@@ -15,6 +15,8 @@ export interface Context {
15
15
  borrowed?: Borrowed;
16
16
  }
17
17
  export declare function createContext(packageRoot: string, entry: string, options: CliOptions): Context;
18
+ /** Reads the config again and takes the storage folder from it (after a migration or a move changed it). */
19
+ export declare function refreshStorage(ctx: Context): void;
18
20
  /** For commands that control the sandbox from your PC: inside the sandbox they make no sense. */
19
21
  export declare function requireOnPc(what: string): void;
20
22
  export declare function requireRunning(hint?: string): void;
@@ -36,14 +36,21 @@ export function createContext(packageRoot, entry, options) {
36
36
  dataPath: insideSandbox() ? GUEST_DATA_DIR : path.join(storageRoot, 'data', loaded.config.storage.dataName),
37
37
  };
38
38
  }
39
+ /** Reads the config again and takes the storage folder from it (after a migration or a move changed it). */
40
+ export function refreshStorage(ctx) {
41
+ ctx.loaded = loadConfig(ctx.options.config);
42
+ ctx.storageRoot = expandPath(ctx.loaded.config.storage.root, ctx.loaded.base);
43
+ if (!insideSandbox())
44
+ ctx.dataPath = path.join(ctx.storageRoot, 'data', ctx.loaded.config.storage.dataName);
45
+ }
39
46
  /** For commands that control the sandbox from your PC: inside the sandbox they make no sense. */
40
47
  export function requireOnPc(what) {
41
48
  if (insideSandbox())
42
- fail('You are inside the sandbox already, so "sandbox ' + what + '" has nothing to control.', 'Run it from a terminal on your PC.');
49
+ fail('You are inside the sandbox already, so "sandbox ' + what + '" has nothing to control.', 'Run it from a terminal on your PC. Inside the sandbox these work: sandbox status, sessions, config, data, db, doctor, logs.');
43
50
  }
44
51
  export function requireRunning(hint = '') {
45
52
  if (!isSandboxRunning())
46
- fail('No Windows Sandbox is running.', hint || 'Start one with sandbox claude.');
53
+ fail('No Windows Sandbox is running.', hint || 'Start one: sandbox start (no agent) or sandbox claude.');
47
54
  }
48
55
  /**
49
56
  * Maps a folder on this PC to its path inside the running sandbox (only folders inside the mapped workspace exist
@@ -1,13 +1,34 @@
1
1
  // `sandbox data clean`: asks, then removes the folders the targets name (DataService does the work).
2
2
  import { humanBytes } from '../../../core/disk.js';
3
- import { askTyped, askYesNo } from '../../../core/prompt.js';
3
+ import { askChoices, askRequired, askTyped } from '../../../core/prompt.js';
4
4
  import { fail } from '../../../core/util/index.js';
5
- import { table } from '../../output/index.js';
5
+ import { nextStep, table, working } from '../../output/index.js';
6
6
  import { DataService } from '../../services/index.js';
7
+ import { cleanTargetOf } from './collect.js';
7
8
  export { resolveCleanTargets } from '../../services/index.js';
9
+ /** No target typed: a list of what can be cleaned, with sizes, to tick from (a terminal is needed). */
10
+ async function pickTargets(service) {
11
+ const fix = 'Name them: sandbox data clean logs tools/go (what exists: sandbox data)';
12
+ if (!process.stdin.isTTY)
13
+ fail('Which data should be cleaned?', fix);
14
+ const rows = await working('Measuring the saved data (big folders take a moment)', () => service.entries());
15
+ const choices = rows.flatMap((e) => {
16
+ const target = cleanTargetOf(e);
17
+ return target ? [{ name: target.padEnd(28) + humanBytes(e.bytes), value: target }] : [];
18
+ });
19
+ if (!choices.length)
20
+ return [];
21
+ return askChoices('What do you want to delete? (space ticks, enter confirms)', choices, fix);
22
+ }
8
23
  export async function dataClean(ctx) {
9
24
  const service = new DataService(ctx);
10
- const { targets, present: sized, totalBytes: total } = service.plan(ctx.options.positionals.slice(1));
25
+ const typed = ctx.options.positionals.slice(1);
26
+ const inputs = typed.length ? typed : await pickTargets(service);
27
+ if (!inputs.length) {
28
+ console.log('Nothing chosen, nothing removed.');
29
+ return 0;
30
+ }
31
+ const { targets, present: sized, totalBytes: total } = service.plan(inputs);
11
32
  if (!sized.length) {
12
33
  console.log('Nothing to remove: ' + targets.map((t) => t.target).join(', ') + ' do(es) not exist.');
13
34
  return 0;
@@ -20,18 +41,20 @@ export async function dataClean(ctx) {
20
41
  if (!yes) {
21
42
  const ok = sized.some((t) => t.target === 'all')
22
43
  ? await askTyped('This cannot be undone; the next sandbox starts from scratch and reinstalls everything.', 'all')
23
- : await askYesNo('Delete ' + sized.map((t) => t.target).join(', ') + ' (' + humanBytes(total) + ')? This cannot be undone.');
44
+ : await askRequired('Delete ' + sized.map((t) => t.target).join(', ') + ' (' + humanBytes(total) + ')? This cannot be undone.', 'Add --yes to delete without asking.');
24
45
  if (!ok) {
25
- console.log('Nothing removed.' + (process.stdin.isTTY ? '' : ' Pass --yes to confirm without a prompt.'));
46
+ console.log('Nothing removed.');
26
47
  return 1;
27
48
  }
28
49
  }
29
50
  const outcome = service.clean({ targets, present: sized, totalBytes: total });
30
- console.log('Freed ' +
31
- humanBytes(outcome.freedBytes) +
32
- '. ' +
33
- (outcome.touchedData ? 'The next sandbox reinstalls what it needs.' : ''));
34
51
  if (outcome.failed.length)
35
52
  fail('Could not remove everything: ' + outcome.failed.join('; '), 'Close programs using those folders and run the same command again.');
53
+ console.log('Removed ' +
54
+ sized.map((t) => t.target).join(', ') +
55
+ ' and freed ' +
56
+ humanBytes(outcome.freedBytes) +
57
+ (outcome.touchedData ? '; the next sandbox reinstalls what it needs.' : '.'));
58
+ nextStep('sandbox data (see what is left)');
36
59
  return 0;
37
60
  }
@@ -2,6 +2,7 @@ export { createContext, type Context } from './context.js';
2
2
  export { launch } from './launch/index.js';
3
3
  export { setup } from './setup/index.js';
4
4
  export { data } from './data/index.js';
5
+ export { storage, storageBeforeCommand } from './storage/index.js';
5
6
  export { repairCommand } from './repair/index.js';
6
7
  export { attach, db, exec, hide, show, restart, stop, sessions, status } from './sessions/index.js';
7
8
  export { account } from './accounts.js';
@@ -2,6 +2,7 @@ export { createContext } from './context.js';
2
2
  export { launch } from './launch/index.js';
3
3
  export { setup } from './setup/index.js';
4
4
  export { data } from './data/index.js';
5
+ export { storage, storageBeforeCommand } from './storage/index.js';
5
6
  export { repairCommand } from './repair/index.js';
6
7
  export { attach, db, exec, hide, show, restart, stop, sessions, status } from './sessions/index.js';
7
8
  export { account } from './accounts.js';
@@ -1,7 +1,8 @@
1
1
  import type { ResolvedRun } from '../../../core/types.js';
2
2
  import { type Context } from '../context.js';
3
3
  /**
4
- * Asked once per parent folder: map it at every start (a project root), so the projects next to this one open in the
5
- * running sandbox without a restart. The answer is saved to your config.
4
+ * Asked at a start from a folder whose parent is not shared yet ("Not now" asks again next time): map it at every
5
+ * start (a project root), so the projects next to this one open in the running sandbox without a restart. The answer is
6
+ * saved to your config.
6
7
  */
7
8
  export declare function maybeAddRoot(ctx: Context, run: ResolvedRun): Promise<void>;
@@ -4,10 +4,12 @@ import { isWithin, planMirrorWorkspace } from '../../../shared/paths/index.js';
4
4
  import { assertSafeMapping, assertSafeWorkspace } from '../../../core/safe-paths.js';
5
5
  import { isRootPath } from '../../../core/util/index.js';
6
6
  import { autoGuestWorkspace, placeInRoot } from '../../../core/run/index.js';
7
+ import { c } from '../../output/index.js';
7
8
  import { addToList, setSetting } from '../user-config.js';
8
9
  /**
9
- * Asked once per parent folder: map it at every start (a project root), so the projects next to this one open in the
10
- * running sandbox without a restart. The answer is saved to your config.
10
+ * Asked at a start from a folder whose parent is not shared yet ("Not now" asks again next time): map it at every
11
+ * start (a project root), so the projects next to this one open in the running sandbox without a restart. The answer is
12
+ * saved to your config.
11
13
  */
12
14
  export async function maybeAddRoot(ctx, run) {
13
15
  const { projects } = run.config;
@@ -27,23 +29,22 @@ export async function maybeAddRoot(ctx, run) {
27
29
  return;
28
30
  }
29
31
  const answer = await select({
30
- message: 'Map ' +
32
+ message: 'Share all projects in ' +
31
33
  parent +
32
- ' at every start, so other projects there (also new ones) open in the running sandbox without a restart? Agents in the sandbox can then see every project in it.',
34
+ ' with the sandbox?\n ' +
35
+ c.dim('Projects there, also new ones, then open without a restart. Agents can see every one of them.'),
33
36
  choices: [
34
- { name: 'Yes, from now on', value: 'yes' },
35
- { name: 'No (and do not ask again for this folder)', value: 'no' },
36
- { name: 'Never ask this again', value: 'never' },
37
+ { name: 'Yes, share ' + parent, value: 'yes' },
38
+ { name: 'Not now', value: 'no' },
39
+ { name: 'No, and stop asking', value: 'never' },
37
40
  ],
38
41
  });
39
42
  if (answer === 'yes') {
40
43
  addToList(ctx, ['projects', 'roots'], parent);
41
44
  run.config.projects.roots.push(parent);
42
- console.log('Added ' + parent + ' to projects.roots (sandbox projects roots remove ' + parent + ' undoes it).');
45
+ console.log('Added ' + parent + '. Undo: sandbox projects roots remove ' + parent);
43
46
  moveUnderRoot(run);
44
47
  }
45
- if (answer === 'no')
46
- addToList(ctx, ['projects', 'declinedRoots'], parent);
47
48
  if (answer === 'never')
48
49
  setSetting(ctx, ['projects', 'askToAddRoot'], false);
49
50
  }