windows-development-sandbox 1.10.0 → 1.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/README.md +64 -17
  2. package/config.example.json +5 -1
  3. package/dist/app/features/accounts/accounts.def.d.ts +122 -0
  4. package/dist/app/features/accounts/accounts.def.js +243 -0
  5. package/dist/app/features/accounts/accounts.run.d.ts +51 -0
  6. package/dist/app/features/accounts/accounts.run.js +125 -0
  7. package/dist/app/features/accounts/index.d.ts +2 -0
  8. package/dist/app/features/accounts/index.js +3 -0
  9. package/dist/app/features/agents/agent-entry.d.ts +17 -0
  10. package/dist/app/features/agents/agent-entry.js +50 -0
  11. package/dist/app/features/agents/agents.def.d.ts +65 -0
  12. package/dist/app/features/agents/agents.def.js +142 -0
  13. package/dist/app/features/agents/agents.run.d.ts +31 -0
  14. package/dist/app/features/agents/agents.run.js +189 -0
  15. package/dist/app/features/agents/index.d.ts +3 -0
  16. package/dist/app/features/agents/index.js +4 -0
  17. package/dist/app/features/apps/apps-rows.d.ts +31 -0
  18. package/dist/app/features/apps/apps-rows.js +73 -0
  19. package/dist/app/features/apps/apps.def.d.ts +181 -0
  20. package/dist/app/features/apps/apps.def.js +264 -0
  21. package/dist/app/features/apps/apps.run.d.ts +58 -0
  22. package/dist/app/features/apps/apps.run.js +76 -0
  23. package/dist/app/features/apps/index.d.ts +3 -0
  24. package/dist/app/features/apps/index.js +4 -0
  25. package/dist/app/features/data/data.def.d.ts +154 -0
  26. package/dist/app/features/data/data.def.js +194 -0
  27. package/dist/app/features/data/data.run.d.ts +46 -0
  28. package/dist/app/features/data/data.run.js +141 -0
  29. package/dist/app/features/data/index.d.ts +2 -0
  30. package/dist/app/features/data/index.js +3 -0
  31. package/dist/app/features/defs.d.ts +959 -4
  32. package/dist/app/features/defs.js +151 -10
  33. package/dist/app/features/engine/engine.def.d.ts +228 -0
  34. package/dist/app/features/engine/engine.def.js +194 -0
  35. package/dist/app/features/engine/engine.run.d.ts +72 -0
  36. package/dist/app/features/engine/engine.run.js +77 -0
  37. package/dist/app/features/engine/index.d.ts +2 -0
  38. package/dist/app/features/engine/index.js +4 -0
  39. package/dist/app/features/files/files.def.d.ts +51 -0
  40. package/dist/app/features/files/files.def.js +38 -0
  41. package/dist/app/features/files/files.run.d.ts +20 -0
  42. package/dist/app/features/files/files.run.js +59 -0
  43. package/dist/app/features/files/index.d.ts +2 -0
  44. package/dist/app/features/files/index.js +3 -0
  45. package/dist/app/features/github/github.def.d.ts +80 -0
  46. package/dist/app/features/github/github.def.js +142 -0
  47. package/dist/app/features/github/github.run.d.ts +36 -0
  48. package/dist/app/features/github/github.run.js +59 -0
  49. package/dist/app/features/github/index.d.ts +2 -0
  50. package/dist/app/features/github/index.js +3 -0
  51. package/dist/app/features/health/health.def.d.ts +275 -0
  52. package/dist/app/features/health/health.def.js +297 -0
  53. package/dist/app/features/health/health.run.d.ts +125 -0
  54. package/dist/app/features/health/health.run.js +204 -0
  55. package/dist/app/features/health/index.d.ts +2 -0
  56. package/dist/app/features/health/index.js +3 -0
  57. package/dist/app/features/logs/index.d.ts +2 -0
  58. package/dist/app/features/logs/index.js +3 -0
  59. package/dist/app/features/logs/logs.def.d.ts +78 -0
  60. package/dist/app/features/logs/logs.def.js +115 -0
  61. package/dist/app/features/logs/logs.run.d.ts +20 -0
  62. package/dist/app/features/logs/logs.run.js +42 -0
  63. package/dist/app/features/projects/index.d.ts +2 -0
  64. package/dist/app/features/projects/index.js +3 -0
  65. package/dist/app/features/projects/projects.def.d.ts +101 -0
  66. package/dist/app/features/projects/projects.def.js +208 -0
  67. package/dist/app/features/projects/projects.run.d.ts +56 -0
  68. package/dist/app/features/projects/projects.run.js +155 -0
  69. package/dist/app/features/sandbox/sandbox.def.js +11 -5
  70. package/dist/app/features/sessions/sessions.def.js +3 -0
  71. package/dist/app/features/settings/categories.def.js +3 -2
  72. package/dist/{cli/menu/settings/share.d.ts → app/features/settings/settings-share.d.ts} +1 -1
  73. package/dist/{cli/menu/settings/share.js → app/features/settings/settings-share.js} +3 -2
  74. package/dist/app/features/settings/settings.def.d.ts +22 -5
  75. package/dist/app/features/settings/settings.def.js +81 -6
  76. package/dist/app/features/settings/settings.run.d.ts +17 -0
  77. package/dist/app/features/settings/settings.run.js +89 -4
  78. package/dist/app/features/storage/index.d.ts +2 -0
  79. package/dist/app/features/storage/index.js +3 -0
  80. package/dist/app/features/storage/storage.def.d.ts +133 -0
  81. package/dist/app/features/storage/storage.def.js +220 -0
  82. package/dist/app/features/storage/storage.run.d.ts +62 -0
  83. package/dist/app/features/storage/storage.run.js +370 -0
  84. package/dist/app/features/updates/index.d.ts +3 -0
  85. package/dist/app/features/updates/index.js +4 -0
  86. package/dist/app/features/updates/update-lines.d.ts +13 -0
  87. package/dist/app/features/updates/update-lines.js +61 -0
  88. package/dist/app/features/updates/updates.def.d.ts +89 -0
  89. package/dist/app/features/updates/updates.def.js +224 -0
  90. package/dist/app/features/updates/updates.run.d.ts +48 -0
  91. package/dist/app/features/updates/updates.run.js +154 -0
  92. package/dist/app/features/vpn/index.d.ts +2 -0
  93. package/dist/app/features/vpn/index.js +3 -0
  94. package/dist/app/features/vpn/vpn.def.d.ts +112 -0
  95. package/dist/app/features/vpn/vpn.def.js +174 -0
  96. package/dist/app/features/vpn/vpn.run.d.ts +37 -0
  97. package/dist/app/features/vpn/vpn.run.js +54 -0
  98. package/dist/app/features/web/index.d.ts +2 -0
  99. package/dist/app/features/web/index.js +3 -0
  100. package/dist/app/features/web/web.def.d.ts +33 -0
  101. package/dist/app/features/web/web.def.js +90 -0
  102. package/dist/app/features/web/web.run.d.ts +24 -0
  103. package/dist/app/features/web/web.run.js +93 -0
  104. package/dist/app/kernel/define.d.ts +10 -1
  105. package/dist/app/kernel/io.d.ts +34 -0
  106. package/dist/app/kernel/io.js +9 -0
  107. package/dist/app/kernel/rpc.d.ts +17 -0
  108. package/dist/app/kernel/text.d.ts +2 -0
  109. package/dist/app/kernel/text.js +7 -0
  110. package/dist/app/kernel/view.d.ts +24 -1
  111. package/dist/app/kernel/view.js +1 -1
  112. package/dist/app/registry.js +74 -1
  113. package/dist/cli/args.js +1 -1
  114. package/dist/cli/commands/context.d.ts +7 -0
  115. package/dist/cli/commands/context.js +29 -2
  116. package/dist/cli/commands/engine.js +5 -58
  117. package/dist/cli/commands/github.d.ts +2 -0
  118. package/dist/cli/commands/github.js +11 -0
  119. package/dist/cli/commands/index.d.ts +3 -5
  120. package/dist/cli/commands/index.js +3 -5
  121. package/dist/cli/commands/launch/launch.js +21 -4
  122. package/dist/cli/commands/launch/running.js +4 -1
  123. package/dist/cli/commands/maintenance/config.js +1 -6
  124. package/dist/cli/commands/maintenance/index.d.ts +0 -1
  125. package/dist/cli/commands/maintenance/index.js +1 -2
  126. package/dist/cli/commands/maintenance/logs.js +27 -32
  127. package/dist/cli/commands/maintenance/migrate.d.ts +0 -8
  128. package/dist/cli/commands/maintenance/migrate.js +2 -44
  129. package/dist/cli/commands/maintenance/update.d.ts +0 -19
  130. package/dist/cli/commands/maintenance/update.js +1 -99
  131. package/dist/cli/commands/projects/index.d.ts +0 -1
  132. package/dist/cli/commands/projects/index.js +0 -1
  133. package/dist/cli/commands/registry.d.ts +1 -1
  134. package/dist/cli/commands/registry.js +29 -11
  135. package/dist/cli/commands/repair/checks/data.js +1 -1
  136. package/dist/cli/commands/repair/checks/hcs.js +28 -1
  137. package/dist/cli/commands/repair/checks/sandbox.js +1 -1
  138. package/dist/cli/commands/repair/health-run.d.ts +30 -0
  139. package/dist/cli/commands/repair/health-run.js +32 -0
  140. package/dist/cli/commands/repair/printer.d.ts +2 -2
  141. package/dist/cli/commands/repair/printer.js +2 -11
  142. package/dist/cli/commands/repair/run.d.ts +1 -21
  143. package/dist/cli/commands/repair/run.js +13 -70
  144. package/dist/cli/commands/storage/index.d.ts +0 -1
  145. package/dist/cli/commands/storage/index.js +0 -1
  146. package/dist/cli/commands/storage/offer.js +6 -2
  147. package/dist/cli/commands/vpn.d.ts +1 -3
  148. package/dist/cli/commands/vpn.js +8 -89
  149. package/dist/cli/commands/web.d.ts +2 -1
  150. package/dist/cli/commands/web.js +14 -78
  151. package/dist/cli/index.js +3 -2
  152. package/dist/cli/manifest.d.ts +16 -153
  153. package/dist/cli/manifest.js +20 -50
  154. package/dist/cli/menu/command-form.js +1 -2
  155. package/dist/cli/menu/io-menu.d.ts +2 -2
  156. package/dist/cli/menu/io-menu.js +6 -4
  157. package/dist/cli/menu/menu.js +1 -1
  158. package/dist/cli/menu/pages/accounts-page.d.ts +5 -17
  159. package/dist/cli/menu/pages/accounts-page.js +28 -170
  160. package/dist/cli/menu/pages/agents-page.d.ts +17 -18
  161. package/dist/cli/menu/pages/agents-page.js +67 -124
  162. package/dist/cli/menu/pages/apps-page.d.ts +15 -8
  163. package/dist/cli/menu/pages/apps-page.js +121 -29
  164. package/dist/cli/menu/pages/list-page.js +10 -1
  165. package/dist/cli/menu/pages/maintenance-page.d.ts +51 -52
  166. package/dist/cli/menu/pages/maintenance-page.js +246 -427
  167. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -5
  168. package/dist/cli/menu/pages/sandbox-page.js +34 -112
  169. package/dist/cli/menu/pages/settings-page.d.ts +21 -3
  170. package/dist/cli/menu/pages/settings-page.js +89 -17
  171. package/dist/cli/menu/render-view.js +2 -1
  172. package/dist/cli/menu/settings/index.d.ts +0 -1
  173. package/dist/cli/menu/settings/index.js +3 -3
  174. package/dist/cli/menu/views.js +28 -0
  175. package/dist/cli/operations/handler.js +7 -3
  176. package/dist/cli/operations/input.d.ts +1 -1
  177. package/dist/cli/operations/input.js +29 -5
  178. package/dist/cli/operations/io-cli.js +9 -1
  179. package/dist/cli/operations/spec.js +8 -2
  180. package/dist/cli/output/render-view.js +2 -0
  181. package/dist/cli/{commands/data/collect.js → services/data-collect.js} +2 -2
  182. package/dist/cli/{commands/data/remove.js → services/data-remove.js} +2 -2
  183. package/dist/cli/services/data-service.d.ts +1 -1
  184. package/dist/cli/services/data-service.js +2 -2
  185. package/dist/cli/services/databases-service.d.ts +5 -0
  186. package/dist/cli/services/databases-service.js +15 -0
  187. package/dist/cli/services/health-service.d.ts +8 -4
  188. package/dist/cli/services/health-service.js +10 -8
  189. package/dist/cli/services/index.d.ts +4 -1
  190. package/dist/cli/services/index.js +4 -1
  191. package/dist/cli/services/logs-service.d.ts +7 -0
  192. package/dist/cli/services/logs-service.js +13 -0
  193. package/dist/cli/services/storage-service.d.ts +19 -0
  194. package/dist/cli/services/storage-service.js +71 -0
  195. package/dist/cli/services/vpn-service.d.ts +6 -4
  196. package/dist/cli/services/vpn-service.js +5 -11
  197. package/dist/cli/services/web-service.d.ts +4 -3
  198. package/dist/cli/services/web-service.js +12 -32
  199. package/dist/core/config/defaults.js +2 -1
  200. package/dist/core/schema/config.d.ts +5 -0
  201. package/dist/core/schema/config.js +2 -0
  202. package/dist/core/schema/github.d.ts +4 -0
  203. package/dist/core/schema/github.js +7 -0
  204. package/dist/core/schema/index.d.ts +1 -0
  205. package/dist/core/schema/index.js +1 -0
  206. package/dist/core/schema/profile.d.ts +1 -0
  207. package/dist/core/schema/profile.js +3 -0
  208. package/dist/core/schema/sandbox.js +3 -3
  209. package/dist/core/schema/toolchains.js +2 -2
  210. package/dist/core/types.d.ts +6 -3
  211. package/dist/guest/boot/boot.js +8 -0
  212. package/dist/guest/daemon/daemon.js +1 -1
  213. package/dist/guest/daemon/sessions.d.ts +3 -2
  214. package/dist/guest/daemon/sessions.js +38 -7
  215. package/dist/guest/governor/core.d.ts +44 -0
  216. package/dist/guest/governor/core.js +124 -0
  217. package/dist/guest/governor/decide.d.ts +46 -18
  218. package/dist/guest/governor/decide.js +136 -82
  219. package/dist/guest/governor/governor.d.ts +2 -38
  220. package/dist/guest/governor/governor.js +33 -113
  221. package/dist/guest/governor/index.d.ts +1 -0
  222. package/dist/guest/governor/index.js +1 -0
  223. package/dist/guest/network/firewall.d.ts +2 -0
  224. package/dist/guest/network/firewall.js +3 -3
  225. package/dist/guest/sessions/viewer.js +5 -1
  226. package/dist/guest/setup/github-token.d.ts +7 -0
  227. package/dist/guest/setup/github-token.js +65 -0
  228. package/dist/guest/toolchains/languages/node.js +11 -1
  229. package/dist/guest/toolchains/native/rust-extras.js +2 -2
  230. package/dist/guest/toolchains/tools/cli.d.ts +8 -0
  231. package/dist/guest/toolchains/tools/cli.js +35 -2
  232. package/dist/guest/vpn/openvpn.d.ts +5 -0
  233. package/dist/guest/vpn/openvpn.js +14 -1
  234. package/dist/guest/vpn/vpn.js +55 -16
  235. package/dist/guest/vpn/wireguard.js +2 -0
  236. package/dist/host/channel/attach.d.ts +1 -0
  237. package/dist/host/channel/attach.js +1 -0
  238. package/dist/host/channel/channel.d.ts +1 -1
  239. package/dist/host/channel/channel.js +2 -2
  240. package/dist/host/engines/hcs/check.d.ts +1 -0
  241. package/dist/host/engines/hcs/check.js +1 -1
  242. package/dist/host/engines/hcs/engine.d.ts +1 -1
  243. package/dist/host/engines/hcs/engine.js +6 -4
  244. package/dist/host/engines/hcs/helper.d.ts +11 -0
  245. package/dist/host/engines/hcs/helper.js +31 -2
  246. package/dist/host/engines/hcs/leftovers.d.ts +42 -0
  247. package/dist/host/engines/hcs/leftovers.js +101 -0
  248. package/dist/host/engines/index.d.ts +1 -0
  249. package/dist/host/engines/index.js +1 -0
  250. package/dist/host/github/deliver.d.ts +13 -0
  251. package/dist/host/github/deliver.js +51 -0
  252. package/dist/host/github/index.d.ts +2 -0
  253. package/dist/host/github/index.js +3 -0
  254. package/dist/host/github/token.d.ts +21 -0
  255. package/dist/host/github/token.js +74 -0
  256. package/dist/host/launch/generate.js +11 -5
  257. package/dist/host/launch/index.d.ts +1 -1
  258. package/dist/host/launch/index.js +1 -1
  259. package/dist/host/launch/session-file.js +1 -2
  260. package/dist/host/launch/wsb-file.d.ts +11 -7
  261. package/dist/host/launch/wsb-file.js +30 -12
  262. package/dist/host/life/host-memory.d.ts +18 -0
  263. package/dist/host/life/host-memory.js +66 -0
  264. package/dist/host/life/watchdog.d.ts +9 -0
  265. package/dist/host/life/watchdog.js +17 -1
  266. package/dist/host/sandbox/tasklist.d.ts +6 -0
  267. package/dist/host/sandbox/tasklist.js +37 -0
  268. package/dist/host/secrets/launch-secrets.d.ts +2 -1
  269. package/dist/host/secrets/launch-secrets.js +4 -2
  270. package/dist/host/vpn/status.js +13 -3
  271. package/dist/host/web/backend.d.ts +1 -3
  272. package/dist/host/web/index.d.ts +2 -1
  273. package/dist/host/web/index.js +2 -1
  274. package/dist/host/web/live.d.ts +23 -0
  275. package/dist/host/web/live.js +107 -0
  276. package/dist/host/web/rpc.d.ts +6 -1
  277. package/dist/host/web/rpc.js +23 -31
  278. package/dist/host/web/runner.d.ts +4 -0
  279. package/dist/host/web/runner.js +12 -1
  280. package/dist/host/web/server.d.ts +30 -2
  281. package/dist/host/web/server.js +87 -29
  282. package/dist/host/web/state.d.ts +1 -0
  283. package/dist/host/web/state.js +2 -0
  284. package/dist/runtime/agent.js +30 -6
  285. package/dist/runtime/daemon.js +337 -177
  286. package/dist/runtime/db.js +30 -6
  287. package/dist/runtime/main.js +389 -77
  288. package/dist/runtime/netproxy.js +30 -6
  289. package/dist/runtime/view.js +495 -146
  290. package/dist/selftest/app.test.js +632 -12
  291. package/dist/selftest/channel.test.js +18 -1
  292. package/dist/selftest/cli.test.js +1 -1
  293. package/dist/selftest/config.test.js +1 -1
  294. package/dist/selftest/contained.test.js +1 -1
  295. package/dist/selftest/data.test.js +1 -2
  296. package/dist/selftest/engine.test.js +3 -1
  297. package/dist/selftest/github.test.d.ts +2 -0
  298. package/dist/selftest/github.test.js +243 -0
  299. package/dist/selftest/hcs.test.js +105 -8
  300. package/dist/selftest/health.test.js +71 -0
  301. package/dist/selftest/heavy-load.test.js +132 -72
  302. package/dist/selftest/index.js +4 -0
  303. package/dist/selftest/layout.test.js +8 -0
  304. package/dist/selftest/live-terminal.test.js +74 -0
  305. package/dist/selftest/menu-screens.js +171 -56
  306. package/dist/selftest/menu.test.js +54 -37
  307. package/dist/selftest/migrate.test.js +14 -12
  308. package/dist/selftest/powershell-variables.test.d.ts +2 -0
  309. package/dist/selftest/powershell-variables.test.js +61 -0
  310. package/dist/selftest/support/engine-golden.js +1 -0
  311. package/dist/selftest/support/fixtures.d.ts +4 -0
  312. package/dist/selftest/support/web-preview.d.ts +1 -0
  313. package/dist/selftest/support/web-preview.js +856 -0
  314. package/dist/selftest/update-service.test.js +15 -8
  315. package/dist/selftest/vpn.test.js +86 -2
  316. package/dist/selftest/web.test.js +58 -11
  317. package/dist/shared/channel/run-dir.d.ts +2 -0
  318. package/dist/shared/channel/run-dir.js +3 -0
  319. package/dist/shared/channel/schema.d.ts +7 -0
  320. package/dist/shared/channel/schema.js +9 -1
  321. package/dist/shared/channel/secrets.d.ts +1 -0
  322. package/dist/shared/channel/secrets.js +3 -0
  323. package/dist/shared/github/index.d.ts +1 -0
  324. package/dist/shared/github/index.js +2 -0
  325. package/dist/shared/github/token.d.ts +29 -0
  326. package/dist/shared/github/token.js +89 -0
  327. package/dist/shared/memory/policy.d.ts +33 -12
  328. package/dist/shared/memory/policy.js +50 -19
  329. package/dist/shared/pty/ctrl-c.d.ts +18 -0
  330. package/dist/shared/pty/ctrl-c.js +36 -0
  331. package/dist/shared/pty/index.d.ts +1 -0
  332. package/dist/shared/pty/index.js +1 -0
  333. package/dist/shared/pty/terminal.d.ts +2 -0
  334. package/dist/shared/pty/terminal.js +21 -2
  335. package/dist/shared/vpn/kill-switch.d.ts +13 -2
  336. package/dist/shared/vpn/kill-switch.js +88 -8
  337. package/dist/shared/web/protocol.d.ts +0 -4
  338. package/dist/sync/watcher.d.ts +2 -0
  339. package/dist/sync/watcher.js +8 -3
  340. package/dist/web/index.html +2 -2
  341. package/dist/web/{main-T5DMCHYV.css → main-MU5XWZMS.css} +1 -1
  342. package/dist/web/main-SLQNJRXD.js +219 -0
  343. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  344. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  345. package/native/csharp/HostTools/MemoryStatus.cs +58 -2
  346. package/native/csharp/HostTools/Program.cs +7 -1
  347. package/package.json +10 -3
  348. package/sandbox/csharp/MemGov.cs +240 -38
  349. package/sandbox/csharp/PtyHost.cs +104 -15
  350. package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
  351. package/sandbox/csharp/SandboxTools/Program.cs +1 -1
  352. package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
  353. package/schemas/config.schema.json +19 -5
  354. package/schemas/sandbox-config.schema.json +7 -3
  355. package/dist/cli/commands/accounts.d.ts +0 -2
  356. package/dist/cli/commands/accounts.js +0 -96
  357. package/dist/cli/commands/data/clean.d.ts +0 -3
  358. package/dist/cli/commands/data/clean.js +0 -60
  359. package/dist/cli/commands/data/index.d.ts +0 -4
  360. package/dist/cli/commands/data/index.js +0 -62
  361. package/dist/cli/commands/maintenance/clean.d.ts +0 -2
  362. package/dist/cli/commands/maintenance/clean.js +0 -24
  363. package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
  364. package/dist/cli/commands/maintenance/config-share.js +0 -80
  365. package/dist/cli/commands/projects/projects.d.ts +0 -2
  366. package/dist/cli/commands/projects/projects.js +0 -162
  367. package/dist/cli/commands/storage/contained.d.ts +0 -3
  368. package/dist/cli/commands/storage/contained.js +0 -179
  369. package/dist/cli/commands/storage/storage.d.ts +0 -8
  370. package/dist/cli/commands/storage/storage.js +0 -179
  371. package/dist/cli/menu/add-agent.d.ts +0 -47
  372. package/dist/cli/menu/add-agent.js +0 -168
  373. package/dist/cli/menu/apps.d.ts +0 -69
  374. package/dist/cli/menu/apps.js +0 -214
  375. package/dist/cli/menu/data-folder.d.ts +0 -18
  376. package/dist/cli/menu/data-folder.js +0 -99
  377. package/dist/cli/menu/share-settings.d.ts +0 -21
  378. package/dist/cli/menu/share-settings.js +0 -112
  379. package/dist/cli/menu/vpn-login.d.ts +0 -16
  380. package/dist/cli/menu/vpn-login.js +0 -74
  381. package/dist/web/main-NRRS5O6Z.js +0 -157
  382. /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
  383. /package/dist/cli/{commands/data/remove.d.ts → services/data-remove.d.ts} +0 -0
