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
@@ -1,33 +1,66 @@
1
1
  // The common shape of a tab that is a list: it loads its data, builds a list screen from it, and acts on what the list
2
2
  // returns. After every action the list is built again from fresh data, on the same entry.
3
- import { ListScreen } from '../../tui/index.js';
3
+ import { ListScreen, } from '../../tui/index.js';
4
4
  export class ListPage {
5
5
  app;
6
6
  stages = false;
7
7
  list;
8
8
  notice;
9
+ /** The list has the keyboard (the menu's navigation does not). */
10
+ focused = true;
11
+ /** The entry that was last acted on: the cursor returns to it when the section opens again. */
12
+ lastFocus;
9
13
  constructor(app) {
10
14
  this.app = app;
11
15
  }
16
+ /** The entry the cursor starts on the first time the section opens (default: the first). */
17
+ initialFocus() {
18
+ return undefined;
19
+ }
12
20
  get capturing() {
13
21
  return this.list?.isSearching ?? false;
14
22
  }
15
- /** The id of the open sidebar category, if the list has one. */
23
+ /** The id of the open category, if the list has any. */
16
24
  get category() {
17
25
  return this.list?.currentCategory;
18
26
  }
27
+ categories() {
28
+ return this.screen().categories;
29
+ }
30
+ async selectCategory(id) {
31
+ this.screen().setCategory(id);
32
+ await this.afterKey();
33
+ }
34
+ setFocus(list) {
35
+ this.focused = list;
36
+ this.list?.setActive(list);
37
+ }
38
+ /** The list on screen, built when there is none yet. */
39
+ screen() {
40
+ return (this.list ??= this.build({}));
41
+ }
42
+ /** A list from the current data; its categories are shown by the menu's navigation. */
43
+ build(extra) {
44
+ const list = new ListScreen({ ...this.options(), ...extra, categoryNav: 'external', escapeLabel: 'sections' });
45
+ list.setActive(this.focused);
46
+ return list;
47
+ }
19
48
  /** The entries ticked in a multi-select list. */
20
49
  ticked() {
21
50
  return this.list?.ticked() ?? [];
22
51
  }
23
52
  async open() {
24
53
  await this.load();
25
- this.rebuild(undefined);
54
+ // Back on the entry used last, when it is still in the category that is open.
55
+ const wanted = this.lastFocus ?? this.initialFocus();
56
+ const open = this.list?.currentCategory;
57
+ const item = wanted === undefined ? undefined : this.options().items.find((i) => i.value === wanted);
58
+ this.rebuild(item && (!open || !item.category || item.category === open) ? wanted : undefined);
26
59
  }
27
60
  /** Builds the list again, on `focus` when it is still there. */
28
61
  rebuild(focus, notice) {
29
62
  const startCategory = this.list?.currentCategory;
30
- this.list = new ListScreen({ ...this.options(), startAt: focus, startCategory, notice: notice ?? this.notice });
63
+ this.list = this.build({ startAt: focus, startCategory, notice: notice ?? this.notice });
31
64
  this.notice = undefined;
32
65
  }
33
66
  /** Shows `text` now, before slow work starts. */
@@ -40,12 +73,10 @@ export class ListPage {
40
73
  this.notice = text;
41
74
  }
42
75
  render(size) {
43
- this.list ??= new ListScreen(this.options());
44
- return this.list.render(size);
76
+ return this.screen().render(size);
45
77
  }
46
78
  async handle(key) {
47
- this.list ??= new ListScreen(this.options());
48
- const step = this.list.handle(key);
79
+ const step = this.screen().handle(key);
49
80
  if (!step)
50
81
  return this.afterKey();
51
82
  const result = step.done;
@@ -55,6 +86,7 @@ export class ListPage {
55
86
  if (outcome.reload)
56
87
  await this.load();
57
88
  const here = result.kind === 'pick' || result.kind === 'action' ? result.value : undefined;
89
+ this.lastFocus = outcome.focus ?? here ?? this.lastFocus;
58
90
  this.rebuild(outcome.focus ?? here, outcome.notice);
59
91
  return;
60
92
  }
@@ -8,6 +8,12 @@ import type { Step } from '../../tui/index.js';
8
8
  import type { ShellExit } from '../shell.js';
9
9
  import { ListPage, type Outcome } from './list-page.js';
10
10
  export interface MaintenanceModel {
11
+ /** The data folder row (where the sandbox keeps its data). */
12
+ readonly dataFolder: {
13
+ label: string;
14
+ hint: string;
15
+ description: string;
16
+ };
11
17
  /** Null until measured (measuring a big data folder takes a while). */
12
18
  readonly data: {
13
19
  entries: DataEntry[];
@@ -69,8 +75,11 @@ export declare class MaintenancePage extends ListPage<string> {
69
75
  private loadDoctor;
70
76
  private loadSetup;
71
77
  protected act(result: ListResult<string>): Promise<Outcome<string>>;
78
+ /** The key an Enter on an Updates row stands for. */
79
+ private updateKey;
72
80
  private measure;
73
81
  private remove;
82
+ /** Repair shows what it does as it goes and asks before it changes anything, so it runs on the normal screen. */
74
83
  private repair;
75
84
  private enable;
76
85
  }
@@ -1,5 +1,6 @@
1
- // Tab 7: keeping things in shape. What is stored (with clean-up), the logs, the doctor, repair, this PC's setup, and
2
- // the less common commands. Each is a category on the left and loads when you open it.
1
+ // Section 7: keeping things in shape. Updates (the program and your saved settings), Data & storage (the data folder,
2
+ // what is stored, clean-up), Health (doctor, repair and this PC's setup together), the logs, and the less common
3
+ // commands. Each is a category on the left and loads when you open it.
3
4
  import _ from 'lodash';
4
5
  import { humanBytes } from '../../../core/disk.js';
5
6
  import { userDir } from '../../../core/config/index.js';
@@ -11,18 +12,37 @@ import { DataService, HealthService, LogsService, MigrateService, NPM_UPDATE_COM
11
12
  import { describeResult } from '../../commands/maintenance/update.js';
12
13
  import { Text, Theme, } from '../../tui/index.js';
13
14
  import { CommandForm } from '../command-form.js';
15
+ import { DataFolderFlow, dataFolderRow } from '../data-folder.js';
14
16
  import { ListPage } from './list-page.js';
15
17
  const CATEGORIES = [
16
- { id: 'data', label: 'Stored data', description: 'What is kept between sandboxes, and deleting parts of it.' },
18
+ {
19
+ id: 'updates',
20
+ label: 'Updates',
21
+ description: 'Which version is installed, installing a newer one, and bringing your saved settings up to date.',
22
+ },
23
+ {
24
+ id: 'data',
25
+ label: 'Data & storage',
26
+ description: 'Where the sandbox keeps its data, what is stored, and deleting parts of it.',
27
+ },
28
+ {
29
+ id: 'health',
30
+ label: 'Health',
31
+ description: 'Checks this PC and your settings, repairs problems, and sets up Windows Sandbox.',
32
+ },
17
33
  { id: 'logs', label: 'Logs', description: "The sandbox's own logs." },
18
- { id: 'doctor', label: 'Doctor', description: 'Checks this PC and your settings.' },
19
- { id: 'repair', label: 'Repair', description: 'Finds common problems and fixes what it can.' },
20
- { id: 'settings', label: 'Saved settings', description: 'Brings your saved settings up to date with this version.' },
21
- { id: 'updates', label: 'Updates', description: 'Which version is installed, and installing a newer one.' },
22
- { id: 'setup', label: 'Set up this PC', description: 'Can this PC run Windows Sandbox?' },
23
34
  { id: 'more', label: 'More commands', description: 'Less common commands.' },
24
35
  ];
25
36
  const MORE_COMMANDS = ['sync', 'audit', 'config', 'generate', 'exec', 'agent-commands'];
37
+ /** Plain names for the commands under More commands. */
38
+ const MORE_LABELS = {
39
+ sync: 'Copy history back now',
40
+ audit: 'What happened in the sandbox',
41
+ config: 'Your settings file',
42
+ generate: 'Preview a start',
43
+ exec: 'Run a command in the sandbox',
44
+ 'agent-commands': 'Agent commands (Beta)',
45
+ };
26
46
  const REPAIR_LABEL = {
27
47
  ok: ['OK', Theme.ok],
28
48
  fixed: ['FIXED', Theme.accent],
@@ -39,17 +59,28 @@ const AREA_LABEL = {
39
59
  host: 'On this PC',
40
60
  };
41
61
  function dataItems(m) {
62
+ const folder = { value: 'data:folder', category: 'data', section: 'Data folder', ...m.dataFolder };
63
+ const clean = {
64
+ value: 'data:clean',
65
+ label: 'Clean up…',
66
+ category: 'data',
67
+ section: 'Clean up',
68
+ description: 'Delete caches, old sandboxes and other leftovers (the clean command, with its options).',
69
+ };
42
70
  if (!m.data)
43
71
  return [
72
+ folder,
44
73
  {
45
74
  value: 'data:measure',
46
75
  label: 'Measure what is stored',
47
76
  category: 'data',
48
- hint: Theme.muted('press m'),
77
+ section: 'Stored data',
49
78
  description: 'Adds up the size of every folder. A big data folder takes a minute or more.',
50
79
  },
80
+ clean,
51
81
  ];
52
82
  return [
83
+ folder,
53
84
  ...m.data.disks.map((d) => ({
54
85
  value: 'disk:' + d.drive,
55
86
  label: d.drive,
@@ -67,6 +98,7 @@ function dataItems(m) {
67
98
  description: cleanTargetOf(e) ? 'x deletes it.' : 'Kept on this PC on purpose; it is not deleted here.',
68
99
  details: [Theme.muted('Folder ') + e.path],
69
100
  })),
101
+ clean,
70
102
  ];
71
103
  }
72
104
  function updateItems(m) {
@@ -74,6 +106,7 @@ function updateItems(m) {
74
106
  value: 'updates:' + id,
75
107
  label,
76
108
  category: 'updates',
109
+ section: 'This program',
77
110
  hint,
78
111
  description,
79
112
  details,
@@ -89,14 +122,16 @@ function updateItems(m) {
89
122
  const scope = u.scope === 'machine' ? 'for everyone on this PC' : 'for you';
90
123
  const rows = [
91
124
  row('version', 'Version', u.version, 'Installed ' + scope + '.'),
92
- row('latest', 'Newest version', m.latest ? Theme.warn(m.latest) : Theme.muted('press c to look'), m.latest ? 'Enter or u installs it.' : 'c looks on GitHub for a newer version.'),
93
- row('auto', 'Automatic updates', u.autoUpdate ? Theme.ok('on') : Theme.muted('off'), 'a switches them. ' +
125
+ row('latest', 'Newest version', m.latest ? Theme.warn(m.latest) : Theme.muted('not looked yet'), m.latest ? 'Enter installs it.' : 'Enter looks on GitHub for a newer version.'),
126
+ row('auto', 'Automatic updates', u.autoUpdate ? Theme.ok('on') : Theme.muted('off'), 'Enter switches them. ' +
94
127
  (u.scope === 'machine'
95
128
  ? 'For everyone: needs an admin terminal.'
96
129
  : 'A new version installs when no sandbox runs.')),
97
130
  ];
131
+ if (u.autoOffText)
132
+ rows.push(row('autooff', 'Automatic updates turned off', Theme.warn('off'), u.autoOffText, [u.autoOffText]));
98
133
  if (u.state.previous)
99
- rows.push(row('previous', 'Previous version', u.state.previous, 'r goes back to it.'));
134
+ rows.push(row('previous', 'Previous version', u.state.previous, 'Enter goes back to it.'));
100
135
  if (u.state.failed)
101
136
  rows.push(row('failed', 'Last failed update', Theme.error(u.state.failed.version), u.state.failed.reason, [
102
137
  u.state.failed.reason,
@@ -116,7 +151,8 @@ export function maintenanceOptions(m) {
116
151
  const doctor = (m.doctor ?? []).map(([name, detail], i) => ({
117
152
  value: 'doctor:' + i,
118
153
  label: name,
119
- category: 'doctor',
154
+ category: 'health',
155
+ section: 'Doctor',
120
156
  hint: Text.truncate(detail, 50),
121
157
  details: [detail],
122
158
  }));
@@ -126,7 +162,8 @@ export function maintenanceOptions(m) {
126
162
  return {
127
163
  value: 'repair:' + i,
128
164
  label: r.name,
129
- category: 'repair',
165
+ category: 'health',
166
+ section: 'Repair',
130
167
  hint: paint(text),
131
168
  description: r.detail,
132
169
  };
@@ -135,19 +172,20 @@ export function maintenanceOptions(m) {
135
172
  {
136
173
  value: 'repair:run',
137
174
  label: 'Run the checks and fix what can be fixed',
138
- category: 'repair',
139
- hint: Theme.muted('press f'),
140
- description: 'Each check confirms all is well, fixes the problem itself, or says what you need to do.',
175
+ category: 'health',
176
+ section: 'Repair',
177
+ description: 'Checks the install, data folder, settings and sandbox, lists what it would change, and asks before it fixes anything.',
141
178
  },
142
179
  ];
143
180
  const setup = m.setup === null
144
181
  ? []
145
182
  : 'error' in m.setup
146
- ? [{ value: 'setup:error', label: m.setup.error, category: 'setup' }]
183
+ ? [{ value: 'setup:error', label: m.setup.error, category: 'health', section: 'Set up this PC' }]
147
184
  : m.setup.checks.map((c, i) => ({
148
185
  value: 'setup:' + i,
149
186
  label: c.name,
150
- category: 'setup',
187
+ category: 'health',
188
+ section: 'Set up this PC',
151
189
  hint: c.status === 'ok'
152
190
  ? Theme.ok('OK')
153
191
  : c.status === 'warn'
@@ -156,12 +194,13 @@ export function maintenanceOptions(m) {
156
194
  description: c.detail,
157
195
  }));
158
196
  const settings = 'error' in m.settings
159
- ? [{ value: 'settings:error', label: m.settings.error, category: 'settings' }]
197
+ ? [{ value: 'settings:error', label: m.settings.error, category: 'updates', section: 'Saved settings' }]
160
198
  : m.settings.pending.length
161
199
  ? m.settings.pending.map((line, i) => ({
162
200
  value: 'settings:' + i,
163
201
  label: line.split(':')[0],
164
- category: 'settings',
202
+ category: 'updates',
203
+ section: 'Saved settings',
165
204
  hint: Theme.warn('to update'),
166
205
  description: 'Enter updates your saved settings (a backup is kept first).',
167
206
  details: [line],
@@ -170,7 +209,8 @@ export function maintenanceOptions(m) {
170
209
  {
171
210
  value: 'settings:none',
172
211
  label: 'Up to date',
173
- category: 'settings',
212
+ category: 'updates',
213
+ section: 'Saved settings',
174
214
  hint: Theme.ok('OK'),
175
215
  description: 'Nothing to update.',
176
216
  },
@@ -178,49 +218,88 @@ export function maintenanceOptions(m) {
178
218
  const updates = updateItems(m);
179
219
  const more = m.more.map((c) => ({
180
220
  value: 'more:' + c.name,
181
- label: Text.humanize(c.name),
221
+ label: MORE_LABELS[c.name] ?? Text.humanize(c.name),
182
222
  category: 'more',
183
- hint: Theme.muted('sandbox ' + c.name),
184
223
  description: c.summary.replace(/^./, (x) => x.toUpperCase()) + '.',
185
224
  }));
186
225
  return {
187
226
  path: [],
188
227
  categories: CATEGORIES,
189
- items: [...dataItems(m), ...logs, ...doctor, ...repair, ...settings, ...updates, ...setup, ...more],
228
+ items: [...updates, ...settings, ...dataItems(m), ...doctor, ...repair, ...setup, ...logs, ...more],
190
229
  empty: 'Nothing here yet.',
191
230
  actions: maintenanceActions(m),
192
- escapeLabel: 'quit',
231
+ enterLabel: (_category, id) => enterLabel(id ?? '', m),
193
232
  };
194
233
  }
234
+ /** What Enter does on a row ("" = the row only shows information). */
235
+ function enterLabel(id, m) {
236
+ if (id === 'data:folder')
237
+ return 'change';
238
+ if (id === 'data:measure')
239
+ return 'measure';
240
+ if (id === 'data:clean')
241
+ return 'choose what';
242
+ if (id === 'repair:run')
243
+ return 'check and fix';
244
+ if (id === 'updates:latest')
245
+ return m.latest ? 'install' : 'look';
246
+ if (id === 'updates:auto')
247
+ return 'switch';
248
+ if (id === 'updates:previous')
249
+ return 'go back';
250
+ if (id.startsWith('settings:') && id !== 'settings:none' && id !== 'settings:error')
251
+ return 'update';
252
+ if (id.startsWith('log:'))
253
+ return 'show';
254
+ if (id.startsWith('more:'))
255
+ return 'open';
256
+ return '';
257
+ }
195
258
  function maintenanceActions(m) {
196
259
  return (category) => {
197
260
  switch (category) {
198
- case 'data':
199
- return [{ key: 'm', label: 'measure' }, ...(m.data ? [{ key: 'x', label: 'delete' }] : [])];
261
+ case 'data': {
262
+ const deletable = new Set((m.data?.entries ?? []).flatMap((e, i) => (cleanTargetOf(e) ? ['entry:' + i] : [])));
263
+ return [
264
+ { key: 'm', label: 'measure again' },
265
+ { key: 'x', label: 'delete', applies: (id) => deletable.has(id) },
266
+ ];
267
+ }
200
268
  case 'logs':
201
269
  return [{ key: 'f', label: 'follow in the terminal' }];
202
- case 'doctor':
203
- return [{ key: 'l', label: 'check again' }];
204
- case 'repair':
205
- return [{ key: 'f', label: 'check and fix' }];
206
- case 'settings':
207
- return [{ key: 'u', label: 'update now' }];
208
- case 'updates':
209
- return 'error' in m.updates || !m.updates.managed
210
- ? []
211
- : [
212
- { key: 'c', label: 'check now' },
213
- { key: 'u', label: 'update now' },
214
- { key: 'r', label: 'roll back' },
215
- { key: 'a', label: 'automatic on/off' },
216
- ];
217
- case 'setup': {
270
+ case 'health': {
218
271
  const canEnable = m.setup !== null && !('error' in m.setup) && m.setup.canEnable;
219
272
  return [
273
+ { key: 'f', label: 'check and fix' },
220
274
  { key: 'l', label: 'check again' },
221
275
  ...(canEnable ? [{ key: 'e', label: 'turn on Windows Sandbox' }] : []),
222
276
  ];
223
277
  }
278
+ case 'updates': {
279
+ const managed = !('error' in m.updates) && m.updates.managed;
280
+ const previous = !('error' in m.updates) && Boolean(m.updates.state.previous);
281
+ return [
282
+ ...(managed
283
+ ? [
284
+ { key: 'c', label: 'check now' },
285
+ { key: 'u', label: 'update now' },
286
+ { key: 'a', label: 'automatic on/off', applies: (id) => id === 'updates:auto' },
287
+ ...(previous
288
+ ? [{ key: 'r', label: 'roll back', applies: (id) => id === 'updates:previous' }]
289
+ : []),
290
+ ]
291
+ : []),
292
+ ...('pending' in m.settings && m.settings.pending.length
293
+ ? [
294
+ {
295
+ key: 's',
296
+ label: 'update saved settings',
297
+ applies: (id) => id.startsWith('settings:') && id !== 'settings:none',
298
+ },
299
+ ]
300
+ : []),
301
+ ];
302
+ }
224
303
  default:
225
304
  return [];
226
305
  }
@@ -255,6 +334,7 @@ export class MaintenancePage extends ListPage {
255
334
  }
256
335
  model() {
257
336
  return {
337
+ dataFolder: dataFolderRow(this.ctx),
258
338
  data: this.data,
259
339
  logs: this.logs,
260
340
  doctor: this.doctorRows,
@@ -288,12 +368,12 @@ export class MaintenancePage extends ListPage {
288
368
  if (category === this.seen)
289
369
  return;
290
370
  this.seen = category;
291
- if (category === 'doctor' && !this.doctorRows)
371
+ if (category !== 'health' || (this.doctorRows && this.setupReport))
372
+ return;
373
+ if (!this.doctorRows)
292
374
  await this.loadDoctor();
293
- else if (category === 'setup' && !this.setupReport)
375
+ if (!this.setupReport)
294
376
  await this.loadSetup();
295
- else
296
- return;
297
377
  this.rebuild(undefined);
298
378
  return;
299
379
  }
@@ -390,6 +470,14 @@ export class MaintenancePage extends ListPage {
390
470
  try {
391
471
  if (key === 'm' || id === 'data:measure')
392
472
  return this.measure();
473
+ if (id === 'data:folder' && result.kind === 'pick') {
474
+ const exit = await new DataFolderFlow(this.app, this.ctx).run();
475
+ return exit ? { exit } : { reload: true };
476
+ }
477
+ if (id === 'data:clean' && result.kind === 'pick') {
478
+ const argv = await new CommandForm(this.app, this.ctx, commandSpec('clean')).run();
479
+ return argv ? { exit: { kind: 'run', argv } } : {};
480
+ }
393
481
  if (key === 'x')
394
482
  return await this.remove(id);
395
483
  if (key === 'f' && this.category === 'logs')
@@ -398,22 +486,21 @@ export class MaintenancePage extends ListPage {
398
486
  const file = this.logs.find((l) => l.name === id.slice(4));
399
487
  return file ? { exit: { kind: 'view', file: file.path } } : {};
400
488
  }
401
- if (this.category === 'updates')
402
- return await this.updates(key ?? (id === 'updates:latest' ? 'u' : undefined));
403
- if (key === 'u' || (result.kind === 'pick' && id?.startsWith('settings:')))
489
+ if ((result.kind === 'pick' && id?.startsWith('settings:')) || (key === 's' && this.category === 'updates'))
404
490
  return await this.updateSettings();
405
- if (key === 'f' || id === 'repair:run')
406
- return this.repair();
407
- if (key === 'l' && this.category === 'doctor') {
408
- await this.loadDoctor();
409
- return {};
410
- }
411
- if (key === 'l') {
412
- await this.loadSetup();
413
- return {};
491
+ if (this.category === 'updates')
492
+ return await this.updates(key ?? this.updateKey(id));
493
+ if (this.category === 'health') {
494
+ if (key === 'f' || id === 'repair:run')
495
+ return this.repair();
496
+ if (key === 'l') {
497
+ await this.loadDoctor();
498
+ await this.loadSetup();
499
+ return {};
500
+ }
501
+ if (key === 'e')
502
+ return await this.enable();
414
503
  }
415
- if (key === 'e')
416
- return await this.enable();
417
504
  if (id?.startsWith('more:') && result.kind === 'pick') {
418
505
  const spec = commandSpec(id.slice(5));
419
506
  const argv = await new CommandForm(this.app, this.ctx, spec).run();
@@ -425,6 +512,16 @@ export class MaintenancePage extends ListPage {
425
512
  }
426
513
  return {};
427
514
  }
515
+ /** The key an Enter on an Updates row stands for. */
516
+ updateKey(id) {
517
+ if (id === 'updates:latest')
518
+ return this.latest ? 'u' : 'c';
519
+ if (id === 'updates:auto')
520
+ return 'a';
521
+ if (id === 'updates:previous')
522
+ return 'r';
523
+ return undefined;
524
+ }
428
525
  measure() {
429
526
  this.busy('Measuring what is stored… this can take a minute or more');
430
527
  const report = this.dataService.report();
@@ -453,17 +550,9 @@ export class MaintenancePage extends ListPage {
453
550
  this.data = { ...this.data, entries: gone, total: _.sumBy(gone, 'bytes') };
454
551
  return { notice: Theme.ok(Theme.glyph.ok + ' Freed ' + humanBytes(outcome.freedBytes) + '.') };
455
552
  }
553
+ /** Repair shows what it does as it goes and asks before it changes anything, so it runs on the normal screen. */
456
554
  repair() {
457
- this.busy('Checking and fixing…');
458
- this.repairRows = this.health.repair();
459
- const needs = this.repairRows.filter((r) => r.status === 'needs-you').length;
460
- return {
461
- notice: needs
462
- ? Theme.warn(needs + ' thing(s) need you (see NEEDS YOU).')
463
- : Theme.ok(Theme.glyph.ok +
464
- ' All good' +
465
- (this.repairRows.some((r) => r.status === 'fixed') ? ': problems were fixed.' : '.')),
466
- };
555
+ return { exit: { kind: 'run', argv: ['repair'] } };
467
556
  }
468
557
  async enable() {
469
558
  const ok = await this.app.ask('Turn on Windows Sandbox?', ['Windows asks for admin permission, then you restart Windows to finish.'], 'Turn on');
@@ -7,6 +7,8 @@ export interface SandboxModel {
7
7
  readonly projects: ProjectsListing;
8
8
  /** Null: the sandbox is not running or did not answer. */
9
9
  readonly databases: DatabaseRow[] | null;
10
+ /** The agent "Start the sandbox" offers while nothing runs. */
11
+ readonly defaultAgent: string;
10
12
  }
11
13
  /** The list for the sandbox tab. Pure. */
12
14
  export declare function sandboxOptions(m: SandboxModel): ListOptions<string>;
@@ -22,6 +24,7 @@ export declare class SandboxPage extends ListPage<string> {
22
24
  private guestWorkspace;
23
25
  protected options(): ListOptions<string>;
24
26
  protected act(result: ListResult<string>): Promise<Outcome<string>>;
27
+ private defaultAgent;
25
28
  private noSandbox;
26
29
  private show;
27
30
  private hide;