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
@@ -0,0 +1,133 @@
1
+ // `sandbox doctor` and `sandbox repair`: both run the same checks through the same engine, a line each as it ends.
2
+ // doctor only looks (and offers to fix, or fixes with --fix); repair looks, lists what it would change, asks once, then
3
+ // fixes and writes a log. --json prints the results instead and never asks.
4
+ import path from 'node:path';
5
+ import { confirm } from '@inquirer/prompts';
6
+ import { DEFAULTS, userDir } from '../../../core/config/index.js';
7
+ import { packageVersion } from '../../../core/package-info.js';
8
+ import { expandPath, UserError } from '../../../core/util/index.js';
9
+ import { insideSandbox } from '../../../host/sandbox/index.js';
10
+ import { printJson, table } from '../../output/index.js';
11
+ import { HealthService } from '../../services/index.js';
12
+ import { createContext, requireOnPc } from '../context.js';
13
+ import { ALL_CHECKS } from './checks/index.js';
14
+ import { buildEnv } from './env.js';
15
+ import { HealthRun, summarize } from './engine.js';
16
+ import { logText, writeRepairLog } from './log.js';
17
+ import { HealthPrinter } from './printer.js';
18
+ const interactive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
19
+ const stdout = { write: (text) => void process.stdout.write(text) };
20
+ /** Runs the checks, then (when allowed) the fixes. `printer` is null for --json. */
21
+ export async function runHealth(env, printer, plan, checks = ALL_CHECKS, confirmFix = (q) => confirm({ message: q, default: true })) {
22
+ const run = new HealthRun(checks, env, printer?.hooks());
23
+ const found = await run.look();
24
+ const fixable = found.filter((r) => r.fixable);
25
+ let final = found;
26
+ let changed = false;
27
+ if (fixable.length) {
28
+ let go = plan.yes;
29
+ if (!go && plan.ask) {
30
+ printer?.plan(fixable);
31
+ go = await confirmFix(plan.question(fixable.length));
32
+ }
33
+ if (go) {
34
+ if (plan.yes)
35
+ printer?.plan(fixable);
36
+ final = await run.fix(found);
37
+ changed = true;
38
+ }
39
+ else
40
+ printer?.line('\nNothing was changed.');
41
+ }
42
+ return { found, final, summary: summarize(final), changed };
43
+ }
44
+ function quote(n, what) {
45
+ return n + ' ' + what + (n === 1 ? '' : 's');
46
+ }
47
+ /** `sandbox doctor` */
48
+ export async function runDoctor(ctx) {
49
+ const health = new HealthService(ctx);
50
+ if (insideSandbox()) {
51
+ table(health.doctor());
52
+ return 0;
53
+ }
54
+ const json = ctx.options.json;
55
+ const printer = json ? null : new HealthPrinter(stdout);
56
+ printer?.title('Checking this PC, the install, your settings and the sandbox...');
57
+ const env = buildEnv(ctx);
58
+ const report = await runHealth(env, printer, {
59
+ yes: ctx.options.fix,
60
+ ask: !json && interactive(),
61
+ question: (n) => quote(n, 'problem') + ' can be fixed. Fix ' + (n === 1 ? 'it' : 'them') + ' now?',
62
+ });
63
+ const details = health.doctor();
64
+ if (printJson(ctx, { checks: report.final, summary: report.summary, details }))
65
+ return 0;
66
+ printer?.summary(report.final, report.summary);
67
+ const left = report.final.filter((r) => r.fixable).length;
68
+ if (left && !report.changed)
69
+ printer?.line('\n' + quote(left, 'problem') + ' can be fixed: run sandbox repair (or sandbox doctor --fix).');
70
+ printer?.line('\n' + 'Details');
71
+ table(details);
72
+ return 0;
73
+ }
74
+ /** `sandbox repair` for a loaded context. */
75
+ export async function runRepair(ctx, configError = null) {
76
+ requireOnPc('repair');
77
+ const json = ctx.options.json;
78
+ const printer = json ? null : new HealthPrinter(stdout);
79
+ printer?.title('Checking this PC, the install, your settings and the sandbox...');
80
+ const env = buildEnv(ctx, configError);
81
+ const yes = ctx.options.yes;
82
+ const ask = !json && interactive();
83
+ const report = await runHealth(env, printer, {
84
+ yes,
85
+ ask,
86
+ question: (n) => 'Fix ' + (n === 1 ? 'this problem' : 'these ' + n + ' problems') + '?',
87
+ });
88
+ const when = new Date();
89
+ const log = writeRepairLog(ctx.storageRoot, logText({
90
+ when,
91
+ version: packageVersion(),
92
+ command: 'sandbox repair' + (yes ? ' --yes' : ''),
93
+ found: report.found,
94
+ final: report.final,
95
+ summary: report.summary,
96
+ }), when);
97
+ const stillFixable = report.final.filter((r) => r.fixable).length;
98
+ if (printJson(ctx, { checks: report.final, summary: report.summary, changed: report.changed, log })) {
99
+ return report.summary.needsYou ? 1 : 0;
100
+ }
101
+ printer?.summary(report.final, report.summary);
102
+ if (stillFixable && !ask && !yes)
103
+ printer?.line('\n' + quote(stillFixable, 'problem') + ' can be fixed: run sandbox repair --yes.');
104
+ printer?.line(log
105
+ ? '\nLog of what was found and changed: ' + log
106
+ : '\nNo log was written (the storage folder does not exist yet).');
107
+ return report.summary.needsYou ? 1 : 0;
108
+ }
109
+ /**
110
+ * Entry point that works even when the config file is broken (createContext would throw): falls back to the built-in
111
+ * defaults so the other checks still run, and reports the settings problem as a check of its own.
112
+ */
113
+ export function repairCommand(packageRoot, entry, options) {
114
+ let ctx;
115
+ try {
116
+ ctx = createContext(packageRoot, entry, options);
117
+ }
118
+ catch (e) {
119
+ if (!(e instanceof UserError))
120
+ throw e;
121
+ const loaded = { config: structuredClone(DEFAULTS), configPath: null, base: userDir() };
122
+ const storageRoot = expandPath(loaded.config.storage.root, loaded.base);
123
+ return runRepair({
124
+ packageRoot,
125
+ entry,
126
+ options,
127
+ loaded,
128
+ storageRoot,
129
+ dataPath: path.join(storageRoot, 'data', loaded.config.storage.dataName),
130
+ }, e);
131
+ }
132
+ return runRepair(ctx);
133
+ }
@@ -1,11 +1,89 @@
1
1
  import type { UserError } from '../../../core/util/index.js';