@@ -0,0 +1,856 @@
1
+ // A preview of the web UI for working on it: the real server and app, the real settings feature against a config file
2
+ // in a temp folder, and sample data for the sandbox and its sessions (a stand-in terminal plays a short agent screen).
3
+ // Nothing on this PC is read or changed. Run: npm run web:preview [-- --port 47900], then open the printed address.
4
+ import fs from 'node:fs';
5
+ import net from 'node:net';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
8
+ import { listAgents } from '../../app/features/agents/index.js';
9
+ import { sandboxStatus } from '../../app/features/sandbox/index.js';
10
+ import { vpnStatus } from '../../app/features/vpn/index.js';
11
+ import { listAccounts } from '../../app/features/accounts/index.js';
12
+ import { engineStatus } from '../../app/features/engine/index.js';
13
+ import { lastHealth } from '../../app/features/health/index.js';
14
+ import { CRASH, listLogs, tailLog } from '../../app/features/logs/index.js';
15
+ import { listProjects } from '../../app/features/projects/index.js';
16
+ import { showData } from '../../app/features/data/index.js';
17
+ import { updatesStatus } from '../../app/features/updates/index.js';
18
+ import { containedStatus, showStorage } from '../../app/features/storage/index.js';
19
+ import { listSessions } from '../../app/features/sessions/index.js';
20
+ import { cancelled } from '../../app/kernel/index.js';
21
+ import { runDefinition } from '../../app/registry.js';
22
+ import { webSession } from '../../cli/services/index.js';
23
+ import { WebServer } from '../../host/web/index.js';
24
+ import { encodeFrame, FrameReader, FrameType } from '../../shared/pty/index.js';
25
+ const TOKEN = 'b'.repeat(64);
26
+ const MINUTE = 60_000;
27
+ /** A short agent screen with colours, so the terminal page has something real to draw. */
28
+ function agentScreen(id) {
29
+ return [
30
+ '\x1b[2J\x1b[H',
31
+ '\x1b[38;5;208m✻\x1b[0m Welcome to \x1b[1mClaude Code\x1b[0m \x1b[2m(preview session ' + id + ')\x1b[0m\r\n\r\n',
32
+ '\x1b[2m /help for help, /status for your current setup\x1b[0m\r\n\r\n',
33
+ '\x1b[1m> \x1b[0mFix the failing test in src/app/kernel/view.ts\r\n\r\n',
34
+ '\x1b[32m●\x1b[0m Read(\x1b[1msrc/app/kernel/view.ts\x1b[0m)\r\n',
35
+ ' ⎿ Read 181 lines\r\n\r\n',
36
+ '\x1b[32m●\x1b[0m Update(\x1b[1msrc/app/kernel/view.ts\x1b[0m)\r\n',
37
+ ' ⎿ Updated with \x1b[32m3 additions\x1b[0m and \x1b[31m1 removal\x1b[0m\r\n\r\n',
38
+ '\x1b[2m╭──────────────────────────────────────────────────────────────╮\x1b[0m\r\n',
39
+ '\x1b[2m│\x1b[0m > ' + ' '.repeat(59) + '\x1b[2m│\x1b[0m\r\n',
40
+ '\x1b[2m╰──────────────────────────────────────────────────────────────╯\x1b[0m\r\n',
41
+ ].join('');
42
+ }
43
+ /** A ptyhost stand-in: sends the screen on HELLO and echoes what is typed. */
44
+ function startFakePty() {
45
+ const server = net.createServer((socket) => {
46
+ const reader = new FrameReader();
47
+ socket.on('error', () => undefined);
48
+ socket.on('data', (chunk) => {
49
+ for (const frame of reader.push(chunk)) {
50
+ if (frame.type === FrameType.Hello) {
51
+ socket.write(encodeFrame(FrameType.Console, Buffer.from('conpty.dll')));
52
+ socket.write(encodeFrame(FrameType.Output, Buffer.from(agentScreen('preview'))));
53
+ }
54
+ else if (frame.type === FrameType.Input) {
55
+ const text = frame.payload.toString('utf8').replace(/\r/g, '\r\n');
56
+ socket.write(encodeFrame(FrameType.Output, Buffer.from(text)));
57
+ }
58
+ }
59
+ });
60
+ });
61
+ return new Promise((resolve) => server.listen(0, '127.0.0.1', () => resolve(server.address().port)));
62
+ }
63
+ function iso(msAgo) {
64
+ return new Date(Date.now() - msAgo).toISOString();
65
+ }
66
+ const SESSIONS = [
67
+ {
68
+ id: 'mva4ungc50e051',
69
+ launchId: 'launch1',
70
+ harness: 'claude',
71
+ cwd: 'C:\\Projects\\AgentProjects\\windows-sandbox',
72
+ project: 'windows-sandbox',
73
+ phase: 'running',
74
+ message: 'running',
75
+ updatedAt: iso(MINUTE),
76
+ startedAt: iso(42 * MINUTE),
77
+ },
78
+ {
79
+ id: '1792104624667-1a3599',
80
+ launchId: 'launch1',
81
+ harness: 'claude',
82
+ cwd: 'C:\\Projects\\AgentProjects\\mw2-agent',
83
+ project: 'mw2-agent',
84
+ phase: 'running',
85
+ message: 'running',
86
+ updatedAt: iso(MINUTE),
87
+ startedAt: iso(43 * MINUTE),
88
+ },
89
+ {
90
+ id: 'k2q9codex0001',
91
+ launchId: 'launch1',
92
+ harness: 'codex',
93
+ cwd: 'C:\\Projects\\AgentProjects\\windows-sandbox',
94
+ project: 'windows-sandbox',
95
+ phase: 'exited',
96
+ message: 'exited',
97
+ exitCode: 0,
98
+ updatedAt: iso(20 * MINUTE),
99
+ startedAt: iso(30 * MINUTE),
100
+ },
101
+ ];
102
+ /** The sandbox as the status query would say it: running, two projects, the helper answering. */
103
+ function sampleStatus(running) {
104
+ const project = (name, here, sessions) => ({
105
+ name,
106
+ host: 'F:\\AgentProjects\\' + name,
107
+ guest: 'C:\\Projects\\AgentProjects\\' + name,
108
+ mechanism: here ? 'launch' : 'root',
109
+ here,
110
+ setup: { phase: 'ready', message: 'Set up 6 toolchains and databases.' },
111
+ databases: name === 'mw2-agent' ? [{ database: 'postgres', port: 5432, state: 'running' }] : [],
112
+ sessions: sessions.map((s) => ({ id: s.id, harness: s.harness, viewers: '1 here', started: s.startedAt })),
113
+ repoGuard: [],
114
+ });
115
+ return sandboxStatus.output.parse({
116
+ sandbox: {
117
+ running,
118
+ phase: running ? 'ready' : 'stopped',
119
+ message: running ? 'Ready' : undefined,
120
+ headless: false,
121
+ startedAt: running ? Date.now() - 45 * MINUTE : null,
122
+ daemon: running ? 'pong (2 session(s) running)' : 'not running',
123
+ account: running ? 'personal' : null,
124
+ syncWatcher: running,
125
+ },
126
+ here: {
127
+ folder: 'F:\\AgentProjects\\windows-sandbox',
128
+ project: 'windows-sandbox',
129
+ guest: 'C:\\Projects\\AgentProjects\\windows-sandbox',
130
+ },
131
+ roots: [{ host: 'F:\\AgentProjects', guest: 'C:\\Projects\\AgentProjects' }],
132
+ projects: running
133
+ ? [
134
+ project('windows-sandbox', true, SESSIONS.filter((s) => s.project === 'windows-sandbox')),
135
+ project('mw2-agent', false, SESSIONS.filter((s) => s.project === 'mw2-agent')),
136
+ ]
137
+ : [],
138
+ otherSessions: [],
139
+ repoGuard: { guarded: 2, findings: [] },
140
+ });
141
+ }
142
+ /** Sample logins (names and emails only, no credentials): Claude with two, codex with one, opencode keeps none. */
143
+ function sampleAccounts() {
144
+ return listAccounts.output.parse({
145
+ agent: 'claude',
146
+ agents: [
147
+ {
148
+ name: 'claude',
149
+ kept: true,
150
+ canSavePc: true,
151
+ accounts: [
152
+ {
153
+ name: 'work',
154
+ email: 'dev@example.com',
155
+ isDefault: true,
156
+ isActive: true,
157
+ savedAt: iso(3 * 24 * 60 * MINUTE),
158
+ },
159
+ { name: 'personal', email: null, isDefault: false, isActive: false, savedAt: iso(9 * 24 * 60 * MINUTE) },
160
+ ],
161
+ },
162
+ {
163
+ name: 'codex',
164
+ kept: true,
165
+ canSavePc: false,
166
+ accounts: [{ name: 'main', email: null, isDefault: true, isActive: false, savedAt: iso(2 * 24 * 60 * MINUTE) }],
167
+ },
168
+ { name: 'opencode', kept: false, canSavePc: false, accounts: [] },
169
+ ],
170
+ });
171
+ }
172
+ function sampleSessions(running) {
173
+ return listSessions.output.parse({
174
+ sandboxRunning: running,
175
+ defaultAgent: 'claude',
176
+ wide: false,
177
+ sessions: running
178
+ ? SESSIONS.map((s) => ({
179
+ ...s,
180
+ projectName: s.project,
181
+ here: s.project === 'windows-sandbox',
182
+ viewers: s.phase === 'running' ? { viewers: 1, remote: 0 } : undefined,
183
+ canOpen: s.phase === 'running',
184
+ }))
185
+ : [],
186
+ });
187
+ }
188
+ /** The program's updates: installed for you, one previous version, one failed update, one saved-settings change. */
189
+ function sampleUpdates() {
190
+ return updatesStatus.output.parse({
191
+ managed: true,
192
+ version: '1.4.3',
193
+ scope: 'user',
194
+ autoUpdate: true,
195
+ autoOffText: null,
196
+ previous: '1.4.2',
197
+ failed: { version: '1.4.4', reason: 'it did not start' },
198
+ npmCommand: 'npm install -g windows-development-sandbox',
199
+ error: null,
200
+ settings: {
201
+ pending: ['2026-10-unpin-config-defaults: stop pinning old defaults in your config.json'],
202
+ error: null,
203
+ },
204
+ });
205
+ }
206
+ /** Where the saved data is (the storage area's query), parsed with its own output schema. */
207
+ function sampleStorage() {
208
+ return showStorage.output.parse({
209
+ root: 'F:\\AgentSandbox',
210
+ exists: true,
211
+ holdsData: true,
212
+ measured: { bytes: 8.9e9, files: 41250, partial: false },
213
+ size: '8.9 GB',
214
+ defaultRoot: 'C:\\ProgramData\\AgentSandbox',
215
+ defaultInUse: false,
216
+ otherFoldersWithData: ['C:\\ProgramData\\AgentSandbox'],
217
+ });
218
+ }
219
+ /** Contained storage (beta): off, and this PC can use it. */
220
+ function sampleContained() {
221
+ return containedStatus.output.parse({
222
+ setting: 'off',
223
+ maxGb: 60,
224
+ available: true,
225
+ reasons: [],
226
+ fixes: [],
227
+ image: 'F:\\AgentSandbox\\contained\\agent.vhdx',
228
+ imageExists: false,
229
+ imageBytes: null,
230
+ mountFolder: 'F:\\AgentSandbox\\mount',
231
+ recordedMounted: false,
232
+ holders: 0,
233
+ mountedNow: null,
234
+ });
235
+ }
236
+ /** What is stored: a toolchain, the agent's login folder, databases and logs, and what this PC keeps (sample sizes). */
237
+ function sampleData() {
238
+ const GB = (n) => (n / 1e9).toFixed(1) + ' GB';
239
+ const entry = (area, name, bytes, target) => ({
240
+ area,
241
+ name,
242
+ path: 'F:\\AgentData\\' + (area === 'host' ? name : area + '\\' + name),
243
+ bytes,
244
+ size: bytes < 1e6 ? (bytes / 1e3).toFixed(1) + ' KB' : GB(bytes),
245
+ target,
246
+ });
247
+ return showData.output.parse({
248
+ dataPath: 'F:\\AgentData',
249
+ storageRoot: 'F:\\',
250
+ totalBytes: 9.6e9,
251
+ total: '9.6 GB',
252
+ storageShare: '<- sandbox storage (9.6 GB of it)',
253
+ areaTotals: { tools: '6.4 GB', databases: '1.2 GB', state: '1.9 GB', logs: '48 KB', host: '4.1 KB' },
254
+ entries: [
255
+ entry('tools', 'rust', 4.6e9, 'tools/rust'),
256
+ entry('tools', 'node', 1.8e9, 'tools/node'),
257
+ entry('databases', 'postgres-18', 1.2e9, 'databases/postgres-18'),
258
+ entry('state', 'claude', 1.9e9, 'state/claude'),
259
+ entry('logs', 'logs', 48_000, 'logs'),
260
+ entry('host', 'accounts', 4096, null),
261
+ ],
262
+ disks: [
263
+ {
264
+ drive: 'C:\\',
265
+ totalBytes: 512e9,
266
+ freeBytes: 210e9,
267
+ usedBytes: 302e9,
268
+ holdsStorage: false,
269
+ used: '302 GB',
270
+ usedPercent: 59,
271
+ free: '210 GB',
272
+ total: '512 GB',
273
+ },
274
+ {
275
+ drive: 'F:\\',
276
+ totalBytes: 1000e9,
277
+ freeBytes: 620e9,
278
+ usedBytes: 380e9,
279
+ holdsStorage: true,
280
+ used: '380 GB',
281
+ usedPercent: 38,
282
+ free: '620 GB',
283
+ total: '1.0 TB',
284
+ },
285
+ ],
286
+ });
287
+ }
288
+ /** The agents as settings and the sandbox say them: two built in (one ready), two added (one ready). */
289
+ function sampleAgents() {
290
+ return listAgents.output.parse({
291
+ folder: 'F:\\AgentProjects\\windows-sandbox',
292
+ defaultAgent: 'claude',
293
+ agents: [
294
+ { name: 'claude', ready: true, isDefault: true, removable: false },
295
+ { name: 'codex', ready: true, isDefault: false, removable: false },
296
+ { name: 'gemini', ready: false, isDefault: false, removable: true },
297
+ { name: 'aider', ready: false, isDefault: false, removable: true },
298
+ ],
299
+ });
300
+ }
301
+ /** Sample projects: this folder's project and a root's (mapped), one not mapped, and one excluded. */
302
+ function sampleProjects(running) {
303
+ const inSandbox = (name, how) => (running ? name + ' (' + how + ')' : null);
304
+ return listProjects.output.parse({
305
+ all: false,
306
+ roots: ['F:\\AgentProjects'],
307
+ exclude: ['F:\\AgentProjects\\old-demo'],
308
+ projects: [
309
+ {
310
+ folder: 'F:\\AgentProjects\\windows-sandbox',
311
+ here: true,
312
+ known: true,
313
+ root: 'F:\\AgentProjects',
314
+ excluded: false,
315
+ mappedAtStart: true,
316
+ running: inSandbox('windows-sandbox', 'launch'),
317
+ },
318
+ {
319
+ folder: 'F:\\AgentProjects\\mw2-agent',
320
+ here: false,
321
+ known: true,
322
+ root: 'F:\\AgentProjects',
323
+ excluded: false,
324
+ mappedAtStart: true,
325
+ running: inSandbox('mw2-agent', 'root'),
326
+ },
327
+ {
328
+ folder: 'F:\\Code\\scratch',
329
+ here: false,
330
+ known: true,
331
+ root: null,
332
+ excluded: false,
333
+ mappedAtStart: false,
334
+ running: null,
335
+ },
336
+ {
337
+ folder: 'F:\\AgentProjects\\old-demo',
338
+ here: false,
339
+ known: true,
340
+ root: null,
341
+ excluded: true,
342
+ mappedAtStart: false,
343
+ running: null,
344
+ },
345
+ ],
346
+ });
347
+ }
348
+ /** The last check: a few results of each kind, the doctor rows, the setup and a log (nothing here is run). */
349
+ function sampleHealth() {
350
+ const at = new Date(Date.now() - 3 * MINUTE).toISOString();
351
+ return lastHealth.output.parse({
352
+ last: {
353
+ at,
354
+ mode: 'repair',
355
+ checks: [
356
+ {
357
+ id: 'pc-edition',
358
+ group: 'This PC',
359
+ name: 'Windows edition',
360
+ status: 'ok',
361
+ detail: 'Windows 11 Pro',
362
+ fixable: false,
363
+ },
364
+ {
365
+ id: 'install-pointers',
366
+ group: 'Install',
367
+ name: 'Install pointers',
368
+ status: 'fixed',
369
+ detail: 'the command points at the new version',
370
+ applied: { done: 'pointed the command at 1.11.0', before: 'points at 1.9.2', after: 'points at 1.11.0' },
371
+ fixable: false,
372
+ },
373
+ {
374
+ id: 'stale-run',
375
+ group: 'Data folder',
376
+ name: 'Stale run folders',
377
+ status: 'needs-you',
378
+ detail: 'two folders from a sandbox that did not close',
379
+ means: 'they take space and can confuse the next start',
380
+ fix: 'stop the sandbox, then run sandbox repair again',
381
+ lines: ['run-20261012-0931', 'run-20261013-1744'],
382
+ fixable: false,
383
+ },
384
+ {
385
+ id: 'proxy',
386
+ group: 'Network',
387
+ name: 'GitHub',
388
+ status: 'warn',
389
+ detail: 'no answer within 20 seconds',
390
+ means: 'downloads of tools may fail',
391
+ fix: 'check your VPN or proxy',
392
+ fixable: false,
393
+ },
394
+ ],
395
+ summary: { total: 4, ok: 1, fixed: 1, warn: 1, needsYou: 1, skipped: 0, fixable: 0 },
396
+ details: [
397
+ ['Windows Sandbox', 'available'],
398
+ ['Config file', 'F:\\AgentProjects\\config.json'],
399
+ ['Projects running', 'windows-sandbox (launch)'],
400
+ ],
401
+ setup: {
402
+ checks: [
403
+ { name: 'Windows edition', status: 'ok', detail: 'Pro' },
404
+ { name: 'Windows Sandbox feature', status: 'action', detail: 'turned off' },
405
+ { name: 'Virtualization', status: 'ok', detail: 'on' },
406
+ ],
407
+ canEnable: true,
408
+ error: null,
409
+ },
410
+ log: 'C:\\AgentData\\logs\\repair-20261016-093012.log',
411
+ },
412
+ });
413
+ }
414
+ const LOG_DIR = 'C:\\AgentData\\logs';
415
+ /** The engines and their checks (what engine.status returns): HCS is missing its features on this sample PC. */
416
+ function sampleEngines() {
417
+ const capabilities = {
418
+ desktop: true,
419
+ gpu: true,
420
+ clipboard: true,
421
+ audio: true,
422
+ video: true,
423
+ printers: true,
424
+ liveFolderAdd: true,
425
+ attachedDisks: false,
426
+ multipleInstances: true,
427
+ hvsocket: false,
428
+ };
429
+ return engineStatus.output.parse({
430
+ engine: 'windows-sandbox',
431
+ engines: [
432
+ {
433
+ id: 'windows-sandbox',
434
+ inUse: true,
435
+ capabilities,
436
+ check: { available: true, reasons: [], fixes: [] },
437
+ },
438
+ {
439
+ id: 'hcs',
440
+ inUse: false,
441
+ capabilities: {
442
+ ...capabilities,
443
+ desktop: false,
444
+ gpu: false,
445
+ clipboard: false,
446
+ audio: false,
447
+ video: false,
448
+ printers: false,
449
+ liveFolderAdd: false,
450
+ multipleInstances: true,
451
+ hvsocket: true,
452
+ },
453
+ check: {
454
+ available: false,
455
+ reasons: ['The Containers feature is not turned on.', 'No Server Core image is on this PC.'],
456
+ fixes: [
457
+ 'Enable-WindowsOptionalFeature -Online -FeatureName Containers -All',
458
+ 'Pull the Server Core image with Docker Desktop, or set AGENT_SANDBOX_HCS_IMAGE to a folder with one.',
459
+ ],
460
+ },
461
+ },
462
+ ],
463
+ });
464
+ }
465
+ /** The sandbox's log files, newest first, and a crash report (what logs.list returns). */
466
+ function sampleLogs() {
467
+ return listLogs.output.parse({
468
+ folder: LOG_DIR,
469
+ files: [
470
+ {
471
+ name: 'guest-2026-10-16.log',
472
+ path: LOG_DIR + '\\guest-2026-10-16.log',
473
+ bytes: 182400,
474
+ modified: Date.now() - MINUTE,
475
+ },
476
+ {
477
+ name: 'daemon-2026-10-16.log',
478
+ path: LOG_DIR + '\\daemon-2026-10-16.log',
479
+ bytes: 9216,
480
+ modified: Date.now() - 12 * MINUTE,
481
+ },
482
+ {
483
+ name: 'bootstrap-2026-10-14.log',
484
+ path: LOG_DIR + '\\bootstrap-2026-10-14.log',
485
+ bytes: 2048,
486
+ modified: Date.now() - 2 * 24 * 60 * MINUTE,
487
+ },
488
+ ],
489
+ crash: true,
490
+ });
491
+ }
492
+ /** The end of one log (what logs.tail returns): plausible sandbox lines, one of them very long. */
493
+ function sampleLogTail(input) {
494
+ const name = input.name ?? 'guest-2026-10-16.log';
495
+ if (name === CRASH)
496
+ return tailLog.output.parse({
497
+ name: CRASH,
498
+ file: LOG_DIR + '\\crashes\\crash-2026-10-14-0912.txt',
499
+ text: 'Crash report (preview)\nThis PC stopped responding at 09:02 and was restarted at 09:14.\n',
500
+ next: 0,
501
+ });
502
+ const lines = Array.from({ length: 40 }, (_, i) => i === 17
503
+ ? '16:02:11 [daemon] session claude-4f2 env ' + 'PATH=C:\\nvm;C:\\Program Files\\Git\\cmd;'.repeat(6)
504
+ : '16:' + String(i).padStart(2, '0') + ':11 [guest] ' + (i % 3 ? 'ok' : 'checked') + ' item ' + i);
505
+ return tailLog.output.parse({
506
+ name,
507
+ file: LOG_DIR + '\\' + name,
508
+ text: lines.join('\n') + '\n',
509
+ next: 0,
510
+ });
511
+ }
512
+ /** The real features where they only touch the temp folder, sample data for the rest. */
513
+ function previewRpc(ctx, state) {
514
+ const sample = async (id, input, io) => {
515
+ switch (id) {
516
+ case 'sandbox.status':
517
+ return sampleStatus(state.running);
518
+ case 'vpn.status':
519
+ return vpnStatus.output.parse({
520
+ enabled: true,
521
+ provider: 'nordvpn',
522
+ protocol: 'udp',
523
+ country: 'Netherlands',
524
+ killSwitch: true,
525
+ login: state.vpnLogin,
526
+ loginSavedAt: state.vpnLogin === 'saved' ? '2026-10-14T09:30:00.000Z' : null,
527
+ running: state.running
528
+ ? {
529
+ level: 'ok',
530
+ text: 'VPN up (nl1234.nordvpn.com), the sandbox appears as 185.1.2.3 (this PC: 81.4.5.6).',
531
+ }
532
+ : null,
533
+ });
534
+ case 'vpn.login':
535
+ // The preview asks the two questions like the real operation and keeps nothing of the answers.
536
+ io.log('NordVPN needs its service credentials, not your usual login. To get them:', 'muted');
537
+ if ((await io.secret({ title: 'Service user name' })) === undefined)
538
+ cancelled();
539
+ if ((await io.secret({ title: 'Service password' })) === undefined)
540
+ cancelled();
541
+ state.vpnLogin = 'saved';
542
+ return { message: 'Saved. Turn the VPN on with: sandbox config set vpn.enabled true' };
543
+ case 'vpn.logout':
544
+ if (!(await io.confirm({ title: 'Delete the saved VPN login?', yes: 'Delete', danger: true })))
545
+ cancelled();
546
+ state.vpnLogin = 'none';
547
+ return { deleted: true, message: 'The saved VPN login is deleted.' };
548
+ case 'health.last':
549
+ return sampleHealth();
550
+ case 'health.check':
551
+ io.progress('Checking this PC');
552
+ return {
553
+ summary: { total: 4, ok: 1, fixed: 0, warn: 1, needsYou: 1, skipped: 0, fixable: 1 },
554
+ changed: false,
555
+ log: null,
556
+ };
557
+ case 'health.repair':
558
+ io.log('Repair will change:', 'accent');
559
+ io.log(' 1. Install pointers: point the command at the new version');
560
+ if (!(await io.confirm({ title: 'Fix this problem?', yes: 'Fix', danger: true })))
561
+ cancelled();
562
+ return {
563
+ summary: { total: 4, ok: 2, fixed: 1, warn: 1, needsYou: 0, skipped: 0, fixable: 0 },
564
+ changed: false,
565
+ log: null,
566
+ };
567
+ case 'health.enableSandbox':
568
+ if (!(await io.confirm({
569
+ title: 'Turn on Windows Sandbox?',
570
+ lines: ['Windows asks for admin permission, then you restart Windows to finish.'],
571
+ yes: 'Turn on',
572
+ danger: true,
573
+ })))
574
+ cancelled();
575
+ return { message: 'Done. Restart Windows to finish. (preview: nothing was changed)' };
576
+ case 'engine.status':
577
+ return sampleEngines();
578
+ case 'logs.list':
579
+ return sampleLogs();
580
+ case 'logs.tail':
581
+ return sampleLogTail(input);
582
+ case 'sessions.list':
583
+ return sampleSessions(state.running);
584
+ case 'agents.list':
585
+ return sampleAgents();
586
+ case 'agents.start':
587
+ return { session: SESSIONS[0].id, message: 'Started claude in windows-sandbox (preview: nothing started).' };
588
+ case 'agents.makeDefault':
589
+ return { message: 'codex is the default agent (preview: nothing was changed).' };
590
+ case 'agents.remove':
591
+ if (!(await io.confirm({ title: 'Remove aider?', yes: 'Remove', danger: true, implied: true })))
592
+ cancelled();
593
+ return { message: 'Removed aider (preview: nothing was changed).' };
594
+ case 'agents.add':
595
+ return { name: 'preview', message: 'Added preview (preview: nothing was saved).' };
596
+ case 'accounts.list':
597
+ return sampleAccounts();
598
+ case 'accounts.remove':
599
+ if (!(await io.confirm({ title: 'Remove the saved account?', yes: 'Remove', danger: true })))
600
+ cancelled();
601
+ return { message: 'Removed account (preview: nothing was changed).' };
602
+ case 'accounts.use':
603
+ return { lines: ['Sandbox now uses "work" (dev@example.com) (preview: nothing was changed).'] };
604
+ case 'accounts.save':
605
+ case 'accounts.default':
606
+ case 'accounts.rename':
607
+ return { name: 'preview', message: 'Done (preview: nothing was changed).' };
608
+ case 'sandbox.stop':
609
+ if (!(await io.confirm({ title: 'Stop the sandbox?', yes: 'Stop', danger: true })))
610
+ cancelled();
611
+ io.progress('Stopping the sandbox');
612
+ await new Promise((r) => setTimeout(r, 800));
613
+ state.running = false;
614
+ return { message: 'The sandbox is stopped (preview).' };
615
+ case 'sandbox.show':
616
+ case 'sandbox.hide':
617
+ return { message: 'Done (preview: nothing was changed).' };
618
+ case 'sessions.restart':
619
+ return { message: 'Restarted (preview: nothing was changed).', restarted: 0 };
620
+ case 'projects.list':
621
+ return sampleProjects(state.running);
622
+ case 'projects.add':
623
+ return { message: 'Added F:\\Code\\scratch to your projects. (preview: nothing was saved)' };
624
+ case 'projects.remove':
625
+ if (!(await io.confirm({ title: 'Forget scratch?', yes: 'Forget', danger: true, implied: true })))
626
+ cancelled();
627
+ return { message: 'Removed F:\\Code\\scratch from your projects (preview: nothing was changed).' };
628
+ case 'projects.include':
629
+ case 'projects.exclude':
630
+ return { message: 'Excluded F:\\AgentProjects\\old-demo. (preview: nothing was changed)' };
631
+ case 'projects.all':
632
+ return { message: 'Mapping all projects at every start is on. (preview: nothing was changed)' };
633
+ case 'projects.roots':
634
+ if (!(await io.confirm({ title: 'Remove the root AgentProjects?', yes: 'Remove', danger: true, implied: true })))
635
+ cancelled();
636
+ return { message: 'Removed the project root F:\\AgentProjects. (preview: nothing was changed)' };
637
+ case 'projects.choose': {
638
+ const picked = await io.checklist({
639
+ title: 'Projects mapped at every start, so they open without a restart:',
640
+ choices: [
641
+ { value: 'windows-sandbox', label: 'F:\\AgentProjects\\windows-sandbox (this folder)' },
642
+ { value: 'mw2-agent', label: 'F:\\AgentProjects\\mw2-agent' },
643
+ { value: 'scratch', label: 'F:\\Code\\scratch' },
644
+ ],
645
+ checked: ['windows-sandbox', 'mw2-agent'],
646
+ });
647
+ if (picked === undefined)
648
+ cancelled();
649
+ return { message: picked.length + ' project(s) mapped at every start (preview: nothing was changed).' };
650
+ }
651
+ case 'updates.status':
652
+ return sampleUpdates();
653
+ // Fakes only: the preview never checks GitHub, installs, or switches anything on this PC.
654
+ case 'updates.update': {
655
+ const u = input;
656
+ if (u.rollback) {
657
+ if (!(await io.confirm({
658
+ title: 'Go back from version 1.4.3 to version 1.4.2?',
659
+ lines: ['Takes effect the next time you start it.'],
660
+ yes: 'Go back',
661
+ danger: true,
662
+ })))
663
+ cancelled();
664
+ return { line: 'Went back to version 1.4.2. (preview: nothing was changed)', latest: null };
665
+ }
666
+ if (u.auto)
667
+ return { line: 'Automatic updates are ' + u.auto + '. (preview: nothing was changed)', latest: null };
668
+ if (u.check)
669
+ return { line: 'Version 1.5.0 is available (you have 1.4.3). Run: sandbox update', latest: '1.5.0' };
670
+ if (!(await io.confirm({ title: 'Install the newest version if there is one?', yes: 'Install', danger: true })))
671
+ cancelled();
672
+ return { line: 'You have the newest version (1.4.3). (preview: nothing was installed)', latest: null };
673
+ }
674
+ case 'updates.migrate':
675
+ return { line: 'Updated: 2026-10-unpin-config-defaults. (preview: nothing was changed)' };
676
+ case 'data.show':
677
+ return sampleData();
678
+ case 'storage.show':
679
+ return sampleStorage();
680
+ case 'storage.containedStatus':
681
+ return sampleContained();
682
+ case 'storage.change': {
683
+ // The real flow asks for the folder (the browser), then move or switch; the preview asks the same questions.
684
+ const picked = await io.path({
685
+ title: 'Choose the folder for your saved data',
686
+ lines: ['Now: F:\\AgentSandbox (8.9 GB).'],
687
+ pathKind: 'dir',
688
+ initial: 'F:\\',
689
+ });
690
+ if (picked === undefined)
691
+ cancelled();
692
+ const how = await io.choose({
693
+ title: 'Move your data to ' + picked + '?',
694
+ lines: ['From: F:\\AgentSandbox', 'Size: 8.9 GB', 'Time: a few seconds (same drive, nothing is copied)'],
695
+ choices: [
696
+ { value: 'move', label: 'Move data' },
697
+ { value: 'use', label: 'Switch without moving' },
698
+ { value: 'cancel', label: 'Cancel' },
699
+ ],
700
+ });
701
+ if (how === undefined || how === 'cancel')
702
+ cancelled();
703
+ return { message: 'Done (preview: nothing was moved or switched).' };
704
+ }
705
+ case 'storage.move':
706
+ if (!(await io.confirm({ title: 'Move your data to F:\\Sandbox?', yes: 'Move' })))
707
+ cancelled();
708
+ return { message: 'Moved (preview: nothing was moved).' };
709
+ case 'storage.use':
710
+ if (!(await io.confirm({ title: 'Use F:\\Sandbox from now on, without moving your data?', yes: 'Use' })))
711
+ cancelled();
712
+ return { message: 'Your data is now looked for in F:\\Sandbox (preview: nothing was changed).' };
713
+ case 'storage.containedOn':
714
+ if (!(await io.confirm({ title: 'Turn contained storage on?', yes: 'Turn on' })))
715
+ cancelled();
716
+ return { message: 'Contained storage is on (preview: nothing was changed).' };
717
+ case 'storage.containedOff':
718
+ if (!(await io.confirm({ title: 'Turn contained storage off?', yes: 'Turn off', danger: true })))
719
+ cancelled();
720
+ return { message: 'Contained storage is off (preview: nothing was changed).' };
721
+ case 'data.clean':
722
+ case 'data.prune':
723
+ if (!(await io.confirm({ title: 'Delete the chosen data?', yes: 'Delete', danger: true, implied: true })))
724
+ cancelled();
725
+ return { message: 'Removed (preview: nothing was deleted).', freedBytes: 0, removed: true };
726
+ case 'apps.request':
727
+ // The real operation opens a browser on this PC; the preview only shows the address it would open.
728
+ return {
729
+ url: 'https://github.com/JoshDiDuca/windows-development-sandbox/issues/new (preview: nothing opened)',
730
+ };
731
+ default:
732
+ return undefined;
733
+ }
734
+ };
735
+ const kinds = {
736
+ 'sandbox.status': 'query',
737
+ 'sessions.list': 'query',
738
+ 'settings.list': 'query',
739
+ 'vpn.status': 'query',
740
+ 'vpn.login': 'operation',
741
+ 'vpn.logout': 'operation',
742
+ 'sandbox.stop': 'operation',
743
+ 'sandbox.show': 'operation',
744
+ 'sandbox.hide': 'operation',
745
+ 'sessions.restart': 'operation',
746
+ 'agents.list': 'query',
747
+ 'agents.start': 'operation',
748
+ 'agents.makeDefault': 'operation',
749
+ 'agents.remove': 'operation',
750
+ 'agents.add': 'operation',
751
+ 'accounts.list': 'query',
752
+ 'accounts.save': 'operation',
753
+ 'accounts.use': 'operation',
754
+ 'accounts.default': 'operation',
755
+ 'accounts.rename': 'operation',
756
+ 'accounts.remove': 'operation',
757
+ 'settings.set': 'operation',
758
+ 'settings.reset': 'operation',
759
+ 'files.browse': 'query',
760
+ 'apps.list': 'query',
761
+ 'apps.toggle': 'operation',
762
+ 'apps.setCustom': 'operation',
763
+ 'apps.request': 'operation',
764
+ 'projects.list': 'query',
765
+ 'projects.add': 'operation',
766
+ 'projects.remove': 'operation',
767
+ 'projects.include': 'operation',
768
+ 'projects.exclude': 'operation',
769
+ 'projects.all': 'operation',
770
+ 'projects.roots': 'operation',
771
+ 'projects.choose': 'operation',
772
+ 'health.last': 'query',
773
+ 'health.check': 'operation',
774
+ 'health.repair': 'operation',
775
+ 'health.enableSandbox': 'operation',
776
+ 'data.show': 'query',
777
+ 'updates.status': 'query',
778
+ 'updates.update': 'operation',
779
+ 'updates.migrate': 'operation',
780
+ 'storage.show': 'query',
781
+ 'storage.containedStatus': 'query',
782
+ 'storage.change': 'operation',
783
+ 'storage.move': 'operation',
784
+ 'storage.use': 'operation',
785
+ 'storage.containedOn': 'operation',
786
+ 'storage.containedOff': 'operation',
787
+ 'data.clean': 'operation',
788
+ 'data.prune': 'operation',
789
+ 'logs.list': 'query',
790
+ 'logs.tail': 'query',
791
+ 'engine.status': 'query',
792
+ };
793
+ return {
794
+ kind: (id) => kinds[id],
795
+ liveMs: (id) => (id === 'sandbox.status' || id === 'sessions.list' ? 2500 : id === 'logs.tail' ? 1000 : undefined),
796
+ run: async (id, input, io) => id !== 'apps.request' && (id.startsWith('settings.') || id.startsWith('apps.') || id === 'files.browse')
797
+ ? runDefinition(id, ctx, input, io)
798
+ : ((await sample(id, input, io)) ?? {}),
799
+ };
800
+ }
801
+ async function main() {
802
+ const portArg = process.argv.indexOf('--port');
803
+ const port = portArg > 0 ? Number(process.argv[portArg + 1]) : 47900;
804
+ const packageRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/(\w:)/, '$1')), '../../..');
805
+ const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'sandbox-web-preview-'));
806
+ const project = path.join(temp, 'project');
807
+ fs.mkdirSync(project);
808
+ const configPath = path.join(temp, 'config.json');
809
+ fs.writeFileSync(configPath, JSON.stringify({
810
+ sandbox: { memoryMb: 16384, vGpu: true },
811
+ web: { enabled: true },
812
+ apps: { install: ['lazygit', 'bruno', 'chrome'] },
813
+ }));
814
+ // Apps: three of the catalogue are downloaded already (the marker a finished download leaves in the data folder).
815
+ const dataPath = path.join(temp, 'data');
816
+ for (const id of ['lazygit', 'bruno', 'sysinternals']) {
817
+ const marker = path.join(dataPath, 'tools', 'apps', id);
818
+ fs.mkdirSync(marker, { recursive: true });
819
+ fs.writeFileSync(path.join(marker, '.agent-sandbox-app'), id);
820
+ }
821
+ const ctx = {
822
+ loaded: { configPath },
823
+ options: { workspace: project },
824
+ storageRoot: path.join(temp, 'storage'),
825
+ dataPath,
826
+ };
827
+ const state = { running: true, vpnLogin: 'none' };
828
+ const ptyPort = await startFakePty();
829
+ const backend = {
830
+ info: () => Promise.resolve({
831
+ sandbox: state.running ? 'running' : 'stopped',
832
+ owner: null,
833
+ canUse: true,
834
+ harnesses: ['claude', 'codex', 'gemini', 'opencode'],
835
+ defaultHarness: 'claude',
836
+ projects: [
837
+ { name: 'windows-sandbox', guest: 'C:\\Projects\\AgentProjects\\windows-sandbox' },
838
+ { name: 'mw2-agent', guest: 'C:\\Projects\\AgentProjects\\mw2-agent' },
839
+ ],
840
+ }),
841
+ sessions: () => Promise.resolve(state.running ? SESSIONS.map((s, i) => webSession(s, i)) : []),
842
+ endpoint: (id) => SESSIONS.some((s) => s.id === id) ? { addresses: ['127.0.0.1'], port: ptyPort, token: 'preview' } : null,
843
+ };
844
+ const server = new WebServer({
845
+ port,
846
+ token: TOKEN,
847
+ backend,
848
+ staticRoot: path.join(packageRoot, 'dist', 'web'),
849
+ rpc: previewRpc(ctx, state),
850
+ onStop: () => process.exit(0),
851
+ });
852
+ await server.start();
853
+ console.log('Web UI preview (sample data; settings in ' + configPath + '):');
854
+ console.log('http://127.0.0.1:' + server.port + '/#k=' + TOKEN);
855
+ }
856
+ void main();