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,112 @@
1
+ import { z } from 'zod';
2
+ import { type Page } from '../../kernel/index.js';
3
+ /** The warnings every VPN user must see (alpha): on every surface. */
4
+ export declare const VPN_WARNINGS: readonly string[];
5
+ /** The steps to get the NordVPN service credentials, in the words of Nord Account (shown before asking). */
6
+ export declare const NORD_STEPS: readonly string[];
7
+ export declare const VpnStatusSchema: z.ZodObject<{
8
+ enabled: z.ZodBoolean;
9
+ provider: z.ZodEnum<{
10
+ nordvpn: "nordvpn";
11
+ "openvpn-file": "openvpn-file";
12
+ "wireguard-file": "wireguard-file";
13
+ }>;
14
+ protocol: z.ZodEnum<{
15
+ udp: "udp";
16
+ tcp: "tcp";
17
+ }>;
18
+ country: z.ZodString;
19
+ killSwitch: z.ZodBoolean;
20
+ login: z.ZodEnum<{
21
+ none: "none";
22
+ saved: "saved";
23
+ unreadable: "unreadable";
24
+ }>;
25
+ loginSavedAt: z.ZodNullable<z.ZodString>;
26
+ running: z.ZodNullable<z.ZodObject<{
27
+ level: z.ZodEnum<{
28
+ ok: "ok";
29
+ warn: "warn";
30
+ bad: "bad";
31
+ }>;
32
+ text: z.ZodString;
33
+ }, z.core.$strip>>;
34
+ }, z.core.$strip>;
35
+ export type VpnStatus = z.output<typeof VpnStatusSchema>;
36
+ export declare const vpnStatus: import("../../kernel/define.js").QueryDef<z.ZodObject<{
37
+ tunnel: z.ZodDefault<z.ZodBoolean>;
38
+ }, z.core.$strip>, z.ZodObject<{
39
+ enabled: z.ZodBoolean;
40
+ provider: z.ZodEnum<{
41
+ nordvpn: "nordvpn";
42
+ "openvpn-file": "openvpn-file";
43
+ "wireguard-file": "wireguard-file";
44
+ }>;
45
+ protocol: z.ZodEnum<{
46
+ udp: "udp";
47
+ tcp: "tcp";
48
+ }>;
49
+ country: z.ZodString;
50
+ killSwitch: z.ZodBoolean;
51
+ login: z.ZodEnum<{
52
+ none: "none";
53
+ saved: "saved";
54
+ unreadable: "unreadable";
55
+ }>;
56
+ loginSavedAt: z.ZodNullable<z.ZodString>;
57
+ running: z.ZodNullable<z.ZodObject<{
58
+ level: z.ZodEnum<{
59
+ ok: "ok";
60
+ warn: "warn";
61
+ bad: "bad";
62
+ }>;
63
+ text: z.ZodString;
64
+ }, z.core.$strip>>;
65
+ }, z.core.$strip>, "vpn.status">;
66
+ export declare const vpnLogin: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strict>, z.ZodObject<{
67
+ message: z.ZodString;
68
+ }, z.core.$strip>, "vpn.login">;
69
+ export declare const vpnLogout: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strict>, z.ZodObject<{
70
+ deleted: z.ZodBoolean;
71
+ message: z.ZodString;
72
+ }, z.core.$strip>, "vpn.logout">;
73
+ /** The Settings row of the menu (label, hint, description), from the status. Pure. */
74
+ export declare function vpnLoginRowOf(s: VpnStatus): {
75
+ label: string;
76
+ hint: string;
77
+ description: string;
78
+ };
79
+ /** The status page: the facts, the next step (command line only), the warnings and the login actions. */
80
+ export declare function vpnPage(s: VpnStatus): Page;
81
+ export declare const vpnView: import("../../kernel/define.js").ViewDef<{
82
+ status: import("../../kernel/define.js").QueryDef<z.ZodObject<{
83
+ tunnel: z.ZodDefault<z.ZodBoolean>;
84
+ }, z.core.$strip>, z.ZodObject<{
85
+ enabled: z.ZodBoolean;
86
+ provider: z.ZodEnum<{
87
+ nordvpn: "nordvpn";
88
+ "openvpn-file": "openvpn-file";
89
+ "wireguard-file": "wireguard-file";
90
+ }>;
91
+ protocol: z.ZodEnum<{
92
+ udp: "udp";
93
+ tcp: "tcp";
94
+ }>;
95
+ country: z.ZodString;
96
+ killSwitch: z.ZodBoolean;
97
+ login: z.ZodEnum<{
98
+ none: "none";
99
+ saved: "saved";
100
+ unreadable: "unreadable";
101
+ }>;
102
+ loginSavedAt: z.ZodNullable<z.ZodString>;
103
+ running: z.ZodNullable<z.ZodObject<{
104
+ level: z.ZodEnum<{
105
+ ok: "ok";
106
+ warn: "warn";
107
+ bad: "bad";
108
+ }>;
109
+ text: z.ZodString;
110
+ }, z.core.$strip>>;
111
+ }, z.core.$strip>, "vpn.status">;
112
+ }, Record<string, never>, "vpn">;
@@ -0,0 +1,174 @@
1
+ // The VPN: its settings, whether a login is saved (never its values), the running tunnel, and saving or deleting the
2
+ // login. Pure: schemas, labels and the view; vpn.run.ts does the work. The login itself is never an input or an output.
3
+ import { z } from 'zod';
4
+ import { action, defineOperation, defineQuery, defineView, } from '../../kernel/index.js';
5
+ import { setSetting } from '../settings/settings.def.js';
6
+ const ProviderSchema = z
7
+ .enum(['nordvpn', 'openvpn-file', 'wireguard-file'])
8
+ .describe('Which VPN (setting vpn.provider)');
9
+ const LoginStateSchema = z
10
+ .enum(['none', 'saved', 'unreadable'])
11
+ .describe('Whether a login is saved and can be opened by you');
12
+ /** The warnings every VPN user must see (alpha): on every surface. */
13
+ export const VPN_WARNINGS = [
14
+ 'The VPN is an alpha: a tunnel carrying traffic is not confirmed yet (docs/vpn.md lists what still needs checking).',
15
+ 'The agent in the sandbox can read the VPN login (a service login you can revoke) and can turn the tunnel off, because it is the administrator there.',
16
+ 'Free VPNs see all your traffic: use one you trust.',
17
+ ];
18
+ /** The steps to get the NordVPN service credentials, in the words of Nord Account (shown before asking). */
19
+ export const NORD_STEPS = [
20
+ 'Sign in at https://my.nordaccount.com with your usual NordVPN e-mail and password.',
21
+ 'Open NordVPN, then "Set up NordVPN manually" (under Advanced settings).',
22
+ 'Verify your e-mail if it asks, then copy the "Service credentials": a user name and a password.',
23
+ 'These are NOT your account password. You can revoke them in the same place whenever you like.',
24
+ ];
25
+ export const VpnStatusSchema = z.object({
26
+ enabled: z.boolean().describe('The VPN is on (setting vpn.enabled)'),
27
+ provider: ProviderSchema,
28
+ protocol: z.enum(['udp', 'tcp']).describe('udp or tcp (setting vpn.protocol)'),
29
+ country: z.string().describe('The NordVPN country; empty = the best server anywhere'),
30
+ killSwitch: z.boolean().describe('No internet when the tunnel fails (setting vpn.killSwitch)'),
31
+ login: LoginStateSchema,
32
+ loginSavedAt: z.string().nullable().describe('When the login was saved (the date and time, never the login)'),
33
+ running: z
34
+ .object({
35
+ level: z.enum(['ok', 'warn', 'bad']).describe('How the tunnel is doing'),
36
+ text: z.string().describe('What the sandbox reported'),
37
+ })
38
+ .nullable()
39
+ .describe("The running sandbox's tunnel, when one runs with the VPN on"),
40
+ });
41
+ export const vpnStatus = defineQuery({
42
+ id: 'vpn.status',
43
+ title: 'VPN',
44
+ summary: 'the VPN settings, whether a login is saved, and the running tunnel',
45
+ input: z.object({
46
+ tunnel: z
47
+ .boolean()
48
+ .default(true)
49
+ .describe('also ask the running sandbox how its tunnel is doing (one request to api.ipify.org)'),
50
+ }),
51
+ output: VpnStatusSchema,
52
+ cli: { name: 'vpn', action: 'status', json: true },
53
+ });
54
+ export const vpnLogin = defineOperation({
55
+ id: 'vpn.login',
56
+ title: 'Save the VPN login…',
57
+ summary: 'save the VPN login (typed hidden, kept encrypted, never printed)',
58
+ input: z.object({}).strict(),
59
+ output: z.object({ message: z.string().describe('What happened') }),
60
+ text: (o) => o.message,
61
+ cli: { name: 'vpn', action: 'login' },
62
+ });
63
+ export const vpnLogout = defineOperation({
64
+ id: 'vpn.logout',
65
+ title: 'Delete the VPN login',
66
+ summary: 'delete the saved VPN login',
67
+ input: z.object({}).strict(),
68
+ output: z.object({
69
+ deleted: z.boolean().describe('A login was saved and is gone'),
70
+ message: z.string().describe('What happened'),
71
+ }),
72
+ danger: true,
73
+ text: (o) => o.message,
74
+ cli: { name: 'vpn', action: 'logout' },
75
+ });
76
+ const PROVIDER_TEXT = {
77
+ nordvpn: 'NordVPN',
78
+ 'wireguard-file': 'your own WireGuard .conf',
79
+ 'openvpn-file': 'your own .ovpn file',
80
+ };
81
+ const LOGIN_TEXT = {
82
+ none: 'not saved',
83
+ saved: 'saved (encrypted)',
84
+ unreadable: 'cannot be read',
85
+ };
86
+ const LOGIN_TONE = {
87
+ none: 'warn',
88
+ saved: 'ok',
89
+ unreadable: 'danger',
90
+ };
91
+ const RUNNING_TONE = {
92
+ ok: 'ok',
93
+ warn: 'warn',
94
+ bad: 'danger',
95
+ };
96
+ /** The Settings row of the menu (label, hint, description), from the status. Pure. */
97
+ export function vpnLoginRowOf(s) {
98
+ if (s.provider === 'wireguard-file')
99
+ return {
100
+ label: 'VPN login',
101
+ hint: 'not needed',
102
+ description: 'A WireGuard file carries its own keys (vpn.configFile): there is no login to set.',
103
+ };
104
+ return {
105
+ label: s.provider === 'nordvpn' ? 'Set NordVPN login…' : 'Set VPN login…',
106
+ hint: s.login === 'saved' ? 'saved' : s.login === 'unreadable' ? 'cannot be read' : 'not saved',
107
+ description: 'The login the VPN uses (for NordVPN the service credentials from Nord Account > NordVPN > Set up NordVPN manually, not your account password). Typed hidden, kept encrypted for your Windows user, never shown. ' +
108
+ VPN_WARNINGS.join(' '),
109
+ };
110
+ }
111
+ /** The status page: the facts, the next step (command line only), the warnings and the login actions. */
112
+ export function vpnPage(s) {
113
+ const wireguard = s.provider === 'wireguard-file';
114
+ const savedDate = s.loginSavedAt ? ' ' + s.loginSavedAt.slice(0, 10) : '';
115
+ const facts = [
116
+ s.enabled
117
+ ? { id: 'vpn', label: 'VPN', value: 'on', tone: 'ok' }
118
+ : { id: 'vpn', label: 'VPN', value: 'off (applies from the next start)', tone: 'muted' },
119
+ { id: 'provider', label: 'Provider', value: PROVIDER_TEXT[s.provider] },
120
+ { id: 'protocol', label: 'Protocol', value: s.protocol },
121
+ { id: 'country', label: 'Country', value: s.country || 'best available' },
122
+ s.killSwitch
123
+ ? { id: 'killSwitch', label: 'Kill switch', value: 'on (no internet if the tunnel fails)' }
124
+ : { id: 'killSwitch', label: 'Kill switch', value: 'off', tone: 'warn' },
125
+ wireguard
126
+ ? { id: 'login', label: 'Login', value: 'not needed (the keys are in your config)', tone: 'muted' }
127
+ : { id: 'login', label: 'Login', value: LOGIN_TEXT[s.login] + savedDate, tone: LOGIN_TONE[s.login] },
128
+ ...(s.running
129
+ ? [
130
+ {
131
+ id: 'running',
132
+ label: 'Running now',
133
+ value: s.running.text,
134
+ tone: RUNNING_TONE[s.running.level],
135
+ },
136
+ ]
137
+ : []),
138
+ ];
139
+ const notes = [
140
+ ...(!wireguard && s.login === 'none'
141
+ ? [{ text: 'Next: sandbox vpn login', tone: 'muted', only: 'cli' }]
142
+ : []),
143
+ ...(s.login === 'unreadable'
144
+ ? [
145
+ {
146
+ text: 'Only the Windows user that saved it can read it. Save it again: sandbox vpn login',
147
+ tone: 'muted',
148
+ },
149
+ ]
150
+ : []),
151
+ ...VPN_WARNINGS.map((text) => ({ text, tone: 'warn' })),
152
+ ];
153
+ // Turning it on or off is the vpn.enabled setting (it applies from the next start).
154
+ const toggle = action(setSetting, { scope: 'user', key: 'vpn.enabled', value: !s.enabled }, { label: s.enabled ? 'Turn the VPN off' : 'Turn the VPN on', verb: s.enabled ? 'turn off' : 'turn on', key: 'o' });
155
+ const actions = [
156
+ toggle,
157
+ ...(wireguard
158
+ ? []
159
+ : [
160
+ action(vpnLogin, {}, { key: 'v', verb: 'save login' }),
161
+ ...(s.login !== 'none' ? [action(vpnLogout, {}, { key: 'x', verb: 'delete login' })] : []),
162
+ ]),
163
+ ];
164
+ const section = { id: 'vpn', facts, notes, actions };
165
+ return { title: 'VPN', sections: [section] };
166
+ }
167
+ export const vpnView = defineView({
168
+ id: 'vpn',
169
+ title: 'VPN',
170
+ summary: "The sandbox's VPN: whether it is on, the saved login, and the tunnel.",
171
+ queries: { status: vpnStatus },
172
+ operations: [vpnLogin, vpnLogout, setSetting],
173
+ build: ({ status }) => vpnPage(status),
174
+ });
@@ -0,0 +1,37 @@
1
+ export declare const vpnStatusRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").QueryDef<import("zod").ZodObject<{
2
+ tunnel: import("zod").ZodDefault<import("zod").ZodBoolean>;
3
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
4
+ enabled: import("zod").ZodBoolean;
5
+ provider: import("zod").ZodEnum<{
6
+ nordvpn: "nordvpn";
7
+ "openvpn-file": "openvpn-file";
8
+ "wireguard-file": "wireguard-file";
9
+ }>;
10
+ protocol: import("zod").ZodEnum<{
11
+ udp: "udp";
12
+ tcp: "tcp";
13
+ }>;
14
+ country: import("zod").ZodString;
15
+ killSwitch: import("zod").ZodBoolean;
16
+ login: import("zod").ZodEnum<{
17
+ none: "none";
18
+ saved: "saved";
19
+ unreadable: "unreadable";
20
+ }>;
21
+ loginSavedAt: import("zod").ZodNullable<import("zod").ZodString>;
22
+ running: import("zod").ZodNullable<import("zod").ZodObject<{
23
+ level: import("zod").ZodEnum<{
24
+ ok: "ok";
25
+ warn: "warn";
26
+ bad: "bad";
27
+ }>;
28
+ text: import("zod").ZodString;
29
+ }, import("zod/v4/core").$strip>>;
30
+ }, import("zod/v4/core").$strip>, "vpn.status">, import("../../../cli/commands/context.js").Context>;
31
+ export declare const vpnLoginRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
32
+ message: import("zod").ZodString;
33
+ }, import("zod/v4/core").$strip>, "vpn.login">, import("../../../cli/commands/context.js").Context>;
34
+ export declare const vpnLogoutRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
35
+ deleted: import("zod").ZodBoolean;
36
+ message: import("zod").ZodString;
37
+ }, import("zod/v4/core").$strip>, "vpn.logout">, import("../../../cli/commands/context.js").Context>;
@@ -0,0 +1,54 @@
1
+ // The VPN feature's work: its status (no request to the network when asked not to), saving the login through io.secret
2
+ // (the answers are kept only for the save, never returned, logged or shown), and deleting it after a confirmation.
3
+ import { requireOnPc } from '../../../cli/commands/context.js';
4
+ import { VpnService } from '../../../cli/services/vpn-service.js';
5
+ import { implement } from '../../context.js';
6
+ import { cancelled } from '../../kernel/index.js';
7
+ import { NORD_STEPS, VPN_WARNINGS, vpnLogin, vpnLogout, vpnStatus } from './vpn.def.js';
8
+ export const vpnStatusRun = implement(vpnStatus, async (ctx, input) => new VpnService(ctx).report({ tunnel: input.tunnel }));
9
+ export const vpnLoginRun = implement(vpnLogin, async (ctx, _input, io) => {
10
+ requireOnPc('vpn login');
11
+ const service = new VpnService(ctx);
12
+ if (service.provider === 'wireguard-file')
13
+ return { message: 'A WireGuard config needs no login: the keys are in the file vpn.configFile points to.' };
14
+ const nord = service.provider === 'nordvpn';
15
+ io.log(nord
16
+ ? 'NordVPN needs its service credentials, not your usual login. To get them:'
17
+ : 'Type the user name and password your VPN profile asks for.');
18
+ if (nord)
19
+ NORD_STEPS.forEach((s, i) => io.log(' ' + (i + 1) + '. ' + s));
20
+ io.log('What you type is not shown. It is kept encrypted for your Windows user and never printed.', 'muted');
21
+ // The validators return fixed texts only: what was typed is never echoed back.
22
+ const username = await io.secret({
23
+ title: nord ? 'Service user name' : 'User name',
24
+ validate: (v) => (v.trim() ? true : 'Type the user name.'),
25
+ });
26
+ if (username === undefined)
27
+ cancelled();
28
+ const password = await io.secret({
29
+ title: nord ? 'Service password' : 'Password',
30
+ validate: (v) => (v ? true : 'Type the password.'),
31
+ });
32
+ if (password === undefined)
33
+ cancelled();
34
+ service.save({ username, password });
35
+ VPN_WARNINGS.forEach((w) => io.log(w, 'muted'));
36
+ return { message: 'Saved. Turn the VPN on with: sandbox config set vpn.enabled true' };
37
+ });
38
+ export const vpnLogoutRun = implement(vpnLogout, async (ctx, _input, io) => {
39
+ requireOnPc('vpn logout');
40
+ const service = new VpnService(ctx);
41
+ if (service.loginState() === 'none')
42
+ return { deleted: false, message: 'No VPN login was saved.' };
43
+ // The CLI never asked before (a typed logout is the answer); the menu and the web still ask.
44
+ const yes = await io.confirm({
45
+ title: 'Delete the saved VPN login?',
46
+ yes: 'Delete',
47
+ danger: true,
48
+ implied: true,
49
+ });
50
+ if (!yes)
51
+ cancelled();
52
+ service.remove();
53
+ return { deleted: true, message: 'The saved VPN login is deleted.' };
54
+ });
@@ -0,0 +1,2 @@
1
+ export * from './web.def.js';
2
+ export * from './web.run.js';
@@ -0,0 +1,3 @@
1
+ // The web feature: the web UI server on this PC (start, open, stop, whether it runs). CLI and menu only.
2
+ export * from './web.def.js';
3
+ export * from './web.run.js';
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod';
2
+ import { type Page } from '../../kernel/index.js';
3
+ export declare const WebStatusSchema: z.ZodObject<{
4
+ running: z.ZodBoolean;
5
+ port: z.ZodNullable<z.ZodNumber>;
6
+ address: z.ZodNullable<z.ZodString>;
7
+ }, z.core.$strip>;
8
+ export type WebStatus = z.output<typeof WebStatusSchema>;
9
+ export declare const webStatus: import("../../kernel/define.js").QueryDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
10
+ running: z.ZodBoolean;
11
+ port: z.ZodNullable<z.ZodNumber>;
12
+ address: z.ZodNullable<z.ZodString>;
13
+ }, z.core.$strip>, "web.status">;
14
+ export declare const startWeb: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
15
+ port: z.ZodNumber;
16
+ message: z.ZodString;
17
+ }, z.core.$strip>, "web.start">;
18
+ export declare const openWeb: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
19
+ message: z.ZodString;
20
+ }, z.core.$strip>, "web.open">;
21
+ export declare const stopWeb: import("../../kernel/define.js").OperationDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
22
+ stopped: z.ZodBoolean;
23
+ message: z.ZodString;
24
+ }, z.core.$strip>, "web.stop">;
25
+ /** The web UI's Maintenance category (the menu): running or not, its address, and the three actions. */
26
+ export declare function webPage(o: WebStatus): Page;
27
+ export declare const webView: import("../../kernel/define.js").ViewDef<{
28
+ status: import("../../kernel/define.js").QueryDef<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
29
+ running: z.ZodBoolean;
30
+ port: z.ZodNullable<z.ZodNumber>;
31
+ address: z.ZodNullable<z.ZodString>;
32
+ }, z.core.$strip>, "web.status">;
33
+ }, Record<string, never>, "web">;
@@ -0,0 +1,90 @@
1
+ // The web UI server on this PC: whether it runs, and start, open and stop it. Pure: schemas, labels and the view;
2
+ // web.run.ts does the work. The web UI cannot control its own server (the page is the web UI), so every definition is
3
+ // CLI and menu only. Nothing here carries the login token: the address the page shows has none.
4
+ import { z } from 'zod';
5
+ import { action, defineOperation, defineQuery, defineView } from '../../kernel/index.js';
6
+ const NOT_ON_WEB = { except: { web: 'the page is the web UI' } };
7
+ export const WebStatusSchema = z.object({
8
+ running: z.boolean().describe('The web UI server answers'),
9
+ port: z.number().nullable().describe('Its port on 127.0.0.1, when it runs'),
10
+ address: z.string().nullable().describe('Its address (without the login token), when it runs'),
11
+ });
12
+ const MessageSchema = z.object({ message: z.string().describe('What happened') });
13
+ export const webStatus = defineQuery({
14
+ id: 'web.status',
15
+ title: 'Web UI',
16
+ summary: 'whether the web UI server runs, and its address',
17
+ input: z.object({}),
18
+ output: WebStatusSchema,
19
+ surfaces: NOT_ON_WEB,
20
+ text: (o) => o.running && o.port
21
+ ? 'The web UI is running at http://127.0.0.1:' + o.port + '/ (sandbox web open signs you in).'
22
+ : 'The web UI is not running (sandbox web start).',
23
+ cli: { name: 'web', action: 'status', json: true },
24
+ });
25
+ export const startWeb = defineOperation({
26
+ id: 'web.start',
27
+ title: 'Start the web UI',
28
+ summary: 'start the web UI server in the background (this PC only)',
29
+ input: z.object({}),
30
+ output: z.object({ port: z.number().describe('Its port'), message: z.string().describe('What happened') }),
31
+ surfaces: NOT_ON_WEB,
32
+ text: (o) => o.message,
33
+ cli: { name: 'web', action: 'start' },
34
+ });
35
+ export const openWeb = defineOperation({
36
+ id: 'web.open',
37
+ title: 'Open the web UI',
38
+ summary: 'start the web UI if needed and open it in your browser, signed in',
39
+ input: z.object({}),
40
+ output: MessageSchema,
41
+ surfaces: NOT_ON_WEB,
42
+ text: (o) => o.message,
43
+ cli: { name: 'web', action: 'open' },
44
+ });
45
+ export const stopWeb = defineOperation({
46
+ id: 'web.stop',
47
+ title: 'Stop the web UI',
48
+ summary: 'stop the web UI server',
49
+ input: z.object({}),
50
+ output: z.object({
51
+ stopped: z.boolean().describe('It was running and stopped'),
52
+ message: z.string().describe('What happened'),
53
+ }),
54
+ surfaces: NOT_ON_WEB,
55
+ text: (o) => o.message,
56
+ cli: { name: 'web', action: 'stop' },
57
+ });
58
+ /** The web UI's Maintenance category (the menu): running or not, its address, and the three actions. */
59
+ export function webPage(o) {
60
+ const open = action(openWeb, {}, { key: 'o', verb: 'open' });
61
+ const start = action(startWeb, {}, { key: 's', verb: 'start' });
62
+ const stop = action(stopWeb, {}, { key: 'x', verb: 'stop' });
63
+ return {
64
+ title: 'Web UI',
65
+ sections: [
66
+ {
67
+ id: 'web',
68
+ facts: [
69
+ {
70
+ id: 'running',
71
+ label: 'Running',
72
+ value: o.running ? 'yes' : 'no',
73
+ tone: o.running ? 'ok' : 'muted',
74
+ },
75
+ ...(o.address ? [{ id: 'address', label: 'Address', value: o.address + ' (this PC only)' }] : []),
76
+ ],
77
+ actions: o.running ? [open, stop] : [start, open],
78
+ notes: [{ text: 'Loopback only, behind a token. Open signs you in.', tone: 'muted' }],
79
+ },
80
+ ],
81
+ };
82
+ }
83
+ export const webView = defineView({
84
+ id: 'web',
85
+ title: 'Web UI',
86
+ summary: 'The web UI server on this PC: start, open, stop.',
87
+ queries: { status: webStatus },
88
+ operations: [startWeb, openWeb, stopWeb],
89
+ build: ({ status }) => webPage(status),
90
+ });
@@ -0,0 +1,24 @@
1
+ import { WebControl, type WebState } from '../../../host/web/index.js';
2
+ export declare const START_WAIT_MS = 15000;
3
+ /**
4
+ * The running server when it is this version's. A server of another version (one left running across an update) is
5
+ * stopped, so the page and the server always match; a state file without a server is removed.
6
+ */
7
+ export declare function currentServer(control: WebControl): Promise<WebState | null>;
8
+ /** Whether the web UI runs, and its address without the token. Never returns the state (it holds the token). */
9
+ export declare const webStatusRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").QueryDef<import("zod").ZodObject<{}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
10
+ running: import("zod").ZodBoolean;
11
+ port: import("zod").ZodNullable<import("zod").ZodNumber>;
12
+ address: import("zod").ZodNullable<import("zod").ZodString>;
13
+ }, import("zod/v4/core").$strip>, "web.status">, import("../../../cli/commands/context.js").Context>;
14
+ export declare const startWebRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
15
+ port: import("zod").ZodNumber;
16
+ message: import("zod").ZodString;
17
+ }, import("zod/v4/core").$strip>, "web.start">, import("../../../cli/commands/context.js").Context>;
18
+ export declare const openWebRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
19
+ message: import("zod").ZodString;
20
+ }, import("zod/v4/core").$strip>, "web.open">, import("../../../cli/commands/context.js").Context>;
21
+ export declare const stopWebRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
22
+ stopped: import("zod").ZodBoolean;
23
+ message: import("zod").ZodString;
24
+ }, import("zod/v4/core").$strip>, "web.stop">, import("../../../cli/commands/context.js").Context>;
@@ -0,0 +1,93 @@
1
+ // The web feature's work: the server in the background (start, open) and stopping it, and whether it runs. The login
2
+ // token lives in the state file and in the address the browser opens; no output, log, progress line or error carries
3
+ // it. The server itself (`sandbox _web`) stays in cli/commands/web.ts.
4
+ import path from 'node:path';
5
+ import { packageVersion } from '../../../core/package-info.js';
6
+ import { fail, sleep } from '../../../core/util/index.js';
7
+ import { requireOnPc } from '../../../cli/commands/context.js';
8
+ import { spawnDetached } from '../../../host/sandbox/index.js';
9
+ import { openBrowser, WebControl, WebStore } from '../../../host/web/index.js';
10
+ import { implement } from '../../context.js';
11
+ import { openWeb, startWeb, stopWeb, webStatus } from './web.def.js';
12
+ export const START_WAIT_MS = 15000;
13
+ function controlOf(ctx) {
14
+ return new WebControl(new WebStore(ctx.storageRoot));
15
+ }
16
+ /**
17
+ * The running server when it is this version's. A server of another version (one left running across an update) is
18
+ * stopped, so the page and the server always match; a state file without a server is removed.
19
+ */
20
+ export async function currentServer(control) {
21
+ const before = await control.status();
22
+ if (before.running && before.state && before.state.version === packageVersion())
23
+ return before.state;
24
+ if (before.running && before.state) {
25
+ await control.stop(before.state);
26
+ for (const started = Date.now(); Date.now() - started < START_WAIT_MS; await sleep(300))
27
+ if (!(await control.status()).running)
28
+ break;
29
+ }
30
+ if (before.state)
31
+ control.clear();
32
+ return null;
33
+ }
34
+ /** Starts the background server (when it is not running) and waits until it answers. */
35
+ async function startServer(ctx, io, control) {
36
+ const running = await currentServer(control);
37
+ if (running)
38
+ return {
39
+ port: running.port,
40
+ message: 'The web UI is already running on port ' + running.port + '.',
41
+ wasRunning: true,
42
+ };
43
+ const { config } = ctx.loaded;
44
+ if (!config.web.enabled)
45
+ io.log('web.enabled is off: this starts the web UI for now only. Set it to true in Settings to keep it allowed.');
46
+ io.progress('Starting the web UI');
47
+ const configFile = ctx.options.config;
48
+ spawnDetached(ctx.entry, ['_web', ...(configFile ? ['--config', path.resolve(configFile)] : [])]);
49
+ for (const started = Date.now(); Date.now() - started < START_WAIT_MS; await sleep(300)) {
50
+ const now = await control.status();
51
+ if (now.running && now.state) {
52
+ io.log('The web UI is running at http://127.0.0.1:' + now.state.port + '/ (this PC only).');
53
+ return { port: now.state.port, message: 'Open it already signed in with: sandbox web open', wasRunning: false };
54
+ }
55
+ }
56
+ return fail('The web UI did not start.', 'Run sandbox _web to see why (the port ' + config.web.port + ' may be taken: change web.port).');
57
+ }
58
+ /** Whether the web UI runs, and its address without the token. Never returns the state (it holds the token). */
59
+ export const webStatusRun = implement(webStatus, async (ctx) => {
60
+ requireOnPc('web');
61
+ const { running, state } = await controlOf(ctx).status();
62
+ const port = running && state ? state.port : null;
63
+ return { running, port, address: port ? 'http://127.0.0.1:' + port + '/' : null };
64
+ });
65
+ export const startWebRun = implement(startWeb, async (ctx, _input, io) => {
66
+ requireOnPc('web');
67
+ const started = await startServer(ctx, io, controlOf(ctx));
68
+ return { port: started.port, message: started.message };
69
+ });
70
+ export const openWebRun = implement(openWeb, async (ctx, _input, io) => {
71
+ requireOnPc('web');
72
+ const control = controlOf(ctx);
73
+ const started = await startServer(ctx, io, control);
74
+ if (started.wasRunning)
75
+ io.log(started.message);
76
+ const { state } = await control.status();
77
+ if (!state)
78
+ return fail('The web UI stopped right away.', 'Run sandbox web start again.');
79
+ openBrowser(control.url(state));
80
+ return { message: 'Opened in your browser.' };
81
+ });
82
+ export const stopWebRun = implement(stopWeb, async (ctx) => {
83
+ requireOnPc('web');
84
+ const control = controlOf(ctx);
85
+ const { running, state } = await control.status();
86
+ if (!state)
87
+ return { stopped: false, message: 'The web UI is not running.' };
88
+ if (!running || (await control.stop(state)))
89
+ control.clear();
90
+ else
91
+ return fail('The web UI did not stop.', 'End the process ' + state.pid + ' in Task Manager.');
92
+ return { stopped: true, message: 'The web UI stopped.' };
93
+ });