2
+ import type { InstallLayout, InstallRecord } from '../../../host/install/index.js';
3
+ import type { SystemProbe } from '../../../host/health/index.js';
4
+ import type { MachineFacts } from '../setup/facts.js';
5
+ import type { Migration } from '../../../host/migrate/index.js';
2
6
  import type { Context } from '../context.js';
3
7
  export type RepairStatus = 'ok' | 'fixed' | 'needs-you' | 'warn' | 'skipped';
8
+ /** The headings the output is grouped under, in the order they are shown. */
9
+ export declare const CHECK_GROUPS: readonly ["This PC", "Install", "Data folder", "Settings", "Sandbox", "Agents & tools", "Network"];
10
+ export type CheckGroup = (typeof CHECK_GROUPS)[number];
11
+ /** The short form of a result (the menu shows these). */
4
12
  export interface RepairResult {
5
13
  name: string;
6
14
  status: RepairStatus;
7
15
  detail: string;
8
16
  }
17
+ /** What a check's run() finds. */
18
+ export interface Finding {
19
+ /** ok, a warning (nothing to do now), something you need to do, or not checked. */
20
+ status: 'ok' | 'warn' | 'needs-you' | 'skipped';
21
+ /** One line: what was found. */
22
+ detail: string;
23
+ /** What it means for you (shown when not ok). */
24
+ means?: string;
25
+ /** What to do about it yourself, when repair cannot (a command or a step). */
26
+ fix?: string;
27
+ /** What repair would change, in a few words ("remove 2 stale records"). Set only when fix() can mend this. */
28
+ plan?: string;
29
+ /** More lines shown under the plan when repair lists what it will change (a diff, the folders). */
30
+ lines?: string[];
31
+ /** Handed to fix() unchanged: what run() decided (the folders to remove ...). */
32
+ data?: unknown;
33
+ }
34
+ /** What a fix reports: what it changed. The before/after lines come from running the check again. */
35
+ export interface FixOutcome {
36
+ done: string;
37
+ }
38
+ export interface Check {
39
+ /** Stable id (kebab-case): used in --json and the repair log. */
40
+ id: string;
41
+ group: CheckGroup;
42
+ /** Short label for the result line ("Data folder"). */
43
+ name: string;
44
+ /** "the data folder" in "Checking the data folder..."; the lower-cased name when left out. */
45
+ checking?: string;
46
+ /** Not shown at all when it returns false (an all-users check on another install). */
47
+ applies?: (env: RepairEnv) => boolean;
48
+ /** Slower checks (the network, Windows tools) say how long they may take; the default is 20 seconds. */
49
+ timeoutMs?: number;
50
+ /** look: do not even look while a sandbox runs (the folders are in use). fix: look, but fix only when none runs. */
51
+ needsIdle?: 'look' | 'fix';
52
+ run: (env: RepairEnv) => Finding | Promise<Finding>;
53
+ fix?: (env: RepairEnv, finding: Finding) => FixOutcome | Promise<FixOutcome>;
54
+ }
55
+ export interface CheckResult extends RepairResult {
56
+ id: string;
57
+ group: CheckGroup;
58
+ means?: string;
59
+ fix?: string;
60
+ plan?: string;
61
+ lines?: string[];
62
+ /** Repair can mend this one (a plan exists and the check has a fix). */
63
+ fixable: boolean;
64
+ timedOut?: boolean;
65
+ /** Milliseconds the look took. */
66
+ ms: number;
67
+ /** After a fix: what was changed, and what the check said before. */
68
+ applied?: {
69
+ done: string;
70
+ before: string;
71
+ after: string;
72
+ };
73
+ /** After a fix that failed: why. */
74
+ error?: string;
75
+ }
76
+ export interface Summary {
77
+ total: number;
78
+ ok: number;
79
+ fixed: number;
80
+ warn: number;
81
+ needsYou: number;
82
+ skipped: number;
83
+ /** Results repair could still mend. */
84
+ fixable: number;
85
+ }
86
+ /** Everything the checks read, in one place: injectable, so tests point it at temp folders. */
9
87
  export interface RepairEnv {
10
88
  ctx: Context;
11
89
  running: boolean;
@@ -13,14 +91,24 @@ export interface RepairEnv {
13
91
  storageRoot: string;
14
92
  toolsDir: string;
15
93
  configError: UserError | null;
94
+ /** The managed install this program runs from, or null (npm). */
95
+ layout: InstallLayout | null;
96
+ /** install.json of that install. */
97
+ record: InstallRecord | null;
98
+ /** %ProgramData%\AgentSandbox (the PC-wide folder of an all-users install). */
99
+ machineHome: string;
100
+ /** ~/.agent-sandbox: the settings file and what belongs to it. */
101
+ userDir: string;
102
+ /** The settings file in use (--config, AGENT_SANDBOX_CONFIG, else <userDir>\config.json). */
103
+ configFile: string;
104
+ /** The settings updates that exist (a test gives its own). */
105
+ migrations: readonly Migration[];
106
+ /** The user-scope install folder next to an all-users one (checked for leftovers). */
107
+ userInstallRoot: string | null;
108
+ system: SystemProbe;
109
+ now: () => number;
110
+ /** What `sandbox setup` learns about this PC (looked up once, the first time a check asks). */
111
+ facts: () => MachineFacts;
16
112
  }
17
- export interface RepairCheck {
18
- name: string;
19
- run: (env: RepairEnv) => Omit<RepairResult, 'name'>;
20
- }
21
- export declare function ok(detail: string): Omit<RepairResult, 'name'>;
22
113
  /** For fixes that must not touch folders a running sandbox may be using. */
23
- export declare const whileRunning: {
24
- status: "skipped";
25
- detail: string;
26
- };
114
+ export declare const WHILE_RUNNING = "a sandbox is running and may be using it; run repair again once it is closed";
@@ -1,8 +1,12 @@
1
- export function ok(detail) {
2
- return { status: 'ok', detail };
3
- }
1
+ /** The headings the output is grouped under, in the order they are shown. */
2
+ export const CHECK_GROUPS = [
3
+ 'This PC',
4
+ 'Install',
5
+ 'Data folder',
6
+ 'Settings',
7
+ 'Sandbox',
8
+ 'Agents & tools',
9
+ 'Network',
10
+ ];
4
11
  /** For fixes that must not touch folders a running sandbox may be using. */
5
- export const whileRunning = {
6
- status: 'skipped',
7
- detail: 'a sandbox is running and may be using it; run repair again once it is closed',
8
- };
12
+ export const WHILE_RUNNING = 'a sandbox is running and may be using it; run repair again once it is closed';
@@ -24,7 +24,7 @@ export async function resume(ctx) {
24
24
  const { storageRoot, dataPath, options } = ctx;
25
25
  const saved = new SessionLedger(storageRoot, dataPath).read();
26
26
  if (!saved) {
27
- console.log('Nothing to reopen: no sandbox of this tool has been recorded yet.');
27
+ console.log('Nothing to resume. Start one: sandbox claude.');
28
28
  return 0;
29
29
  }
30
30
  // By hand, you asked for it. From the watcher, the setting decides.
@@ -32,7 +32,7 @@ export async function resume(ctx) {
32
32
  const life = new LifeRecord(storageRoot, dataPath).read();
33
33
  const reopening = !options.auto || shouldReopen(setting === 'ask' ? 'always' : setting, life, saved) === 'reopen';
34
34
  if (!options.auto && !saved.sessions.length) {
35
- console.log('Nothing to reopen: no agent sessions were running in the last sandbox.');
35
+ console.log('Nothing to resume. Start one: sandbox claude.');
36
36
  return 0;
37
37
  }
38
38
  if (reopening && saved.sessions.length)
@@ -23,9 +23,10 @@ export async function sessions(asked) {
23
23
  return 0;
24
24
  }
25
25
  // Harness, cwd and times are written by the sandbox.
26
+ const wide = ctx.options.wide;
26
27
  const folderWidth = Math.max(16, termWidth() - 80);
27
28
  table([
28
- ['', 'ID', 'AGENT', 'PROJECT', 'STATE', 'ATTACHED', 'FOLDER', 'STARTED'],
29
+ ['', 'ID', 'AGENT', 'PROJECT', 'STATE', 'ATTACHED', ...(wide ? ['FOLDER'] : []), 'STARTED'],
29
30
  ...service
30
31
  .ordered(list)
31
32
  .map((s) => [
@@ -35,11 +36,13 @@ export async function sessions(asked) {
35
36
  safeText(s.projectName ?? '-'),
36
37
  s.phase + (s.exitCode !== undefined ? ' (' + s.exitCode + ')' : ''),
37
38
  viewerText(s.viewers),
38
- shortenMiddle(safeText(s.cwd), folderWidth),
39
+ ...(wide ? [shortenMiddle(safeText(s.cwd), folderWidth)] : []),
39
40
  ago(s.startedAt),
40
41
  ]),
41
42
  ]);
42
43
  if (list.some((s) => s.here))
43
44
  console.log(c.dim('* = the project of this folder'));
45
+ if (!wide)
46
+ console.log(c.dim('Folders: sandbox sessions --wide'));
44
47
  return 0;
45
48
  }
@@ -1,2 +1,4 @@
1
1
  import type { Context } from '../context.js';
2
+ /** "pong (2 session(s) running)" from the helper in the sandbox, in plain words. */
3
+ export declare function helperText(answer: string): string;
2
4
  export declare function status(asked: Context): Promise<number>;
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import { safeText } from '../../../core/util/index.js';
3
2
  import { printJson, table, ago, c, shortenMiddle, termWidth } from '../../output/index.js';
4
3
  import { SandboxService } from '../../services/index.js';
@@ -29,6 +28,13 @@ function printProject(p) {
29
28
  for (const f of p.repoGuard)
30
29
  console.log(' ' + c.yellow('guard: ' + f));
31
30
  }
31
+ /** "pong (2 session(s) running)" from the helper in the sandbox, in plain words. */
32
+ export function helperText(answer) {
33
+ const sessions = /^pong \((\d+) session/.exec(answer);
34
+ if (!sessions)
35
+ return answer === '-' ? '-' : safeText(answer);
36
+ return 'responding, ' + sessions[1] + (sessions[1] === '1' ? ' session' : ' sessions') + ' running';
37
+ }
32
38
  export async function status(asked) {
33
39
  // Another user's sandbox: shared, it is shown from their folders; not shared, only whose it is.
34
40
  const view = lookAtSandbox(asked);
@@ -63,19 +69,34 @@ export async function status(asked) {
63
69
  };
64
70
  if (printJson(ctx, info))
65
71
  return 0;
66
- const yesNo = (v) => (typeof v === 'boolean' ? (v ? 'yes' : 'no') : String(v ?? '-'));
72
+ const sb = info.sandbox;
67
73
  if (view.line)
68
74
  console.log(c.bold(view.line) + c.dim('. Its window is on their desktop; use its agents here.'));
69
- table(Object.entries(info.sandbox).map(([k, v]) => [_.startCase(k), safeText(yesNo(v))]));
75
+ table([
76
+ ...(ctx.borrowed ? [['Started by', safeText(ctx.borrowed.user)]] : []),
77
+ ['Running', sb.running ? 'yes' : 'no'],
78
+ ...(sb.running
79
+ ? [
80
+ ['Phase', safeText(sb.phase ?? '-')],
81
+ ['Message', safeText(sb.message ?? '-')],
82
+ ['Window', sb.headless ? 'hidden (sandbox show opens it)' : 'shown'],
83
+ ['Uptime', sb.uptime ?? '-'],
84
+ ['Helper', helperText(sb.daemon)],
85
+ ]
86
+ : []),
87
+ ['Account', sb.account ? safeText(sb.account) : 'none selected (sandbox account use)'],
88
+ ['Background sync', sb.syncWatcher ? 'on' : 'off'],
89
+ ]);
70
90
  if (!state.running)
71
91
  return 0;
72
- console.log('\n' +
73
- c.bold('Projects') +
74
- c.dim(' (* = this folder: ' + info.here.folder + (info.here.project ? '' : ', not in this sandbox') + ')'));
92
+ console.log('\n' + c.bold('Projects'));
75
93
  for (const p of info.projects)
76
94
  printProject(p);
77
95
  for (const r of info.roots)
78
96
  console.log(' root ' + r.host + ' -> ' + r.guest + c.dim(' (every project in it opens without a restart)'));
97
+ console.log(c.dim(info.projects.some((p) => p.here)
98
+ ? '* = the project of this folder'
99
+ : info.here.folder + ' is not in this sandbox (start it here: sandbox claude)'));
79
100
  for (const s of info.otherSessions)
80
101
  console.log(' session ' + s.id + ' ' + s.harness + ' ' + s.cwd);
81
102
  const findings = info.repoGuard.findings;
@@ -1,2 +1,7 @@
1
1
  import { type Context } from '../context.js';
2
+ /**
3
+ * First start on a PC without Windows Sandbox: offers to turn it on (the setup steps) instead of a bare error.
4
+ * Returns the setup's exit code, or undefined when there is nothing to offer (it is on, no terminal, or declined).
5
+ */
6
+ export declare function offerSetupWhenOff(ctx: Context): Promise<number | undefined>;
2
7
  export declare function setup(ctx: Context): Promise<number>;
@@ -1,6 +1,10 @@
1
1
  // `sandbox setup`: checks this PC can run Windows Sandbox and offers to turn the feature on.
2
+ import { spawnSync } from 'node:child_process';
2
3
  import { askYesNo } from '../../../core/prompt.js';
3
- import { fail } from '../../../core/util/index.js';
4
+ import { fail, isWin } from '../../../core/util/index.js';
5
+ import { insideSandbox, sandboxFeatureInstalled } from '../../../host/sandbox/index.js';
6
+ import { refuseInSelfTest } from '../../../host/test-guard.js';
7
+ import { SYSTEM } from '../../../shared/system.js';
4
8
  import { c, table } from '../../output/index.js';
5
9
  import { HealthService } from '../../services/index.js';
6
10
  import { ENABLE_COMMAND } from './facts.js';
@@ -12,6 +16,25 @@ const LABEL = {
12
16
  function print(checks) {
13
17
  table(checks.map((check) => [LABEL[check.status], check.name, check.detail]));
14
18
  }
19
+ /** Seconds Windows waits before it restarts (shutdown /a cancels in that time). */
20
+ const RESTART_DELAY_SECONDS = 30;
21
+ /** After turning the feature on Windows must restart: offered, never done without a yes. */
22
+ async function offerRestart() {
23
+ if (!(await askYesNo('Restart Windows now?')))
24
+ return;
25
+ refuseInSelfTest('restart Windows');
26
+ spawnSync(SYSTEM.shutdown(), ['/r', '/t', String(RESTART_DELAY_SECONDS)], { windowsHide: true });
27
+ console.log('Windows restarts in ' + RESTART_DELAY_SECONDS + ' seconds. To cancel: shutdown /a');
28
+ }
29
+ /**
30
+ * First start on a PC without Windows Sandbox: offers to turn it on (the setup steps) instead of a bare error.
31
+ * Returns the setup's exit code, or undefined when there is nothing to offer (it is on, no terminal, or declined).
32
+ */
33
+ export async function offerSetupWhenOff(ctx) {
34
+ if (!isWin || insideSandbox() || sandboxFeatureInstalled() || !process.stdin.isTTY)
35
+ return undefined;
36
+ return (await askYesNo('Windows Sandbox is not turned on. Turn it on now?', true)) ? setup(ctx) : undefined;
37
+ }
15
38
  export async function setup(ctx) {
16
39
  const health = new HealthService(ctx);
17
40
  health.assertWindows();
@@ -28,6 +51,7 @@ export async function setup(ctx) {
28
51
  console.log('Done. Restart Windows to finish, then run sandbox setup again.\n');
29
52
  checks = health.setupReport().checks;
30
53
  print(checks);
54
+ await offerRestart();
31
55
  }
32
56
  else
33
57
  console.log('To do it yourself, in an admin PowerShell run:\n ' + ENABLE_COMMAND + '\nthen restart Windows.');
@@ -0,0 +1,2 @@
1
+ export { storage, storageBusy, performMove } from './storage.js';
2
+ export { storageBeforeCommand } from './offer.js';
@@ -0,0 +1,2 @@
1
+ export { storage, storageBusy, performMove } from './storage.js';
2
+ export { storageBeforeCommand } from './offer.js';
@@ -0,0 +1,3 @@
1
+ import { type Context } from '../context.js';
2
+ /** Before a command (after the saved settings are up to date). A failed move never stops the command. */
3
+ export declare function storageBeforeCommand(ctx: Context, command: string): Promise<void>;
@@ -0,0 +1,85 @@
1
+ // At the start of an interactive command: makes sure the storage folder exists (private when it should be) and, once,
2
+ // offers to move saved data from another folder to where it belongs. Never asks without a terminal.
3
+ import { select } from '@inquirer/prompts';
4
+ import { userDir } from '../../../core/config/index.js';
5
+ import { errMsg } from '../../../core/util/index.js';
6
+ import { isSandboxRunning, insideSandbox } from '../../../host/sandbox/index.js';
7
+ import { protectPrivateFolder } from '../../../host/sharing/index.js';
8
+ import { describeDuration, describeSize, ensureStorageRoot, estimate, measureFolder, moveWarning, planOffer, StorageHistory, } from '../../../host/storage/index.js';
9
+ import { c, working } from '../../output/index.js';
10
+ import { refreshStorage } from '../context.js';
11
+ import { performMove } from './storage.js';
12
+ /** Commands that do not touch the storage folder, or must work whatever state it is in. */
13
+ const NO_STORAGE = ['self-test', '_watch', '_web', 'update', 'storage', 'migrate', 'repair'];
14
+ /** Commands that start something the user is sitting in front of: the offer is shown before them. */
15
+ const OFFERS = ['menu', 'launch'];
16
+ async function ask(text) {
17
+ console.error('\n' + text + '\n');
18
+ return select({
19
+ message: 'Move it now?',
20
+ choices: [
21
+ { name: 'Move now', value: 'now' },
22
+ { name: 'Not now', value: 'later' },
23
+ { name: "Don't ask again", value: 'never' },
24
+ ],
25
+ default: 'now',
26
+ });
27
+ }
28
+ function offerText(offer, size, time, warning) {
29
+ const where = offer.toIsDefault
30
+ ? 'The default folder is now ' + offer.to + ', which works for both kinds of install.'
31
+ : 'Your folder is ' + offer.to + '.';
32
+ return ('Your saved data (' +
33
+ size +
34
+ ') is in ' +
35
+ offer.from +
36
+ '. ' +
37
+ where +
38
+ ' Move it there now? ' +
39
+ time +
40
+ '.' +
41
+ (warning ? '\n' + warning : ''));
42
+ }
43
+ async function offerMove(ctx, history) {
44
+ const offer = planOffer(ctx.storageRoot, history);
45
+ if (!offer || isSandboxRunning())
46
+ return;
47
+ const measured = await working('Looking at your saved data', () => measureFolder(offer.from));
48
+ const est = estimate(offer.from, offer.to, measured);
49
+ const spoken = est.sameVolume ? 'a few seconds' : describeDuration(est.seconds);
50
+ const time = spoken.charAt(0).toUpperCase() + spoken.slice(1);
51
+ if (!est.fits) {
52
+ console.error(c.dim(moveWarning(measured, est) ?? ''));
53
+ return;
54
+ }
55
+ const answer = await ask(offerText(offer, describeSize(measured), time, moveWarning(measured, est)));
56
+ if (answer === 'never')
57
+ history.setDontAsk();
58
+ else if (answer === 'later')
59
+ history.setNotNow();
60
+ if (answer !== 'now')
61
+ return;
62
+ const result = await performMove({ ...ctx, storageRoot: offer.from }, offer.to, false);
63
+ console.error('Moved. Your data is now in ' + result.to + '.');
64
+ for (const note of result.notes)
65
+ console.error(c.dim(note));
66
+ refreshStorage(ctx);
67
+ }
68
+ /** Before a command (after the saved settings are up to date). A failed move never stops the command. */
69
+ export async function storageBeforeCommand(ctx, command) {
70
+ if (insideSandbox() || NO_STORAGE.includes(command))
71
+ return;
72
+ if (OFFERS.includes(command) &&
73
+ process.stdin.isTTY &&
74
+ process.stdout.isTTY &&
75
+ !ctx.options.json &&
76
+ !ctx.options.unattended) {
77
+ try {
78
+ await offerMove(ctx, new StorageHistory(userDir()));
79
+ }
80
+ catch (e) {
81
+ console.error(c.red('Could not move your data: ') + errMsg(e));
82
+ }
83
+ }
84
+ ensureStorageRoot(ctx.storageRoot, protectPrivateFolder);
85
+ }
@@ -0,0 +1,8 @@
1
+ import { type MoveResult } from '../../../host/storage/index.js';
2
+ import { type Context } from '../context.js';
3
+ /** Why a move cannot start (a background sync is still on a data folder in the old storage), or null. */
4
+ export declare function storageBusy(root: string): string | null;
5
+ /** Moves the data with progress on the terminal; remembers both folders. Used by the command and the start offer. */
6
+ export declare function performMove(ctx: Context, to: string, keepOld: boolean): Promise<MoveResult>;
7
+ /** `sandbox storage [show|move <folder>|use <folder>]`. */
8
+ export declare function storage(ctx: Context): number | Promise<number>;